Building a Video Party App with Ruby on Rails

For the recent RoR hackathon that happened down in Mountain View this past weekend, I built a new sample application. I needed to learn Rails really quickly, and I also wanted to see if I could port an old Call Widget API sample application easily into the OpenTok world. To check it out, go here:

http://opentok-videoparty.heroku.com

We got really lucky as I was able to convince someone to build a Ruby Gem for OpenTok. You can find it on GitHub here:

https://github.com/kblake/opentok

I think it’s going to be even better when views, helpers and the like are added to it. The best bit of having the gem now though is there’s no longer a need to figure out how plugins work… which drove me a little batty in the building of this application.

Now, on to the code…

The model is super simple. Here is the code for the migration:

[ror]
class CreateRooms < ActiveRecord::Migration
def self.up
create_table :rooms do |t|
t.string :name
t.string :sessionId
t.boolean :public

t.timestamps
end
end

def self.down
drop_table :rooms
end
end
[/ror]

All that’s really happening is that a Video Party “room” has a session ID associated with it, and on top of that we want to know if the end-user wants the room to be listed in the public directory.

So now we need to build out the rooms_controller.rb file. The code looks like this:

[ror]
class RoomsController < ApplicationController

def index
@rooms = Room.where(:public => true).order("created_at DESC")
@new_room = Room.new
end

def create
config_opentok
session = @opentok.create_session request.remote_addr
params[:room][:sessionId] = session.session_id

@new_room = Room.new(params[:room])

respond_to do |format|
if @new_room.save
format.html { redirect_to("/party/"+@new_room.id.to_s) }
else
format.html { render :controller => ‘rooms’,
:action => "index" }
end
end
end

def party
@room = Room.find(params[:id])

config_opentok

@tok_token = @opentok.generate_token :session_id =>
@room.sessionId
end

private
def config_opentok
if @opentok.nil?
@opentok = OpenTok::OpenTokSDK.new {API_KEY}, {API_SECRET}
end
end
end
[/ror]

One quick note… in the function config_opentok make sure that you set the API_KEY and API_SECRET values to the ones you’ve requested from TokBox.

The function index is the action that our “root” route points to. It simply grabs all of the public rooms, and returns them in order from newest to oldest.

The function create is the action against which the form on the homepage posts. It creates new rooms by first generating a session ID to associate with the room, and then saving the data that the end-user passed in to the database.

The function party is the action against which the individual rooms and shared links work against. The route takes an id, looks up that room and returns the Room object. The Room object then gets passed into the view, and the video chat is built off of the properties on that object.

In terms of OpenTok functionality, which is what this is all about in the end, there’s really nothing beyond what you would find in the Basic Tutorial. I will point out how I did the layout of the videos though. It’s a little bit of CSS, and a little bit of Javascript. The CSS code looks something like this:

[css]
#videobox {
width: 100%;
height: 100%;

max-width: 800px;
max-height: 600px;

margin-right: auto;
margin-left: auto;
}

#videobox object {
float: left;
}
[/css]

I’m really doing two things here. I’m making sure that the videobox expands to the height and width of the elements within it, but only up to 800×600. I’m also making sure that all of the object elements within the videobox float left. To really solve the problem I also need to add a div with a style of clear:both after the widgets.

The Javascript code is a bit more complex, but not too crazy. The Javascript code looks like this:
[javascript]
var videos = 1;
var publisherObj;

var subscriberObj = {};

var MAX_WIDTH_VIDEO = 264;
var MAX_HEIGHT_VIDEO = 198;

var MIN_WIDTH_VIDEO = 200;
var MIN_HEIGHT_VIDEO = 150;

var MAX_WIDTH_BOX = 800;
var MAX_HEIGHT_BOX = 600;

var CURRENT_WIDTH = MAX_WIDTH_VIDEO;
var CURRENT_HEIGHT = MAX_HEIGHT_VIDEO;

function layoutManager() {
var estBoxWidth = MAX_WIDTH_BOX / videos;
var width = Math.min(MAX_WIDTH_VIDEO, Math.max(MIN_WIDTH_VIDEO,
estBoxWidth));
var height = 3*width/4;

publisherObj.height = height;
publisherObj.width = width;

for(var subscriberDiv in subscriberObj) {
subscriberDiv.height = height;
subscriberDiv.width = width;
}

CURRENT_HEIGHT = height;
CURRENT_WIDTH = width;
}
[/javascript]

What’s going on here? There are a few assumptions. The maximum number of videos in a row is three. I’ve set a maximum and minimum size for the publisher and subscriber widgets. When the first row fills up, all of the widgets will be the size of the minimum window and tile three across. I also call this function every time a video is added or removed from the videobox, and it goes through the process of rebalancing the widgets.

The routes.rb file and views are pretty simple, and so just looking at the GitHub repository should be enough to understand what’s going on there. If there are any questions, then please throw them in the comments, and I’ll be sure to help out.

Other than that, you should be all set to go to build your own video party Ruby on Rails application!