Tag Archives: asterisk

Recording Accurate CDRs

If you’re serious about your call data records – because you’re billing customers, or because you want to automatically reconcile calls against your invoice – then they’d better be accurate.

An easy win here is to normalise the numbers you call. In South Australia, a number listed as “(08) 5550 1234″ can be dialled as either 0855501234 or 55501234 – the “08″ prefix is optional, since it merely clarifies the area code.

Since you don’t want to have to reconcile against both forms (that just makes things messy), let’s clean it up so it always appears with the leading ’08′:

;; Handle 08XXXXXXXX calls by default, as this is our "native" area code here in SA.
exten => _XXXXXXXX,1,Goto(08${EXTEN},1)

Easily done.

Another common issue is to ‘answer’ an outbound call (either explictly with Answer() or implicitly with something like Playback()) before actually dialling. Answering the call too early means your billsec – which you’re potentially basing your customer billing on – is higher than it should be!

If you want to play a message back to the caller before the call itself is made, use Progress() to indicate that you’re doing it as the call progresses, and that the call isn’t actually connected yet.

A final example is much less common – when dialling one number actually calls another; you have several options available with different tradeoffs. For this example, pretend that the PSTN-looking number 0855501234 should actually be delivered to the VoIP-looking number 0870101234. (Maybe it’s a cheaper internal-use-only equivalent number, and people forget to use it?)

This example will have your CDR showing the original number (the PSTN number that was dialled, rather than the number that was actually called). It assumes your upstream SIP provider is named vsp1


exten => 0855501234,1,Dial(SIP/0870101234@vsp1)

This example will have your CDR showing the number that was really called, not the number dialled:


exten => 0855501234,1,Goto(0870101234,1)

The following will have a mix of the two – a CDR for 0870101234 for the ringing, and a CDR for 0855501234 covering the ringing and the billable call. This assumes regular_outbound is your context for outbound calls.

exten => 0855501234,n,Dial(LOCAL/0870101234@regular_outbound)

So, that’s a few easy ways to make sure that your CDRs are actually worth the bits they’re saved with.

Asterisk – Using CallerID to make decisions

CallerID information is carried along quite readily within the SIP protocol; most SIP providers pass that along to their customers for free. Other than just showing it as “This is the number the call is coming from”, can we do something more useful?

Absolutely!

As an example, imagine the contexts incoming (where calls go to when they come in to Asterisk from a SIP provider) and outgoing (which allows outbound calls from internal phones). There’s also an internal context to allow calls between internal phones.

[internal]
exten => s,1,WaitForExten

;Internal extensions
exten => 1000,1,Dial(SIP/alice)
exten => 1001,1,Dial(SIP/bob)
exten => 1002,1,Dial(SIP/charlie)
exten => 1003,1,Dial(SIP/jack)

[outgoing]
include => internal
;External calls
exten => _XX.,1,Dial(SIP/${EXTEN}@voipprovider)

[incoming]
; Incoming calls go to Alice, our receptionist
exten => s,1,Dial(SIP/alice)

Let’s add in an override for when an employee rings in from their mobile phone – instead of having to talk to Alice, they get put back into the internal context, so they get to directly dial an extension.

Within the incoming context, add:

exten => s/0491570156,1,Playback(please-enter-the)
exten => s/0491570156,n,Playback(number)
exten => s/0491570156,n,Goto(internal)

We can make it a bit better yet. Let’s allow another employee’s mobile phone in, and let’s share the config by moving them to a different context. We can also reuse parts of the dialplan in the new context by only using the CallerID information to override the first part of the sequence.

[incoming]
exten => s/0491570156,1,Goto(employeemobiles)
exten => s/0491570157,1,Goto(employeemobiles)
exten => s/0491570158,1,Goto(employeemobiles)
[employeemobiles]
exten => s/0491570156,1,Set(CDR(accountcode)=alice)
exten => s/0491570157,1,Set(CDR(accountcode)=bob)
exten => s/0491570158,1,Set(CDR(accountcode)=charlie)
exten => s,2,Background(please-enter-the)
exten => s,3,Background(number)
exten => s,4,WaitForExten
include => internal

Note the accountcode being set – this way, you can readily choose to allow outgoing calls from your PABX for remote employees – and it all gets tracked separately (per employee) in your call data records.

You can also just as easily use include => outgoing so that calls in from the mobiles can make calls back out to any other number (eg. if you have great international rates from your PABX, or free calls to certain numbers).

Asterisk – Specifying outbound routes for fun and profit

…or at least a little savings.

You’re in a quandry. You’ve found VSP1, with brilliant general rates. VSP2 has fantastic rates for mobile calls. VSP3 has the cheapest calls of all to England, where you have family. You can’t use just the best bits of each… can you?

With Asterisk, yes you can!

The extension configs here assume that you’ve set up your VSP peers already as vsp1, vsp2, and vsp3.

Starting with your usual outbound context:

[regular_outbound]
; Handle calls out
exten => _XX.,1,Dial(SIP/${EXTEN}@vsp1,,)
;

Add in some new patterns for the different call types. (0011 is the code to dial an international number from Australia, 44 is the UK “country code”, and 04 is the prefix for all mobile phones, which are always ten digits).

[regular_outbound]
; Mobiles go via VSP2
exten => _04XXXXXXXX,1,Dial(SIP/${EXTEN}@vsp2,,)
; UK numbers via VSP3
exten => _001144.,1,Dial(SIP/${EXTEN}@vsp3,,)
; Handle all other calls out
exten => _XX.,1,Dial(SIP/${EXTEN}@vsp1,,)
;

After some time, you find out that VSP3 isn’t terribly reliable. Rather than just disallow the call at all, instead let’s use VSP1 as a fallback.

Instead of:

; UK numbers via VSP3
exten => _001144.,1,Dial(SIP/${EXTEN}@vsp3,,)
;

Do:

; UK numbers via VSP3, fallback to VSP1
exten => _001144.,1,Dial(SIP/${EXTEN}@vsp3,,)
exten => _001144.,2,Dial(SIP/${EXTEN}@vsp1,,)
;

If the first Dial() statement succeeds, the dialplan execution will not continue. If it fails, the next statement will execute, thus running the second Dial() via VSP1. (This functionality is more commonly used to implement line hunting, or to redirect to voicemail on busy and no-answer).

Note that in some cases, the call may actually happen twice – if the remote end is genuinely busy, for instance. You can check the contents of ${DIALSTATUS} and only redirect in some cases – but then you might not fall through if VSP3 incorrectly gives you a busy tone instead of ringing!

Asterisk – Email notifications

One of the things I like about Asterisk, is its ability to send email notifications to me if certain things happen. There’s no built-in ability to send emails by itself, so we’ll use its integration with the underlying server to do it.

Let’s start by sending me an email if someone uses my VoIP line to make an international call. In Australia, all international calls are prefixed with “0011″…

[regular_outbound]
; Email me for international calls
exten => _0011.,1,System(mail -s "International Call to ${EXTEN}" example@mibus.org < /home/mibus/Documents/international-call.msg)
exten => _0011.,n,Dial(SIP/${EXTEN}@nodephone,,)
; Handle other calls out
exten => _XX.,1,Dial(SIP/${EXTEN}@nodephone,,)
;

Note that the subject is InternationalCall, the destination email address is example@mibus.org, and the body of the email comes from a file I’ve already saved to /home/mibus/Documents/international-call.msg. From now on, I’ll know whenever an expensive international call is made.

A rarely-used feature of extensions.conf is the built-in h extension. Let’s use that (inside whatever context rings your real internal phone) to let us know by email when we’ve missed a call for any reason. For example, if my phone is rung on extension 99…

exten => 99,1,NoOp(Inbound)
exten => 99,n,Dial(SIP/myphone,30,)
exten => 99,n,Hangup()

exten => h,1,GotoIf($["${DIALSTATUS}" = "ANSWER"]?done)
exten => h,n,System(mail -s "Missed Call From ${CALLERID(num)}" example@mibus.org < /home/mibus/Documents/missed-call.msg)
exten => h,n(done),NoOp()
;

Note that I’m specifically using only the number component of the Caller-ID – if your VSP supports sending textual Caller-ID alongside it, it means that random foreign callers can alter your System() call!

Asterisk – Dual-dialling to save money

Asterisk saves me money, even using just the one VoIP provider. (Disclaimer: The provider I use is run by my employer, but I’m writing this only as a happy customer! :).

It just so happens that my work desk phone number is a free call, but my wife can never remember the number and is usually in too much of a hurry to stop and think about whether I’m at my desk yet etc. etc. (We have lots of small kids – I’m surprised I have time to write this post :). My VoIP provider (nodephone) also happens to allow two concurrent calls by default… let’s see what fun we can have with that?

My outgoing context used to look a bit like this:

[frominside]
exten => _XX.,1,Dial(SIP/${EXTEN}@nodephone,,)
;

What I wanted, was to automatically ring my desk phone whenever I was likely to be at it. Just in case I wasn’t, ring my mobile phone at the same time – let me answer whichever I choose.

Move the contents of the frominside context into a new context regular_outbound, and use an include to keep it all working the same…

[frominside]
include => regular_outbound

[regular_outbound]
exten => _XX.,1,Dial(SIP/${EXTEN}@nodephone,,)
;

Next, make a new context that will dual-dial when you call my mobile number. (No, those aren’t real phone numbers, they’re dummy numbers from ACMA). Include it at the top of the frominside context, and limit it to a “safe” set of working hours.

[frominside]
include => mibus_at_work|08:15-16:45|mon-fri|*|*
include => regular_outbound

[regular_outbound]
exten => _XX.,1,Dial(SIP/${EXTEN}@nodephone,,)

[mibus_at_work]
exten => 0491570156,1,Wait(1)
exten => 0491570156,n,Playback(hang-on-a-second)
exten => 0491570156,n,Set(LIMIT_WARNING_FILE=beep)
exten => 0491570156,n,Dial(SIP/${EXTEN}@nodephone&SIP/0855501234@nodephone,,)
;

Done! Now, trying to ring 0491570156 will also ring 0855501234. They’re charged at vastly different rates, so if I can, I’ll answer on the “cheaper” one. If not, it’ll ring my mobile phone anyway – just as it always would have.

Asterisk – Database-driven CallerID

One of the nice things Asterisk can do is manipulate Caller ID information on the fly. Since I’m too lazy to update the stored numbers within my individual cordless handsets, I use Asterisk to cheat. Asterisk looks up the incoming phone number (“08XXXXXXXX”) in a MySQL table, finds matching text (“Bob”) and passes that along to the handsets for display.

This assumes you have a MySQL database on the same box as asterisk, with a username of asterisk, password of mypassword, your database is called asterisk, and your final internal destination is SIP/myphone. (I’m inventive, I am… ;). Extension 99 in this example is where your inbound calls end up in order to ring your phone.

exten => 99,1,NoOp(Inbound)
exten => 99,n,MYSQL(Connect connid localhost asterisk mypassword asterisk)
exten => 99,n,GotoIf($["${connid}" = ""]?nodb)
exten => 99,n,MYSQL(Query resultid ${connid} SELECT\ name\ FROM\ addressbook\ WHERE\ phone_number="${CALLERID(num)}"\ LIMIT\ 1)
exten => 99,n,MYSQL(Fetch fetchid ${resultid} name)
exten => 99,n,MYSQL(Clear ${resultid})
exten => 99,n,Set(CALLERID(name)=${name})
exten => 99,n,MYSQL(Disconnect ${connid})
exten => 99,n(nodb),NoOp(DoneDB)
exten => 99,n,Dial(SIP/myphone,30,)
exten => 99,n,Congestion()

To actually make it work, you also need the database filled in.

CREATE TABLE addressbook (
    phone_number VARCHAR(40),
    name VARCHAR(40),
    PRIMARY KEY(phone_number)
);
INSERT INTO addressbook VALUES ('08XXXXXXX1', 'Bob');
INSERT INTO addressbook VALUES ('08XXXXXXX2', 'Mary');

(and so forth).

So, what next? Well, you’re logging your CDR into MySQL, right? Let’s make a ‘view’ of the CDR that includes the names:

CREATE VIEW cdr_with_names AS
    SELECT cdr.*,ab_src.name AS src_name,ab_dst.name AS dst_name
    FROM cdr
    LEFT JOIN addressbook ab_src
        ON ((cdr.src = ab_src.phone_number)
        OR (CONCAT('08',cdr.src) = ab_src.phone_number))
    LEFT JOIN addressbook ab_dst
        ON ((cdr.dst = ab_dst.phone_number)
        OR (CONCAT('08',cdr.dst) = ab_dst.phone_number))
;

What’s this CONCAT('08',cdr.src) stuff? ’08′ is my local area code, and I can leave it off outbound calls to the same area code if I so choose. This way, my query finds both variants (‘XXXXXXXX’ and ’08XXXXXXXX’).

It’s such a messy view for direct use, though. Let’s clean it up with a view that only shows us the columns we really care that much about:

CREATE VIEW cdr_easy AS SELECT calldate,src,src_name,dst,dst_name,disposition,billsec FROM cdr_with_names

In a few minutes of hacking at extensions.conf and MySQL, you now have database-driven CallerID text and a straightforward CDR view that includes human-readable names. What can’t Asterisk do?

Asterisk – Adding Game

A quick adding game for Asterisk.

Set up an extension (I used “4263″) to Goto(game,s,1). It will speak two numbers from 1-8, and expects a single key to be pressed for the sum of those two numbers. I’ve only used fairly standard sounds, so there’s no recording involved.

Hoping that my five-year-old enjoys this :)

[game]
exten => s,1,NoOp(GameSTART)
exten => s,n,Set(num1=${RAND(1,8)});
exten => s,n,Set(maxnum2=$[9-${num1}])
exten => s,n,Set(num2=${RAND(1,${maxnum2})})
exten => s,n,Set(total=$[${num1}+${num2}])
exten => s,n(quest),SayNumber(${num1})
exten => s,n,Playback(letters/plus)
exten => s,n,SayNumber(${num2})
exten => s,n,WaitExten

exten => _X,1,NoOp(GameHazDigits)
exten => _X,n,GotoIf($[${EXTEN} = ${total}]?GotItRight)
exten => _X,n(GotItWrong),NoOp(Awww)
exten => _X,n,Playback(privacy-incorrect)
exten => _X,n,Playback(pls-try-again)
exten => _X,n,Goto(s,quest)
exten => _X,n(GotItRight),NoOp(YAY)
exten => _X,n,Playback(yes-dear2)
exten => _X,n,Goto(s,1)

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

You have a PABX at home? Why!?

When I mention to someone that I have a PABX at home, people always ask me – WHY???

Early Media – this is a fancy way of saying that when someone calls me it doesn’t just go “ring ring” – I have it going “rrrrrinngggggg rrrrrrinnnngggg” like an old-school telephone. I’ve considered having cackling monkeys, but I don’t want to confuse people too much.

Free Calls Home – Anywhere I have full Internet access (like at an Internode CityLan hotspot ;) I can connect to the PABX and call the “extension” that rings my home phone. End result, free calls.

Call Announcements – I [can] have announcements for how much a call will cost, or minutely beeps to remind you that you’re on a timed call. Great for keeping the bills down!

Simultaneous Ring – Calling my mobile phone, in hours that I’ve decided I’m likely to be at my desk at work, will actually ring my mobile and my desk phone. Whichever I pick up first, ‘gets’ the call. End result, cheaper (or in this case, free) calls, without having to call multiple numbers by hand.

Automated Outbound Calls – If I can’t get hold of Missy (my darling wife who has had to put up with all this tinkering ;), I can have the phone system repeatedly call the home phone until it’s picked up. (Say, every 15 minutes). Once answered, it will play a pre-recorded message (eg. I’m running late and my mobile phone battery is about to die).

Direct Peering – Some friends of ours don’t have VoIP, but do have a VoIP-capable ATA. So, we’ve hooked them in to our PABX much like they normally would a fully-fledged VoIP provider. A quick “calls to this prefix go via VoIP” dialplan later, and we can have free calls between our house phones. This is particularly awesome when using the Siemens C470IP Gigaset that we have – it can do multiple SIP providers, using dialplans to choose which to send a call through.

Calling Card Functionality – I can configure my phone to accept incoming calls from certain numbers, and do different things with them. An example of that, is placing incoming calls from a family member into a part of the PABX that allows outbound calls. End result, a family member makes a local call to me, then can take advantage of the good international call rates I get by using VoIP – without all the hassle with ADSL and ATAs. A variation of this would be to put “normal” outbound calls through a PIN checker, so you could isolate users within your house (and allow through family and emergency numbers directly).

External Notification – I have certain calls also have other events attached – eg., I get sent an email, IM, and SMS if anyone calls 000. No, I don’t rely on my cordless phone, VoIP, and PABX for all emergency calls. We have a corded handset by a spare phone jack for “just in case”.

But the #1 reason…

Because I can – I’m a giant bloody geek, with a server and a DSL connection. What do you expect? :)