PalavaMachine

WebRTC Signaling powered by Ruby





Ruby User Group Berlin | October 10, 2013

Jan Lelis | Marius Melzer

@happycode | @faraoso

What is WebRTC?


What is palava?


What is Signaling?


What is PalavaMachine?



Upcoming Standard

Internet Engineering Task Force

World Wide Web Consortium

getUserMedia


Signaling

PalavaMachine

PalavaMachine

Signaling server written in Ruby

Talks WebSockets via em-websockets

Allows client to join a room to find other clients

Signaling Protocol

A few defined JSON messages

Client → Server


join_room(room_id, status)

send_to_peer(peer_id, data)

update_status(status)

Server → Client


joined_room(me, peers)

peer_updated_status(peer_id, peer_status)

error(id, message)

shutdown(seconds)

Client → Client

via send_to_peer


offer(sdp)

answer(sdp)

ice_candidate(...)

EventMachine Reactor


  EM.run{
  em_init
  trap(:TERM){ em_sigterm }
  trap(:INT){ em_sigint }

  EM::WebSocket.run(options){ |ws|
    ws.onopen{ |handshake|  ws_open(ws, handshake) }
    ws.onmessage{ |message| ws_message(ws, message) }
    ws.onclose{ |why|       ws_close(ws, why) }
    ws.onerror{ |error|     ws_error(ws, error) }
    EM.error_handler{ |e|   em_error(e) }
  }
}
            

def ws_message(ws, message)
  ws_message_action(ws, ws_message_parse(ws, message))
rescue MessageParsingError, MessageError => e
  send_error(ws, e)
end
            


def ws_message_parse(ws, message)
  connection_id = manager.connections.get_connection_id(ws) or
      raise MessageError.new(ws), 'unknown connection'
  ClientMessage.new(message, connection_id)
end
            


def ws_message_action(ws, message_event)
  manager.debug "#{message_event.connection_id} <#{message_event.name}>"
  manager.public_send(
    message_event.name,
    message_event.connection_id,
    *message_event.arguments
  )
end
            

Redis Store

Redis Store

Stores in which room a connection resides

Stores a connection ids per open socket

Uses asynchronous em-hiredis driver

Join Room Example / Ruby Land


def join_room(connection_id, room_id, status)
  return_error connection_id, 'no room id given' if !room_id
  return_error connection_id, 'room id too long' if room_id.size > 50
  # ...
  info "#{connection_id} joins ##{room_id[0..10]}... #{status}"
  script_join_room(connection_id, room_id, status){ |members|
    # ...
            

def script_join_room(connection_id, room_id, status, &block)
  @redis.eval \
    SCRIPT_JOIN_ROOM,
    4,
    "store:room:members:#{room_id}",
    "store:room:peak_members:#{room_id}",
    "store:connection:joined:#{connection_id}",
    "store:connection:room:#{connection_id}",
    connection_id,
    PAYLOAD_NEW_PEER[connection_id, status],
    Time.now.getutc.to_i,
    room_id,
    &block
end
            

Join Room Example / Lua Land


local members = redis.call('smembers', KEYS[1])
local count = 0
for _, peer_id in pairs(members) do
  redis.call('publish', "ps:connection:" .. peer_id, ARGV[2])
  count = count + 1
end
redis.call('sadd', KEYS[1], ARGV[1])
if count == 0 or tonumber(redis.call('get', KEYS[2])) <= count then
  redis.call('set', KEYS[2], count + 1)
end
redis.call('set', KEYS[3], ARGV[3])
redis.call('set', KEYS[4], ARGV[4])
return members
            

Inter Machine Communication

Inter Machine Communication

Using redis' PubSub feature

Allows for multiple EM socket servers running simultanously

Every socket connection listens on its own redis queue

Redis PubSub


def announce_connection(ws)
  connection_id = @connections.register_connection(ws)
  info "#{connection_id} <open>"

  @subscriber.subscribe "ps:connection:#{connection_id}" do |payload|
    ws.send_text(payload)
  end
end
            

# ...

unless %w[offer answer ice_candidate].include? data['event']
  return_error connection_id, 'event not allowed'
end

@publisher.publish "ps:connection:#{peer_id}",
    (data || {}).merge("sender_id" => connection_id).to_json
          

Undocumented Bonus Feauters

Extendable Plugin Architecture

General Usage Stats

Palava Demo

https://palava.tv

Alternatives

All written in node.js

signalmaster

webrtc.io

together.js hub

peerjs server

Palava as a non-profit organization

Thank you | Find the Code at

github.com/palavatv/palava-machine

One more thing

signaling.io

We are working on a webrtc signaling service. You might want to check it out if you consider using webrtc in a future project.

Thank you | Find the Code at

github.com/palavatv/palava-machine


More palava Information

@palavatv | blog.palava.tv


Signaling Service

http://signaling.io