ELC Technologies  /  
To use this application you need the Adobe Flash Player

Tutorial - Red5, AS3, FC4, and Shared Fridge Magnets!

By Cary Dunn / January 24, 2008


Jargon...zZzZz

Red5 is an Open Source Flash Server written in Java that supports: Streaming Audio/Video (FLV and MP3), Recording Client Streams (FLV only), Shared Objects, Live Stream Publishing, Remoting”

Red5 is essentially an open source alternative to Adobe’s Flash Media Server. Both technologies leverage Adobe’s RTMP (Real Time Message Protocol) to stream small binary fragments in real time. The packets are multiplexed and therefore only one persistent connection is needed for each user. Objects are serialized via AMF (Action Message Format) which is what we will be using in this tutorial to create SharedObjects, which as the name suggests, are objects (in this case refrigerator magnets!) that are shared amongst all viewers of the application.



Red5 Boostrap

Download Red5

Once installed, navigate the Red5 root directory to get started.


Red5 Structure Rundown

Just the important stuff...

In the root Red5 directory you’ll find red5.jar which holds a pre-compiled jar holding the red5 java classes. You’ll use this later to compile your main application class.

The directory webapps is where you will be creating new Red5 applications. All new applications have a consistent structure which is laid out as a template for you in doc/templates


Red5 New Application Structure Rundown

Creating a new Red5 application is simple. We just create a new folder in webapps/.

We will create an app called elcMagnets so we create a directory for it and now have webapps/elcMagnets. Red5 expects us to also have a directory inside our new application named WEB-INF/ so we create that as well, and now have webapps/elcMagnets/WEB-INF.

There are 4 default configuration files in doc/templates/myapp/WEB-INF that we will modify and use in our app, so we can copy those over to our elcMagnets directory. (log4j.properties, red5-web.properties, red5-web.xml, web.xml)

You can read up about all the properties and handlers specified in these files here.

For now, we only want to customize these files for our current app. We need to change the webapp.contextPath specified in red5-web.properties to reflect our newly created app. Take note of the virtualHosts parameter and remember to deal with it on deployment to a remote host.

webapp.contextPath=/elcMagnets
webapp.virtualHosts=localhost, 127.0.0.1


The only other configuration file we will modify for now is red5-web.xml. For this we need to specify the handler that is invoked when users connect to the app. You can read up on handlers here.

For the purposes of this demo app we will only be creating a web.handler. We will end up writing Application.java as the web.handler inside the a package called package org.red5.server.webapp.elcMagnets so we will set our web.handler to org.red5.server.webapp.elcMagnets.Application.

<bean id=”web.handler” 
	    class=”org.red5.server.webapp.elcMagnets.Application” 
		singleton=true” />


Lastly we will comment out the sample service bean since we will not be using that in this demo.


Application.java

To keep things organized, we will create the directories lib/, classes/, src/ inside webapps/. Next we will create Application.java inside of src/.

As you recall, Application.java will serve as our web.handler, and therefore needs to extend ApplicationAdapter. (For more info on handlers, see the ‘HOWTO-NewApplications.txt’) In short, it allows you to stack functionality on top of existing events (connect, disconnect, join, leave, start, stop) or create your own.

Our example handler will be trivial, but illustrate calls to the Red5 server.

package org.red5.server.webapp.elcMagnets;

import org.red5.server.adapter.ApplicationAdapter;

public class Application extends ApplicationAdapter {
	public String high5Red5(int how_many)
	{
		String highFives = “”;
		if(how_many==0){ return “I dont like you anyways, bro.”; }
		for(int i=0;i<how_many;i++){ highFives += “*Smack*\n”; }
		return highFives;
	}
}


Later, we can directly call this handler in ActionScript...
nc.call("high5Red5",nr,5);
// Or more generally...
netconnection.call("function",responder,arguments.....)


Compiling Application.java

What we want to end up with is a nicely packaged up elcMagnets.jar located in lib/

So from src/ we compile Application.java to the classes/ directory.

javac -classpath ../../../../red5.jar -d ../classes Application.java


Now lets create our jar file. First we need our MANIFEST.MF. If you aren’t familiar with it...


MANIFEST.MF

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7
Created-By: 1.5.0_06-b05 (Sun Microsystems Inc.)
Class-Path: ../../../../red5.jar

(you can try yum/port install ant, but seem to remember building it)


Compiling elcMagnets.jar

jar -cmf MANIFEST.MF ../lib/elcMagnets.jar ../classes/org/red5/server/webapp/elcMagnets/Application.class


OK! Done with Red5.

You should now be able to start up your Red5 server and have it load up our new elcMagnets application.

Flash App

Next we will create an AS3 flash app to interact with our Red5 application and utilize SharedObjects.

Fridge.as (Document Class)

(I'm just going to post code, comment if you need any explanation.)

//	=======================================
// 	Cary Dunn 
//	ELC Technologies http://www.elctech.com
//

package
{
	import flash.events.*;
	import flash.display.MovieClip;
	import flash.text.TextField;
	import flash.errors.IOError;
	import flash.system.Security;
	import caurina.transitions.Tweener;
	import flash.net.*;
	import com.elctech.Magnet;
	
	public class Fridge extends MovieClip
	{
		NetConnection.defaultObjectEncoding = ObjectEncoding.AMF0 ;
		private var nc:NetConnection = null;
		private var alphabet:Array = new Array;
		private const LETTERS:Array	= ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z",",","!"]
		
		public function Fridge():void
		{
			nc = new NetConnection();
			nc.addEventListener(NetStatusEvent.NET_STATUS,netStatusHandler);
			var nr:Responder = new Responder(onHighFives,null);;
			nc.connect("rtmp://localhost/elcMagnets");
			nc.call("high5Red5",nr,5);
		}
		
		private function onHighFives(resp:String):void
		{
			trace(resp);
		}

		
		private function netStatusHandler(event:NetStatusEvent):void
		{
			trace(event.info.code);
			if(event.info.code == "NetConnection.Connect.Success")
			{
				createAlphabet();
			}
		}
		
		private function createAlphabet():void
		{
			for(var i:uint = 0; i < LETTERS.length; i++)
			{
				var new_magnet:Magnet = new com.elctech.Magnet(LETTERS[i],nc,i);
				addChild(new_magnet);
				alphabet.push(new_magnet);
			}
		}
	}
}

com.elctech.Magnet.as

//	=======================================
// 	Cary Dunn 
//	ELC Technologies http://www.elctech.com
//

package com.elctech
{
	import flash.display.MovieClip;
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.geom.Rectangle;
  import flash.events.*;
	import flash.display.Stage;
	import flash.text.TextField;
	import flash.net.*;
	import flash.utils.Timer;
	import caurina.transitions.Tweener;
	
	public class Magnet extends MovieClip
	{
		private var _id:uint = 0;
		private var _so = null;
		private var _nc:NetConnection = null;
		private var _l:String = null;
		static internal var dragging:Boolean = false;
		static const MAGNET_COLORS:Array = [0xFF3333, 0x3399FF, 0x339966, 0x993399, 0xFF9933]
		
		static internal const ELASTICITY:Number = .5;
		static internal const FRICTION:Number = .5;
		private var ax:Number = 0;
		private var ay:Number = 0;
    private var vx:Number = 0;
		private var vy:Number = 0;
		
		public function Magnet(l:String, nc:NetConnection, i:uint):void
		{
			this.letter.text = l;
			this.letter.textColor = MAGNET_COLORS[Math.round(Math.random()*(MAGNET_COLORS.length-1))];
			this.x = Math.round(Math.random()*390)+67;
			this.y = Math.round(Math.random()*260)+20;
			trace("New Magnet " + l);
			
			_l = l;
			_nc = nc;
			_id = i;
			
			_so = SharedObject.getRemote("letter_"+_id, _nc.uri, true);
			_so.addEventListener(SyncEvent.SYNC,syncEventHandler);
			_so.connect(_nc);
			
			this.buttonMode = true;
			
			this.addEventListener(MouseEvent.MOUSE_DOWN, function(evt:Event):void {
				dragging = true;
				stage.addEventListener(MouseEvent.MOUSE_UP, stopDragging);
				evt.target.parent.addEventListener(Event.ENTER_FRAME, updatePosition);
			});
			
			this.addEventListener(MouseEvent.MOUSE_UP, stopDragging);
		}
		
		private function stopDragging(evt:Event):void
		{
			this.removeEventListener(Event.ENTER_FRAME, updatePosition);
			stage.removeEventListener(MouseEvent.MOUSE_UP, stopDragging);
			dragging = false;
		}
		
		private function updatePosition(evt:Event):void
		{
      ax = (stage.mouseX-this.x+Math.random()*5)*ELASTICITY;
      ay = (stage.mouseY-this.y)*ELASTICITY;
      vx += ax;
      vy += ay;
      vx *= FRICTION;
      vy *= FRICTION;
      this.x += vx;
      this.y += vy;
      this.scaleX = (100-Math.abs(ax)*2)/100;
      this.scaleY = (100-Math.abs(ay)*2)/100;
      this.rotation = ax*3;

			_so.setProperty("currentPosition", {x: evt.target.x, y: evt.target.y});
		}
		
		private function syncEventHandler(evt:SyncEvent):void
		{
			trace("Sync for letter "+_l);
			if(dragging){ return; }
			
			Tweener.addTween(this, {x:_so.data.currentPosition.x, y:_so.data.currentPosition.y, time:0.5, transition:"easeOutBack"});
		}
	}
}

Download Project Source



Installing Red5 on FC4

This section documents my trials and tribulations with installing Red5 on an Amazon EC2 instance running a standard FC4 image. This is a nasty (but working) implementation of this.

Some of the rpms are unnecessary, but some of the yum packages were failing on me. Anyways, this might help someone...

$ yum install gcc
$ rpm -ivh ftp://rpmfind.net/linux/fedora/core/updates/4/i386/libstdc++-devel-4.0.2-8.fc4.i386.rpm
$ rpm -ivh ftp://rpmfind.net/linux/fedora/core/updates/4/i386/gcc-c++-4.0.2-8.fc4.i386.rpm
$ yum install fedora-rpmdevtools
$ fedora-buildrpmtree
$ cd /etc/yum.repos.d/
$ wget http://www.jpackage.org/jpackage.repo
---->>> download jdk 5.0 update .bin from <a href="http://java.sun.com/javase/downloads/index.jsp" target="_blank">sun</a>, scp it up to server (requires accepting of TOS)
---->>> cp jdk-....bin rpmbuild/SOURCES
$ wget http://mirrors.dotsrc.org/jpackage/1.7/generic/non-free/SRPMS/java-1.5.0-sun-1.5.0.14-1jpp.nosrc.rpm
$ rpmbuild --rebuild java-1.5.0-sun-1.5.0.14-1jpp.nosrc.rpm
$ cd ~/rpmbuild/RPMS/i586/
$ (echo config gpgcheck 0; echo localinstall java-1.5.0-sun*.rpm; echo run) > yum-cmd
$ yum shell yum-cmd
$ rm yum-cmd

$ cd ~/
wget http://archive.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.tar.gz
$ cd /usr/local/
$ tar -zxf ~/apache-ant-1.7.0-bin.tar.gz
$ mv apache-ant-1.7.0 ant

$ vim /etc/profile
PATH=$PATH:$HOME/bin:/usr/local/ant/bin
export PATH

$ source /etc/profile

$ tar -zxvf red5-0.6.3.tar.gz
$ cd red5-0.6.3
$ make
$ make install
$ /usr/lib/red5/red5.sh

At this point if you can hit http://{ip here}:5080 you are golden.

JRuby&Red5



Comments

Interesting post?  Show some love and post a comment!
Using pieces of this code?  Post a link!

Add a Comment