Our Confabio.com project, web video conferencing, is being developed as we speak. The concept is relatively simple, therefore the technology is as well. This article will explain what we have come up with now. Be aware of geek jargon!
# What problems are we trying to solve?
* We want data from the webcam and microphone.
* We want to stream that to and from the server.
* We want some user join/left logic.
The first problem can at the moment only be solved using Flash. Of course we could build our own plugin but that would be silly, since everyone uses Flash to watch full episodes on YouTube. A future alternative [could be Silverlight](http://www.techcrunch.com/2007/05/01/take-time-to-understand-silverlight-its-important/) (let’s not hope so!). For now we are using Flash. More specifically we are using Macromedia Flex (it was the only trial I could download at the time). Flex is a trick to use cool words like XML, CSS and AS3 in your Flash project.
As far as we know, Flash server-side communication can only be done in three ways: raw GET/POST (no way!), RTMP (secret!) and .NET (yeah right!).
Streaming the video can only be done using that secret RTMP to communicate with an expensive Adobe package. Fortunatly some cool people reverse engineered RTMP and made a [free alternative called Red5](http://osflash.org/red5/). Red5 is written in Java and it does a lot of things when it starts up, very pretty. Unfortunately, Red5 is not the pragmatic solution we were hoping for ([hello world is 5 pages](http://www.joachim-bauch.de/tutorials/red5/HOWTO-NewApplications.txt)). Nevertheless, it works!
The third problem, user join/left logic, could also be solved using Red5. In doing so we would have to hack into those Java apps (or use [Red5 Jruby ducktape](http://flexonrails.net/?p=64)). Also we would have to do database access in Java (And [burn in DAO Factory Hell™](http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html)). No thanks!
For now we are using [RubyOnRails-WebORB](http://www.themidnightcoders.com/weborb/rubyonrails/), an open source plugin to easily make calls from Flash. (get_users, login, register that’s all!).
Naturally we try to use as much Open Source as possible, We like it, we trust it and we’re cheap-ass. Unfortunately, the most important part of this project has to be written using the Adobe trick called Flex. Although they might open source it in the future (whatever that means), it’s still a hassle for now.
Let’s ‘pretty please’ that with a diagram:

# When someone enters a conversation
Confabio is all about starting conversations / entering rooms:
1. Browser gets http://confabio.com/teabreak
2. RubyOnRails prepares variables: server-settings, client IP-address and geo information and passes them as FlashVars in the rendered view.
3. The rendered .SWF file will register or login itself into the ‘teabreak’ room, depending on the stored flash-cookie.
4. .SWF will start polling the server-side RoomService for any new users (every x seconds). (using WebORB)
5. Once a user joins, broadcasting is done to the Red5 server (using RTMP™). Also the other user’s stream will be played.
# The RubyOnRails Part
*1. Browser gets http://confabio.com/teabreak*
RubyOnRails defines these routes (config/routes.rb):
map.room 'weborb/:action', :controller => 'weborb'
map.room ':identifier', :controller => 'home', :action => 'room'
*2. RubyOnRails prepares variables: server-settings, client IP-address and geo information and passes them as FlashVars in the rendered view.*
In this home_controller there’s an action called ‘room’ that makes sure that we have the proper FlashVars for Flash:
@flash_vars = params
@flash_vars[:debug] = true unless RAILS_ENV == "production"
domain = request.env['SERVER_NAME']
@flash_vars[:root_url] = 'http://'+domain+':4000/'
@flash_vars[:rtmp_url] = "rtmp://"+domain+"/messageRecorder"
@flash_vars[:remote_ip] = request.remote_ip
...
# convert hash to Flash stuff
@flash_vars = @flash_vars.collect{ |key,value| key.to_s+"="+value.to_s }
@flash_vars = @flash_vars.join('&')
In it’s view (app/views/home/room.rhtml) there’s the usual Flash Object HTML:
allowScriptAccess="sameDomain"
type="application/x-shockwave-flash"
flashVars="<%= @flash_vars %>”
# The Flex Flash Part
Luckily, we figured out how to code without IDE, we can use a single script and it will give us the build_at timestamp:
cat compile_die_zooi.sh
export PATH=$PATH:"/Applications/Adobe Flex Builder 2/Flex SDK 2/bin"
cat confabio.mxml | sed 's/CONFABIO_BUILT_AT/'`date +%H%M`'/' > confabio_built_at.mxml
mxmlc -services /Users/dodo/checkouts/confabio/config/WEB-INF/flex/services-config.xml ¥
-compiler.context-root http://confabio.com:4000/swf/ confabio_built_at.mxml
echo "w000t"
mv confabio_built_at.swf ../../public/swf/confabio.swf
Also, I recommend NOT using trace(); There’s just too much hassle to get the debug message on your screen (without IDE and also with IDE it’s slow as hell). Instead write your own puts(); routine.
Debugging .swf in our project looks like this:

*3. The rendered .SWF file will register or login itself into the ‘teabreak’ room, depending on the stored flash-cookie.*
/* initiate room and eventlisteners */
room = new Room(identifier);
room.addEventListener(Room.USER_JOINED, on_user_joined);
room.addEventListener(Room.USER_LEFT, on_user_left);
room.addEventListener(Room.SELF_REGISTERED, on_self_registered);
room.addEventListener(Room.SELF_REGISTER_FAILURE, on_self_register_failure);
/* register/login ourselves to the room */
if(session.data.user_id) {
room.login(session.data.user_id);
puts("login as "+session.data.user_id+" in room "+room.identifier);
} else {
puts("registering to room "+room.identifier);
room.register();
}
*4. SWF will start polling the server-side RoomService for any new users (every x seconds). (using WebORB)*
Inside the onzin/Room.as constructor:
room_service = new RemoteObject();
room_service.destination = "RoomService";
room_service.register.addEventListener("result", on_register);
room_service.get_users.addEventListener("result", on_get_users);
This will initialize the communication with the RubyOnRails service RoomService.rb. room_service.users results in a on_get_users callback.
*5. Once a user joins, broadcasting is done to the Red5 server (using RTMP™). Also the other user’s stream will be played.*
broadcaster = new Broadcaster(Application.application.parameters.rtmp_url, room.identifier+room.user_id, local_player.camera);
broadcaster.connect();
broadcaster.net_connection.addEventListener(NetStatusEvent.NET_STATUS, on_broadcast_net_event);
remote_player = new RemotePlayer(you, broadcaster.rtmp_url, room.identifier+event.user_id)
remote_player.connect();
remote_player.net_connection.addEventListener(NetStatusEvent.NET_STATUS, on_play_net_event);
# The Red5 Part
We don’t know what it’s doing, but it works for now. We should get an alternative for this. Some dude named [Yannick wrote an RTMP implementation for Ruby](http://osflash.org/rtmp_os?s=rtmp+ruby#yannick_s_ruby_build). Basically it’s a zipfile with a lot of Ruby files. Undocumented of course, kind of like [the black monolith from 2001 A Space Odyssey](http://img.photobucket.com/albums/v226/JeffWells/subalbum1/monolith-sized.jpg). Still I think this thing might be our RTMP salvation.
# Source Code, We want More
Pop us an email.