Call Tranfsers

Where is the dialplan for warm (*2) and blind (##) configuration?

I was thinking I could use the extensions_override config to address two issue:

  1. Give more time to dial the transfer to number before the timeout path occurs.

  2. Trying to figure out a way to cause the transfer to “let go” of the agent (virtual extensions, mobile phone, via FMFM, yes + ringinuse=no) so the agent can take the next call WITHOUT having to wait for the transferred call to disconnect from Asterisk

Assuming that the queue does not call the virtual extension again, is because the local queue channel is in use, so you may want to try redirect the caller’s channel by using ChannelRedirect() in your dialplan along with a custom dynamic feature.

In /etc/asterisk/features_featuremap_custom.conf add the following:

[applicationmap](+)
ccredirect => #48,self/caller,Gosub(chan-redirect,s,1)

Then, you will need to add that custom dynamic feature to the incoming calls, you can either do it on the Trunk or send the calls to a custom context prior to sending to the queue.

in extensions_custom.conf

[add-custom-dynamic-feature]
exten => s,1,Noop(Entering custom context ${CONTEXT} to add the dynamic feature)
exten => s,n,Set(__DYNAMIC_FEATURES=ccredirect)
exten => s,n,Return()

Then modify the below dialplan to fit your needs

[chan-redirect]
exten => s,1,Noop(Entering custom context ${CONTEXT} to add the transfer the call)
exten => s,n,Read(ext_to_transfer,custom/please-enter-ext-number,4,,2,5) ; this should ask them to enter the extension number. I allowed 4 digits, change to whatever fits your needs.
;Here you can ask the person to confirm what they entered is correct by playing back to them the variable with SayDigits()
;You can also validate to make sure that the extension they want to transfer to exists in the DB by using the DB_EXISTS function
;Once you are sure that it will be transferred to the right destination, allow the call to the next line 
exten => s,n,ChannelRedirect(${BRIDGEPEER},from-internal,${ext_to_transfer},1)
exten => s,n,Return()

Note: I tested this on calls that were not routed through a queue and it works. It might need some adjustments. Please keep us updated with your trouble/findings…

If you get a bonus this month, remember why :wink:

3 Likes

Awesome @PitzKey. I will try this out today, and report back. Looks like exactly what I need.

@PitzKey, How do I do this? I have added to /etc/asterisk/features_featuremap_custom.conf and extensions_custom.conf but how do I do it with the trunk? I also realize I don’t know how to do the custom context either. I have used custom destinations plenty of times before, but I am not sure how to hit the [add-custom-dynamic-feature] and then carry on to the original destination (the queue).

Right now when I dial #48 nothing happens (the audio goes silent for a second, then I hear the #48 key presses, and nothing happens), but I am thinking I am missing this step.

Thanks again for carrying me across the finish line here. This is the last part of the build that needs resolving.

Update: Got it working by hard-coding a destination into the [add-custom-dynamic-feature] context. Now I can put the custom destination on the inbound route and still get to where I am going. Clunky, but good enough for testing with the queue. I can refine it after I know it works.

I read a bit more and see there is a context component on the PJSIP Trunk, which This box doesn’t have yet (I know, I know). and Tried to look into the custom context module, but have no idea how that works and I do not see a wiki for it.

Update2: It works with queues! @PitzKey you rock! :slight_smile:

By using #48, the answering agent can transfer the call, and immediately be available for the next queue call.

Where I am stuck now is:

  1. The current experience is to press #48, enter the extension, and the “transfer” completes. Is there a way to emulate something closer to a warm transfer: press #48, enter the extension, connect with the transfer number, talk to them, then press some button to finish the “transfer”?

  2. How to call the context more efficiently. I would like to apply it to chan sip trunk so I do not have to build anything into the [add-custom-dynamic-feature context] to help route the call.

Any ideas?

I wanted to respond on Friday but I got busy, sorry about that.

Let’s say you have option 7 in your IVR going to a queue, then I would create a custom destination that has add-custom-dynamic-feature,s,1 as the target, enable the return option and set the queue as the destination. I would do it that way, but adding it on the Trunk level would work as well, but I’d add some more security checks so not everyone can dial #48

To do it on the Trunk level, change the incoming context to add-custom-dynamic-feature and then change the dialplan in extensions_custom.conf to the following:

[add-custom-dynamic-feature]
exten => _.,1,Noop(Entering custom context ${CONTEXT} to add the dynamic feature)
exten => _.,n,Set(__DYNAMIC_FEATURES=ccredirect)
exten => _.,n,Goto(from-pstn,${EXTEN},1)

Regarding doing this with attendant/warm transfer, I’ll have to think of an idea how to achieve this. It’s probably doable as well. You’ll likely have to dump the caller into a temp bridge and then redirect the channel or merge the bridge based on if they want to accept the call.

1 Like

This change let me put it in the trunk. Besides the warm transfer functionality, I think we are almost there. The only other issue I am having is that the caller (customer) and callee(queue agent) can both use #48. The caller (customer) cannot use ## or *2, it just seems to be #48.

Any idea on what needs to be adjusted in the dialplan to stop the caller(customer) from using #48?

Is it the self/caller component of [applicationmap](+)?

Thanks!

To restrict access to only extensions that exist on the PBX, which was touched on here:

you can try the following.

[chan-redirect]
exten => s,1,Noop(Entering custom context ${CONTEXT} to add the transfer the call) 
exten => s,n,Set(FM_user=${CUT(UNIQCHAN,@,1)})
exten => s,n,GotoIf($["${DB_EXISTS(AMPUSER/${CUT(FM_user,/,2)}/cidnum)}" != "1"]?done)
exten => s,n,Read(ext_to_transfer,custom/please-enter-ext-number,4,,2,5)
exten => s,n,ChannelRedirect(${BRIDGEPEER},from-internal,${ext_to_transfer},1) 
exten => s,n(done),Return() 

Or a bit shorter, but I am not sure if it will always work:

[chan-redirect]
exten => s,1,Noop(Entering custom context ${CONTEXT} to add the transfer the call) 
exten => s,n,GotoIf($["${DB_EXISTS(AMPUSER/${RG_IDX}/cidnum)}" != "1"]?done)
exten => s,n,Read(ext_to_transfer,custom/please-enter-ext-number,4,,2,5)
exten => s,n,ChannelRedirect(${BRIDGEPEER},from-internal,${ext_to_transfer},1) 
exten => s,n(done),Return()
1 Like

No dice :frowning:

When implemented, neither the agent (answering the call from their cellphone via FMFM) nor the caller can access #48. When pressing #48, you hear the key press, but nothing happens.

The call log shows:
[2021-03-15 20:59:15] VERBOSE[23568][C-0002ad0b] pbx.c: Executing [s@chan-redirect:1] NoOp("SIP/AVAYA-#-########", "Entering custom context chan-redirect to add the transfer the call") in new stack

[2021-03-15 20:59:15] VERBOSE[23568][C-0002ad0b] pbx.c: Executing [s@chan-redirect:2] Set("SIP/AVAYA-#-########", "FM_user=SIP/AVAYA-#-########") in new stack

[2021-03-15 20:59:15] VERBOSE[23568][C-0002ad0b] pbx.c: Executing [s@chan-redirect:3] GotoIf("SIP/AVAYA-#-########", "1?done") in new stack

On my PBX it is:

Executing [s@chan-redirect:2] Set("SIP/from-yplab-00000052", "FM_user=Local/501") in new stack

So it looks for AMPUSER/501/cidnum Can you modify your dialplan to the below and then post a call trace via pastebin?

[chan-redirect] 
exten => s,1,Noop(Entering custom context ${CONTEXT} to add the transfer the call) 
exten => s,n,Set(FM_user=${CUT(UNIQCHAN,@,1)}) 
exten => s,n,DumpChan()
exten => s,n,GotoIf($["${DB_EXISTS(AMPUSER/${CUT(FM_user,/,2)}/cidnum)}" != "1"]?done) 
exten => s,n,Read(ext_to_transfer,custom/please-enter-ext-number,4,,2,5) 
exten => s,n,ChannelRedirect(${BRIDGEPEER},from-internal,${ext_to_transfer},1) 
exten => s,n(done),Return()

I feel silly! To speed things up, I was calling an extension directly (vs. through a queue) to test. When I tried a call through a queue, it worked correctly (the agent could #48, the caller could not).

When I call the virtual extension directly, that is when I get the strangeness. Since all the calls will originate via the queue, I think this is okay.

The only piece left is to see if there is a way to replicate an attended transfer.

@PitzKey, have you had anytime to think about this? We have everything wrapped up but this last piece (warm transfer from a queue). They are going live at the end of next week. I really appreciate the help and once we are launched I think I am going to do a write up on remote call centers to originate all this into one post for future readers.

Thanks again for any insights!

Refresh my memory. How does attendant transfer work?
Once the transferee (is that even the right term?) Is OK to accept the call, does the caller get bridged, or does it start ringing?

Attendant transfer (*2)

  • Agent is talking with a customer from a queue call
  • Agent presses *2
  • Customer put on hold
  • Agent hears enter extension number
  • Agent enters extension number
  • Agent connects with transfer to party and provides any relevant information
  • Agent hangs up the call, which causes the customer to be connected to the transfer to party, and the agent falls off

Being able to replicate this, in a way that lets the remote (cellphone FMFM) agent take the next call, like you can do with #48 (above), is the goal.

The above and beyond would be including someway that the agent can disconnect from the transfer to party and go back to customer. This would be used if the transfer party didn’t pick up the phone or didn’t connect quite right. The agent could get back to the agent, and try something else.

I tried reproducing this, but it seems that it does not work that way. You must press *2 again to connect the caller with the person you wish to transfer the call to.

Unless I missed something?

FWIW, I think you can do it both ways. Regardless, we would follow any procedure that allowed a remote agent to do an attended transfer AND let them be available for the next queue call as soon as the transfer was complete. :slight_smile:

Understood. Not sure I will have time this week. Maybe next week.

I did a little more searching and found the above. This looks almost perfect, except that it would channel redirect the caller right away (before the consult with the transfer to party). I think this will flag the agent as available and queue calls would begin to route.

[macro-nway-start]
 exten => s,1,Set(CONFNO=${FindFreeConf()})
 exten => s,n,ChannelRedirect(${BRIDGEPEER},dynamic-nway,${CONFNO},1)
 exten => s,n,Read(DEST,dial,,i)
 exten => s,n,Set(DYNAMIC_FEATURES=nway-inv#nway-noinv)
 exten => s,n,Dial(Local/${DEST}@dynamic-nway-dest,,g)
 exten => s,n,Set(DYNAMIC_FEATURES=)
 exten => s,n,Goto(dynamic-nway,${CONFNO},1)

instead of step 2, is there a way to put the caller on hold or stasis, until you press **? Then the transfer to goes to conference first, you go back to the caller, then you channel redirect the caller to the conference and disconnect.

Once the original callers channel redirect occurs, you would start ringing for the next call.

Down to the wire here, and I know PitzKey is busy this week. I came up with a new approach I think can work.

Idea:
I want to change the hint at the time of the transfer (right before the agent’s cell phone gets hung up on). Basically flip the hint that is stopping the next queue call coming. Move it from inuse to free (or the equivalent).

Questions:
What hint is it? What hint is asterisk reading to see :
Local/2171@from-queue/n (ringinuse disabled) (dynamic) (In use)
or
Local/2171@from-queue/n (ringinuse disabled) (dynamic) (Not in use)

Example queue:5555
Example agent: 2171
Reminder: These are all virtual extensions to cell phones using FMFM with the queue set to skip busy: Yes + (ringinuse=no)

I’ve tried to look though the hints myself, but db show but there are a lot (a lot!).

I’ve see some posts from @lgaetz and @cynjut on hint manipulation, do one of you know?

Thanks in advice!