Posted on by 4 comments

LinkedInGoogle+TwitterFacebook

Interactive applications require low-latency, just like phone calls, in order to make them real-time and natural. While REST drives much of the APIs on the web today, sometimes it just adds too much overhead and therefore introduces latency. In steps WebSockets, a part of the HTML5 standard. WebSockets provide a persistent bi-directional connection between your users and yours services. Now, with Tropo, you may write real-time applications that provide snappy interactions to drive games, interactive billboards and just about any other interactive application that requires a great user experience.

An example of just such an application was one built by Manou Andraos and Melissa Mongiat for the Mutek BlocJam festival in Montreal in June 2010. They projected a musical collaboration interface onto a seven story building in downtown Montreal. Then published a phone number that people on the street could dial with their mobile phones and interact together in a public space to make music in real-time.

This project was built using Adhearsion, a project sponsored by Voxeo Labs, which allows for real-time streaming of user input to an application using Asterisk.

Tropo also allows for real-time streaming of user input from the cloud. While Tropo may do REST just fine, the real power in our platform is Tropo Scripting. By hosting your app on our application servers, you may wire your apps to the web the way you want. So, building on Chris Matthieu’s recent post on using XMPP to speak to the web, and my previous post for using TCP Sockets, we will now walk you through using WebSockets to drive your applications from the Tropo cloud.

We created a prototype that provides an example of how to stream real-time DTMF (those sounds your phone makes when hitting the keys) input from a user to your application over a WebSocket.

In the diagram above you may see that we created a ‘WebSocket Relay’ that takes two inbound WebSocket requests and relays them via a unique session to each other. This allows for applications behind firewalls to establish outbound connections, rather than having to accept inbound requests. For the relay we used EventMachine and the em-websocket gem. And for the Tropo Ruby script we used the web-socket-ruby gem (originally created by Hiroshi Ichikawa) to establish the outbound WebSocket from Tropo to the relay. Here is this scenario in action:

(The source code for the WebSocket Relay, the Tropo Ruby script and the HTML5 web page are available on Github here.)

The Tropo portion of the script that powers this is quite straight forward (full script here):

# Create a connection to the WebSocket server
client = WebSocket.new("ws://sandite.orl.voxeo.net:8082")

loop do
result = ask "Press any digit, or press zero to end the session.", { :choices => "[1 DIGITS]" }
msg = { :type => 'publisher', :id => 'tropo-app1', :data => { :caller_id => '4155551212', :command => result.value } }.to_json
client.send msg
break if result.value == '0' || $currentCall.isActive == false
end

say 'Thank you for playing, goodbye.' if $currentCall.isActive

While the EventMachine WebSocket Relay portion is only 57 lines of code:

class SessionChannels
def initialize
@channels = {}
@mutex = Mutex.new
end

def publish(id, message)
create_channel id if @channels[id].nil?
@channels[id].push message
end

def subscribe(id, socket)
create_channel id if @channels[id].nil?
@channels[id].subscribe { |msg| socket.send msg.to_json }
end

private

def create_channel(id)
@mutex.synchronize { @channels[id] = EM::Channel.new }
end
end

@session_channels = SessionChannels.new

EM::WebSocket.start(APP_CONFIG['websocket']) do |socket|
socket.onopen {
ap "WebSocket connection open"
}

socket.onmessage { |msg|
msg = JSON.parse msg
case msg['type']
when 'subscriber'
@session_channels.subscribe(msg['id'], socket)
when 'publisher'
@session_channels.publish(msg['id'], msg['data'])
end
}

socket.onclose { ap "Connection closed" }
end

Now all that limits you for creating interactive applications is your imagination. If you would like any additional insight or assistance in exploring this approach or others, please do not hesitate to reach out to us on ‘support@tropo.com‘.

Note: Recently a security issue was disocovered in the WebSocket protocol which has caused Firefox to remove WebSockets from their latest beta. While you may still use WebSockets in certain scenarios, the standard now appears to be in flux again. WebSockets will be around, albeit most likely with changes. We will be following this post up with a more detailed overview of how to use XMPP and BOSH from our network, as Tropo natively supports XMPP, to achieve the same real-time capabilities.

4 Responses to “WebSockets and Tropo, Putting the Real-Time in Your Communications”

  1. spearwolf

    hi, is there any reason why you are using a mutex.synchronize around EM::Channel.new ?

    greetz,
    spearwolf

    Reply
  2. Jason Goecke

    Just to ensure the @channels hash would only get written to at one time in case both WebSocket clients connected at the same time. Although, probably would not hurt anything if that scenario did happen and there was not a Mutex.

    Reply
  3. Joe Ellis

    I was just looking through the shared github repository, but I didn’t see the actually HTML page you used for the demo. Was it added to the repository, or am I perhaps looking in the wrong place?

    Reply

Trackbacks/Pingbacks

  1.  Awesome use of Websockets and mobile tech — realtime crowd sourced music composition | markjeee.com

Leave a Reply

  • (will not be published)