FreePBX 13 - Call Parking (from PHP)

I’m trying to test out an agi exec call on a channel to attempt to park the call. I have two extensions I’m testing with and have the following in my extensions_custom.conf file:

exten => 100,1,NoOp(Async AGI)
same => n,AGI(agi:async)

exten => 101,1,NoOp(Async AGI)
same => n,AGI(agi:async)

When I try to execute my command on the CLI:
agi exec SIP/100-00000024 ParkAndAnnounce(…

I get a warning that the channel is ‘not setup for Async AGI’.

Do I need to do something else to ensure the channels for those extensions can have AMI-AGI controls? Do I have something wrong?

I have also tried specifying the context as default and general but still have had no luck in getting this to work. I can’t seem to see where the dialplan is processing these entries. I suspect this has to do with the contexts that are FreePBX generated for the extension processing and the ones I’m specifying.

Or maybe someone has a completely different way they can recommend for me to try to control the call channels? The hope was to use the $astman->Command() method in PHP pages in writing a custom phone services app.

I’ve observed that the macro-dial-one in extensions.conf has an include for macro-dial-one-custom. I then changed my extensions_custom.conf to:

exten => s,1,NoOp(-----====== Async AGI ======-----)
exten => s,n,AGI(agi:async)

My hope was that I would finally see this included into the dialplan but this still doesn’t seem to be getting included / executed.

How would one use the xxx-custom contexts that are included in the FreePBX macros? I’m thinking maybe that the FreePBX macro-dial-one context entries are maybe over-writing my ‘first two’ context entries. Not sure how to debug that.

Or maybe there is an error in my definition?

Examine the macro-dial-one context for the predial hook macro (on mobile so can’t look it up for you). You can use the hook context for your own code.

I thought that is what the macro-dial-one-custom context is meant for. I can’t seem to find the macro-dial-one-custom context defined anywhere else. I guess at this point I’m confused as to why the include doesn’t seem to work as I have it implemented. So that I understand correctly, the ‘hook’ you are referring to is the include to macro-dial-one-custom, correct?

Is there a Wiki somewhere that references how to successfully hook into the contexts in FreePBX for enabling an Async AGI session? Or maybe a context map for the way FreePBX processes calls?

For a test I added a new context into extensions_custom.conf and looked at the dialplan and it did show up with the dialplan show output. Therefore I know that updated extensions_custom.conf file is truly being processed as part of the dialplan load process. I tried created a new extension that simply says ‘goodbye’ and hangs up. Unfortunately I can’t seem to figure out how to define the context to make that work either as the system simple doesn’t see the extension I defined.

I did at least figure out the correct context to use for a custom extension. I didn’t drill deep enough to get the correct context for my in that case script. However this doesn’t have anything to do with my original problem.

My extensions_custom.conf has this small section to prove the the dialplan sees the content of the file:

exten => 191,1,Noop(My test context is running here)
exten => 191,n,Answer
exten => 191,n,Wait(1)
exten => 191,n,Playback(vm-goodbye)
exten => 191,n,Hangup

When I dial 191 I hear the announcement and it hangs up.

So maybe I’m still using the wrong context for my AGI setup?

I don’t know what you are trying to accomplish, but if you want to execute your own code as part of the macro-dial-one context, there is a hook for that called macro-dialout-one-predial-hook. If you search the file extensions_additional.conf for occurrences of ‘hook’ you will find a few others. As you’ve discovered, most of the *custom contexts are not usable, and of the few that are, using them can have unintended consequences in the form of overwriting generated dialplan. Use the hooks where you can.

Alternatively, you can literally overwrite FreePBX generated dialplan by editing the file extensions_override_freepbx.conf, but do this as a last resort, there is always the possibility that future FreePBX updates with clash with the content of this file.

As stated in my first post, I am trying to use the AMI-AGI interface to Park a call. I am attempting to test the out at the CLI. To use the AGI interface my understanding is that I need to enable the AGI asynchronous interface in the dialplan for the extension. I am attempting to do this with:

exten => s,1,Noop(-----====== Async AGI ======-----)
exten => s,n,AGI(agi:async)

If I place this code in the macro-dialout-one-predial-hook context, defined in extensions_custom.conf, the dialplan stops at this point and does not return to the remaining part of the FreePBX dialplan to route the call as expected as it thinks it found a match.

Is there something I need to define differently?

Placing this in the macro-dial-one-custom context has no impact / effect at all. I’m not sure why it doesn’t get used there but does get used in macro-dialout-one-predial-hook. But as you state, maybe this is one that is not usable.

I’ve seen several posts on FreePBX forums and on other sites, asking the same question regarding Asynchronous AGI use on FreePBX and I don’t see any solutions posted anywhere.

I’m not sure how adding something in extensions_override_freepbx.conf will work any differently unless I replicate the entire context map from extensions.conf. Or am I missing something?

Maybe the AGI(agi:async) isn’t doing what I am expected from reading articles about it. To call ParkAndAnnounce from the CLI or AMI, the channel needs to be setup as a Asyncronous AGI session. So again, the questions remains, how do I part a call from the CLI or AMI?

There should be almost no need to set async on an agi script. Is there some particular reason you are wanting async? Everything you are doing can be done without async. In fact you’d almost want/need to use sync here.

Can you point me to some documentation on the method you have in mind? Please help me out here. I haven’t found a method yet other than using the ParkAndAnnounce app but don’t know how to call it from the CLI or AMI.

The easier way would be for you to create a context then have your agi use a goto into that context.

I haven’t thought of it that way but that does seem to make more sense to me now that you pointed me in that direction.

So, in the PHP, what would this look like?

$astman->Command("agi exec {$myactivechanhere} Goto(park-my-call-context)");

I would think I need to pass more arguments in somehow to the macro so it knows what extension to park in the dialplan, correct?

I’ve continued to struggle to figure out what you are really referring to as I have been unable to make the goto call work either. I see the same warning that the channel ‘is not setup for Async AGI’.

So how do I call a the context / macro from the PHP side?

Could someone please point me in the right direction here with a little detail? How do I park a call using ParkAndAnnounce from PHP?

This seems like this should be well documented but I can’t seem to find anything that helps me here. I figured this shouldn’t be too hard but I can’t seem to put the pieces together and actually have them function.

Stop using async agi and stop executing agi commands through asterisk manager.

I think you need to state what you are trying to do. Give us a bigger picture here. Eg is the call coming in and going to your agi? Why do you need an agi?

Thw documentation you are seeking is in the asterisk book.

Sorry, I thought I was being clear. I’ll change the title of the post.

I’m trying to park a call channel from a PHP script. The call channel is already identified to the extension the call is needing to be parked from. I’ve been through much of the Asterisk WIKI and through the Definitive Guide (Bryant, Madsen and Meggelen). I seem to be able to query for all that state and status that I want, I can’t seem to figure out how to CONTROL a channel that is active. Specifically start a transfer and then use ParkAndAnnounce is the desired approach but I’m open to what I can make work.

Maybe this could be done with the AMI attended transfer (atxfer) to the park and announce extension (mine is 70)? But you recommend that I don’t use the AMI in PHP?

What interface in PHP should I be looking at using for this?

Also, please let me know what book you are referring. Is there a tutorial on using the interface from PHP for the mechanism you suggest?

I understand now. So you’ve chosen the most complicated way to interact with Asterisk.

When you added

exten => s,1,Noop(-----====== Async AGI ======-----)
exten => s,n,AGI(agi:async)

You stated

This is correct. You’ve initated agi:async the Asterisk Book states ( )

When you use async AGI, Asterisk will send out a manager event to initiate the async AGI session.

Specifically Asterisk is now waiting for you to tell the channel to do something. It will not return into the FreePBX dialplan because it’s waiting for you to tell it what to do.

agi:async is really old. You won’t find many examples because it’s so complex. These days people use something like Asterisk ARI.

I never said such a thing. I said don’t use async agi. Why did I say that? Because it’s very complex and there are way easier ways to control channels since Asterisk 12.

I don’t have the Aync AGI included any longer as it was indicated that was NOT a good path. I now understand that making CLI calls with $astman->Command required an asynchronous call session. I thought maybe the Goto call to a dialplan context would not require the async session but obviously that is not correct. So please be clear, that is not the ‘chosen path’.

If there is a question why I’m using PHP, that is because the phones I’m working with can call a web service page where I can implement additional features. The phones do not support call parking feature buttons / soft functions so I am attempting to add that functionality through a web service accessed easily by the user from the phone.

I’ve investigated using $astman->Redirect($thechannel, $extrachannel, $exten, $context, $priority) with some success but have not found documentation on this. I don’t quite understand the channels and bridging that needs to be setup before this so my attempt to park a channel ends up with the wrong side hearing the parking lot the call was parked on. The call is parked and can be picked up but timeout ring back isn’t setup correctly either.

I see when a call is manually (with the user pressing *270 on a phone keypad while the call is active) that some LOCAL channels are spanned and bridge connections swapped around before the park occurs. The park seems to actually work on one the spawned LOCAL channels, not the raw channel to the extension directly. My redirect call to 70 doesn’t perform the channel spawns so it looks like the raw channel is put into the parking lot.

Specifically my PHP call I have tried working with looks like this:
> $thechannel = ‘SIP/101-0000001c’; //test channel
> $extrachannel = ‘’;
> $exten = 70;
> $context = ‘from-internal-xfer’;
> $priority = 1;
> $out = $astman->Redirect($thechannel, $extrachannel, $exten, $context, $priority);

I haven’t figured out what the extrachannel argument actually does yet. If I add the call’s other channel half here I get both channels parked and I get both channels parked into different lots. Cool but not very useful.

Is there a way to get a detailed explanation of the Redirect method call and the parameter interactions? Very little insight can be gleaned from the build it help (manager show command topic redirect). Searches for this have come up blank other than the reference at

I think with all the effort that has been put into indicating why what I’m doing will not work but no algorithm of actually doing this has been put forward, that no one actually knows how to park a call (two channels that are in an existing bridge) using php? Again, I already can identify the channels setup to the extension making the PHP web service call.

In looking at the Asterisk ARI and investigating PHPARI which appear would need to be installed, I’m still not clear on basic mechanism to achieving my goal. Seems like the dialplan would have to use the Stasis app but that is not a core part way FreePBX work is it? I’m not sure how this helps solve my problem. At this point, the question isn’t as much about the technology as much as the technique to be used.

I believe I just had a break through using the AMI in a sort of brute force socket connection method. I figured the Atxfer method should work but it is not part of the $astman class (like many other things).

>     $socket = fsockopen("","5038", $errno, $errstr, $timeout);
>     //log in
>     fputs($socket, "Action: Login\r\n");
>     fputs($socket, "UserName: admin\r\n");
>     fputs($socket, "Secret: xxx\r\n\r\n");

> ... verify with fgets...

>     fputs($socket, "Action: Atxfer\r\n");
>     fputs($socket, "ActionID: 125\r\n");    
>     fputs($socket, "Channel: $nearchannel\r\n");
>     fputs($socket, "Exten: 70\r\n");
>     fputs($socket, "Context: from-internal-xfer\r\n\r\n");

Everything seems to be working as expected, including the ringback to the extension that place the call into the parking lot. There is a fairly substantial reply back through the AMI from the Atxfer. Haven’t had a chance to really parse through that yet but not sure I need to do anything as I plan to publish a page back to the phone that shows the current parking slots with CID.