Termination Attempt
Introduction
A SIP call-control Lua script using LhoSipIncallLuaService or LhoSipOutcallLuaAgent may request that an attempt be made to terminate to a B-Leg using an outbound SIP INVITE Request.
If any internal Media Server or external SRF is currently connected to the A-Leg as a result of previous interactions, it will be disconnected prior to the B-Leg termination attempt.
If the B-Leg is successfully established, the SIP framework will connect it to the A-Leg
using either SIP INVITE Final Response 200 OK or SIP re-INVITE Request.
There are three distinct modes for a Termination:
- Termination Attempt without Monitoring or Charging.
- Termination Attempt with Monitoring of answered call.
- Termination Attempt with Charging of answered call.
In the simplest case (no monitoring, no charging) the termination is attempted with four possible outcomes.
- The A-Leg abandons the call. The Lua script resumes control but can no longer interact with the call.
- The B-Leg is answered. The Lua script resumes control but can no longer interact with the call.
- The B-Leg rejects the call or does not answer. The Lua script resumes control of the call.
- A SIP processing error occurs. The Lua script resumes control but can no longer interact with the call.
The second outcome is different if Monitoring is requested:
- The B-Leg is answered. The Lua script resumes control and must read monitor reports for the call.
The second outcome is also different if Charging is requested:
- The B-Leg is answered. The Lua script resumes control and must read charge reports for the call and grant extensions.
If a Monitored or Charged call is answered by the B-Leg, the Lua script will be able to resume control of the call if the B-Leg subsequently hangs up but the A-Leg remains. Otherwise if the A-Leg hangs up, the B-Leg will be disconnected, and the Lua script will resume control but can no longer interact with the call.
If a call that is not Monitored or Charged is answered by the B-Leg, the Lua script will resume control but can no longer interact with the call.
The LhoSipLuaService Termination API
.termination_attempt [Asynchronous]
This method provides full access to the Termination mechanism and is provided for use by custom service developers. In the majority of scenarios, one of the subsequently-described convenience methods should be sufficient and preferable. However, this full-featured alternative is provided for use by complex or non-standard services.
NOTE: If this method returns result.answered == true and result.monitored == truethen your service logic must invokesip_incall_api.monitor_checkuntil the call is no longer monitored or the logic decides to end the call (using the.hangup` method or ending the script).
NOTE: If this method returns result.answered == true and result.charged == true then your
service logic must invoke sip_incall_api.charge_check and sip_incall_api.charge_extend
alternately until the call is no longer charged or the logic decides to
end the call (using the .hangup method or ending the script).
This method takes a single details parameter which is a Lua table with the following structure:
| Field | Type | Description |
|---|---|---|
details
|
Table | [Required] The detailed SIP parameters for the message. |
.address_digits
|
(+)Hex String |
[Required] The userinfo part of the INVITE Request URI address.The protocol and domain parts of the address will be determined automatically. The applicable configured called_party denormalisation on the LhoSipApp will be applied.
|
.calling_party
|
(+)Hex String |
The userinfo part of the INVITE Request From header address.The protocol and domain parts of the address will be determined automatically. The applicable configured calling_party denormalisation on the LhoSipApp will be applied.Set to UNDEF to suppress the network-supplied presented calling party (if any).This parameter will have no effect if presentation of the calling party is restricted. (Default = for an A-Leg initiated by an outbound INVITE Request, the A-Leg presented called party; for an A-Leg initiated by an inbound INVITE Request, the A-Leg presented calling party). |
.is_calling_restricted
|
Boolean |
Specify whether presentation of the calling party should be restricted. This parameter will have no effect if:
From and Contact
headers will be anonymous, and a Privacy header containing the id
flag will be included. Other flags from any Privacy headers in the A-Leg INVITE Request
or Response will be included in the B-Leg INVITE Request Privacy header.When not restricted, the B-Leg INVITE Request From and Contact headers will
not be anonymous, and a Privacy header will not be included.(Default = for an A-Leg initiated by an inbound INVITE Request, the restriction requested by the calling party; for an A-Leg initiated by an outbound INVITE Request, the restriction requested by the called party). |
.original_called_party
|
(+)Hex String |
The userinfo part of the INVITE Request To header address.The protocol and domain parts of the address will be determined automatically. The applicable configured called_party denormalisation on the LhoSipApp will be applied.(Default = use the .address_digits parameter).
|
.no_answer_timeout
|
Positive Integer |
Specifies the desired time limit for INVITE Request processing in seconds. The LhoSipApp will enforce a maximum bound for this value.A CANCEL Request will be sent if a Final Response is not received within this time. (Default = use the default_no_answer_secs configured on the LhoSipOutcallLuaAgent or LhoSipIncallLuaService).
|
.extra_headers
|
Table |
Additional user headers to include in the SIP INVITE Request. The table keys are header names. The table values are tables of header values. (Default = do not add extra user headers). |
.max_call_secs
|
Positive Integer |
Specifies the desired maximum permitted call duration in seconds. The LhoSipApp will enforce minimum and maximum bounds for this value.(Default = use the max_call_secs configured on the LhoSipApp).
|
.monitored
|
Boolean |
Set this to true to indicate that this is a "Monitored" call attempt.Only one of .monitored or .charged may be set to true.If this call attempt is answered, the service logic must use the .monitor_check
method to monitor the call until it completes.SIP re-INVITE Requests will be sent to both the A-Leg and B-Leg at intervals specified by .monitor_interval_secs to check that the call is still active.
Corresponding monitor reports will be sent to the service logic.(Default = false, the call is not monitored).
|
.monitor_interval_secs
|
Positive Integer |
Specifies the desired interval in seconds between the SIP re-INVITE Requests / monitor reports. The LhoSipApp will enforce minimum and maximum bounds for this value.Valid only when .monitored is true.(Default = use the activity_interval_secs configured on the LhoSipApp).
|
.charged
|
Boolean |
Set this value to indicate that this is a "Charged" call attempt. Only one of .monitored or .charged may be set to true.If this call attempt is answered, the service logic must use the .charge_check and
.charge_extend methods to authorise extensions on the charged call until it completes.SIP re-INVITE Requests will be sent to both the A-Leg and B-Leg at the end of grant periods to check that the call is still active. Corresponding charge reports will be sent to the service logic. (Default = false, the call is not charged).
|
.grant_secs
|
Positive Integer |
[Required if .charged is true] Specifies the desired period in
seconds from when the call attempt is answered until the initial SIP re-INVITE Requests / charge report.The LhoSipApp will enforce minimum and maximum bounds for this value.Valid only when .charged is true.
|
The termination_attempt method returns a Lua table with the following attributes.
| Attribute | Type | Description |
|---|---|---|
.controlled
|
Boolean |
[Required] Is this call still controlled right now? This value being true indicates that (at least some) telephony API actions can be performed by service logic.Note that in some cases the available control actions may be limited. |
.answered
|
Boolean |
[Required] Was this call answered? This value being true indicates that the A-Leg to B-Leg setup was successfully completed.
|
.monitored
|
Boolean |
[Required] Is this call monitored? This value will be true when "Monitored" termination was requested, and .answered is true.Only one (or neither) of .monitored or .charged will be true.
|
.charged
|
Boolean |
[Required] Is this call charged? This value will be true when "Charged" termination was requested, and .answered is true.Only one (or neither) of .monitored or .charged will be true.
|
.proceed_ok
|
Boolean |
[Required] Can the service logic still use the .proceeding method?This value will be true when .controlled is true,
we have not yet sent a Final Response, and an SDP Offer would not be required to proceed.
|
.decline_ok
|
Boolean |
[Required] Can the service logic still use the .decline method?This value will be true when .controlled is true and
we have not yet sent a Final Response.
|
.reason
|
No Route / Declined / No Answer / Answered / Abandoned
|
[Required] The reason why the termination attempt ended. |
.code
|
Integer |
A SIP Final Response code (in the range 200-699) associated with the B-Leg termination attempt.This value is present only when the B-Leg termination attempt received a SIP INVITE Final Response. (Default = not present, a Final Response was not received). |
.ring_dsm
|
Integer |
The ring-time duration in deci-seconds, as measured by the LhoSipApp.This value is present only when .answered is true.(Default = not present, .answered is false).
|
.max_call_secs
|
Positive Integer |
The actual maximum permitted call duration in seconds. This may differ from the requested value because the LhoSipApp applies a default, and minimum and maximum bounds.This value is present only when .answered is true.(Default = not present, .answered is false).
|
.monitor_interval_secs
|
Positive Integer |
The actual monitor interval in seconds. This may differ from the requested value because the LhoSipApp applies a default, and minimum and maximum bounds.This value is present only when .monitored and .answered are true.(Default = not present, .monitored or .answered are false).
|
.grant_secs
|
Positive Integer |
The actual first grant duration in seconds. This may differ from the requested value because the LhoSipApp applies minimum and maximum bounds.This value is present only when .charged and .answered are true.(Default = not present, .charged or .answered are false).
|
If the A-Leg abandons before the B-Leg answers, the result will be:
{ controlled = false, answered = false, monitored = false, charged = false, proceed_ok = false, decline_ok = false, reason = "Abandoned" }
Otherwise if the B-Leg is not answered, the result will always include:
{ controlled = true, answered = false, monitored = false, charged = false, proceed_ok = <boolean>, decline_ok = <boolean>, reason = <No Route/No Answer/Declined> }
The result may include code = <300-699> if a Final Response was received from the B-Leg.
If the B-Leg is answered, the result will always include:
{ answered = true, proceed_ok = false, decline_ok = false, reason = "Answered", code = <200-299>, ring_dsm = <integer>, max_call_secs = <integer> }
If the B-Leg is answered for a call attempt that is not monitored or charged, the result will also include:
{ controlled = false, monitored = false, charged = false }
If the B-Leg is answered for a monitored call attempt, the result will also include:
{ controlled = true, monitored = true, charged = false, monitor_interval_secs = <integer> }
If the B-Leg is answered for a charged call attempt, the result will also include:
{ controlled = true, monitored = false, charged = true, grant_secs = <integer> }
Example (connection attempt to called party with a prefix, 60 second no-answer timeout, custom header):
local n2svcd = require "n2.n2svcd"
local incall_api = require "n2.n2svcd.sip_incall_service"
local sip_incall = ...
local result = incall_api.termination_attempt ({
address_digits = '1703' .. sip_incall.normalised_called_party,
no_answer_timeout = 60,
extra_headers = {
'ChargeRef' = { 'XX-001234' } -- Header values must be contained in a list.
}
})
if (result.answered) then
n2svcd.notice ("CALL ANSWERED = YES")
else
if (result.controlled) then
n2svcd.notice ('Controlled after Reason = %s', result.reason)
if (result.decline_ok) then
incall_api.decline (633)
else
incall_api.hangup ()
end
else
n2svcd.notice ('Control Lost after Reason = %s', result.reason)
end
end
return
Example (monitored connection attempt to called party with a prefix, 10 minute maximum talk-time, 60 second monitor interval):
local n2svcd = require "n2.n2svcd"
local incall_api = require "n2.n2svcd.sip_incall_service"
local sip_incall = ...
local result = incall_api.termination_attempt ({
monitored = true,
address_digits = '1703' .. sip_incall.normalised_called_party,
max_call_secs = 600,
monitor_interval_secs = 60
})
-- When a monitored call is answered, we must sweep for monitor events.
if (result.answered) then
repeat
result = sip_incall_api.monitor_check ()
until (not result.monitored)
end
return
Example (charged connection attempt to called party with a prefix, 10 minute maximum talk-time, 60 + 30 + 30 + end):
local n2svcd = require "n2.n2svcd"
local incall_api = require "n2.n2svcd.sip_incall_service"
local sip_incall = ...
local result = incall_api.termination_attempt ({
charged = true,
address_digits = '1703' .. sip_incall.normalised_called_party,
max_call_secs = 600,
grant_secs = 60
})
-- When a charged call is answered, we must sweep for charge events and extend.
-- We grant 30 + 30 then no more
--
if (result.answered) then
local ngrants = 0
while (true) do
result = sip_incall_api.charge_check ()
if (not result.charged) then break end
ngrants = ngrants + 1
if (ngrants <= 2) then
sip_incall.charge_extend (30)
else
sip_incall.hangup ()
break
end
end
end
return
.connect_attempt [Asynchronous]
This helper method provides a flattened-argument version of the termination_attempt method.
The connect_attempt method takes the following arguments:
| Field | Type | Description |
|---|---|---|
called_party
|
(+)Hex String |
[Required] The userinfo part of the INVITE Request To header address.The protocol and domain parts of the address will be determined automatically. The applicable configured called_party denormalisation on the LhoSipApp will be applied.
|
no_answer_timeout
|
Positive Integer |
Specifies the desired time limit for INVITE Request processing in seconds. The LhoSipApp will enforce a maximum bound for this value.A CANCEL Request will be sent if a Final Response is not received within this time. (Default = use the default_no_answer_secs configured on the LhoSipOutcallLuaAgent or LhoSipIncallLuaService).
|
max_call_secs
|
Positive Integer |
Specifies the desired maximum permitted call duration in seconds. The LhoSipApp will enforce minimum and maximum bounds for this value.(Default = use the max_call_secs configured on the LhoSipApp).
|
The connect_attempt method returns the same table structure as termination_attempt.
Example (connect to called party with a prefix, 60 second no-answer timeout):
local n2svcd = require "n2.n2svcd"
local incall_api = require "n2.n2svcd.sip_incall_service"
local sip_incall = ...
local result = incall_api.connect_attempt ('1703' .. sip_incall.normalised_called_party, 60)
if (result.answered) then
n2svcd.notice ("CALL ANSWERED = YES")
end
return
.connect_monitored [Asynchronous]
This helper method provides a flattened-argument version of the termination_attempt method for the “Monitored” call mode.
NOTE: If this method returns result.answered == true then your service logic must invoke
sip_incall_api.monitor_check until the call is no longer monitored or the logic decides to
end the call (using the .hangup method or ending the script).
The connect_monitored method takes the following arguments:
| Field | Type | Description |
|---|---|---|
called_party
|
(+)Hex String |
[Required] The userinfo part of the INVITE Request To header address.The protocol and domain parts of the address will be determined automatically. The applicable configured called_party denormalisation on the LhoSipApp will be applied.
|
no_answer_timeout
|
Positive Integer |
Specifies the desired time limit for INVITE Request processing in seconds. The LhoSipApp will enforce a maximum bound for this value.A CANCEL Request will be sent if a Final Response is not received within this time. (Default = use the default_no_answer_secs configured on the LhoSipOutcallLuaAgent or LhoSipIncallLuaService).
|
monitor_interval_secs
|
Positive Integer |
Specifies the desired interval in seconds between the SIP re-INVITE Requests / monitor reports. The LhoSipApp will enforce minimum and maximum bounds for this value.(Default = use the activity_interval_secs configured on the LhoSipApp).
|
max_call_secs
|
Positive Integer |
Specifies the desired maximum permitted call duration in seconds. The LhoSipApp will enforce minimum and maximum bounds for this value.(Default = use the max_call_secs configured on the LhoSipApp).
|
The connect_monitored method returns the same table structure as termination_attempt.
Example (connect to specific destination, 10 second no-answer timeout, 3 second monitor interval, 20 second max call duration):
local n2svcd = require "n2.n2svcd"
local incall_api = require "n2.n2svcd.sip_incall_service"
local sip_incall = ...
local result = sip_incall_api.connect_monitored ("902112233", 10, 3, 20)
if (result.answered) then
n2svcd.notice ("CALL ANSWERED = YES")
print ("Actual monitor_interval_secs = " .. tostring (result.monitor_interval_secs))
print ("Actual max_call_secs = " .. tostring (result.max_call_secs))
-- When a monitored call is answered, we must sweep for monitor events.
repeat
result = sip_incall_api.monitor_check ()
until (not result.monitored)
elseif (result.decline_ok) then
sip_incall_api.decline (400)
end
return
.connect_charged [Asynchronous]
This helper method provides a flattened-argument version of the termination_attempt method for the “Charged” call mode.
NOTE: If this method returns result.answered == true then your service logic must invoke
sip_incall_api.charge_check and sip_incall.charge_extend alternately until the call is no longer
charged or the logic decides to end the call (using the .hangup method or ending the script).
The connect_charged method takes the following arguments:
| Field | Type | Description |
|---|---|---|
called_party
|
(+)Hex String |
[Required] The userinfo part of the INVITE Request To header address.The protocol and domain parts of the address will be determined automatically. The applicable configured called_party denormalisation on the LhoSipApp will be applied.
|
no_answer_timeout
|
Positive Integer |
Specifies the desired time limit for INVITE Request processing in seconds. The LhoSipApp will enforce a maximum bound for this value.A CANCEL Request will be sent if a Final Response is not received within this time. (Default = use the default_no_answer_secs configured on the LhoSipOutcallLuaAgent or LhoSipIncallLuaService).
|
grant_secs
|
Positive Integer |
[Required] Specifies the desired period in
seconds from when the call attempt is answered until the initial SIP re-INVITE Requests / charge report. The LhoSipApp will enforce minimum and maximum bounds for this value.
|
max_call_secs
|
Positive Integer |
Specifies the desired maximum permitted call duration in seconds. The LhoSipApp will enforce minimum and maximum bounds for this value.(Default = use the max_call_secs configured on the LhoSipApp).
|
The connect_charged method returns the same table structure as termination_attempt.
Example (connect to specific destination, grant 30 seconds indefinitely):
local n2svcd = require "n2.n2svcd"
local incall_api = require "n2.n2svcd.sip_incall_service"
local sip_incall = ...
local result = sip_incall_api.connect_charged ("902112233", nil, 30)
if (result.answered) then
while (true) do
result = sip_incall_api.charge_check ()
if (not result.charged) then break end
sip_incall.charge_extend (30)
end
end
return
.monitor_check [Asynchronous]
This monitor check method must be invoked by any script using monitored calls, after a monitored call attempt has been answered.
- A monitored call attempt is one for which the
termination_attemptdetails.monitoredattribute is settruedirectly or viaconnect_monitored. - An answered call attempt is one for which the returned
answeredattribute istrue.
The logic must repeat calls to result = sip_incall_api.monitor_check until result.monitored is false.
The script may perform other protocol actions prior to each invocation of monitor_check. These may include
asynchronous actions, e.g. Diameter client or REST client actions via the corresponding agent.
See also the subsequent sections related to follow-on telephony actions, and to service-initiated hangup
during monitored calls for further discussion of how the monitor_check method interacts with other
telephony methods.
The monitor_check method takes no arguments.
The monitor_check method returns a Lua table with the following attributes.
| Attribute | Type | Description |
|---|---|---|
.controlled
|
Boolean |
[Required] Is this call still controlled right now? This value being true indicates that (at least some) telephony API actions can be performed by service logic.Note that in some cases the available control actions may be limited. |
.monitored
|
Boolean |
[Required] Is this call still monitored. This value being true indicates that the A-Leg to B-Leg talk-time is still in progress, and
the total talk-time has reached the sum of all monitoring report intervals to-date.
|
.monitored_secs
|
Integer |
The accumulated talk-time in seconds confirmed by this and all previous reports, as measured by the LhoSipApp.This value is present only when .monitored is true.(Default = not present, .monitored is false).
|
.talk_dsm
|
Integer |
The talk-time duration in deci-seconds, as measured by the LhoSipApp.This value is present only when .monitored is false.(Default = not present, .monitored is true).
|
If the call successfully completes the entire monitoring interval with both legs still connected, the result will be:
{ controlled = true, monitored = true, monitored_secs = <integer> }
If the B-Leg is terminated but the A-Leg is still available, follow-on telephony is possible, and the result will be:
{ controlled = true, monitored = false, talk_dsm = <integer> }
If the A-Leg is terminated then the B-Leg will also be terminated and the result will be:
{ controlled = false, monitored = false, talk_dsm = <integer> }
.charge_check [Asynchronous]
This charge check method must be invoked by any script using charged calls, after the charged
call attempt has initially been answered, and then subsequently after each call to charge_extend.
- A charged call attempt is one for which the
termination_attemptdetails.chargedattribute is settruedirectly or viaconnect_charged. - An answered call attempt is one for which the returned
answeredattribute istrue.
The script may perform other protocol actions prior to each invocation of charge_check. These may include
asynchronous actions, e.g. Diameter client or REST client actions via the corresponding agent.
See also the subsequent sections related to follow-on telephony actions, and to service-initiated hangup
during charged calls for further discussion of how the charge_check method interacts with other
telephony methods.
The charge_check method takes no arguments.
The charge_check method returns a Lua table with the following attributes.
| Attribute | Type | Description |
|---|---|---|
.controlled
|
Boolean |
[Required] Is this call still controlled right now? This value being true indicates that (at least some) telephony API actions can be performed by service logic.Note that in some cases the available control actions may be limited. |
.charged
|
Boolean |
[Required] Is this call still charged. This value being true indicates that the A-Leg to B-Leg talk-time is still in progress, and
the total talk-time has reached the sum of all granted intervals to-date.
|
.charged_secs
|
Integer |
The accumulated talk-time in seconds confirmed by this and all previous reports, as measured by the LhoSipApp.This value is present only when .charged is true.(Default = not present, .charged is false).
|
.talk_dsm
|
Integer |
The talk-time duration in deci-seconds, as measured by the LhoSipApp.This value is present only when .charged is false.(Default = not present, .charged is true).
|
If the call successfully completes the entire granted time with both legs still connected, the result will be:
{ controlled = true, charged = true, charged_secs = <integer> }
If the B-Leg is terminated but the A-Leg is still available, follow-on telephony is possible, and the result will be:
{ controlled = true, charged = false, talk_dsm = <integer> }
If the A-Leg is terminated then the B-Leg will also be terminated and the result will be:
{ controlled = false, charged = false, talk_dsm = <integer> }
.charge_extend [Synchronous]
This charge extend method must be invoked by any script using charged calls, whenever the
charge_check method returns result.charged = true and the service decides to grant
a subsequent talk-time extension.
If the service does not wish to grant a talk-time extension, then it should invoke the
hangup method or end the script. This must be done before the service logic timer
expires.
The script may perform other protocol actions prior to each invocation of charge_extend. These may include
asynchronous actions, e.g. Diameter client or REST client actions via the corresponding agent.
See also the subsequent sections related to follow-on telephony actions, and to service-initiated hangup
during charged calls for further discussion of how the charge_extend method interacts with other
telephony methods.
The charge_extend method takes the following arguments:
| Field | Type | Description |
|---|
The charge_extend method returns true.
Limited Telephony During Monitoring/Charging
The termination_attempt, monitor_check, and charge_check methods can return
monitored = true or charged = true when controlled = true.
This indicates that a monitored or charged call is in a progress, and a limited telephony control is available. Specifically, the following methods are the only methods that should be invoked:
monitor_check(whenmonitoredistrue)charge_check(whenchargedistrue)charge_extend(only aftercharge_check, whenchargedistrue)hangup
After using the hangup method the call is over and there is no additional information which
can be provided. No methods should be invoked, including those listed above.
Follow-On Telephony After Monitoring/Charging
The monitor_check and charge_check methods can return monitored = false and charged = false
when controlled = true.
This occurs when the B-Leg of the monitored/charged call ends, but the A-Leg is still available.
At this time, almost all of the standard telephony methods are available, including those associated with interaction and B-Leg termination.
Exceptions are:
- The
sip_incall_service.proceedingmethod (including theringingwrapper method). This method can never be used after any termination attempt is answered. - The
sip_incall_service.declinemethod (including theredirectwrapper method). This method can never be used after any termination attempt is answered. - The
sip_outcall_agent.establish_new_callmethod (including theoutcallwrapper method). This method can never be used after an A-Leg is connected.
Slow Service Logic
All service logic must respond promptly, within the service_logic_ms timer (default = 2500 milliseconds)
configured for the LhoSipApp.
If the service logic response is not received within this time whenever it is expected, the LhoSipApp
will assume that call control has been abandoned, and will terminate the in-progress call with the loss
of all legs.
Constants
The following relevant constants are defined on the sip_incall_service and sip_outcall_agent objects:
sip_incall_service.REASON_NO_ROUTE = "No Route" -- B-Party RSF (we have no route)
sip_incall_service.REASON_DECLINED = "Declined" -- B-Party Busy (and other explicit decline)
sip_incall_service.REASON_NO_ANSWER = "No Answer" -- B-Party Time-Out
sip_incall_service.REASON_ANSWERED = "Answered" -- B-Party Answer
sip_incall_service.REASON_ABANDONED = "Abandoned" -- A-Party Hangup
sip_outcall_agent.REASON_NO_ROUTE = "No Route" -- A/B-Party RSF (we have no route)
sip_outcall_agent.REASON_DECLINED = "Declined" -- A/B-Party Busy (and other explicit decline)
sip_outcall_agent.REASON_NO_ANSWER = "No Answer" -- A/B-Party Time-Out
sip_outcall_agent.REASON_ANSWERED = "Answered" -- A/B-Party Answer
sip_outcall_agent.REASON_ABANDONED = "Abandoned" -- A-Party Hangup before Answer