Overview
The Web Receiver SDK features native support for ad breaks and companion ads
within a given media stream. It provides APIs to set the ad position, ad source,
and behavior of ad breaks and their associated break clips. In this guide, a Break
refers to an interval for playback containing one or more ads or bumpers and
each ad or bumper is referred to as a BreakClip
.
These breaks are associated to the media that is being loaded or playing.
Ad types
The Web Receiver SDK supports client side ad insertion (CSAI) and server stitched ad insertion (SSAI). Client-stitchedads can be manually set by the application or extracted from VASTand VMAPtemplate files. Server-stitchedads should be specified manually prior to content load as embeddedads or dynamically during content playback as embedded expandedads. Implementations for each of these ad types are described in detail below.
manual client-stitched
The manual client-stitched ad breakis a type of ad break that is stitched
together by the client and is specified manually by the application using the
SDK APIs. This ad type is not embedded in the main content’s stream. The BreakClip
must provide the contentId
which is a URL that points to the ad content, the contentType
describing the ad content's format, and the title
.
The Break
must have isEmbedded
and expanded
set to the default value false
. The position
can be set to a pre-roll
, mid-roll
or post-roll
ad break (see more in the break positioning
section). When preparing the
ad for playback, the Web Receiver SDK generates another player instance to load
and play the ad content. These breaks require a stitched timeline
and must be
added statically(see more in the ad insertion
section). The sample below shows a basic
implementation of a manual client-stitchedad:
// Create the BreakClip.
let
clipClient
=
new
cast
.
framework
.
messages
.
BreakClip
(
'bc_client'
);
clipClient
.
title
=
'The Ad Title to be displayed during playback'
;
clipClient
.
contentId
=
'https://example.com/ad.m3u8'
;
clipClient
.
contentType
=
'application/vnd.apple.mpegurl'
;
// Optional: Used when HLS ad container formats differ from the main content's.
clipClient
.
hlsSegmentFormat
=
cast
.
framework
.
messages
.
HlsSegmentFormat
.
FMP4
;
// Create the Break using the BreakClip id above.
let
breakPostrollClient
=
new
cast
.
framework
.
messages
.
Break
(
'break_postroll_client'
,
[
'bc_client'
],
-
1
);
breakPostrollClient
.
isEmbedded
=
false
;
// Optional: default is false.
breakPostrollClient
.
expanded
=
false
;
// Optional: default is false.
VAST
The Web Receiver SDK supports adding IAB standard VAST(Video Ad Serving Template) ads. When provided, the XML template is parsed to generate a subsequent client-stitchedbreak clip upon entering the break.
To create a VAST ad, the receiver app must create a VastAdsRequest
and specify it in the BreakClip
vastAdsRequest
property. The VastAdsRequest
object must have either the adsResponse
(a
string representation of the XML template itself) or the adTagUrl
(the url
where the XML template is hosted) property defined. If the URL is specified, the
SDK will handle fetching the template. The encapsulating Break
follows
conventions for client-stitchedads. These ads can be added along other manual client-stitchedads in the same break or in separate breaks for the
same piece of content. The sample below shows a basic implementation of a VAST
ad:
// Create the VastAdsRequest.
let
vastTemplate
=
new
cast
.
framework
.
messages
.
VastAdsRequest
();
vastTemplate
.
adTagUrl
=
'https://example.com/ads.xml'
// Create the BreakClip.
let
clipVast
=
new
cast
.
framework
.
messages
.
BreakClip
(
'bc_vast'
);
clipVast
.
vastAdsRequest
=
vastTemplate
;
// Create the Break using the BreakClip id above.
let
breakPostrollVast
=
new
cast
.
framework
.
messages
.
Break
(
'break_postroll_vast'
,
[
'bc_vast'
],
-
1
);
breakPostrollVast
.
isEmbedded
=
false
;
// Optional: default is false.
breakPostrollVast
.
expanded
=
false
;
// Optional: default is false.
When a Break
that contains a VAST BreakClip
is entered, the Web Receiver
SDK will optionally fetch, and then parse the template. While parsing, the SDK
will generate a new BreakClip
and populate it with the extracted values from
the template such as the contentId
, contentType
, title
, duration
, whenSkippable
, and clickThroughUrl
. The id
for the generated break clip is
set to GENERATED:N
where N
is an integer that increments by 1
for each new VASTbreak clip created starting at 0
. The generated ad is then added to
the BreakClip
array. Each VASTbreak clip's id
in the current Break
is
then replaced with its corresponding generated break clip's id
. The snippets
below illustrate the changes in the MEDIA_STATUS
messages that pertain to ads before and after entering such a break.
Break
and BreakClip
information prior to entering a break with VAST ads.
"breaks"
:
[
{
"id"
:
"break_postroll_vast"
,
"breakClipIds"
:
[
"bc_vast"
],
"position"
:
0
,
"isWatched"
:
false
}
],
"breakClips"
:
[
{
"id"
:
"bc_vast"
}
]
Break
and BreakClip
information after entering a break with VAST ads.
"breaks"
:
[
{
"id"
:
"break_postroll_vast"
,
"breakClipIds"
:
[
"GENERATED:0"
],
"position"
:
0
,
"isWatched"
:
true
}
],
"breakClips"
:
[
{
"id"
:
"bc_vast"
},
{
"id"
:
"GENERATED:0"
,
"contentId"
:
"https://example.com/break-clip-1.mpd"
,
"contentType"
:
"application/dash+xml"
,
"title"
:
"Ad Title Extracted from Template"
,
"duration"
:
10
,
"whenSkippable"
:
5
,
"clickThroughUrl"
:
"https://example.com/ad-target"
}
]
VMAP
The Web Receiver SDK supports the IAB VMAP(Video Multiple Ad Playlists)
standard. When a VMAP is provided, the Web Receiver SDK will parse the VMAP
response and generate client-stitched Break
objects for any <AdBreak>
entries in the response. It will also generate the appropriate BreakClips
with
a vastAdsRequest
object for each <AdSource>
entry provided in the VMAP. To
enable VMAP for inserting ads into your content, the application must create a VastAdsRequest
object and assign it to the vmapAdsRequest
property of the MediaInformation
in the LoadRequestData
.
These ads must be inserted statically(see more in the ad insertion
section). Below is a snippet outlining the
creation of a VMAP request.
// Create the VastAdsRequest.
let
vastTemplate
=
new
cast
.
framework
.
messages
.
VastAdsRequest
();
vastTemplate
.
adTagUrl
=
'https://example.com/vmap.xml'
// Add it to the MediaInformation of the LoadRequest.
loadRequestData
.
media
.
vmapAdsRequest
=
vastTemplate
;
embedded
The embedded ad breakis a type of ad break that is stitched server side
into the main content’s stream. The duration of the Break
is subtractedfrom the main content's duration when calculating the media time.
The BreakClip
must provide the duration
of the ad content, and the title
.
The Break
must have isEmbedded
set to true
and expanded
set to false
. The position
can be set to as a pre-roll
or mid-roll
ad break. Post-roll
ad breaks are
supported with positive exact position
values. See more on this in the break positioning
section. When the ad is triggered to
play, the Web Receiver SDK continues playback of the stream as the ad segments
are embedded in it. There is no additional loading mechanism for this ad type.
The relevant ad metadata is shown to the user once the playhead is within the
break time range. These breaks require an embedded timeline
and must be added statically(see more in the ad insertion
section). The
sample below shows a basic implementation of an embedded
ad.
// Create the BreakClip.
let
clipEmbedded
=
new
cast
.
framework
.
messages
.
BreakClip
(
'bc_embedded'
);
clipEmbedded
.
title
=
'The Ad Title to be displayed during playback'
;
clipEmbedded
.
duration
=
15
;
// Create the Break using the BreakClip id above.
let
breakPrerollEmbedded
=
new
cast
.
framework
.
messages
.
Break
(
'break_preroll_embedded'
,
[
'bc_embedded'
],
0
);
breakPrerollEmbedded
.
isEmbedded
=
true
;
breakPrerollEmbedded
.
expanded
=
false
;
// Optional: default is false.
embedded expanded
The embedded expanded ad breakis a type of ad break that is stitched server
side into the main content’s stream. The duration of the Break
is includedin the main content's duration when calculating the media time.
The BreakClip
must provide the duration
of the ad content, and the title
.
The Break
must have isEmbedded
set to true
and expanded
set to true
. The position
can be set to as a pre-roll
or mid-roll
ad break. Post-roll
ad breaks are
supported with positive position
values. See more on this in the break positioning
section. When the ad is triggered to
play, the Web Receiver SDK continues playback of the stream as the ad segments
are embedded in it. There is no additional loading mechanism for this ad type.
The relevant ad metadata is shown to the user once the playhead is within the
break time range. These breaks require an embedded timeline
and can be added
either staticallyor dynamically(see more in the ad insertion
section). The sample below shows a basic
implementation of an embedded expanded
ad:
// Create the BreakClip.
let
clipEmbeddedExpanded
=
new
cast
.
framework
.
messages
.
BreakClip
(
'bc_embedded_expanded'
);
clipEmbeddedExpanded
.
title
=
'The Ad Title to be displayed during playback'
;
clipEmbeddedExpanded
.
duration
=
15
;
// Create the Break using the BreakClip id above.
let
breakPrerollEmbeddedExpanded
=
new
cast
.
framework
.
messages
.
Break
(
'break_preroll_embedded_expanded'
,
[
'bc_embedded_expanded'
],
0
);
breakPrerollEmbeddedExpanded
.
isEmbedded
=
true
;
breakPrerollEmbeddedExpanded
.
expanded
=
true
;
Player timeline types
When creating a player instance, the Web Receiver SDK selects a timeline type to
support playing ads during content playback. Each timeline enables certain ad
break types to be added. The timeline type is determined by the ad types
present during load time in the MediaInformation
of the LoadRequestData
.
If embeddedad breaks are present, the embedded
timeline is selected. If client-stitchedad breaks are present, the stitched
timeline is selected.
In the case that no ads are present, the SDK defaults to using the embedded
timeline. Once the timeline is selected, it cannot be changed for the current
media item. The table below provides a detailed description of each timeline.
Timeline Type | Description |
---|---|
embedded timeline | A representation of media time that supports ads which are embedded into the main content ( embeddedand embedded expandedad breaks). When an unexpanded ad break is present, the duration of it is subtracted from the total duration of the content. On the other hand, when an expanded ad break is present, its time is considered to be a part of the main content. |
stitched timeline | A representation of media time which supports ads that are sourced from external media files ( manual client-stitched, VASTand VMAPad breaks). When added, the ad break's duration is not a part of the main content’s duration. |
Figures 1 to 3 below illustrate some content with varied ad types and their respective timeline values. The content is configured with a pre-roll break containing two break clips and mid-roll and post-roll breaks containing a single break clip. The wall clock timesince the start of content playback, the media timeof the main content, and the time of the break's currently playing break clip are aligned below each figure.
Break positioning
The Web Receiver SDK allows developers to specify where ad breaks should be
placed by setting the position
property of the Break
. This value corresponds to the main content's media time
and can be used to create pre-roll
, mid-roll
, and post-roll
ad breaks.
These are defined as follows:
Break Position | Description |
---|---|
pre-roll | An ad break that is played before the main content. This is
denoted by setting the breakPosition
to 0
|
mid-roll | An ad break that is played mid content. This is denoted by
setting the breakPosition
to a time in which the break's
start is greater than the start of the main content, and
the break’s end time is less than the main content’s end
time. |
post-roll | An ad break that is played after the main content. This is
denoted by setting the breakPosition
to -1
for stitched timelines
. For embedded
timelines
the breakPosition
should be set to the main content's duration subtracted by
the duration of the break. Not supported for live content. |
Interoperability matrix
As a quick reference point, Table 1 shows an overview of the ad types and their compatibility with ad related features.
Feature Support | manual client-stitched ad | VAST | VMAP | embedded ad | embedded expanded ad |
---|---|---|---|---|---|
compatible with
|
VAST | manual client-stitched | N/A | embedded expanded | embedded |
timeline
|
stitched | stitched | stitched | embedded | embedded |
ad insertion
|
static | static | static | static | static, dynamic |
ad removal
|
|||||
pre-roll ad
|
|||||
mid-roll ad
|
|||||
post-roll ad
|
|||||
ad skip
|
|||||
break seek interceptor
|
|||||
break clip load interceptor
|
Events
When key break events occur, the cast SDK will dispatch events of type BreaksEvent
.
A receiver app can subscribe to them using the PlayerManager
addEventListener
API.
These events can be used for analytics and ad playback tracking. When VMAP(Video Multiple Ad Playlist) and VAST(Video Ad Serving Template) ads are used, any standard tracking events provided in the responses are automatically dispatched by the SDK.
The event types are listed in Table 2 along with a detailed description on when they are fired.
BREAK_STARTED
position
of an unwatched break.BREAK_CLIP_LOADING
BREAK_CLIP_STARTED
BREAK_CLIP_ENDED
endedReason
will be populated for the following circumstances: - A stitched timeline break clip played through entirely.
- A stitched timeline break clip transitions to another break clip.
- Any break clip is skipped.
- The last break clip played through entirely in a post-roll embedded break.
- An error occurred.
BREAK_ENDED
Ad insertion
The cast SDK enables applications to insert and remove ads at different moments
of a cast session. The two types of ad insertion are staticand dynamic. Staticad insertion requires that ads be specified in the LoadRequestData
prior to player creation. Dynamicad insertion makes use of the BreakManager
addBreak
API to insert breaks in the already loaded content. Each type of insertion
method is compatible with certain ad types
. A compatibility
overview is provided in the interoperability matrix
.
Static ad insertion
Static ad insertion is characterized by adding the relevant ad metadata prior
to player creation. This information is provided in the MediaInformation
of the LoadRequestData
. For example, this can be set in a connected sender's
original load request or it can be inserted by the Web Receiver application by
intercepting the LOAD
request. Once the LoadRequestData
is returned to the
Web Receiver SDK for processing, the player is created. See more on loading media
. The sample
below shows a manual client-stitchedad being added in the LOAD
request
interceptor.
const
context
=
cast
.
framework
.
CastReceiverContext
.
getInstance
();
const
playerManager
=
context
.
getPlayerManager
();
playerManager
.
setMessageInterceptor
(
cast
.
framework
.
messages
.
MessageType
.
LOAD
,
loadRequestData
=
>
{
// Create the BreakClip.
let
clipClient
=
new
cast
.
framework
.
messages
.
BreakClip
(
'bc_client'
);
clipClient
.
title
=
'The Ad Title to be displayed during playback'
;
clipClient
.
contentId
=
'https://example.com/ad.mp4'
;
clipClient
.
contentType
=
'video/mp4'
;
// Create the Break using the BreakClip id above.
let
breakPostrollClient
=
new
cast
.
framework
.
messages
.
Break
(
'break_postroll_client'
,
[
'bc_client'
],
-
1
);
// Set the ad information in the load request data.
let
media
=
loadRequestData
.
media
;
media
.
breakClips
=
[
clipClient
];
media
.
breaks
=
[
breakPostrollClient
];
return
loadRequestData
;
});
Dynamic ad insertion
Dynamic ad insertion is characterized by setting an ad break during content
playback. This is done by obtaining an instance of BreakManager
and calling
the addBreak
API. This takes two parameters at minimum, an embedded expanded
Break
and
an array of BreakClip
.
An optional third property is included to force sending the changes to
connected senders through a MediaStatus
broadcast when set to true
. When
adding breaks and break clips, the corresponding ids must be unique. These ads
can only be added once the player has been created. The Web Receiver SDK fires
the PLAYER_LOADING
event once the player is created. See the sample below showcasing the usage in
an event handler which responds to changes in the ID3 metadata of a stream and
creates Break
and BreakClip
objects to insert it into the timeline.
const
context
=
cast
.
framework
.
CastReceiverContext
.
getInstance
();
const
playerManager
=
context
.
getPlayerManager
();
const
breakManager
=
playerManager
.
getBreakManager
();
playerManager
.
addEventListener
(
cast
.
framework
.
events
.
EventType
.
ID3
,
(
event
)
=
>
{
// Create the BreakClip.
let
clipEmbeddedExpanded
=
parseBreakClipFromData
(
event
.
segmentData
);
let
breakEmbeddedExpanded
=
parseExpandedBreakFromData
(
event
.
segmentData
);
// Add the break and break clip.
breakManager
.
addBreak
(
breakEmbeddedExpanded
,
[
clipEmbeddedExpanded
]);
});
Dynamic ad removal
To remove dynamic breaks, the application should call removeBreakById
during playback. The function takes in a string identifier of the break to be
removed from the timeline. The breakId
specified must point to an embedded
expandedad break. If any other type of ad break is detected, then the break
will remain in the timeline. See the sample below which removes a break.
const
context
=
cast
.
framework
.
CastReceiverContext
.
getInstance
();
const
playerManager
=
context
.
getPlayerManager
();
const
breakManager
=
playerManager
.
getBreakManager
();
breakManager
.
removeBreakById
(
'break_midroll_embedded_expanded'
);
Behavior of breaks
The SDK defines a default behavior for when the player enters and leaves breaks
and provides for a way to customize it further using some of the APIs provided
in BreakManager
.
Default break behavior
When a Break
is entered through regular playback or by seeking over a Break
,
the SDK will evaluate whether or not the user has already seen it by checking
the isWatched
property. When created, a break's default value for this property is false
. If
the property is true
, the break will not be played when entered and main
content will continue playing. If the property is false
, the break will be
played when entered.
When seeking past breaks, the default implementation obtains all of the Break
items whose position
is between the seek operation's seekFrom
and seekTo
values. From this list of breaks, the SDK will play the Break
whose position
is closest to the seekTo
value and whose isWatched
property is set to false
. That break's isWatched
property will then be set to true
and the
player will commence playing its break clips. Once the break is watched,
the main content will resume playback from the seekTo
position. If no such
break exists, then no break will be played and the main content will resume
playing at the seekTo
position.
During break playback, the SDK will broadcast any relevant updates to connected
sender applications in the MediaStatus
.
These applications will use the broadcasts to update their UI for ads by reading
the breakStatus
property. This property is defined only during break playback.
Receiver applications can also directly query information pertaining to the
position of the playhead with respect to the current time of the BreakClip
shown by calling PlayerManager
getBreakClipCurrentTimeSec
.
Similarly, applications can query the duration of the current BreakClip
by
calling getBreakClipDurationSec
.
Custom break behavior
The default behavior
for breaks and break clips can be modified using the setBreakClipLoadInterceptor
and setBreakSeekInterceptor
methods provided in BreakManager
.
Break seek interceptor
The break seek interceptor allows the app to control the behavior of seeking
over ad breaks. The function is triggered when a seek operation is requested
that seeks forward or backward over one or more breaks. When called, the BreakSeekData
is passed as a parameter to the callback function. The BreakSeekData
object
contains an array of Break
objects whose position
property is set to a number between the current
playhead time defined as seekFrom
and the seek destination time seekTo
.
This interceptor allows the Break
objects in the respective breaks to be
modified. When implemented, the break seek interceptor must specify which ad
breaks to play by returning an optionally modified BreakSeekData
object. The
player will proceed to play all breaks included in the return value. If a value
of null
or nothing is returned from the break seek interceptor, the break is
skipped over.
See the sample below for a simple implementation of the interceptor which overrides the default behavior to watch all ad breaks seeked over with the exception of already watched breaks.
const
context
=
cast
.
framework
.
CastReceiverContext
.
getInstance
();
const
playerManager
=
context
.
getPlayerManager
();
const
breakManager
=
playerManager
.
getBreakManager
();
breakManager
.
setBreakSeekInterceptor
((
breakSeekData
)
=
>
{
// Filter the breaks array by removing watched breaks.
const
unwatchedBreaks
=
breakSeekData
.
breaks
.
filter
(
adBreak
=
>
!
adBreak
.
isWatched
);
breakSeekData
.
breaks
=
unwatchedBreaks
;
return
breakSeekData
;
});
Break clip load interceptor
By using the break clip load interceptor, a BreakClip
object can be modified
before its playback begins.
The break clip load interceptor is called only for stitched timeline breaks
and can be set using setBreakClipLoadInterceptor
.
Prior to entering a Break
, this interceptor is called once for each individual BreakClip
defined in that break. The SDK passes the original BreakClip
object as a parameter of the callback function. The application can then modify
this BreakClip
and return it so that the SDK can fetch and display the break
clip with the updated configuration. If null
or nothing is returned, the break
clip is skipped over.
See below for an example which modifies the contentUrl
of the break clips with
a utility function call getUrlFromClipId
where the id
of the BreakClip
is mapped to a URL.
const
context
=
cast
.
framework
.
CastReceiverContext
.
getInstance
();
const
playerManager
=
context
.
getPlayerManager
();
const
breakManager
=
playerManager
.
getBreakManager
();
breakManager
.
setBreakClipLoadInterceptor
(
(
breakClip
,
breakClipLoadInterceptorContext
)
=
>
{
// Obtains the URL of a break clip id from a function call.
breakClip
.
contentUrl
=
getUrlFromClipId
(
breakClip
.
id
);
return
breakClip
;
});
Ad Skipping
The Web Receiver SDK provides APIs to skip ad breaks and individual break clips within an ad break. The SDK also allows users to optionally skip break clips by interacting with their sender applications or smart display devices.
User skippable break clips
Setting break clips as skippable allows users to interact with connected sender
applications and smart display devices to optionally skip the rest of a
currently playing break clip. Setting the whenSkippable
property to a non-negative number of seconds will enable this feature for the BreakClip
object. The player will consider the break clip skippable once the
break clip has played for that number of seconds. Setting this value to 0
allows users to skip the break clip immediately.
// Create the BreakClip.
let
clip
=
new
cast
.
framework
.
messages
.
BreakClip
(
'bc'
);
clip
.
title
=
'The Ad Title to be displayed during playback'
;
clip
.
whenSkippable
=
10
;
// Users can skip the clip after 10 seconds of playback.
This information can be set in the sender's original load request or in the receiver app. When skipped, a break clip in a stitched timelinead break will stop playing the current break clip. The player will either load the next break clip if present or load the main content. When skipped, a break clip in an embedded timelinead break will seek to the end of the break clip and continue playback of the stream at that point.
Programmatically skipping ads
Ads can also be skipped automatically without any user interaction.
To skip an entire breakfrom playing, an application should set the isWatched
property of a Break
to true
. This can be done anytime during the load
sequence or content playback. The isWatched
property is evaluated by the
player when a break's position
is met in the main content's current time. At
that point, the player will determine whether or not a break should be entered.
See the sample below which loops through all of the breaks and modifies the
value when the player is loading.
const
context
=
cast
.
framework
.
CastReceiverContext
.
getInstance
();
const
playerManager
=
context
.
getPlayerManager
();
const
breakManager
=
playerManager
.
getBreakManager
();
playerManager
.
addEventListener
(
cast
.
framework
.
events
.
EventType
.
PLAYER_LOADING
,
(
event
)
=
>
{
// Obtain the breaks and iterate through each item to skip all ad breaks.
let
breaks
=
breakManager
.
getBreaks
();
breaks
.
forEach
((
brk
)
=
>
{
brk
.
isWatched
=
true
;
});
});
To skip a specific break clipprogrammatically, the break clip load interceptor
should be used. By
returning null
or not returning a value in the callback function, the clip in
that break will be skipped.
const
context
=
cast
.
framework
.
CastReceiverContext
.
getInstance
();
const
playerManager
=
context
.
getPlayerManager
();
const
breakManager
=
playerManager
.
getBreakManager
();
breakManager
.
setBreakClipLoadInterceptor
(
(
breakClip
,
breakClipLoadInterceptorContext
)
=
>
{
return
null
;
});