Asterisk version 12 introduced a number of changes both in its internals and the various control APIs. While these changes were important, they also were not backward compatible (and this is a good thing). Since Asterisk 13, the Long Term Support release, was made in October of last year, we’ve been looking at what it would take to get Adhearsion to support Asterisk 13, while retaining support for Asterisk 11. This post addresses the changes we made to reach that goal.
The most relevant changes as far as Adhearsion is involved are the revamped bridging core and the AMI v2 specification, which for the most part removes sub-event types from AMI messages.
Other important new parts include a PJSIP channel type and the ARI REST interface, based on the new StasisCore.
You can find more information on the changes in the following documents:
– New in 12 Asterisk wiki page
– AMI v2 Specification
– CHANGES for Asterisk 12
– UPGRADE.txt for Asterisk 12
Asterisk 13 is the long term support version, incorporating changes from 12 with more fixes and upgrades.
We based our Adhearsion upgrade on Asterisk 13 to ensure long-term compatibility.
Adhearsion and Asterisk 13
Adhearsion interacts with Asterisk through the Punchblock translator, so most changes that we will discuss were actually done at that level. Punchblock uses AsyncAGI to grab control of a call using the Asterisk Manager Interface (AMI), which sends Events and accepts Commands. The problem was that the SubEvent change mentioned above caused our AMI parser to not recognize certain Asterisk 13 events.
How we solved it
The AMI v2 specifications has three major areas which had to be addressed to have basic translator functionality work on Asterisk 13:
– AsyncAGI
events, which used to have a subtype, now are separate (AsyncAGIStart
, AsyncAGIExec
, etc.)
– DTMF
events went through the same change, and were replaced by DTMFStart
and DTMFEnd
events
– Bridging was entirely redone and warrants its own discussion
We wanted to make sure Punchblock supported both Asterisk 11 and 13, and were helped by the extensive test coverage that we built over the course of the years. I cannot stress enough how having a comprehensive suite of tests is essential to ensuring quality code that can be trusted as a foundation to build complex applications. It gives us much more confidence when making these types of changes that what was working before, still works after we finish the upgrade.
Events have no subtype any more
The AsyncAGI
family of events is used by Punchblock to acquire control of a call and manage the lifecycle of commands it sends.
The compatibility work here mostly involved using has_guarded_handlers‘s’ excellent support for specifying complex conditions on an event handler.
Since the events themselves are not different, that is all that is needed to grab a call on AsyncAGIStart
or receive confirmation for a command from AsyncAGIExec
.
register_tmp_handler :ami, [{name: 'AsyncAGI', [:[], 'SubEvent'] => 'Exec'}, {name: 'AsyncAGIExec'}], [{[:[], 'CommandID'] => agi.id}, {[:[], 'CommandId'] => agi.id}] # ...
The same changes allow us to handle DTMFEnd
events that replaced DTMF
with a End
subtype.
Wait, that did not work.
The first iteration through the above changes caught us by surprise, since everything looked to be in its place but command confirmations were not being received correctly.
After a short investigation, we found a minor but very important difference that is worth noting: the CommandID
field in an AMI event used to be spelled with a final capital D
, and that syntax had a few inconsistencies too. From Asterisk 12 onwards, the field is consistently spelled as CommandId
.
The new bridging model
AsyncAGI and DTMF events only required a different handler syntax but still have the same payload.
Asterisk 13 handles bridging in an entirely different way than previous versions.
The new bridge lifecycle involves the following events:
– BridgeCreate
when channels are about to enter a bridge
– BridgeEnter
when a channel is put in a bridge
– BridgeLeave
when a channel leaves a bridge
– BridgeDestroy
when a bridge ceases existing
All events are always emitted and Asterisk 12 makes sure they are in the correct order. A lot of work has been put into making the bridging interface deterministic and simple to parse (and thanks to the Asterisk development team for that!).
That said, we ran into one major problem.
The old bridging event model uses entirely different messages, BridgeExec
to signal that a Bridge
command has been acknowledged, and the Bridge
event subtypes to indicate that channels have been joined or unjoined.
The Asterisk 11 model is in general a bit cumbersome, but it does have an advantage, which is that it passes in the names of both channels that have participated in a join.
On Asterisk 12 and up, each event only relates to its own channel. That results in us having to track the bridge creation and destruction to figure out which call got joined to another.
That is done by considering the first BridgeEnter
and BridgeLeave
for a specific BridgeId
as the creation event, then using the second to count the latch up or down and sending the correct Joined
or Unjoined
events to calls.
After solving that, though, the new events provide a more reliable way to follow calls and make sure they are all kept in the correct state.
More to follow!
The above concludes the first batch of work on Asterisk 13 compatibility, without introducing new functionality. However, Asterisk 13 does expose some new and interesting AMI commands that we plan to use to build a better translator layer in Punchblock.
Some of those functions are:
– MixMonitor
now has an option to automatically play a beep before starting to record. It does also not need flags to be set to record both legs of a bridge.
– ControlPlayback
is a new command that allows for stopping, rewinding and seeking playback of an audio file. Adhearsion currently relies on stopping output by redirecting a channel to a special context that is added programmatically.
– BridgeWait
is similar in function to call parking, but it is cleaner to use for general channel handling and initial call setup.
Conclusions
Adhearsion and Punchblock are ready now to be used with Asterisk 13, and soon there will be more and better functionality available.
Stay tuned for more updates soon!
The post Making Adhearsion Compatible with Asterisk 13 appeared first on Mojo Lingo.