Better FollowMe for FreeSwitch

The problem

The examples for Follow-Me on FreeSwitch had always left me wanted; two issues specifically were pretty frustrating:

  1. Most examples use the common method of doing a bridge command with failover (using the call_timeout channel variable), for example:
     <action application="bridge"
      data="${extension}|${extension},${followme}"/>
    FreeSwitch will do what it is being told: generate a call setup to the extension, then take that call back, then place a new (failover) call to both the extension and the followme. This causes issues if the user picks up the call right before the failover, since they may pick up the phone, only to answer a call that was just taken back, and see a new call from the same caller come up right afterwards. More importantly, if the user only has a single line appearance, then the call will not ring back (since the extension is busy) and will be lost.
  2. I was used to FreePBX's call confirmation feature, and although I could recreate it with a group_confirm script, since the scripts cannot be assigned to a specific outbound leg on a call, my script ended up being non-generic (doing a regex match on the destination number to figure out whether call confirmation was needed or not).

The solution

Until yesterday, that is. I read the bridge documentation carefully, and re-read the channel variables documentation carefully, and figured out:

  1. Using the leg_delay_start parameter, there is no need to rely on failover. It's sufficient to delay the follow-me call setup:
     <action application="bridge"
      data="${extension},[leg_delay_start=12]${followme}"/> 
    In that last example, the extension will start ringing immediately, and the followme starts ringing after 12 seconds; the call to the original extension is never taken back, so the glare scenario I described earlier is eliminated.
  2. Once I had figured out per-leg parameters, I tried to see whether I could create my own parameter. It worked... To do per-destination call confirmation, you can write for example:
     <action application"bridge"
      data="${extension},[leg_delay_start=12,leg_confirm=y]${followme}"/> 
    In this example the original extension will not get call confirmation, but the followme destination will.

Putting these two elements together, a FreeSwitch XML script for follow-me would look like this: <pre> <action application=”set” data=”group_confirm_key=exec”/> <action application=”set” data=”group_confirm_file=javascript confirm.js”/> <action application=”bridge” data=”${extension},[leg_delay_start=12,leg_confirm=y]${followme}”/></pre> Here is confirm.js:

//  confirm.js - FreeSwitch call confirmation script
//  (c) 2009 - Stéphane Alnet
//  License: GPL2 or above

console_log("info", "Destination: "+ session.destination + "\n");
if(!session.getVariable('leg_confirm'))
{
  console_log("info", "No need to confirm, connect the call!\n");
  exit();
}

var confirmed = false;
var confirmation_digit = "1";
var try_count = 6;
var prompt_file = "connect-to-caller-press-1.wav";

function onInput( session, type, data, arg ) {
  if ( type == "dtmf" ) {
    console_log( "info", "Got digit "..data.digit.."\n" );
    if ( data.digit == confirmation_digit ) {
      confirmed = true;
      console_log( "info", "Confirming session..\n" );
      return(false);
    }
  }
  return(true);
}

if ( session.ready() ) 
{
  session.answer();
  session.flushDigits();
  console_log("info", "Starting confirmation\n");
  var count = try_count;
  while( session.ready() && ! confirmed && count-- > 0 )
  {
    session.execute("sleep","200");
    session.streamFile( prompt_file, onInput );
  }
  if( ! confirmed )
  {
    console_log("info", "Not confirmed\n");
    session.hangup();
  }
  else
  {
    console_log("info", "Confirmed\n");
  }
}
else
{
  console_log("info", "Session is not ready.\n");
}

Note: the value of the leg_confirm variable is never used. If the variable is present, call confirmation will happen. The script could be modified to use the value of the variable as the confirmation digit, instead of using a hard-coded value of "1". This would also require to use a dynamic prompt, instead of the static connect-to-caller-press-1.wav filename embedded in the script.

posted: 2009-03-21 07:08

Written on March 21, 2009