播放使用 Google Cloud Video Stitcher API 注册的直播
本指南演示了如何使用 IMA DAI SDK for CAF Web Receiver 来 请求和播放使用 Google Cloud Video Stitcher API注册的活动的直播, 并在播放期间插入广告插播时间点。
本指南扩展了完整服务 DAI 中的基本示例,增加了对使用 Google Cloud Video Stitcher API 注册的内容流的支持。
在继续之前,请确保您的流式传输格式受 CAF Web Receiver 支持。
如需了解如何与其他平台集成或使用 IMA 客户端 SDK,请参阅互动式媒体广告 SDK。
背景
在使用本指南之前,请先熟悉 Chromecast 应用框架的 Web Receiver 协议。
本指南假定您对 CAF Receiver 概念(
例如 消息
拦截器、
MediaInformation
对象)以及使用 Cast Command and Control
工具模拟 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项目编号:使用 Video Stitcher API 的 Google Cloud 项目编号。
PROJECT_NUMBEROAuth 令牌:具有 Video Stitcher 用户角色的服务帐号的短期 OAuth 令牌。详细了解如何为服务账号创建短期凭据。
OAUTH_TOKEN广告资源网代码:用于请求广告的 Google Ad Manager 广告资源网代码。
NETWORK_CODE自定义资源键:在使用 Video Stitcher API 为直播活动创建配置的过程中生成的 Google Ad Manager 自定义资源键。
CUSTOM_ASSET_KEY
对于自定义 Cast Receiver,您需要以下内容:
一个 Cast 开发者控制台账号,其中包含 许可名单中的测试设备。
一个托管的 Web Receiver 应用,该应用已在您的 Cast 开发者控制台中注册,并且可以进行修改以 托管本指南提供的代码。
一个配置为使用您的 Web Receiver 应用的发送应用。在本示例中,本指南使用 Cast Command and Control 工具作为发送器。
准备发送器以将内容流数据传递给 Receiver
首先,配置您的发送器应用,以向您的 Web Receiver 发出加载请求,
其中包含平台
MediaInformation
对象中的以下字段。
| 字段 | 目录 | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
contentId
|
此媒体项的唯一标识符,如 Cast
参考文档中所定义。此 ID 不应在同一媒体队列中重复用于多个项。
|
||||||||||||||
contentUrl
|
如果 DAI 内容流加载失败,则播放的可选备用推流网址。
|
||||||||||||||
contentType
|
如果 DAI 内容流加载失败,则播放的备用推流网址的可选 MIME 类型。
|
||||||||||||||
streamType
|
用于此值的字符串字面量或常量因发送器
平台而异。
|
||||||||||||||
customData
|
|
以下是一些代码示例,可帮助您入门:
Web
如需在 Cast Web 发送器中配置这些值,请先使用所需数据创建
MediaInfo
对象,然后向 Web Receiver 发出 加载
请求。
// 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 Receiver 发出加载
请求。
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 Receiver 发出加载
请求。
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 Receiver 发出加载
请求。
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 Command and Control 工具中配置这些值,请点击“加载媒体”标签页,并将 自定义加载请求类型设置为 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"
}
}
}
此自定义加载请求可以发送给 Receiver,以测试其余步骤。
创建自定义 CAF Web Receiver
创建自定义 Web Receiver,如 CAF SDK 自定义 Web Receiver 指南中所述。
Receiver 的代码应如下所示:
<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 的脚本之后,立即添加一个脚本标记,以将 IMA DAI SDK for CAF 导入到您的 Web Receiver。然后,在后面的脚本标记中,将 Receiver 上下文和 Player Manager 存储为常量,然后再启动 Receiver。
<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 Stream Manager
初始化 IMA Stream Manager。
<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;
};
(可选)添加流式传输会话选项
通过添加会话选项来自定义内容流请求,以替换默认的
Cloud Video Stitcher API 配置,使用
VideoStitcherLiveStreamRequest.videoStitcherSessionOptions。
如果您提供无法识别的选项,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);