Tag Archives: asterisk

Some recent projects for fun and work

I’ve had fun with a few personal and work-related VoIP projects lately. I’ll summarize them here, and if there’s any interest I’ll expand one or more of them into full how-to articles. 

speak2tweet
You may have heard about the Google/Twitter project called speak2tweet that was created over a weekend during the Egyptian protests, with the goal of allowing protesters whose Internet connectivity was cut to get their voices on to the web. Some folks on the PBX-in-a-Flash forum were talking about it and we realized it would not be hard to build, especially with the Tropo transcription service available to us.
Check out the first page of that thread for the dial-in numbers, and then try it out yourself. The code is posted on the forum for the first hack at it, which only does transcription. The current version includes links to the recordings, too, just like the original speak2tweet. I need to clean it up and post it. See and hear your spoken tweets at twitter.com/piafspeaktweet.
Fax
I have largely ignored fax over VoIP for a long time, because it’s not something I do. At PSU, we attach fax machines to analog lines; done. But recently, I was asked to assist with a quick-turnaround fax project: send a fax to 4,059 analog lines on campus, calls spaced one minute apart, and record the results, so that we can see how many fax machines are hooked up out there. Interesting. I tried Digium’s Free Fax for Asterisk module, but couldn’t get it to communicate. Next I built the soft-switch.org spandsp module, and told Asterisk to use it, and it worked right away. A Perl script using the excellent Asterisk::AMI module (referenced previously on this blog) drove the dialer, and standard Asterisk CDR with a few extra fields recorded the fax results. By the way, the faxes were sent in audio mode (not T.38) using SIP and G.711u over the Internet, and only 3 out of 4,059 calls failed.
FreeSWITCH revisited
Back when I wrote about using FreeSWITCH alongside Asterisk as a gateway to Google Voice, I determined that at some point I’d come back and dig into FreeSWITCH a little more just to understand it. I updated that article with a slightly better config, including lines that turn on comfort noise, which helps the FreeSWITCH-Asterisk bridge maintain synchronization on RTP. (See the FreeSWITCH wiki for more information on that.)

ssmtp to handle your PBX’s e-mail

Here’s a simple how-to for processing the mail your Asterisk server generates, without running a full mail-transfer agent (MTA) like sendmail or postfix.

First, two assertions:

  • You need to deal with mail, even if you aren’t using Asterisk’s voicemail-attached-to-e-mail feature, because your system daemons like cron are generating mail that you may want to read.
  • Running a mail daemon of any kind is a waste of resources when all you really want to do is get the mail off your Asterisk server to some other server for processing.

In the past, a Linux admin would enable sendmail, set the domain name and basically be done. Mail would work on port 25, everyone would accept everyone else’s mail, and life was good. Then spammers ruined our lives and we have to use strange ports, domain validation and a bunch of other things to make ourselves an official mail server. That’s too much work, especially for a box that’s supposed to be a PBX, not a mail system. And if you’re on a residential Internet connection, forget it–you’re probably in every blacklist.

Enter ssmtp, the simple SMTP sender. We’ll use it to send both Internet e-mail, such as might be produced by Asterisk’s voicemail system, and local root-type mail (e.g. cron alerts) through a legitimate SMTP server. It does not run as a system daemon, only on-demand when something on the server generates e-mail. And it’s simple to set up.

Setup

  • Get the source: http://packages.debian.org/source/sid/ssmtp . The file you want is the orig.tar.bz2 file.
  • tar jxvf ssmtp_(version).orig.tar.bz2 to expand it.
  • ./configure --enable-ssl (if the build fails later, yum install openssl-devel [CentOS/RedHat] to get the necessary SSL libraries)
  • make then make install, as root. On a fresh install, sample configurations are installed in /usr/local/etc/ssmtp/. The program is in /usr/local/sbin/.
  • Edit /usr/local/etc/ssmtp/ssmtp.conf. For a basic configuration that will send all locally-addressed mail to a single address, and Internet-addressed mail to the appropriate address, this is all you need:
    # The person who gets all mail for userids < 1000 root=mailbox@example.com # The place where the mail goes. The actual machine name is required # no MX records are consulted. Commonly mailhosts are named mail.domain.com mailhub=smtp.gmail.com:587 # The full hostname hostname=asteriskbox.example.com fromlineoverride=yes authuser=USERNAME authpass=PASSWORD useTLS=yes useSTARTTLS=yes authmethod=LOGIN 

    This example configuration, as you can guess, is for a Gmail account, and will also work with a Google Apps account. Since so many folks use Gmail, you could just cut and paste this, replacing the hostname and credentials with your own. If you are using a different SMTP server, adjust as necessary. With Gmail, the fromlineoverride won’t work–Gmail uses your Gmail address as the From. But it may work on other servers, especially if you are running your own mail server on a different box and send your mail to that.

  • Finally, get rid of sendmail and link to ssmtp in its place. yum erase sendmail will get rid of it from CentOS. Then ln -s /usr/local/sbin/ssmtp /usr/sbin/sendmail to trick your programs into believing sendmail is there, while ssmtp runs instead.

Test it out

You can install mailx with yum install mailx, then try both local mail and Internet mail:

mail root
mail youraddress@example.com

With mail, end your message by pressing Control-D.

Or you can use ssmtp directly: ssmtp root or sendmail root

Try sendmail -t and then fill out the header by typing to: address and so on.

Once you see that mail is moving, you’re done. If you encounter a problem, check /var/log/maillog.

More advanced

If you want to control where mail goes for individual local accounts, check out the revaliases file in /usr/local/etc/ssmtp/. Otherwise, all mail destined to local accounts with UID < 1000 will go to the mailbox specified in the root= line in the config.

Note

If you are using authenticated SMTP (as in the example config above), your ssmtp.conf file contains your SMTP password in plain text. If your box is secure and you are the only user of it, this may not matter. If other users are logging in to the box, and you don’t want them to be able to see the config, you can chmod 600 ssmtp.conf to make it readable only by root, then setuid root the ssmtp binary with chmod +s /usr/local/sbin/ssmtp .

References

Debian wiki on sSMTP

Asterisk hack: make your Google Talk client invisible

It’s been a too-busy-to-write week, but I found some time the last few evenings to brush up my C coding (only hacking at this point, really) to make Asterisk 1.8 do something I’ve wanted from the beginning: Google Talk’s invisible mode for the Google Voice integration.

Quick background: Google wrote a variety of XMPP extensions to make Google Talk do voice and a bunch of other non-standard XMPP things. One of those things is what Google calls “shared statuses,” which also includes invisible mode–the ability to be online but set your client as invisible so that others can’t see you, but could chat with you.

You might want to use this feature if, like me, your Google Voice number is attached to your main GMail account. I don’t use the chat features but I appear online to anyone who has me in their contact list, as long as Asterisk is logged in, and that has the potential to draw unwanted instant messages (that will never get answered).

Note: I want to reinforce that this is a hack. The code is clean enough, but this is only useful for Google Talk and is only implemented as a set of Asterisk CLI commands. Furthermore, this functionality would probably never be implemented in Asterisk’s res_jabber because it’s Google-proprietary. On the other hand, if any Asterisk developers want to run with this, go for it! I don’t guarantee that this code will work for you and if your Asterisk process segfaults, stop using it.

Setup

Apply this patch against Asterisk 1.8.2.2’s (or trunk, currently) res/res_jabber.c by downloading the patch to your Asterisk source directory and running patch < res_jabber.patch . You may have to tell it to apply the patch to res/res_jabber.c.

Rebuild (or build) Asterisk. If you are rebuilding, just run make after applying the patch. You should see make build the res_jabber module. Then make install and restart Asterisk.

Usage

At the CLI, you can issue jabber set invisible on asterisk to turn on invisibility for the Jabber connection named “asterisk.” If you don’t know what your Google Talk XMPP connection is called, just issue jabber show connections and find out. You can set your connection visible again with jabber set invisible off asterisk.

Now, here’s another thing that is really hacky: Google Talk only seems to apply the visibility/invisibility change if you are toggling. Here’s what I mean: if you were invisible, and logged out, then logged back in, Google still thinks you are invisible–but you’re not! So in that case, if you jabber set invisible on ..., it doesn’t do anything, until you first set it off and then back on again. I think I know why this is happening and it has to do with res_jabber sending standard <presence> information at login rather than Google’s special shared-status presence scheme. If you want to be sure you are invisible, just start off by setting invisible off and then set it on. For me, that works every time. (I’d be grateful for someone who really knows all about this to fix it up and make it work right, the first time.)

References

I got the idea from this year-old blog posting about enabling Google Talk invisibility in Pidgin, which refers to the official documents published by Google on how it works.

Analog remix part 3: some Perl CGI to route the call

Part 3 of the analog remix ties it all together. We need a way for Tropo to tell Asterisk to transfer the call, since we’re not going to use SIP REFER. A simple Perl CGI that connects to Asterisk Manager Interface (AMI) will do the trick.

I’m sticking with old-school Perl for this one because I really like Ryan Bullock’s Asterisk::AMI modules. His code is easy to use and he keeps it up to date.

Referring back to part 2, you can see where the curl function calls tropo.cgi (the Perl script below) with parameters f=xfer (the only function for now), callid=the SIP Call-ID, and dest=the number the caller requested. The Perl script finds the Call-ID by iterating through the channel list, finding one that’s connected to Tropo, and then checking the Call-ID to make sure it’s the exact one. (You could have more than one channel open to Tropo.) Once it finds that, it transfers the second leg of that call, which is the caller. Output is to STDERR so that I can review the transaction in the Apache error log.

Updated 12/19/2010: This line

my $link = $currchan->{'Link'} || $currchan->{'BridgedChannel'};

is updated to use either the key returned by Asterisk 1.4 (“Link”) or by later versions (“BridgedChannel”) in the channel listing.

The code:

#!/usr/bin/perl

use strict;
use Asterisk::AMI::Common;
use CGI;
use URI::Escape;

select(STDERR);
local $| = 1;
select(STDOUT);
local $| = 1;

my $cgi = CGI->new;
my $func = $cgi->param('f');
my $callid = uri_unescape($cgi->param('callid'));
my $dest = $cgi->param('dest');

print $cgi->header("text/plain");

if(defined $func) {
  if($func eq "xfer") {
    if(defined $dest && $dest ne "") {
      my $ami = Asterisk::AMI::Common->new (PeerAddr => 'localhost',
                                    PeerPort => '5038',
                                    Username => 'USERNAME',
                                    Secret => 'PASSWORD',
                                    Events => 'off',
                                    on_error => &errorHandler
                                   )
      or die "Unable to connect to Asterisk Manager.n";

      my $channels = $ami->channels;
      if (defined($channels)) {
        foreach my $channel (keys %{$channels}) {
          my $currchan = %{$channels}->{"$channel"};
          if ($channel =~ m/tropo.com/) { # find channels connected to Tropo
            my $currchan_callid = $ami->get_var($channel, "SIPCALLID");
            if ($currchan_callid == $callid) { # make sure it's the right call,
              print STDERR "Channel $channel"; # identified by Call-ID
              print STDERR "Callid $callid";

              my $link = $currchan->{'Link'} || $currchan->{'BridgedChannel'};
              if (defined($link)) { # this is the initiating leg of the call
                my $transfer = $ami->transfer($link, $dest, "from-internal");
                if (defined($transfer)) {
                  if ($transfer == 1) {
                    print STDERR "Tropo successfully transferred $link to $dest.";
                  } else {
                    print STDERR "Tropo FAILED to transfer $link to $dest.";
                  }
                } else {
                  print STDERR "System error performing transfer.";
                }
              } else {
                print STDERR "Local channel leg not found.";
              }
            }
          }
        }
      } else {
        print STDERR "Could not get channel list from Asterisk manager.";
      }
      $ami->disconnect; # close Manager connection
    } else {
      print STDERR "xfer requested but no dest specified.";
    }
  } else {
    print STDERR "Invalid function sent in CGI.";
  }
} else {
  print STDERR "No function sent in CGI.";
}

print "Done.n";
exit;

#### Functions ####

sub errorHandler {  # A fatal error occurred
  my ($amiobj, $errmsg) = @_;
  print STDERR "AMI Fatal error: $errmsgn";
  exit 1;
}

Summary

Starting with part 1, configure a hot line or warm line for your old analog device to automatically ring an extension on your system. You’ll define that extension as the SIP URI to the Tropo application you made in part 2. The Tropo application, in turn, will connect back to your Asterisk server running web services (Apache) with a CGI that can take the input and connect to the Asterisk Manager Interface and transfer your call. Simple! 🙂

Asterisk 1.8+Google Voice fixed

The Asterisk team released a small patch that fixes the protocol issue that was keeping Asterisk 1.8 users from dialing out through Google Voice.

You can apply the patch against version 1.8.0 or 1.8.1. And if you’ve never used the patch command before, it’s easy:
  • Go to the Asterisk bug tracker and get the attached file named fix

  • Put it in your Asterisk source directory (the root, where the configure script, Makefile, and other such files exist). Call it gtalkfix.patch, to be a little less ambiguous.
  • From that same directory, run the command patch < gtalkfix.patch . If it says it can’t find the file to patch, specify channels/chan_gtalk.c. Oh, and if you don’t have the patch command, just yum install patch first.
  • You should see something like this:
    patching file channels/chan_gtalk.c
    Hunk #1 succeeded at 193 with fuzz 2 (offset -3 lines).
    Hunk #2 succeeded at 463 (offset -5 lines).
    Hunk #3 succeeded at 1006 (offset -3 lines).
    Hunk #4 succeeded at 1814 (offset -5 lines).
  • Now run make and you will see it compile chan_gtalk again. Of course, if you are applying it against the raw distribution, you’ll go through the entire build process.
  • make install and start Asterisk and you’ll be able to call through Google Voice again.

Asterisk 1.8+Google Voice broken; FreeSWITCH still works

As some folks commented, Google Voice seems to have stopped accepting outbound calls from Asterisk 1.8. There’s a bug report open with Asterisk on this issue, and several discussions in user forums.

I fired up FreeSWITCH again, without updating any code (still the source from mid-October, 1.0.head (git-dc40a77 2010-10-17 16-19-38 -0400)), and it works perfectly. Apparently, the FreeSWITCH guys are using a different method to make the Google Voice connection, or the Google folks are specifically filtering Asterisk or have made a change that affects Asterisk and to which FreeSWITCH is immune.

Adding Google Voice to FreePBX

If you’ve moved ahead to Asterisk 1.8 in production or are testing it out, use FreePBX as your configuration GUI, and want to add Google Voice such that inbound and outbound routing can easily be configured from FreePBX, here’s a small how-to. Unless and until a GTalk FreePBX module comes along, there’s some command-line work to do, but only for initial configuration.

References:

How To Add Google Voice To FreePBX

Part 1: In the shell

  1. Refer to the Asterisk Wiki: Calling Using Google. We’ll be following that as our guide.
  2. From the command line, as user root or asterisk, verify that the res_jabber and chan_gtalk modules are loaded.
    • [root@asterisk18 ~]# asterisk -rx "module show" | grep res_jabber
      res_jabber.so                  AJI - Asterisk Jabber Interface          0
      [root@asterisk18 ~]# asterisk -rx "module show" | grep chan_gtalk
      chan_gtalk.so                  Gtalk Channel Driver                     0
    • If one or both of those grep commands returns nothing, you need to build the modules (don’t forget to have OpenSSL development libraries installed) and make sure they are loading at Asterisk startup (autoload=yes OR load => res_jabber.so and load=> chan_gtalk.so in /etc/asterisk/modules.conf).
  3. There are three config files in /etc/asterisk to edit by hand (use vi, nano, emacs or whatever you like): jabber.conf, gtalk.conf, and extensions_custom.conf.
    • jabber.conf

      Edit or replace jabber.conf to follow what is listed in Calling Using Google, and which I am pasting almost verbatim here. (I removed debug=yes.) This establishes the XMPP connection.

      [general]
      autoprune=no
      autoregister=yes

      [asterisk]
      type=client
      serverhost=talk.google.com
      username=your_google_username@gmail.com/asterisk
      secret=your_google_password
      port=5222
      priority=1
      usetls=yes
      usesasl=yes
      statusmessage="I am an Asterisk Server"
      timeout=100

    • gtalk.conf

      Again referring to the Asterisk wiki, edit gtalk.conf thus:

      [general]
      context=from-google
      allowguest=yes
      bindaddr=0.0.0.0
      ;externip=1.2.3.4 ; if you know your external ip addr
      stunaddr=stun01.sipphone.com ; use STUN if you're on dynamic IP and NAT

      [guest]
      disallow=all
      allow=ulaw
      context=from-google
      connection=asterisk

      Some notes about gtalk.conf:

      • Use context from-google, which we will set up in the extensions_custom.conf.
      • connection=asterisk must match the connection definition (in square brackets) in jabber.conf.
      • Use externip or stunaddr to get your external IP address if you’re behind a NAT.
    • extensions_custom.conf

      Make a section like this:

      [from-google]
      exten => s,1,Answer()
      exten => s,n,Wait(2)
      exten => s,n,SendDTMF(1)
      exten => s,n,Set(CALLERID(num)=${CUT(CALLERID(name),@,1)})
      exten => s,n,Set(CALLERID(name)=${CUT(CALLERID(name),/,1)})
      exten => s,n,Goto(from-trunk,YOUR-GV-NUMBER,1)
      exten => s,h,Hangup

      • Replace YOUR-GV-NUMBER with your Google Voice DID.
      • The Set commands fix up the caller ID to get rid of the long XMPP ID that is passed on an inbound call.
  4. Once these files are in place, restart Asterisk (amportal restart).
  5. Issue the following command to see that the XMPP connection to Google Talk has been established:

    # asterisk -rx "jabber show connections"
    Jabber Users and their status:
           User: ...@gmail.com/asterisk     - Connected
    ----
       Number of users: 1

  6. Now you’re ready to set up a Google Voice trunk and inbound and outbound routes in FreePBX.

Part 2: FreePBX

  1. Add a new Custom Trunk.
    • Trunk name: Google Voice
    • Outbound Caller ID: put your Google Voice DID, even though this will be ignored (GV always uses your GV number for the outbound Caller ID)
    • Dialed Number Manipulation Rules: Google Voice requires that the number be a full 11 digits, starting with 1. Either here or in your outbound route (or both), make sure you are sending a full 11-digit number. See the screenshot for my config.
    • Custom Dial String: This is the most important part. Enter gtalk/asterisk/+$OUTNUM$@voice.google.com where asterisk matches the client definition in your jabber.conf (in square brackets). If you’ve followed this how-to exactly, then this line is correct.
    • Submit changes.
    • Screenshot (click for full version):
      gvtrunk-small.png
  2. Add a new Outbound Route.
    • You can send any US domestic calls through Google Voice. Just configure an appropriate outbound route and select Google Voice as the trunk. In this screenshot, I have configured 11-, 10-, and 7-digit dialing within my own area code.
    • Screenshot (click for full version):
      outroute-small.png
  3. Add a new Inbound Route.
    • Refer back to this line you entered in extensions_custom.conf: exten => s,n,Goto(from-trunk,YOUR-GV-NUMBER,1) Whatever you entered for YOUR-GV-NUMBER will be the DID you use for your inbound route.
    • Description: Google Voice (or whatever you want)
    • DID Number: YOUR-GV-NUMBER
    • Other stuff: defaults
    • Destination: wherever you want the incoming call to go. In my screenshot, it is directly dialing an extension.
    • Screenshot (click for full version):
      inroute-small.png
  4. Submit all changes and apply configuration. Done! You have added a Google Voice two-way trunk to FreePBX and can use it in your inbound and outbound routing. Don’t forget to log in to Google Voice and select Google Chat (…@gmail.com) as the phone to which your incoming calls are forwarded!

Asterisk 1.8 on the Rackspace Cloud

In this post I’ll share the few notes I have on installing Asterisk 1.8 on a Rackspace CloudServer. First, note that I am not promoting this specific cloud provider. (There are several others, such as Amazon EC2 and Linode.) But I am all about VoIP on the cheap, and the baseline RS CloudServer seems to be as inexpensive as you can get. Moreover, I started using RS CloudServers a little while ago just for some quick Linux testing, and liked them. So when I thought about testing Asterisk 1.8, I set up a new instance there.

I’m not a software engineer and can’t effectively analyze Asterisk’s code to say whether it should or should not perform well in a cloud environment, but testing in this environment shows that it works fine, with one caveat: you can’t use the DAHDI kernel module. On other providers where the kernel headers and sources are available, you can compile DAHDI, but RS Cloud does not provide their Xen-optimized kernel source. The good news is that with Asterisk 1.8 (actually, starting in 1.6.2), you don’t need DAHDI unless you have directly-attached telephony hardware, which you don’t, because your server is in the cloud.

To further explain that: previously, you’d need a DAHDI hardware module or the DAHDI dummy driver to provide the timer for the IAX2 protocol and MeetMe. IAX2 no longer needs it, and while MeetMe does still need at least the dummy timer, there’s a new conference bridge application available that doesn’t need it–app_confbridge. (And if you don’t care about having a conference bridge anyway, this whole matter is moot.)

After all that introduction, I’m glad to say that actually building Asterisk and FreePBX on the cloud server is straightforward and only requires a few adjustments from building on physical hardware. I’m going on the assumption that you have built Asterisk and FreePBX before on a physical server. Here are the extra steps I had to take to build on RS Cloud.

Asterisk

  • Create an instance of CentOS 5.5 on the 256 MB RAM/10 GB storage server. For test, this is enough. If you end up running a lot of calls through it, you’ll need a bigger VM. But the 256 MB server is a bargain at 1.5 cents per hour and 22 cents per gigabyte download and 8 cents per gigabyte upload. (Can you even get old hardware, electricity and bandwidth for testing for this price?)
  • yum update and add build tools to the environment (yum install gcc make gcc-c++ ncurses-devel libtool subversion). This is also a good time to add the packages that FreePBX needs. (My list included mysql-server mysql-devel libxml2-devel libtiff-devel php-pear php-pear-DB php-gd php-mysql php-pdo perl-DateManip mod_ssl)
  • useradd -c "Asterisk PBX" -d /var/lib/asterisk asterisk; mkdir /var/run/asterisk; mkdir /var/log/asterisk
  • Get asterisk-1.8.x.tar.gz and expand. There is no more asterisk-addons package; it’s now part of the asterisk tar file.
  • For Google Talk/XMPP/Google Voice:
    • yum install openssl-devel
    • svn co http://iksemel.googlecode.com/svn/trunk/ iksemel-read-only
    • Build iksemel with ./autogen.sh; ./configure; make; make install
    • Iksemel puts its libraries in /usr/local/lib, so add this location to your library path: echo /usr/local/lib > /etc/ld.so.conf.d/local.conf; ldconfig
  • Build: cd to the asterisk-1.8 directory, then ./configure; make menuselect
  • Review the modules being built. app_meetme won’t be available because DAHDI isn’t built. Add app_confbridge instead. Make sure res_jabber and chan_gtalk are selected if you want to set up Google Talk/Voice. Review the other modules including the ones listed in Add-ons (formerly a separate tar file) especially if you are adding FreePBX–you’ll want cdr_mysql.
  • Keep building: make; make install; make samples
  • Important for the RS Cloud environment: there is no TTY9, which safe_asterisk puts the Asterisk console on. Edit /usr/sbin/safe_asterisk and comment out line 5 (TTY=9) and set CONSOLE=no on line 6. Everything else should be fine.
  • Asterisk should be ready to go!

FreePBX

  • When I installed FreePBX 2.8.0, it complained that Asterisk 1.8 was not supported. The repository has an updated installer (see http://www.freepbx.org/v2/changeset/10494) but if you’re going from the 2.8.0 (or earlier?) tarball, you’ll have to make the change highlighted here. Edit line 899 in install_amp and change 1.7 to 1.9.
  • Now install FreePBX according to your own documentation or that available on FreePBX.org

Startup

  • Add /usr/local/sbin/amportal start to the end of /etc/rc.d/rc.local, or make an init script for /etc/init.d. I’m lazy and chose the former.
  • Start everything up with amportal start.

More to do

Get familiar with iptables, if you’re not already. This is the way to control access on your RS CloudServer node. By default it permits SSH, so you’ll want to add lines to permit web, SIP, IAX2, and so on.

Since you’re running in 256 MB RAM, you might want to pare down the /etc/httpd/conf/httpd.conf and reduce the number of web servers spawned, to save a little memory. The RS CloudServer is already pretty thin, otherwise.

Testing

I did some additional configuration of FreePBX, not essential to this posting, and then configured a softphone extension and a Google Voice trunk (to be discussed in a later posting). Then I made some calls. Even with both legs of the call going over the Internet, from a shared hosting facility, using G.711 uLaw (PCMU), the sound was great.

Later

More on the Google Voice setup and FreePBX, and considerations for having your PBX out on the Internet. This would be a good time to start thinking about secure RTP!