Re: WebSocket Stasis Control Best Practice

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I also wanted to add that I am now attempting to just throw channel variables in as a way to pass arguments since I cannot pass them directly to Stasis. When I attempt to originate a new call with /channels/ and then right after I get the ID, I try to /channels/{channelID}/variable?appargs=blah but get the error Channel not in Stasis application. I can see that it's sent from /res/ari/resource_channels.c in find_control (from ast_ari_channels_set_channel_var). I understand that, at that point in time, while executing other Asterisk Apps, Stasis does not "own" the channel (if I understand that correctly) - but shouldn't it still be possible to set channel variables regardless of who owns the channel at the time the variable is attempting to be set? 

-- 
KB

On Monday, June 16, 2014 at 6:03 PM, Krandon wrote:

On Monday, June 16, 2014 at 9:12 AM, Matthew Jordan wrote:
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

Hey Matt/Everyone,

I actually really like the ideology behind this. The idea that ARI is truly a platform for which people can build complex telephony apps without having to write them in C is really neat. Also, since it's WebSockets, inherently very horizontally scalable which was somewhat of a challenge previously. I do understand some barrier to entry for people who are transitioning from AMI/AGI or even dial plan if they are "porting" an app because of functionality/apps that have to be essentially rewritten/rethought. As with any project, however, I strongly believe that more and more apps will become the "core" of several libraries for interfacing with ARI. It gives a lot of power to the individual utilizing the ARI interface.

With the TALK_DETECT function, I could re-create AMD and it would actually would be way more extendable (not to mention decently fast). 

I have at least tested the scalability of concurrent calls and requests generating lots of events and have been extremely impressed so far. This may be the scalability freak in me, but is there a way I can tell the ARI not to send me events that I don't care about when first connecting to /events? For example, RTP related events. I remember seeing something about not having pub/sub for a reason. I could just discard processing the packet, but with the load we've been dealing with, even that is very expensive.

Even setting channel variables in Stasis, then /continue to execute a dialplan app, then stasis again, reading the resulting channel vars. I actually don't think it's that much of a "hack" and could make for a really elegant app/app infrastructure, though not quite as sexy, I mean, extendable. 

Gone are the days of using manager to throw two people into a queue, crossing your fingers and hoping some weird masquerade a) makes it to a CDR which can be tracked and b) doesn't blow up - big props to the Asterisk dev team on that! (unrelated to ARI, but still very important for the growth and implementation of ARI - imho)

I'll report back results of an AMD implementation using TALK_DETECT - checking out the latest Asterisk 12 now.

Thanks all,

-- 
KB



_______________________________________________
asterisk-app-dev mailing list
asterisk-app-dev@xxxxxxxxxxxxxxxx
http://lists.digium.com/cgi-bin/mailman/listinfo/asterisk-app-dev

[Index of Archives]     [Asterisk SS7]     [Asterisk Announcements]     [Asterisk Users]     [PJ SIP]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Linux API]

  Powered by Linux