PIONEERS Picking up a call on hold on another extension

nicknomo

Happy-IT-Guy
Joined
Mar 5, 2009
Messages
63
Reaction score
12
UPDATE:
Now with a Yealink APP:
http://pbxinaflash.com/community/index.php?threads/yealink-app-for-picking-up-calls-on-hold.14759/

I was wondering if anyone had any input on this approach. What I've been working on is being able to grab a call that is on hold on another extension in asterisk. This is usually needed when you didn't have the foresight to park a call, and you or someone else ends up wanting to pick it up on another extension.

There doesn't appear to be any channel variables that indicate a call is on hold... there is only hold events, but you'd need to constantly monitor the system to keep track of them. Neither FreePBX nor Elastix currently have any methods for picking up a held call, and I could not find any built in application within asterisk that natively does this.. What I ended up noticing was that calls on hold has the write format of "slin", and I've leveraged that to isolate calls on hold.

What I ended up doing was using "core show channels" and "core show channel" to see what was in use by the extension we want to steal the call from. I'd go down the list and look for channels that belong to SIP/{$extension}. I'd then look at who they are bridged with, and use "core show channel" on those bridged channels to see the "write format". If its playing a wav file (hence the signed linear write format), then I take the call.

I'm curious to hear from the rest of you if you can see any problems with this approach? It appears to work OK in testing, but its with a limited number of calls.
 

nicknomo

Happy-IT-Guy
Joined
Mar 5, 2009
Messages
63
Reaction score
12
Here are the files I'm using. I've placed them in /var/lib/asterisk/agi-bin . They will require execute privileges (chmod 755).

There are two variants I made (files are attached to this post):
1) holdsteal2.agi - made to get out of the script as soon as it finds a match.
2) holdsteal.agi - made to get a full array of held calls, in the case that there may be more than one. This is slated for future development, and I want to try making an app for the T46G using this.

As far as the dialplan work, I added this under [from-interal-custom] in extensions_custom.conf
Code:
[from-internal-custom]
include => pickuphold

and at the bottom of the file, I have this:
Code:
[pickuphold]
exten => _#9X.,1,NoOP(PICK UP HELD CALL: ${EXTEN:2})
exten => _#9X.,n,Set(ARG1=${EXTEN:2})
exten => _#9X.,n,AGI(holdsteal2.agi,${ARG1})
exten => _#9X.,n,NoOP(This was returned as the held call channel2: ${HELD_CHANNEL})
exten => _#9X.,n,Bridge(${HELD_CHANNEL})
exten => _#9X.,n,hangup()
;end of [pickuphold]

I've elected to use #9 and then the extension number to perform the action (e.g. #9301 ).

Limitations:
1) You must use SIP extensions.
2) You MUST have hold music
3) This will NOT work with GSM hold music. Preferably the format should be WAV, but
MP3 does work as well. Other formats are probably not supported.
4) If you use elastix, you'll need to put a different password in the .agi file.
 

Attachments

  • holdstealv1.zip
    4.3 KB · Views: 18

atsak

Guru
Joined
Sep 7, 2009
Messages
2,381
Reaction score
436
What happens if the extension who had the call on hold tries to pick it up out of interest?
 

nicknomo

Happy-IT-Guy
Joined
Mar 5, 2009
Messages
63
Reaction score
12
Just wanted to post this, in case anyone wanted to make the held call pickup the same as the current pickup feature code "**", you'd use the following dial plan code.

Code:
[pickuphold]
include => app-pickup
exten => _**X.,1,NoOP(PICK UP HELD CALL: ${EXTEN:2})
exten => _**X.,n,Set(ARG1=${EXTEN:2})
exten => _**X.,n,AGI(holdsteal2.agi,${ARG1})
exten => _**X.,n,NoOP(This was returned as the held call channel2: ${HELD_CHANNEL})
exten => _**X.,n,GotoIf($[ "{$HELD_CHANNEL}" != "" ] ?bridgeit:passit)
exten => _**X.,n(bridgeit),Bridge(${HELD_CHANNEL})
exten => _**X.,n(bridgeit),hangup()
exten => _**X.,n(passit),NoOP(Passing it!!!!)
exten => _**X.,n(passit),GOTO(from-internal-additional,${EXTEN},1)
exten => _**X.,n(passit),hangup()
;end of [pickuphold]

If it doesn't find a call on hold, it passes it onto the normal dial plan.
 

nicknomo

Happy-IT-Guy
Joined
Mar 5, 2009
Messages
63
Reaction score
12
What happens if the extension who had the call on hold tries to pick it up out of interest?


The line is basically disconnected on the original extension, so they don't have a chance to retrieve it back. Its a lot like if the call was transferred. Its similar to call parking, except it never leaves the extension it is on.

The upside to doing this is, unlike a parked call, there isn't really a chance for the call to be orphaned. So, if the call isn't picked up, the person who has the call on hold still sees it and is aware of it. The down side to this is

1) it could be a security issue, to have employees steal other calls
2) It cannot handle more than one call on hold. It just takes the first one it found.

#2 is customizable... I could potentially return the call that has been on hold the longest, or the shortest.
 

kenn10

Well-Known Member
Joined
Dec 16, 2007
Messages
3,765
Reaction score
2,173
I'd like to see something like this developed to act the way the old Rolm/Siemens PBX's worked. Any extension could place a call on hold and another user could dial an access code plus the extension number where the call was on hold and retrieve it. On the multi-line sets, the call would just drop off when picked up elsewhere.

Likewise, you could dial a feature code and place a call on-hold at any extension in the system. On multiline phones, it would show up as a held call and on single line phones, it was retrieved with a single retrieve code.

This is kind of like valet call parking on a per station basis where every extension supports a parking slot. This, and other multiline shared call functionality is sadly lacking in Asterisk.
 

nicknomo

Happy-IT-Guy
Joined
Mar 5, 2009
Messages
63
Reaction score
12
I'd like to see something like this developed to act the way the old Rolm/Siemens PBX's worked. Any extension could place a call on hold and another user could dial an access code plus the extension number where the call was on hold and retrieve it. On the multi-line sets, the call would just drop off when picked up elsewhere.

Likewise, you could dial a feature code and place a call on-hold at any extension in the system. On multiline phones, it would show up as a held call and on single line phones, it was retrieved with a single retrieve code.

This is kind of like valet call parking on a per station basis where every extension supports a parking slot. This, and other multiline shared call functionality is sadly lacking in Asterisk.


If the access code was shared among all extensions, or large ranges of extensions, that would actually be very easily done in the dial plan. If you wanted the access code when you dial in, like #9 + <access code> + <extension> ... then the extension 300, with access code 8843, would look like this when dialed - #98843300 . It would only require a minor modification to my code above, like so:

Code:
[pickuphold]
exten => _#98843X.,1,NoOP(PICK UP HELD CALL: ${EXTEN:6})
exten => _#98843X.,n,Set(ARG1=${EXTEN:6})
exten => _#98843X.,n,AGI(holdsteal2.agi,${ARG1})
exten => _#98843X.,n,NoOP(This was returned as the held call channel2: ${HELD_CHANNEL})
exten => _#98843X.,n,Bridge(${HELD_CHANNEL})
exten => _#98843X.,n,hangup()
;end of [pickuphold]

To use your own pin, you could sub out the 8843 from the code above with whatever 4 digit code you wanted. You could also change the #9 to whatever two digit feature code you wanted, provided its not in use already.

If you want the system to prompt you and ask for a pin, then code like this should work
Code:
[pickuphold]
exten => _#9X.,1,NoOP(PICK UP HELD CALL: ${EXTEN:2})
exten => _#9X.,n,Set(ARG1=${EXTEN:2})
exten => _#9X.,n,Authenticate(8843,)
exten => _#9X.,n,AGI(holdsteal2.agi,${ARG1})
exten => _#9X.,n,NoOP(This was returned as the held call channel2: ${HELD_CHANNEL})
exten => _#9X.,n,Bridge(${HELD_CHANNEL})
exten => _#9X.,n,hangup()
;end of [pickuphold]

The line that says Authenticate() checks for the pin inside the brackets. You could change out the number as desired.

Now, as far as putting calls on hold remotely, I don't know of any way to do that... From what I can tell, being "on hold" in asterisk doesn't involve asterisk doing much. Its really more of a function of the phone. The phone tells asterisk its putting the line on hold, stops sending audio data, and then the phone does whatever the manufacturer decides to do. Asterisk really only comes into play by saying "welp, I guess I should play some hold music for this guy". The channel is still technically open on both sides. Not much has really changed.

Basically, what I think would stop me from forcing a hold is that I can't really make the phones do anything. Even if I could, it would likely be manufacture specific.

What I *could* do is make a script to steal an ACTIVE call. I'd guess the only reason you'd want to put a call on hold is so you can take it from an extension that is off the hook, but no one is present. I'm guessing you'd put the call on hold, just to steal pick it up from hold? If so, stealing an active call would effectively do that. That would require a change to my AGI code, but it would be a relatively minor one.
 

kenn10

Well-Known Member
Joined
Dec 16, 2007
Messages
3,765
Reaction score
2,173
Great ideas. I'd be curious what others on this forum think of the ideas.
 

nicknomo

Happy-IT-Guy
Joined
Mar 5, 2009
Messages
63
Reaction score
12
I've updated this a little to reflect what was previously suggested.

Here are the files I'm using. I've placed them in /var/lib/asterisk/agi-bin . They will require execute privileges (chmod 755).

There are two variants I made (files are attached to this post):
1) holdsteal2.agi - made to get out of the script as soon as it finds a match.
2) callsteal.agi - This script takes a live/active call from another extension. Its ideal if you left a handset off the hook, and you want to pick it up.

As far as the dialplan work, I added this under [from-interal-custom] in extensions_custom.conf
Code:
[from-internal-custom]
include => pickuphold

and at the bottom of the file, I have this:
Code:
[pickuphold]
exten => _#99X.,1,NoOP(PICKING UP ACTIVE CALL: ${EXTEN:3})
exten => _#99X.,n,Authenticate(31337,)
exten => _#99X.,n,Set(ARG1=${EXTEN:3})
exten => _#99X.,n,AGI(callsteal.agi,${ARG1})
exten => _#99X.,n,NoOP(This was returned as the active call channel: ${HELD_CHANNEL})
exten => _#99X.,n,GotoIf($[ "${HELD_CHANNEL}" != "" ] ?bridgeit1:passit1)
exten => _#99X.,n(bridgeit1),Bridge(${HELD_CHANNEL})
exten => _#99X.,n(bridgeit1),hangup()
exten => _#99X.,n(passit1),NoOP(Passing it!!!!)
exten => _#99X.,n(passit1),hangup()
 
exten => _#9X.,1,NoOP(PICK UP HELD CALL: ${EXTEN:2})
;exten => _#9X.,n,Authenticate(31337,)
exten => _#9X.,n,Set(ARG1=${EXTEN:2})
exten => _#9X.,n,AGI(holdsteal2.agi,${ARG1})
exten => _#9X.,n,NoOP(This was returned as the held call channel: ${HELD_CHANNEL})
exten => _#9X.,n,GotoIf($[ "${HELD_CHANNEL}" != "" ] ?bridgeit2:passit2)
exten => _#9X.,n(bridgeit2),Bridge(${HELD_CHANNEL})
exten => _#9X.,n(bridgeit2),hangup()
exten => _#9X.,n(passit2),NoOP(Passing it!!!!)
exten => _#9X.,n(passit2),GOTO(from-internal-additional,${EXTEN},1)
exten => _#9X.,n(passit2),hangup()
;end of pickup hold

I've elected to use #99 and then the extension number to pickup live calls (e.g. #99301 ). This requires an authentication code, and as of now its set to 31337 .

I've elected to use #9 and then the extension number to pickup held calls. (e.g. #9305 ). The authentication line is commented out, but its there in case someone wants to enable it..

This has tested well so far. It proves to be more useful than park, since if you leave your desk with a call on hold, then you or anyone else can pick it up anywhere. Now, with the forceful active call steal, you don't even need that call to be on hold.

It should cover the features provided by many legacy PBX's.

Limitations:
1) You must use SIP extensions.
2) You MUST have hold music (or anything else playing on hold)
3) This will NOT work with GSM hold music. Preferably the format should be WAV, but MP3 does work as well. Other formats are probably not supported.
4) If you use elastix, you'll need to put a different password in the .agi file.
5) If you have more than one call on hold, the hold steal will likely find the oldest one and steal that one.
6) Using the #99 feature code to steal a live call prohibits you from using extentions 900-999 for the hold steal. Any extension that starts with 9 (e.g. 901) will trigger the live steal instead, since the sequence will read #9901 . Instead of picking up the held call on 901 (#9 + 901), it will try to pick up a live call on 01 (#99 + 01).
 

Attachments

  • holdstealv3.zip
    4.3 KB · Views: 26

phoneguy

Guru
Joined
Jan 13, 2008
Messages
285
Reaction score
54
We have a app coming out for this in the next release that does everything through AMI and does not have any of the requirements above and the potential issues of anyone can now pickup any held call and no control over which one. Also how do you verify its a call on hold with this setup versus my extension getting MoH for some other reason.

http://wiki.freepbx.org/display/FCM/RESTful+Phone+Apps-Roadmap
 

nicknomo

Happy-IT-Guy
Joined
Mar 5, 2009
Messages
63
Reaction score
12
We have a app coming out for this in the next release that does everything through AMI and does not have any of the requirements above and the potential issues of anyone can now pickup any held call and no control over which one. Also how do you verify its a call on hold with this setup versus my extension getting MoH for some other reason.

http://wiki.freepbx.org/display/FCM/RESTful Phone Apps-Roadmap


This is done partially through AMI as well... but it using a very simple approach on sending console commands. What is your approach? I posted here looking for cleaner ways to do it, so I'm open to hearing suggestions. If there is more direct way to look up this information, I'd definitely consider a rewrite. I've yet to hear of another approach to this... in fact I've seen plenty of people say it couldn't be done to begin with. AFAIK there is no channel data, or other accessible variables that indicate a call is on hold.

Security is definitely light in my work here (partially by design - that is how the legacy phone systems worked). I've added the option to authenticate, but I personally won't be using it... and I wrote it so I can use it.

In theory you could easily add granular protections to the dial plan... but it would be a lot of manual work. If security information was added to the DB via the GUI, I could create generic code that makes it secure. Do you plan to put the entry for these controls in the main release of FreePBX or are they going to only be in a commercial module?

As far as verifying the call is on hold, we can be reasonably certain they are not getting MoH for any other reason. Basically we are looking at the channels bridged with our target extension, and nothing else. If they are bridged, the remote channel is either talking or on hold, save for some uncommon scenarios (none that I've yet to run into).

I'm planning to make a yealink app to use in conjunction with my logic here. The only thing I'm a little unsure of is how to get the call to the extension requesting it. I'd have to do something like park it first if I wanted the phone to dial in. I could transfer the call to the extension, but that feels too much like a hack. How do you think the calls should be bridged?
 

phoneguy

Guru
Joined
Jan 13, 2008
Messages
285
Reaction score
54
As far as permissions this is all controlled through the FreePBX Class of Service module which yes is a commercial module.
 

Pinellas Computers

New Member
Joined
Nov 5, 2015
Messages
1
Reaction score
0
This is done partially through AMI as well... but it using a very simple approach on sending console commands. What is your approach? I posted here looking for cleaner ways to do it, so I'm open to hearing suggestions. If there is more direct way to look up this information, I'd definitely consider a rewrite. I've yet to hear of another approach to this... in fact I've seen plenty of people say it couldn't be done to begin with. AFAIK there is no channel data, or other accessible variables that indicate a call is on hold.

Security is definitely light in my work here (partially by design - that is how the legacy phone systems worked). I've added the option to authenticate, but I personally won't be using it... and I wrote it so I can use it.

In theory you could easily add granular protections to the dial plan... but it would be a lot of manual work. If security information was added to the DB via the GUI, I could create generic code that makes it secure. Do you plan to put the entry for these controls in the main release of FreePBX or are they going to only be in a commercial module?

As far as verifying the call is on hold, we can be reasonably certain they are not getting MoH for any other reason. Basically we are looking at the channels bridged with our target extension, and nothing else. If they are bridged, the remote channel is either talking or on hold, save for some uncommon scenarios (none that I've yet to run into).

I'm planning to make a yealink app to use in conjunction with my logic here. The only thing I'm a little unsure of is how to get the call to the extension requesting it. I'd have to do something like park it first if I wanted the phone to dial in. I could transfer the call to the extension, but that feels too much like a hack. How do you think the calls should be bridged?

@nicknomo: This is great! I'm going to be playing around with it tomorrow. These two features, along with chanspy, whisper and bardge - make administering our retail customer service offices so much better. I was really excited to see someone had come up with a "call steal" applet and was super impressed at the idea of picking up calls on hold. Have you made any further updates/progress on this, or is this the most up to date content we should play with? Thanks!

Also, we love custom features like this. If you have any other cool applets like this, please link to them or share their concept. :)
 

Members online

Forum statistics

Threads
25,782
Messages
167,514
Members
19,203
Latest member
frapu
Get 3CX - Absolutely Free!

Link up your team and customers Phone System Live Chat Video Conferencing

Hosted or Self-managed. Up to 10 users free forever. No credit card. Try risk free.

3CX
A 3CX Account with that email already exists. You will be redirected to the Customer Portal to sign in or reset your password if you've forgotten it.
Top