Can I grab an active call from another user?

Let's play thief - What was yours, is now mine!

Playing nicely: Pixbay

On the FreePBX forums, a newbie asked if it is possible to "steal" an active call from another extension.

In their words:

I’m putting phones (Yealink T31P) in a classroom that already have a SIP PA speaker (Valcom VIP-431As). The phone and speaker each have their own extension. When calling the PA speaker’s extension, the PA speaker automatically picks up. What I’d love to do is have a button on the phone that can “take” the already answered call and bring it to the handset.

Scenario: if the office pages into the room, and the teacher doesn’t want to respond in front of the whole class. They walk over, press a button on the phone, and the call is “grabbed” from the speaker and brought to the phone. Kind of like a hostile transfer. 

Initially I thought, yes, that is doable with a custom dialplan. But hey, let them hire someone to code this up.

But then I went back to the post and decided to give them an idea of how such a custom dialplan would look like.

In a nutshell, when the "thief" calls the custom dialplan, it would have to do the following:

  • Find the active call
  • Find the channel that you want to "steal"
  • Redirect the channel to a holding station (something like Park or a Dynamic Bridge)
  • Have the "thief" pull the channel from park or add their channel to the Dynamic Bridge
  • Destroy the "victim's" channel.

And I continued on with my business...  

A bit later, I got an email that a fellow Community Contributor -- who's opinions and expertise I respect a lot, saying that my solution is not going to work because of x,y and z.

Well, that encouraged me to get a proof of concept going.

Later that day, when I finished working, I rolled up my sleeves and got my hands dirty.

After a bit of testing, I was surprised that it is way easier than I thought.

Yes, it is a one liner of dialplan... Here's the dialplan.

Let's break it down into pieces.

The "thief" dials *37 followed by the extension number of the "victim", so we use the Noop() application to say: "Extnering custom context to seize call from 1234"

The next line is where all the magic happens.

The Asterisk Bridge() application allows the current channel to create a bridge with another active channel. So all we need to do, if somehow find the channel of the party the "victim" is speaking with and pass it to the Bridge() application. 

How do we do that?

The easiest way, is probably to obtain the channel using the ${BRIDGEPEER} variable. But how?

First we have to find the channel of the "victim". So we use the Asterisk function ${CHANNELS()} which allows you to pass a regular expression and returns the matching channel(s).

Now that we have the "victim's" channel, we have to find the channel of the person they are speaking with.

Here's when we use the Asterisk ${IMPORT()} function and pass the "victim's" channel. Bingo!

Finally, after it is all put together, it looks like this

Bridge(${IMPORT(${CHANNELS(${EXTEN:3})},BRIDGEPEER)})

Now you are going to ask: What about the channel of the "victim", don't we have to destroy that?

Well, thankfully, Asterisk is smart enough to realize that there's a channel in a empty bridge, so it kicks the channel from the bridge and destroys the call.

You know what's nice? Thanks to PJSIP's line updates, the party is getting updated in realtime that they are now speaking with the "thief".

I tweeted about this. Join the conversation:

I also, submitted this as an official contribution to the FreePBX project with an addition to play to the "thief" an announcement if something went wrong. You can follow the progress in this ticket https://issues.freepbx.org/browse/FREEPBX-24135

Cheers!

Comments