Overview
The Web Receiver SDK supports queueing with the
default queue provided by the
SDK using
QueueData
and
QueueManager
or using a custom queue by
implementing
cast.framework.QueueBase
and using
QueueManager
for updates.
The Queueing API allows applications to better integrate with Cast by providing the following features:
- Support of Google's and partner's cloud queue implementation so externally stored and created queue can be directly loaded into Cast devices.
- Mechanisms that allows pagination of items in the queue rather than loading everything at once.
- Support for new messaging such as going to the next item, the previous item, fetching a window of items, as well as getting media information related to a set of queue items.
- The
QueueManager
to manage insertion, removal, and update of queue items.
Default queue
The Web Receiver SDK provides limited queue support out of the box in the form of a default queue.
To use the default queue, provide the
queueData
in the LoadRequestData
of your sender-side loads or send a local load request
using
PlayerManager#load
.
Also see Loading media.
On the receiver-side, the queue can be modified using the
QueueManager
once the initial media has been loaded.
Custom queue
If the default queue does not provide the queueing functionality required for your app, the ability to create a custom queue is available, allowing for more capabilities and flexibility.
Application developers can create a Web Receiver side queue by implementing
cast.framework.QueueBase
.
Here is a basic example of a simple queue where the
initialize
call is overridden and then a list of queue items along with queue descriptions
are provided to the Cast device.
Also see Loading media.
// 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;
}
};
In this example, the list of items in the
initialize
call is provided in the provider's
QueueBase
constructor call. However, for a cloud queue implementation, the custom Web
Receiver logic can fetch the items externally and then return them as part of
the initialize call.
To demonstrate a more comprehensive use of the queueing API, here is a Demo
queue that implements most of the
QueueBase
class.
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);
}
};
In the example above, YourServer
is your cloud queue server and has logic
about how to fetch certain media items.
To use QueueBase
-implemented queueing, one would set the queue option in the
CastReceiverContext
:
const context = cast.framework.CastReceiverContext.getInstance();
context.start({queue: new DemoQueue()});
Managing a queue
The
QueueManager
gives developers flexibility in developing their queueing solutions by providing
methods to access the currently stored list of queue items as well as the
current playing item. It also provides operations such as insertion, removal,
and update of queueing items. The following snippet shows how to access an
instance of
QueueManager
:
const context = cast.framework.CastReceiverContext.getInstance();
const queueManager = context.getPlayerManager().getQueueManager();
Default queue management
Once the initial queue has been loaded, the
QueueManager
can be used to perform actions such as retrieving the current item, retrieving
all items in the queue, and updating the items in the queue using
insertItems
,
removeItems
,
and
updateItems
.
Custom queue management
Here is an example of a custom queue implementation that uses the insertion and
removal methods based on some event. The example also demonstrates a usage of
updateItems
where the developers can modify the queue items in the existing queue, such as
removing ad breaks.
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;
}));
}
};
Incoming and outgoing messages
To fully support receiver-side queue fetching as the source of truth, the following additional queueing messages are introduced and handled by the CAF Receiver SDK:
Incoming Message | Parameters | Outgoing Response Message | Return |
NEXT | No parameter needed. | MEDIA_STATUS | Receiver will (fetch through nextItems() if necessary) and start playing the next item. |
PREVIOUS | No parameter needed. | MEDIA_STATUS | The Web Receiver will (fetch through prevItems() if necessary) and start playing the previous item. |
FETCH_ITEMS | FetchItemsRequestData | QUEUE_CHANGE | A cast.framework.messages.QueueChange. As an example, for an insert case, the items field in the JSON will contain the list of new items fetched. |
GET_ITEMS_INFO | GetItemsInfoRequestData containing itemIds: Array<number> | ITEMS_INFO | cast.framework.messages.ItemsInfo with queue item information. |
GET_QUEUE_IDS | No parameter needed. | QUEUE_IDS | cast.framework.messages.QueueIds. |
For NEXT
/PREVIOUS
, if the existing queue representation on the Web Receiver
does not have more items, the
QueueBase.nextItems()
or
QueueBase.prevItems()
is automatically invoked to receive more items.
For FETCH_ITEM
, the corresponding function
fetchItems
in the QueueBase
implementation is called for cloud queues, which retrieves
the relevant data to be returned to the Web Receiver to store.
Whenever more items are fetched, a new message type QUEUE_CHANGE
is triggered
and sent back to the sender. See the various types of
queue changes.
For GET_ITEMS_INFO
,
QueueBase
's
implementation is not triggered and the Web Receiver returns media information
already known to the list of ids.
Shuffling a queue
To set the items in your queue to be shuffled, set the
shuffle
flag of
QueueData
to true
when loading your items into the queue.
If you are using an implementation of
QueueBase
, use
the
shuffle
method to return a shuffled list of items.
To shuffle an existing queue, use the
shuffle
flag of the QUEUE_UPDATE
MessageType
,
rather than the QUEUE_SHUFFLE
command. See
QueueUpdateRequestData
for more information.
Repeat mode
To set the items in your queue to be repeated, set the
repeatMode
property of
QueueData
to the desired
RepeatMode
when loading your items into the queue.
To change the RepeatMode
of an existing queue, use the
repeatMode
property of the
QueueUpdateRequestData
,
which uses the QUEUE_UPDATE
MessageType
.