Introduction
The Brightcove Live system sends notifications of various events. You can set up listeners for notifications to trigger further actions. The listener(s) can be written in any server-side language you use, and they would look for incoming POST requests, parse the JSON request body, and then take whatever action you want. Below we will see how you can request notifications.
Requesting notifications
You can request notifications by including one or more notifications
fields in the outputs your Create Job request.
The value of notifications
is an array of notification destination objects. You can use a simple string with a url: "https://httpbin.org/post"
, or you can use an object with following options: {"url": "https://httpbin.org/post", "credentials": "reference_to_your_credentials"}
. A notification will be sent to the destination you specify when the output changes its state. If you apply this parameter to a VOD output the notifications will only be related to that VOD job, not to the live job.
Here are some examples:
Notifications for a Live job
{
"live_stream": true,
"region": "us-west-2",
"reconnect_time": 20,
"notifications": [
{"url": "https://httpbin.org/post/URLA",
"credentials": "reference_to_your_credentials",
"event": "first_segment_uploaded"},
{"url": "https://httpbin.org/post/URLB",
"credentials": "reference_to_your_credentials",
"event": "state_changed"}
],
"outputs": [
{
"label": "hls360p",
"live_stream": true,
"height": 360,
"video_bitrate": 650,
"segment_seconds": 6
},
{
"url":"s3://YOURBUCKET/path/filename.mp4",
"credentials": "accConfiguredCredsAWSIdSecret",
"notifications": [
{
"url": "https://httpbin.org/post?vodStateChange"
},
{
"url": "https://httpbin.org/post?vodFinished",
"event": "output_finished"
}
]
}]
}
Notifications for Live to VOD (output_finished
event only)
{
"videocloud": {
"video": {
"name": "video name"
}
},
"notifications": [{
"url": "https://httpbin.org/post?vodFinished",
"event": "output_finished"
}]
}
Notifications for Live to VOD (all events)
{
"videocloud": {
"video": {
"name": "video name"
}
},
"notifications": [{
"url": "https://httpbin.org/post"
}]
}
Retry strategy
In the event of a failed request to send a notification, the default retry strategy is to retry 50 times with an exponential delay between attempts.
max_retry_times = 50
delay_delta_s = 5
next_retry = now_s + retry_count * delay_delta_s
Events
Below are the events of a job lifecycle you can listen for. Note that the event scope is per job, so the event lifecycle for a live job would be separate from the lifecycle for a VOD clipping job based on the same live stream.
state_changed
- the state of the live job changed; see the table below for detailsfirst_segment_uploaded
- the first segment of the live stream is uploaded to originoutput_finished
- the live event has ended, and VOD processing has created at least one audio and one video rendition, or one progressive MP4 rendition
The state_changed
will notify on the following states described in the table below
State | Description |
---|---|
JOB States (reported in notifications as state ) |
|
error |
An error has occurred; the job will not be processed. |
standby |
(Only applicable to Static Entry Point [SEP] jobs.) The job is allocated and ready for activation. |
processing |
The encoder is connected and the job is available for playback. |
disconnected |
The encoder has disconnected and the streaming worker is waiting for a reconnection. |
cancelling |
The job has been cancelled and the worker is stopping the job and will NOT process any pending VOD outputs. |
finishing |
The encoder has been disconnected for more than reconnect_time , and streaming worker is stopping the jobs and creating any associated VOD outputs. |
cancelled |
The job has been cancelled successfully. |
finished |
The job has finished successfully. |
failed |
The job has stopped as a result of a system error. |
VOD JOB States (reported in notifications as jvod_state ) |
|
error |
An error has occurred; the job will not be processed. |
waiting |
The job waiting for processing. |
waiting_finish_live |
The job waiting for the Live Job to finish (if the clip depends on that). |
processing |
The clip is being processed. |
creating_asset |
A VOD asset is being created. |
cancelling |
The job has been cancelled and the worker is stopping the job and will NOT process any pending VOD outputs. |
cancelled |
The job has been cancelled successfully. |
finished |
The job has finished successfully. |
failed |
The job has stopped as a result of a system error. |
SSAI States (reported in notifications as ssai_state ) |
|
none |
The job is not an SSAI job. |
waiting_input |
The streaming worker is waiting for the encoder to connect and provide the stream input information. |
start_transcoding |
The encoder has connected and the SSAI slate has been queued for transcoding based on the stream input data and outputs data. |
transcoding |
The slate is being transcoded. |
error |
The slate could not be downloaded or transcoded. |
ready |
The slate has been generated and the job is ready for SSAI playback. |
SEP States (reported in notifications as sep_state ) |
|
none |
The job is not an SEP job. |
waiting |
The job has been assigned to a streaming worker and ready for the encoder to connect. |
ready |
The entry point has been activated and ready for the encoder to connect. |
pending_activation |
The entry point has been queued for streaming worker assignment. |
activation_in_progress |
The entry point is updating to route connections to the streaming worker. |
pending_deactivation |
The entry point has been queued for cleanup from the streaming worker. |
deactivation_in_progress |
The entry point is disconnecting from the streaming worker. |
cancelled |
The entry point has been cancelled. |
finished |
The entry point has completed successfully. |
RTMP Output States (reported for rtmp_output_state_changed notifications as state ) |
|
starting |
The stream is starting. |
connected |
The encoder has connected. |
Disconnected |
The encoder has disconnected. |
error |
The stream failed to connect. |
pending_deactivation |
The entry point has been queued for cleanup from the streaming worker. |
deactivation_in_progress |
The entry point is disconnecting from the streaming worker. |
cancelled |
The entry point has been cancelled. |
finished |
The entry point has completed successfully. |
Sample notifications
Live stream notification
Here is a sample notification for a state_changed
event for a live job:
{
"outputs": [
{
"rfc_6381_video_codec": null,
"finished_at": "2017-10-19T20:08:11.115Z",
"segment_seconds": 4,
"created_at": "2017-10-19T19:47:04.534Z",
"privacy": false,
"md5_checksum": null,
"audio_codec": "AAC",
"error_class": null,
"updated_at": "2017-10-19T20:08:11.115Z",
"video_bitrate_in_kbps": 2150.4,
"id": "0-621669558be84a7da4ff20bccb9a6a1a",
"state": "cancelled",
"playback_url": "https:\/\/bcovlive-a.akamaihd.net\/621669558be84a7da4ff20bccb9a6a1a\/us-west-2\/NA\/profile_0\/chunklist.m3u8",
"duration_in_ms": 1156873,
"file_size_bytes": null,
"height": 720,
"playback_url_dvr": "https:\/\/bcovlive-a.akamaihd.net\/621669558be84a7da4ff20bccb9a6a1a\/us-west-2\/NA\/profile_0\/chunklist_dvr.m3u8",
"error_message": null,
"video_codec": "H.264",
"audio_bitrate_in_kbps": 196.608,
"fragment_duration_in_ms": null,
"test": false,
"playback_url_vod": "https:\/\/bcovlive-a.akamaihd.net\/621669558be84a7da4ff20bccb9a6a1a\/us-west-2\/NA\/profile_0\/chunklist_vod.m3u8",
"total_bitrate_in_kbps": 2347.008,
"format": null,
"label": "hls720p",
"frame_rate": null,
"video_codec_profile": "high",
"keyframe_interval": 60,
"keyframe_interval_follow_source": false,
"live_stream": true,
"channels": null,
"playback_added_cdns": [
],
"width": 1280,
"rfc_6381_audio_codec": null,
"audio_sample_rate": null
},
{
"rfc_6381_video_codec": null,
"finished_at": "2017-10-19T20:08:11.115Z",
"segment_seconds": 4,
"created_at": "2017-10-19T19:47:04.534Z",
"privacy": false,
"md5_checksum": null,
"audio_codec": "AAC",
"error_class": null,
"updated_at": "2017-10-19T20:08:11.115Z",
"video_bitrate_in_kbps": 1536,
"id": "1-621669558be84a7da4ff20bccb9a6a1a",
"state": "cancelled",
"playback_url": "https:\/\/bcovlive-a.akamaihd.net\/621669558be84a7da4ff20bccb9a6a1a\/us-west-2\/NA\/profile_1\/chunklist.m3u8",
"duration_in_ms": 1156873,
"file_size_bytes": null,
"height": 540,
"playback_url_dvr": "https:\/\/bcovlive-a.akamaihd.net\/621669558be84a7da4ff20bccb9a6a1a\/us-west-2\/NA\/profile_1\/chunklist_dvr.m3u8",
"error_message": null,
"video_codec": "H.264",
"audio_bitrate_in_kbps": 196.608,
"fragment_duration_in_ms": null,
"test": false,
"playback_url_vod": "https:\/\/bcovlive-a.akamaihd.net\/621669558be84a7da4ff20bccb9a6a1a\/us-west-2\/NA\/profile_1\/chunklist_vod.m3u8",
"total_bitrate_in_kbps": 1732.608,
"format": null,
"label": "hls540p",
"frame_rate": null,
"video_codec_profile": "main",
"keyframe_interval": 60,
"keyframe_interval_follow_source": false,
"live_stream": true,
"channels": null,
"playback_added_cdns": [
],
"width": 960,
"rfc_6381_audio_codec": null,
"audio_sample_rate": null
},
{
"rfc_6381_video_codec": null,
"finished_at": "2017-10-19T20:08:11.115Z",
"segment_seconds": 4,
"created_at": "2017-10-19T19:47:04.534Z",
"privacy": false,
"md5_checksum": null,
"audio_codec": "AAC",
"error_class": null,
"updated_at": "2017-10-19T20:08:11.115Z",
"video_bitrate_in_kbps": 819.2,
"id": "2-621669558be84a7da4ff20bccb9a6a1a",
"state": "cancelled",
"playback_url": "https:\/\/bcovlive-a.akamaihd.net\/621669558be84a7da4ff20bccb9a6a1a\/us-west-2\/NA\/profile_2\/chunklist.m3u8",
"duration_in_ms": 1156873,
"file_size_bytes": null,
"height": 360,
"playback_url_dvr": "https:\/\/bcovlive-a.akamaihd.net\/621669558be84a7da4ff20bccb9a6a1a\/us-west-2\/NA\/profile_2\/chunklist_dvr.m3u8",
"error_message": null,
"video_codec": "H.264",
"audio_bitrate_in_kbps": 196.608,
"fragment_duration_in_ms": null,
"test": false,
"playback_url_vod": "https:\/\/bcovlive-a.akamaihd.net\/621669558be84a7da4ff20bccb9a6a1a\/us-west-2\/NA\/profile_2\/chunklist_vod.m3u8",
"total_bitrate_in_kbps": 1015.808,
"format": null,
"label": "hls360p",
"frame_rate": null,
"video_codec_profile": "main",
"keyframe_interval": 60,
"keyframe_interval_follow_source": false,
"live_stream": true,
"channels": null,
"playback_added_cdns": [
],
"width": 640,
"rfc_6381_audio_codec": null,
"audio_sample_rate": null
},
{
"playlist_type": "defaultS3",
"dvr_filename": "playlist_dvr.m3u8",
"filename": "playlist.m3u8",
"playback_url": "https:\/\/bcovlive-a.akamaihd.net\/621669558be84a7da4ff20bccb9a6a1a\/us-west-2\/NA\/playlist.m3u8",
"type": "playlist",
"playback_url_dvr": "https:\/\/bcovlive-a.akamaihd.net\/621669558be84a7da4ff20bccb9a6a1a\/us-west-2\/NA\/playlist_dvr.m3u8"
}
],
"input": {
"finished_at": "2017-10-19T20:08:11.115Z",
"created_at": "2017-10-19T19:47:04.534Z",
"privacy": false,
"md5_checksum": null,
"audio_codec": null,
"error_class": null,
"updated_at": "2017-10-19T20:08:11.115Z",
"video_bitrate_in_kbps": null,
"id": "input-621669558be84a7da4ff20bccb9a6a1a",
"state": "cancelled",
"duration_in_ms": 1156873,
"file_size_bytes": null,
"audio_tracks": null,
"height": null,
"error_message": null,
"video_codec": null,
"audio_bitrate_in_kbps": null,
"test": false,
"total_bitrate_in_kbps": null,
"format": null,
"frame_rate": null,
"url": null,
"channels": null,
"width": null,
"audio_sample_rate": null
},
"event": "state_changed",
"job": {
"event_length": 0,
"static": false,
"finished_at": "2017-10-19T20:08:11.115Z",
"test": false,
"submitted_at": "2017-10-19T19:47:04.534Z",
"created_at": "2017-10-19T19:47:04.534Z",
"privacy": false,
"out_worker_bytes_rate": 0,
"ad_insertion": false,
"metadata_passthrough": false,
"live_stream": true,
"out_worker_bytes": 147114065,
"live_dvr_sliding_window_duration_ms": 57600000,
"updated_at": "2017-10-19T20:08:11.115Z",
"encryption": [
],
"live_dvr_sliding_window_duration_ms": 57600000,
"ssai_state": "none",
"id": "621669558be84a7da4ff20bccb9a6a1a",
"state": "cancelled",
"playback_url": "https:\/\/bcovlive-a.akamaihd.net\/621669558be84a7da4ff20bccb9a6a1a\/us-west-2\/NA\/playlist.m3u8",
"region": "us-west-2",
"reconnect_time": 1800,
"playback_url_dvr": "https:\/\/bcovlive-a.akamaihd.net\/621669558be84a7da4ff20bccb9a6a1a\/us-west-2\/NA\/playlist_dvr.m3u8"
}
}
Clipping to S3 sample
Below is a sample state_changed
event for creating a clip and sending it to an S3 bucket. Note that it includes the S3 address of the clip as jvod_url
.
{
"jvod_id": "b750cce9e21a4cc894c4507208495b0c",
"jvod_url": "s3:\/\/some.bucket\/test_dur60.mp4",
"jvod_created_at": 1517520650785,
"jvod_duration_s": 30,
"jvod_cancelling_flag": false,
"label": "last_30",
"jvod_reported_duration_s": null,
"jvod_finished_at": 0,
"jvod_type": "s3",
"account_id": "a95ac581551b4478b27910e5675db1f8",
"jvod_worker_id": "b55b6fec738e4d2788544d3233b5ecf6",
"user_id": "c2691d4d039040be96c190a949d754a7",
"job_id": "7005c6e07bc24ca7b69b6b9d24052720",
"jvod_last_state_change_at": 1517520652312,
"jvod_region": "us-west-2",
"cloud_id": "301c91a5d9254b5d944b108c355f12be",
"event": "state_changed",
"jvod_state": "processing"
}
Handling notifications
To receive notifications, you simply need an app that can receive HTTP/HTTPS POST
requests. The app can then parse the JSON notifications and do whatever you want based on their contents.
As a simple example, here is a PHP app we use in Brightcove Learning Services to receive notifications and write them to a text file.
<?php
// POST won't work for JSON data
$problem = "No errors";
$notificationType = null;
try {
$json = file_get_contents('php://input');
$decoded = json_decode($json, true);
// turn notification into pretty printed JSON
$notification = json_encode($decoded, JSON_PRETTY_PRINT);
} catch (Exception $e) {
$problem = $e--->getMessage();
$notification = $json;
}
$logEntry = $notification."\n \n";
// Tell PHP where it can find the log file and tell PHP to open it
// and add the string we created earlier to it.
$logFileLocation = "live-log.txt";
$fileHandle = fopen($logFileLocation, 'a') or die("-1");
fwrite($fileHandle, $logEntry);
fclose($fileHandle);
// line below is displayed when you browse the app directly
echo "Live callback app is running";
?>
Notes
- In certain cases, identical notifications will be sent more than once. If your handler is taking actions (apart from simple logging) based on notifications, you should configure it to check for duplicates (multiple notifications with the same
id
andstatus
) and ignore them.
Set up notifications in the Live module
To set up notifications for a live event created in the Live Module, you will need to do the following:
- Create a handler application that can receive POST requests like the PHP app shown in the previous section.
- Host the app on a public URL.
- When you create your live job in the Live module, expand the Advanced Options.
- Check the Enable stream status notifications option and enter the URL for your handler app: