/

Plugin Development


What is a Red5 Pro Plugin

Red5 Pro ships out of the box with a feature set that handles most of your streaming needs. However, applications often have business rules and or third-party integration needs which extend beyond what is provided by the server’s default installation. In these scenarios, which tend to be the rule rather than the exception, you are presented with two elegant methods of extension; extending the ApplicationAdapter of your web app or creating a plugin. In this article, we’ll cover the process of creating a Red5 Pro Plugin and reveal why Plugins may be the right choice for extending your server.

Let’s first discuss some use cases around why you might create a Red5 Pro Plugin. As an example, you may need to do authentication for new connections or you may need some kind of custom validation for publish and playback requests of streams.

Adding the code to your application directly may work for a simple use case. But if you need to add the same functionality to different applications and/or you need to be able to add/remove the functionality on demand without having to modify the main Application class of each Red5 Pro application, then you need to implement your code as a plugin.

A Plugin encapsulates your code logic inside a portable module making it modular and more shareable.

As a golden rule, "It is always good to put added feature/functionality logic into a plugin". For simpler cases you can just update your Application class with the required logic.

Red5 Pro Plugin Structure & Lifecycle

A Red5 Pro plugin can extends the Red5Plugin class. In this section we will explore the structure and methods of a Red5Plugin class based plugin.Given below is a simple plugin class snippet without any custom code which provides us with an overview of the plugin structure.

public class Red5TemplatePlugin extends Red5Plugin {

    private Logger log = Red5LoggerFactory.getLogger(Red5TemplatePlugin.class);
    public static final String NAME = "red5-template-plugin";

    @Override
    public String getName() {
        return Red5TemplatePlugin.NAME;
    }

    @Override
    public void doStart() throws Exception {
        log.info(NAME + "doStart called");
    }

    @Override
    public void doStop() throws Exception {
        log.info(NAME + "doStop called");
    }

}

A standard Red5Plugin type class consists of the following methods:

  1. doStart: The entry point of your plugin startup
  2. getName: Return the name of the plugin. The name should be unique. This is very important for plugin startup on the server.
  3. doStop: The end point of the plugin lifecycle. All resources acquired by the plugin should be released in this method.

Generally all plugin initialization task should happen in the doStart method call. You can access a sample Red5 plugin template on github

NOTE: Do not use blocking code in the doStartPlugin method. This may cause a delayed startup of the server scopes. Red5 Pro attempts to start all plugins before it starts the Red5 pro applications. So care must be taken to not delay the server startup.

Writing your own Red5Plugin

Setting up the development environment

The Red5 Pro plugin development environment is similar to Red5 Pro application development environment.

Software requirements

Maven

Maven

The Red5 Pro plugin projects are maven managed java project. Maven is a dependency management and build system for java. To resolve standard red5 dependencies for the plugin you need to have maven installed on your system and it should be available in the operating system environment path. You can download maven from its official page. Follow the platform specific instructions from apache maven official page to install maven and add it to your environment path.

To test that your maven setup is successful, you can launch a shell prompt in any directory and type mvn and press enter. You will be greeted by a maven error which indicates that maven was installed and it could not find a pom.xml file in the current location.

[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.321 s
[INFO] Finished at: 2017-06-21T20:16:43+05:30
[INFO] Final Memory: 9M/309M
[INFO] ------------------------------------------------------------------------
Red5 Pro Media Server

Red5 Pro

To test/debug/deploy your plugin you will need to have a copy of the Red5 Pro media server installed locally. Red5 Pro media server can be from red5pro.com here. You can find Red5 Pro Media server install instructions for windows and linux in the Red5 Pro documentation section.

Eclipse Ide For Coding

Eclipse Jee

For developing Red5 Pro applications/plugins you need to obtain a JEE version of eclipse such as Mars, Neon etc:. Download and extract the package to an accessible location on your system.

There are no special requirements for setting up the IDE. You just need to ensure that you have extracted the files to a location with proper read/write permission and that you have java 1.8 installed on your system.

Starting a new plugin project using template

Obtaining the template

You can start your own Red5Plugin project using one of the templates provided on the red5-development-series github repository.

You will need to use your git tool to clone the repository somewhere on your harddrive to gain access to the template plugins.

For starting a standard Red5Pluginbased plugin project use the red5-template-plugin

Importing the project into Eclipse

Once you have cloned the repository, you can now import the red5-template-plugin project.

Always create a copy of the template plugin directory you wish to use to create your own plugin. This way you can create multiple plugin projects from the same template plugin.

To import the project into eclipse:

  1. Navigate to the directory where the template plugins are located.
  2. Open a command prompt / shell while in the directory.
  3. Type the command mvn eclipse:eclipse. This will make maven generate necessary files for eclipse.
  4. Launch your eclipse jee IDE.
  5. Select File -> Import to open the project import window.
  6. Select Maven -> Existing Maven Projects and click Next
  7. Browse and select the root of the red5-template-plugin project.
  8. Click finish to close the window. The project will now be imported into eclipse and you can access it from the Project explorer view.

Eclipse Project Explorer

Once the project is available in Project explorer, right click the project -> Select : Maven -> Update Project. This refreshes the maven project, validating & rebuilding the dependencies cache for the maven project. If everything is done correctly there will be no errors in the eclipse Markers view.

Renaming template project

Now that we have our template plugin open in the eclipse IDE, we can use it for our new plugin project: HelloRed5Plugin. To change the project name to HelloRed5Plugin:

  1. Right click the project
  2. Select Refactor -> Rename and change the project name to hello-red5-plugin in the Rename Resource dialog.
  3. Click ok to complete refactoring. This will change the project name to hello-red5-plugin.

Renaming the plugin class

The next step is to rename the plugin class. To change the plugin class name:

  1. Open the src/main/java folder in the project explorer of hellored5
  2. Locate the package org.red5.server.plugin.examples
  3. Right click the file and select : Refactor -> Rename and change the package name to org.red5.server.plugin.examples.hellored5 .
  4. Locate the class file Red5TemplatePlugin.java under the package org.red5.server.plugin.examples.hellored5.
  5. Right click the file and select : Refactor -> Rename.
  6. In the dialog box, enter HelloRed5Plugin and click ok to complete the refactor.

Your plugin class file is now renamed to HelloRed5Plugin.java.

  • Finally, in your HelloRed5Plugin.java change the plugin's NAME property value to "red5-hello-plugin".

The NAME property need not be same as the project name. However this needs to be unique amongst other plugins. The Red5 Pro plugin system requires every plugin to have a unique name.

Recommended naming convention

  • Plugin name must be unique
  • The plugin name should start with red5 or red5pro
  • The name parts should be separated by hyphens
  • The plugin filename should always be in lowercase

Updating maven file - pom.xml

Finally we need to update the maven project configuration file - pom.xml. The pom file is used by maven to compile your project into a jar file with a auto generated manifest. The pom.xml tells maven which file is to be treated as the main entry point of your plugin.

The elements that need to be edited in the pom.xml file are as follows:

  1. name : The plugin name. This should match the value of the NAME property in the plugin class file (discussed earlier). The name also translates to the name of the jar generated by maven.
  2. artifactId: The maven project artifactId. The artifactId is used to identify a maven project uniquely in the maven online repository. You can name it the same as your plugin name.
  3. version : The version number of your Red5 Pro plugin.
  4. description : A simple one line description of your plugin.
  5. Red5-Plugin-Main-Class: The next element to change is the name of the plugin class. This is part of the maven-jar-plugin and can be located under the element build -> plugins -> {maven-jar-plugin entry} -> manifestEntries-> Red5-Plugin-Main-Class. Change this to the plugin class name: <Red5-Plugin-Main-Class>org.red5.server.plugin.examples.hellored5.HelloRed5Plugin</Red5-Plugin-Main-Class>. Note that the name should include the complete package name of the class as well.
  6. Once done editing, right click the project in the project explorer, select Maven -> Update Project

To know more about the maven pom.xml, please check out the official maven page on pom.xml file.

Initializing the plugin

As discussed earlier the entry point of a Red5Pro plugin is the doStart. Hence we will add any plugin initialization code , such as reading external configuration , initializing objects etc inside the doStart method.

Loading configuration

A rule of the thumb is that all plugins must go into $RED5_PRO_HOME/plugins/ directory and all configuration files must go into RED5_PRO_HOME/conf/ directory. example. If the configuration does not exist it will be created at the same location.

A plugin configuration is loaded from a configuration file and read/stored into appropriate objects inside the plugin. Simple configurations (suitable for most use cases) can be stored in java properties file. for more complex scenarios you can use a context file (XML formatted) to declare configuration using java beans.

In the code snippet below we will attempt to load configuration file for our HelloRed5Plugin example. If the configuration does not exist it will be created. The configuration file will be called hello-red5-plugin.properties.

hello-red5-plugin.properties file

# Hello Red5 Plugin Properties
#

# Default state of plugin
hellored5.default.active=false

# Default message from plugin
hellored5.default.message=Hello Red5

Loading and storing data from hello-red5-plugin.properties

@Override
public void doStart() throws Exception {
    log.info(NAME + "doStart called");

    log.trace("Loading properties");
    Resource res = getConfResource(context, "hello-red5-plugin.properties");
    if (!res.exists())
    {
        log.debug("Properties not found in conf, creating default configuration");

        // Build default configuration
        configuration.put("hellored5.default.active", "true");
        configuration.put("hellored5.default.message", "Hello Red5");
        addConfResource(configuration, configurationFile, "HelloRed5 Properties\n");
    }
    else
    {
        /******** Load configuration into local model *******/

        InputStream in = res.getInputStream();
        configuration.load(in);
        in.close();
    }


    boolean defaultActive = Boolean.parseBoolean(configuration.getProperty("hellored5.default.active", "false"));
    if (log.isDebugEnabled()) {
        log.debug("default active {}", defaultActive);
    }

    String defaultMessage = configuration.getProperty("hellored5.default.message", "Hello Red5");
    if (log.isDebugEnabled()) {
        log.debug("defaultMessage {}", defaultMessage);
    }

    /******** Store configuration into local model *******/

    defaultConfiguration = new Configuration();
    defaultConfiguration.setActive(defaultActive);
    defaultConfiguration.setMessage(defaultMessage);
}

The method definition source code for getConfResource and addConfResource can be seen in the HelloRed5Pluginclass file.. If you run the plugin on the server the very first time, you will notice that it generates the configuration file hello-red5-plugin.properties in the RED5_HOME/conf.

Once you have loaded the configuration data and stored it in a local model you can pass it around anywhere in your plugin code to make use of it.

Accessing server applications from plugin

Once your configuration is loaded the next thing you might need to configure your plugin's logic to work with your Red5 application running on the server. To do this we need to find the application and be able to access the application adapter class MultiThreadedApplicationAdapter.

There are two conditions here that we need to consider before writing the code. The first one is that a scope starts before applications and from there on we can listen for application startup (ideal condition). The second condition is when the plugin startup gets delayed due to some other process and the plugin starts after the applications have started (adverse condition). We need to account for both these conditions in our code.

To our HelloeRed5Plugin.java class we will add a method called scanForApplications, which will be responsible for locating applications and in turn their application adapters.

Listening for application creation

Every plugin has access to a server object. To listen for application startups we simply need to add a IScopeListener to the server. The snippet below show how we can listen for application startup (handling the ideal condition).

IScopeListener scopeListener = new IScopeListener() {
    @Override
    public void notifyScopeCreated(IScope scope) {
        if (scope.getType() == ScopeType.APPLICATION) {
           log.info("Application started : {}", scope);
        }
    }

    @Override
    public void notifyScopeRemoved(IScope scope) {
        if (scope.getType() == ScopeType.APPLICATION) {
            log.info("Application stopped : {}", scope);
        }
    }
};

server.addListener(scopeListener);

The concept of scope is discussed in a separate article and is a must read before getting started with plugin development. A application is scope identified by its type property.

Locate running red5 applications

The snippet below shows how we can locate applications that are already started in red5 (handling the adverse condition).

log.debug("Setting handlers for apps that might have already started up");

Iterator<IGlobalScope> inter = server.getGlobalScopes();
while (inter.hasNext()) {
    IGlobalScope gscope = inter.next();
    Set<String> appSet = gscope.getBasicScopeNames(ScopeType.APPLICATION);
    Iterator<String> setInter = appSet.iterator();
    while (setInter.hasNext()) {
        String sApp = setInter.next();
        IBasicScope theApp = gscope.getBasicScope(ScopeType.APPLICATION, sApp);
        IScope issc = (IScope) theApp;

        log.info("Application found : {}", issc);
    }
}

Notice how we scan iterate through the global scopes looking for applications.

Accessing the Application adapter

The application adapter is the main class of your red5 application (entry point). Your application adapter class normally extends the red5 MultiThreadedApplicationAdapter class. It contains all the methods necessary to interact with the application.

For a quick reference you can take a look at a application adapter demo application on github.

The adapter object can be referenced from a application scope using the getHandler() method.

Example

 MultiThreadedApplicationAdapter adapter = (MultiThreadedApplicationAdapter) scope.getHandler();

The complete implementation for the method scanForApplications is provided on github in the Hello Red5 Plugin project

Building the plugin JAR

To build the plugin JAR, simply open a shell prompt in the plugin project directory (where the pom.xml is located) and type the command mvn clean package. This will invoke maven on your plugin.

Maven downloads and verifies all the dependencies mentioned in your pom.xml, before compiling the classes into a jar file. The jar output is generated in a folder called target.

For example our HelloRed5Plugin project compiles to hello-red5-plugin-1.0.0.jar inside the target directory. Given below is a sample of the maven build process output.

C:\Users\rajde\Documents\GitHub\red5-development-series\plugin-examples\hello-red5-plugin>mvn clean package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building hello-red5-plugin 1.0.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ hello-red5-plugin ---
[INFO] Deleting C:\Users\rajde\Documents\GitHub\red5-development-series\plugin-examples\hello-red5-plugin\target
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello-red5-plugin ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.6.1:compile (default-compile) @ hello-red5-plugin ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to C:\Users\rajde\Documents\GitHub\red5-development-series\plugin-examples\hello-red5-plugin\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hello-red5-plugin ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory C:\Users\rajde\Documents\GitHub\red5-development-series\plugin-examples\hello-red5-plugin\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.6.1:testCompile (default-testCompile) @ hello-red5-plugin ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ hello-red5-plugin ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ hello-red5-plugin ---
[INFO] Building jar: C:\Users\rajde\Documents\GitHub\red5-development-series\plugin-examples\hello-red5-plugin\target\hello-red5-plugin-1.0.0.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 10.564 s
[INFO] Finished at: 2017-06-21T16:16:58+05:30
[INFO] Final Memory: 16M/166M

Deploying plugin JAR to server

Once you have the plugin JAR built, you need to deploy it to your Red5 Pro server instance to see it in action. To deploy the plugin JAR to server:

  • Copy the plugin jar file from the target directory into Red5 server plugin directory ($RED5_PRO_HOME/plugins/).

Plugins

  • Restart the Red5 Pro service.

If you already had an older version of the plugin JAR in the plugins directory, simply overwrite it. If you changed your configuration file structure, make sure to delete the older configuration file from the $RED5_PRO_HOME/conf directory so that it can be regenerated in the new format when the server starts up.

Debugging the plugin

Debugging a Red5 Pro plugin is achieved using java remote debugging. Currently we do not have an integrated approach to allow running the plugin from within eclipse. Java remote debugging allows you to debug a plugin or a Red5 Pro application running locally or on a remote server. The process below explains how to debug a plugin using java remote debugging (For example the HelloRed5Plugin).

  1. With the plugin project open in eclipse, create a remote java application debug configuration for your project.
  2. In eclipse ide select : Run -> Debug Configurations from the menu.
  3. Double click the Remote Java Application configuration type to create a configuration for the currently open plugin project.
  4. Change the port to 8787 (default red5 debugging port)
  5. Check the Host to ensure that you are targeting the correct Red5 Pro instance
  6. Click Apply to assert the configuration changes

Remote Debugging Configuration

You can optionally check the Allow termination of remote VM option to terminate Red5 Pro when you terminate debugger. Do not select this option if you wish the server to keep running even after you terminate debugging.

  1. Start The Red5 Pro instance where your plugin is deployed using the red5-debug.sh or red5-debug.bat option to enable debugging. The server will then start listening at port 8787 for debugger connections.
  2. In eclipse select and run the debug configuration. You can execute the configuration from the Run menu item (Run -> Debug Configuration -> HelloRed5Plugin -> Debug) or using the Debug icon shortcut in the toolbar.
  3. Now if your project contains breakpoints, they will be triggered as seen by the debugger. Ideally you can also add breakpointsbefore you start the server. This helps you debugs the startup of a plugin and debug potential issues in configuration load.

Breakpoints

Along with remote debugging always use logging as much as you need to log-out event, object and errors as they happen inside the plugin.

Tips and tricks

Monitoring red5 application events

A Red5 Pro application consists of a few discrete application events that define the lifecycle of a Red5 Pro application and that of a client connecting to it. To tap into the application events you need to register a IApplication implementation on the application adapter.

Let us quickly take a look at a IApplication implementing class to have a overview of the application events available to us.

public class AppEventMonitor implements IApplication {

    @Override
    public boolean appStart(IScope app) {
        return true;
    }

    @Override
    public boolean appConnect(IConnection conn, Object[] params) {
    }

    @Override
    public boolean appJoin(IClient client, IScope app){
        return true;
    }

    @Override
    public void appDisconnect(IConnection conn){
    }

    @Override
    public void appLeave(IClient client, IScope app){
    }

    @Override
    public void appStop(IScope app){
    }

    @Override
    public boolean roomStart(IScope room){
        return true;
    }

    @Override
    public boolean roomConnect(IConnection conn, Object[] params){
        return true;
    }

    @Override
    public boolean roomJoin(IClient client, IScope room){
        return true;
    }

    @Override
    public void roomDisconnect(IConnection conn){
    }

    @Override
    public void roomLeave(IClient client, IScope room){
    }

    @Override
    public void roomStop(IScope room){
    }
}

For detailed information on the methods you can go through IApplication javadocs.

To attach the IApplication object to application's handler use the following code:

adapter.addListener(new AppEventMonitor());

Where adapter is the MultiThreadedApplicationAdapter (IScopeHandler) of a application scope

For a more practical example of the IApplication usage checkout the article on red5pro-simple-auth-plugin and the project source code.

Checkout the HelloRed5Plugin project source for AppEventMonitor code.

Intercepting stream publish and subscribe

Red5 Pro provides some special interfaces with regards to Stream security and SharedObject security. These interfaces let you tap into crucial points in the flow of events allowing you to intercept stream publish/subscribe attempts and similar SharedObject intercept points.

Intercepting stream publish

To intercept the stream publish action you need to register a IStreamPublishSecurity implementing class with the application adapter.

The class implementing the IStreamPublishSecurity interface gets a method called isPublishAllowed which returns boolean value. If you return a Boolean true, the publish action is allowed else it's rejected.

public class PublishInterceptor implements IStreamPublishSecurity {
    @Override
    public boolean isPublishAllowed(IScope scope, String name, String mode) {
        // TODO Auto-generated method stub
        return true;
    }
}

You can register the implementation with your application adapter as shown below:

adapter.registerStreamPublishSecurity(new PublishInterceptor());

Checkout the HelloRed5Plugin project source for code sample.

Intercepting stream subscribe

To intercept the stream subscribe action you need to register a IStreamPlaybackSecurity implementing class with the application adapter.

The class implemnting the IStreamPlaybackSecurity interface gets a method called isPlaybackAllowed which returns boolean value. If you return a Boolean true, the subscribe action is allowed else its rejected.

public class PlaybackInterceptor implements IStreamPlaybackSecurity {

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

}

You can register the implementation with your application adapter as shown below:

adapter.registerStreamPlaybackSecurity(new PlaybackInterceptor());

Checkout the HelloRed5Plugin project source for code sample.

Accessing the current connection

Whenever you are writing a piece of Red5 Pro code, be it for a plugin or an application, there are times when you need to access the current connection. By current we mean the connection which is the context of the current thread or the connection which results in the flow of events which you might be interested in.

Fortunately Red5 Pro provides a magical method to gain access to the current connection from anywhere in your code. The code is shown below.

IConnection conn = Red5.getConnectionLocal();