Quantcast
Channel: The Michigan Telephone blog » Programming
Viewing all articles
Browse latest Browse all 4

Use Tropo to bring Skype calls into your Asterisk/FreePBX server (with voice or tone activated IVR)

$
0
0

(This was edited on January 6, 2011, to use a fix suggested by Tropo instead of a workaround I had been using.)

If you read my Mini-review of Tropo, you may have thought that I gave up on it in frustration. Well, not quite — there’s enough potential in that platform that I decided to see if I could work around the problems.  So here’s a project I attempted, just to show one of the things that can be done.  This will allow Skype users to call into an IVR, either press or say a number corresponding with a selection, and be transferred to various extensions on your Asterisk/FreePBX system.

To begin with, you’ll need to set up a Tropo account, so go to the Tropo website and click on Account Login at the top of the page. A login window should pop up:

Tropo Account Login window

Click where it says “click here to register” and fill out the registration information, then click Create Account.  Note that “developer” accounts (which is what your account is to begin with) are free.  After you’ve completed registration, you should be taken to a window with a “Create New Application” button:

Tropo Your Applications initial screen

Click that “Create New Application” button, and you will see the New Application screen:

Tropo New Application screen

We’re going to create a Tropo Scripting application, so click on that icon. You’ll be taken back to a “New Applications” screen, but this time with text boxes to enter necessary information:

Tropo New Application screen with text entry boxes

Give your application a name — any name you like is fine — and then click on the “Hosted File” link over the second text box. That will pop up a small box with two additional links:

Tropo Hosted File selection boxSince you’re just starting out, you’ll want to create a new hosted file for this application, so click that link and you’ll be taken to a new screen where you will be asked to enter a new file name and below that, there will be a text box to enter your actual program script (this is a partial screenshot):

Tropo New Mapped File entryThe big thing to keep in mind here is to use an extension that corresponds to the program language — it has to be one of the languages that Tropo supports.  In this case we are using a PHP script, so be sure to give the filename a .php extension (other than that, you can call it whatever you like).  You’ll then want to copy the script into the File Text area.  Here’s a sample script you can use to get started, though obviously you’ll want to change a few things:

<?php

// SSML tags needed for advanced text-to-speech manipulation
$ssml_start = "<?xml version='1.0'?><speak>";
$sayas_end="</say-as>";
$sayas_digits ="<say-as interpret-as='vxml:digits'>";
$ssml_end = "</speak>";

// This line includes a fix suggested by Tropo Support
$SIPheaders = array('x-voxeo-aom' => 'true');

// Do NOT remove the next two lines if you don't want weirdness!
answer();
Say ("Hello");

// If a Skype call create a custom SIP header so we can get the Skype user name
if ($currentCall->network == "SKYPE") {
	if (preg_match('/"([^"]*)"\s*<sip/', $currentCall->getHeader('x-sbc-from'), $matches)) {
		$SIPheaders = array("X-Skype-User" => "$matches[1]", 'x-voxeo-aom' => 'true');
		}
	}

// Maximum # of times caller can attempt to make a selection
$retries = 5;

// Ask caller to make a choice, then see if it matches a valid choice
do {

	$result = ask("Thank you for calling. To speak to Larry, press or say 1. To speak to Moe, press or say 2. To speak to Curly - or - Shemp, press or say 3. Please make your selection now!", array(
		"voice" => "allison",
		"choices" => "[1 DIGITS]",
		"bargein" => "true",
		"attempts" => "$retries",
		"minConfidence" => 0.4,
		"recognizer" => "en-us"
		 )
	);

	if ($result->value == "1")
		{
			say("Connecting you to Larry.");
			$retries = 0;
			transfer('sip:123@yourserver.tld', array(
				'headers' => $SIPheaders,
				)
			);
		 }

	elseif ($result->value == "2")
		{
			say("Connecting you to Moe.");
			$retries = 0;
			transfer('sip:456@yourserver.tld', array(
				'headers' => $SIPheaders,
				)
			);
		}

	elseif ($result->value == "3")
		{
			say("Connecting you to Curly or Shemp.");
			$retries = 0;
			transfer('sip:789@yourserver.tld', array(
				'headers' => $SIPheaders,
				)
			);
		}

	else
	    {
			say("I'm sorry, valid selections are one - two - or three. Please try again.");
			$retries--;
	    }
} while ($retries > 0);
?>

(Copy and paste the above code into a text editor so that you can see all of it, including the lines that get cut off from the display due to length.)

The above code shows three possible selections, although you can have more or fewer (this code limits you to single digit choices, but that’s easily changed). Replace yourserver.tld with the address of your Asterisk server.  Replace the number between sip: and @ with a valid DID that maps to a user extension in one of your inbound routes.  You could also use an extension number there, but then you’d have to create an inbound route with that extension as the DID — remember, if it doesn’t match a DID in an inbound route, Asterisk will drop it like a hot potato! Also, unless your users are named Larry, Moe, and Curly or Shemp, you may want to change that.  I included two names on the last choice to show that punctuation DOES make a difference — after you have this working, try changing the hyphens to commas and note the difference.

Other than those changes, try not to change anything until you have this working.  Some parts of the script have non-obvious reasons for being there, like the Say (“Hello”); statement — go back to my Mini-review of Tropo if you want to know why that is there!

After you have entered and saved your changes, you should be taken back to the New Applications page, but now the text boxes should be filled in with a URL pointing to your script:

Tropo New Application page with URL filled in

Note the five digit number (where 00000 is in the screenshot) – that’s a number unique to your account, and it’s how Tropo keeps your files separate from everyone else’s. If you look further down on this page, you’ll see a section headed Phone Numbers, and one of those will be a Skype Voice number that starts with +99000.  Copy that number down somewhere because you will need it later.  If you’re into INum, there’s also an INum number that can be used as an alternative access method, and you even have the option to get a PSTN number in the U.S.A., or in one of several other countries.  Also note that in the blue bar at the top, there is a link that says “Application Debugger” (you can only see the first part of “Application” in the screenshot).  Click on that if you want to see how your script is running in real-time.

In FreePBX, you’ll need to do three things:

  1. Create inbound routes with DID’s that match the numbers you used between sip: and the @ symbol in your sip destinations, if you didn’t use existing DID numbers.
  2. Create a trunk so that Asterisk won’t think the incoming calls from Tropo are anonymous SIP calls.
  3. Add a bit of custom context to /etc/asterisk/extensions_custom.conf

For the trunk, just create a plain old SIP trunk, in the two “Trunk Name” fields call it “Tropo”, and in the PEER Details just paste in this:

host=66.193.54.6
type=peer
dtmfmode=rfc2833
context=custom-from-tropo
disallow=all
allow=ulaw

That is ALL you need – the only purpose of the trunk is to keep Asterisk from rejecting the calls because they come from an unknown source, and to tell it which context the calls should be routed to.  You don’t need to fill in anything else because you’re not registering with Tropo’s servers and you’re not going to use the trunk for outgoing calls.

And finally, here’s the custom-from-tropo context (mentioned in the trunk settings above) that has to go into /etc/asterisk/extensions_custom.conf:

[custom-from-tropo]
exten => _X!,1,Noop(Incoming Tropo call)
exten => _X!,n,GotoIf($[${LEN(${SIP_HEADER(x-skype-user)})} = 0]?notskype)
exten => _X!,n,Set(CALLERID(name)=${SIP_HEADER(x-skype-user)})
exten => _X!,n,Set(CALLERID(num)=SKYPE)
exten => _X!,n(notskype),Goto(from-trunk,${EXTEN},1)
exten => h,1,Macro(hangupcall,)

The above context looks to see if the call came from Skype, and if so, it reads the custom SIP header that was generated by the PHP script that contains the Skype user name, and puts that in the Caller ID name field, and also puts “Skype” in the Caller ID number field (if you have endpoints that puke on non-numeric data in the Caller ID number field, then you can change that to whatever they will accept).

EDIT (January 7, 2011):  The above section of code formerly also put the call in an “Answer” state as soon as it arrived, which solved a couple of issues — namely, caller doesn’t hear audio while the extension is ringing, and when the caller hangs up, the called phone continues to ring until answered — but I am now using a fix suggested by Tropo support that works better for this purpose (it adds the x-voxeo-aom SIP header, though I have no idea why that works).  Also, I said above that you have to send calls to existing DIDs OR create inbound routes to match on the numbers to which you’re sending the calls.  It occurs to me that by changing “from-trunk” to “from-internal” on the next to last line of the [custom-from-tropo] context, you could send calls directly to any internal destinations, without the need to create any inbound routes — HOWEVER, the drawbacks to that approach are that you’d lose any functionality normally available on the Inbound Routes pages (which may or may not matter to you), and also, there might be some unforeseen security implications that I haven’t considered.

Don’t forget to do an orange bar reload in FreePBX after you’ve made the above additions. Now you’re ready to try a call to that Skype Voice number and see if it works!  Try using both voice and the tone pad in the Skype client to make your selections.

I think that covers everything – I had so many false starts and issues trying to get this working that it’s possible I’ve overlooked something, but I don’t think so.  The above is just to get you started – obviously with some tweaking, you can do much more.  For example, in theory it’s possible to have Tropo directly recognize spoken names, by simply listing them in the “choices” option, for example:
“choices” => “Larry, Moe, Curly, Shemp”,
I figure that limiting recognition to digits makes the recognition more reliable (though I might be wrong about that), and makes the spoken instructions easier (“Please press or say one” is less confusing than “Press one or say Larry”).

I’m wondering now if the techniques in Bill’s Analog remix part 2 article could be combined with a menu similar to the one above, to create an IVR for FreePBX that would accept touch tone or verbal input.  But since I had such a difficult time getting this to work, I’m not quite ready to tackle that yet. ;) (EDIT: But I finally did – see How to create an IVR (answering voice menu) for FreePBX that accepts DTMF (touch tone) OR voice responses).



Viewing all articles
Browse latest Browse all 4

Trending Articles