Asterisk Asynchronous AGI

I have been coding some new stuff for Asterisk lately, but the feature I like the most is Asynchronous AGI. I got the idea from MAGI, an old patch written by David Pollak that allowed AGI execution thru the manager interface. For those ignoring what AGI and AMI are, go read:

Asterisk Gateway Interface ( AGI )
Asterisk Manager API ( AMI )

So, my patch, allow users to execute AGI commands using “Action: AGI” and get the response reading “Event: AsyncAGI”. The manager header “CommandID” can be specified to match up the responses. Let’s see an example

In extensions.ael you would put something like this:

context sample-async-agi {
    test => {
        AGI(agi:async);
    };
};

That will put the channel to wait AGI commands. The channel will NOT do anything but wait for Hangup or any AGI command you ask it to execute. AGI commands can arrive from 2 sources. The most important and useful source of commands is the manager, but with my patch you can also execute AGI from the command line. Let’s see how it is done from the manager:

# telnet localhost 5038
Action: Login
Username: test
Secret: test

Action: AGI
Channel: SIP/33-blah
Command: EXEC Playback tt-monkeys
CommandID: MyCommandID

That would cause Asterisk to execute the “Playback” application on channel SIP/33-blah, which MUST be in AGI(agi:async) application. After executing the command you will be able to read an event with the AGI response url-encoded. If the channel is not in Async AGI, the command will not be executed and you will get an error response.

As I said, you can use the command line to execute Async AGI as well, just like this:

tcore*CLI> agi exec SIP/testing-09a5b960 “EXEC startmusiconhold”
tcore*CLI> agi exec SIP/testing-09a5b960 “EXEC stopmusiconhold”
tcore*CLI> agi exec SIP/testing-09a5b960 “EXEC Dial(Agent/23)”

That will start MOH, then stop it, and finally will dial to the Agent 23. This means you can implement a Queue without using native buggy Asterisk queues. You can receive calls and send them to Async AGI to put them on hold, then, when you detect availability of some of your Agents, Dial() to that agent.

If you want to learn more about this feature here is the mantis bug entry: http://bugs.digium.com/view.php?id=11282.

If you want the patch back-ported to 1.4, I have one here: http://www.moythreads.com/asterisk-1.4.15-async-agi.patch

In case you find this patch useful, please try it in trunk as well and provide feedback in mantis. Even when some people has found this patch useful, some of the top developers at asterisk-dev are hesitating in accepting it because similar results can be obtained thru the use of FastAGI, however, me and other people at asterisk-dev are trying to prove the patch also makes easier the implementation of some applications.

This is a hot discussion we got some weeks ago about it: http://lists.digium.com/pipermail/asterisk-dev/2007-December/031046.html

See you!

This entry was posted in asterisk, C/C++, voip. Bookmark the permalink.

33 Responses to Asterisk Asynchronous AGI

  1. You could certainly see your enthusiasm within the paintings
    you write. The world hopes for more passionate writers like you who are not afraid to mention how
    they believe. All the time follow your heart.

  2. moy says:

    @BrettNem, That’s what AGI is for, forking a process that will handle the call. AMI is for asynchronous control over the whole Asterisk system so you can do more powerful things beyond the scope of a single call.

  3. BrettNem says:

    Is there anyway to execute (fork) a background process once the async.agi is established? That would be really useful to have AMI script executed in the context of the channel itself handle the call rather than some long running monitoring process on AMI

  4. Steve Mathers says:

    Hey, this has me very interested. i would like to try it out. im a bit confused. I do everything through a php script, kinda like this:

    [cloud]
    exten => 999,1,Answer
    exten => 999,n,AGI(cloud.php)
    exten => 999,n,Hangup

    so my script runs various things. what i would like to do is a stream file in the asyncAGI. then have the program continue on to do an exec_dial to a callcenter. once that callcenter answers ill run a post-dial macro that could break the asyncAGI stream file and then the 2 parties can only hear each other. also if a digit was pressed during the stream file can i catch it with commandID and do other processing?

    Also normally i would just use asterisk manager proxy and post xml to execute the AMI commands. perhaps theres a better way? Thanks for your time!

  5. Jeryes Farah says:

    Hi,

    I have two asterisk-java applications, that connects to the same asterisk by AsyncAGI, and both of them are receiving the same events, but only one is going to process it. The application that won’t process the new event, basically does nothing and “leaves” that channel without any operations or actions, and after concluding it, the channel get released, and interrupts the processing of the other application.
    So do you know if there is a way to connect more than one async java application on the same asterisk using AsyncAgi.
    Thanks in advance!

  6. Moy says:

    I’m not familiar with the inner workings of adhearsion. What is an Adhearsion server? is it an AMI client connection?

    You should be able to differentiate by sending arguments like:

    AGI(agi:async,arg1,arg2,arg3)

    The arguments will be sent in the initial AsyncAGI manager event that is sent each time a new channel enters the AGI application, the arguments are numbered as manager headers in this format:

    agi_arg_%d: value

    Where %d is the number of the argument you provided. This way you could route certain requests to one server or the other.

    AGI(agi:async,server1) when you want server1 to take care of it.

  7. Pavel Siderov says:

    Hi Moy,

    I have the same case as Zac. I have several adhearsion servers registered at asterisk. I need to address some prefixes in the dialplan to one adhearsion server and others to different adhearsion server. That’s why I need account association too. Is there any other way to achieve this?

    Thanks in advance,
    Pavel

  8. Pingback: cheap calls from the UK

  9. Moises Silva says:

    Hi Zac,

    I’m glad you found it useful.

    I am not sure I am following what you propose. When you say:

    “the following would send the AGI request to sessions authenticated by the AMI user account ‘mark’”

    What AGI “request” are you talking about? The initial AsyncAGI event that is launched when a channel executes the AGI(agi:async:ami_accnt=’mark’) application?

    If that is the case, then, it looks like you’re talking about associating a given AsyncAGI execution (both manager commands and events??) to a single manager account?

  10. Zac Wolfe says:

    Great addition Moy! We use this feature extensively in our SafiServer product. Among other things it’s helped us work around some limitations in Asterisk 1.6+ FastAGI implementations. Nice Work!

    One thing I would love to see is the ability to target a specific AMI session with the command to better support environments with multiple concurrent AMI sessions. For example, the following would send the AGI request to sessions authenticated by the AMI user account ‘mark’

    AGI(agi:async:ami_acct=’mark’)

    What are your thoughts. Would this be difficult to implement?

  11. Moises Silva says:

    No idea what you can possibly be doing wrong.

    I recommend you to ask in the asterisk-users mailing list, you have more chances of getting help there.

  12. billy says:

    Thank for your answer, but i still didn’t get success with it
    Command ‘agi exec SIP/601-000000c6 “Answer”‘ failed

    How can i do it?

    Thanks.

  13. Moises Silva says:

    You don’t call AGI(agi:async) from the command line. You call it from your dial plan. Once the channel is inside the app, from the command line you can do:

    tcore*CLI> agi exec SIP/testing-09a5b960 “Answer”

  14. billy says:

    How can i call agi with arguments agi:async in cli?
    Ex: with answer command?

  15. moy says:

    Hi CT1972,

    You just need to call the AGI application with the arguments agi:async, like this:

    AGI(agi:async);

  16. CT1972 says:

    Hi everybody!
    I have a problem, I send an AGI command using AMI:
    Action: AGI
    Channel: SIP/8029-000001ea
    Command: SET MUSIC ON

    I have the next response:
    Failed to add AGI command to channel SIP/8029-000001ea queue

    In the CLI interface I see this control message:
    Channel SIP/8029-000001ea is not at Async AGI.

    Why? How can I add a channel to Async AGI?

    Thanks

  17. cyr2242 says:

    great, I posted the DEBUG output at:
    http://lists.digium.com/pipermail/asterisk-users/2009-March/229524.html
    I see you there

  18. moy says:

    I see, thanks a lot for the detailed explanation, in order to determine where the problem is I need the debug output of Asterisk itself, not just the manager. That is, enable debugging in /etc/asterisk/logger.conf and pastebin.com the output of a success and failing scenario just as you did with the manager output.

    What do you say if we take this conversation to asterisk-users mailing list? just let me know the name of the thread name when you send it and I will continue answering there.

  19. cyr2242 says:

    Hi, I just do it. You can find an output for that scenario in:
    http://docs.google.com/Doc?id=ahfnfrcrh3rr_29863zkwc2
    Regards

    • Nati says:

      I know a lot of my friends who use this in their ofcfie. Although I have no personal experience with it yeah.Opensource software is always great for the consumers as well as for the developers. Because the consumers gets something free and high quality while the developers get to hone their skills to create better software.

  20. moy says:

    mmm, I don’t see why you would get a hangup, I’d like to see the debug output of such scenario.

  21. cyr2242 says:

    Hi,
    redirecting caller’s channel (listening a playback in AGI) to agent’s channel was the first thing I tried but I got a disconnection on my device (caller’s channel) so I thought it wasn’t the right way. However your approach redirecting the call to AGI again, then Dialing to the agent, could be work. I’ll give it a go.

    Thanks for the hint

  22. moy says:

    Hello,

    The problem you mention is addressed by redirecting the channel, you can do that with the manager Redirect action (I have not used Asterisk lately, but I expect that action to still be named the same), the truth is that behind the scenes, a Redirect causes a hangup of the channel, but the call stays alive in a new channel (this process is known as masquerade), this will break your channel out of any application (Playback, Dial, etc) and return control to the dial plan. This is useful for you to Redirect the channel to the one and only Async AGI control loop (ideally in my ideal system there is only 1 Async AGI loop) and then you can proceed to Dial() to the free Agent.

    Let me know if this crappy explanation was not enough.

  23. cyr2242 says:

    I’m pulling it up because I’m interested on it. I have written some asynchronous voice and telephony application for years and this AsyncAGI almost meets my expectations about a 3rd party call control for Asterisk, but IMHO there’s a lack:
    If I’m playing an announcement for a wait on queue functionality … how can I stop the announcement when an agent (I have my own implementation for agents in my application) becomes free before redirect him the call? I can’t see any AGI command like stopPlay.
    I know your AsyncAGI relies on AGI, so this lack for a stop function isn’t a FastAGI’s fail but I suppose you have already thought about it before me. I would appreciate some hints about it in order to becoming the use of AsyncAGI in something as useful as I think it would be.
    Thanks

  24. manuna says:

    Sorry, i’ve really misunderstood the way it works. My mind was that asynchronous channel can execute some AGI script (determined in dialplan), meanwhile being able to receive and execute asynchronous commands (from an external AMI application). So the initial script sets up a call, and later on it can be asynchronously bridged, put on hold, etc.

  25. moy says:

    Then probably AsyncAGI is not for you.

    What you don’t seem to understand is what I just said to you, AsyncAGI HANDLES ALL THE CHANNELS THROUGH THE MANAGER, there is no such thing as an execution script (sure thing probably there will be manager connections controled from scripts, but that’s outside the AsyncAGI scope to know). That’s what “Async” means, Asynchronous.

    When you execute a script via FastAGI that script will control the channel during the life of the script, your script just takes care of that single channel and when you execute an AGI command your script “blocks” its execution until the command finishes.

    AsyncAGI just puts the channel to wait for Asynchronous AGI commands, where those commands will come from? is up to you. In my case I had a program that connected to the Asterisk manager and handled all the channels, so I had a single script that worked pretty much like a PBX in a scripting language, took care of knowing which channels were active and what to do with ALL of them, bridging them, un-bridging them, put in them in conferences, play audio etc.

    If you do anything at all with Async AGI you will have to understand event-oriented programming, because that’s how you do to control channels over AsyncAGI.

  26. manuna says:

    Will this be implemented in a way like:
    AGI(agi:async/scriptname?par1=val1&par2=val2…) ?
    For me it’s crucial to determine scriptname, because my FastAGI server processes different kinds of scripts, depending on extension dialed.

  27. moy says:

    You are correct in that it’s quite undocumented. Sorry about that, I will fix that as soon as I have a chance, I will add an entry into voip-info.org

    Even when anything you can do through FastAGI you can do it as well throug Async AGI, the client code has to change quite a bit since now, froma single connection you have to be aware of ALL channels, not of a single channel. This brings power but also complexity when dealing with many channels.

    Currently you cannot pass parameters directly to AsyncAGI, but you can

    Set(param1=val1)
    Set(param2=val2)
    AGI(agi:async)

    Then from your manager connection
    Action: AGI
    Command: GetVariable param1

    However I agree is easier to just pass parameters, so I will add that support.

  28. manuna says:

    Last days i tried to make something usable with AsyncAgi (using Asterisk-Java). It’s a nice thing, but really undocumented over the internet.
    The question is: what’s the simplest way of replacing FastAGI server with AsyncAGI server? I guess, all AGI scripts can be left intact, but i don’t quite understand, how should dialplan look like.

    ie, Fastagi call looked like:
    123 =>{
    AGI(agi://hostname:4567/scriptname?param1=val1&param2=val2);
    };

    How should this be implemented with AsyncAGI?

  29. Pingback: Asterisk-Java

  30. moy says:

    The “CommandID” header is independent of the “ActionID” header. This means you can actually specify both. ActionID is used internally by the core AMI system, so you will get an AMI packet with the specified ActionID as soon as the command enter the Async AGI queue. The “CommandID” will be sent as part of an AsyncAGI event to notify execution of the command, hence, you can add 3 commands in a row and get almost immediate response with the proper ActionID, but the CommandID will only get back until the each queued command gets actually executed.

  31. el_pop says:

    Why no “ActionID” in place of “CommandID”?. In all Manager commands is used “ActionID”. only to have a homogeneus notation with AMI.

  32. Pingback: SinoLogic » Cómo ejecutar AGI de forma asíncrona

Leave a Reply

Your email address will not be published. Required fields are marked *

*