Enabling SimSub

If you are a TV service provider and that the legislation in your country requires to implement Simultaneous Substitution as it is required in Canada, you are in the right place!

Simultaneous Substitution (SimSub)

For those who are not familiar with the term, Simultaneous Substitution is a concept invented in order to answer to regulatory Broadcasting rules in some countries such as Canada or the United states. Its purpose is to force the delivery of a content or event by a local Broadcaster, when the content is available both on an international and on local Television channels within the TV provider service plan. The end goal behind this is to ensure that Broadcasters can benefit from advertising revenues as well as keeping advertising money in the local market.

Let's take the example of an NFL game from which a Canadian Broadcaster has acquired the rights to broadcast in Canada. At the same time, the usual NFL games American Broadcaster also has the rights to broadcast this very same game to its own audience, or to the audiences of distributors which purchased the right to broadcast the channel. Some of these distributors in fact, are Canadian TV service providers.

De facto, a person who would subscribe to the TV service of a Canadian provider which is distributing the American channel, without the Simultaneous Substitution concept, would have access to the game on two different channels, the local Canadian Broadcaster channel, and the channel from the American Broadcaster. With the regulatory rules applied in Canada, TV service providers have to replace the content of the American channel, with the content of the local Canadian Broadcaster, over the period of time of the game, including advertisements. Therefore, no matter which channel a subscriber is tuned into, they will watch the NFL game and advertisements from the local Canadian Broadcaster.

2012

Schedule of a Canadian TV service provider

In this article, we explain how a TV service provider can leverage broadpeak.io technology to implement simsub and be compliant with regulations.
The first part explains how to implement the simplest way of doing simsub, with all users of a channel audience are being switched to a local alternate content. In a second part, we will explain how simsub can also be applied to a set of specific Audiences, so each audience can be switched to their own local version of the Channel. This second use case allows Canadian TV service provider to deliver local advertising to the right audience (local).

For more information about the use case(s), there are several blog posts which explains very well the concept such as Simsub, a case for broadpeak.io or how mid-size US cable operators can compete in this new era of tv services

What you need to implement this playbook:

  • A broadpeak.io account. You can register here, it's free!
  • Some live content. Optimally two sources, an original and replacement stream prepared in a same way
  • A CDN configuration access to set the right routes and caching policies for media segments and manifests.
  • A scheduling system, or an API client (Postman, Insomnia)/a terminal with Curl command available to simulate the scheduling. You can also use our knowledge center to send API calls and simulate the scheduling in a first step.

Part 1 - Unconditional substitution

1. Identifying the live channels subject to substitution

As a TV service provider the first thing is to identify what channels are subject to see their content being replaced, and what channels are subject to replace content. In our example of a Canadian TV service provider, the American channel would be subject to being replaced by the Canadian channel.

For the sake of simplicity and to quote no names, we will call the American channel, Channel A, and the Canadian channel, Channel C.

TV providers in Canada would then need to have Channel A being replaced by Channel C during the period of the NFL game.

2. Preparing the live streams for substitution

When performing content replacement in HLS, it is critical that original and replacement Sources are prepared in the same way. The content must be compatible with each other to avoid disturbing the players and ensure a great quality of experience. We invite you to read the Content-Replacement guidelines article to ensure that both original and replacement Sources are compatible and that they follow broadpeak.io's input requirements

broadpeak.io generates manifests which contain multiple periods in MPEG-DASH and discontinuities in HLS as stated in the Manifest manipulationsection.

3. Creating live Sources in broadpeak.io

These two channels, Channel A and Channel C, have to be defined as Source in broadpeak.io. Assuming that you only have one streaming link per channel and per format (DASH and HLS), you would have to create two Sources per channel. To do so, navigate to the Sources tab in the web app, and click on CREATE NEW:

DASH

You can define Channel A Source for MPEG-DASH at this stage by selecting, or filling the required fields:

The url status should turn green if the platform can access the content.

HLS

You can repeat the same steps to define Channel A for HLS as a Source. The same field as previously need to be filled:

🚧

Handling several Outputs

Most TV service providers generate different streaming links for the same channel, each of which is supposed to address a specific set of devices (mobiles, STB, desktops...) being used by their subscribers. Each streaming link usually points to a specific output configuration (codecs, packaging format and media containers).

If this is also your case, you have to create a broadpeak.io Source for each of these variants.
We recommend you to name each Source meaningfully.

You can repeat this step 3 to also define Channel C as MPEG-DASH and HLS Sources in broadpeak.io .

At the end of this step, you should have at least two sources defined, pointing to Channel A and Channel C. If you have several outputs for each of these channels, you should define as many Sources as you have outputs for each channel.

📘

Automate this step through the API

You are currently handling a high number of live channels?
broadpeak.io has a REST API that you can use to automate the creation of your channels as Sources.
The API reference for Source creation is available here

4. Defining Content Replacement Services to activate simultaneous substitution

Now that Sources have been defined, we can create a Content Replacement service in broadpeak.io . It might appear weird at first to define a Content Replacement service in a Simsub use-case, but we are actually leveraging the Content Replacement technology to build this usecase!

In this section, we explain how to create Content Replacement Services for a single simsub channel - channel A, but obviously you can replicate the same steps to create more Services so other channel can benefit from Simultaneous substitution.
Alright, let's get started, navigate to the Services tab in the web app, and click on CREATE NEW.

In our use case, we need to replace the NFL games on the American Channel (Channel A), when these very same games are available on the Canadian Channel (Channel C).

MPEG-DASH

When using the web app User Interface, Service creation is done in three steps:

  1. Specifying Content Replacement services characteristics (Name, original Source, ...)
  2. Service review and deployment.
4.1 Specifying Services characteristics

We start with defining a service for MPEG-DASH, and we need to fill the required fields:

  • Service type: set this to Content Replacement
  • Service name: set a meaningful name for this Service - here we will call it mySimsubService_DASH
  • Environment tags (optional): set a tag according to your preference, prod should be used when the service is ready to go live.
  • Original content: this is the American channel on which we want to substitute content. Here we need to choose ChannelA_DASH.
  • Default replacement content: this is the Canadian channel which is used as a substitute content. Here we need to choose ChannelC_DASH.

📘

Activating substitution using multiples channels as substitutes over different periods

In this rather simple example, it might appear as if a Content Replacement service can only substitute content of a live channel by a single other live channel. In fact, the default replacement content is only used when no substitute Source is specified by the scheduler.
It is possible to define multiple Sources in broadpeak.io and to create a Service which allows you replace a same channel with different content from multiple Sources, over different period of time.
Head to Part 2 of this article for more details.

From there, your are ready to go to the next step, and click on NEXT.

4.2 Service review and deployment

This page is a summary of the Service which is about to be created with all the information specified until now.
The Review section contains information about the Name, Tags, Original content and Replacement content specified for this Service.
The Output Information section contains the streaming link which needs to be used to retrieve the Manifest for this Service.
That link will be used to configure your Content Delivery Network in the next steps, so copy/paste it somewhere for now.

If you are happy with the info you have entered, then you can click RUN to deploy your Service. It usually takes a couple of seconds (up to 15s) for your Service to be fully deployed.

Now, we invite you to do the same process with HLS.

HLS

Create a new Content Replacement service and fill the required fields:

  • Service type: set this to Content Replacement
  • Service name: set a meaningful name for this Service - here we will call it mySimsubService__HLS
  • Environment tags (optional): set a tag according to your preferences, prod should be used when the service is ready to go live.
  • Original content: this is the American channel on which we want to substitute content. Here we need to choose ChannelA_HLS.
  • Default replacement content: this is the Canadian channel which is used as a substitute content. Here we need to choose ChannelC_HLS.

At the end of this step 4, you should have two Content Replacement services, one for each format, HLS and MPEG-DASH.

5. Verifying that Services are functional

🚧

Preview only works with non-encrypted content

If you are using free-to-air original and replacement content, then the Preview page can help you verify that the Service created is operating as expected.
In the event you are using encrypted content, the player of the Preview page is not going to work as the player will not decode the content. We invite you to directly check that the expected behavior is correct within the Manifests delivered.

5.1 Using the Preview page (non-encrypted content)

From here, it is interesting to validate that our services are working as expected before moving to the next steps. Head to the tab Services and on the line of one of the Content Replacement Service that you just created, click the eye icon.

The Preview page provides two players, one on the left hand side configured to play the original content, and one on the right, configured to play the Content Replacement Service that you just created. It is possible through a button to create a Slot so we can observe the switch from the original content to the default replacement content specified at Service creation.

When landing on the Preview page, it is expected that both players are actually playing the same content, the original content. If you are experiencing some issues playing the stream at this stage, we invite you to verify that the original Source is available through the specified streaming link.

If both sources are playing the original content, click CREATE A CONTENT REPLACEMENT SLOT. This has for effect to send an API call to broadpeak.io backend to generate a slot for this service in 30 seconds for now. You should be able to experience the switch from original content to replacement content once thoses 30 seconds have elapsed (+ player buffering).

In the case the switch from original content to the default replacement content is not happening, we invite you to consult the Troubleshooting page.

Once you can experience the switch, then you are ready to move to the next step and configure your CDN.

📘

Fun fact!

In our documentation, slots are always called "Content Replacement slots". This can be misleading here since we want to perform Simultaneous Substitution slot, but here we are leveraging the Content Replacement application to enable a content replacement scenario :).

6. Configure your Content Delivery Network for Simsub delivery.

The recommended way of implementing broadpeak.io in your media delivery ecosystem is to have it seated in between your Origin function and your CDN function.
For more information about how broadpeak.io operates and why using a CDN, we invite you to consult the Content Replacement with a CDN section.

When configuring your CDN, it is important to follow two majors rules:

  1. CDN should only go fetch Manifests from broadpeak.io.
  2. Media segment from the original and replacement content must be retrieved by the CDN directly to the Origin. If you are using different Origins for Channel A and Channel C, then the CDN must be configured to fetch content respectively to their own origin.
6.1 Configuring CDN for Manifest requests

In our case, we have created two Content Replacement Services one for DASH, and one for HLS. At the end of the creation process, I have been given two streaming links, one for DASH and the other for HLS:

🚧

Generated streaming links change

When implementing this playbook with your own content and defining your own Services and Sources, you will notice that streaming links generated for your Services are different than the ones generated in our use-case. This is normal and expected, the URI contains a hash which makes it unique per Service.

We need to configure the CDN so all requests that match 7647966b7343c290d6dd5403458c95a3/channelA/output/manifest.mpd or 7647966b7343c29054d43754e025d160/channelA/output/index.m3u8 must go to broadpeak.io FQDN:

Configuration:

  • Origin: stream.broadpeak.io
  • Protocol: HTTPS
  • Behaviors / Rules to match for HLS: /channelA/output/index.m3u8
  • Behaviors / Rules to match for DASH: /channelA/output/manifest.mpd

Some query parameters are introduced by broadpeak.io, so make sure the CDN policies allow these parameters to be forwarded on manifest requests. More information is available on the page Forwarding query param from the CDN to broadpeak.io to know more about which parameters to whitelist.

6.2 Configuring CDN for Media segments.

In our example for Channel A and Channel C, both content are originated by the same origin server "origin.video". We need to make sure that Audio, Video, Subtitles (and Thumbnails if necessary) are routed to this Origin.
For the sake of simplicity it is assumed that containers used by DASH are MP4 with .m4s extensions, and containers used for HLS are Transport Stream + webvtt.

Configuration

  • Origin: origin.video
  • Protocol: HTTPS
  • Behaviors / Rules to match for DASH:
    • Channel A Video/Audio/Subtitles: /channelA/output/*.m4s
    • Channel C Video/Audio/Subtitles: /channelC/output/*.m4s
  • Behaviors / Rules to match for HLS:
    • Channel A Video/Audio: /channelA/output/*.ts
    • Channel A Subtitles: /channelA/output/*.webvtt
    • Channel C Video/Audio: /channelC/output/*.ts
    • Channel C Subtitles: /channelC/output/*.webvtt

Note: the container extensions are given as examples, replace them with the ones you specifically use. You can also configure URI path for thumbnails as well if you are using them.

So, at the end of this step, we have two Content Replacement Services, which are properly configured on the CDN. The Player is able to retrieve manifests from the CDN, which is configured to fetch them on broadpeak.io. Media Segments are configured to be fetched by the CDN to the Origin directly for both HLS and DASH Format.

The streaming links generated by the CDN are now ready to be used in your Service Platform for Channel A. In your case they would look like below:
The final CDN streaming link that needs to be provided to the player, will look like this:

From here, we are almost ready to roll!

7. Scheduling Simultaneous substitution.

Until this step, we have built the whole delivery path for our NFL game Simsub application, in both HLS and DASH. Now we need to spend a bit of time on implementing the scheduling logic which indicates to broadpeak.io when to perform exactly the content substitution. The idea behind this logic is to be able to specify when to swap Channel A, with Channel C. It needs to be implemented outside of broadpeak.io.

For example, in the case of NFL games, we know that we want to perform this Simsub scenario when NFL games are on. Such information is usually available directly from the Programmers or Content Providers through diverse formats. If as a TV service provider, you are able to translate this information into time periods where content needs to be swapped, then you can leverage broadpeak.io's ESNI or REST API to build fully automated applications.

In general, we observe a couple of ways for TV service provider to retrieve the scheduling information from Content providers. One way to do it is directly through SCTE-224 which is the simplest and most convenient way (but unfortunately not yet the most common). If you are a TV service provider and that Content providers from which you acquire content have the ability to send it through SCTE-224, then the good news is that you can use broadpeak.io with very little adaptation and have them directly send the schedule through the ENSI API as the figure below illustrates it.

163

Direct SCTE-224 integration with Content provider's scheduling system

If you are less lucky, it is most probable that Content Providers share the programming schedule in some other ways, one of them being a CSV file sent regularly over a communication channel. In this case, you would need a connector to translate the scheduling in Simsub slots either using the ESNI API or the REST API.

183

Integration with Content provider's scheduling system via connector

If you are interested in working with broadpeak.io to implement your Simsub application and are looking for a connector, please contact us at [email protected].

Now that we know this, what do we need to implement?

Well, since we don't have a scheduling system here or a connector to use in this example, we will simulate the API call. It is really not that complex here, each time there is a game scheduled, a slot needs to be created on both Content Replacement Service (HLS and DASH) specifying the start time of the game, its duration, and the replacement Source. In our example, the replacement Source is always the same, Channel C, but we could think of a scenario where there are multiple replacement Sources (see Part 2). The API allows to specify the replacement Source for each slot.

7.1. Generating our API keys

To start working with the REST API, we need to generate a token which grants access to the API. This token needs to be provided as a bearer token in the Authorization header. Information about how to generate a token can be found generate-your-api-key

7.2. Retrieving the Content Replacement Service Ids

First we need to retrieve the Id of the two created Content Replacement Services. This can be done using the REST API function to retrieve all existing Services.

curl --request GET \
     --url https://api.broadpeak.io/v1/services \
     --header 'Accept: application/json' \
     --header 'Authorization: Bearer ${yourAPIKEY}'

Note: ${yourAPIKEY} must be replaced by your actual key.

This should return a list of Services and amongst them should be the two Content Replacement Services created previously via the UI. The value that we need to keep are the Id of each Service, as we will need to use them in order to create slots.
In my case the values are "1721" for DASH and "1722" for HLS.

[
    {
        "id": 1721,
        "name": "mySimsubService_DASH",
        "tenantId": XX,
        "type": "content-replacement",
        "environmentTags": [
            "Lab"
        ]
    },
    {
        "id": 1722,
        "name": "mySimsubService_HLS",
        "tenantId": XX,
        "type": "content-replacement",
        "environmentTags": [
            "Lab"
        ]
    }
]

7.3. Retrieving the Sources Id

We need to identify what are the id of the replacement Sources. It can be done using the REST API function which lists all the existing Sources.

curl --request GET \
     --url https://api.broadpeak.io/v1/sources \
     --header 'Accept: application/json' \
     --header 'Authorization: Bearer ${yourAPIKEY}'

Note: ${yourAPIKEY} must be replaced by your actual key

This should return a list of Sources and amongst them should be the two replacement Sources (HLS and DASH) previously created which points to Channel C. The values that we need to keep are the Id of each Source, as we will need to use them in order to create slots. In my case the values are:

  • Channel C DASH : 2388
  • Channel C HLS: 2384
[ 
  {
    "id": 2382,
    "name": "ChannelA_DASH",
    "type": "live"
  },
  {
    "id": 2383,
    "name": "ChannelA_HLS",
    "type": "live"
  },
  {
    "id": 2388,
    "name": "ChannelC_DASH",
    "type": "live"
  },
  {
    "id": 2384,
    "name": "ChannelC_HLS",
    "type": "live"
  }
]

7.4. Creating a Simsub Slot

Now that we have identified our Services and replacement Sources, we can start create slots to replace channel A by channel C in a specific time slot that represents NFL games schedule. This can be done with the REST API function to create new Slots.

For a same NFL game, we have to create two slots, one to target the Content Replacement DASH Service and another one to target the Content Replacement HLS Service.

7.4.1 Slot on DASH Service
  • The URL needs to contain the Content Replacement Service Id that we are targeting, here 1721.
  • The body needs to contains information such as:
    • replacement source Id: we need to indicate the Source Id of the substitute content. Here it is the Id of ChannelC_DASH, which is 2388.
    • name of the slot: it can be any unique name. Here we will just combine the Date+Format to build a name "DASH_2023-10-08T15:00:00"
    • start time of the slot: the exact time when the content substitution should happen (ISO format). This is probably a bit before the NFL game starts. The Content Provider would provide this information.
    • duration of the slot: the duration of the content substitution in seconds. NFL games usually last 3h12min so we will set 11520 seconds, but in reality this information would be provided by the content Provider.
curl --request POST \
     --url https://api.broadpeak.io/v1/services/content-replacement/1721/slots \
     --header 'Accept: application/json' \
     --header 'Authorization: Bearer ${yourAPIKEY}' \
     --header 'Content-Type: application/json' \
     --data '
{
     "replacement": {
          "id": 2388
     },
     "name": "DASH_2023-10-08T15:00:00",
     "startTime": "2023-10-08T15:00:00",
     "duration": 11520
}
'

Note: ${yourAPIKEY} must be replaced by your actual key.

broadpeak.io should return a HTTP 202 if the Slot has been successfully created.

7.4.2 Slot on HLS Service:

You can follow the same process to create a slot on the HLS service, using the same REST API

  • The URL needs to contain the Content Replacement Service Id that we are targeting, here 1722.
  • The body needs to contains information such as:
    • replacement source Id: we need to indicate the Source Id of the substitute content. Here it is the Id of ChannelC_HLS, which is 2384.
    • name of the slot: we can specify a different value than the value used for the slot on DASH Service."HLS_2023-10-08T15:00:00"
    • start time of the slot: we can use the same value as used for the slot on DASH Service.
    • duration of the slot: we can use the same value as used for the slot on DASH Service, so 11520 seconds.
curl --request POST \
     --url https://api.broadpeak.io/v1/services/content-replacement/1722/slots \
     --header 'Accept: application/json' \
     --header 'Authorization: Bearer ${yourAPIKEY}' \
     --header 'Content-Type: application/json' \
     --data '
{
     "replacement": {
          "id": 2384
     },
     "name": "HLS_2023-10-08T15:00:00",
     "startTime": "2023-10-08T15:00:00",
     "duration": 11520
}
'

Note: ${yourAPIKEY} must be replaced by your actual key.

broadpeak.io should return an HTTP 202 if the Slot has been successfully created.

📘

Overtime Management

In sports where we often observe overtime, it is complex to know in advance the exact end time of a game. Using the broadpeak.io API, it is possible to update an existing slot with new values. Therefore updating an existing slot with a new duration at the end of the game to signal that the stream needs to go back to the original content becomes easy like a walk in the park!

7.5 Listing all scheduled slots

Using the REST API, you can also list all scheduled Slots for a specific Content Replacement service, and retrieve the slots newly created.
The Id of the Content Replacement Service needs to be provided within the endpoint URL.

curl --request GET \
     --url https://api.broadpeak.io/v1/services/blackout/1721/slots \
     --header 'Accept: application/json' \
     --header 'Authorization: Bearer ${yourAPIKEY}'

Note: ${yourAPIKEY} must be replaced by your actual key.

[
  {
    "id": 13186,
    "name": "DASH_2023-10-08T15:00:00",
    "startTime": "2023-10-08T15:00:00.000Z",
    "duration": 11520,
    "replacement": {
      "type": "live",
      "id": 2388,
      "name": "ChannelC_DASH",
      "url": "https://origin.video/channelC/output/manifest.mpd",
      "backupIp": null,
      "description": null
    },
    "categories": []
  }
]

Using these different API calls, you can build the scheduling logic and automate the management of simsub slots on the channels on which you, as a TV provider, are required to comply with regulation.

📘

Using the Knowledge Center as API client (testing purposes)

If you don't feel like implementing the scheduling logic right now but still want to see how simsub is being rendered on the screen, you can use the Knowledge Center. It leverages swagger which allows you to send API calls directly using the API token provided by broadpeak.io.

8. Streaming from our simultaneous substitution service

Once you have implemented the logic for scheduling slots in broadpeak.io via API , or if you just want to start with creating a few simsub slots via CURL commands or the Knowledge Center (swagger), it is time to verify that our simsub service correctly and accurately switches from Channel A to Channel C when we define these slots.

8.1: Forming the final URL

As a result of the defining a Simsub Services (Content Replacement Service) in broadpeak.io, you have been provided with streaming URIs, one for DASH, and one for HLS, as below:

We have configured the CDN in step 6, and as a result, we obtained a FQDN for this distribution.
In our example, we assumed that this distribution FQDN is "myCDN.video".
Therefore the final CDN streaming links look like this:

You can use these links in your respective DASH and HLS players and start streaming. If you have not created a slot yet, Channel A should be displayed on the screen.

8.2 Playout and Content switching

Now that you are able to play the content from your CDN connected to broadpeak.io , you can define a simsub slot at a specified time. You should experience the switch when the player reaches the specified time in the manifest.

🚧

Compatible Players

DASH manifests generated by broadpeak.io are multi-period manifests, which are not all supported by Players.
For more information, we invite you to consult the Ensuring players Compatibility

Part 1 - Conclusion.

We have build a simple use-case of unconditional simsub, where all TV subscribers using the same streaming link are automatically switched to local content when necessary. We have seen that the scheduling process can be fully automated with the use of broadpeak.io API, either using direct connectivity with Content Providers via SCTE-224, or in some cases with the need to implement a scheduling logic or a connector.

Part 2 - Audience based conditional Substitution

Now that we know how to implement unconditional substitution to switch all TV subscribers watching the American channel to the Canadian channel at the time of the NFL game, we would like to push the use-case a little further.

In a country like Canada, it is common practice to broadcast a same channel with personalized content based on the geographical location of the subscribers. For instance, TV subscribers in Toronto, who watch the same channel as subscribers in Ottawa, would have different advertisings as Broadcaster would deliver two different variants of a same channel, with different advertising based on the Audience. This way, Advertisers are much more likely to pay a higher price for Publishers' Television time, as they can expect more relevant targeting and a direct increase in sales.

2246

Schedule of a Canadian TV service provider with Audience based distribution

When performing Simultaneous Substitution, it is important to keep this concept of delivering targeted content per geographical location, so revenues expectations can remain at the same level. We will explain how to implement this with broadpeak.io in this second part.

In this example we will re-use the previous American and Canadian channels, with the difference that the Canadian channels have multiple streaming endpoints representing one stream per targeted city. For the sake of this example, we will only focus on three cities, Toronto, Ottawa, and Montreal.

  1. Canadian Channel broadcasted to Toronto - we will name it Channel C Toronto.
  2. Canadian Channel broadcasted to Ottawa- we will name it Channel C Ottawa.
  3. Canadian Channel broadcasted to Montreal- we will name it Channel C Montreal.

1. Identifying the live streams subject to substitution

As we did in part 1, we need to identify which channel is subject to substitution, and for each channel, what are the different variants used for each location. We will call a variant a version of a channel prepared for a specific city and surroundings. In our example, we will assume that we have a one variant per format (HLS/DASH) for the American Channel, and three variants per format for the Canadian Channel, one for each city to address.

As in the previous example in Part 1 of this article, TV providers in Canada would need Channel A to be substituted by Channel C for the period of the NFL game. However, TV subscribers watching the NFL Game from Toronto need to watch the local channel C, Channel C Toronto, while Tv subscribers located in Vancouver and Montreal need respectively to watch Channel C Ottawa and Channel C Montreal.

2. Preparing the live streams for substitution

Again, all streams must be prepared in the same way to be compatible with each other and experience a successful Simultaneous substitution. We invite you to refer to the Input formats section for more information.

3. Creating live Sources in broadpeak.io

In our previous example, we have already created the American Channel as Source for HLS and DASH in broadpeak.io. Now we need to define as Source, the Channel C streams targeted for each geographical location, and we will use the Create a live source to do so.

MPEG-DASH

Let's look at the definition of the Channel C stream dedicated to the Toronto Audience, we have:

In the API call, the body must contain:

  • name: the name of the Source that will be defined in broadpeak.io. We will use ChannelC_Toronto_DASH here.
  • url: the streaming link of the variant so broadpeak.io can retrieve the manifest. In our case, we use the value stated above "https://origin.video/channelC/toronto/manifest.mpd"
  • description: this is an optional string, just here to help identify what this Source is.
curl --request POST \
     --url https://api.broadpeak.io/v1/sources/live \
     --header 'Accept: application/json' \
     --header 'Authorization: Bearer ${yourAPIKEY}' \
     --header 'Content-Type: application/json' \
     --data '
{
     "name": "ChannelC_Toronto_DASH",
     "url": "https://origin.video/channelC/toronto/manifest.mpd",
     "description": "Channel C as source, DASH variant for Toronto"
}
'

Note: ${yourAPIKEY} must be replaced by your actual key.

HLS

In HLS, we also need to define all the following variant of Channel C dedicated to the different Audiences:

In the API call, the body must contain:

  • name: the name of the Source that will be defined in broadpeak.io. We will use ChannelC_Toronto_HLS here.
  • url: the streaming link of the variant so that broadpeak.io can retrieve the manifest. This time for HLS, it is "https://origin.video/channelC/toronto/index.m3u8"
  • description: as for DASH, this is an optional string, just here to help identify what this Source is.
curl --request POST \
     --url https://api.broadpeak.io/v1/sources/live \
     --header 'Accept: application/json' \
     --header 'Authorization: Bearer ${yourAPIKEY}' \
     --header 'Content-Type: application/json' \
     --data '
{
     "name": "ChannelC_Toronto_HLS",
     "url": "https://origin.video/channelC/toronto/index.m3u8",
     "description": "Channel C as source, HLS variant for Toronto"
}
'

We invite you to repeat the same steps for the other variants (Ottawa and Montreal) of Channel C. In fact, you will have to create a new Source for each geographic area that you are targeting, and per streaming format.

At the end of this step, you should have:

  • 2 Sources that represent this American Channel for DASH and HLS
  • 2 Sources that represent the Toronto variant of the Canadian Channel for DASH and HLS
  • 2 Sources that represent the Ottawa variant of the Canadian Channel for DASH and HLS
  • 2 Sources that represent the Montreal variant of the Canadian Channel for DASH and HLS
[
  {
    "id": 2382,
    "name": "ChannelA_DASH",
    "type": "live"
  },
  {
    "id": 2383,
    "name": "ChannelA_HLS",
    "type": "live"
  },
  {
    "id": 2610,
    "name": "ChannelC_Toronto_DASH",
    "type": "live"
  },
  {
    "id": 2611,
    "name": "ChannelC_Toronto_HLS",
    "type": "live"
  },
  {
    "id": 2612,
    "name": "ChannelC_Ottawa_DASH",
    "type": "live"
  },
  {
    "id": 2613,
    "name": "ChannelC_Ottawa_HLS",
    "type": "live"
  },
  {
    "id": 2614,
    "name": "ChannelC_Montreal_DASH",
    "type": "live"
  },
  {
    "id": 2615,
    "name": "ChannelC_Montreal_HLS",
    "type": "live"
  }
]

📘

Retrieving the list of sources created using the API

You can retrieve the list of all Sources created in broadpeak.io using this REST API call

4. Defining Content Replacement Services to enable simultaneous substitution

Since we have already created our Content Replacement Service to enable simultaneous substitution in Part 1, we don't need to do anything else at this stage. We will reuse the same Service.
If you haven't read part 1, we invite you follow the steps detailed here.

5. Checking that the Services are functional

This step has also already been covered in Part 1, so we already know that our Service is functional.
If you haven't read part 1, we invite you to follow the steps detailed here.

6. Configuring your Content Delivery Network for Simsub delivery

The recommended implementation of broadpeak.io is to have it located in between your Origin and your CDN.
For more information about how broadpeak.io operates and you should use a CDN, we invite you to consult the Using broadpeak.io with a CDN section.

The configuration of your CDN is an important step to build a functional simsub application, two major rules need to be followed

  1. The CDN should only fetch Manifests from broadpeak.io.
  2. Media segments from Channel A and Channel C must be retrieved by the CDN directly to the Origin. If you are using different Origins for Channel A and Channel C, the CDN must be configured to fetch each content to its respective origin.
6.1 Configuring CDN for Manifest requests

We can re-use the configuration made during Part 1, but we need to make a few add-ups. In this new use-case, we have TV subscribers located in different Cities experiencing a content switch to their respective local content at the time of the NFL game. We mentioned that each subscriber in its own city would get the local content prepared with local Advertising, which by definition means that media manifests are personalized per Audience. Therefore the same manifest cannot be delivered to all users and media manifest must not be cached. It is very important to make sure that caching policies are de-activated on manifest requests or else the Simsub application conditioned for specific Audiences will not be functional.

6.3 Configuring CDN for Media segments.

During Part 1, we made sure that Audio, Video, Subtitles of Channels A and C were correctly routed to the Origin "origin.video". We assumed that both channels came from the same origin, and that containers used by DASH are MP4 with .m4s extensions, and containers used for HLS are Transport Stream + webvtt. We will keep these assumptions for sake of simplicity.

We already have a valid configuration for Channel A that we made in Part 1, so we will just need to add the new variants for Channel C.

Configuration

  • Origin: origin.video
  • Protocol: HTTPS
  • Behaviors / Rules to match for DASH:
    • Channel C Video/Audio/Subtitles: /channelC/*/*.m4s
  • Behaviors / Rules to match for HLS:
    • Channel C Video/Audio: /channelC/*/*.ts
    • Channel C Subtitle: /channelC/*/*.webvtt

Note: Container extensions are given as examples, replace them with the ones you specifically used. You might want to use thumbnails path as well if you are using some.

As an outcome of the CDN configuration, you should be able to retrieve the distribution's streaming links or FQDNs. These are the streaming links generated by the CDN configuration in Part 1, and should look like this in our case:

At the end of this step, players should be able to retrieve manifests from the CDN, which is configured to fetch them on broadpeak.io. Media Segments are configured to be fetched from the CDN to the Origin directly for HLS and DASH formats for Channel A as well as for all variants of Channel C.

We will see in the next section that players or applications also need to add some contextual information as query parameters when streaming to indicate which audience the subscriber actually belongs to.

7. Scheduling conditional Simultaneous substitution

7.1 Identifying Audiences and Actions

If you have read this far, I can safely assume that you are finding value in this playbook. Well, good news, this is the last stretch :).
Now that we have defined all our Sources in broadpeak.io, our Simsub services, and configured the CDN for delivery, we need to define the switching rules.
These can be summarized in 3 points:

  • Who: which Audience and how do we define an Audience?
  • When: what events require simsub? When and for how long should the switch?
  • What to do: which stream should substitute which stream?

These three pieces of information should be provided by the Content Provider either through the ENSI SCTE-224 MediaPoints or other type of formats (csv...). A connector between the CP and broadpeak.io might be needed if the data is not provided by SCTE-224, otherwise you should be able to connect broadpeak.io directly with the Content Provider's programming system.

So, in our case, we expect the Content Provider to define the Audience with a list of zip codes for the different cities and their surroundings. All TV subscribers can have their location identified by their zip code. Therefore, each Audience can be defined by a list of all zip code which belongs to this very same Audience.

In this example, we will use the ESNI API, which is pretty much designed to manage Audiences, but the same thing can be achieved using the REST API, and we will define an Audience Object in XML under the ESNI specification, for each city.

The Whom?

As mentioned, the location of TV Subscribers can be identified by their home zip code. Content Providers utilise a list of zip codes to define an Audience. Subscribers in Toronto, would have a zip code that belongs to the list of zip codes defined for the Toronto Audience.

<Audience id="Toronto">
    <audience:zip>M1R0E9</audience:zip>
    <audience:zip>M1R0C1</audience:zip>
    <audience:zip>M1R0C2</audience:zip>
    <audience:zip>...</audience:zip>  
</Audience>

Note: This is not a fully functional XML or MediaPoint. Parts of the MediaPoint structure that are not relevant for the example have been omitted.

The Audience defined for Ottawa contains its unique list of zip codes of Ottawa and surroundings:

<Audience id="Ottawa">
    <audience:zip>V5K0A1</audience:zip>
    <audience:zip>V5K0A2</audience:zip>
    <audience:zip>V5K0A3</audience:zip>
    <audience:zip>....</audience:zip>
</Audience>

Note: This is not a fully functional XML or MediaPoint. Parts of the MediaPoint structure that are not relevant for the example have been omitted.

The Audience defined for Montreal, also contains its unique list of zip codes which represents Montreal and its surroundings:

<Audience id="Montreal">
    <audience:zip>H1A0A1</audience:zip>
    <audience:zip>H1A0A2</audience:zip>
    <audience:zip>H1A0A5</audience:zip>
    <audience:zip>....</audience:zip>
</Audience>

Note: This is not a fully function XML or MediaPoint. Parts of the MediaPoint structure that are not relevant for the example have been omitted.

The When?

In our NFL game example, we expect the Content Provider to provide information to switch from the American Channel to the Canadian channel a bit before the NFL game starts, or maybe a bit before so that local ads can reach their Audience. This time is provided by the Content Provider, and should be provided in the API call under 'matchTime' in UTC ISO Format.

The What?

The Content Providers would also specify which channel should substitute the American Channel during the NFL game, based on the Audience. Since we are addressing three cities and their surroundings, we have three types of possible actions:

  1. A switch must be performed to the Canadian Channel broadcast for Toronto when the subscriber's zip code belongs to the Toronto Audience.
  2. A switch must be performed to the Canadian Channel broadcast for Ottawa when the subscriber's zip code belongs to the Ottawa Audience.
  3. A switch must be performed to the Canadian Channel broadcast for Montreal when the subscriber's zip code belongs to the Montreal Audience.

Three distinct actions means three ENSI MediaPoints to create, one per Audience and per stream format. Since we are working with DASH and HLS here, we should create six MediaPoints. Don't worry, the idea behind this is to leverage the broadpeak.io API to automate this flow.

This is how MediaPoints would be represented for a NFL game on HLS:

DASH MediaPoint for the NFL Game for Toronto:

<Media href="mySimsubService">
    <MediaPoint id="HLS_2023-10-08T15:00:00_Toronto" matchTime="2023-10-08T15:00:00" expectedDuration="PT3H12M">
        <Apply>
            <Policy id="1">
                <ViewingPolicy id="1">
                    <Audience id="Toronto">
                        <audience:zip>M1R0E9</audience:zip>
                        <audience:zip>M1R0C1</audience:zip>
                        <audience:zip>M1R0C2</audience:zip>
                    </Audience>
                    <action:Content>ChannelC_Toronto_DASH</action:Content>
                </ViewingPolicy>
            </Policy>
        </Apply>
    </MediaPoint>
</Media>

DASH MediaPoint for the NFL Game for Ottawa:

<Media href="mySimsubService">
    <MediaPoint id="HLS_2023-10-08T15:00:00_Ottawa" matchTime="2023-10-08T15:00:00" expectedDuration="PT3H12M">
        <Apply>
            <Policy id="1">
                <ViewingPolicy id="1">
                    <Audience id="Ottawa">
                        <audience:zip>V5K0A1</audience:zip>
                        <audience:zip>V5K0A2</audience:zip>
                        <audience:zip>V5K0A3</audience:zip>
                    </Audience>
                    <action:Content>ChannelC_Ottawa_DASH</action:Content>
                </ViewingPolicy>
            </Policy>
        </Apply>
    </MediaPoint>
</Media>

DASH MediaPoint for the NFL Game for Montreal:

<Media href="mySimsubService">
    <MediaPoint id="HLS_2023-10-08T15:00:00_Montreal" matchTime="2023-10-08T15:00:00" expectedDuration="PT3H12M">
        <Apply>
            <Policy id="1">
                <ViewingPolicy id="1">
                    <Audience id="Montreal">
                        <audience:zip>H1A0A1</audience:zip>
                        <audience:zip>H1A0A2</audience:zip>
                        <audience:zip>H1A0A5</audience:zip>
                    </Audience>
                    <action:Content>ChannelC_Montreal_DASH</action:Content>
                </ViewingPolicy>
            </Policy>
        </Apply>
    </MediaPoint>
</Media>

For each MediaPoint, we need to define:

  • a Media href value: this is the Content Replacement service name we created for this simsub application "mySimsubService", which points to Channel A by default.
  • a MediaPoint Id: this is the Identifier which can be used to retrieve the MediaPoint information or to update it. Here we chose a meaningful string for the sake of simplicity, but can be an integer.
  • a MediaPoint matchTime: this is the time when the content switch should happen in ISO Format.
  • a MediaPoint duration: this is the duration for which the substitute content should remain on the screen.
  • Policy and Viewing policy are not used in our case, so we can set their id to 1.
  • The Viewing Policy object contains the Audience and Action objects:
    • Audience: the Audience with the list of zip codes that we defined for each city.
    • Action: the value must contain the Source defined in broadpeak.io as the local replacement content for each city. Here this is Channel C, with a variant per city.

The same MediaPoints should also be created for HLS.

At the end of this step, you must be able to create MediaPoint (simsub slots) for specific event and for specific audiences, through API.

8. Streaming and playing conditional Simultaneous substitution

Now that we are able to create MediaPoints (simsub events) with specific rules that apply to different Audiences, you must wonder how broadpeak.io knows which Audience a TV subscriber who requests manifests belongs to.

As a TV service provider, you have information about your own subscribers, and including where their home address is located. As mentioned earlier, we suggest using the zip code as a location identifier for each subscriber. This information should be passed in the streaming request, so that broadpeak.io can decide what action to perform based on the defined rules (MediaPoints) for these specific users. The typical implementation relies on the CMS or on the STB application being able to append this zip code as a query parameter to the streaming link.

1360

Simsub global ecosystem

To represent this, the query parameter "zipcode=${SubscriberZipcodeValue}" would need to be added to the streaming link. In our example, the final CDN streaming links look like this:

Here is how the streaming link would look for a subscriber in Toronto:
https://myCDN.video/7647966b7343c290d6dd5403458c95a3/channelA/output/manifest.mpd?zipcode=M1R0E9

For a subscriber in Vancouver:
https://myCDN.video/7647966b7343c290d6dd5403458c95a3/channelA/output/manifest.mpd?zipcode=V5K0A3

For a subscriber in Montreal:
https://myCDN.video/7647966b7343c290d6dd5403458c95a3/channelA/output/manifest.mpd?zipcode=H1A0A2

Part 2 - Conclusion

We have seen how TV providers can simply implement channel Simultaneous Substitution to always present a local content to a local Audience when the same program is available on multiple channels. Switching rules can be created through what is being called Slots or MediaPoints (ESNI), which represent a switching action to be performed at a specific time, for a specific duration and a specific Audience. While the scheduling logic still needs to be built, these scenarios can be fully automated using the ESNI (scte-224) or REST API available on broadpeak.io.