Send other agents to a different context when multiple people are called

I hope I can explain this well enough…
Our agents are stored in a relational database, with various status codes available to them, and a companion desktop application for them to manage their status. Things like “Available”, “Lunch”, “Meeting”, “Training”, etc. When a call comes in, it looks for anyone in an available state and directs the call to them, and sets their status to “Inbound Call”. No answer, we put them to away, etc etc etc you get the idea.

Here’s the issue I’m trying to solve for. Team has requested a special emergency line (literal life and death thing), so that if a call comes in on that specific number, it jumps the queues, skips all menus, and just rings EVERYONE who is online (but not already on a call). I’ve got that solved, sure, but the problem with Dial() is it doesn’t continue until the call has ended.

At the start of the call, I set all online agents to “EMERGENCY CALL” status, so that no other call will come to them. However, when someone answers, I need to put the other agents back to their original state, so that they can continue to take normal calls. How can I do this when the Dial() application doesn’t continue until the call ends, and how can I know who answered the call? Please note, the agents are dialed purely through their IP:Port, we are not using asterisk contact lists.

I can figure out most likely how to tell which agent it is as long as Asterisk tells me the IP that answered, but right now the big hangup is how do I let the other agents get back to whatever status they were in while the call is still happening?

If I understand what you are doing, use local channels, set to not optimise out.

Forgive me, I inherited this from another guy that left the company. I’ve been coding for it for about a year, but that’s been primarily in php / agi…

Right now for this I’m using Dial(sip&sip&sip&sip) (I mean, a couple other options too but)
I’m not quite understanding what you mean about “not optimise out”

-- Executing [2015551234@company:2] AGI("SIP/10.123.123.123-00000084", "company/session_id.agi") in new stack
-- Launched AGI Script /var/lib/asterisk/agi-bin/company/session_id.agi
-- <SIP/10.123.123.123-00000084>AGI Script company/session_id.agi completed, returning 0
-- Executing [2015551234@company:3] AGI("SIP/10.123.123.123-00000084", "company/agi.session_creation.php") in new stack
-- Launched AGI Script /var/lib/asterisk/agi-bin/company/agi.session_creation.php
-- <SIP/10.123.123.123-00000084>AGI Script company/agi.session_creation.php completed, returning 0
-- Executing [2015551234@company:4] GotoIf("SIP/10.123.123.123-00000084", "1?vipline,bypass,1") in new stack
-- Goto (vipline,bypass,1)
-- Executing [bypass@vipline:1] AGI("SIP/10.123.123.123-00000084", "company/cdr_log.agi,0e93cd94-9ce8-4078-a454-c049b4932f9f,application_update,,"vipline called"") in new stack
-- Launched AGI Script /var/lib/asterisk/agi-bin/company/cdr_log.agi
-- <SIP/10.123.123.123-00000084>AGI Script company/cdr_log.agi completed, returning 0
-- Executing [bypass@vipline:2] Set("SIP/10.123.123.123-00000084", "session_status=Hangup - Normal") in new stack
-- Executing [bypass@vipline:3] Goto("SIP/10.123.123.123-00000084", "queue,vipline,1") in new stack
-- Goto (queue,vipline,1)
-- Executing [vipline@queue:1] AGI("SIP/10.123.123.123-00000084", "company/queue_all_agents.agi,0e93cd94-9ce8-4078-a454-c049b4932f9f,932616e3-35a8-41ab-b4db-77c8df04e766") in new stack
-- Launched AGI Script /var/lib/asterisk/agi-bin/company/queue_all_agents.agi
-- <SIP/10.123.123.123-00000084>AGI Script company/queue_all_agents.agi completed, returning 0
-- Executing [vipline@queue:2] Set("SIP/10.123.123.123-00000084", "session_status=Abandoned - Waiting in queue") in new stack
-- Executing [vipline@queue:3] MixMonitor("SIP/10.123.123.123-00000084", "0e93cd94-9ce8-4078-a454-c049b4932f9f.wav,b") in new stack
-- Executing [vipline@queue:4] AGI("SIP/10.123.123.123-00000084", "company/get_caller_id.agi,") in new stack
-- Executing [vipline@queue:5] Set("SIP/10.123.123.123-00000084", "CALLERID(name)=EMERGENCY CALL") in new stack
-- Executing [vipline@queue:6] Set("SIP/10.123.123.123-00000084", "startTime=2024-01-26T20:39:00") in new stack
-- Executing [vipline@queue:7] Dial("SIP/10.123.123.123-00000084", "SIP/10.321.MY.IP:PORT&SIP/10.321.ANOTHER.AGENT:PORT,60,mg") in new stack

As you can, on the last line, I dial 2 agents. I want (as an example) - I pick up, asterisk tells me the call was picked up, and who got it, so I can set the other agents back to a normal status.

Currently, the dialplan doesn’t go anywhere until the call ends, so all agents are stuck on the “EMERGENCY CALL” status, and can’t receive other calls

Dial(Local/xxxxx/n&Local/yyyyy/n&Local/zzzzz/n)

Read up on local channels for more. The local channel hangup handlers will run when the outgoing call is stopped on the channel, not when the top level Dial application exits.

Hmm. Not sure how this would work, since local dials into the dialplan… I currently have an agi returning a list of SIP addresses, as they are dynamic. Could be one, could be 20. I’m not seeing a way I can pass the SIP address to the local channel when using this option… If I could simply pass at least an integer (index for array) then have the local channel collect the SIP address from that array using AGI, or if there is a way to pass the SIP address to the local channel, that may work.

The example I’m looking at here: Local Channels
shows static addresses to dial. I’m not sure how to do this with a dynamic list

I just found the functions FIELDQTY and CUT, I’ll look into using those. I’ll set a field with the SIP addresses separated by a comma, then build my Dial( string in the agi to something like Local/channel_1/n&Local/channel_2/n… etc. I’ll have up to 20 max, and build up to channel_20 in the dialplan, and have them all route to the same handler… that might work

In reality, if it actually gets up to 20 people available to take said call… Someone had better answer lol. I even modified the CALLERID(name) to “EMERGENCY CALL” so they have no excuse for not answering

Okay finally coming back to this part -
So, I used /n, but I’m still losing my variables.

dialplan:

 ;Ring list
 same => n,Noop(${sip_list})
 same => n,Dial(${dial_list},60,mg)

dial_list is ‘Local/channel1@vipline/n’
now in channel1:

exten => channel1,1,Noop(Dialing channel 1)
 same => n,Noop(${sip_list})

Output:

-- Executing [bypass@vipline:8] NoOp("SIP/0.0.0.0-00000088", "1.1.1.1:61206") in new stack
-- Executing [bypass@vipline:9] Dial("SIP/0.0.0.0-00000088", "Local/channel1@vipline/n,60,mg") in new stack
-- Called Local/channel1@vipline/n
-- Started music on hold, class 'default', on channel 'SIP/0.0.0.0-00000088'
-- Executing [channel1@vipline:1] NoOp("Local/channel1@vipline-00000001;2", "Dialing channel 1") in new stack
-- Executing [channel1@vipline:2] NoOp("Local/channel1@vipline-00000001;2", "") in new stack

I have four variables, three of which are needed for this to work:
agent_list - list of agent ids
sip_list - list of sip addresses for Dial()
stat_list - the original status of the agent, so I can put it back if someone else answers

Okay, update, I figured out a crucial piece of information I was not aware of before.
I’m setting the variables with __var now, so they are being inherited by the spawned channels from the main.