Posts Tagged ‘adhearsion’

Update to AGItate

Friday, March 11th, 2011

I have released v0.1.3 of AGItate today. In case you have forgotten, AGItate turns Tropo into an Asterisk AGI client for use with the likes of Adhearsion, Asterisk-Java and others.

The following enhancements were made today:

  • AGItate now requires YAML to coincide with upcoming upgrade to JRuby 1.5.6 on Tropo.
  • There is now full support for the STREAM FILE command in Asterisk AGI.
  • 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.

WebSockets and Tropo, Putting the Real-Time in Your Communications

Thursday, December 16th, 2010

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.

Outbound with Tropo AGItate

Thursday, October 14th, 2010

We have shown you Tropo AGItate and how to mix it with Asterisk to add Tropo capabilities. Now, its time to show how to create outbound calls using the Tropo Session API, all using AGItate, Adhearsion and CouchDB.

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!

Asterisk & Tropo and a Single Adhearsion Dialplan

Friday, October 8th, 2010

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:

  • Speech Synthesis/TTS in 7 languages and 2 dialects
  • Speech Recognition/ASR in 7 languages and 2 dialects
  • Transcription of audio messages, like voicemail
  • 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!

Howto Install and Use Tropo AGItate

Wednesday, October 6th, 2010

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:

Tropo talks at Cluecon

Monday, July 5th, 2010

ClueconWe’ll have a group from Tropo at ClueCon August 3-5 in Chicago. Got questions about Moho, Adhearsion, or Tropo? Talk to the people who built them.

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