Ad Breaks
The Web Sender SDK provides support for Ad Breaks and companion ads within a given media stream.
See the Web Receiver Ad Breaks Overview for more information on how Ad Breaks work.
While breaks can be specified on both the sender and receiver, it is recommended for them to be specified on the Web Receiver and Android TV Receiver to maintain consistent behavior across platforms.
On the web, specify Ad Breaks in a load command using BreakClip
and Break
:
let
breakClip1
=
new
BreakClip
(
'bc0'
);
breakClip1
.
title
=
'Clip title'
breakClip1
.
posterUrl
=
'https://www.some.url'
;
breakClip1
.
duration
=
60
;
breakClip
.
whenSKippable
=
5
;
let
breakClip2
=
...
let
breakClip3
=
...
let
break1
=
new
Break
(
'b0'
,
[
'bc0', 'bc1', 'bc2'
]
,
10
);
let
mediaInfo
=
new
chrome
.
cast
.
media
.
MediaInfo
(
< contentId
> ,
'<contentType'
);
...
mediaInfo
.
breakClips
=
[
breakClip1, breakClip2, breakClip3
]
;
mediaInfo
.
breaks
=
[
break1
]
;
let
request
=
new
chrome
.
cast
.
media
.
LoadRequest
(
mediaInfo
);
cast
.
framework
.
CastContext
.
getInstance
().
getCurrentSession
().
loadMedia
(
request
)
Using the tracks APIs
A track can be a text (subtitle or caption) object, or an audio or video stream object. The Tracks APIs let you work with these objects in your application.
A Track
object
represents a track in the SDK. You can configure a track and assign a unique ID
to it like this:
var
englishSubtitle
=
new
chrome
.
cast
.
media
.
Track
(
1
,
// track ID
chrome
.
cast
.
media
.
TrackType
.
TEXT
);
englishSubtitle
.
trackContentId
=
'https://some-url/caption_en.vtt'
;
englishSubtitle
.
trackContentType
=
'text/vtt'
;
englishSubtitle
.
subtype
=
chrome
.
cast
.
media
.
TextTrackType
.
SUBTITLES
;
englishSubtitle
.
name
=
'English Subtitles'
;
englishSubtitle
.
language
=
'en-US'
;
englishSubtitle
.
customData
=
null
;
var
frenchSubtitle
=
new
chrome
.
cast
.
media
.
Track
(
2
,
// track ID
chrome
.
cast
.
media
.
TrackType
.
TEXT
);
frenchSubtitle
.
trackContentId
=
'https://some-url/caption_fr.vtt'
;
frenchSubtitle
.
trackContentType
=
'text/vtt'
;
frenchSubtitle
.
subtype
=
chrome
.
cast
.
media
.
TextTrackType
.
SUBTITLES
;
frenchSubtitle
.
name
=
'French Subtitles'
;
frenchSubtitle
.
language
=
'fr'
;
frenchSubtitle
.
customData
=
null
;
var
frenchAudio
=
new
chrome
.
cast
.
media
.
Track
(
3
,
// track ID
chrome
.
cast
.
media
.
TrackType
.
AUDIO
);
frenchAudio
.
trackContentId
=
'trk0001'
;
frenchAudio
.
trackContentType
=
'audio/mp3'
;
frenchAudio
.
subtype
=
null
;
frenchAudio
.
name
=
'French Audio'
;
frenchAudio
.
language
=
'fr'
;
frenchAudio
.
customData
=
null
;
A media item may have multiple tracks; for example, it can have multiple subtitles (each for a different language) or multiple alternative audio streams (for different languages).
MediaInfo
is the class that models a media item. To associate a collection of Track
objects with a media item, you update its tracks
property. This association needs to be made before the media is
loaded to the receiver:
var
tracks
=
[
englishSubtitle
,
frenchSubtitle
,
frenchAudio
];
var
mediaInfo
=
new
chrome
.
cast
.
media
.
MediaInfo
(
mediaURL
);
mediaInfo
.
contentType
=
'video/mp4'
;
mediaInfo
.
metadata
=
new
chrome
.
cast
.
media
.
GenericMediaMetadata
();
mediaInfo
.
customData
=
null
;
mediaInfo
.
streamType
=
chrome
.
cast
.
media
.
StreamType
.
BUFFERED
;
mediaInfo
.
textTrackStyle
=
new
chrome
.
cast
.
media
.
TextTrackStyle
();
mediaInfo
.
duration
=
null
;
mediaInfo
.
tracks
=
tracks
;
You can set the active tracks in the media activeTrackIds
request.
You can also activate one or more tracks that were associated with the media
item, after the media is loaded, by calling EditTracksInfoRequest(opt_activeTrackIds, opt_textTrackStyle)
and passing the IDs of the tracks to be activated in opt_activeTrackIds
. Note,
both parameters are optional and you may choose which, active tracks or styles,
to set at your discretion. For example, here is how to
activate the French subtitle ( 2
) and French audio ( 3
):
var
activeTrackIds
=
[
2
,
3
];
var
tracksInfoRequest
=
new
chrome
.
cast
.
media
.
EditTracksInfoRequest
(
activeTrackIds
);
media
.
editTracksInfo
(
tracksInfoRequest
,
successCallback
,
errorCallback
);
To remove all audio or video tracks from the current media, simply set mediaInfo.tracks=null
(an empty array) and reload the media.
To remove all text tracks from the current media (for example, turning off subtitles), do one of the following:
- Update
var activeTrackIds = [2, 3];
(shown previously) so it includes [3] only, the audio track. - Set
mediaInfo.tracks=null
. Note that it's not necessary to reload the media to turn off text captions (track.hidden
). Sending anactiveTracksId
array that doesn't contain a previously enabledtrackId
disables the text track.
Styling text tracks
TextTrackStyle
is the object that encapsulates the styling information of a text track. After
creating or updating an existing TextTrackStyle
object, you can apply that to
the currently playing media item by calling its editTrackInfo
method, like this:
var
textTrackStyle
=
new
chrome
.
cast
.
media
.
TextTrackStyle
();
var
tracksInfoRequest
=
new
chrome
.
cast
.
media
.
EditTracksInfoRequest
(
textTrackStyle
);
media
.
editTracksInfo
(
tracksInfoRequest
,
successCallback
,
errorCallback
);
You can track the status of the request with result of the callbacks, either success or error, and update the originating sender accordingly.
Applications should allow users to update the style for text tracks, either using the settings provided by the system or by the application itself.
You can style the following text track style elements:
- Foreground (text) color and opacity
- Background color and opacity
- Edge type
- Edge Color
- Font Scale
- Font Family
- Font Style
For example, set the text color to red with 75% opacity as follows:
var
textTrackStyle
=
new
chrome
.
cast
.
media
.
TextTrackStyle
();
textTrackStyle
.
foregroundColor
=
'#80FF0000'
;
Volume control
You can use the RemotePlayer
and RemotePlayerController
to set the receiver volume.
function
changeVolume
(
newVolume
)
{
player
.
volumeLevel
=
newVolume
;
playerController
.
setVolumeLevel
();
// Update sender UI to reflect change
}
The sender app should adhere to the following guidelines for controlling volume:
- The sender application must synchronize with the receiver so that the
sender UI always reports the volume per the receiver. Use the
RemotePlayerEventType.VOLUME_LEVEL_CHANGED
andRemotePlayerEventType.IS_MUTED_CHANGED
callback to maintain the volume on the sender. See Status updates for more information. - Sender apps must not set the volume level at a specific, pre-defined level or set the volume level to the sender device's ringer/media volume when the app loads on the receiver.
See Sender volume controls in the Design Checklist .
Sending media messages to the receiver
Media Messages
can be sent from the sender to
receiver. For example, to send a SKIP_AD
message to the receiver:
// Get a handle to the skip button element
const
skipButton
=
document
.
getElementById
(
'skip'
);
skipButton
.
addEventListener
(
"click"
,
function
()
{
if
(
castSession
)
{
const
media
=
castSession
.
getMediaSession
();
castSession
.
sendMessage
(
'urn:x-cast:com.google.cast.media'
,
{
type
:
'SKIP_AD'
,
requestId
:
1
,
mediaSessionId
:
media
.
mediaSessionId
});
}
});
Status updates
When multiple senders are connected to the same receiver, it is important for each sender to be aware of the changes on the receiver even if those changes were initiated from other senders.
To this end, your application should register all necessary listeners on the RemotePlayerController
.
If the TextTrackStyle
of the current media changes, then all of the connected senders will be notified
and the corresponding properties of the current media session, such as activeTrackIds
and textTrackStyle
of the MediaInfo
field will be sent to senders in callbacks. In this case, the receiver SDK
does not verify whether the new style is different from the previous one and
notifies all the connected senders regardless.
Progress indicator
Showing the playback location with a progress indicator on the sender is a requirement for most apps. The Cast APIs use the Cast media protocol, which optimizes bandwidth consumption for this and other scenarios, so you do not need to implement your own status synchronization. For the proper implementation of a progress indicator for media playback using the APIs, see the CastVideos-chrome sample app.
CORS requirements
For adaptive media streaming, Google Cast requires the presence of CORS headers, but even simple mp4 media streams require CORS if they include Tracks. If you want to enable Tracks for any media, you must enable CORS for both your track streams and your media streams. So, if you do not have CORS headers available for your simple mp4 media on your server, and you then add a simple subtitle track, you will not be able to stream your media unless you update your server to include the appropriate CORS headers.
You need the following headers: Content-Type
, Accept-Encoding
, and Range
.
Note that the last two headers, Accept-Encoding
and Range
, are additional
headers that you may not have needed previously.
Wildcards "*" cannot be used for the Access-Control-Allow-Origin
header. If
the page has protected media content, it must use a domain instead of a
wildcard.
Resuming a session without reloading the web page
To resume an existing CastSession
, use requestSessionById(sessionId)
with the sessionId
of the session you are attempting to join.
The sessionId
can be found on the active CastSession
using getSessionId()
after calling loadMedia()
.
The recommended approach is to:
- Call
loadMedia()
to start the session - Store the
sessionId
locally - Rejoin the session using
requestSessionById(sessionId)
when needed
let
sessionId
;
function
rejoinCastSession
()
{
chrome
.
cast
.
requestSessionById
(
sessionId
);
// Add any business logic to load new content or only resume the session
}
document
.
getElementById
(
'play-button'
).
addEventListener
((
"click"
),
function
()
{
if
(
sessionId
==
null
)
{
let
castSession
=
cast
.
framework
.
CastContext
.
getInstance
().
getCurrentSession
();
if
(
castSession
)
{
let
mediaInfo
=
createMediaInfo
();
let
request
=
new
chrome
.
cast
.
media
.
LoadRequest
(
mediaInfo
);
castSession
.
loadMedia
(
request
)
sessionId
=
CastSession
.
getSessionId
();
}
else
{
console
.
log
(
"Error: Attempting to play media without a Cast Session"
);
}
}
else
{
rejoinCastSession
();
}
});
Next steps
This concludes the features that you can add to your Web Sender app. You can now build a sender app for another platform ( Android or iOS ), or build a receiver app .