Posts in Category: voip

Asterisk 1471: Take 3

Hmm, this is turning into a regular saga now: so much so I’ve added a voip tag to these posts to help keep them together.

My original macro worked just fine when the incoming number and the dialled extension matched, but this is only true for my LAN and is not generally true when using external SIP providers as the incoming extension is very often the user id of the account. For this reason it’s very helpful to be able to pass in the destination extension number to the macro so that when the user calls 1471, the extension used to place that call will hear the correct caller id.

In this example, 123456 is the incoming extension from an external SIP provider, and 2000 is the actual extension on the LAN that the call is destined for:

[macro-dialcliexten]
exten => s,1,Set(DB(LastCallFrom/${ARG2})=${CALLERID(num)})
exten => s,2,Set(DB(LastCallTime/${ARG2})=${STRFTIME(${EPOCH},,%s)})
exten => s,3,Dial(${ARG1},30,toj)
exten => s,104,Voicemail(${ARG2})
exten => s,105,Hangup
 
[fromexternalsip] exten => 123456,1,Answer exten => 123456,2,Macro(dialcliexten,SIP/2000,2000)

Yes, this does cause some slight issues with groups: I haven’t got enough devices on my LAN to test that properly, but one idea I had was to store the caller id twice in the macro, with 0 being the group number (a synonym for the operator/group ring: change it if you like !):

[macro-dialcliexten]
exten => s,1,Set(DB(LastCallFrom/0)=${CALLERID(num)})
exten => s,2,Set(DB(LastCallFrom/${ARG2})=${CALLERID(num)})
exten => s,3,Set(DB(LastCallTime/0)=${STRFTIME(${EPOCH},,%s)})
exten => s,4,Set(DB(LastCallTime/${ARG2})=${STRFTIME(${EPOCH},,%s)})
...etc...

and with 1471 then reading out two numbers. This slightly deviates from the BT norm, and might need some user education but it’s not enough to simply store the number and only read out the most recent timestamp when calling 1471 as it’s possible for a group call to come in whilst one extension is in use.

Recording a couple of new voice prompts to give a result such as:

“The last number to call this extension was 01234 567890, today at 12:04pm and the last number to call these premises was 09876 543210 at 12:07pm”

might be one solution.

Asterisk 1471: Take 2

Update: Thanks to Steve for pointing out that SayNumber (line 5 of 1471 below) is a bad idea: it works just fine in limited testing on my LAN, but when given a normal UK 11-digit number it seems to have some trouble trying to pronounce 01234 567 890 as 1 billion, 234 million, 567 thousand 890…

Switching that command for SayDigits not only lets the function work, it also makes far, far more sense when listening to the result, too.

Ok, so I couldn’t leave it alone: here’s a macro’ed version with a modified 1471 readout that ought to trap illegal values. The only issue here is that I don’t currently have the FXO hardware and so I can’t say what the BT Unavailable, International and Withheld caller ID codes translate to in Asterisk.

All in the extensions.conf file, starting with the Macro definition:

[macro-dialcli]
exten => s,1,Set(DB(LastCallFrom/${MACRO_EXTEN})=${CALLERID(num)})
exten => s,2,Set(DB(LastCallTime/${MACRO_EXTEN})=${STRFTIME(${EPOCH},,%s)})
exten => s,3,Dial(${ARG1},30,toj)
exten => s,104,Voicemail(${MACRO_EXTEN})
exten => s,105,Hangup

And again, place these mappings in the correct context for your usage:

exten => 2000,1,Answer
exten => 2000,2,Macro(dialcli,SIP/2000)
 
exten => 2001,1,Answer
exten => 2001,2,Macro(dialcli,IAX2/2001)

Finally the new 1471 with a better date phrasing and some error checking:

exten => 1471,1,Answer
exten => 1471,2,Set(last=${DB(LastCallFrom/${CALLERID(num)})})
exten => 1471,3,Set(dtime=${DB(LastCallTime/${CALLERID(num)})})
exten => 1471,4,Playback(last-num-to-call)
exten => 1471,5,ExecIf($["${last}" != ""]|SayDigits|${last})
exten => 1471,6,ExecIf($["${last}" = ""]|Playback|unavailable)
exten => 1471,7,ExecIf($["${dtime}" != ""]|SayUnixTime|${dtime}||"Q IMp")
exten => 1471,8,Wait(2)
exten => 1471,9,Hangup

If anything, I suppose the lack of caller ID could be trapped at the start of the 1471 code and an “Unavailable” message could be played, but because this is on my own network I’m not that bothered about those cases as I will always want internal CID to be presented.

(Oops: an extra } crept in, so if you have taken a copy of this any time before the 23rd then do check your macro carefully)

Asterisk 1471

Wanting to make my home Asterisk box a convergence point for VoIP and PSTN mans that I really wanted to have the “last number caller id” option that BT offer in the UK, but sadly the page on the Asterisk Wiki that mentions 1471 is no longer valid, so here’s my own implementation. It’s not 100% feature complete, but it does work in a comparable way to the PSTN version.

All the work is done in the extensions.conf file and you need to add an explicit store of the incoming CID and time before routing the call to the correct extension, so this could (obviously) be improved by using the Macro command, but that, as many of my past lecturers used to say, is left as an exercise for the reader.

In this case, two extensions 2000 and 2001 are shown as examples:

exten => 2000,1,Answer
exten => 2000,2,Set(DB(LastCallFrom/${EXTEN})=${CALLERID(num)})
exten => 2000,3,Set(DB(LastCallTime/${EXTEN})=${STRFTIME(${EPOCH},,%s)})
exten => 2000,4,Dial(SIP/200,30,toj)
 
exten => 2001,1,Answer
exten => 2001,2,Set(DB(LastCallFrom/${EXTEN})=${CALLERID(num)})
exten => 2001,3,Set(DB(LastCallTime/${EXTEN})=${STRFTIME(${EPOCH},,%s)})
exten => 2001,4,Dial(IAX2/201,30,toj)

The playback code is fairly straight forward:

exten => 1471,1,Answer
exten => 1471,2,Set(last=${DB(LastCallFrom/${CALLERID(num)})})
exten => 1471,3,Playback(last-num-to-call)
exten => 1471,4,SayNumber(${last})
exten => 1471,5,Playback(on)
exten => 1471,6,Set(dtime=${DB(LastCallTime/${CALLERID(num)})})
exten => 1471,7,SayUnixTime(${dtime})
exten => 1471,8,Wait(2)
exten => 1471,9,Hangup

Items to note:

  • Correct use of the Macro command would improve this a lot, so by creating something like DialCID and using that in place of Dial would make it trivial to use for all extensions
  • I have not tested this with Witheld or Blocked numbers and would expect that the SayNumber line would just say "Zero", so adding some conditional testing in there would make things nicer (test for zero CID)
  • I have not tested this for the case when no call has been received before for an extension: I would assume it’s another "Zero" response, but again, more conditionals in the 1471 section would make that nicer (test for zero date)
  • I find the date pronunciation quite offensive, as I am not currently in the year "two thousand seven" but "two thousand and seven" – there are options to SayUnixTime that I have yet to investigate
  • I haven’t implemented the "Press 1 to return this call" voice prompt that BT have

Feel free to correct these oversights in the comments – if things get optimised a lot I’ll post an update with the best/most feature complete version.

Nokia N770, Asterisk and Google Talk

I’ve wanted to get a VoIP application working on my N770 pretty much since day 1: the trouble is I’m rather picky…

I want to be able to use it without pain from any WiFi point I happen to find myself at and I can’t use the N800 version of Skype, but that’s fine by me as I want to have some control over my datastream. It does however pretty much rule out most SIP-based solutions, as one-way audio is the best to hope for without control of NAT port forwarding (and that isn’t something hotels/coffee shops are going to have much truck with).

I would like to be able to use it for free for pure VoIP calls, but would also like the option of paying not-silly prices for real landline interconnects, and for extra points voicemail and multiple country phone network numbers would be a huge advantage (so callers get to choose the cheapest way to talk to me).

The biggest point, though, is that my family must have a really, really simple way of keeping in touch with me as work-related overseas travel is looking more and more likely (after a delightful five year hiatus). Yes, I could ssh-tunnel SIP, but making lossy UDP channels into TCP ones is a lesson in pain waiting to happen, but equally it’s not something I expect anyone else in my family would want to setup just to be able to chat for 3 or 4 minutes.

I have the 2007HE OS on the N770 (as the original 2006 is just painful) so Google Talk is integrated very nicely, but unfortunately, even after sharing board members between Apple and Google there’s still no voice support for GTalk in iChat 🙁 In fact, unless you have Windows, forget Google Talk – and that’s a very annoying thing to have to do.

I’ve tried using the rather intriguing GTalk 2 Voip service but have had problems getting the system to work for more than just a ringing tone, and although I have a real UK number for my home SIP phone, I didn’t want to have to pay to call it just for testing, although by all accounts that aspect should work fairly well. The next stop was the Gizmo Project for the N770, but that isn’t 100% stable (could be the 2007HE, of course) and again suffered from not wanting to do more than ring my other phone, or create one-way audio channels.

Finally, I took the obvious course of action: installing Asterisk 1.4 beta on my Qube 2, giving it it’s own Google email address and configuring the GTalk<>SIP gateway… Bam: working two way calling !

There are some downsides: I can’t seem to get the basic Asterisk installation to talk via text with me (I need to investigate some primitive AGI bot) so I can only initiate a GTalk voice call to the Qube, at which point I can only create a call to a specific SIP device as I have no way of sending DTMF data via the native N770 Google Talk client. This isn’t so bad for my immediate use as I can simply create as many Google Accounts as I require outgoing call destination, and considering that I can’t bridge to my own home land line (yet), that means having an account with an external provider setup to pay for the UK leg, so it’s of limited use. I only really need to call two main numbers when away for work anyway, and one of those is a SIP destination which works very nicely directly from Asterisk. I have also setup the Asterisk box to login into Sipgate in order to have a UK landline for the box, which I can then easily forward to GTalk or bounce to Voicemail.

Or so I thought, until I wandered over to my neighbour to get his Asterisk talking IAX2 to mine, and found that my N770 would ring when on his LAN, but not get any further. Some asterisk -vvvvv sessions later (yup, logged into my Asterisk box via ssh from the N770, of course !) and it turns out that Asterisk is sending packets out to GTalk with the main WAN IP of the box, and then the LAN IP and alternating during the call setup. Very odd, but a few vi edits later (yup, still via the N770: it’s getting mighty masochistic at this point) and all of the relevant binaddr lines have been changed from 0.0.0.0 to just specify the WAN IP. Hooray.

Except it’s still alternating WAN and LAN in the GTalk packets. Hmm. Poking around in the channel/chan_gtalk.c file proved to be very worthwhile though, as at like 762 (Asterisk 1.4.11) there’s the following comment:

/* XXX We should really stun for this one not just go with externip XXX */

To which my only response is “Yes, you should”. Adding in a line just before the if statement along the lines of:

sprintf(externip,"1.2.3.4");

(but with my WAN IP) and voila – working calls !

As this is beta software I fully expect the STUN issue to be resolved in time, but for now I have a UK number which can be called from my home SIP phone for free (or the main landline at reasonable rates – 5.5p/hr evenings and weekends) that rings my N770 whenever it’s logged into GTalk. I have tried a couple of access points that are the standard ‘home NAT’ setup and it works just fine with two way audio, and the separation of the speaker and mic on the N770 is so well done that conversations are far less of a problem than my normal phone in speakerphone mode. I have had some reports of slight clipping at the start of a sentence, so maybe my silence suppression needs a look, but changing the angle I spoke into the N770 was enough to get by for that call.