[asterisk-app-dev] WebSocket Stasis Control Best Practice

Matthew Jordan mjordan at digium.com
Mon Jun 16 09:12:24 CDT 2014


On Mon, Jun 16, 2014 at 7:42 AM, Ben Merrills <b.merrills at mersontech.co.uk>
wrote:

> We had a similar discussion a while back about executing dialplan
> applications from within ARI. Please see:
> http://lists.digium.com/pipermail/asterisk-app-dev/2014-February/000367.html
>
> Although this doesn't provide you with an answer, it may help you to
> understand the current thinking of the asterisk/ari development team
>
>
I'm going to chime in again on this topic, because I do think that this is
one of the hardest points to grasp with the new interface.

To begin, it's important to understand how dialplan execution works within
Asterisk. When a channel is executing dialplan, a dedicated thread - the
pbx_thread - "owns" the channel. It is responsible for a variety of things:
understanding the location of the channel in the dialplan stack, servicing
frames from the channel in a timely fashion, running each application, and
more. The pbx_thread is the thread that services the channel.

With AGI, you are performing remote execution of dialplan. Hence, executing
any dialplan application from your AGI is completely within the scope of
that interface. The pbx_thread is still the owner in this case - it just
happens to be waiting for your command from the AGI. When it gets said
command, it goes off and executes the dialplan just as if it were walking
through statements in extensions.conf. There's a key point here however -
while it is off executing dialplan, your AGI can't do anything with the
channel. It doesn't own the channel - it merely gets to instruct the
pbx_thread what to go do. If, for example, you sent said channel off into
VoiceMail and then decided you wanted instead to Playback howler monkeys to
the channel, you couldn't do that: the pbx_thread is off on its mission,
and can't be interrupted.

With AMI, you don't really own channels - nor can you do much with them.
There's really only two operations that affect the state of a channel -
Redirect and Bridge. In the case of Redirect, you are "simply" moving a
channel to a new location in the dialplan. Again, a pbx_thread still owns
the channel - even when this occurs. With Bridge, you are doing something a
bit more creative: both channels are stolen from their pbx_thread and
shoved into a bridge. Now, of course, there is a slight problem - what
happens when those channels leave the bridge? Unless AMI uses redirect on
the channels from the bridge it created for them, there's no place for them
to go - the threads that serviced them are long gone, and they don't have
anywhere to return. They get hung up.

Contrasting both of these interfaces with ARI, there's two key differences:
(1) In AGI and AMI, you are constrained by the dialplan. This is not a
terrible thing - dialplan is, after all, very powerful. But dialplan
applications are an abstraction over Asterisk's core resources, and often
they don't expose exactly what you want to do - or you have to do some
strange machinations to get them to do what you want.
(2) AGI (in particular) and AMI (to a lesser extent) are channel based.
While channels are still the most powerful construct in Asterisk, there are
other resources - such as bridges and endpoints - that can also be
manipulated - and typically are by dialplan applications.

ARI seeks an alternative path: get the channel out of the dialplan and hand
it over to something external. Because we remove the dialplan from the
equation, we can let something external asynchronously control the channel
as well as bridges, endpoints, and other things.

As an example, take the Bridge AMI action and an equivalent operation in
ARI.

When you execute Bridge in AMI in Asterisk 12, the following is what
actually occurs:
(1) Create a new bridge.
(2) Find the first channel. If the channel is in a bridge, perform a bridge
move operation. If the channel is not in a bridge, panic and do the
following:
(2a) Issue an ast_channel_yank on the channel. This will (carefully)
perform a masquerade: a new channel is created, the private data structure
is taken from the existing channel and moved to the new channel, and the
existing channel is hung up in a silent fashion. This is done to 'steal'
the channel from the running pbx_thread.
(2b) Take the new channel - which we now own - and perform an
ast_bridge_impart into the newly created bridge.
(3) Find the second channel. If the channel is in a bridge, perform a
bridge move operation. If the channel is not in a bridge, panic again and
do the following:
(3a) Issue an ast_channel_yank on the second channel. This will (again
carefully) perform the dreaded masquerade: create a new channel, move the
private data structure over, hang up the existing channel silently, and
'steal' the channel from the running pbx_thread.
(3b) Take the new channel - which again we now own - and perform an
ast_bridge_impart into the newly created bridge.
(4) Return success

Consider, instead, adding two channels to a bridge in ARI:
(1) Make the bridge. This directly maps to ast_bridge_create.
(2) Add the first channel. Since ARI owns the channel, there is no need to
yank it from something else. Call ast_bridge_impart.
(3) Add the second channel. Since ARI owns the channel, again, there is no
need to yank it from somewhere else or perturb an existing thread. Call
ast_bridge_impart.
(4) Rejoice in the lack of insanity.

If, on the other hand, ARI allowed a channel to be 'owned' by a dialplan
application, we could not make the assumptions in steps 2 and 3 that ARI
'owns' the channel. We'd have to go through some severe machinations to get
ownership again. And this is a relatively trivial case: manipulating media,
for example, on a channel in a dialplan application has a lot of strange
corner cases that could be extremely volatile.

Hence, the goal for ARI is not to turn it into dialplan execution. Instead,
we want to find a way to enable use cases currently met by dialplan
applications - typically in a fashion that provides information
asynchronously to ARI applications. Hence, the TALK_DETECT function as a
way to enable WaitForSilence/WaitForNoise.

Matt

-- 
Matthew Jordan
Digium, Inc. | Engineering Manager
445 Jan Davis Drive NW - Huntsville, AL 35806 - USA
Check us out at: http://digium.com & http://asterisk.org
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-app-dev/attachments/20140616/8be4f36c/attachment.html>


More information about the asterisk-app-dev mailing list