Archive for June, 2010

Building Tropo apps with PHP and Limonade

Tuesday, June 29th, 2010

This is a guest post from Mark Headd, introducing a PHP library for the Tropo WebAPI.

This post is a continuation of the series on building cloud communication applications with Tropo and the PHP WebAPI Library.

In this post, we’ll be looking at Tropo’s support for multi-channel applications and using the incredibly flexible and powerful Limonade library for PHP (think Sinatra for PHP).

Working with the Session Object

As I explained very briefly in the previous post on this subject, the Tropo WebAPI is an HTTP/JSON API for building multi-channel communication apps.

What this means essentially is that the Tropo platform does all of the hard stuff involved with executing a communication app – DTMF/speech recognition, rendering Text-To-Speech (TTS), maintaining and managing all of the connections to the different communication networks (PSTN, SMS, IM networks, Twitter). You tell Tropo how to govern the interaction between a caller and your application on a specific channel by sending it a set of instructions in JSON format.

In this series of posts, we’re using the PHP WebAPI Library for Tropo to generate the JSON that gets sent to, and consumed by Tropo. But this exchange of JSON isn’t one-way – Tropo also sends JSON packages to your application with important information about (among other things) the network a user selects to interact with your application on and any input they have provided in response to prompts.

At the beginning of a user session (when a user first connects to your application), Tropo will deliver a JSON Session object to your application. This object contains all sorts of useful information that your app can use when rendering out JSON instructions to send back to Tropo. Let’s examine what a real life Session object looks like.

The easiest way to do this is to simply go over to PostBin.org and make a new PostBin. PostBin is a service that lets you see HTTP posts that get sent to the special URL that is generated when you create a new PostBin.

After you have created a new PostBin, log into your Tropo account and create a new WebAPI application. Use the PostBin URL as the URL that powers your new Tropo WebAPI app. After your app is created, you will have a newly provisioned Skype number that you can use to call it.

When you call your application using the Skype number provisioned by Tropo, you won’t hear anything – remember, we haven’t yet generated any JSON to tell the Tropo platform what to say or do when a user connects. After you make your call (it will be over quickly), go back to your PostBin URL (you may need to refresh) and you will see an object in JSON format, like this:

{
  "session": {
    "accountId": "9178", 
    "callId": "33e6f280ec9e740ad57ec3464175e502", 
    "from": {
      "channel": "VOICE", 
      "id": "mheadd", 
      "name": "unknown", 
      "network": "PSTN"
    }, 
    "headers": {
      "CSeq": "2 INVITE", 
      "Call-ID": "0-13c4-4c162a69-77e521a6-72fc-1d004d38", 
      "Contact": "<sip:mheadd@10.90.63.103:5060>", 
      "Content-Length": "249", 
      "Content-Type": "application\/sdp", 
      "From": "<sip:mheadd@10.90.63.103:5060>;tag=0-13c4-4c162a69-77e521a6-5ba", 
      "To": "<sip:9991443038@10.90.61.101:5060>", 
      "Via": "SIP\/2.0\/UDP 67.28.127.103:5060;received=10.90.63.103", 
      "x-sbc-allow": "BYE", 
      "x-sbc-call-id": "MTJjZTIzNzBkMDI1MzJhMmJlNjQ1YWQ0NmNmODZkMmM.", 
      "x-sbc-contact": "<sip:0000123456@192.168.14.61:16000>", 
      "x-sbc-cseq": "1 INVITE", 
      "x-sbc-from": "\"mheadd\"<sip:0000123456@192.168.14.61>;tag=93658f52", 
      "x-sbc-max-forwards": "70", 
      "x-sbc-record-route": "<sip:80.252.85.73:5061;r2=on;lr;ftag=93658f52>", 
      "x-sbc-request-uri": "sip:990009369991443038@67.28.127.103:5060", 
      "x-sbc-to": "<sip:990009369991443038@67.28.127.103:5060>", 
      "x-sbc-user-agent": "sipgw-1.0", 
      "x-sid": "cc6499d5ec479c60633f7ad2b6a4df15", 
      "x-voxeo-sbc": "true", 
      "x-voxeo-sbc-name": "10.90.63.103", 
      "x-voxeo-sbc-session-id": "cc6499d5ec479c60633f7ad2b6a4df15", 
      "x-voxeo-to": "<sip:990009369991443038@67.28.127.103:5060>"
    }, 
    "id": "6e15c4ecadf33b72c9e0ba52f707b18c", 
    "initialText": null, 
    "timestamp": "2010-06-14T13:11:04.977Z", 
    "to": {
      "channel": "VOICE", 
      "id": "9991443038", 
      "name": "unknown", 
      "network": "PSTN"
    }, 
    "userType": "HUMAN"
  }
}

This is the Session object for the call you just made. It’s what is sent to your application (via HTTP POST) each time a new session is started on Tropo. Working with this object using the PHP WebAPI Library is easy. You just create a new instance of the Session object in PHP and you can start accessing the properties of this object:

$session = new Session();
$from_info = $session->getFrom();
echo $from_info['channel'];
// Using the example Session object JSON from above would render VOICE.

Being able to access the channel and network a user is accessing your application from can be useful when you want to tailor prompts or actions to a specific channel – e.g., a phone call vs. an IM session.

Also make note of the initialText property – this will be important when building SMS and IM applications, where a user will begin an interaction with your application by sending information to it. This property will allow you to process the initial input for those channels without having to ask the user for it again (something users generally dislike).

Next, let’s take a look a the Result object that is sent from Tropo to your application when a user provides input in response to a prompt or direction. In order to do this, we need to take a sip of Limonade.

Mmmm… Limonade!

Limonade is a lightweight PHP framework that is very much like the Sinatra framework for Ruby. I won’t go into too much detail on it, as there is ample documentation available on the Limonade site , but here is quick introduction that will let us build enough of a structure to see the Tropo result object.

When you use Limonade, you set up routes for HTTP requests. A route is comprised of an HTTP method, a URL matching pattern and a PHP method. When an HTTP request is made to a URL that matches the pattern, and uses the method specified in the route, the designated PHP function gets invoked. For example:

dispatch_post('/', 'test');
  function test() {
    echo 'This is a test.';
}

The ‘dispatch_post()’ directive specifies that the HTTP method for this route with be POST (which is what is used by Tropo to send JSON to your application). The two parameters to this directive specify the URL pattern to match (in this case, the root directory on the domain were this script is located) and the PHP method to invoke, which is defined below this directive. In a nutshell, whenever an HTTP POST is made to the root domain where this script is located, the text This is a test will be rendered.

Let’s build out a simple shell that we’ll use to construct our Tropo application for the next few posts in this series:

// Include Tropo classes.
require('TropoClasses.php');

// Include Limonade framework (http://www.limonade-php.net/).
require('path/to/limonade/lib/limonade.php');

dispatch_post('/start', 'zip_start');
function zip_start() {
	// Tell the user to enter their zip code.
}

dispatch_post('/end', 'zip_end');
function zip_end() {
	// Do something with the entered zip code.
}

dispatch_post('/error', 'zip_error');
function zip_error() {
	// Tell the user an error has occurred.
}

// Run this sucker!
run();

Our Tropo application will collect a user’s zip code and then look up some information based on the input they provide. As you can see, we’ve included the PHP WebAPI Library and the Limonade Framework. We’ve also set up three Limonade routes start, end and error (all using the HTTP POST method) and stubbed out the PHP function that will render JSON for Tropo to consume.

To get a look at the Tropo Result object, lets add some logic to the zip_start() function:

dispatch_post('/start', 'zip_start');
function zip_start() {

	// Step 1. Create a new instance of the Session object, and get the channel information.
	$session = new Session();
	$from_info = $session->getFrom();
	$network = $from_info['channel'];

       // Step 2. Create a new instance of the Tropo object.
	$tropo = new Tropo();

	// Step 3. Welcome prompt.
	$tropo->say("Welcome to the Tropo PHP zip code example for $network");

	// Step 4. Set up options for zip code input.
	$options = array("attempts" => 3, "bargein" => true, "choices" => "[5 DIGITS]", "name" => "zip", "timeout" => 5);

	// Step 5. Ask the caller for input, pass in options.
	$tropo->ask("Please enter your 5 digit zip code.", $options);

	// Step 6. Tell Tropo what to do when the user has entered input. Enter your PostBin URL in the "next" array element.
	$tropo->on(array("event" => "continue", "next" => "http://www.PostBin.org/xxxxxxx", "say" => "Please hold."));

	// Step 7. Render the JSON for the Tropo WebAPI to consume.
	return $tropo->RenderJson();

}

As you can see, inside this function we create a new instance of the Session object and get the channel the user is accessing our application from. We also create a new instance of the Tropo object (this is what we’ll use to send JSON instructions back to the Tropo platform).

The next several steps are fairly self explanatory, but take special note of Step 6. Here we are telling the Tropo platform that when a ‘continue’ event is raised (when a user finishes entering input) tell them to ‘Please hold’ and then POST the results of their input to a PostBin URL. (Note – replace the value above with the PostBin URL you used at the beginning of this tutorial.)

Working with the Result Object

Save your script and change the URL for your WebAPI application in the Tropo Applications manager to point to it. You can now test your script using the the Skype number for your app as we did before . When you access your script, you’ll get the instructions to enter a zip code, after which Tropo will POST the results to the PostBin URL you inserted into the script in Step 6 above.

Now, when you look at your PostBin URL, you’ll see something like this:

{
  "result": {
    "actions": {
      "attempts": 1, 
      "confidence": 100, 
      "disposition": "SUCCESS", 
      "interpretation": "12345", 
      "name": "zip", 
      "utterance": "1 2 3 4 5", 
      "value": "12345", 
      "xml": "<?xml version=\"1.0\"?>\r\n<result grammar=\"0@9ea5756d.vxmlgrammar\">\r\n    <interpretation grammar=\"0@9ea5756d.vxmlgrammar\" confidence=\"100\">\r\n        \r\n      <input mode=\"dtmf\">dtmf-1 dtmf-2 dtmf-3 dtmf-4 dtmf-5<\/input>\r\n    <\/interpretation>\r\n<\/result>\r\n"
    }, 
    "callId": "6d620e133c2f7f265b4b34f94438fd95", 
    "complete": true, 
    "error": null, 
    "sequence": 1, 
    "sessionDuration": 10, 
    "sessionId": "bc73448b723c8c5dc4498d1a322851ec", 
    "state": "ANSWERED"
  }
}

As you can see, the Result object that gets sent from Tropo to your app has a wealth of information on what the user entered, how it was interpreted by Tropo and even the confidence level of the recognition (if speech recognition is used).

You can access the Result object using the PHP WebAPI Library just like you can the Session object:

$result = new Result();<br />

$zip = $result->getValue();<br />
echo $zip
// Using the example Result object JSON from above would render 12345<br />

You would use the Result object in the zip_end() function we stubbed out above. You use the value of the zip code entered to look up information relevant for that zip code (like a weather forecast) and present it to the caller. In the next post in this series, we’ll complete our simple zip code example by adding a weather forecast lookup and present it to the user. We’ll also tweak our script to optimize it for different channels that a user might employ to access it, to ensure the experience is optimized for phone, IM and SMS.

Stay tuned…

About the author: Mark J. Headd is an experienced voice, mobile and web application developer who has been certified as a VoiceXML Application Developer by the VoiceXML Forum. He currently works as a Senior Application developer for Tele-Works, Inc., which develops IVR solutions and software for local government across the country. This post originally appeared on Mark’s blog.

How the Star Wars hotline was created

Tuesday, June 29th, 2010

In yesterday’s Star Wars hotline post we resurrected the old Empire Strikes Back fan hotline using the recently rediscovered teaser recordings from starwars.com. The post on startwars.com about the old hotline says

This was before the telephone system was completely computerized. Back then, there was a lot of mechanical switching equipment. The first week the system went live, so many people called the number, AT&T couldn’t handle it. They were so overloaded, the system couldn’t even handle generating busy signals to all of the calls. The 800 system for Illinois crashed and shut down for several hours. AT&T insisted that we add additional phone lines.

When we started the company 10 years ago, we started out with a problem statement that we then set out to solve. That problem? “Computer telephony sucks.”

The telephony world has come a long way since the days of the original Empire hotline. Instead of roomfuls of switching equipment, all we needed to build the Empire hotline was 5 lines of PHP code.

<?php
$urls = array('http://www.starwars.com/media/audio/empire1_c3po.mp3', 'http://www.starwars.com/media/audio/empire1_han.mp3', 'http://www.starwars.com/media/audio/empire1_leia.mp3', 'http://www.starwars.com/media/audio/empire1_luke.mp3', 'http://www.starwars.com/media/audio/empire1_vader.mp3');
$key = array_rand($urls,1);
answer();
say($urls[$key] . ' Call back for another message. There are five in all.');
hangup();
?>

The app uses the MP3 recordings stored on starwars.com. If you use an audio URL in your Tropo Say statement, we’ll play it. So the code takes the five urls of the different recordings, selects a random one, then answers the phone and plays the recording. Then it lets you know that you can call back for more messages and hangs up.

That’s a lot simpler than a roomful of switching equipment. And since we work with the carriers, if one of them can’t handle the call volume, we’ll route around them. And you don’t need to add any phone lines. We’ll scale to handle as many calls as you need.

SF Telephony meetup

Monday, June 28th, 2010

SF Telephony Inaugural Meetup - San Francisco Telephony Group (San Francisco, CA) - Meetup.com.jpgCome join Tropo and a bunch of people interested in building telephony apps and products in San Francisco Wednesday night.

Zhao Lu from Orange Labs and creator of OpenVoice has organized the San Francisco Telephony Meetup and the first meetup has a bang-up agenda.

Gabriel Sidhom CTO, Orange Labs – Introduction

Jason Goecke, VP of Innovation at Voxeo Labs, will talk about Tropo & Moho – An open-source cloud communications platform that helps developers to create multi-channel real-time communications apps from the cloud or on your own open-source instance.

Adrian Georgescu, CEO of AG Projects Introduction to SIP2SIP.info - Free SIP accounts for the masses - Self-organizing SIP server infrastructure - Remote provisioning API based on SOAP/XML

Chris Matthieu, the Founder of Teleku.com, will introduce the new cloud communication start-up’s RESTful web service APIs which allow web developers to write sophisticated phone applications using PhoneML, TwiML, or VoiceXML that run on any carrier’s network as well as their own free open-souce telephony stack called Ninja.

Dan Miller (Opus Research, 10min), Opus Research: Intro to Recombinant Communications (RC), what it is and what opportunities it presents to developers, incumbent carriers, wireless enterprise IT/app managers.

James Li/Dominic Lee (Orange Labs) – What else can you do while watching TV

Darren Schreiber (15min): an open-source, distributed cloud platform for putting distributed FreeSWITCH nodes on disparate servers. It’s written in Erlang mostly and utilizes some cool messaging and data storage technologies, including NoSQL.

A handful of Tropo people will be on hand, including me (Adam Kalsey), Jason Goecke, and John Higgins. RSVP on meetup.com and come join us.

June 30, 2010 at 6:30pm
Orange Labs
801 Gateway Blvd Suite 500
South San Francisco

Star Wars Empire Strikes Back hotline on Tropo

Monday, June 28th, 2010

A long time ago (30 years), in a galaxy far away (Illinois)…

Lucasfilm created a telephone hotline where you could call and hear teaser audio from the upcoming Empire Strikes Back film. Telephony apps were harder back then:

This was before the telephone system was completely computerized. Back then, there was a lot of mechanical switching equipment and specific prefixes were limited to specific geographic areas. 521 was in Illinois so we had to set up our phone lines to answer the calls in that state.

Five different actors recorded a short message for fans, and each month fans could call in and hear the new message. The audio was lost until recently, when Lucasfim’s first head of fan relations found an old cassette tape with the recordings on it.

StarWars.com put a copy of the audio files up for download, but since telephony is much easier now, we wrote a few lines of PHP code on Tropo and you can hear the recordings the way they were meant to be heard, over the phone.

Give the hotline a call at (714) 643-2997 (or via SIP at 9991443239@sip.tropo.com or Skype at +99000936 9991443239) and you’ll hear one of the five recordings at random.

Tracking calls with Google Analytics

Monday, June 28th, 2010

If you’re building a web site you’re probably using Google Analytics to track traffic. All the cool kids are. How’d you like to start tracking your Tropo phone calls in Analytics as well?

This tutorial is going to show you how to use Google Analytic’s Mobile Web support to insert call information into your Analytics account.

First download the client libraries for Google Analytics Mobile (use the “server-side snippets” code). At the time of this writing, the download includes libraries for PHP, Perl, JSP and ASPX. There’s a PDF file in the download that tells you how to get your mobile tracking ID. It’s just your Google Analytics account ID, but with the UA- replaced with MO-. If your Analytics ID is UA-123456-1 then your mobile ID will be MO-123456-1.

Normally Google Analytics uses tracking code that uses JavaScript on your page to send some data to Google each time a page is accessed. On mobile web sites and apps, Javascript might not be available, so Google has created a way for you to send the data over to them using code running on your server. The phone doesn’t run client-side JavaScript either, so we’re going to use this same server side method on a Tropo WebAPI application to push call data into Analytics.

Google has designed the the client library to create a unique URL that’s inserted as an image tag on your mobile site. When the image is loaded, the library builds the analytics data and pushes it to Google. Since the phone is an environment that doesn’t support image tags, we’re going to build the URL and then open it with an HTTP client during each call.

This code uses the PHP Google library, Tropo’s Web API, and the Tropo PHP library for the WebAPI.

Most of the things that you’d track in web reports like URLs visited, IP addresses, and user-agent strings don’t exist in a phone call, so to make our reports more useful, we’re going to set some of the headers and environment variables manually. This is something you’ll probably want to tweak to get useful reports. I’m going to set the User-Agent to the caller’s area code and build a unique user ID cookie for tracking repeat calls.

The PHP library has a snippet of code (snippet1.php) that’s supposed to be placed at the top of our PHP file. Place that at the top of your app’s code. Google’s instructions also include a second snippet that’s to be placed at the bottom of the PHP page, but since we’re not using the image tags, you don’t need to do that.

You’ll need to edit the snippet after you add it, since it contains a bug. The PHP and Perl libraries don’t properly set the query string. The ASPX and JSP libraries don’t have this bug. In the PHP snippet you just added, find the lines that say …

if (!empty($path)) {
  $url .= "&utmp=" . urlencode($path);
}

… and change it to read …

if (!empty($path)) {
  if (!empty($query)) {
    $path .= "?$query";
  }
  $url .= "&utmp=" . urlencode($path);
}

Or, instead of manually editing the files, here’s a zip with patches for PHP and Perl.

Now right before the snippet you added, we’ll create a user-agent string with the caller’s area code and a cookie value that matches the format that Google sets when they create a tracking cookie.

$session = new Session();
// Create a User-Agent string for the area code.
$UA = 'Area code '. substr($session->from['id'],1,3);
// Create a user ID cookie based on the callerid
$cookie = "0x" . substr(md5($session->from['id']), 0, 16);

Now right after the snippet from the PHP library, we need to load the tracking URL with PHP. The Mobile Web library snippet includes a function googleAnalyticsGetImageUrl() that builds a portion of the URL but it only returns the filename and query string. To load the URL manually, we need a fully-qualified base URL in the form http://example.com/some/path/ instead. Assuming that you’re putting ga.php in the same directory as your Tropo app, all you need to do is construct a base URL and append the output of googleAnalyticsGetImageUrl() to it.

$protocol = $_SERVER['HTTPS'] == 'on' ? 'https' : 'http';
$port = ($_SERVER["SERVER_PORT"] == "80") ? "" : ":".$_SERVER["SERVER_PORT"];
$path = dirname($_SERVER['REQUEST_URI']);
$path == '/' ? '' : $path;
$url = $protocol .'://'. $_SERVER['HTTP_HOST'] . $port . $path .'/'. googleAnalyticsGetImageUrl();

Now that the URL is built, we need to send a GET request to it. This GET request will set the cookie and the user-agent then load the URL just as if it were an image being called from a web browser. The image itself never gets displayed, but the fact that it gets loaded means the tracking data is sent off to Google’s servers for your Analytics account.

$options = array(
  "http" => array(
      "method" => "GET",
      "user_agent" => $UA,
      "header" => "Accept-Language: " . 
                  $_SERVER["HTTP_ACCEPT_LANGUAGE"] . "\r\n".
                  "Cookie: __utmmobile=" . $cookie . "\r\n"
      )
);
$data = file_get_contents($url, false, stream_context_create($options));

Putting it all together, we have the following code, added to the top of any Tropo PHP web application:

<?php
require_once 'TropoClasses.php';
require_once 'ga.php';
$session = new Session();
// Create a User-Agent string for the area code.
$UA = 'Area code '. substr($session->from['id'],1,3);
// Create a user ID cookie based on the callerid
$cookie = "0x" . substr(md5($session->from['id']), 0, 16);
// Build a tracking URL
$protocol = $_SERVER['HTTPS'] == 'on' ? 'https' : 'http';
$port = ($_SERVER["SERVER_PORT"] == "80") ? "" : (":".$_SERVER["SERVER_PORT"]);
$path = dirname($_SERVER['REQUEST_URI']);
$path == '/' ? '' : $path;
$url = $protocol .'://'. $_SERVER['HTTP_HOST'] . $port . $path .'/'. googleAnalyticsGetImageUrl();
$options = array(
  "http" => array(
      "method" => "GET",
      "user_agent" => $UA,
      "header" => "Accept-Language: " . 
                  $_SERVER["HTTP_ACCEPT_LANGUAGE"] . "\r\n".
                  "Cookie: __utmmobile=" . $cookie . "\r\n"
      )
);
$data = file_get_contents($url, false, stream_context_create($options));
?>

You can even turn it into an include and stick it at the beginning of all your calls.

Once this is added, any calls to your app will be recorded by Google Analytics and will show up in your reports alongside your web traffic.

If you want to track specific data in your application, one technique you could use is to set the query string to include the information you want to appear in Analytics. Just add this code somewhere before you call googleAnalyticsGetImageUrl().

$_SERVER["QUERY_STRING"] = urlencode('Your data here');

Think about what you want to track in your app. Have a menu-driven IVR? Perhaps you can track each step of the menu. Have different phone numbers you’re using for different locations and want to know which one is getting used more often? Shove $session->to['id'] into your query string.

A PHP library for Tropo’s Web API

Friday, June 25th, 2010

This is a guest post from Mark Headd, introducing a PHP library for the Tropo WebAPI.

A few months back, I wrote a series of posts on building NoSQL telephony applications with Tropo and CouchDB. Today I’m going to start a continuation of that series, focusing on how to build cutting edge cloud communications apps with the Tropo WebAPI.

What is the Tropo WebAPI?

The Tropo WebAPI is, in a nutshell, an HTTP/JSON API for building multi-channel communication applications – applications that you interact with via phone, IM, SMS or Twitter. While my earlier series on Tropo focused on building applications in Tropo’s scripting environment (another fine option for developers), this series will focus on building JSON-based applications (generated using PHP) that can be hosted anywhere and executed in the Tropo cloud environment.

The Tropo service is truly multi-channel – using the Tropo WebAPI you can build applications that work on a range of different communication channels, not just phones (although you can build some pretty slamming phone apps as well).

Since I’m a phone app developer at heart, some of the features that Tropo provides for phone applications really get me excited. Tropo supports both DTMF entry and speech recognition. It also has broad multilingual support. In addition, Tropo gives phone application developers the ability to manipulate SIP headers, an important feature in building sophisticated cloud communication apps that I hope to demonstrate down the road a bit.

Getting Started

Head on over to Tropo.com and set up a new account (if you don’t have one already). Take a little time to review the documentation for the Tropo WebAPI. For the example applications in this series of blog posts I’ll be using a PHP class library I developed specifically to interact with the Tropo WebAPI.

The crew behind Tropo have provided a Ruby Gem for interacting with the Tropo WebAPI. However, since I like to do my cloud telephony work with PHP I decided to write my own set of classes for doing this. Whether you’re a Ruby-head or a PHP enthusiast, using one of these tools to generate JSON for consumption by the Tropo WebAPI can make build an application significantly easier, particularly as you get into more sophisticated application development.

You can get my PHP Library, as well as some of the sample apps we’ll be looking at, from GitHub:

$ git clone git@github.com:tropo/tropo-webapi-php.git

Or download a Zip file with the library.

You’ll need to host these classes and the PHP scripts you write with them on a server that can be accessed from the Tropo environment. Any web server that supports PHP will do.

My First Tropo WebAPI Application

Let’s start with the standard Hello World app:

<?php

// Include Tropo classes.
require('path/to/TropoClasses.php');

// Create a new instance of the Tropo object.
$tropo = new Tropo();

// Add a prompt to the object using the Say() method.
$tropo->Say("Hello World!");

// Render the JSON for the Tropo WebAPI to consume.
$tropo->RenderJson();

?>

You can look at the rendered JSON in your browser, and you should see something like this:

{
    "tropo": [
        {
            "say": [
                {
                    "value": "Hello World!"
                }
            ]
        }
    ]
}

Go to the Applications section in your Tropo account and set up a new WebAPI application that points to the location of this script.

When you create your application, Tropo will automatically provision a Skype number, a SIP number and an iNum. You can additionally add a PSTN number in a range of different area codes at no charge.

You may also notice the section below the provisioned phone numbers entitled “Instant Messaging Networks” – this section allows you to set up any number of different IM accounts (and Twitter!) that your application can use. We’ll dive deeper into this in future posts.

For now, we’ll keep it simple and use the auto provisioned Skype number – when you call this number, you will hear it say “Hello World.”

The next post in this series will focus on a more sophisticated application that uses the TropoPHP classes and the utterly awesome Limonade PHP framework.

Stay tuned…

About the author: Mark J. Headd is an experienced voice, mobile and web application developer who has been certified as a VoiceXML Application Developer by the VoiceXML Forum. He currently works as a Senior Application developer for Tele-Works, Inc., which develops IVR solutions and software for local government across the country. This post originally appeared on Mark’s blog.

Building Tropo Apps with PHP and Limonade

Thursday, June 17th, 2010

Mark Headd (@mheadd) over at Vox Populi has been working on a PHP WebAPI library for the Tropo WebAPI that is now complete. Mark has done a great write-up on how to use the new PHP library along with the PHP web framework Limonade.

We love having developers like this in our community and really appreciate the effort in contributing such great software and content. Thanks Mark!

You may read his blogpost here.

Processing recordings with PHP

Thursday, June 10th, 2010

When you tell Tropo to record audio, either through a call recording or by using the record command to record a specific prompt, Tropo then sends that audio to your server. You can give Tropo FTP credentials and we’ll FTP it over to you, or you can give an http URL and we’ll make an POST to that URL containing your file.

When Tropo POSTS an audio file, we submit it as multipart form data, so the same tools you’d use to process a file upload field on a form can be used to save your recording. The form field name Tropo uses for the file is “filename“.

Here’s an example using the Tropo WebAPI, PHP, and the PHP WebAPI library. In this example, I’m building a simple voicemail recorder, asking the caller to leave a message at the beep, and then saving the recorded audio to my server.

I’m also introducing some logging, using the excellent KLogger class to write a log file every time we save a recording.

First, a walkthrough of the important parts of the code, then a link to the full code at the end.

<?php
  $tropo->record(array(
    'say' => 'Leave your message at the beep.',
    'url' => getself() . '?record', // append ?record to the URL
    ));

function getself() {
 $pageURL = 'http';
 $url = ($_SERVER["HTTPS"] == "on") ? 'https' : 'http';
 $url .= "://" . $_SERVER["SERVER_NAME"];
 $url .= ($_SERVER["SERVER_PORT"] != "80") ? ':'. $_SERVER["SERVER_PORT"] : '';
 $url .= $_SERVER["REQUEST_URI"];
 return $url;
}
?>

Create a recording prompt, saying “Leave your message at the beep.” Tropo has a beep parameter that you can use to turn off the beep if you want. It’s on by default, and we want to leave it on here. We also add the URL where we’d like to send the recording using a simple function that gives us the full URL of the current application. Appended to the URL is ?record, a flag we’ll use to see if the request to our app is an incoming call or a call recording being posted.

This PHP code generates the follow JSON that’s sent to Tropo:

{
    "tropo": [
        {
            "record": {
                "say": {
                    "value": "Leave your message at the beep."
                },
                "url": "http://example.com/recordingdemo.php?record"
            }
        }
    ]
}

So now to save the file…

<?php
  $target_path = 'path/to/recording/' . $_FILES['filename']['name'];
  if(move_uploaded_file($_FILES['filename']['tmp_name'], $target_path)) {
    $log->LogInfo("$target_path [{$_FILES['filename']['size']} bytes] was saved");
  } else {
    $log->LogError("$target_path could not be saved.");
  }
?>

In this code, which we only run if the ?record flag is present, we use PHP’s global $_FILES array to fetch the file data out of the multipart form post. We start by setting the path and filename we’d like to use for saving the file (line 2) using the filename that Tropo gives us in $_FILES['filename']['name']. Then in line 3, we move the uploaded file from the temporary location that PHP stores a new upload in to the path we chose. If the file is moved successfully, we write a log entry with the path and file size (line 4). If an error occurred, we note that in the log on line 6.

To get the whole sample code, grab the Tropo WebAPI PHP library from github and look in the Samples directory or just grab the sample off Github directly.

Tropo at Pivotal Labs

Tuesday, June 8th, 2010

Jose De Castro, Chief Architect of Voxeo Labs and the lead on Tropo, gave a talk at Pivotal Labs in April. Pivotal is one of the premier web app development shops and invites people in to talk about interesting web technologies. Attendance to the the talks are open by invitation only, but Pivotal Labs records the talks on video and makes them available to the public.

In his one hour talk, Jose talks about Tropo; how we built an open communications platform including our open source contributions, how we built the Tropo application stack, and how we’re trying to bring innovation to communications.

Improved Text to Speech

Monday, June 7th, 2010

We just released an update that improves the sound of the default text to speech voice; a few developers have been testing out Allison in recent weeks and now we’ve not only released it for everyone, but also made it the default voice.

If you have an app that’s using the default TTS voice, try giving your app a call and give it a listen.