播放使用 Google Cloud Video Stitcher API 注册的直播
本指南演示了如何使用适用于 CAF Web 接收器的 IMA DAI SDK 请求并播放已通过 Google Cloud Video Stitcher API 注册的活动的直播,以及在播放期间插入广告插播时间点。
本指南对完整服务 DAI 的基本示例进行了扩展,添加了对使用 Google Cloud Video Stitcher API 注册的串流的支持。
请先确保 CAF Web 接收器支持您的在线播放格式,然后再继续。
如需了解如何与其他平台集成或如何使用 IMA 客户端 SDK,请参阅互动式媒体广告 SDK。
背景
在使用本指南之前,请先熟悉 Chromecast 应用框架的 Web 接收器协议。
本指南假定您基本熟悉 CAF 接收器概念,例如消息拦截器、MediaInformation
对象,以及使用 Cast 命令和控制工具来模拟 CAF 发送器。
应用组件和架构
如本指南所示,使用 Google Cloud Video Stitcher API 和 IMA CAF DAI SDK 实现直播播放涉及两个主要组成部分:
VideoStitcherLiveStreamRequest
:用于定义对 Google 服务器的流式传输请求的对象。该请求指定 Cloud Video Stitcher API 的实例、直播配置 ID 和其他可选参数。StreamManager
:用于处理视频流与 IMA DAI SDK 之间的通信的对象,例如触发跟踪 ping 和将流事件转发给发布商。
前提条件
您需要为 IMA SDK 提供以下变量:
实时配置 ID:这是您在创建 Video Stitcher API 实时配置时指定的实时配置 ID。
LIVE_CONFIG_ID
位置:创建实时配置的 Google Cloud 区域。
LOCATION
Project Number:使用 Video Stitcher API 的 Google Cloud 项目编号。
PROJECT_NUMBER
OAuth 令牌:服务账号的短期有效 OAuth 令牌,具有视频剪辑器用户角色。详细了解如何为服务账号创建短期凭据。
OAUTH_TOKEN
广告资源网代码:用于请求广告的 Google Ad Manager 广告资源网代码。
NETWORK_CODE
自定义素材资源键:使用 Video Stitcher API 为直播活动创建配置过程中生成的 Google Ad Manager 自定义素材资源键。
CUSTOM_ASSET_KEY
如需使用自定义 Cast 接收器,您需要满足以下要求:
一个 Cast 开发者控制台账号,其中包含已列入许可名单的测试设备。
已在 Cast 开发者控制台中注册的托管网络接收器应用,可修改为托管本指南提供的代码。
已配置为使用 Web 接收器应用的发送应用。在本例中,本指南使用 Cast 命令和控制工具作为发送方。
准备好发送端以将流数据传递给接收端
首先,将发送方应用配置为向 Web 接收器发出加载请求,并在平台的 MediaInformation
对象中包含以下字段。
字段 | 目录 | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
contentId
|
此媒体内容的唯一标识符,如投放参考文档中所定义。请勿将此 ID 重复用于同一媒体队列中的多个项。
|
||||||||||||||
contentUrl
|
备用直播网址(可选),用于在 DAI 直播无法加载时播放。
|
||||||||||||||
contentType
|
备用视频流网址的 MIME 类型(可选),用于在 DAI 视频流无法加载时播放。
|
||||||||||||||
streamType
|
用于此值的字符串字面量或常量因发件人平台而异。
|
||||||||||||||
customData
|
|
以下是一些代码示例,可帮助您开始使用:
Web
如需在 Cast Web 发送器中配置这些值,请先创建包含所需数据的 MediaInfo
对象,然后向 Web 接收器发出加载请求。
// Create mediaInfo object
const mediaInfo = new chrome.cast.media.MediaInfo("CONTENT_ID");
mediaInfo.contentUrl = "BACKUP_STREAM_URL";
mediaInfo.contentType = "BACKUP_STREAM_MIMETYPE";
mediaInfo.streamType = chrome.cast.media.StreamType.LIVE;
mediaInfo.customData = {
liveConfigID: "LIVE_CONFIG_ID",
region: "LOCATION",
projectNumber: "PROJECT_NUMBER",
oAuthToken: "OAUTH_TOKEN",
networkCode: "NETWORK_CODE",
customAssetKey: "CUSTOM_ASSET_KEY"
};
// Make load request to cast web receiver
const castSession = cast.framework.CastContext.getInstance().getCurrentSession();
const request = new chrome.cast.media.LoadRequest(mediaInfo);
castSession.loadMedia(request).then(
() => { console.log('Load succeed'); },
(errorCode) => { console.log('Error code: ' + errorCode); });
Android
如需在 Cast Web 发送器中配置这些值,请先使用所需数据创建 MediaInfo
对象,然后向 Web 接收器发出加载请求。
JSONObject customData = new JSONObject()
.put("liveConfigID", "LIVE_CONFIG_ID")
.put("region", "LOCATION")
.put("projectNumber", "PROJECT_NUMBER")
.put("oAuthToken", "OAUTH_TOKEN")
.put("networkCode", "NETWORK_CODE")
.put("customAssetKey", "CUSTOM_ASSET_KEY");
MediaInfo mediaInfo = MediaInfo.Builder("CONTENT_ID")
.setContentUrl("BACKUP_STREAM_URL")
.setContentType("BACKUP_STREAM_MIMETYPE")
.setStreamType(MediaInfo.STREAM_TYPE_LIVE)
.setCustomData(customData)
.build();
RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient();
remoteMediaClient.load(new MediaLoadRequestData.Builder().setMediaInfo(mediaInfo).build());
iOS (Obj-C)
如需在 Cast Web 发送器中配置这些值,请先创建包含所需数据的 GCKMediaInformation
对象,然后向 Web 接收器发出加载请求。
NSURL url = [NSURL URLWithString:@"BACKUP_STREAM_URL"];
NSDictionary *customData = @{
@"liveConfigID": @"LIVE_CONFIG_ID",
@"region": @"LOCATION",
@"projectNumber": @"PROJECT_NUMBER",
@"oAuthToken": @"OAUTH_TOKEN",
@"networkCode": @"NETWORK_CODE",
@"customAssetKey": @"CUSTOM_ASSET_KEY"
};
GCKMediaInformationBuilder *mediaInfoBuilder =
[[GCKMediaInformationBuilder alloc] initWithContentID: @"CONTENT_ID"];
mediaInfoBuilder.contentURL = url;
mediaInfoBuilder.contentType = @"BACKUP_STREAM_MIMETYPE";
mediaInfoBuilder.streamType = GCKMediaStreamTypeLive;
mediaInfoBuilder.customData = customData;
self.mediaInformation = [mediaInfoBuilder build];
GCKRequest *request = [self.sessionManager.currentSession.remoteMediaClient loadMedia:self.mediaInformation];
if (request != nil) {
request.delegate = self;
}
iOS (Swift)
如需在 Cast Web 发送器中配置这些值,请先创建包含所需数据的 GCKMediaInformation
对象,然后向 Web 接收器发出加载请求。
let url = URL.init(string: "BACKUP_STREAM_URL")
guard let mediaURL = url else {
print("invalid mediaURL")
return
}
let customData = [
"liveConfigID": "LIVE_CONFIG_ID",
"region": "LOCATION",
"projectNumber": "PROJECT_NUMBER",
"oAuthToken": "OAUTH_TOKEN",
"networkCode": "NETWORK_CODE",
"customAssetKey": "CUSTOM_ASSET_KEY"
]
let mediaInfoBuilder = GCKMediaInformationBuilder.init(contentId: "CONTENT_ID")
mediaInfoBuilder.contentURL = mediaUrl
mediaInfoBuilder.contentType = "BACKUP_STREAM_MIMETYPE"
mediaInfoBuilder.streamType = GCKMediaStreamType.Live
mediaInfoBuilder.customData = customData
mediaInformation = mediaInfoBuilder.build()
guard let mediaInfo = mediaInformation else {
print("invalid mediaInformation")
return
}
if let request = sessionManager.currentSession?.remoteMediaClient?.loadMedia(mediaInfo) {
request.delegate = self
}
CAC 工具
如需在 Cast 命令和控制工具中配置这些值,请点击“Load Media”(加载媒体)标签页,然后将自定义加载请求类型设置为“LOAD”。然后,将文本区域中的 JSON 数据替换为以下 JSON:
{
"media": {
"contentId": "CONTENT_ID",
"contentUrl": "BACKUP_STREAM_URL",
"contentType": "BACKUP_STREAM_MIMETYPE",
"streamType": "LIVE",
"customData": {
"liveConfigID": "LIVE_CONFIG_ID",
"region": "LOCATION",
"projectNumber": "PROJECT_NUMBER",
"oAuthToken": "OAUTH_TOKEN",
"networkCode": "NETWORK_CODE",
"customAssetKey": "CUSTOM_ASSET_KEY"
}
}
}
此自定义加载请求可发送给接收器,以测试其余步骤。
创建自定义 CAF Web 接收器
创建自定义 Web 接收器,如 CAF SDK 自定义 Web 接收器指南中所述。
接收器的代码应如下所示:
<html>
<head>
<script
src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js">
</script>
</head>
<body>
<cast-media-player></cast-media-player>
<script>
const castContext = cast.framework.CastReceiverContext.getInstance()
castContext.start();
</script>
</body>
</html>
导入 IMA DAI SDK 并获取 Player Manager
在脚本加载 CAF 后,添加一个脚本标记,以将适用于 CAF 的 IMA DAI SDK 导入到您的 Web 接收器。然后,在接下来的脚本标记中,将接收器上下文和播放器管理器存储为常量,然后再启动接收器。
<html>
<head>
<script
src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
<script src="//imasdk.googleapis.com/js/sdkloader/cast_dai.js"></script>
</head>
<body>
<cast-media-player></cast-media-player>
<script>
const castContext = cast.framework.CastReceiverContext.getInstance();
const playerManager = castContext.getPlayerManager();
castContext.start();
</script>
</body>
</html>
初始化 IMA 串流管理器
初始化 IMA 串流管理器。
<html>
<head>
<script type="text/javascript"
src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
<script src="//imasdk.googleapis.com/js/sdkloader/cast_dai.js"></script>
</head>
<body>
<cast-media-player></cast-media-player>
<script>
const castContext = cast.framework.CastReceiverContext.getInstance();
const playerManager = castContext.getPlayerManager();
const streamManager = new google.ima.cast.dai.api.StreamManager();
castContext.start();
</script>
</body>
</html>
创建 Stream Manager 加载拦截器
在媒体内容传递给 CAF 之前,请在 LOAD 消息拦截器中创建流式传输请求。
const castContext = cast.framework.CastReceiverContext.getInstance();
const playerManager = castContext.getPlayerManager();
const streamManager = new google.ima.cast.dai.api.StreamManager();
/**
* Creates a livestream request object for the Video Stitcher API.
* @param {!LoadRequestData} castRequest The request object from the cast sender
* @return {StreamRequest} an IMA stream request
*/
const createStreamRequest = (castRequest) => { /* ... */};
/**
* Initates a DAI stream request for the final stream manifest.
* @param {!LoadRequestData} castRequest The request object from the cast sender
* @return {Promise<LoadRequestData>} a promise that resolves to an updated castRequest, containing the DAI stream manifest
*/
const createDAICastRequest = (castRequest) => {
return streamManager.requestStream(castRequest, createStreamRequest(castRequest))
.then((castRequestWithStreamData) => {
console.log('Successfully made DAI stream request.');
return castRequestWithStreamData;
})
.catch((error) => {
console.log('Failed to make DAI stream request.');
// CAF will automatically fallback to the content URL
// that it can read from the castRequest object.
return castRequest;
});
};
playerManager.setMessageInterceptor(
cast.framework.messages.MessageType.LOAD, createDAICastRequest);
castContext.start();
创建数据流请求
完成 createStreamRequest
函数,以便根据 CAF 加载请求创建 Video Stitcher API 直播请求。
/**
* Creates a livestream request object for the Video Stitcher API.
* @param {!LoadRequestData} castRequest The request object from the cast sender
* @return {StreamRequest} an IMA stream request
*/
const createStreamRequest = (castRequest) => {
const streamRequest = new google.ima.cast.dai.api.VideoStitcherLiveStreamRequest();
const customData = castRequest.media.customData;
streamRequest.liveStreamEventId = customData.liveConfigID;
streamRequest.region = customData.region;
streamRequest.projectNumber = customData.projectNumber;
streamRequest.oAuthToken = customData.oAuthToken;
streamRequest.networkCode = customData.networkCode;
streamRequest.customAssetKey = customData.customAssetKey;
return streamRequest;
};
(可选)添加在线播放会话选项
使用 VideoStitcherLiveStreamRequest.videoStitcherSessionOptions
添加会话选项以替换默认的 Cloud Video Stitcher API 配置,从而自定义您的串流请求。
如果您提供的选项无法识别,Cloud Video Stitcher API 将返回 HTTP 400 错误。如需帮助,请参阅问题排查指南。
例如,您可以使用以下代码段替换清单选项,该代码段会请求两个串流清单,其中呈现方式的排序方式为从最低比特率到最高比特率。
...
// The following session options are examples. Use session options
// that are compatible with your video stream.
streamRequest.videoStitcherSessionOptions = {
"manifestOptions": {
"bitrateOrder": "ascending"
}
};
streamManager.requestStream(streamRequest);