Live API: Cue Points and Ad Beacons with SSAI
Overview
Server-side ad insertion (SSAI) allows you display ads during a live streaming event at specified times. For general information, see the Live API: Server-Side Ad Insertion (SSAI) document.
Cue points
Ad breaks are triggered by cue points, which can be specified in two ways:
- Sent to Brightcove by the encoder
- Immediate cue points created via the Live API
From the encoder
The Brightcove live delivery system can interpret cue points submitted by the encoder in the AMF format:
AMFDataList
[0]:onCuePoint
[1]:{Obj[]:
time: 1.9889, //Difference from PTS of THIS packet to the first PTS of the 1st video frame in the adbreak
name: "scte35",
type: "event",
ad_server_data: "eyJrZXkiOiJ2YWx1ZSJ9", // optional introduced by Brightcove. It is a base64 encoded json map of
parameters e.g. {"key":"value"}
parameters: {Obj[]:
type: "avail_in",
duration: 12.0
}
}
Notes:
- Since timecodes are expressed in HH:MM:SS, there is no notion of what day is meant. This can lead to problems such as sending cue point at 23:55:00 for an ad break to start at 00:01:00 and having the server interpret that as almost 24 hours ago. Brightcove has implemented a fix for this as follows: for cue points arriving between 23:50:00 and 00:00:00 only, we will assume you are scheduling an ad break for the following day.
- Up to 128 cue points can be stacked in a single request, but given the rules around "rollover" explained above, cue points cannot be sent in this manner for the following day.
- Since SMPTE timecodes are associated with the stream, it is possible that a cue could arrive after the scheduled time in the stream. Brightcove will allow up to a 5 seconds tolerance after the cue to still insert a Cue point.
- Only
avail_in
andavail_out
type cue points are currently supported in RTMP input. - SCTE-35 cue points are supported in RTP and SRT inputs.
Manual cue point insertion
You can create immediate cue points for a job or a redundant group using the Live API
by sending a POST
request:
Method | POST |
---|---|
URL (for a job) | https://api.bcovlive.io/v1/jobs/{Job_ID}/cuepoint |
URL (for a redundant group) | https://api.bcovlive.io/v1/jobs/{Redundant_Group_ID}/cue point |
Header | X-API-KEY: {your API
KEY} |
Include a request body specifying the following:
Field | Type | Description |
---|---|---|
duration |
Integer | Duration of the break in seconds. The duration of the cue point being inserted needs to be at least twice the length of the segments in the job. See the duration example. |
timecode |
SMPTE format | OPTIONAL: A timecode in SMPTE format, HH:MM:SS:FF (FF = frames), to
specify when a set of any variables (key/value pairs) should be passed to the adServer. If omitted, the cue point will be inserted immediately. If you use the timecode property, the encoder must be sending SMPTE-formatted ( HH:MM:SS:FF ) timecode stored in the tc property via
OnFI . Timecodes are from the start of the live stream.
|
ad_server_data |
Object | OPTIONAL: The key/value pairs you pass will depend on the ad server you are using. For more details, see your ad server documentation and the Targeting ads using ad macros section. |
cuepoint_id |
String | OPTIONAL: Optional. ID to use when creating cue point. If cancel is true , then this field is
required and is the ID of cue point to cancel. |
cancel |
Boolean | OPTIONAL: Optional. Default: false . When true , cue point specified by cuepoint_id will be
canceled. If the ad break is already in progress, a crash-out will occur, returning to the main content.
|
Duration example
The duration of the cue point being inserted needs to be at least twice the length of the segments in the job.
For example, inserting a 10 second cue point in a job with "segment_seconds"=4
, will work fine. However, inserting the same cue point in a job with
"segment_seconds"=6
will result in the following error:
"error": "The parameter duration should be greater than
or equal to (2 * target duration) of the job"
Sample request body
{
"duration": 30,
"timecode": "15:50:49:16",
"ad_server_data" : {
"adbreakid": 12312
"breaktheme": "fitness"
}
}
Notes
- Software encoders such as Wirecast and OBS do not support the sending timecode via
OnFI
packets in the RTMP stream - Elemental hardware encoders do support the sending timecode via
OnFI
packets in the RTMP stream
Sample response
{
"id": "Job_ID",
"cue_point": {
"id": "adBreak-2f58393ada1442d98eca0817fa565ba4",
"duration": 30,
"accuracy": "segment", [Can be segment
or frame
]
"inserted_at": "2017-07-21T09:30:46.307Z" [ Time when the cue point was inserted in the stream]
},
}
Beacons
Beacons are data points on playback sent to third-party analytics to track whether and how much of ads were played. In this section we will look at the beacon types that can be set using the Live API, and variables that can be used to provide the data. The next section will detail the API requests use to create and manage beacon sets.
Beacon types
Beacon Type | Description |
---|---|
Load |
Fired once per session and only triggered when top level manifest is requested |
Play |
Content has been requested and the first segment returned |
Heartbeat |
Target duration (segment seconds) |
AdStart |
Individual ad started |
AdFirstQuartile |
First ad quartile (25%) |
AdMidpoint |
Second ad quartile (50%) |
AdThirdQuartile |
Third ad quartile (75%) |
AdComplete |
Individual ad completed |
AdBreakStart |
Ad break has started |
AdBreakComplete |
ad break has ended |
Beacon/Ad variables
The table below shows the variables you can use to provide data for the beacon URLs. To include a variable,
surround with double curly braces, like this: {{job.job_id}}
. See the next section
on managing beacon sets for full examples.
Variable |
Description
|
---|---|
session.session_id |
unique session id
|
job.job_id |
unique job id
|
videocloud.video_id |
Only available for jobs created with a VideoCloud video.
|
application_ad_configuration.description |
value of the application at session creation
|
random.int32 |
random 32-bit signed integer
|
random.int64 |
random 64-bit signed integer
|
random.uint32 |
random 32-bit unsigned integer
|
random.uint64 |
random 64-bit unsigned integer
|
random.uuid |
random uuid
|
server.timestamputc |
epoch time in milliseconds when the call from the ads-api has been made
|
client.useragent |
http user-agent header value at session creation
|
client.ipaddress |
http x-forwarded-for header value at session creation, if provided,
otherwise the remote address
|
client.referrer |
http referer header value at session creation (note: that is the correct
spelling)
|
client.referer |
http referer header value at session creation (http spelling)
|
client.ipuaid |
hash value of client.ipaddress and client.useragent
|
live.adbreak |
(currently unused)
|
live.adbreakdurationms |
Ad break duration in milliseconds
|
live.adbreakduration |
Ad break duration in double-precision floating-point seconds
|
live.adbreakdurationint |
Ad break duration in integer seconds
|
live.adbreak.timestamputc.wallclock |
epoch time in milliseconds when the call to the ads server has been made
|
live.adbreak.timestamputc.origin |
epoch time in milliseconds from the origin chunklist. This value
indicates the time when the cue out chunk has been created in the origin chunklist.
|
live.adbreak.timestamputc.session |
epoch time in milliseconds from the ssai chunklist. This value indicates
the time of the cue out chunk in the ssai chunklist. Since the adbreak content and the adbreak gap are NOT
usually the same, after the 1st adbreak the
live.adbreak.timestamputc.origin
is different from live.adbreak.timestamputc.session . This value takes into
account the time adjustments that have been made in the SSAI chunklist. |
SCTE-35 ad variables
The Society of Cable Telecommunications Engineers (SCTE) defines a standard for dynamic ad insertion for live streams. An SCTE-35 ad marker defines the timestamp and duration where an ad can be inserted into the stream.
If parsed from SCTE-35, the following configuration variables can be applied to your ad tags:
Variable |
Description
|
---|---|
{{scte35_eventID}} |
an unique event id passed with an SCTE35 message.
|
{{scte35_programID}} |
A unique program id passed with an SCTE35 message.
|
{{scte35_availNum}} |
An id for a specific splice time available for ads, send via a SCTE35
message.
|
{{scte35_breakDuration}} |
Break duration for the ad break, in terms of ticks of the program’s 90
kHz clock, passed with a SCTE35 message.
|
{{scte35_spliceTime}} |
Splice time for an ad break, in terms of ticks of the program’s 90 kHz
clock, passed with a SCTE35 message.
|
As part of the HLS manifests, the SCTE-35 messages are also base64 with the variables in JSON. For example:
{"scte35_eventID": somevalue, "scte35_programID":
somevalue}
Managing beacon sets
This section provides details on the API requests to manage beacon sets. See the previous section for beacon types and variables.
To add a beacon set to a Live job, first create the beacon set, and then include the id when you create the job, like this:
{
"live_stream": true,
"region": "us-west-2",
"reconnect_time": 30,
"ad_insertion": true,
"beacon_set": "beacon_set_id", ...
Create a beacon set
To create a beacon set, send a POST
request:
Method | POST |
---|---|
URL | https://api.bcovlive.io/v1/ssai/beaconsets |
Header | X-API-KEY: your API KEY
|
Sample request body
{
"account_id": "User's Account ID [Optional]",
"beacon_urls": [
{
"beacon_url":
"https://myserver.com/beaconRX/{{job.job_id}}/load?position=load&sid={{session.session_id}}&jid={{job.job_id}}&app={{application_ad_configuration.description}}&rnd32={{random.int32}}&rnd64={{random.int64}}&bid={{random.uuid}}&t={{server.timestamputc}}&ua={{client.useragent}}&ip={{client.ipaddress}}&ref={{client.referrer}}&ref={{client.referer}}&ab={{live.adbreak}}&abd={{live.adbreakduration}}&abdi={{live.adbreakdurationint}}",
"beacon_type": "Load"
},
{
"beacon_url":
"https://myserver.com/beaconRX/{{job.job_id}}/play?position=play&sid={{session.session_id}}&jid={{job.job_id}}&app={{application_ad_configuration.description}}&rnd32={{random.int32}}&rnd64={{random.int64}}&bid={{random.uuid}}&t={{server.timestamputc}}&ua={{client.useragent}}&ip={{client.ipaddress}}&ref={{client.referrer}}&ref={{client.referer}}&ab={{live.adbreak}}&abd={{live.adbreakduration}}&abdi={{live.adbreakdurationint}}",
"beacon_type": "Play"
}
]
}
Sample response
{
"beacon_set": {
"beacon_urls": [{
"beacon_url":
"https://myserver.com/beaconRX/{{job.job_id}}/load?position=load&sid={{session.session_id}}&jid={{job.job_id}}&app={{application_ad_configuration.description}}&rnd32={{random.int32}}&rnd64={{random.int64}}&bid={{random.uuid}}&t={{server.timestamputc}}&ua={{client.useragent}}&ip={{client.ipaddress}}&ref={{client.referrer}}&ref={{client.referer}}&ab={{live.adbreak}}&abd={{live.adbreakduration}}&abdi={{live.adbreakdurationint}}",
"beacon_type": "Load"
},
{
"beacon_url":
"https://myserver.com/beaconRX/{{job.job_id}}/play?position=play&sid={{session.session_id}}&jid={{job.job_id}}&app={{application_ad_configuration.description}}&rnd32={{random.int32}}&rnd64={{random.int64}}&bid={{random.uuid}}&t={{server.timestamputc}}&ua={{client.useragent}}&ip={{client.ipaddress}}&ref={{client.referrer}}&ref={{client.referer}}&ab={{live.adbreak}}&abd={{live.adbreakduration}}&abdi={{live.adbreakdurationint}}",
"beacon_type": "Play"
}],
"beacon_set_id": "Inserted Beacon Set ID",
"account_id": "USER's ACCOUNT ID"
}
"inserted": true
}
Update a beacon set
Updating a beacon set is similar to creating one. Submit a PUT
request:
Method | PUT |
---|---|
URL | https://api.bcovlive.io/v1/ssai/beaconsets/beaconset/beacon_set_id |
Header | X-API-KEY: your API KEY
|
Sample request body
{
"account_id": "User's Account ID [Optional]",
"beacon_urls": [
{
"beacon_url": "https://myserver.com/beaconRX/load",
"beacon_type": "Load"
},
{
"beacon_url": "https://myserver.com/beaconRX/play",
"beacon_type": "Play"
}
]
}
Sample response
{
"beacon_set": {
"account_id": "User's Account ID",
"beacon_set_id": "Beacon set ID",
"beacon_urls": [{
"beacon_url": "https://myserver.com/beaconRX/load",
"beacon_type": "Load"
},
{
"beacon_url": "https://myserver.com/beaconRX/play",
"beacon_type": "Play"
}],
"updated_beacon_set": {
"beacon_set_id": "Beacon set ID",
"beacon_urls": [{
"beacon_url": "https://myserver.com/beaconRX/load",
"beacon_type": "Load"
},
{
"beacon_url": "https://myserver.com/beaconRX/play",
"beacon_type": "Play"
}],
"account_id": "User's Account ID"
}
}
}
Get beacon sets
To retrieve the beacon sets for an account, submit a GET
request:
Method | GET |
---|---|
URL | https://api.bcovlive.io/v1/ssai/beaconsets/account/Account ID |
Header | X-API-KEY: your API KEY
|
Sample response
[{
"account_id": "User's Account ID",
"beacon_set_id": "Beacon set ID1",
"beacon_urls": [{
"beacon_url": "https://myserver.com/beaconRX/load",
"beacon_type": "Load"
}]
},
{
"account_id": "User's Account ID",
"beacon_set_id": "Beacon set ID2",
"beacon_urls": [{
"beacon_url": "https://myserver.com/beaconRX2/load",
"beacon_type": "Load"
},
{
"beacon_url": "https://myserver.com/beaconRX2/play",
"beacon_type": "Play"
}]
}]
Get beacon sets for requesting user
You can also get the beacon sets for the account of the requesting user without including the account id in the request URL:
Method | GET |
---|---|
URL | https://api.bcovlive.io/v1/ssai/beaconsets |
Header | X-API-KEY: your API KEY
|
Sample response
[{
"account_id": "User's Account ID",
"beacon_set_id": "Beacon set ID1",
"beacon_urls": [{
"beacon_url": "https://myserver.com/beaconRX/load",
"beacon_type": "Load"
}]
},
{
"account_id": "User's Account ID",
"beacon_set_id": "Beacon set ID2",
"beacon_urls": [{
"beacon_url": "https://myserver.com/beaconRX2/load",
"beacon_type": "Load"
},
{
"beacon_url": "https://myserver.com/beaconRX2/play",
"beacon_type": "Play"
}]
}]
Get a beacon set by id
To retrieve a single beacon set by its id, submit a GET
request:
Method | GET |
---|---|
URL | https://api.bcovlive.io/v1/ssai/beaconsets/beaconset/beacon_set_id |
Header | X-API-KEY: your API KEY
|
Sample response
{
"account_id": "User account ID",
"beacon_set_id": "Beacon set ID",
"beacon_urls": [{
"beacon_type": "Load",
"beacon_url": "https://myserver.com/beaconRX2/load"
},
{
"beacon_type": "Play",
"beacon_url": "https://myserver.com/beaconRX2/play"
}]
}
Delete a beacon set
Finally, to delete a beacon set, send a DELETE
request:
Method | DELETE |
---|---|
URL | https://api.bcovlive.io/v1/ssai/beaconsets/beaconset/beacon_set_id |
Header | X-API-KEY: your API KEY
|
Sample response
The response will look like this:
{
"beacon_set_id": "Beacon set ID",
"deleted": true
}
Appendix
Below is a screenshot to show a sample cue point setup for the Elemental encoder.