Well, I ended up successfully accomplishing this, albeit using a very custom (and therefore more error prone) method.
I’m scripting using PHP with the AMI and a class I found called AstMan. AstMan is a small, to the point class that lets you easily query the AMI.
The purpose of all this is to be used as an emergency intercom, so that is a message absolutely must be delivered, it will be, even if someone is on their phone. It seemed there was no good way to force a call through to a phone.
Basically, I wrote two functions (along with a couple helpers). getChannelData queries the CLI through the Command AMI action and retrieves the channel information from “show channels”. It then parses that text into an easily usable object that contains total active channels, total active calls and all currently open channels.
Next I created the getDeviceChannels function, which takes the device name as the first argument (SIP/250 for instance). It then runs through the active channel data adding any channel names that belong to the passed device to an array. It then returns this, which means that we now have the full channel name of every open channel on a specified device. Yay!
Now that we have information, it’s very easy to disconnect every call on the device, simply by running through the array of returned channels and doing something like this:
$hangup = “Action: Command\r\nCommand: soft hangup $channel\r\n\r\n”;
Merging all of this into my original intercoming script effectively solved my problem. Now before originating to each extension that will receive the intercom message, the device is first checked for open channels, all of which are disconnected. Then script continues on as normal and originates the call, and then end user gets the important message.
To cut down of performance issues, I only retrieve channel data once per intercom message, at the beginning.
The below code may not really be usable for anyone else, and I can’t guarantee it to be reliable or anything, I -just- wrote, and have a lot more testing to do, but I hope I helped out someone.
function getDeviceChannels($device, $channel_data = NULL){
global $api;
if(is_null($channel_data)){
$channel_data = getChannelData($api);
}
$open_channels = $channel_data['channel_names'];
for($count = 0; $count < count($open_channels); $count++){
if(substr($open_channels[$count], 0, strlen($device)) == $device){
$device_channels[] = $open_channels[$count];
}
}
return $device_channels;
}
function getChannelData($api){
$columns[] = new column('Channel');
$columns[] = new column('Location');
$columns[] = new column('State');
$columns[] = new column('Application(Data)');
$parser = new columnParser($columns);
$line[] = "Action: Command";
$line[] = "Command: show channels";
$command = buildCommand($line);
$response = $api->Query($command);
$textArr = $parser->make_array($response, "\r\n");
$infoArr = $parser->make_array($textArr[2], "\n");
$header = $infoArr[0];
$info_startIndex = 1;
$info_endIndex = array_ereg('[[:digit:]]{0,5} active channels', $infoArr);
for($count = $info_startIndex; $count < $info_endIndex; $count++){
$channelInfo[] = $infoArr[$count];
}
$active_channels = split(" ", $infoArr[array_ereg('[[:digit:]]{0,5} active channels', $infoArr)]);
$active_channels = $active_channels[0];
$active_calls = split(" ", $infoArr[array_ereg('[[:digit:]]{0,5} active call', $infoArr)]);
$active_calls = $active_calls[0];
$results = $parser->get_columns($header, $channelInfo);
$channel_names = $results[0]->data;
$channel_states = $results[2]->data;
$channel_data['active_channels'] = $active_channels;
$channel_data['active_calls'] = $active_calls;
$channel_data['channel_names'] = $channel_names;
$channel_data['channel_states'] = $channel_states;
return $channel_data;
}
function array_ereg($pattern, $haystack) {
for($i = 0; $i < count($haystack); $i++) {
if(ereg($pattern, $haystack[$i])) {
return $i;
}
}
return false;
}
function buildCommand($arr){
foreach($arr as $l){
$command .= $l . "\r\n";
}
$command .= "\r\n";
return $command;
}
class columnParser {
var $columns = '';
function columnParser($columns){
$this->columns = $columns;
}
function make_array($text, $split){
return split($split, $text);
}
// returns zero indexed array
function get_columns($header, $textArr){
for($count = 0; $count < count($this->columns) + 1; $count++){
$loc = strpos($header, $this->columns[$count]->name);
if($count < count($this->columns)){
$this->columns[$count]->loc = $loc;
}
if($count > 0){
$this->columns[$count - 1]->end_loc = ($loc - 1);
}
}
// grab data from results
foreach($textArr as $line){
if(strlen(trim($line)) > 0){
foreach($this->columns as $key => $col){
$col->data[] = trim(substr($line, $col->loc, $col->end_loc - $col->loc));
$this->columns[$key] = $col;
}
}
}
return $this->columns;
}
}
class column {
var $name = '';
var $loc;
var $end_loc;
var $data = array();
function column($name=''){
$this->name = $name;
}
}