Subscriptions

Media Nodes do the work; subscriptions generate the data flows between the Media Nodes.

Subscriptions are dynamic and can be changed in real time. For example, if an RTMP input node informs you that a new RTMP source has come online, you might well update subscriptions to plumb that content into downstream flows (for example by adding a new subscription to a SourceSwitcher or Compose Node, or to allow a moderator to preview the stream before plumbing it into the main output).

A subscription tells a media node where it should get its content from. Most of the time, you can let Norsk worry about the details of a subscription (especially if you are using a Norsk SDK rather than the gRPC interface directly). Here’s the example subscription that we set up in our Getting Started (TL;DR Version) example:

output.subscribe([{ source: input, sourceSelector: selectAV }]);

This tells Norsk to send all audio and video from the input Node through to the the output Node. By and large, you don’t need to worry about exactly what that entails, but let’s explore the detail for a while.

The reality is that most of the times you write an application, you know in advance what media it will consume (e.g. you know it is an RTMP stream with exactly one audio and one video stream), and you can just use the simple subscription call shown in the example above. The good news is that even when the inbound media has a more complex structure, you can easily access and control which parts of the media you want to deal with (for example, your business rule might be "use Spanish audio if it is present, otherwise just use the audio stream with the lowest PID"). The example repo also shows how you can use Norsk to control the PID of the streams you output.

Subscription decisions are made every time either the source context changes. You might have set up a subscription based on the then-correct mapping of audio streams, and you may need to revisit those choices when things change. Say, for example, you are publishing the Spanish audio from a Transport Stream source that has both Spanish and English versions. If the TS ceases to publish a Spanish audio PID, you’ll need to update your subscription accordingly.

Let’s revisit the subscription from our earlier example:

myOutput.subscribe([{ source: myInput, sourceSelector: selectAV }]);

Here’s the code for selectAV

function selectAV(streams: StreamMetadata[]) {
  const audio = audioStreamKeys(streams);
  const video = videoStreamKeys(streams);
  return audio.concat(video);
}

function audioStreamKeys(streams: StreamMetadata[]): StreamKey[] {
  return audioStreams(streams).map((stream) => stream.getStreamKey());
}

export function videoStreams(streams: StreamMetadata[]): StreamMetadata[] {
  return streams.filter((stream) => stream.hasVideo());
}

selectAV is a function that is passed the latest context, every time it changes. The function returns the list of streamKeys it wishes to subscribe to. As the name suggests, selectAV simply returns all the audio and all the video stream keys present in the upstream media node’s output. For most use cases, that simple logic is enough.

For our "Should we publish Spanish or English?" example above, hopefully it’s clear how you’d go about implementing your business logic. Maybe you know your inbound streams are normalized (so English is always PID 257 and Spanish, if present, is always PID 258). Maybe you know that the TS has language descriptors in the program-specific information (you get PSI details in callbacks from the TS Input Node), and you can make your decision based on these.

Once a context changes, Norsk has to pause the flow to any recipient media nodes. It makes no sense to, for example, publish a Spanish audio stream in your output if there is no longer any Spanish audio available in your input! Whether you switch to English or stop publication altogether (simply return no audio or video stream keys) is up to you.

Because the streams are frozen till Norsk gets a reply to the new context message, any decisions should be based on local information. The context-changed callback is not the right time to be making, for example, a potentially slow API call into a remote system.

One good way of exploring what the Norsk contexts look like is to use the real-time workflow visualizer on your workflow, as that lets you easily see the most up-to-date context every media node has received.