Red5 Pro Streams

1. About Red5 Pro streams

Streams are the core objects in Red5 Pro that represent audio/video operations in the context of the media server. Red5 Pro stream objects encapsulate information about client/server streams for live/video-on-demand content.

At its core every Red5 Pro stream is a IStream object.

  • A generic broadcaster stream extends from a IStream and is represented by a IBroadcastStream.

  • A generic subscriber stream extends from the IStream object and is represented by a ISubscriberStream

You can explore the APIs in details by inspecting each IStreaminterface and its implementation individually, starting at the IStream interface.

2. Red5 Pro stream action callbacks in application adapter

Every Red5 Pro application extends the MultiThreadedApplicationAdapter and has access to specific callback methods for stream events. We can override these methods in our own application class to handle the callbacks ourselves.

Following is a snippet from a sample application adapter class that extends the MultiThreadedApplicationAdapter:

 @Override
public void streamBroadcastClose(IBroadcastStream stream) {
    log.info("Stream broadcast close {}", stream);
}

@Override
public void streamBroadcastStart(IBroadcastStream stream) {
    log.info("Stream broadcast start {}", stream);
}

@Override
public void streamRecordStart(IBroadcastStream stream) {
    log.info("Stream record start {}", stream);
}

@Override
public void streamRecordStop(IBroadcastStream stream) {
    log.info("Stream record stop {}", stream);
}

@Override
public void streamSubscriberStart(ISubscriberStream stream) {
    log.info("Stream subscribe start {}", stream);
}

@Override
public void streamSubscriberClose(ISubscriberStream stream) {
    log.info("Stream subscribe close {}", stream);
}

streamBroadcastStart : Invoked when a broadcast starts

streamBroadcastClose : Invoked when a broadcast stops

streamRecordStart : Invoked when recording of a broadcast stream starts

streamRecordStop : Invoked when recording of a broadcast stream stops

streamSubscriberStart : Invoked when a subscriber requests a stream

streamSubscriberClose : Invoked when a subscriber stops subscribing

For detailed information on these callbacks and more, check out the MultiThreadedApplicationAdapter documentation You can access the complete source code of the snippet shown above on github here.

3. Fetching all the live stream names in an application

Often when developing a live streaming application you may want to fetch the list of active live streams in your application. The MultiThreadedApplicationAdapter documentation provides a method specifically for this. The snippet below shows how you can use the getBroadcastStreamNames method) to list out live streams.

public List<String> getLiveStreams(String appname, IScope scope) throws Exception {
    List<String> streams = null;

    try
    {
        MultiThreadedApplicationAdapter adapter = (MultiThreadedApplicationAdapter) application.getHandler();
        Set<String> broadcastStreams = adapter.getBroadcastStreamNames(scope);

        Iterator<String> iter = broadcastStreams.iterator();
        streams = new ArrayList<String>();

        while (iter.hasNext()) {
            String name = iter.next();
            IClientBroadcastStream stream = (IClientBroadcastStream) adapter.getBroadcastStream(application, name);
            IConnection conn = stream.getConnection();
            if (conn != null && conn.isConnected())
                streams.add(name);
        }

        return streams;
    }
    catch (Exception e)
    {
        log.error("An unexpected error occurred." + e.getMessage());
        throw e;
    }
}

The important line to notice above is this one :

Set<String> broadcastStreams = adapter.getBroadcastStreamNames(scope);

If you are looking for live streams at the application level then scope would be your APPLICATION scope or if you are looking for streams in a sub-scope, scope should refer to a ROOM scope.

Exception will be thrown if the scope is not found on server. It is recommended that you read through Red5 Pro scopes document for more information on scopes.

4. Access a live stream object in a Red5 Pro scope

Once you have a list of live stream names, you may want to reference the stream object itself to operate on it using the Red5 Pro API. Similar to the stream list look up, the use of scopes applies here as well. Following is a snippet showing how to fetch reference to a stream as a broadcast stream.

If you look back at our getLiveStreams method earlier, you will see how we resolve a ClientBroadcastStream using the stream name. The MultiThreadedApplicationAdapter documentation provides a method called getBroadcastStream to resolve the reference object of a live stream.

Example:

IClientBroadcastStream stream = (IClientBroadcastStream) adapter.getBroadcastStream(scope, name);

The method requires the stream name and the scope where to look for the stream. If your stream is at the application level, then scope should refer to your APPPLICATION scope else if your stream exists in a subscope then scope should refer to the appropriate ROOM scope.

The getBroadcastStream returns a IBroadcastStream object, which can be casted to a IClientBroadcastStream. It is recommended that you read through Red5 Pro scopes document for more information on scopes.

5. Record a live stream

Having reference of the stream object means we can now operate on it. You can take a look at the ClientBroadcastStream class to see the various method available to us.

One of the most common operations on broadcast streams is live recording, capturing the broadcast stream to media file. In the previous section we type-casted the IBroadcastStream object to IClientBroadcastStream. You can also cast the object to a ClientBroadcastStream which is a concrete implementation of the IClientBroadcastStream interface.

5.1. Start Record

This class provides all necessary API methods needed to work with broadcast streams. To record a live stream we use the saveas method of the ClientBroadcastStream class. Following is a code snippet showing how to record a live broadcast stream to disk when broadcast starts.

@Override
public void streamBroadcastStart(IBroadcastStream stream)
{
    try
    {
       ClientBroadcastStream bStream = (ClientBroadcastStream) stream;
       if(!bStream.isRecording()) {
          bStream.saveAs(bStream.getPublishedName(), false);
       }
    }
    catch (IOException | ResourceNotFoundException | ResourceExistException e) {
        e.printStackTrace();
    }
}

The streamBroadcastStart callback method is invoked when the broadcast starts. At this point the callback receives a reference to the stream as a IBroadcastStream object. We then explicitly cast it to a ClientBroadcastStream object. Once the object is casted to a ClientBroadcastStream, we get access to a range of stream API methods through the ClientBroadcastStream class.

We use the isRecording() method to check whether the stream is already recording or not. If not then we start recoring the stream using the saveas method

The saveas method accepts two parameters, the filename to use for recording and a Boolean parameters indicating whether the recording is to be appended or overwritten if the file already exists.

5.2 Stop Record

Normally recording automatically terminates when the stream is closed (client closes connection/stream). However if you wish to stop the recording manually, you can use the stopRecording method of the ClientBroadcastStream class.

public void stopRecording(IBroadcastStream stream)
{
    try
    {
       ClientBroadcastStream bStream = (ClientBroadcastStream) stream;
       if(bStream.isRecording()) {
          bStream.stopRecording();
       }
    }
    catch (IOException | ResourceNotFoundException | ResourceExistException e) {
        e.printStackTrace();
    }

}

6. Stream Statistics

A Red5 Pro broadcast stream object provides statistics information through the getStatistics() method of the IClientBroadcastStream interface which returns a IClientBroadcastStreamStatistics.

Example :

IClientBroadcastStream broadcastStream = (IClientBroadcastStream) stream;
IClientBroadcastStreamStatistics stats = broadcastStream.getStatistics();

To obtain the IClientBroadcastStreamStatistics object from a broadcast stream it should be cast to a IClientBroadcastStream.

Check out the stream-statistics-demo example on GitHub for more information on how to fetch live stream statistics.

7. Terminate a stream

If you wish to close a Red5 Pro stream from the server side, you can use the close() method of the IStream interface. Every stream object in Red5 is a IStream object and hence implements the close method.

Example:

@Override
public void streamBroadcastStart(IBroadcastStream stream) {
 stream.close();
}

In the above snippet we close a broadcast stream as soon as the publisher starts publishing. The streamBroadcastStart is invoked when the broadcast starts. then we call the close method on the IBroadcastStream object received through the streamBroadcastStart method to close it.

8. Securing publish & playback

The Red5 Pro framework provides a simple yet sturdy security mechanism for protection of publish & playback streams. In this section we shall see how we can prevent illegal access to Red5 pro streams using the stream security features of Red5.

Red5 provides two security interfaces - IStreamPublishSecurity & IStreamPlaybackSecurity in its api, which simplify the process of controlling access to streams. The IStreamPublishSecurity is used to secure access to stream publishing where as IStreamPlaybackSecurity is used to secure stream subscription.

Publisher security

To add publisher security, you need to create a implementation of IStreamPublishSecurity and register it with your application adapter using the registerStreamPublishSecurity) method.

An application adapter can have multiple IStreamPublishSecurity implementations registered with it. When you have multiple IStreamPublishSecurity implementations, even a single rejection (returning false) will override the results of other implementations.

Let us see how the IStreamPublishSecurityimplementation works.

When you create an implementation of the IStreamPublishSecurity interface you must also implement the isPublishAllowed method.

@Override
public boolean isPublishAllowed(IScope scope, String name, String mode)
{
    return true;
}

This method hooks us to the flow of the publisher session initialization event chain. Whenever a client tries to publish a stream, this method gets invoked. The method returns a boolean value. Returning a true allows the session initialization chain to continue whereas returning a false breaks the chain and causes the publish request to be rejected.

The method provides three parameters which can be used for authorizing/rejecting the publish request:

  • scope: The scope (location) in the application where the stream is going to be published to.
  • name: Name of the stream
  • mode: The publish mode of the stream. Publish mode can be 'live or record or append.

You can checkout the complete example demonstrating publish security on github.

Subscriber security

To add subscriber security, you need to create an implementation of IStreamPlaybackSecurity and register it with your application adapter using the registerStreamPlaybackSecurity) method.

When you have multiple IStreamPlaybackSecurity implementations, even a single rejection (returning false) will override the results of other implementations.

Let us see how the IStreamPlaybackSecurity implementation works.

When you create an implementation of the IStreamPlaybackSecurity interface you must implement the isPlaybackAllowed method.

@Override
public boolean isPlaybackAllowed(IScope scope, String name, int start, int length, boolean flushPlaylist)
{
    return false;
}

This method hooks us to the flow of the subscribe session initialization event chain. Whenever a client tries to subscribe to a stream, this method gets invoked. The method returns a boolean value. Returning a true allows the session initialization chain to continue whereas returning a false breaks the chain and causes the subscribe request to be rejected.

The method provides five parameters which can be used for authorizing/rejecting the subscribe request:

  • scope: The scope (location) in the application where the stream is going to be subscribed from.
  • name: Name of the stream
  • start: Requested start position for playback (not applicable to live streams)*
  • length: Requested stream duration for playback (not applicable to live streams)
  • flushPlaylist: Flush the playlist

You can checkout the complete example demonstrating playback security on github.

Suggested Reading:

Capturing client parameters

Authenticating publishers

Authenticating subscribers