Termination Attempt
Introduction
An SIP incall Lua script 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 playing previous announcements, then it will be disconnected prior to the B-Leg termination attempt.
If the B-Leg is successfully established, then the SIP framework will connect it to the A-Leg
using either SIP INVITE 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 can no longer interact with the call.
- The B-Leg is answered. The Lua script can no longer interact with the call.
- The B-Leg does not answer. The Lua script resumes control of the call.
- A SIP processing error occurs. The Lua script can no longer interact with the call.
If Monitoring is requested, then the second outcome is different:
- The B-Leg is answered. The Lua script must read monitor reports for the call.
If Charging is requested, then the second outcome is different:
- The B-Leg is answered. The Lua script must read charge reports for the call and grant extensions.
In this case where a Monitored or Charged call is answed by the B-Leg, the service logic may regain control of an answered call, i.e. in the case where the B-Leg is torn down but the A-Leg remains.
If the call is not Monitored or Charged then the service logic has no further involvement in a call after it is answered.
The LhoSipLuaService Termination API
.termination_attempt [Asynchronous]
This method provides full access to the Termination (Attempt & Monitored) 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
== true
then your
service logic must invoke sip_incall_api.monitor_check
until the call is no longer monitored.
NOTE: If this method returns result.answered
== true
and result.charged
== true
then your
service logic must alternately invoke sip_incall_api.charge_check
and
sip_incall_api.charge_extend
until the call is no longer charged.
This method takes a single details
parameter which is a LUA table with the following structure:
Field | Type | Description |
---|---|---|
details
|
Object | [Required] The detailed SIP parameters for the message. |
.address_digits
|
(+)Hex String |
[Required] The digits part of the new To address for the B-Leg.The protocol and domain parts of the address will be determined automatically. |
.no_answer_timeout
|
Integer |
Specify how long the B-Leg SIP INVITE Request will be permitted to try before we use SIP CANCEL .(Default = use the default_no_answer_secs configured on the Service).
|
.extra_headers
|
Object |
Additional user headers to add for this outbound B-Leg SIP INVITE. The table entry key is the header name. Each table entry value is a list (array) of header value strings. (Default = do not add extra outbound SIP INVITE user headers). |
.max_call_secs
|
Integer |
Specifies the maximum permitted call duration in seconds. The LhoSipApp may enforce minimum and maximum bounds for this value. (Default = use the max_call_secs configured on the LhoSipApp).
|
.monitored
|
1
|
Set this value to indicate that this is a "Monitored" call attempt. The call will have SIP re-INVITE activity tests sent to check that the call is still active. If this call attempt is answered, then the service logic must use the monitor_check method to monitor the call until it completes.(Default = the call is not monitored). |
.monitor_interval_secs
|
Integer |
Request the desired interval in seconds between monitor reports. The LhoSipApp may enforce minimum and maximum bounds for this value. Valid only when monitored = 1 .(Default = use the monitor_interval_secs configured on the LhoSipApp).
|
.charged
|
1
|
Set this value to indicate that this is a "Charged" call attempt. The call will have SIP re-INVITE activity tests sent to check that the call is still active. If this call attempt is answered, then the service logic must use the charge_check and charge_extend methods to authorize extensions on the charged call until it completes.(Default = the call is not charged). |
.grant_secs
|
Integer |
[Required] Request the initial granted talk-time. The LhoSipApp may enforce minimum and maximum bounds for this value. Valid only when charged = 1 .
|
The termination_attempt
method returns a table structure indicating the result of the termination attempt.
Attribute | Type | Description |
---|---|---|
.controlled
|
Boolean |
[Required] Is this call still controlled at all 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 |
Was this call answered. This value being true indicates that the A-Leg to B-Leg setup was successfully completed.
|
.monitored
|
Boolean |
Is this call monitored. This value will be true when "Monitored" termination was requested, and answered = true .
|
.charged
|
Boolean |
Is this call charged. This value will be true when "Charged" termination was requested, and answered = true .
|
.decline_ok
|
Boolean |
Can the service logic still use the .decline method?This field is present if and only if .controlled is true .This field will be true if we have not yet sent a 2XX or 300-699 Response code.
|
.code
|
Integer |
An SIP Response final 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 final SIP INVITE Response code. |
.reason
|
No Route / Declined / No Answer / Answered / Abandoned
|
[Required] A descriptive string for how the termination attempt ended. |
.max_call_secs
|
Integer |
Specifies the actual maximum permitted call duration in seconds, in the case when a call is answered. The LhoSipApp will apply default, minimum, and maximum bounds for this value, so it may differ from requested. |
.monitor_interval_secs
|
Integer |
Confirms the actual monitored call activity test interval, in the case where a monitored call is answered. The LhoSipApp will apply default, minimum, and maximum bounds for this value, so it may differ from requested. |
.grant_secs
|
Integer |
Confirms the actual first charge period granted, in the case where a charged call is answered. The LhoSipApp will apply minimum, and maximum bounds for this value, so it may differ from requested. |
If the B-Leg is not answered, the result controlled/answered/code/reason are one of the following sub-cases:
{ controlled = false, monitored = false, answered = false, reason = "Abandoned" }
(A-Leg used CANCEL or BYE before B-Leg completed){ controlled = true, monitored = false, answered = false, reason = "No Answer" }
(Our internal “no answer” Timeout fired before B-Leg completed){ controlled = true, monitored = false, answered = false, reason = "No Route" }
(We could not route the B-Leg){ controlled = true, monitored = false, answered = false, code = 300-699, reason = "Declined" }
(B-Leg SIP INVITE Response code 300-699)
If the B-Leg is answered for a call attempt (not monitored, not charged) the result will be:
{ controlled = false, monitored = false, answered = true, reason = "Answered", max_call_secs = <integer> }
If the B-Leg is answered for a call attempt (monitored) the result will be:
{ controlled = true, monitored = true, answered = true, reason = "Answered", max_call_secs = <integer>, monitor_interval_secs = <integer> }
If the B-Leg is answered for a call attempt (charged) the result will be:
{ controlled = true, charged = true, answered = true, reason = "Answered", max_call_secs = <integer>, 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 (connection monitored attempt to called party with a prefix, 10 minute maximum talk time, 60 second 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 (connection monitored 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 |
---|---|---|
address_digits
|
(+)Hex String |
[Required] The digits part of the new To address for the B-Leg.The protocol and domain parts of the address will be determined automatically. |
no_answer_timeout
|
Integer |
Specify how long the B-Leg SIP INVITE Request will be permitted to try before we use SIP CANCEL .(Default = use the default_no_answer_secs configured on the Service).
|
max_call_secs
|
Integer |
Specifies the maximum permitted call duration in seconds. The LhoSipApp may 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 result 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 with “Monitored” call mode enabled.
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 applies a forced
call-end by invoking the hangup method or ending the script.
The connect_monitored
method takes the following arguments:
Field | Type | Description |
---|---|---|
address_digits
|
(+)Hex String |
[Required] The digits part of the new To address for the B-Leg.The protocol and domain parts of the address will be determined automatically. |
no_answer_timeout
|
Integer |
Specify how long the B-Leg SIP INVITE Request will be permitted to try before we use SIP CANCEL .(Default = use the default_no_answer_secs configured on the Service).
|
monitor_interval_secs
|
Integer |
Request the desired interval in seconds between monitor reports. The LhoSipApp may enforce minimum and maximum bounds for this value. (Default = use the monitor_interval_secs configured on the LhoSipApp).
|
max_call_secs
|
Integer |
Specifies the maximum permitted call duration in seconds. The LhoSipApp may 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 result structure as termination_attempt
.
Example (connect to called party with a prefix, 60 second monitor intervals):
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 with “Charged” call mode enabled.
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 applies a forced call-end by invoking the hangup method or ending the script.
The connect_charged
method takes the following arguments:
Field | Type | Description |
---|---|---|
address_digits
|
(+)Hex String |
[Required] The digits part of the new To address for the B-Leg.The protocol and domain parts of the address will be determined automatically. |
no_answer_timeout
|
Integer |
Specify how long the B-Leg SIP INVITE Request will be permitted to try before we use SIP CANCEL .(Default = use the default_no_answer_secs configured on the Service).
|
grant_secs
|
Integer |
[Required] Request the initial granted talk-time. The LhoSipApp may enforce minimum and maximum bounds for this value. |
max_call_secs
|
Integer |
Specifies the maximum permitted call duration in seconds. The LhoSipApp may 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 result structure as termination_attempt
.
Example (connect to called party with a prefix, 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 called by any script using monitored calls, after a monitored call attempt has been answered.
- A monitored call attempt is one which sets the
monitored
attribute intermination_attempt
directly or viaconnect_monitored
. - An answered call attempt is one where the
answered
attribute is returnedtrue
.
The logic must repeat calls to result = sip_incall_api.monitor_check
until not result.monitored
.
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 table with the following structure:
Attribute | Type | Description |
---|---|---|
.controlled
|
Boolean |
[Required] Is this call still controlled at all 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. When this value returns true it 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 |
What is the total talk time confirmed by this and all previous reports. This value is present only when .monitored = true .
|
.talk_dsm
|
Integer |
Returns the measured talk-time in deci-seconds for the entire talk period. This value is present only when .monitored is not true .
|
If the call successfully completes the entire monitoring interval with both legs still connected, then the return value is:
{ controlled = true, monitored = true, monitored_secs = <integer> }
If the B-Leg is terminated but the A-Leg is still available, then follow-on telephony is possible, and the return is:
{ controlled = true, monitored = false, talk_dsm = <integer> }
If the A-Leg is terminated, then the B-Leg will also be terminated and the return is:
{ controlled = false, monitored = false, talk_dsm = <integer> }
.charge_check [Asynchronous]
This charge check method must be called 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 which sets the
charged
attribute intermination_attempt
directly or viaconnect_charged
. - An answered call attempt is one where the
answered
attribute is returnedtrue
.
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 monitored 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 table with the following structure:
Attribute | Type | Description |
---|---|---|
.controlled
|
Boolean |
[Required] Is this call still controlled at all 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. When this value returns true it indicates that the A-Leg to B-Leg talk-time is still in progress, and
the total talk time has reached the sum of the initial grant and all subsequent grant intervals to-date.
|
.charged_secs
|
Integer |
What is the total talk time confirmed by this and all previous reports. This value is present only when .charged = true .
|
.talk_dsm
|
Integer |
Returns the measured talk-time in deci-seconds for the entire talk period. This value is present only when .charged is not true .
|
If the call successfully completes the total granted time with both legs still connected, then the return value is:
{ controlled = true, charged = true, charged_secs = <integer> }
If the B-Leg is terminated but the A-Leg is still available, then follow-on telephony is possible, and the return is:
{ controlled = true, charged = false, talk_dsm = <integer> }
If the A-Leg is terminated, then the B-Leg will also be terminated and the return is:
{ controlled = false, charged = false, talk_dsm = <integer> }
.charge_extend [Synchronous]
This charge grant method must be called 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 monitored 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 |
---|---|---|
grant_secs
|
Integer |
[Required] Request the additional granted talk-time interval in seconds. The LhoSipApp may enforce minimum and maximum bounds for this value. |
The charge_extend
method returns true
.
Limited Telephony within Monitor/Charge
The termination_attempt
, monitor_check
, and charge_check
methods can return:
monitored
=true
orcharged
=true
(which will also have)controlled
=true
This is a limited form of telephony control. The service logic can only perform some very specific functions while the monitored/charged call is in progress, specifically:
monitor_check
charge_check
charge_extend
(only aftercharge_check
)hangup
After using the hangup
method, you should not call monitor_check
, charge_check
,
or charge_extend
. The call is now over and there is no additional information which
can be provided.
Follow-On Telephony after Monitor/Charge
The monitor_check
and charge_check
methods can return:
monitored
=false
orcharged
=false
(but with)controlled
=true
This occurs when the B-Leg of the monitored/charged call ends, but the A-Leg is still available.
At this time, all of the standard telephony methods are now available, including follow-on interaction and/or B-Leg termination.
The exception is the decline
method (including the redirect
wrapper method). This method can never
be used after any termination attempt is performed.
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, then 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 constants are defined on the returned sip_incall_service
object.
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_incall_service.EARLY_MEDIA_REQUIRE = "require"
sip_incall_service.EARLY_MEDIA_PREFER = "prefer"
sip_incall_service.EARLY_MEDIA_ALLOW = "allow"
sip_incall_service.EARLY_MEDIA_NEVER = "never"