概览
Web Receiver SDK 支持使用 SDK 提供的默认队列排队,方法是使用 QueueData
和 QueueManager
,或使用自定义队列(实现 cast.framework.QueueBase
并使用 QueueManager
进行更新)。
Queueing API 允许应用通过提供以下功能来与 Cast 更好地集成:
- 支持 Google 及合作伙伴的云端队列实现,因此外部存储和创建的队列可以直接加载到投放设备中。
- 支持对队列中的项进行分页的机制,而不是一次性加载所有内容。
- 支持新的消息传递,例如转到下一项、上一项、提取窗口以及获取与一组队列项相关的媒体信息。
QueueManager
,用于管理队列项的插入、移除和更新。
默认队列
Web Receiver SDK 以默认队列的形式为开箱提供有限的队列支持。
如需使用默认队列,请在发件人端加载的 LoadRequestData
中提供 queueData
,或使用 PlayerManager#load
发送本地加载请求。另请参阅加载媒体。
在接收器端,加载初始媒体后可以使用 QueueManager
修改队列。
自定义队列
如果默认队列未提供您的应用所需的排队功能,则可以创建自定义队列,从而获得更多功能和灵活性。
应用开发者可以通过实现 cast.framework.QueueBase
来创建 Web 接收器端队列。
下面是一个基本示例,其中简单的 initialize
调用会被替换,然后队列内容列表及队列说明会提供给 Cast 设备。
另请参阅加载媒体。
// Creates a simple queue with a combination of contents.
const DemoQueue = class extends cast.framework.QueueBase {
constructor() {
super();
/**
* List of media urls.
* @private @const {!Array<string>}
*/
this.myMediaUrls_ = [...];
}
/**
* Provide a list of items.
* @param {!cast.framework.messages.LoadRequestData} loadRequestData
* @return {!cast.framework.messages.QueueData}
*/
initialize(loadRequestData) {
const items = [];
for (const mediaUrl of this.myMediaUrls_) {
const item = new cast.framework.messages.QueueItem();
item.media = new cast.framework.messages.MediaInformation();
item.media.contentId = mediaUrl;
items.push(item);
}
let queueData = loadRequestData.queueData;
// Create a new queue with media from the load request if one doesn't exist.
if (!queueData) {
queueData = new cast.framework.messages.QueueData();
queueData.name = 'Your Queue Name';
queueData.description = 'Your Queue Description';
queueData.items = items;
// Start with the first item in the playlist.
queueData.startIndex = 0;
// Start from 10 seconds into the first item.
queueData.currentTime = 10;
}
return queueData;
}
};
在此示例中,initialize
调用中的项列表在提供方的 QueueBase
构造函数调用中提供。不过,对于云队列实现,自定义 Web 接收器逻辑可以从外部提取项,然后将其作为初始化调用的一部分返回。
为了更全面地展示队列 API 的用法,下面是一个实现大多数 QueueBase
类的演示队列。
const DemoQueue = class extends cast.framework.QueueBase {
constructor() {
/** @private {} */
super();
YourServer.onSomeEvent = this.updateEntireQueue_;
}
/**
* Initializes the queue.
* @param {!cast.framework.messages.LoadRequestData} loadRequestData
* @return {!cast.framework.messages.QueueData}
*/
initialize(loadRequestData) {
let queueData = loadRequestData.queueData;
// Create a new queue with media from the load request if one doesn't exist.
if (!queueData) {
queueData = new cast.framework.messages.QueueData();
queueData.name = 'Your Queue Name';
queueData.description = 'Your Queue Description';
// Put the first set of items into the queue
const items = this.nextItems();
queueData.items = items;
// Start with the first item in the playlist.
queueData.startIndex = 0;
// Start from 10 seconds into the first item.
queueData.currentTime = 10;
}
return queueData;
}
/**
* Picks a set of items from remote server after the reference item id and
* return as the next items to be inserted into the queue. When
* referenceItemId is omitted, items are simply appended to the end of the
* queue.
* @param {number} referenceItemId
* @return {!Array<cast.framework.QueueItem>}
*/
nextItems(referenceItemId) {
// Assume your media has a itemId and the media url
return this.constructQueueList_(YourServer.getNextMedias(referenceItemId));
}
/**
* Picks a set of items from remote server before the reference item id and
* return as the items to be inserted into the queue. When
* referenceItemId is omitted, items are simply appended to beginning of the
* queue.
* @param {number} referenceItemId
* @return {!Array<cast.framework.QueueItem>}
*/
prevItems(referenceItemId) {
return this.constructQueueList_(YourServer.getPrevMedias(referenceItemId));
}
/**
* Constructs a list of QueueItems based on the media information containing
* the item id and the media url.
* @param {number} referenceItemId
* @return {!Array<cast.framework.QueueItem>}
*/
constructQueueList_(medias) {
const items = [];
for (media of medias) {
const item = new cast.framework.messages.QueueItem(media.itemId);
item.media = new cast.framework.messages.MediaInformation();
item.media.contentId = media.url;
items.push(item);
}
return items;
}
/**
* Logs the currently playing item.
* @param {number} itemId The unique id for the item.
* @export
*/
onCurrentItemIdChanged(itemId) {
console.log('We are now playing video ' + itemId);
YourServer.trackUsage(itemId);
}
};
在上面的示例中,YourServer
是您的云队列服务器,并且具有有关如何提取某些媒体项的逻辑。
如需使用由 QueueBase
实现的队列,需要在 CastReceiverContext
中设置队列选项:
const context = cast.framework.CastReceiverContext.getInstance();
context.start({queue: new DemoQueue()});
管理队列
通过提供访问当前存储的队列项列表以及当前播放项的方法,QueueManager
让开发者可以灵活地开发其排队解决方案。它还提供插入、移除和更新队列项等操作。以下代码段展示了如何访问 QueueManager
的实例:
const context = cast.framework.CastReceiverContext.getInstance();
const queueManager = context.getPlayerManager().getQueueManager();
默认队列管理
初始队列加载完成后,QueueManager
可用于执行各种操作,例如检索当前项、检索队列中的所有项,以及使用 insertItems
、removeItems
和 updateItems
更新队列中的项。
自定义队列管理
下面是一个自定义队列实现示例,该实现使用基于某个事件的插入和移除方法。该示例还演示了 updateItems
的使用情形,开发者可以修改现有队列中的队列项,例如移除广告插播时间点。
const DemoQueue = class extends cast.framework.QueueBase {
constructor() {
super();
/** @private @const {!cast.framework.QueueManager} */
this.queueManager_ = context.getPlayerManager().getQueueManager();
}
/**
* Provide a list of items.
* @param {!cast.framework.messages.LoadRequestData} loadRequestData
* @return {!cast.framework.messages.QueueData}
*/
initialize(loadRequestData) {
// Your normal initialization; see examples above.
return queueData;
}
/** Inserts items to the queue. */
onSomeEventTriggeringInsertionToQueue() {
const twoMoreUrls = ['http://url1', 'http://url2'];
const items = [];
for (const mediaUrl of twoMoreUrls) {
const item = new cast.framework.QueueItem();
item.media = new cast.framework.messages.MediaInformation();
item.media.contentId = mediaUrl;
items.push(item);
}
// Insert two more items after the current playing item.
const allItems = this.queueManager_.getItems();
const currentItemIndex = this.queueManager_.getCurrentItemIndex();
const nextItemIndex = currentItemIndex + 1;
let insertBefore = undefined;
if (currentItemIndex >= 0 &&
currentItemIndex < allItems.length - 1) {
insertBefore = allItems[nextItemIndex].itemId;
}
this.queueManager_.insertItems(items, insertBefore);
}
/** Removes a particular item from the queue. */
onSomeEventTriggeringRemovalFromQueue() {
this.queueManager_.removeItems([2]);
}
/** Removes all the ads from all the items across the entire queue. */
onUserBoughtAdFreeVersion() {
const items = this.queueManager_.getItems();
this.queueManager_.updateItems(items.map(item => {
item.media.breaks = undefined;
return item;
}));
}
};
传入和传出的消息
为了全面支持将接收器端队列提取作为可信来源,CAF 接收器 SDK 引入了并处理以下额外的排队消息:
收到的消息 | 参数 | 传出响应消息 | 返回 |
下一步 | 无需参数。 | 媒体状态 | 接收器将(在必要时通过 NextItems() 提取)并开始播放下一项内容。 |
上一页 | 无需参数。 | 媒体状态 | 网络接收器将(通过 prevItems() 提取,如有必要)并开始播放上一项内容。 |
FETCH_ITEMS | FetchItemsRequestData | QUEUE_CHANGE | 一个 cast.framework.messages.QueueChange。例如,对于插入情形,JSON 中的 items 字段将包含所提取的新项的列表。 |
GET_ITEMS_INFO | 包含 itemIds 的 GetItemsInfoRequestData:数组<number> | ITEMS_INFO | 包含队列项信息的 cast.framework.messages.ItemsInfo。 |
GET_QUEUE_IDS | 无需参数。 | QUEUE_IDS | cast.framework.messages.QueueIds。 |
对于 NEXT
/PREVIOUS
,如果 Web 接收器上的现有队列表示没有更多项,系统会自动调用 QueueBase.nextItems()
或 QueueBase.prevItems()
来接收更多项。
对于 FETCH_ITEM
,系统会为 Cloud 队列调用 QueueBase
实现中的相应函数 fetchItems
,该函数会检索要返回给 Web 接收器以存储的相关数据。
每当提取更多项时,系统都会触发新的消息类型 QUEUE_CHANGE
,并将其发送回发送者。查看各种类型的队列更改。
对于 GET_ITEMS_INFO
,QueueBase
的实现不会被触发,并且 Web 接收器会返回 ID 列表已知的媒体信息。
随机播放队列
如需设置要随机播放队列中的项,请在将项加载到队列中时将 QueueData
的 shuffle
标志设置为 true
。
如果您使用的是 QueueBase
的实现,请使用 shuffle
方法返回已打乱顺序的项列表。
如需打乱现有队列,请使用 QUEUE_UPDATE
MessageType
的 shuffle
标志,而不是 QUEUE_SHUFFLE
命令。如需了解详情,请参阅 QueueUpdateRequestData
。
重复模式
如需将队列中的项设置为重复项,请在将项加载到队列中时将 QueueData
的 repeatMode
属性设置为所需的 RepeatMode
。
如需更改现有队列的 RepeatMode
,请使用 QueueUpdateRequestData
的 repeatMode
属性,该属性使用 QUEUE_UPDATE
MessageType
。