Could we get something like Ooma’s call flip? A feature code to dial while in a call that will ring all other devices for the user with no ring playback in the active call. Answering the call on another device seamlessly takes over the call.
I created a custom feature that does that.
First we’ll need to create a custom dialplan… You can create a new file in /etc/asterisk/vitalpbx and name it extensions__91-call-move.conf
[move-active-call]
exten => s,1,Noop(Custom context to move active calls)
same => n,GotoIf($["${CALL_TYPE}"="2"]?inbound)
same => n,GotoIf($["${CALL_TYPE}"="3"]?outbound)
same => n,GotoIf($["${CALL_TYPE}"="1"]?internal)
same => n,Goto(end)
same => n(inbound),GotoIf($["${CALLERID(num)}"="${CALL_SOURCE}"]?end)
same => n,Set(extension_number=${CALL_DESTINATION})
same => n,Set(cid_num=${CALL_SOURCE})
same => n,Goto(move)
same => n(outbound),GotoIf($["${CALLERID(num)}"="${NTD}"]?end)
same => n,Set(extension_number=${CALL_SOURCE})
same => n,Set(cid_num=${CALL_DESTINATION})
same => n,Goto(move)
same => n(internal),Noop()
same => n,ExecIf($["${CALL_DESTINATION}"="${EXTENSION_TO_DIAL}"]?Set(extension_number=${CALL_SOURCE}):Set(extension_number=${IF($["${CALL_DESTINATION}"="${CALLEE}"]?${CALL_DESTINATION}:)}))
same => n,ExecIf($["${CALL_DESTINATION}"="${EXTENSION_TO_DIAL}"]?Set(cid_num=${CALL_DESTINATION}):Set(cid_num=${IF($["${CALL_DESTINATION}"="${CALLEE}"]?${CALL_SOURCE}:)}))
Same => n,GotoIf(${ISNULL(${extension_number})}?end)
same => n(move),Noop(Trying to move ${BRIDGEPEER} to another device for extension ${extension_number})
same => n,Set(devices=${DB(${TENANT_PATH}/extensions/${extension_number}/dial)})
same => n,GotoIf(${ISNULL(${devices})}?end)
same => n,Set(device_count=${FIELDQTY(devices,&)})
same => n,Set(count=1)
same => n,While($[${count} <= ${device_count}])
same => n,Set(current_device=${CUT(devices,&,${count})})
same => n,GotoIf($["${DEVICE_STATE(${current_device})}"=~"NOT_INUSE|RINGING|ONHOLD"]?:next)
same => n,Set(ds=${IF(${ISNULL(${ds})}?${current_device}:${ds}&${current_device})})
same => n(next),Set(count=$[${count} + 1])
same => n,EndWhile()
same => n,GotoIf(${ISNULL(${ds})}?end)
same => n,Originate(Local/ring_devices@move-active-call,exten,move-active-call,take_call,1,,av(ds=${ds}^bp=${BRIDGEPEER}^cid_num=${cid_num}))
same => n(end),Return()
exten => ring_devices,1,Noop(Attempting to ring devices)
same => n,Set(CALLERID(num)=${cid_num})
same => n,Dial(${ds},30)
same => n,Hangup()
exten => take_call,1,Noop(Bridging the call)
same => n,Bridge(${bp},x)
Now we’ll create a dynamic feature, and added it to the custom_features, which is applied to all calls by default. You can create a new file in /etc/asterisk/vitalpbx and name it features__91-call-move.conf
[applicationmap](+)
move_call => *5,self/callee,Gosub(move-active-call,s,1)
[custom-features](+)
move_call =>
Now do a core reload asterisk -x"core reload"
and test the new feature by dialing *5 while on an active call.
PS. I only tested this on a single tenant system, but it should work on multi tenant as well. I also did not confirm that this doesn’t mess up cdr, call recording, etc.
Wow thanks for this, I really appreciate! We’ll test it out.
I just wanted to let you know this worked exactly how I hoped and appears to work with multiple tenants. It does only work once during a call so I guess that feature code isn’t getting applied after the call is bridged.
Thanks again for posting this and with very clear directions.
Thank you for the feedback, I made some changes to the dialplan to address this issue, and some other issues I noticed (below).
The only downside with this version (that I noticed) is that it’ll also ring the device that activated the feature code which can be a bit confusing.
Issues resolved in this new version.
- Only working once per call
- Not following diversions
- Cannot be triggered from an external followme destination
- Not working for extension with only one endpoint (device), but multiple contacts
- Missing recording / cdr
New dialplan
[move-active-call]
exten => s,1,Noop(Custom context to move active calls)
same => n,Set(CT=${CALL_TYPE})
same => n,GotoIf($["${CT}"="2"]?inbound)
same => n,GotoIf($["${CT}"="3"]?outbound)
same => n,GotoIf($["${CT}"="1"]?internal)
same => n,Goto(end)
same => n(inbound),GotoIf($["${CALLERID(num)}"="${CALL_SOURCE}"]?end)
same => n,Set(extension_number=${CALL_DESTINATION})
same => n,Set(cid_num=${CALL_SOURCE})
same => n,Set(CTL=IN)
same => n,Goto(move)
same => n(outbound),Set(CT=2)
same => n,Set(CTL=IN)
same => n,GotoIf($[ $["${SRC_APP:0:2}"="FW"] & $["${CALL_ORIGIN}"="diversions"] ]?followme)
same => n,GotoIf($["${CALLERID(num)}"="${NTD}"]?end)
same => n,Set(extension_number=${CALL_SOURCE})
same => n,Set(cid_num=${CALL_DESTINATION})
same => n,Goto(move)
same => n(followme),Set(extension_number=${DIVERSION_ORIGIN})
same => n,Set(cid_num=${CALL_SOURCE})
same => n,Goto(move)
same => n(internal),Noop()
same => n,Set(CTL=LOCAL)
same => n,ExecIf($["${CALL_DESTINATION}"="${EXTENSION_TO_DIAL}"]?Set(extension_number=${CALL_SOURCE}):Set(extension_number=${IF($["${CALL_DESTINATION}"="${CALLEE}"]?${CALL_DESTINATION}:)}))
same => n,ExecIf($["${CALL_DESTINATION}"="${EXTENSION_TO_DIAL}"]?Set(cid_num=${CALL_DESTINATION}):Set(cid_num=${IF($["${CALL_DESTINATION}"="${CALLEE}"]?${CALL_SOURCE}:)}))
Same => n,GotoIf(${ISNULL(${extension_number})}?end)
same => n(move),Noop(Trying to move ${BRIDGEPEER} to another device for extension ${extension_number})
same => n,Set(cos=${DB(${TENANT_PATH}/extensions/${extension_number}/context)})
same => n,GotoIf(${ISNULL(${cos})}?end)
same => n,Originate(Local/ring_exten@move-active-call,exten,move-active-call,take_call,1,,av(bp=${BRIDGEPEER}^callSource=${cid_num}^callType=${CT}^ext=${extension_number}^cos=${cos}^callTypeLabel=${CTL}))
same => n(end),Return()
exten => ring_exten,1,Noop(Setting variables and calling extension)
same => n,Set(CALLERID(num)=${callSource})
same => n,Set(__CALL_TYPE=${callType})
same => n,Set(__CALL_TYPE_LABEL=${callTypeLabel})
same => n,Set(_CALL_TYPE_CONFIGURED=yes)
same => n,ExecIf($["${CALL_TYPE}"="2"]?Set(__INCOMING_SOURCE=${callSource}))
same => n,Goto(${cos},${ext},1)
exten => take_call,1,Noop(Bridging the call)
same => n,Bridge(${bp},x)
I’ve been meaning to thank you for this, this is great. We’ve done a little bit of testing and this does behave better. We’ll have clients start using it and post back here if we run into anything. This is a very slick feature to add.