Skip to main content

Integrating Stream Providers with Maestro

This document can be followed by live-streaming providers to add live streaming capabilities for the Maestro platform.

Maestro supports a range of live streaming providers. To add your live-streaming capabilities to the platform, Maestro require the following minimal capabilities:

  1. RTMP Ingest
  2. Live HLS output
  3. CDN storage for live and recorded on-demand (VOD) assets

Below is a sequence diagram describing Maestro's standardized streaming provider integration workflow.

Optional workflows omitted

Registration

Registering your Streaming Provider Contract

Stream Provider -> Maestro

curl -X POST https://api.maestro.io/streamprovider/v1/register
-d {
"name": "my awesome streaming provider",
"urls": {
"createStream": "https://my.api/create",
"deleteStream": "https://my.api/delete",
"deleteVod": "https://my.api/assets/delete",
"startStream": "https://my.api/start",
"stopStream": "https://my.api/stop",
"verifyAccount": "https://my.api/verify" // required if useAccount: true
},
"accountCredentials": {}, // required if useAccount
"useAccount": false,
}

Response:

{
"id": "0866047ea2e84b41a58fa1b4a3b23687",
"authorization": "b0612f9f-03a8-4f59-9cb3-c7429b57c228"
}

‌ Save the authorization value in your database. That value must be present in the authorization header as a Bearer token to all requests back to Maestro, including webhooks, VOD’s, and making modifications to a provider contract that has already been registered (contracts are unique by name). The authorization does not expire and will be used for the lifetime of the registered provider.

Create Stream

Receiving a create stream request‌

Maestro -> Stream Provider‌

curl -X POST <your urls.createStream>
-d {
"fallbackImageUrl": "https://cdn.com/slate-image.jpg",
"title": "Baking with Bob",
"accountCredentials": {} // optional, see next section
}

title - A unique string identifier for the live stream.

fallbackImageUrl - A public URL for a static image asset for the transcoder output to fallback to in the case of an interruption in the stream ingest. This image should be the output of the live HLS during an encoder reconnect window.

Your Response:

{
"ingestUrl": "rtmp://some-ingest-url",
"streamKey": "02b1fa17fa634848d98306914b3f901bdb",
"playbackUrl": "https://url-user-can-use-to-view-stream",
"providerStreamId": "3b6d1467-55ad-4fc1-a89f-a259f55c1fba",
}

‌ `providerStreamId`` should be a unique identifier (GUID) to identify the stream (or a particular set of resources) on the stream provider side. In the remaining parts of the streaming workflow, Maestro’s API’s will use this ID to make requests to the streaming provider service.

Creating a stream using an existing client account

(Optional feature. To enable support register with useAccount: true )

Stream creation assumes usage would be billed to a master Maestro account. If you would like to support creating the streams using an existing customer’s account rather than the Maestro account, register the provider with option useAccount: true. If not, this section can be skipped.

Additional Requirements

  1. An accountCredentials value will be required in the registration payload.

This map is how a streaming provider defines which account data are required in order to create the stream on the client’s account. The createStream request will include this data in the payload. The schema for this map should be:

accountCredentials { 
[credentialName: string]: label as string,
}
  • credentialName keys will be reused by Maestro in the verifyAccount & createStream payloads (camelCase preferred).
  • The label will be used as an input field label in the Maestro UI for a client to connect their account details. This text will be rendered to the Maestro admin, so please keep it short and formatted (capitalize appropriately, no punctuation, etc.).

Example registration payload with useAccount feature enabled:

{
"name": "bill my customers",
"accountCredentials": {
"accountId": "Account ID",
"apiKey": "API Key",
},
"useAccount": true,
"urls": {
...
}
}

Example createStream request including accountCredentials :

curl -X POST <your createStream endpoint>
-d {
"title": "my stream",
"accountCredentials": {
"accountId": "123456789",
"apiKey": "h2fx-kc8ae-m02v"
}
}
  • If the accountCredentials in the createStream request are not valid, return 401
  • If the account is valid but the stream cannot be created for another reason, such as resource limitations, return 403 status

‌2. If the useAccount feature is enabled, the urls map in the registration must include verifyAccount. This endpoint will be utilized by Maestro to test the validity of a set of account details.

Example request:

curl -X POST <your verifyAccount url>
-d {
"accountCredentials": {
"accountId": "123456789",
"apiKey": "h2fx-kc8ae-m02v'
}
}

Responses:

  • Valid account: respond with 200 status code
  • Invalid account: return 401 status code

Start Stream

Receiving a start stream request

At the time of the request to start a stream, all content ingested from then forward should be recorded for later VOD playback. Note that the broadcaster can be previewing their stream before the startStream request. The HLS should be live as soon as the stream is ingesting.

curl -X POST <URL you provided for "startStream">
-d {
"id": "3b6d1467-55ad-4fc1-a89f-a259f55c1fba",
"liveBroadcastId": "9e68e4c3-997c-4e84-b59a-ff083daa5511"
}
  • id is the providerStreamId returned from the request to create the stream.
  • The liveBroadcastId is generated by Maestro to identify the broadcast. Cache it and return it with the VOD asset (see below).

Stop Stream

Receiving a stop stream request

‌The Stop Stream request should end the VOD recording, but leave the underlying stream / transcoder active. Content ingested after this request should not be added to the recorded VOD playlist.

curl -X POST <URL you provided for "stopStream">
-d {
"id": "3b6d1467-55ad-4fc1-a89f-a259f55c1fba"
}

VOD Delivery

Sending a recording to Maestro

‌The request to stopStream finalizes the recording, so at this point a URL to the recorded VOD asset should be delivered back to Maestro.

Stream Provider -> Maestro

curl -X POST https://api.maestro.io/video/v3/vod
-H "Authorization: Bearer b0612f9f-03a8-4f59-9cb3-c7429b57c228"
-d {
"durationSeconds": 300,
"liveBroadcastId": "9e68e4c3-997c-4e84-b59a-ff083daa5511",
"vodId": "<my-unique-asset-id>",
"streamId": "3b6d1467-55ad-4fc1-a89f-a259f55c1fba",
"url": "https://some-cdn/some-playback-url",
}

The Bearer token GUID is the authorization value returned to the stream provider from the request to /register.

The liveBroadcastId returned to Maestro should be the same value from the startStream request that initiated the VOD recording.

vodId should be a unique GUID to use to reference a recording within the streaming provider service. The streaming provider should create an ID for a recording after it has been added to CDN storage and deliver that to Maestro’s video API with the url .

Delete (Disable) Stream

Receiving a delete stream request

A request from Maestro to delete a stream should ensure that a client encoder can no longer connect to the resources designated by the stream id. It should effectively block the ingest for that stream key and halt transcoding. The internal method of stopping the ingest is up to the provider, but the end result should be that all transcoding is disabled for that stream.

curl -X POST <URL you provided in "deleteStream">
-d {
"id": "3b6d1467-55ad-4fc1-a89f-a259f55c1fba"
}

Delete VOD

Cleaning up a VOD Recording

The deleteVod endpoint should remove all recorded assets from storage for a specific live broadcast. This is different from the deleteStream endpoint which disables an ingest.

The id should point to a vodId that has already been delivered to Maestro using the video/v3/vod endpoint.

curl -X POST "<my deleteVod endpoint>"
-d {
"id": "a-unique-vod-id"
}
note

There is no UI in Maestro to trigger the delete Stream/VOD requests from Maestro. In order to complete integration testing, there are two endpoints available to test these requests.

Sending Webhooks to Maestro

‌Full integration as a Maestro Streaming Provider requires the provider to POST webhook event payloads to Maestro regarding the state of a stream.

This should happen for all streams created using the streaming provider contract, regardless of whether the stream was created on the Maestro account or a mutual customer’s account.

The provider's requests should be triggered when:

  • A source encoder either connects to or disconnects from provider rtmp url
  • When the live HLS manifest designated by the playbackUrl either has content to view or is empty/dead.

Webhook Types

TypeDescription
“connected”Source encoder has connected
“active”Live HLS manifest has data, playback url does not 404
“disconnected”Source encoder has disconnected
“idle”Live HLS manifest is empty, playback url is “dead”

For all broadcasts, webhooks should be delivered in the above order. In the event of a non-200 response, use exponential retry backoff.

When thinking about event types, the important thing to remember is that the "connected" /"disconnected" events are concerning the source encoder → rtmp ingest connection state, while the "active" / "idle" events denote the playback and usually transcoder state.

curl -X POST https://api.maestro.io/stream/v1/webhook
-H "Authorization: Bearer b0612f9f-03a8-4f59-9cb3-c7429b57c228"
-d {
"type": "active" | "idle" | "connected" | "disconnected",
"id": "3b6d1467-55ad-4fc1-a89f-a259f55c1fba",
"time": 1613242238573, // unix epoch timestamp in milliseconds
}

Activate Stream (Optional)

note

It may not be necessary for all streaming providers to use the “activate” workflow.

In the case that a stream must be “activated” in order for the rtmp ingest to accept an incoming connection, the provider contract can support this by adding an activateStream endpoint to the urls map.

Additionally, if the implementation of the provider deleteStream url disables the livestream ingest, this route should be used to re-enable that ingest.

Example registration:

{
"name": "transcoder provider name",
"urls": {
...
"activateStream": "https://my.api/activate",
}
}

Example activateStream request:

curl -X POST <activate stream url>
-H 'Authorization: Bearer <your auth token>`
-d {
"id": <your provider stream id>
}
  • Duplicate requests can be ignored. i.e. an activateStream request for an already active stream can be ignored (return 200)
  • Streams should be automatically deactivated by the streaming provider based on an acceptable timeout period. A minimum window of 5 minutes should be allowed for an encoder to reconnect to an ingest before deactivating it.
    • Note that deactivating the stream (stopping / cleaning up the transcoder) is different than disabling the stream (blocking the ingest)