Seattle P-I on VoIP

The P-I has a nice little article on VoIP on their website today. It’s much more positive then I’ve come to expect–basically, it presents VoIP as an up-and-coming way to save money on phone service. They talked to Skype and Vonage users, as well as some industry types, and generally gave a spin-free picture of what’s possible with current consumer VoIP services.

There’s no real discussion of business VoIP usage, or anything like Asterisk, but that’s really out of scope for most newspapers anyway.

Posted by Scott Laird Fri, 23 Jul 2004 18:16:09 GMT


Asterisk status

I’ve been paying a bit of extra attention to Asterisk this week, trying to figure out exactly what is stable and production-ready and what is still flaky.

By and large, most of the complaints that I’ve seen on the asterisk-users mailing list have something to do with one of these areas:

  • H.323
  • Echos in voice calls
  • Problems with analog FXO lines, particularly outside of the US
  • NAT
  • Configuring SIP phones
  • VoIP provider issues (finding one, provisioning problems, outages, etc)
  • Generic asterisk configuration problems (lack of documentation)

Of these, the first three are real production problems with Asterisk, while the other four are either teething problems or generic problems with VoIP in complex networks. Generally, once you find a provider and configure your hardware and software, Asterisk seems reliable. Except for echo.

Echos are a fundamental problem with all types of phone calls–most users hear echos of their own voice on cell phones and traditional long-distance phone calls from time to time, although it’s fairly rare. A number of things can cause echos, but it’s usually either analog impedance mis-matches or 4-wire to 2-wire transitions. Since every analog phone in the country uses a 2-wire connection to the network, every single phone has the ability to add echos.

For low-latency local calls, echoing isn’t a problem–it sounds like light reverb on your own voice, and it isn’t usually even noticeable. The big problem comes in when calls have longer latencies, either because of the distances involved or because of VoIP packetization delays. When that happens, the delay between your voice going out and the echo coming back can be long enough to be annoying or distracting.

Because of this, a lot of work has went into echo cancelation for digital phone systems. Asterisk includes a configurable echo canceler. While this canceler may not be as good as some commercial equipment, it’s generally good enough, unless a few specific conditions exist:

  1. You’re using analog phone lines (FXO) and there’s an impedance *or* level mis-match between Asterisk’s FXO interfaces and the phone lines. This will cause all sorts of fun problems. Similar problems have plagued traditional phone systems for years. Solutions exist, but they tend to require someone who really knows analog phone lines. In theory, knowledge of the local telco’s test phone numbers and a couple tools should be good enough to tune Asterisk to avoid these problems, but the actual procedures aren’t well documented.

  2. You’re using digital phone lines (T1, PRI) but you’re losing frames from time to time, due to PCI latency problems or possibly system load. It appears that Asterisk’s echo canceler can cause echos when this occurs, although this hasn’t been conclusively proved.

  3. Given #2, it’s possible that the same problems can occur when using VoIP and packet loss occurs, but I haven’t heard anyone raise this as a possibility.

Other then that, Asterisk seems to be working well for people. Most people seem to be using it as a traditional business PBX with SIP phones and a PRI for external calls without any problems at all. Given Asterisk’s price and flexibility, this sounds like a great way for an organization with in-house Linux experience to get a power, flexible phone system for a reasonable price.

Posted by Scott Laird Thu, 22 Jul 2004 01:05:06 GMT


Asterisk 1.0-rc1

Mark Spencer announced the first release candidate for Asterisk 1.0 over the weekend:

We have officially made the first release candidate of Zaptel, Libpri, Asterisk and Gastman available. While there are still open major bugs, they are relatively limited, and it was time to go ahead and get the 1.0 ball rolling in earnest.

ftp://ftp.digium.com/pub/asterisk

Enjoy the code. Special thanks to all the bug marshals and contributers and to everyone who has supported Asterisk through the purchase of Digium hardware. I apologize in advance for our slow 768k link. Please report bugs at http://bugs.digium.com and please read the instructions there before submitting bugs or patches.

I hope everyone can share in my excitement, especially as excited as I’ll be once I’ve actually had some sleep.

This is a great step, as Asterisk hasn’t had a stable release in a while; the preferred way of installing it has been directly out of CVS, but the CVS tree has been so active that the mailing list has been dotted with users with broken builds and weird transient bugs. Settling down for a release is just was Asterisk needs at this point.

I’ll upgrade my home server this week as time permits.

Posted by Scott Laird Mon, 19 Jul 2004 06:05:25 GMT


Asterisk config example

Someone asked for a copy, so here’s an edited copy of my Asterisk extensions.conf file. I changed most of the email addresses to user@example.com, and replaced parts of specific phone numbers with ‘9999’, but other then that, it’s essentially the same. There’s some legacy cruft in here, and parts of it are overly complex. It implements a few features that you don’t strictly need in most setups. particularly the 10-digit dialing bit that makes ‘1’ for long distance optional.

Here it is, warts and all:

[general]
  static=yes
  writeprotect=no

[globals]
  TRUNK=Zap/1                           ; FXO interface
  ANALOG=Zap/2                          ; FXS interface

  SCOTTSIP=Sip/2202
  CYNSIP=Sip/2203
  KITSIP=Sip/2204
  NUFONE=IAX2/account@NuFone
  PHONES=${ANALOG}&${SCOTTSIP}&${CYNSIP}&${KITSIP}

; Fax receiving macro.  Handles rxfax and directing the fax to the 
; correct email address.
[macro-faxreceive]
  exten => s,1,SetVar(FAXFILE=/var/spool/asterisk-fax/${UNIQUEID}.tif)
  exten => s,2,DBGet(EMAILADDR=extensionemail/${MACRO_EXTEN})
  exten => s,3,rxfax(${FAXFILE})
  exten => s,103,SetVar(EMAILADDR=user@example.com)
  exten => s,104,Goto(3)

; Outside line macro.  This handles incoming phone calls from outside
; of the house, including caller-ID rewriting, blacklisting, and
; distinctive ring.
[macro-outsideline]
  exten => s,1,SetCDRUserField(Outside (${CHANNEL}))
  exten => s,2,LookupCIDName
  exten => s,3,SetMusicOnHold(random)
  exten => s,4,Macro(setalertinfo)
  exten => s,5,LookupBlacklist
  exten => s,6,Dial(${PHONES},13,Ttmr)
  exten => s,7,Answer
  exten => s,8,Goto(outside-ivr,s,1)
  exten => s,106,Goto(206)
  exten => s,107,Goto(7)
  exten => s,206,Wait(3600)
  exten => s,207,Hangup

; Extension dialing logic.  Call an internal extension and bounce to VM
; if no answer.
[macro-callextension]
  exten => s,1,Dial(${ARG1},30,t)
  exten => s,2,Voicemail(${ARG2})
  exten => s,3,Hangup
  exten => s,102,Voicemail(${ARG2})
  exten => s,103,Hangup

; The next block of macros handle outgoing calls.  This is more complex
; then you'd expect for a couple reasons.  First, I'm using two different
; outgoing mechanisms--NuFone and my POTS line, but I'd like either one
; to be able to work as a fallback if the other fails.
;
; Next, I want to be able to handle 7- and 10-digit dialing without
; having to remember which area codes and prefixes require a '1' first.
; I'm in the Seattle area, and part of 425 is free, along with 95% of
; 206.  With POTS, I must dial a '1' iff it is a toll call.  With
; NuFone I must always dial a 1.
;
; See http://scottstuff.net/scott/archives/000163.html

; This handles 10-digit local numbers
[macro-dialanalogwithfallback]
  exten => s,1,Dial(${TRUNK}/${MACRO_EXTEN})
  exten => s,2,Congestion
  exten => s,102,SetCallerID(4254889999)
  exten => s,103,SetCIDName(LAIRD SCOTT)
  exten => s,104,Dial(${NUFONE}/1${MACRO_EXTEN})
  exten => s,105,Congestion
  exten => s,205,Busy

; This handles 7-digit local numbers
[macro-dialanalogwithfallback425]
  exten => s,1,Dial(${TRUNK}/425${MACRO_EXTEN})
  exten => s,2,Congestion
  exten => s,102,SetCallerID(4254889999)
  exten => s,103,SetCIDName(LAIRD SCOTT)
  exten => s,104,Dial(${NUFONE}/1425${MACRO_EXTEN})
  exten => s,105,Congestion
  exten => s,205,Busy

; This handles 10-digit non-local numbers
[macro-dialanalogwithfallback1]
  exten => s,1,Dial(${TRUNK}/1${MACRO_EXTEN})
  exten => s,2,Congestion
  exten => s,102,SetCallerID(4254889999)
  exten => s,103,SetCIDName(LAIRD SCOTT)
  exten => s,104,Dial(${NUFONE}/1${MACRO_EXTEN})
  exten => s,105,Congestion
  exten => s,205,Busy

; This just dials via POTS without any special handling
[macro-dialanalog]
  exten => s,1,Dial(${TRUNK}/${MACRO_EXTEN})
  exten => s,2,Congestion
  exten => s,102,Busy

; ditto, but for NuFone.
[macro-dialnufone]
  exten => s,1,SetCallerID(4254889999)
  exten => s,2,SetCIDName(LAIRD SCOTT)
  exten => s,3,Dial(${NUFONE}/${MACRO_EXTEN})
  exten => s,4,Congestion

[macro-dialnufonewithfallback]
  exten => s,1,SetCallerID(4254889999)
  exten => s,2,SetCIDName(LAIRD SCOTT)
  exten => s,3,Dial(${NUFONE}/${MACRO_EXTEN})
  exten => s,4,Congestion
  exten => s,104,Dial(${TRUNK}/${MACRO_EXTEN})
  exten => s,105,Macro(fastbusy)
  exten => s,205,Busy

; for 10-digit dialing in non-local areas
[macro-dialnufonewithfallback1]
  exten => s,1,SetCallerID(4254889999)
  exten => s,2,SetCIDName(LAIRD SCOTT)
  exten => s,3,Dial(${NUFONE}/1${MACRO_EXTEN})
  exten => s,4,Congestion
  exten => s,104,Dial(${TRUNK}/1${MACRO_EXTEN})
  exten => s,105,Macro(fastbusy)
  exten => s,205,Busy

; This sets the ALERT_INFO variable based on the CALLERIDNUM
; setting via a lookup in the 'distinctivering' database.  See
; http://scottstuff.net/scott/archives/000163.html
[macro-setalertinfo]
  exten => s,1,DBGet(ALERT_INFO=distinctivering/${CALLERIDNUM})

; This is the 'inside' context, where calls made from inside of the
; house start out.  The 'inside' context (or 'inside-sip'/'inside-analog')
; is referred to in sip.conf and zapata.conf.  That's what ties this all
; together.
[inside]
  include => parkedcalls
  include => operator
  include => e911
  include => forced-analog
  include => information
  include => local
  include => pstn-local10
  include => tollfree
  include => pstn-nonlocal10
  include => international

; There's no real reason for these to exist right now; I could
; just replace the references to them in sip.conf/zapata.conf
; with references to the 'inside' context.  This is kind of 
; historical.
[inside-sip]
  include => inside

[inside-analog]
  include => inside

[operator]
  exten => 0,1,Macro(dialanalog)

[e911]
  exten => 911,1,Macro(dialanalog)
  exten => 9911,1,Macro(dialanalog)

[forced-analog]
  exten => _9.,1,Macro(dialanalog)

[information]
  exten => 411,1,Macro(dialanalog)

; The 'local-extensions.conf' file is autogenerated.  See
; http://scottstuff.net/scott/archives/000163.html and
; http://svn.scottstuff.net/project/asterisk-lca-map/
[pstn-local10]
#include "local-extensions.conf"

[pstn-nonlocal10]
  exten => _NXXNXXXXXX,1,Macro(dialnufonewithfallback1)
  exten => _1NXXNXXXXXX,1,Macro(dialnufonewithfallback)

[tollfree]
  exten => _1888NXXXXXX,1,Macro(dialanalogwithfallback)
  exten => _1877NXXXXXX,1,Macro(dialanalogwithfallback)
  exten => _1866NXXXXXX,1,Macro(dialanalogwithfallback)
  exten => _1855NXXXXXX,1,Macro(dialanalogwithfallback)
  exten => _1800NXXXXXX,1,Macro(dialanalogwithfallback)

  exten => _888NXXXXXX,1,Macro(dialanalogwithfallback1)
  exten => _877NXXXXXX,1,Macro(dialanalogwithfallback1)
  exten => _866NXXXXXX,1,Macro(dialanalogwithfallback1)
  exten => _855NXXXXXX,1,Macro(dialanalogwithfallback1)
  exten => _800NXXXXXX,1,Macro(dialanalogwithfallback1)

[international]
  exten => _011.,1,Macro(dialnufone)

[local]
  exten => 2200,1,Macro(callextension,${PHONES},2201)
  exten => 2201,1,Macro(callextension,${ANALOG},2201)
  exten => 2202,1,Macro(callextension,${SCOTTSIP},2202)
  exten => 2203,1,Macro(callextension,${CYNSIP},2203)
  exten => 2204,1,Macro(callextension,${KITSIP},2201)
  exten => 2205,1,Macro(callextension,${KITSIP},2201)

  exten => 2230,1,Answer
  exten => 2230,2,Wait(5)
  exten => 2230,3,Goto(fax,2201,1)

  exten => 2211,1,Answer
  exten => 2211,2,Goto(outside-ivr,s,1)
  exten => 2211,3,Beep
  exten => 2211,4,Hangup

  exten => 2222,1,Wait,2
  exten => 2222,2,VoicemailMain(s2201)
  exten => 2222,3,Hangup

  exten => 2223,1,Wait,2
  exten => 2223,2,VoicemailMain
  exten => 2223,3,Hangup

[outside-ivr]
  ; This is the outside IVR
  ; Playback a "We're not home message"
  ; To leave a message for Scott, press 1
  ; To leave a message for C, press 2
  ; Otherwise stay on the line.
  ;
  ; Also, 3 => main voicemail
  ;   4 => check voicemail (main)
  ;   5 => check voicemail
  ;
  ; Check for fax, too

  exten => s,1,AppendCDRUserField( -> IVR)
  exten => s,2,DigitTimeout(5)
  exten => s,3,ResponseTimeout(2)
  exten => s,4,Wait(1)
  exten => s,5,Background(laird/ivr-greeting)

  exten => 1,1,AppendCDRUserField( -> 1)
  exten => 1,2,Wait(1)
  exten => 1,3,VoiceMail(us2202)
  exten => 1,4,Hangup

  exten => 2,1,AppendCDRUserField( -> 2)
  exten => 2,2,Wait(1)
  exten => 2,3,VoiceMail(us2203)
  exten => 2,4,Hangup

  exten => 3,1,AppendCDRUserField( -> 3)
  exten => 3,2,Wait(1)
  exten => 3,3,VoiceMail(us2201)
  exten => 3,4,Hangup

  exten => 4,1,AppendCDRUserField( -> 4)
  exten => 4,2,Wait(1)
  exten => 4,3,VoiceMailMain(2201)
  exten => 4,4,Hangup

  exten => 5,1,AppendCDRUserField( -> 5)
  exten => 5,2,Wait(1)
  exten => 5,3,VoiceMailMain
  exten => 5,4,Hangup

  exten => 7,1,AppendCDRUserField( -> 7)
  exten => 7,2,Goto(outside-ivr-7,s,1)

  exten => fax,1,AppendCDRUserField( -> fax)
  exten => fax,2,Answer
  exten => fax,3,Goto(fax,2201,1)

  exten => t,1,AppendCDRUserField( -> timeout)
  exten => t,2,VoiceMail(s2201)
  exten => t,3,Hangup

  exten => i,1,AppendCDRUserField( -> invalid)
  exten => i,2,Playback(tt-allbusy)
  exten => i,3,Goto(s,3)

[outside-ivr-7]
  exten => s,1,AppendCDRUserField( -> ivr7)
  exten => s,2,Wait(1)
  exten => s,3,Background(tt-weasels) ; need to record a better message...

  exten => t,1,Goto(s,1)

  exten => i,1,Goto(s,1)

  exten => 1,1,Dial(Local/12069999991@inside)
  exten => 2,1,Dial(Local/12069999992@inside)
  exten => 0,1,Goto(outside-ivr,s,1)

[fax]
  exten => fax,1,Macro(faxreceive)
  exten => 2201,1,Macro(faxreceive)
  exten => 2202,1,Macro(faxreceive)
  exten => 2203,1,Macro(faxreceive)

  exten => h,1,system(/usr/local/sbin/mailfax ${FAXFILE} ${EMAILADDR} "${CALLERIDNUM} ${CALLERIDNAME}")

; This is where outside calls enter the system, thanks to 
; zapata.conf, sip.conf, and iax2.conf.  By and large, calls are
; directed to the 'outsideline' macro, *except* for the second 
; 866 number; that's just for checking voicemail.
[outside]
  exten => s,1,Macro(outsideline)
  exten => s,2,Hangup
  exten => 4254889999,1,Macro(outsideline)
  exten => 4254889999,2,Hangup
  exten => 8662299999,1,Macro(outsideline)
  exten => 8662299999,2,Hangup

  exten => 8662559999,1,VoicemailMain(2201)
  exten => 8662559999,2,Hangup
  exten => 8662559999/2069999991,1,VoicemailMain(s2201)
  exten => 8662559999/2069999991,2,Hangup
  exten => 8662559999/2069999992,1,VoicemailMain(s2201)
  exten => 8662559999/2069999992,2,Hangup

  exten => fax,1,Goto(fax,2201,1)
  exten => t,1,Hangup
  exten => h,1,Hangup

[outside-analog]
  exten => s,1,Goto(outside,4254889999,1)

[outside-sip]
  include => outside

[outside-nufone]
  include => outside

Posted by Scott Laird Fri, 18 Jun 2004 13:23:15 GMT


New rates for NuFone

It looks like NuFone has finally listed their rates on their website. I’ve been happy with their services, but getting information out of them has been like pulling teeth.

On the plus side, their US rates have dropped from $0.0295/minute to $0.0200/minute. That’s $1.20/hour. My monthly long-distance bill has dropped off to almost nothing since I started using VoIP.

Just out of curiosity, I ran a quick search to see which countries I could call for under $0.05/minute. This doesn’t mean that all numbers are cheap (calls to mobile phones tend to cost extra), but that at least one part of the country (the capital city, if no where else) has cheap telephone access:

Argentina, Australia, Austria, Belgium, Brazil, Canada, Chile, China, Czech Republic, Denmark, Estonia, Finland, France, Germany, Hong Kong, Ireland, Israel, Italy, Japan, Luxembourg, Malaysia, Mexico, Netherlands, New Zealand, Norway, Peru, Portugal, Russia, Singapore, South Korea, Spain, Sweden, Switzerland, Taiwan, US, United Kingdom

In other words, I can call pretty much every industrialized country in the world via VoIP for less then my ILEC charges me to call numbers 10 miles away.

Posted by Scott Laird Wed, 16 Jun 2004 22:57:00 GMT


And speaking of hating software...

This was the buggiest weekend that I’ve had in years. I tried to do one simple thing: upgrade Asterisk to the latest CVS version to fix a Cisco-Asterisk interaction bug. Here’s what went wrong:

  1. Asterisk wouldn’t install without some new sound files that didn’t exist in the CVS tree.
  2. Once it was installed, it wouldn’t start. Staring at things long enough lead to an obsolete plugin that worked with the previous version (3 months old), but not the new one. Deleting it let Asterisk start again.
  3. Incoming calls via POTS work fine, but incoming calls via NuFone refuse to go to voicemail. They’ll ring, but if no one answers, instead of my voicemail prompt, callers hear Allison saying that the caller is unavailable. According to my logs, I’m not playing the message, so it must be NuFone.
  4. My new asterisk->cellphone email script wasn’t working, so I upgraded my MTA to the latest minor revision from Debian and discovered two bugs. Basically, the upgrade ate my entire alias file, and it failed to fix the original bug.
  5. And that bug’s just great: Debian’s build of courier’s makealiases script does weird things to command aliases. Basically, it double-appends the domain name to the name of the alias in aliases.dat, but only appends it once when generating the .courier file that actually runs the command. So, email aliases that get piped to commands just don’t work.

Oh, and on top of that, Asterisk’s hold music generator ran wild yesterday and slogged down my Asterisk server, leaving me with no phone service at home for a few hours. Ugh. There’s a reason that I waited 3 months to upgrade. I swear, once 1.0 is finally released, I’m not upgrading for years.

Posted by Scott Laird Tue, 15 Jun 2004 13:56:58 GMT


Asterisk, the OS X Address Book, and cheap calls without dialing '1'

I am a happy man. I have, after four years of trying, achieved nerdvana. I am down to one single address book, accessible everywhere. It’s shared between my computer, my cell phone, my palm, my wife’s Mac, her phone, and finally, as of yesterday, our home phone. I can add new contacts anywhere, and they show up everywhere automatically.

It’s actually even more pervasive then that; the same address book entries re-write incoming caller ID and control our home phone’s ringer, so we can tell the difference between friends and telemarketers without even looking at the caller ID display. The best part is that it all just works. Setting it up in the first place took a bit of work, but once it’s running, all I have to do is drag cards around inside of the OS X Address Book, and everything else follows along on its own.

The first part of this whole operation was to get data out of the OS X Address Book and into a form that I could work with on one of my servers at home. Towards that end, I wrote ab2vcard, a simple tool that extracts vCards for every address book entry and stores them in a directory. If you set up Subversion and use the right flags on ab2vcard, then all of your vCards will be checked into Subversion and automatically replicated onto the Subversion server. I run ab2vcard from cron, so every two hours, all of my addresses are automatically sent to my server at home.

Next, I wrote asterisk-vcard-cid so I could use the names in my Address Book for Caller ID instead of the nasty stuff that Verizon sends me. If you copy the ‘vcardcid-cron.sh’ file that comes with it onto your Asterisk server and run it every couple hours, then it’ll do all of the hard work of checking changes out of Subversion and shoving them into Asterisk. The way I have it set up, I have 5 groups in my Address Book:

  • Home CallerID
  • Home Ring 1
  • Home Ring 2
  • Home Ring 3
  • Home Ring 4

Any contacts in the ‘Home CallerID’ group will automatically be added to the caller ID DB in Asterisk. Anyone in one of the ‘Home Ring’ groups will have ‘distinctive ring’ turned on when they call. That was really easy with Asterisk. All I had to do was add a macro like this:

[macro-setalertinfo]
  exten => s,1,DBGet(ALERT_INFO=distinctivering/${CALLERIDNUM})

Then, I make sure that all incoming calls use this macro. Here’s my complete outside line macro:

[macro-outsideline]
  exten => s,1,SetCDRUserField(Outside (${CHANNEL}))
  exten => s,2,LookupCIDName
  exten => s,3,SetMusicOnHold(random)
  exten => s,4,Macro(setalertinfo)
  exten => s,5,LookupBlacklist
  exten => s,6,Dial(${PHONES},13,Ttmr)
  exten => s,7,Answer
  exten => s,8,Goto(outside-ivr,s,1)
  exten => s,106,Wait(3600)
  exten => s,107,Hangup

This handles caller-ID rewriting, blacklisting, distinctive rings, adds extra logging, and sends unanswered calls to voicemail.

One little note on distinctive ring: the way I’m using it, it probably only works right with Cisco SIP phones, although other SIP phones that support distinctive ring will work with a few changes to the vcardcid-cron script.

Finally, I’ve added a mechanism for tying the same set of vCards into the speed dial directory on Cisco SIP phones. I’m using the 7940, but the 7905, 7912, 7920, 7960, and 7970 should all work. Each of these phones has the ability to download XML programming objects over HTTP. There aren’t a lot of great references out there, but this one is fairly complete and seems accurate so far.

The directory tool that I wrote, cisco-phone-directory, runs as a CGI on a web server. If you set up the Cisco phone right, every time you select ‘external directory’ from the directory menu, you’ll be prompted with a search screen. Enter a few letters from the name that you’re looking for, and you should get a nice, short list of names to choose from. At this point, it works with almost no fuss, and almost no user training.

Er, except for one little problem. All of the numbers in my address book look like (206)-555-1212. Once you strip the punctuation, you’re left with 10 digits. The problem is that I need to dial a ‘1’ before I call long distance numbers, and it’s not really obvious which numbers are long distance and which aren’t. I can dial most numbers in the 206 area code for free, and about half of the numbers in 425, but there’s no simple way to tell which numbers are which. Since I’m cheap, I want to send toll-free calls out over a real phone line, because it doesn’t cost me anything, while I send toll calls to NuFone over the Internet, because they cost about half as much per minute.

In order to do that, I need to know which numbers are local, given my phone’s area code and exchange. So, enter yet another tool: asterisk-lca-map. If your home number was (425)-488-1212, then you’d run it from the command line like this:

$ asterisk-lca-map.rb 425 488 1212 'Macro(dialanalog)'

and it’ll produce a dial plan that sends all local calls out ‘Macro(dialanalog)’, like this:

exten => _206200XXXX,1,Macro(dialanalog)
exten => _206202XXXX,1,Macro(dialanalog)
exten => _206203XXXX,1,Macro(dialanalog)
exten => _206204XXXX,1,Macro(dialanalog)
exten => _206205XXXX,1,Macro(dialanalog)
exten => _206208XXXX,1,Macro(dialanalog)
exten => _206210XXXX,1,Macro(dialanalog)
exten => _206213XXXX,1,Macro(dialanalog)
exten => _206214XXXX,1,Macro(dialanalog)
exten => _206215XXXX,1,Macro(dialanalog)

You can then add a couple extra rules at the bottom to handle 800 numbers and toll calls:

exten => _888NXXXXXX,1,Macro(dialanalog1)
exten => _1888NXXXXXX,1,Macro(dialanalog)
; continue on with 877, 866, 855, and 800

exten => _NXXNXXXXXX,1,Macro(dialnufone1)
exten => _1NXXNXXXXXX,1,Macro(dialnufone)

The ‘dialanalog1’ and ‘dialnufone1’ macros prepend a ‘1’ to the number that they’re calling. When all of this is done, dialing ‘2062001111’ goes out the POTS line as-is, while dialing ‘2125551212’ goes out NuFone as ‘12125551212’. Everything Just Works, and users don’t have to know when to dial a 1 and when not to. They never actually need to dial the 1 at all, although if they do, it’ll still work. And that’s what I’m aiming for–the back end is complex, because it has to interact with complex parts of the real world. The front end is dead simple, though, because I can handle all of the hard bits without bothering the user. They can just dial the phone number, and I’ll route it out the cheapest connection automatically.

Posted by Scott Laird Fri, 09 Apr 2004 08:23:06 GMT


Asterisk and Request Tracker

I’d probably be more excited about this if I had to perform day-to-day support anymore, but it’s still cool: an interface between the Asterisk VoIP PBX and the Request Tracker trouble-ticket system. This would probably be a great way to handle support voicemail in a small tech company. It’d be interesting to see what it’d take to route all support calls through RT; it’s pretty typical to have support email recorded in RT, so why not “this message may be recorded to ensure quality service” calls?

Posted by Scott Laird Mon, 05 Apr 2004 20:20:08 GMT


vCard to Asterisk conversion tool (asterisk-vcard-cid)

I’ve been using the LookupCIDName command to re-write incoming caller ID names for people that I know. This way, instead of ‘VOICESTREAM’, I get names like ‘Laird, Rusty - cell’.

Using LookupCIDName is easy, but populating the database it uses isn’t. So, here’s a tool: asterisk-vcard-cid. It extracts names and numbers for a directory full of vCards and inserts them into Asterisk’s cidname database. This, combined with ab2vcard and Subversion makes it easy to export your Mac OS X Address Book into Asterisk, although nothing here is really limited to Mac OS X; vCards are the dominant standard for exchanging address book information, so almost everything supports them.

There are two things to be aware of for this release. First, the code is written in Ruby, so you’re going to need a Ruby interpreter installed. Most Linux distributions have one prepackaged; use ‘ruby1.8’ on Debian.

Second, this release can only handle 1 vCard per vCard file. That’s the format that I’m using with ab2vcard, but most tools would rather do bulk exports by bundling lots of vCards together into a single file. If anyone is interested, then I can add support for multiple-vCard files in the next release.

Posted by Scott Laird Tue, 30 Mar 2004 13:23:23 GMT


Faxing with Asterisk

I’ve spent some time working with Asterisk and faxes this weekend. By itself, Asterisk doesn’t know much about faxing. It’s able to spot incoming faxes and yank them out of IVR menus, but that’s about it.

Fortunately, Asterisk is extensible, and someone has written a software faxmodem plugin for it. More specifically, Steve Underwood has written SpanDSP, a more or less complete fax modem, plus a couple Asterisk applications (RxFax and TxFax) for sending and receiving faxes. The applications still need a bit of polishing (as far as I can tell, there’s no way to extract fax metadata from them, like the speed of the connection, the caller’s fax number, and so forth), but they work, and he’s spitting out a couple new releases per week, adding workarounds for increasing numbers of broken fax devices.

I probably wouldn’t trust SpanDSP with all of my company’s faxes today, but it’s improving so quickly that I’ll probably want to revisit that conclusion in a month or two. In preparation for that day, I’m prototyping what it takes to add direct-dialed fax extensions to Asterisk, and then deliver the faxes via email. It turned out to be surprisingly easy.

First, add this to the top of your /etc/asterisk/extensions.conf file:

[macro-faxreceive]
  exten => s,1,SetVar(FAXFILE=/var/spool/asterisk-fax/${UNIQUEID}.tif)
  exten => s,2,DBGet(EMAILADDR=extensionemail/${MACRO_EXTEN})
  exten => s,3,rxfax(${FAXFILE})
  exten => s,103,SetVar(EMAILADDR=defaultuser@example.com)
  exten => s,104,Goto(3)

Next, create a ‘fax’ context in Asterisk and add all of your fax extensions to it. This seems to be the easiest way to have a script run whenever a fax line hangs up, but not run it on every call (hmm, how does this work if you include the fax context into ‘outside’?):

[fax]
  exten => 2201,1,Macro(faxreceive)
  exten => 2202,1,Macro(faxreceive)
  exten => 2203,1,Macro(faxreceive)

  exten => h,1,system(/usr/local/sbin/mailfax ${FAXFILE} \
        ${EMAILADDR} "${CALLERIDNUM} ${CALLERIDNAME}")

Of course, incoming fax calls have to make it to this extension. Here’s part of my ‘outside’ context that hands fax calls off to the fax context:

[outside]
  exten => 2125551212,1,Goto(fax,5555,1)
  exten => fax,1,Goto(fax,2201,1)

The ‘fax’ line will catch any faxes that end up autodetected in the middle of an IVR or voicemail prompt.

SpanDSP receives faxes into TIFF files, but they’re kind of a pain to view, so I’m converting them to PDFs inside of /usr/local/sbin/mailfax:

#!/bin/sh

FAXFILE=$1 
RECIPIENT=$2
FAXSENDER=$3

tiff2ps -2eaz -w 8.5 -h 11 $FAXFILE | 
  ps2pdf - |
  mime-construct --to $RECIPIENT --subject "Fax from $FAXSENDER" \
    --attachment fax.pdf --type application/pdf --file - 

There’s just one final step. Rather then code extension-to-email mapping directly into extensions.conf, I added a lookup via Asterisk’s internal database. So, you need to add DB entries for each extension. This is pretty easy; from the Asterisk CLI just type:

*CLI> database put extensionemail 2202 bob@example.com

You can verify that it worked by running ‘database show’.

One comment on fax and VoIP: conventional wisdom holds that the two don’t mix. At the very least, you can’t send faxes over a compressed VoIP link, although uncompressed (the G.711 ULAW codec in Asterisk) will probably work over a LAN. I haven’t tested it. In general, stick to faxing over traditional telephone interfaces, like POTS lines, ISDN, or T1s, and you’ll be happier.

Two final things: First, I’m fairly new to Asterisk. There’s probably an easier way then the way I’ve done it here. See the comment about ‘include =>’ above. Second, I’m kind of trusting Asterisk not to put nasty shell metacharacters into the parameters that I’m passing to mailfax. That’s probably not a good assumption; consider auditing the Asterisk code a bit, or just remove the caller ID name from the call to mailfax.

Posted by Scott Laird Mon, 29 Mar 2004 05:07:36 GMT