Archive for the 'red5' Category

OpenID From AIR

I’ve been working on some web services recently.  There’s both plain old browser accessed HTML pages plus an AMF interface to them.  One feature of the HTML version is OpenID authentication.  Now OpenID is all fine and dandy for a web application, but we get some problems when we want to use an AIR desktop client to connect and authenticate through OpenID. 

If you’re not familiar with how OpenID works, here’s a quick summary.

  1. User goes to an application (Usually a web-app)
  2. User types in their OpenID URL to that app
  3. They get forwarded to their OpenID page where they can either grant or deny access.
  4. That page then forwards them back to the original web app with an authentication token set.

Obviously, it’s kind of hard to redirect back to a desktop application.  I was thinking up some wacky work-a-rounds for this but then it hit me.

In the AIR app I can just use the HTML component and point it towards the login form of the web services.  The user can then log in using either username/password or OpenID just like they do on the website.  Now, here’s the cool part…  The AIR HTML component shares a network stack with the AIR/Flex NetConnection object.  That means any session/cookies/whatever opened in the HTML component carry through to the remoting calls I want to make from Actionscript. So I can authenticate using a web form, but then consume BlazeDS/LiveCycleDS/AMFPHP/Red5 services using AMF over Netconnection.

I did up a quick proof of concept and it works on both Windows and OSX.  I was able to successfully call a remoting service that requires an authenticated session.  So this was actually a much easier problem to figure out than I had feared.

Now, I’ll just need to make the web page that loads after a successful login somehow indicate to the AIR app that the user is successfully logged in.  I’ll probably either use a tiny Flash component that signals over LocalConnection, or I’ll just make the AIR app watch for when the HTML component gets to a specific URL. I’m pretty sure I can get this to be a completely seamless experience for the user.

Oh, and as a bonus… the user can sign up for a new account instead of log into an existing one from "within the app" instead of going to an external website to do that.


The Essential Guide to Open Source Flash Development

The book I’ve been working on, The Essential Guide to Open Source Flash Development, is now out in stores.  It’s hard to believe that I started working on it about 11 months ago!  It’s really great to see all of that hard work finally in print.

So What is it about?

The book does a few things.  First, about a third of the book introduces you to some open source tools for doing flash development.  Things like FlashDevelop, MTASC, SwfMill, ANT, and ASDT.  It’ll show you how to create an AS2 and an AS3 based flash application using completely free and open software.  This goes all the way from installing the tools, creating a sample app, writing up some unit tests for it, and then to publishing it to the web.  Along the way it’ll give you a brief introduction to each tool, explain what it does, and then give a quick example of how to use it.  (That’s the 5 chapters I wrote)

The remaining 2/3 of the book dedicates a chapter to various open source projects going into a little more detail about them.  There’s a chapter on Papervision 3D, SWX, FUSE/Go, HAXE, AMFPHP, two for Red5 and a couple more.

This was a lot of fun to work on, and my only regret is not getting to know the other authors better.

If you’re looking for a place to buy it, check out Bookpool.   I worked for them for a year and they’re really stellar guys.  They offer good prices, but more importantly;  as long as the book is in stock, they do their damndest to get it on a truck the day you order it. (Of course, you’re at the mercy of the publisher if it’s out of stock)

XML Facade instead of value objects?

I have a project I’m working on where it’d be great if older versions of the software preserved information in the XML file format that it didn’t understand. For example, imagine if Version 1 (V1) of the software had this for a file format:

<data>
<value>1</value>
</data>

Now imagine if V2 of the file added an attribute

<data>
<value type=”number”>1</value>
</data>

It’d be great if you opened that second file with the V1 software and then saved it again, it would preserve the stuff it didn’t understand. Unfortunately that’s not how I usually write my value objects. Usually I do something like:

public class ValueObject{public var value:Number;public static function fromXML( xml:XML ) : ValueObject{var v:ValueObject = new ValueObject();v.value = xml.value;}

public function toXML(  ) : XML{var xml:XML = <data>;xml.value = value;return xml;}}

As you can see, anything in the file that it doesn’t understand is lost. But what if we followed a facade pattern for our data objects and did something more like this:

public class ValueObject{protected var source:XML;

public static function fromXML( xml:XML ) : ValueObject{v.source = xml;}

public function toXML() : XML{return source;}

public function get value() : Number {return source.value;}public function set value(val:Number) : void {source.value = val;}}

They both have the exact same API, but the second one will preserve XML attributes (or even nodes) that it doesn’t understand.

What about AMF based projects, especially when passing rich objects with a Red5 server? I know there’s a pretty seamless mechanism in place if properties aren’t known, but how do you get those unknown properties back to the server?

What other solutions or best-practices do other people follow for solving this issue?

Real time log viewing with flash and red5

Disclaimer: The idea for this isn’t mine. Another guy did a great version of it over at http://www.fudgie.org/ The only improvement mine has is that it’s in flash so it’s web-accessible by multiple people at once. His looks cooler, has more data, and probably performs better.

Here’s a quick little mini-project I banged out last night.
http://www.agileagenda.com/logview/LogViewAs.html
It shows traffic to my websites as balls flying through space. It uses Red5 on the server to watch the log files, and Flash on the client to display and animate that data. It’s watching the websites:

www.agileagenda.com
www.flashyourspace.com
www.marc-hughes.com
www.rogue-development.com

Just open up the flash page, and if nothing is currently happening browse to those sites.

I’ll post server & client side post under an MIT license when I get it to a more polished state.

Red5, 1&1, and epoll

If you’re trying to run red5 on a 1&1 managed server, you have to turn epoll support off because their linux distribution chokes on it. To do that, add this command paramater:

-Djava.nio.channels.spi.SelectorProvider=sun.nio.ch.PollSelectorProvider

The error looks something like this:

Exception in thread “main” java.lang.InternalError: unable to get address of epoll functions, pre-2.6 kernel?
at sun.nio.ch.EPollArrayWrapper

.init(Native Method)
at sun.nio.ch.EPollArrayWrapper.(EPollArrayWrapper.java:227)
at sun.nio.ch.EPollSelectorImpl.( EPollSelectorImpl.java:52)
at sun.nio.ch.EPollSelectorProvider.openSelector(EPollSelectorProvider.java:18)
at java.nio.channels.Selector.open(Selector.java:209)
at org.apache.mina.transport.socket.nio.SocketAcceptor.startupWorker (SocketAcceptor.java:162)
at org.apache.mina.transport.socket.nio.SocketAcceptor.bind(SocketAcceptor.java:141)
at org.apache.mina.common.support.BaseIoAcceptor.bind(BaseIoAcceptor.java:42)
at org.red5.server.net.rtmp.RTMPMinaTransport.start(RTMPMinaTransport.java:218)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java :39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod (AbstractAutowireCapableBeanFactory.java:1240)

My first Red5 experience

I’ve worked with both Chris Allen and John Grden on some projects for my employer. During that time, I can’t count the number of times I heard about Red5, but I never got a chance to try it out.

This past week I caught Chris’ “Building Red5 Applications” session at FlashForward. I finally got up the motivation to download and try it out.

Here’s my experience. It’s my first time playing with Red5 (but I have plenty of java & eclipse experience) so it’s almost guaranteed I’m not doing everything the “right way”. But this way worked for me, maybe it’ll help someone else. If it does help you, please leave a comment. Writing this up takes a while and I’m not going to bother in the future for other things if nobody gets value out of it.


Attempt #1

I wanted to try out the .tar.gz package so I would know how to deal with it on Linux as well as Windows. That way I’d be able to deploy anything I built on my webhost fairly easily.

I unpacked it, ran ant, and let it all build. So far so good.

Then I ran the red5.bat file. Lots of exceptions. Like millions, maybe billions, I lost track. Seems my sample applications weren’t found. I poked around a bit, but no good. Screw this.

Attempt #2
I went for the windows installation package. That unpacked everything and the server ran fine. I could open up a web browser to http://localhost:5080/ and view the demos, admin panel, etc.

Note: The default admin username/password is admin/admin. You can change that in conf/tomcat-users.xml I’d suggest changing it.

Eclipse

So now I want to get it rocking with eclipse. I launch eclipse (I’m lazy and like things easy so I use easy eclipse.)

I select File->Import->Existing project, then pick my Red5 project. Bamn, I got an eclipse project set up.

But there’s compile errors.

Severity and Description Path Resource Location Creation Time Id
Project red5_server is missing required source folder: ‘test’ red5_server Build path 1190574481375 173990
The project cannot be built until build path errors are resolved red5_server Unknown 1190574530687 173992

So I closed the red5 eclipse project, fired up a text editor, and looked in my .classpath file inside the red5 folder. It had the offending entry.

<classpathentry kind=”src” path=”test”/>

Note… I delete this line later on:
<classpathentry kind=”con” path=”org.jayasoft.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/ivy.xml/test,”/>
You might as well do it now since you’re in there.

So I removed it, and repopened eclipse.

A quick Project->Clean and…
3656 Errors

Ok, seems it doesn’t see some libraries. Right click on my project, select properties. Go into “Java Build Path”, select the “Libraries” tab, click the “Add Jars…” button, and add all of the .jar files in the lib directory.

A quick Project->Clean and…
0 Errors

WOOT

Running it from Eclipse

Now I go into src/org/red5/server, find the StandAlone.java, right click it, and select “Run as…”->”Java Application”.

I check my eclipse console panel and get a bunch of lines the last one being:

[INFO] 2007-09-23 15:14:20,875 main:( org.red5.server.Standalone.main ) Startup done in: 5875 ms

Nice.

I point a web browser at: http://localhost:5080/ and see that the red5 server is indeed running. I launch the ball demo and push the connect button. Then I make a new browser window and launch the demo again. When I move the red5 logo in one window, it moves in the other. That means it’s all working.

Eclipse also helpfully added an entry to my run button (the green circle with the play button) in my toolbar so I don’t have to find the StandAlone.java file again.

I want a quick launch button for debugging too, so I kill the server (click the red square on the console panel) and right click the StandAlone.java and select “Debug as java application”. The server starts in debug mode, and eclipse adds it to my debug button on the toolbar. (the green beetle button)

Making something

Now, I want to make something. But first, I want to get rid of the samples. So I kill the server, close the eclipse project, and edit the .classpath file again. I know there’s a way to do this through eclipse, but I find editing the file quicker.

I get rid of these entries:
<classpathentry excluding=”.svn/*” kind=”src” path=”webapps/echo/WEB-INF/src”/>
<classpathentry excluding=”.svn/*” kind=”src” path=”webapps/tutorial/WEB-INF/src”/>
<classpathentry excluding=”.svn/*” kind=”src” path=”webapps/fitcDemo/WEB-INF/src”/>
<classpathentry excluding=”.svn/*” kind=”src” path=”webapps/oflaDemo/WEB-INF/src”/>
<classpathentry excluding=”.svn/*” kind=”src” path=”conf”/>
<classpathentry excluding=”.svn/*” kind=”src” path=”webapps/test/WEB-INF/src”/>
<classpathentry excluding=”.svn/*” kind=”src” path=”webapps/midiDemo/WEB-INF/src”/>
<classpathentry excluding=”.svn/*” kind=”src” path=”webapps/agile/WEB-INF/src”/>

And I add one for my project, I’m going to work on something for AgileAgenda, so I’ll call it agile.

<classpathentry excluding=”.svn/*” kind=”src” path=”webapps/agile/WEB-INF/src”/>

Then I go rename the “echo” example to “agile”, and delete all the other samples (I deleted admin too, not sure if that was a good idea or not)

Open up the project in Eclipse again.

And I don’t see my agile webapp. WTF? Oh yeah… Eclipse is retarded. Right Click->Refresh and it shows up.

I want to rename the Application class in my webapps folder (see the picture).

Luckily, Eclipse rocks Java more than it rocks Flex, so I can just right click, select refactor, and pick move. Then I click “Create Package” enter in com.agileagenda.services and click ok a bunch of times.

I delete the rest of the webapp echo source tree.

A project->Clean and…

I think I broke something. Oh well.

Project->Properties->Builders and remove the invalid entry.

Project->Clean and build successful.

I hit the debug button, and search the console output. No errors reported and:

[INFO] 2007-09-23 15:44:45,375 main:( /agile.invoke0 ) Initializing Spring root WebApplicationContext

So I guess it found my new app. Yay!

Kill the server.

So I go back to my Application class and make a new method.

public function login(username:String, password:String) : Boolean
{
return true;
}

Then I remember that this is Java and not Actionscript so I rewrite it…

public boolean login(String username, String password)
{
return true;
}

I go to my project menu and turn on “Build Automatically” and get…

Severity and Description Path Resource Location Creation Time Id
Unbound classpath container: ‘org.jayasoft.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/ivy.xml/test,’ in project red5_server red5_server Build path 1190576857156 182811

WTF?

Close the project, open my .classpath file, remove the offending line:
<classpathentry kind=”con” path=”org.jayasoft.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/ivy.xml/test,”/>

Open the project, Project->Clean, build success.

I have no idea why that didn’t bite me earlier.

I press the debug button. The red5 server launches.
[INFO] 2007-09-23 15:51:26,062 main:( org.red5.server.Standalone.main ) Startup done in: 4937 ms

Yay.

Writing some actionscript

Now that I have a (dumb) login method, I want to try it out in Flex.

I have a “Sandbox” AIR application set up in Eclipse that I use when I want to quickly play with something. I highly suggest everyone do that. So I open my sandbox, open the MXML and create a quick login form.

<mx:Label x="26" y="43" text="Username:"/>
<mx:TextInput x="101" y="41" id="txtUsername"/>
<mx:TextInput x=”101″ y=”71″ id=”txtPassword” displayAsPassword=”true”/>
<mx:Label x=”26″ y=”73″ text=”Password”/>
<mx:Button x=”196″ y=”101″ label=”Login” click=”onLoginClick()”/>
<mx:Label x=”58″ y=”148″ text=”Label” id=”lblResult” width=”281″/>

And then add in some code (remembering that this is Actionscript!)…

private var netConn:NetConnection;

protected function onLoginClick() : void
{
NetConnection.defaultObjectEncoding = flash.net.ObjectEncoding.AMF0;
SharedObject.defaultObjectEncoding = flash.net.ObjectEncoding.AMF0;

netConn = new NetConnection();
netConn.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus );
netConn.addEventListener( SecurityErrorEvent.SECURITY_ERROR, errorHandler );
netConn.addEventListener( AsyncErrorEvent.ASYNC_ERROR, errorHandler );
netConn.addEventListener( IOErrorEvent.IO_ERROR, errorHandler );

netConn.connect(”rtmp://localhost/agile”);

}

protected function sendLogin() : void
{
var responder:Responder = new Responder( onLoginResult );
netConn.call(”login”,responder,txtUsername.text, txtPassword.text);
}

protected function onLoginResult( result:Boolean ) : void
{
lblResult.text = result ? “Login Success!” : “Login Fail!?!”;
}

protected function onNetStatus(event:NetStatusEvent) : void
{
switch( event.info.code )
{
case “NetConnection.Connect.Success”:
lblResult.text = “Connected, sending login”;
sendLogin();
break;

default:
lblResult.text = “ERROR!! ” + event.toString();
break;
}

}

protected function errorHandler(event:Event) : void
{
lblResult.text = “ERROR! ” + event.toString();
}

I start the server, run my sandbox app, click the login button, and get a connection error. Something went wrong somewhere.

I bet it’s a configuration problem. I open webapps/agile/WEB-INF and notice 3 config files.

in web.xml I make this change:

<context-param>
<param-name>webAppRootKey</param-name>
<param-value>/agile</param-value>
</context-param>

In red5-web.xml I make this change:

<bean id=”web.handler”
class=”com.agileagenda.services.Application
singleton=”true” />

In red5-web.properties, I make this change:

webapp.contextPath=/agile

Kill the server, restart it (debug mode), try my app again. “Login Sucess” YES!

Now I head into the java class and put a breakpoint on the “return true;” line. I hit the button on my AIR app and Eclipse correctly breaks on the line. Yay!

I inspect the username and password parameters, and the values I had filled into the AIR app are present. Yay!

I’m now to the point where I can start actually writing my application.