The SAY DIGITS AGI command speaks the digits properly again.
If you are pulling directly from Github then you already have the update, if not go ahead and follow the instructions here to get the AGItate update up and running.
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.
For this example we will show an Italian catering company calling out to their appointments to ask them which shape of pasta they would like to have at their party. I have written an Adhearsion component that selects customers to call from the database. The component then launches an outbound request to Tropo, which in turn is handled by the Adhearsion dialplan via Tropo AGItate. Watch it in action:
The code for the component may be found on Github as couchdb-dialer. Enjoy!
A key goal of Tropo AGItate is to allow you to use Tropo seamlessly with an existing Asterisk server. With AGItate you may add any Tropo feature to your existing Asterisk server without installing additional Asterisk modules and using the AGI protocol you already know. These features include:
Multi-channel support for SMS, Instant Messaging and Twitter
Conferencing
and more
The ease of interoperability between Asterisk and the Tropo cloud highlights exactly why we run and make available an open SIP network. Every application created gets a SIP address automatically:
To show this in action I have chosen Adhearsion as the framework to serve diaplans for both Asterisk and Tropo to process a single caller on an Asterisk server. Here is a quick overview of how it works:
Through the use of SIP, SIP headers and call tagging in Adhearsion, you may write a single dialplan that handles the call and interaction between the Asterisk and Tropo cloud seamlessly. Here is a quick walkthrough of the dialplan itself and the dialplan taking calls in action:
The entire dialplan may be seen here:
# Serves up FastAGI to your Asterisk server
asterisk_agi {
# Add a custom SIP Header to the session so that when we send to
# Tropo we may know which Asterisk call the Tropo call is
# servicing
execute 'SIPAddHeader', "x-ahn-id: #{channel}"
# Send the call to your Tropo AGItate app on Tropo
# option 'g' is required in order for the call to come back
# to the dialplan
dial 'SIP/9991479110@sip.tropo.com', { :options => 'g' }
# After the call comes back find this call and then
# grab the tag of the result we are looking for
this_call = Adhearsion.active_calls.find(channel)
favorite_muppet = ''
this_call.tags.each do |tag|
hash = JSON.parse tag
favorite_muppet = hash['favorite_muppet'] if hash['favorite_muppet']
end
# Play back the appropriate audio file based on the user's input by passing the appropriate value
# in a custom SIP header
case favorite_muppet
when 'kermit'
# Tropo supports wav/mp3 playback, so pass it a link
execute 'SIPAddHeader', "x-ahn-mp3file: http://downloads.members.tripod.com/Tiny_Dancer/beingreen.mp3"
when 'swedish chef'
execute 'SIPAddHeader', "x-ahn-mp3file: http://dl.dropbox.com/u/25511/Voxeo/TTS-Example/SwedishChef.mp3"
else
execute 'SIPAddHeader', "x-ahn-choice: bad"
end
dial 'SIP/9991479110@sip.tropo.com', { :options => 'm(silence)' }
}
# Serves up FastAGI to your Tropo AGItate application
tropo_agi {
# Grab the SIP headers from the Tropo cloud delivered in the first message over AGI and made
# available in Adhearsion as 'tropo_headers'
headers = JSON.parse tropo_headers
if headers['x-ahn-mp3file']
# If we have the mp3file header, then lets play the fileback, otherwise ask for the input
play headers['x-ahn-mp3file']
elsif headers['x-ahn-choice']
# If the bad choice header is here, we know they did not choose a Muppet they should have
play 'You silly muppet fan, the best muppets are kermit or the swedish chef. Try again another time. Goodbye.'
else
# Invoke the Tropo Speech Synthesis/TTS to speak to the caller
# https://www.tropo.com/docs/scripting/say.htm
play 'Welcome to the Muppetorium.'
# Invoke the Tropo Speech Recognition/ASR to ask the caller for input
# https://www.tropo.com/docs/scripting/ask.htm
result = execute 'ask', { :prompt => 'Which is your favorite muppets character?',
:choices => 'kermit, fozzie, statler, waldorf, oscar, bert, ernie, swedish chef',
:attempts => 3,
:timeout => 10 }.to_json
# Parse the result from Tropo into a Ruby hash
result = JSON.parse result.split('200 result=')[1]
# Find the active Adhearsion call object based on the SIP header passed into Tropo
call = Adhearsion.active_calls.find headers['x-ahn-id']
# Tag that call object with the value of the speech recognition, hangup the call between Asterisk and Tropo
# so that Asterisk may continue handling it on its own
call.tag({ :favorite_muppet => result['interpretation'] }.to_json)
end
}
Or downloaded here. Thats it! You now have a fully featured Asterisk instance leveraging the best of what the cloud has to offer without adding or purchasing any additional software for your Asterisk box.
To get started with AGItate we created a howto walkthrough that you may see here. Tropo is free for development use, so there is no reason not to give it a try. Enjoy!
Last Friday we announced Tropo AGItate on the Voipusers Conference. As you may recall, AGItate is a Tropo script that turns Tropo into an Asterisk platform in the cloud. This script allows you to run any FastAGI framework controlling Tropo as if it were an Asterisk server.
We have put together a short screencast that walks you through the simple installation of the script. And then show you the script in action with Adhearsion. Have a watch:
In addition, Jason Goecke will be giving a talk describing Moho, our open source telephony framework, how it works, and how we use it to build Tropo. And Adam Kalsey will be presenting on the basics of creating usable voice user interfaces.
Cluecon’s discounted hotel rate expires next week and conference pass prices go up at the same time, so get your tickets now.
ClueCon Telephony Developers Conference
August 3-5, 2010
Trump International Hotel & Tower, Chicago