I gave a talk about Adhearsion, the Ruby VoIP framework that interfaces with Asterisk, to ScotRUG. You can see the video on Vimeo. The talk wasn’t too well-prepared, in particular I hadn’t tested to see if Asterisk was working properly on my netbook. Of course, it wasn’t, and so I couldn’t do a demo.
The main application I’m building with Adhearsion’s not ready yet, so I decided to build something quickly that I could use to show how Adhearsion works. Hopefully it’ll be a fun little app/toy in its own right, too.
Your 140 Seconds lets you call up a number (0131 512 0050) and post up to 140 seconds of audio to a shared Twitter account @y140s. There’s no users, no identification (other than an area code extracted from the caller ID), just 140 seconds of randomness. It should be fun.
It’s been a good project for me – it’s helped a lot for pinning down what I’ll need for deploying the other project, and it’s always nice to actually finish something.
The source code is on GitHub, with some notes on deployment in
Adhearsion’s a great framework and doesn’t require that much Asterisk configuration. I’m going to go over how y140s is set up here.
I’m using phone numbers supplied by UKDDI. They have options for logging into their SIP server as if you were a remote client, which matches how I’ve used Asterisk/Adhearsion before with SIPGate and Gizmo5. More interestingly, they also have options for sending the calls directly to your SIP server. This keeps the configuration needed down quite a bit. In fact, you should be able to get away with one change to
sip.conf and one new stanza in
exten => 666,1,AGI(agi://127.0.0.1)
exten => 666,n,Hangup
This takes any call to extension 666 and punts it to Adhearsion, then hangs up if Adhearsion happens to return the call control back. (Normally you’ll want to tell Adhearsion to explicitly hang up in your app, since you’ll be handling the whole call flow there.)
You’ll also need to ‘include’ it in the default context – the default file includes the ‘demo’ context, just switch it out there.
On the UKDDI site, you’ll need to set your routing to something like
sip:email@example.com, where the extension used matches whatever you picked in
sip.conf all you need to do is change the default context for incoming calls from ‘default’ to ‘adhearsion’. This is set right at the start of the
[general] stanza. Adhearsion expects to find a block for the context the call is being made in, like this:
If the context doesn’t match anything in
dialplan.rb the call will fail, so it’s really important to get the contexts matching.
On receiving a call, Adhearsion executes the contents of that block. There’s some special methods you get (like
menu) and you can call your own functions too.
menu function is how you do IVR menus – it has an extra over standard Asterisk in that the menus can be interrupted while playing prompts. It uses call-backs defined outside of the main block (
on_retry in this example) or each option can call a block in-line (as seen for
In this example app I’m not using the Rails integration, but it’s as simple as putting a line like this in
config.enable_rails :path => '../webapp', :env => :development
There’s more notes on the GitHub project, including the details of a little bit of hoop-jumping required to get beanstalkd working on Ubuntu 8.04.
If you’ve not used message queuing before, now’s the time to start. By default, adhearsion throws an exception and dies when a caller hangs up on you, so if you’ve not done your background processing before then it’ll never get done. Also, if you think people are impatient waiting on a web page to load while you do processing during the request cycle, imagine how much worse they are waiting on the phone?
If the call goes quiet for too long, they’re likely to assume that it’s failed and hang up – so it’s really vital that you keep it responsive by firing things off for processing elsewhere. Beanstalkd is a really lightweight system, which suits me. In a Rails app I’d just use delayed_job, and I am on my other telephony app, but it’s a bit of a pain to use without Rails.
My mechanism for picking items off the queue is really basic – a cron job calls a rake task once a minute. It’s simple and it works. It doesn’t scale very well, but if I’m seeing more than sixty calls an hour then other parts of the system will probably fall over first.
Overall, I’m quite pleased with this little app. It’s a good example of how things hook together when you’re using adhearsion and it’s been really useful for helping me consider deployment strategies for larger telephony applications. It’s definitely not perfect, so if anyone spots any bugs or has any suggests, please let me know – or even better, fork it on GitHub and send a pull request!