Inbound post-call configuration hook

I’m writing a custom AGI that would send call recordings and call information after each call to a webhook. It does work as intended for all outgoing calls. I’m now focusing on inbound.

For outbound, the logic I used (thanks forums) was to Set(CHANNEL(hangup_handler_push) inside [macro-dialout-trunk-predial-hook], add MixMonitor() and work from there.

For inbound, all information I found consistently suggests using custom destinations. The way I understood it is:

  • Create a custom destination
  • Add configuration to custom destination (i.e. CHANNEL(hangup_handler_push) )
  • Set incoming route to custom destination

However, this does not seem ideal for me as I’ll need to manage several different queues and it seems to me that I will have to set return to Yes and indicate a queue in custom destination.

Is that piece correct? Because if so, I will need to create so many custom destinations with exactly the same custom configuration just so they can point back at the correct queue (right now I I have queues set directly in each incoming route).

Is there a general configuration file I can edit/set for incoming routes that would be always processed at the end of any incoming calls?

You could write one ‘context’ that looks-up appropriate variables previously stored associatively in the sqlite3 astdb . i.e. DID’s associated with particular queue or agent, hangup handler or whatever is logical in your use case

Right now the association between Queue and DID is done at the inbound route level. However, If I point the inbound route to a custom destination I will lose that. Would there be any other place I could set that relationship via GUI? I’m concerned at hardcoding that into the custom destination as those may get changed relatively often.

I will then have to find a way to also tie individual numbers (ie. not queues) to the same behavior.

Why did you need to add MixMonitor there?

Why would you lose that association, maybe get clever with ChanDump()

The user case is to to attach the recording of every call (incoming/outgoing) with the webhook data (from, to, extension, duration, billable seconds etc.). I am absolutely open to change this further if there’s a better way.

I initially tried using AMI but cdr would not include a recording filename among other issues. So I then tried output my own custom event (and switched to AGI). In the process, and looking at the forum (sorry I can’t find the reference), it was suggested that cdr may be called before the standard mixmonitor would finish, preventing a filename to be output. So I added one myself and it worked. It works well for outbound calls, and also allowed be to be in full control of filename etc.

Why, if Mixmonitor was not needed there would be an answer for a post-incoming-call hook?

Could you elaborate please?

What I meant is that right now I specify which queue to go to in each incoming route. But if I have to set that incoming route to point to a custom destination instead of the queue, the queue information will no longer be found in the incoming route itself.

No, neither the cdr record nor any AMI event can refer to a un-closed call until it is closed for obvious reasons ;l-), you will need to use the hangup handler for either bridged channel

If you’re already recording calls, MixMonitor has been initiated. All you need to do is set MIXMON_POST and as long as that is set MixMonitor will execute it after each recording as if you set the command option in MixMonitor

In the globals_custom.conf file you add:

MIXMON_POST = /path/to/your/script ^{VAR1} ^{VAR2} ^{VAR3}

Apologies I’m new to this, if I have to have this triggered end of each call, where would I put t and how do I trigger it (unless it triggers by itself) so it happens at the end of each incoming call?

exten => h,1,NoOp(Call has ended - custom_incoming called)

In looking at the forum I this I read that extension_custom.conf was not the right place because in a queue/ring group situation this would be triggered for every sub-call (i.e. each member of the ring group,not only the actual call).

Thanks, that helps. Could you please give me some additional pointers.

Currently my script for outgoing does something like this:
1 Gets call record (time, callers, etc.) and recording filename
2 Checks if filename exists and gets the file content
3 Output the whole thing including file via webhook

If I use MIXMON_POST as suggested I guess it’ll become something like this:
1 Gets call record (time, callers, etc.)
2 Gets MIXMON_POST on a different instance
3 Need to look somewhere to establish a relation between recording and call record
4 Output the whole thing including file via webhook

How would you structure 3? Looking in some db by uniqueid?

Or, would it work if I do something like this to rename and move the recording and I add a uniqueid to the name so the current script works the same:
1 Gets call record (time, callers, etc.) and expected recording filename
2 separate script renames file in line with 1
3 Checks if filename exists and gets the file content
4 Output the whole thing including file via webhook

The recording already has the uniqueid for the channel in it. Have you reviewed how call recordings are named and what variables make up the filename? The relation between the call recording and the CDR is the uniqueid that is generated by the system.

What does this mean? What is the difference instance?

I thought you meant to suggest to use MIXMON_POST to send just the file to my script, which therefore would have to account for the file sent at that point, and couple it somehow with the call information from the hangup handler. I think this is the wrong understanding.

Are you suggesting to literally use MIXMON_POST as THE way to get all data from the system? Something like:

1 Ensure Recordings are enabled in relevant outbound/inbound routes
2 Edit MIXMON_POST in globals_custom_conf to pass all call related variables
3 Configure script to get both file and call data and shoot out webhook

Like this?

MIXMON_POST = /path/to/your/script ^{MIXMONITOR_FILENAME} ^{CALL_DIRECTION} ^{CALLERID(num)} ^{CDR(disposition)} ^{CDR(accountcode)} ^{CALLERID(name)} ^{FROMEXTEN} ^{EXTEN} ^{OUTNUM} ^{CDR(start)} ^{CDR(end)} ^{CDR(duration)} ^{CDR(billsec)} ^{CHANNEL} ^{CHANNEL_ANSWER} ^{CDR(uniqueid)} ^{CHANNEL(VM_INFO)} ^{CHANNEL(VM_DUR)} ^{CHANNEL(VM_MSGPATH)}

Did you make a bunch of custom changes and add a bunch of variables? Both in dialplan and the cdr structure?

Originally I was trying AMI, so yes it was custom cdr. But AMI wasn’t working for this so I tried AGI. So for AGI no, I did not add custom cdr events, but yes, all is currently triggered and dealt with in the dialplan (for outgoing).

However, the variables listed above are all variables I need to get out of the system (together with recording) and send via webhook.

exten => s,1,NoOp(Call has ended - custom_AMI_outgoing called)
exten => s,n,Set(CALL_FROM=${CALLERID(num)})
exten => s,n,Set(CALL_DISPOSITION=${CDR(disposition)})
exten => s,n,Set(CALL_ACCOUNT_CODE=${CDR(accountcode)})
exten => s,n,Set(CALL_HANDLED_BY_NAME=${CALLERID(name)})
exten => s,n,Set(CALL_TO=${OUTNUM})
exten => s,n,Set(CALL_START_TIME=${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M:%S)})
exten => s,n,Set(CALL_ANSWER_TIME=${IF($[${ANSWEREDTIME} != "" ]?${STRFTIME(${ANSWEREDTIME},,%Y-%m-%d %H:%M:%S)})})
exten => s,n,Set(CALL_END_TIME=${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M:%S)})
exten => s,n,Set(CALL_DURATION=${CDR(duration)})
exten => s,n,Set(CALL_BILLABLE_SECONDS=${CDR(billsec)})
exten => s,n,Set(CALL_CHANNEL=${CHANNEL})
exten => s,n,Set(CALL_UNIQUEID=${CDR(uniqueid)})
exten => s,n,Set(OUTGOING_REC_FILENAME=${outgoing_rec_filename})
exten => s,n,Return

(I was planning to get rid of the variable set() and put all system variables directly in AGI() once I verified it was working)