Asterisk PBX
-
@dkf said in Asterisk PBX:
@onyx said in Asterisk PBX:
T-Scum
It could be worse. It could be Vodafuck.
There's also O2Offline.
-
Hokay, since I had to poke around this particular hornet's nest again due to "who the fuck even approved this?" client request I remembered how stupid it is. Rant time!
First of all, I have to point out that Asterisk was not designed as a SIP PBX specifically. It was instead designed as a PBX that can (with additional hardware, where needed) handle everything from POTS and ISDN to craziness like H323, MGCP, SCCP and every other way to transfer voice over a wire in an overly complicated way you can think of. SIP support is just one module out of many that you can use.
For years, the only way to connect SIP to Asterisk was its, in-house developed,
chan_sip
module. It worked, but just barely. Not that it crashed or anything, but it didn't support the entirety of SIP either (hell, rich presence doesn't work at all to this day without extra fuckery). One of the most glaring omissions was an ability to use multiple devices on a single endpoint (think having the same phone number on your desk phone, a SIP client on your PC, and you also connect your mobile phone to it). Enter PJSIP, an open source library which is much more flexible (and is probably used in most SIP clients these days) which someone wrapped into an Asterisk module. Modern features, yay!Now, since Asterisk is an "universal" PBX, it's not well equipped for something like this. To make the problem clear, let's go with an example. Let's say you have an extension whose phone number is
100
. To make a call to it you'd do this in your dialplan:Dial(technology/100,more,options,here)
- wheretechnology
is basically the protocol you're using, so for POTS and ISDN it would beDAHDI/100
, for oldchan_sip
it would beSIP/100
. The other options are things like how long to ring the phone or a piece of code to execute when the phone is picked up etc. So, with PJSIP, in its simplest form, you'd writeDial(PSJIP/100)
. The phone rings, everyone's happy. Yay.Now you want to connect your mobile phone to PBX (either using a third party SIP client, or, for example, Android's built-in SIP client). You set PJSIP up to allow multiple contacts per endpoint, you can make calls from both of them, cool. But here's the problem: calling both of those phones. See, Asterisk has no concept of multiple contacts per endpoint.
Dial
cannot cope. If you try to just do it naively Asterisk will just call whichever contact registered last. But, fear not, there's a solution! You can parallel dial in Asterisk. Basically, you just list multiple contacts to call and separate them with an&
. So, you can do something like:Dial(technology/100&technology/101&technology/102)
to simultaneously ring phones100
,101
and102
. They don't even have to be on the same tech stack. Sweet!So, in this case you can do something like:
Dial(PJSIP/100@192.168.1.14&PJSIP/100@10.0.0.43)
and there you go! It's usually a bit more complicated than that since every contact tends to have a unique tag at the end so it can be identified as it changes IP addresses etc. But there's a handy function calledPJSIP_DIAL_CONTACTS
that will generate this mess for you, so all you do is:Dial(${PJSIP_DIAL_CONTACTS(100)})
and bam! It works! Yay!Ok, so, why this huge wall'o'text? Because now you can finally understand why the following hackery is needed. It's queues. It's always fucking queues. See, the
Queue
application internally just calls an equivalent ofDial
. So, if you addPJSIP/100
to a queue, it will just do aDial(PJSIP/100)
internally, meaning only one of the phones will ring. Which is no good. You can't tell it what to run instead, so, you're boned.Time for hackery! See, Asterisk has one more type of channel, one that doesn't rely on any other technology. A
Local
channel. It's something Asterisk can manipulate internally and can come in handy at times. So, here's the plan. First, we create a context for our agents in queue:context queue-agents { _X. => { Dial(${PJSIP_DIAL_CONTACTS(${EXTEN})}); } }
_X.
means this will execute as long as you call anything starting with a digit in that context. TheEXTEN
variable is usually whatever the user dialed, but in this particular case it will be theQueue
application dialing it. The principle is the same. So, we add this to our queue instead:queue add member Local/100@queue-agents/n to MyQueue
- where/n
part means "automatically answer all requests". Because of course that's what/n
means, what are you, stupid?But, damn it, now it's always available. Because
Local
channels always are. Ok, ok, we can do something about that, we'll force it to use the state of the endpoint instead:queue add member Local/100@queue-agents/n to MyQueue as 100 penalty 0 state_interface hint:PJSIP/100
Now, that's not confusing, right? Oh, yeah, you have to give it an alias and a penalty even if you don't care, because the parser is an idiot and requires all the arguments in that order, and you can't skip any, EVEN THOUGH THEY ARE NAMED. And
hint:PJSIP/100
means "report the state ofPJSIP/100
instead of the local channel". And this is, BTW, documented exactly nowhere, I lucked out on finding the example of this in some unrelated piece of code somewhere online. I have no idea how that poor soul figured that out, but I salute them as I drink myself into a coma. And for both of you smartasses who are about to say I should just useAddQueueMember
application from the dialplan and just pass empty parameters for those I don't care about, shush, I'm ranting!Now you're like, Onyx, you fuck, I read this wall of text and the amount of ery wasn't worth it! I want my internetpointzzz back! Hold your disco horses, now we're going into what this shit does internally.
So, say someone calls in to your queue. Your phone rings and you answer. What happens internally?
- A channel for the caller is created, called something like
PJSIP/providername-randomgibberish
- A local channel is created, called something like
Local/100@queue-agents-otherrandomgibberish;1
- Another local channel is created, called something like
Local/100@queue-agents-otherrandomgibberish;2
- A channel for the callee is created, called something like
PJSIP/100-differentothergibberish
- Caller is bridged to one of the local channels, let's say
Local/100@queue-agents-otherrandomgibberish;1
- Caller is bridged to one of the local channels, let's say
Local/100@queue-agents-otherrandomgibberish;2
- A local bridge is created between
Local/100@queue-agents-otherrandomgibberish;1
andLocal/100@queue-agents-otherrandomgibberish;2
- You are now sorry you answered the call because the caller is a prick
So yeah, two extra channels are made, just so they can be bridged together. Fun. I mean, it works, it's not the worst thing in the world. But then you're trying to figure out who the fuck is talking to whom in realtime, just sniffing Asterisk's
asstelnet output and you scratch your fucking head. "Regular" bridges haveBridgeCreate
,BridgeEnter
andBridgeLeave
events. And every bridge has a unique ID, so you can easily identify it and track it. Local bridges just pop out of nowhere. They have no unique ID, because fuck you. But you still need to track them and hop over them just to figure out who's on the other side of the call.And I had to reverse engineer and figure out most of this shit on my own. Maybe that's why I'm angry and this is not so bad? Dunno. You tell me.
- A channel for the caller is created, called something like
-
@onyx I can tell you I got about halfway through that before saying "Fuck this." (Yes, I did continue through to the end.)
Is the reason people use this that it's free/OSS? Is that really it? Or is there no viable competitor in the field? Because fuck that.
-
@heterodox said in Asterisk PBX:
Is the reason people use this that it's free/OSS? Is that really it?
Pretty much. Also, most commercial offerings are locked down and have shitty APIs, so if their GUI doesn't let you change stuff, tough shit (note: I'm mostly buttuming here because I'm unaware of many people doing complex integrations, and most of them won't let you even see the API docs without buying a licence so I can't really even read it to get a feel for it).
@heterodox said in Asterisk PBX:
Or is there no viable competitor in the field?
I'm hearing good things about FreeSwitch. Sadly, we have no time to spare on researching if we should switch stacks, hopefully we will manage to allocate some resources to that come Autumn.
@heterodox said in Asterisk PBX:
Because fuck that.
To be fair, some of the shit is just inherent to the whole telephony thing in general. But they also fucked up some implementation details to be sure.
-
@onyx Thanks for convincing me to stay doing sane things. Like fixing bugs in implementations of badly-written TLS RFCs.