This document describes how new applications can be created in Red5. It applies to the
new API introduced by Red5 0.4.
10.1. The application directory
Red5 stores all application definitions as folders inside the "webapps" directory beneath the
root of Red5. So the first thing you will have to do in order to create a new application, is to
create a new subfolder in "webapps". By convention this folder should get the same name
the application will be reached later.
Inside your new application, you will need a folder "WEB-INF" containing configuration files
about the classes to use. You can use the templates provided by Red5 in the folder "doc/
templates/myapp".
During the start of Red5, all folders inside "webapps" are searched for a directory "WEB-
INF" containing the configuration files.
10.2. Configuration
The main configuration file that is loaded is "web.xml". It contains the following parameters:
10.2.1. webAppRootKey
Unique name for this application, should be the public name:
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>/myapp</param-value>
</context-param>
10.3. Handler configuration
Every handler configuration file must contain at least three beans:
10.3.1. Context
The context bean has the reserved name web.context and is used to map paths to scopes,
lookup services and handlers. The default class for this is org.red5.server.Context.
By default this bean is specified as:
<bean id="web.context" class="org.red5.server.Context"
autowire="byType" />
Every application can only have one context. However this context can be shared across
multiple scopes.Create new applications in Red5
44
10.3.2. Scopes
Every application needs at least one scope that links the handler to the context and the
server. The scopes can be used to build a tree where clients can connect to every node
and share objects inside this scope (like shared objects or live streams). You can see the
scopes as rooms or instances.
The default scope usually has the name web.scope, but the name can be chosen
arbitrarily.
The bean has the following properties:
- server This references the global server red5.server. - parent References the parent for
this scope and usually is global.scope. - context The server context for this scope, use the
web.context from above. - handler The handler for this scope (see below). - contextPath
The path to use when connecting to this scope. - virtualHosts A comma separated list of
hostnames or ip addresses this scope runs at.
A sample definition looks like this:
<bean id="web.scope" class="org.red5.server.WebScope"
init-method="register">
<property name="server" ref="red5.server" />
<property name="parent" ref="global.scope" />
<property name="context" ref="web.context" />
<property name="handler" ref="web.handler" />
<property name="contextPath" value="/myapp" />
<property name="virtualHosts" value="localhost, 127.0.0.1" />
</bean>
You can move the values for contextPath and virtualHosts to a separate properties file and
use parameters. In that case you need another bean:
<bean id="placeholderConfig"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
Create new applications in Red5
<property name="location" value="/WEB-INF/red5-web.properties" />
</bean>
Assuming a red5-web.properties containing the following data:
webapp.contextPath=/myapp
webapp.virtualHosts=localhost, 127.0.0.1
the properties of the scope can now be changed to:Create new applications in Red5
45
<property name="contextPath" value="${webapp.contextPath}" />
<property name="virtualHosts" value="${webapp.virtualHosts}" />
The contextPath specified in the configuration can be seen as "root" path of the scope.
You can add additional elements after the configured path when connecting to dynamically
create extra scopes.
These extra scopes all use the same handler but have their own properties, shared objects
and live streams.
10.4. Handlers
Every context needs a handler that implements the methods called when a client
connects to the scope, leaves it and that contains additional methods that can be
called by the client. The interface these handlers need to implement is specified by
org.red5.server.api.IScopeHandler, however you can implement other interfaces if you
want to control access to shared objects or streams.
A sample implementation that can be used as base class can be found at
org.red5.server.adapter.ApplicationAdapter. Please refer to the javadoc documentation for
further details.
The bean for a scope handler is configured by:
<bean id="web.handler"
class="the.path.to.my.Application"
singleton="true" />
10.5. Logging
Logging Setup Tutorial [Documentation/Tutorials/LoggingSetup]46
11.1. Preface
This document describes how to deploy Red5 to Tomcat as web application archive
(WAR). The standard Red5 deployment consists of a standalone Java application with an
embedded J2EE container (Jetty or Tomcat) running as a system service, whereas the
WAR version runs inside of a J2EE container.
11.2. Deployment
The Tomcat war deployer scans the webapps directory for wars periodically. When a war is
found that has not yet been deployed, the deployer will expand the war file into a directory
based on the filename of the war. A war named myapp.war would be expanded into a
directory named myapp; depending upon your installation the full path would look similar to
this C:\Tomcat- 6.0.14\webapps\myapp.
Red5 server is packaged into a file named ROOT.war, this filename has a special
connotation on most J2EE application servers and is normally the default or root web
context. The root web context is responsible for servicing requests which do not contain
a path component. A url with a path component looks like
http://www.example.com/myapp wheres root web application url would resemble this
http://www.example.com/. An
additional configuration file the context descriptor, is located in the META-INF directory
for each web context. Applications that are not accessed via HTTP, do not require a web /
servlet context. The root war file contains nearly everything that is in a standalone server
build except for embedded server classes and select configuration files.
11.3. Context descriptors
A Context XML descriptor is a fragment of XML data which contains a valid Context
element which would normally be found in the main Tomcat server configuration file (conf/
server.xml). For a given host, the Context descriptors are located in $CATALINA_HOME/
conf/[enginename]/[hostname]/. Note that while the name of the file is not tied to the
webapp name, when the deployer creates descriptors from the context.xml files contained
in the war; their names will match the web application name.
Context descriptors allow defining all aspects and configuration parameters of a context,
such as naming resources and session manager configuration. It should be noted that the
docBase specified in the Context element can refer to either the .WAR or the directory
which will be created when the .WAR is expanded or the .WAR itself.
11.4. Red5 Configuration
Configuration of the Red5 server consists of a few context parameters in the web.xml,
a default context file, a bean ref file, and a Spring web context file for each application
that will utilize Red5 features. Web applications that use only AMF to communicate
with Red5 do not require a configuration entry in the servers application context. The
application context which is managed via Spring is only available to applications that are
contained within the root war; due to the way that the web application classloaders work.
In addition, Red5 uses a context counterpart called a Scope which serves as a container
for the context, handler, server core instance, and a few other objects. A scope is similarDeploying Red5 To Tomcat
47
to the application model in FMS. The initial entry point or startup servlet for Red5 is the
WarLoaderServlet and it is configured as a servlet listener in the web.xml as shown below.
Functionally this servlet takes the place of the Standalone class in a standard Red5 server
<listener>
<listener-class>org.red5.server.war.WarLoaderServlet</listener-class>
</listener>
This listener is responsible for starting and stopping Red5 upon receipt of context initialized
and context destroyed container events. The war loader is similar in function to the Spring
ContextLoaderListener servlet but is specialized for Red5.
11.4.1. Spring contexts
There are two types of contexts used by Red5, "default" and "web"; there may be only one
default context but any number of web contexts.
11.4.2. Default context
The default context is synonymous with the global application context and is responsible
for providing objects and resources at the top or global level. Spring beans in this
level are configured via the defaultContext.xml and beanRefContext.xml which are
located in the ROOT classes directory (ex. C:\Tomcat-6.0.14\webapps\ROOT\WEB-
INF\classes). The bean ref file defines the default.context bean which as an instance
of org.springframework.context.support.ClassPathXmlApplicationContext. Two other
configuration files red5-common.xml and red5-core.xml are used to construct the default
context; these files are derived from the standalone configuration files of the same names,
the primary difference is that the server embedding sections have been removed.
The default context is referenced in the web.xml via the parentContextKey parameter:
<context-param>
<param-name>parentContextKey</param-name>
<param-value>default.context</param-value>
</context-param>
This parameter is used by the ContextLoader to locate the parent context, which
in turn allows the global resources to be located. The context loader is used by the
WarLoaderServlet to initialize the web contexts.
The scope counterpart to the global context is the global scope and it is referenced in the
web.xml via the globalScope parameter:
<context-param>
<param-name>globalScope</param-name>
<param-value>default</param-value> Deploying Red5 To Tomcat
48
</context-param>
11.4.3. Web context
Web context definitions are specified in Spring configuration files suffixed with -web.xml; If
your application is named oflaDemo then its configuration file would be named oflaDemo-
web.xml. The Spring web context files should not be confused with J2EE context
descriptors as they are only used for red5 web contexts and the later are used by Tomcat.
Each web context must have a corresponding configuration file, the configuration files are
specified using an ant- style parameter in the web.xml as shown below.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/classes/*-web.xml</param-value>
</context-param>
Context configuration files specify the resources that are used to notify the application
about joining / leaving clients and provide the methods that a client can call. Additionally,
the configuration files specify the scope hierarchy for these classes.
Every context configuration must contain a minimum of three entries - a context, scope,
and handler. The only exception to this rule is the root web application since it does not
have a handler application, in this case the global handler is used.
• Context - Each context must have a unique name assigned since all the
contexts exist within a single Spring application context. The root web context is named
web.context, additional contexts suffix this base name with their web application name; for
example oflaDemo would be named web.context.oflaDemo. A context is specified in the
web context file as shown below.
<bean id="web.context" class="org.red5.server.Context">
<property name="scopeResolver" ref="red5.scopeResolver" />
<property name="clientRegistry" ref="global.clientRegistry" />
<property name="serviceInvoker" ref="global.serviceInvoker" />
<property name="mappingStrategy" ref="global.mappingStrategy" />
</bean>
• Scope - Every application needs at least one scope that links the handler
to the context and the server. The scopes can be used to build a tree where clients can
connect to every node and share objects inside this scope (like shared objects or live
streams). You can consider the scopes as rooms or instances. The root scope has the
name web.scope, additional scope names should follow the naming convention specified
for contexts. A scope for oflaDemo would be named web.scope.oflaDemo so that it will not
conflict with other contexts.
• A scope bean has the following properties:Deploying Red5 To Tomcat
49
1. server - This references the server red5.server
2. parent - The parent for this scope is normally global.scope
3. context - Context for this scope, use the web.context for root and
• web.context.oflaDemo for oflaDemo
1. handler - Handler for this scope, which is similar to a main.asc in
• FMS.
1. contextPath - The path to use when connecting to this scope.
2. virtualHosts - A comma separated list of host names or IP addresses this scope
listens on. In the war version we do not control the host names, this is accomplished
by Tomcat.
The root scope definition looks like this:
<bean id="web.scope" class="org.red5.server.WebScope" init-method="register">
<property name="server" ref="red5.server" />
<property name="parent" ref="global.scope" />
<property name="context" ref="web.context" />
<property name="handler" ref="global.handler" />
<property name="contextPath" value="/" />
<property name="virtualHosts" value="*,localhost, localhost:8080" />
</bean>
The contextPath is similar to the docBase in the J2EE context file for each web application.
Where the docBase is used to locate resources by HTTP, the contextPath is use to find
resources via RTMP. Your applications may add additional elements after the configured
path to dynamically create extra scopes. The dynamically created scopes all use the same
handler but have their own properties, shared objects and live streams.
• Handler - Every context needs a handler to provide the methods called by
connecting clients. All handlers are required to implement
org.red5.server.api.IScopeHandler, however you may implement additional interfaces for
controlling access to shared objects or streams. A sample implementation is provided with
Red5 that may be used as your base class: org.red5.server.adapter.ApplicationAdapter.
Please refer to the javadoc for this class for additional details. As an example the scope
handler for the oflaDemo is shown:
<bean id="web.handler.oflaDemo"
class="org.red5.server.webapp.oflaDemo.Application"/>
The id attribute is referenced by the oflaDemo scope definition:Deploying Red5 To Tomcat
50
<bean id="web.scope.oflaDemo" class="org.red5.server.WebScope" init-
method="register">
<property name="server" ref="red5.server" />
<property name="parent" ref="global.scope" />
<property name="context" ref="web.context.oflaDemo" />
<property name="handler" ref="web.handler.oflaDemo" />
<property name="contextPath" value="/oflaDemo" />
<property name="virtualHosts" value="*,localhost, localhost:8080" />
</bean>
If you don't need any special server-side logic, you can use the default application handler
provided by Red5:
<bean id="web.handler" class="org.red5.server.adapter.ApplicationAdapter" />
11.4.4. External applications
An external application refers to a web application that accesses Red5 outside of the
ROOT web application. Whether these applications exist within the same JVM instance or
not, they may only access Red5 via RTMP or the AMF tunnel servlet. The tunnel servlet
is configured in the web.xml for each application that requires AMF communication with
Red5, an example is shown below:
<servlet>
<servlet-name>gateway</servlet-name>
<servlet-class>org.red5.server.net.servlet.AMFTunnelServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>gateway</servlet-name>
<url-pattern></servlet-mapping>
</servlet-mapping>
The tunnel servlet class must be on the classpath of the application under which it is
executed. In addition to the tunnel servlet the org.red5.server.net.servlet.ServletUtils class
is required along with the following library jars:
commons-codec-1.3.jar
commons-httpclient-3.0.1.jar
commons-logging-1.1.jar
log4j-1.2.14.jar
mina-core-1.1.2.jar
These jars should be placed in the WEB-INF/lib directory of your application. ex.Deploying Red5 To Tomcat
51
C:\Tomcat-6.0.14\webapps\myapp\WEB-INF\lib
11.5. Creating and deploying your application
In the following section, two applications will be covered. The first will be a web application
that communicates with Red5 via AMF or RTMP and has its own handler, referred to
as "RemoteApp". The second will consist an SWF that communicates with Red5 via
RTMP, this application will be called "LocalApp". Any IDE may be used to create these
applications as long as it supports Java; the Eclipse IDE is suggested. SWF files outlined in
the examples were created using AS3 in Flex.
11.5.1. Remote application
This example will provide you with the minimum amount of configuration needed for a
remote Red5 application. The following resources will be created:
• J2EE web application
• Client SWF
• Red5 handler class
• Spring web context
Steps
1. Create a web application named RemoteApp in your IDE.
2. Obtain a red5.jar, which may be downloaded from
http://red5.googlecode.com/files/red5.jar or built from source with the command "ant jar". This library is needed if you
extend the ApplicationAdapter for your scope handler.
3. Obtain the red5-remoting.jar, this may be accomplished by building yourself
from the command line with "ant remotejar" or by downloading it from
http://red5.googlecode.com/files/red5-remoting.jar. This library provides the AMF tunnel
servlet.
4. Place the library jars in your project library directory and add them to your build
classpath.
5. Compile the Java and Flex source.
6. Create a directory named RemoteApp in the Tomcat webapps directory. ex. C:
\Tomcat-6.0.14\webapps\RemoteApp
7. Copy the contents of the web directory to the RemoteApp directory.
8. From the bin directory copy the RemoteApp.swf to the webapps\RemoteApp directory.
9. Copy the lib directory and its contents to the WEB-INF, excluding the red5.jar file.
10. Copy the whole example directory and the RemoteApp-web.xml file from the bin
directory to the classes directory under ROOT. ex. C:\Tomcat- 6.0.14\webapps\ROOT
\WEB-INF\classesDeploying Red5 To Tomcat
52
11. Restart tomcat
12.Open your browser and go to:
http://localhost:8080/RemoteApp/RemoteApp.html13. Click on the RTMP or HTTP connect buttons. For a successful test you should see a
server response of "Hello World".
11.5.2. Local application
A simple application that resides entirely within the ROOT web application. This example
consists of a Spring web context, handler class, and a client SWF.
'Steps '
1. Create a web application named LocalApp in your IDE.
2. Obtain a red5.jar, which may be downloaded from
http://red5.googlecode.com/files/red5.jar or built from source with the command "ant jar". This library is needed if you
extend the ApplicationAdapter for your scope handler.
3. Place the library jar in your project library directory and add it to your build classpath.
4. Compile the Java and Flex source.
5. Copy the LocalApp.html and LocalApp.swf from the bin directory to the ROOT directory.
ex. C:\Tomcat-6.0.14\webapps\ROOT
6. Copy the whole example directory and the LocalApp-web.xml file from the bin directory
to the classes directory under ROOT. ex. C:\Tomcat- 6.0.14\webapps\ROOT\WEB-INF
\classes
7. Restart tomcat
8. Open your browser and go to:
http://localhost:8080/LocalApp.html9. Click on the connect button. For a successful test you should see a server response of
"Hello World".
11.5.3. Example Source
The example application source is available in Subversion at
https://red5.googlecode.com/svn/java/example/trunk/
11.6. Additional web configuration
Log4j - The path to the logging configuration file and the Spring logging startup servlet are
shown below. These entries should precede the war loader servlet entry so that logging is
initialized prior to Red5 startup.
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/log4j.properties</param-value> Deploying Red5 To Tomcat
53
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
AMF gateway - This servlet provides communication with server applications using AMF.
<servlet>
<servlet-name>gateway</servlet-name>
<servlet-class>org.red5.server.net.servlet.AMFGatewayServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>gateway</servlet-name>
<url-pattern>/gateway</url-pattern>
</servlet-mapping>
RTMPT - This servlet implements an RTMP tunnel via HTTP, this is normally used to
bypass firewall issues.
<servlet>
<servlet-name>rtmpt</servlet-name>
<servlet-class>org.red5.server.net.rtmpt.RTMPTServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>rtmpt</servlet-name>
<url-pattern>/open/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>rtmpt</servlet-name>
<url-pattern>/idle/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>rtmpt</servlet-name>
<url-pattern>/send/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>rtmpt</servlet-name>
<url-pattern>/close/*</url-pattern>
</servlet-mapping>
Security - The following entries are used to prevent retrieval of sensitive information.
<security-constraint>
<web-resource-collection>
<web-resource-name>Forbidden</web-resource-name>
<url-pattern>/WEB-INF/*</url-pattern>
</web-resource-collection>
<auth-constraint />
</security-constraint>
<security-constraint>
<web-resource-collection> Deploying Red5 To Tomcat
54
<web-resource-name>Forbidden</web-resource-name>
<url-pattern>/persistence/*</url-pattern>
</web-resource-collection>
<auth-constraint />
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Forbidden</web-resource-name>
<url-pattern>/streams/*</url-pattern>
</web-resource-collection>
<auth-constraint />
</security-constraint>
11.7. Troubleshooting
If you have problems with deployment or if your application does not start, follow these
steps prior to posting a bug. Directory examples use a typical windows based path
structure.
1. Stop the Tomcat server
2. Locate your Tomcat installation directory
C:\Program Files\Apache\Tomcat
1. Delete the "work" directory
C:\Program Files\Apache\Tomcat\work
1. Delete the "Catalina" directory from the "conf" directory
C:\Program Files\Apache\Tomcat\conf\Catalina
1. Delete the expanded war directories, if they exist
C:\Program Files\Apache\Tomcat\webapps\ROOT
C:\Program Files\Apache\Tomcat\webapps\echo
C:\Program Files\Apache\Tomcat\webapps\SOSample
1. Ensure your WAR files are in the webapps directory
C:\Program Files\Apache\Tomcat\webapps\ROOT.war
C:\Program Files\Apache\Tomcat\webapps\echo.war
C:\Program Files\Apache\Tomcat\webapps\SOSample.war
1. Restart TomcatDeploying Red5 To Tomcat
55
If you still experience problems, gather the following information and post an issue on Jira
after you do a quick search to see if others have experienced the same problem.
1. Java version
2. Tomcat version
3. Operating system
4. Red5 version (0.6.2, Trunk, Revision 2283, etc...)
11.8. Definitions
AMF::
A binary format based loosely on the Simple Object Access Protocol
(SOAP). It is used primarily to exchange data between an Adobe Flash
application and a database, using a Remote Procedure Call. Each AMF
message contains a body which holds the error or response, which will be
expressed as an ActionScript Object.
Ant::
Software tool for automating software build processes. It is similar to make
but is written in the Java language, requires the Java platform, and is best
suited to building Java projects.
AS3::
A scripting language based on ECMAScript, used primarily for the
development of websites and software using the Adobe Flash Player
platform.
Flex::
Software development kit and an IDE for a group of technologies initially
released in March of 2004 by Macromedia to support the development
and deployment of cross platform, rich Internet applications based on their
proprietary Macromedia Flash platform.
RTMP::
Real Time Messaging Protocol (RTMP) is a proprietary protocol developed
by Adobe Systems that is primarily used with Adobe Flash Media Server to
stream audio, video, and data over the internet to the Adobe Flash Player
client. RTMP can be used for Remote Procedure Calls. RTMP maintains a
persistent connection with an endpoint and allows real-time communication.
Other RPC services are made asynchronously with a single client/server
request/response model, so real-time communication is not necessary.
RTMPT::
RTMP using HTTP tunneling.Deploying Red5 To Tomcat
56
SWF::
Proprietary vector graphics file format produced by the Flash software
from Adobe. Intended to be small enough for publication on the web, SWF
files can contain animations or applets of varying degrees of interactivity
and function. SWF is also sometimes used for creating animated display
graphics and menus for DVD movies, and television commercials.
Tomcat::
A web container, or application server developed at the Apache Software
Foundation (ASF). Tomcat implements the servlet and the JavaServer
Pages (JSP) specifications from Sun Microsystems, providing an
environment for Java code to run in cooperation with a web server. It adds
tools for configuration and management but can also be configured by
editing configuration files that are normally XML-formatted. Tomcat includes
its own internal HTTP server.
11.9. Bibliography
• Red5 -
http://osflash.org/red5• Apache Tomcat -
http://tomcat.apache.org• Wikipedia -
http://en.wikipedia.org57This document describes how applications can stream ondemand videos (VOD) from or
record to custom directories other than the default streams folder inside the webapp.
12.1. Filename generator service
Red5 uses a concept called scope services for functionality that is provided for a certain
scope. One of these scope services is IStreamFilenameGenerator
http://dl.fancycode.com/red5/api/org/red5/server/api/stream/IStreamFilenameGenerator.html that generates
filenames for VOD streams that should be played or recorded.
12.2. Custom generator
To generate filename in different folders, a new filename generator must be implemented:
import org.red5.server.api.IScope;
import org.red5.server.api.stream.IStreamFilenameGenerator;
public class CustomFilenameGenerator implements IStreamFilenameGenerator {
/** Path that will store recorded videos. */
public String recordPath = "recordedStreams/";
/** Path that contains VOD streams. */
public String playbackPath = "videoStreams/";
/** Set if the path is absolute or relative */
public boolean resolvesAbsolutePath = false;
public String generateFilename(IScope scope, String name, GenerationType type) {
// Generate filename without an extension.
return generateFilename(scope, name, null, type);
}
public String generateFilename(IScope scope, String name, String extension, GenerationType type) {
String filename;
if (type == GenerationType.RECORD)
filename = recordPath + name;
else
filename = playbackPath + name;
if (extension != null)
// Add extension
filename += extension;
return filename;
}
public boolean resolvesToAbsolutePath()
{
return resolvesAbsolutePath;
}
}
The above class will generate filenames for recorded streams like recordedStreams/
red5RecordDemo1234.flv and use the directory videoStreams as source for all VOD
streams.Customize Stream Paths
58
12.3. Activate custom generator
In the next step, the custom generator must be activate in the configuration files for the
desired application.
Add the following definition to yourApp/WEB-INF/red5-web.xml:
<bean id="streamFilenameGenerator"
class="path.to.your.CustomFilenameGenerator" />
This will use the class defined above to generate stream filenames.
12.4. Change paths through configuration
While the class described here works as expected, it's a bit unhandy to change the paths
inside the code as every change requires recompilation of the class.
Therefore you can pass parameters to the bean defined in the previous step to specify the
paths to use inside the configuration file.
Add three methods to your class that will be executed while the configuration file is parsed:
public void setRecordPath(String path) {
recordPath = path;
}
public void setPlaybackPath(String path) {
playbackPath = path;
}
public void setAbsolutePath(Boolean absolute) {
resolvesAbsolutePath = absolute;
}
Now you can set the paths inside the bean definition:
<bean id="streamFilenameGenerator"
class="path.to.your.CustomFilenameGenerator">
<property name="recordPath" value="recordedStreams/" />
<property name="playbackPath" value="videoStreams/" />
<property name="absolutePath" value="false" />
</bean>
<bean id="streamFilenameGenerator"
class="path.to.your.CustomFilenameGenerator">
<property name="recordPath" value="/path/to/recordedStreams/" />
<property name="playbackPath" value="/path/to/videoStreams/" />
<property name="absolutePath" value="true" />
</bean>
You can also move the paths to the yourApp/WEB-INF/red5-web.properties file and use
parameters to access them:Customize Stream Paths
59
<bean id="streamFilenameGenerator"
class="path.to.your.CustomFilenameGenerator">
<property name="recordPath" value="${recordPath}" />
<property name="playbackPath" value="${playbackPath}" />
<property name="absolutePath" value="${absolutePath}" />
</bean>
In that case you will have to add the following lines to your properties file:
red5-web.properties -
recordPath=recordedStreams/
playbackPath=videoStreams/
absolutePath=false
recordPath=/path/to/recordedStreams/
playbackPath=/path/to/videoStreams/
absolutePath=true 60
This document describes the Red5 API that was introduced in version 0.6 to protect access
to streams and/or shared objects similar to what the properties Client.readAccess and
Client.writeAccess provide in the Macromedia Flash Communication Server / Flash Media
Server 2.
13.1. Stream Security
Read (playback) and write (publishing/recording) access to streams is protected separately
in Red5.
13.1.1. Stream playback security
For applications that want to limit the playback of streams per user or only want to provide
access to streams with a given name, the interface IStreamPlaybackSecurity
http://dl.fancycode.com/red5/api/org/red5/server/api/stream/IStreamPlaybackSecurity.html is
available in Red5.
It can be implemented by any object and registered in the ApplicationAdapter
http://dl.fancycode.com/red5/api/org/red5/server/adapter/ApplicationAdapter.html . An arbitrary
number of stream security handlers is supported per application. If at least one of the
handlers denies access to the stream, the client receives an error NetStream.Failed with a
description field giving a corresponding error message.
An example handler that only allows access to streams that have a name starting with
liveStream is described below:
import org.red5.server.api.IScope;
import org.red5.server.api.stream.IStreamPlaybackSecurity;
public class NamePlaybackSecurity implements IStreamPlaybackSecurity {
public boolean isPlaybackAllowed(IScope scope, String name, int start,
int length, boolean flushPlaylist) {
if (!name.startswith("liveStream")) {
return false;
} else {
return true;
}
};
}
To register this handler in the application, add the following code in the appStart method:
registerStreamPlaybackSecurity(new NamePlaybackSecurity());
Red5 includes a sample security handler that denies all access to streams
(DenyAllStreamAccess
http://dl.fancycode.com/red5/api/org/red5/server/api/stream/support/DenyAllStreamAccess.html).Security
61
13.1.2. Stream publishing security
In most applications that allow the user to publish and/or record streams, this access
must be limited to prevent the server from being misused. Therefore, Red5 provides the
interface IStreamPublishSecurity
http://dl.fancycode.com/red5/api/org/red5/server/api/stream/IStreamPublishSecurity.html to deny publishing of certain streams.
Similar to IStreamPlaybackSecurity
http://dl.fancycode.com/red5/api/org/red5/server/api/stream/IStreamPlaybackSecurity.html, it can be implemented by any object and registered
in the ApplicationAdapter
http://dl.fancycode.com/red5/api/org/red5/server/adapter/ApplicationAdapter.html. If one of the registered handlers denies access, the client receives
an error NetStream.Failed with a description field giving a corresponding error message.
An example handler that only allows authenticated connections to publish a live stream
starting with liveStream and deny all other access is described below:62
14.1. I. Select a scripting implementation
Level: Beginner
Red5 includes interpreters for the following scripting languages:
• Javascript - version 1.6 (Mozilla Rhino version 1.6 R7)
• JRuby - version 1.0.1 (Ruby version 1.8.5)
• Jython - version 2.2 (Python version 2.1)
• Groovy - version 1.0
• Beanshell - version 2.0b4
Future versions may include:
• JudoScript
• Scala
• PHP (This one is non-trivial, I may just provide a bridge)
• Actionscript (Maybe SSAS)
The scripting implementation classes are pre-specified in the following locations depending
upon your Java version:
Java5 - js-engine.jar, jython-engine.jar, groovy-engine.jar
Java6 - resources.jar
File location: /META-INF/services/javax.script.ScriptEngineFactory
It is most likely that the classes read from the jdk or jre will be prefered over any specified
elsewhere.
14.2. II. Configuring Spring
Level: Intermediate
Step one is to locate your web applications red5-web.xml file. Within the xml config file the
web.scope bean definition must supply a web.handler, this handler is your Red5 application
(An application must extend the org.red5.server.adapter.ApplicationAdapter class).
The application provides access to the Red5 server and any service instances that are
created. The service instances and the application itself may be scripted. Bean definitions
in Spring config files may not have the same id, here are some web handler definition
examples:
• Java class implementationScripting Implementations
63
<bean id="web.handler" class="org.red5.server.webapp.oflaDemo.MultiThreadedApplicationAdapter" />
• Javascript implementation
<bean id="web.handler" class="org.red5.server.script.rhino.RhinoScriptFactory">
<constructor-arg index="0" value="classpath:applications/main.js"/>
<constructor-arg index="1">
<list>
<value>org.red5.server.api.IScopeHandler</value>
<value>org.red5.server.adapter.IApplication</value>
</list>
</constructor-arg>
<constructor-arg index="2">
<value>org.red5.server.adapter.ApplicationAdapter</value>
</constructor-arg>
</bean>
• Ruby implementation
<bean id="web.handler" class="org.springframework.scripting.jruby.JRubyScriptFactory">
<constructor-arg index="0" value="classpath:applications/main.rb"/>
<constructor-arg index="1">
<list>
<value>org.red5.server.api.IScopeHandler</value>
<value>org.red5.server.adapter.IApplication</value>
</list>
</constructor-arg>
</bean>
• Groovy implementation
<bean id="web.handler" class="org.red5.server.script.groovy.GroovyScriptFactory">
<constructor-arg index="0" value="classpath:applications/main.groovy"/>
<constructor-arg index="1">
<list>
<value>org.red5.server.api.IScopeHandler</value>
<value>org.red5.server.adapter.IApplication</value>
</list>
</constructor-arg>
</bean>
• Python implementation
Red5 Open Source
Flash Server (0.7.1) 51
<bean id="web.handler" class="org.red5.server.script.jython.JythonScriptFactory">
<constructor-arg index="0" value="classpath:applications/main.py"/>
<constructor-arg index="1">
<list> Scripting Implementations
64
<value>org.red5.server.api.IScopeHandler</value>
<value>org.red5.server.adapter.IApplication</value>
Scripting Implementations
</list>
</constructor-arg>
<constructor-arg index="2">
<list>
<value>One</value>
<value>2</value>
<value>III</value>
</list>
</constructor-arg>
</bean>
In general the configuration using scripted classes is defined using the constructor
arguments (see interpreter section) in the following order:
• Argument 1 - Location of the script source file
• Argument 2 - Java interfaces implemented by the script.
The interfaces for the code which extends an Application are basically boilerplate as seen
in the examples above; You do not have to use those interfaces in all your script definitions.
• Argument 3 - Java classes extended by the script.
The extended class is not always necessary, it depends upon the scripting engine
implementation.
The example location starts with classpath:applications which in physical disk terms for the
"oflaDemo" application equates to webapps/oflaDemo/WEB-INF/applications
14.3. III. Creating an application script
14.3.1. 1. Application adapter
Scripting an application adapter is more difficult in some languages than it is in others,
because of this I present the Ruby example which works really well and is easy to write and
integrate. The application services are easily written in any of the supported languages, but
they require a Java interface at a minimum.
i. JRuby application adapter implementation
# JRuby
require 'java'
module RedFive
include_package "org.red5.server.api"
include_package "org.red5.server.api.stream"
include_package "org.red5.server.api.stream.support"
include_package "org.red5.server.adapter"
include_package "org.red5.server.stream"
end
#
# application.rb - a translation into Ruby of the ofla demo application, a red5 example. Scripting Implementations
65
#
# @author Paul Gregoire
#
class Application < RedFive::ApplicationAdapter
attr_reader :appScope, :serverStream
attr_writer :appScope, :serverStream
def initialize
#call super to init the superclass, in this case a Java class
super
puts "Initializing ruby application"
end
def appStart(app)
puts "Ruby appStart"
@appScope = app
return true
end
def appConnect(conn, params)
puts "Ruby appConnect"
measureBandwidth(conn)
puts "Ruby appConnect 2"
if conn.instance_of?(RedFive::IStreamCapableConnection)
puts "Got stream capable connection"
sbc = RedFive::SimpleBandwidthConfigure.new
sbc.setMaxBurst(8388608)
sbc.setBurst(8388608)
sbc.setOverallBandwidth(8388608)
conn.setBandwidthConfigure(sbc)
end
return super
end
def appDisconnect(conn)
puts "Ruby appDisconnect"
if appScope == conn.getScope && @serverStream != nil
@serverStream.close
end
super
end
def toString
return "Ruby toString"
end
def setScriptContext(scriptContext)
puts "Ruby application setScriptContext"
end
def method_missing(m, *args)
super unless @value.respond_to?(m)
return @value.send(m, *args)
end
end Scripting Implementations
66
14.3.2. 2. Application services
Here is an example of a Java interface (Yes, the methods are supposed to be empty) which
is used in the examples to provide a template for applications which will gather a list of files
and return them as a "Map" (key-value pairs) to the caller.
i. Simple Java interface for implementation by scripts
package org.red5.server.webapp.oflaDemo;
import java.util.Map;
public interface IDemoService {
/**
* Getter for property 'listOfAvailableFLVs'.
*
* @return Value for property 'listOfAvailableFLVs'.
*/
public Map getListOfAvailableFLVs();
public Map getListOfAvailableFLVs(String string);
}
ii. Spring bean definition for a script implementation of the interface
<bean id="demoService.service" class="org.springframework.scripting.jruby.JRubyScriptFactory">
<constructor-arg index="0" value="classpath:applications/demoservice.rb"/>
<constructor-arg index="1">
<list>
<value>org.red5.server.webapp.oflaDemo.IDemoService</value>
</list>
</constructor-arg>
</bean>
iii.JRuby script implementing the interface
# JRuby - style
require 'java'
module RedFive
include_package "org.springframework.core.io"
include_package "org.red5.server.webapp.oflaDemo"
end
include_class "org.red5.server.api.Red5"
include_class "java.util.HashMap"
#
# demoservice.rb - a translation into Ruby of the ofla demo application, a red5 example.
#
# @author Paul Gregoire Scripting Implementations
67
#
class DemoService < RedFive::DemoServiceImpl
attr_reader :filesMap
attr_writer :filesMap
def initialize
puts "Initializing ruby demoservice"
super
@filesMap = HashMap.new
end
def getListOfAvailableFLVs
puts "Getting the FLV files"
begin
dirname = File.expand_path('webapps/oflaDemo/streams').to_s
Dir.open(dirname).entries.grep(/\.flv$/) do |dir|
dir.each do |flvName|
fileInfo = HashMap.new
stats = File.stat(dirname+'/'+flvName)
fileInfo["name"] = flvName
fileInfo["lastModified"] = stats.mtime
fileInfo["size"] = stats.size || 0
@filesMap[flvName] = fileInfo
print 'FLV Name:', flvName
print 'Last modified date:', stats.mtime
print 'Size:', stats.size || 0
print '-------'
end
end
rescue Exception => ex
puts "Error in getListOfAvailableFLVs #{errorType} \n"
puts "Exception: #{ex} \n"
puts caller.join("\n");
end
return filesMap
end
def formatDate(date)
return date.strftime("%d/%m/%Y %I:%M:%S")
end
def method_missing(m, *args)
super unless @value.respond_to?(m)
return @value.send(m, *args)
end
end
iv.Java application implementing the interface, upon which the Ruby code was based (This
code is NOT needed when using the script)Scripting Implementations
68
package org.red5.server.webapp.oflaDemo;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.red5.server.api.IScope;
import org.red5.server.api.Red5;
import org.springframework.core.io.Resource;
public class DemoService {
protected static Log log = LogFactory.getLog(DemoService.class.getName());
/**
* Getter for property 'listOfAvailableFLVs'.
Scripting Implementations
*
* @return Value for property 'listOfAvailableFLVs'.
*/
public Map getListOfAvailableFLVs() {
IScope scope = Red5.getConnectionLocal().getScope();
Map<String, Map> filesMap = new HashMap<String, Map>();
Map<String, Object> fileInfo;
try {
log.debug("getting the FLV files");
Resource[] flvs = scope.getResources("streams/*.flv");
if (flvs != null) {
for (Resource flv : flvs) {
File file = flv.getFile();
Date lastModifiedDate = new Date(file.lastModified());
String lastModified = formatDate(lastModifiedDate);
String flvName = flv.getFile().getName();
String flvBytes = Long.toString(file.length());
if (log.isDebugEnabled()) {
log.debug("flvName: " + flvName);
log.debug("lastModified date: " + lastModified);
log.debug("flvBytes: " + flvBytes);
log.debug("-------");
}
fileInfo = new HashMap<String, Object>();
fileInfo.put("name", flvName);
fileInfo.put("lastModified", lastModified);
fileInfo.put("size", flvBytes);
filesMap.put(flvName, fileInfo);
}
}
Resource[] mp3s = scope.getResources("streams/*.mp3");
if (mp3s != null) {
for (Resource mp3 : mp3s) {
File file = mp3.getFile();
Date lastModifiedDate = new Date(file.lastModified());
String lastModified = formatDate(lastModifiedDate);
String flvName = mp3.getFile().getName();
String flvBytes = Long.toString(file.length());
if (log.isDebugEnabled()) {
log.debug("flvName: " + flvName);
log.debug("lastModified date: " + lastModified);
log.debug("flvBytes: " + flvBytes);
log.debug("-------");
}
fileInfo = new HashMap<String, Object>();
fileInfo.put("name", flvName);
fileInfo.put("lastModified", lastModified);
fileInfo.put("size", flvBytes); Scripting Implementations
69
filesMap.put(flvName, fileInfo);
}
}
} catch (IOException e) {
log.error(e);
}
return filesMap;
}
private String formatDate(Date date) {
SimpleDateFormat formatter;
String pattern = "dd/MM/yy H:mm:ss";
Locale locale = new Locale("en", "US");
formatter = new SimpleDateFormat(pattern, locale);
return formatter.format(date);
}
}