<< April 2010 | Home | June 2010 >>

Installing Red5 on a Linux system

Installing Red5 : Open Source Flash Server on an Ubuntu system from the source

Building and installing a Red5 server on a Linux box.

Adding a new user

First we create a new user for the Red5 service.
server:~> adduser red5
and deactivate the interactive shell.
red5:x:10xy:10xy:,,,:/home/red5:/bin/false

Installing a Red5 server on a Linux server.

Building a Red5 installer

To get a grip on Red5 we import the source into an IDE and build the server locally using the current stable release (as of May 2010 this is version 0.9.1).
server:~> svn checkout http://red5.googlecode.com/svn/java/server/tags/0_9_1
server:~> mv 0_9_1 red5-server-0.9.1
server:~> ln -s red5-server-0.9.1 red5-server-0.9.x
Look into the interior of the server, adapt code as needed.
server:~> cd red5-server-0.9.x
server:~> ant dist
Create a
server:~> ant dist-installer
Or download the latest release from http://code.google.com/p/red5/ if the binary distribution is all you need.

Add a Red5 server startup script

Based on the /etc/init.d/skeleton a startup script for the installation above could look like this:
#! /bin/sh
### BEGIN INIT INFO
# Provides:          red5-server
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Red5 server script
# Description:       Based on skeleton
### END INIT INFO

# Author: fluffi 
#
# Do NOT "set -e"

# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Red5 server"
NAME=red5-server

DAEMON=/home/red5/red5-server-0.9.x/dist/red5.sh
DAEMON_STOP=/home/red5/red5-server-0.9.x/dist/red5-shutdown.sh
DAEMON_ARGS=""
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME

JAVA_HOME=/usr/lib/jvm/java-6-sun/jre
RED5_HOME=/home/red5/red5-server-0.9.x/dist

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions

DAEMON_OPTS="--quiet"
DAEMON_OPTS="--chdir $RED5_HOME --chuid red5"

#
# Function that starts the daemon/service
#
do_start()
{
	# Return
	#   0 if daemon has been started
	#   1 if daemon was already running
	#   2 if daemon could not be started
	start-stop-daemon --start --background --chdir $RED5_HOME --chuid red5 --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
		|| return 1
	start-stop-daemon --start --background --chdir $RED5_HOME --chuid red5 --pidfile $PIDFILE --startas $DAEMON -- \
		$DAEMON_ARGS \
		|| return 2
	# Add code here, if necessary, that waits for the process to be ready
	# to handle requests from services started subsequently which depend
	# on this one.  As a last resort, sleep for some time.
}

#
# Function that stops the daemon/service
#
do_stop()
{
	# Return
	#   0 if daemon has been stopped
	#   1 if daemon was already stopped
	#   2 if daemon could not be stopped
	#   other if a failure occurred
	start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
	RETVAL="$?"
	[ "$RETVAL" = 2 ] && return 2
	# Wait for children to finish too if this is a daemon that forks
	# and if the daemon is only ever run from this initscript.
	# If the above conditions are not satisfied then add some other code
	# that waits for the process to drop all resources that could be
	# needed by services started subsequently.  A last resort is to
	# sleep for some time.
	start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
	[ "$?" = 2 ] && return 

	start-stop-daemon --start --background --chdir $RED5_HOME --chuid red5 --pidfile $PIDFILE --startas $DAEMON_STOP -- \
	sleep 10

	# Many daemons don't delete their pidfiles when they exit.
	rm -f $PIDFILE
	return "$RETVAL"
}

#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
	#
	# If the daemon can reload its configuration without
	# restarting (for example, when it is sent a SIGHUP),
	# then implement that here.
	#
	start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
	return 0
}

case "$1" in
  start)
	[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
	do_start
	case "$?" in
		0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
		2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
	esac
	;;
  stop)
	[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
	do_stop
	case "$?" in
		0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
		2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
	esac
	;;
  restart|force-reload)
	#
	# If the "reload" option is implemented then remove the
	# 'force-reload' alias
	#
	log_daemon_msg "Restarting $DESC" "$NAME"
	do_stop
	case "$?" in
	  0|1)
		do_start
		case "$?" in
			0) log_end_msg 0 ;;
			1) log_end_msg 1 ;; # Old process is still running
			*) log_end_msg 1 ;; # Failed to start
		esac
		;;
	  *)
	  	# Failed to stop
		log_end_msg 1
		;;
	esac
	;;
  *)
	#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
	echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
	exit 3
	;;
esac

:

Starting the Red5 server manually

With the red5-server startup script the Red5 server should start with uid=red5.
server:~> sudo /etc/init.d/red5-server start
Point your web browser to http://localhost:5080/ to verify the basic installation:

Making Red5 script run at boot time

server:~> update-rc.d red5-server defaults

First experiments with the installed Red5 server.

Pimp some Spring beans in the Red5 server installation

First experiments with the installed Red5 server.

The oflaDemo streams from data files inside the exploded war. In this experiment i want to stream from outside the Red5 installation. Take a deep breath and dive into the code of the Red5 server:

Some small changes in DefaultStreamFilenameGenerator and the class is configurable via Spring: First i refactored the hardwired local variable "streams/" into a field to make to make the prefix configurable and added an appropriate setter.
    private String prefix = "streams/";
...
    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }
Next was to refactor the hardwired absolute path flag:
    public boolean resolvesToAbsolutePath() {
        return false;
    }
To make it configurable, too.
    private boolean absolutePath = false;
...
    public boolean resolvesToAbsolutePath() {
        return absolutePath;
    }
    public void setAbsolutePath(boolean absolutePath) {
        this.absolutePath = absolutePath;
    }
The resulting bean definition in our example is added to red5-default.xml and looks is as follows (beware! name/id matters with Red5 bean resolving strategy):
    <bean id="streamFilenameGenerator" class="org.red5.server.stream.DefaultStreamFilenameGenerator">
        <property name="prefix" value="${sfg.prefix}" />
        <property name="absolutePath" value="${sfg.absolutePath}" />
    </bean>
With the configuration inside red5.properties.
# streamFilenameGenerator configuration
sfg.prefix=/tmp/upload/
sfg.absolutePath=true

Test the pimped version of Red5 with some small changes in the oflaDemo.

As with the Red5 DefaultStreamFilenameGenerator the oflaDemo, DemoService is given a configurable field:
    private String fileDirectory = "streams/";
...
    public void setFileDirectory(String fileDirectory) {
        this.fileDirectory = fileDirectory;
    }
The resulting configurable bean definition inside WEB-INF/red5-web.xml:
    <bean id="demoService.service" class="org.red5.demos.oflaDemo.DemoService">
        <property name="fileDirectory" value="${fileDirectory}" />
    </bean>
is configured via WEB-INF/red5-web.properties
#fileDirectory=streams/
fileDirectory=file:/tmp/upload/
Drop the oflaDemo.war into the embedded Tomcat deploy directory.
server:~> cp oflaDemo.war ~red5/red5/webapps
Red5 will "explode" the web archive and start the application. Point your browser to see the oflaDemo in action.