diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
index 35c3c96a24..69c0beb9ea 100644
--- a/channels/chan_pjsip.c
+++ b/channels/chan_pjsip.c
@@ -3266,6 +3266,8 @@ static struct ast_custom_function session_refresh_function = {
.write = pjsip_acf_session_refresh_write,
};
+static char *app_pjsip_hangup = "PJSIPHangup";
+
/*!
* \brief Load the module
*
@@ -3323,6 +3325,13 @@ static int load_module(void)
goto end;
}
+ if (ast_register_application_xml(app_pjsip_hangup, pjsip_app_hangup)) {
+ ast_log(LOG_WARNING, "Unable to register PJSIPHangup dialplan application\n");
+ goto end;
+ }
+ ast_manager_register_xml(app_pjsip_hangup, EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, pjsip_action_hangup);
+
+
ast_sip_register_service(&refer_callback_module);
ast_sip_session_register_supplement(&chan_pjsip_supplement);
@@ -3370,6 +3379,9 @@ end:
ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
ast_custom_function_unregister(&chan_pjsip_parse_uri_function);
ast_custom_function_unregister(&session_refresh_function);
+ ast_unregister_application(app_pjsip_hangup);
+ ast_manager_unregister(app_pjsip_hangup);
+
ast_channel_unregister(&chan_pjsip_tech);
ast_rtp_glue_unregister(&chan_pjsip_rtp_glue);
@@ -3399,6 +3411,8 @@ static int unload_module(void)
ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
ast_custom_function_unregister(&chan_pjsip_parse_uri_function);
ast_custom_function_unregister(&session_refresh_function);
+ ast_unregister_application(app_pjsip_hangup);
+ ast_manager_unregister(app_pjsip_hangup);
ast_channel_unregister(&chan_pjsip_tech);
ao2_ref(chan_pjsip_tech.capabilities, -1);
diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c
index 0496f048e3..f1365adba9 100644
--- a/channels/pjsip/dialplan_functions.c
+++ b/channels/pjsip/dialplan_functions.c
@@ -29,563 +29,6 @@
core
***/
-/*** DOCUMENTATION
-
-
- Return a dial string for dialing all contacts on an AOR.
-
-
-
- Name of the endpoint
-
-
- Name of an AOR to use, if not specified the configured AORs on the endpoint are used
-
-
- Optional request user to use in the request URI
-
-
-
- Returns a properly formatted dial string for dialing all contacts on an AOR.
-
-
-
-
- Media and codec offerings to be set on an outbound SIP channel prior to dialing.
-
-
-
- types of media offered
-
-
-
- When read, returns the codecs offered based upon the media choice.
- When written, sets the codecs to offer when an outbound dial attempt is made,
- or when a session refresh is sent using PJSIP_SEND_SESSION_REFRESH.
-
-
-
- [PJSIP_SEND_SESSION_REFRESH]
-
-
-
-
- 13.18.0
- 14.7.0
- 15.1.0
- 16.0.0
-
-
- Get or change the DTMF mode for a SIP call.
-
-
-
-
- When read, returns the current DTMF mode
- When written, sets the current DTMF mode
- This function uses the same DTMF mode naming as the dtmf_mode configuration option
-
-
-
-
- Get or change the on-hold behavior for a SIP call.
-
-
-
-
- When read, returns the current moh passthrough mode
- When written, sets the current moh passthrough mode
- If yes, on-hold re-INVITEs are sent. If no, music on hold is generated.
- This function can be used to override the moh_passthrough configuration option
-
-
-
-
- 13.12.0
- 14.1.0
- 15.0.0
-
-
- W/O: Initiate a session refresh via an UPDATE or re-INVITE on an established media session
-
-
-
- The type of update to send. Default is invite.
-
-
- Send the session refresh as a re-INVITE.
-
-
- Send the session refresh as an UPDATE.
-
-
-
-
-
- This function will cause the PJSIP stack to immediately refresh
- the media session for the channel. This will be done using either a
- re-INVITE (default) or an UPDATE request.
-
- This is most useful when combined with the PJSIP_MEDIA_OFFER
- dialplan function, as it allows the formats in use on a channel to be
- re-negotiated after call setup.
-
- The formats the endpoint supports are not
- checked or enforced by this function. Using this function to offer
- formats not supported by the endpoint may result
- in a loss of media.
-
-
- ; Within some existing extension on an answered channel
- same => n,Set(PJSIP_MEDIA_OFFER(audio)=!all,g722)
- same => n,Set(PJSIP_SEND_SESSION_REFRESH()=invite)
-
-
-
- [PJSIP_MEDIA_OFFER]
-
-
-
-
- 13.24.0
- 16.1.0
- 17.0.0
-
-
- Parse an uri and return a type part of the URI.
-
-
-
- URI to parse
-
-
- The type parameter specifies which URI part to read
-
-
- Display name.
-
-
- URI scheme.
-
-
- User part.
-
-
- Password part.
-
-
- Host part.
-
-
- Port number, or zero.
-
-
- User parameter.
-
-
- Method parameter.
-
-
- Transport parameter.
-
-
- TTL param, or -1.
-
-
- Loose routing param, or zero.
-
-
- Maddr param.
-
-
-
-
-
- Parse an URI and return a specified part of the URI.
-
-
-
-
-
- R/O Retrieve media related information.
-
- When rtp is specified, the
- type parameter must be provided. It specifies
- which RTP parameter to read.
-
-
- Retrieve the local address for RTP.
-
-
- Retrieve the remote address for RTP.
-
-
- If direct media is enabled, this address is the remote address
- used for RTP.
-
-
- Whether or not the media stream is encrypted.
-
-
- The media stream is not encrypted.
-
-
- The media stream is encrypted.
-
-
-
-
- Whether or not the media stream is currently restricted
- due to a call hold.
-
-
- The media stream is not held.
-
-
- The media stream is held.
-
-
-
-
-
-
- When rtp is specified, the
- media_type parameter may be provided. It specifies
- which media stream the chosen RTP parameter should be retrieved
- from.
-
-
- Retrieve information from the audio media stream.
- If not specified, audio is used
- by default.
-
-
- Retrieve information from the video media stream.
-
-
-
-
-
- R/O Retrieve RTCP statistics.
-
- When rtcp is specified, the
- statistic parameter must be provided. It specifies
- which RTCP statistic parameter to read.
-
-
- Retrieve a summary of all RTCP statistics.
- The following data items are returned in a semi-colon
- delineated list:
-
-
- Our Synchronization Source identifier
-
-
- Their Synchronization Source identifier
-
-
- Our lost packet count
-
-
- Received packet jitter
-
-
- Received packet count
-
-
- Transmitted packet jitter
-
-
- Transmitted packet count
-
-
- Remote lost packet count
-
-
- Round trip time
-
-
- Transmitted Media Experience Score
-
-
- Received Media Experience Score
-
-
-
-
- Retrieve a summary of all RTCP Jitter statistics.
- The following data items are returned in a semi-colon
- delineated list:
-
-
- Our minimum jitter
-
-
- Our max jitter
-
-
- Our average jitter
-
-
- Our jitter standard deviation
-
-
- Their minimum jitter
-
-
- Their max jitter
-
-
- Their average jitter
-
-
- Their jitter standard deviation
-
-
-
-
- Retrieve a summary of all RTCP packet loss statistics.
- The following data items are returned in a semi-colon
- delineated list:
-
-
- Our minimum lost packets
-
-
- Our max lost packets
-
-
- Our average lost packets
-
-
- Our lost packets standard deviation
-
-
- Their minimum lost packets
-
-
- Their max lost packets
-
-
- Their average lost packets
-
-
- Their lost packets standard deviation
-
-
-
-
- Retrieve a summary of all RTCP round trip time information.
- The following data items are returned in a semi-colon
- delineated list:
-
-
- Minimum round trip time
-
-
- Maximum round trip time
-
-
- Average round trip time
-
-
- Standard deviation round trip time
-
-
-
-
- Retrieve a summary of all RTCP Media Experience Score information.
- The following data items are returned in a semi-colon
- delineated list:
-
-
- Minimum MES based on us analysing received packets.
-
-
- Maximum MES based on us analysing received packets.
-
-
- Average MES based on us analysing received packets.
-
-
- Standard deviation MES based on us analysing received packets.
-
-
- Minimum MES based on data we get in Sender and Receiver Reports sent by the remote end
-
-
- Maximum MES based on data we get in Sender and Receiver Reports sent by the remote end
-
-
- Average MES based on data we get in Sender and Receiver Reports sent by the remote end
-
-
- Standard deviation MES based on data we get in Sender and Receiver Reports sent by the remote end
-
-
-
- Transmitted packet count
- Received packet count
- Transmitted packet jitter
- Received packet jitter
- Their max jitter
- Their minimum jitter
- Their average jitter
- Their jitter standard deviation
- Our max jitter
- Our minimum jitter
- Our average jitter
- Our jitter standard deviation
- Transmitted packet loss
- Received packet loss
- Their max lost packets
- Their minimum lost packets
- Their average lost packets
- Their lost packets standard deviation
- Our max lost packets
- Our minimum lost packets
- Our average lost packets
- Our lost packets standard deviation
- Round trip time
- Maximum round trip time
- Minimum round trip time
- Average round trip time
- Standard deviation round trip time
- Our Synchronization Source identifier
- Their Synchronization Source identifier
-
- Current MES based on us analyzing rtt, jitter and loss
- in the actual received RTP stream received from the remote end.
- I.E. This is the MES for the incoming audio stream.
-
-
- Current MES based on rtt and the jitter and loss values in
- RTCP sender and receiver reports we receive from the
- remote end. I.E. This is the MES for the outgoing audio stream.
-
- Max MES based on data we get in Sender and Receiver Reports sent by the remote end
- Min MES based on data we get in Sender and Receiver Reports sent by the remote end
- Average MES based on data we get in Sender and Receiver Reports sent by the remote end
- Standard deviation MES based on data we get in Sender and Receiver Reports sent by the remote end
- Max MES based on us analyzing the received RTP stream
- Min MES based on us analyzing the received RTP stream
- Average MES based on us analyzing the received RTP stream
- Standard deviation MES based on us analyzing the received RTP stream
-
-
-
- When rtcp is specified, the
- media_type parameter may be provided. It specifies
- which media stream the chosen RTCP parameter should be retrieved
- from.
-
-
- Retrieve information from the audio media stream.
- If not specified, audio is used
- by default.
-
-
- Retrieve information from the video media stream.
-
-
-
-
-
- R/O The name of the endpoint associated with this channel.
- Use the PJSIP_ENDPOINT function to obtain
- further endpoint related information.
-
-
- R/O The name of the contact associated with this channel.
- Use the PJSIP_CONTACT function to obtain
- further contact related information. Note this may not be present and if so
- is only available on outgoing legs.
-
-
- R/O The name of the AOR associated with this channel.
- Use the PJSIP_AOR function to obtain
- further AOR related information. Note this may not be present and if so
- is only available on outgoing legs.
-
-
- R/O Obtain information about the current PJSIP channel and its
- session.
-
- When pjsip is specified, the
- type parameter must be provided. It specifies
- which signalling parameter to read.
-
-
- The SIP call-id.
-
-
- Whether or not the signalling uses a secure transport.
-
- The signalling uses a non-secure transport.
- The signalling uses a secure transport.
-
-
-
- The contact URI where requests are sent.
-
-
- The local URI.
-
-
- Tag in From header
-
-
- The remote URI.
-
-
- Tag in To header
-
-
- The request URI of the incoming INVITE
- associated with the creation of this channel.
-
-
- The current state of any T.38 fax on this channel.
-
- T.38 faxing is disabled on this channel.
- Asterisk has sent a re-INVITE to the remote end to initiate a T.38 fax.
- The remote end has sent a re-INVITE to Asterisk to initiate a T.38 fax.
- A T.38 fax session has been enabled.
- A T.38 fax session was attempted but was rejected.
-
-
-
- On inbound calls, the full IP address and port number that
- the INVITE request was received on. On outbound
- calls, the full IP address and port number that the INVITE
- request was transmitted from.
-
-
- On inbound calls, the full IP address and port number that
- the INVITE request was received from. On outbound
- calls, the full IP address and port number that the INVITE
- request was transmitted to.
-
-
-
-
-
-
-
-
- ; Log the current Call-ID
- same => n,Log(NOTICE, ${CHANNEL(pjsip,call-id)})
-
- ; Log the destination address of the audio stream
- same => n,Log(NOTICE, ${CHANNEL(rtp,dest)})
-
- ; Store the round-trip time associated with a
- ; video stream in the CDR field video-rtt
- same => n,Set(CDR(video-rtt)=${CHANNEL(rtcp,rtt,video)})
-
-
-***/
-
#include "asterisk.h"
#include
@@ -596,6 +39,7 @@
#include "asterisk/module.h"
#include "asterisk/acl.h"
#include "asterisk/app.h"
+#include "asterisk/conversions.h"
#include "asterisk/channel.h"
#include "asterisk/stream.h"
#include "asterisk/format.h"
@@ -1784,3 +1228,121 @@ int pjsip_acf_session_refresh_write(struct ast_channel *chan, const char *cmd, c
return ast_sip_push_task_wait_serializer(channel->session->serializer, refresh_write_cb, &rdata);
}
+
+struct hangup_data {
+ struct ast_sip_session *session;
+ int response_code;
+};
+
+/*!
+ * \brief Serializer task to hangup channel
+ */
+static int pjsip_hangup(void *obj)
+{
+ struct hangup_data *hdata = obj;
+ pjsip_tx_data *packet = NULL;
+
+ if ((hdata->session->inv_session->state != PJSIP_INV_STATE_DISCONNECTED) &&
+ (pjsip_inv_answer(hdata->session->inv_session, hdata->response_code, NULL, NULL, &packet) == PJ_SUCCESS)) {
+ ast_sip_session_send_response(hdata->session, packet);
+ }
+
+ return 0;
+}
+
+/*!
+ * \brief Callback that validates the response code
+ */
+static int response_code_validator(const char *channel_name,
+ const char *response) {
+ int response_code;
+
+ int rc = ast_str_to_int(response, &response_code);
+ if (rc != 0) {
+ response_code = ast_sip_str2rc(response);
+ if (response_code < 0) {
+ ast_log(LOG_WARNING, "%s: Unrecognized response code parameter '%s'."
+ " Defaulting to 603 DECLINE\n",
+ channel_name, response);
+ return PJSIP_SC_DECLINE;
+ }
+ }
+
+ if (response_code < 400 || response_code > 699) {
+ ast_log(LOG_WARNING, "%s: Response code %d is out of range 400 -> 699."
+ " Defaulting to 603 DECLINE\n",
+ channel_name, response_code);
+ return PJSIP_SC_DECLINE;
+ }
+ return response_code;
+}
+
+/*!
+ * \brief Called by pjsip_app_hangup and pjsip_action_hangup
+ * to actually perform the hangup
+ */
+static void pjsip_app_hangup_handler(struct ast_channel *chan, int response_code)
+{
+ struct ast_sip_channel_pvt *channel;
+ struct hangup_data hdata = { NULL, -1 };
+ const char *tag = ast_channel_name(chan);
+
+ hdata.response_code = response_code;
+
+ ast_channel_lock(chan);
+ if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
+ ast_log(LOG_WARNING, "%s: Not a PJSIP channel\n", tag);
+ ast_channel_unlock(chan);
+ return;
+ }
+
+ channel = ast_channel_tech_pvt(chan);
+ hdata.session = channel->session;
+
+ if (hdata.session->inv_session->role != PJSIP_ROLE_UAS || (
+ hdata.session->inv_session->state != PJSIP_INV_STATE_INCOMING &&
+ hdata.session->inv_session->state != PJSIP_INV_STATE_EARLY)) {
+ ast_log(LOG_WARNING, "%s: Not an incoming channel or invalid state '%s'\n",
+ tag, pjsip_inv_state_name(hdata.session->inv_session->state));
+ ast_channel_unlock(chan);
+ return;
+ }
+
+ ast_channel_unlock(chan);
+
+ if (ast_sip_push_task_wait_serializer(channel->session->serializer,
+ pjsip_hangup, &hdata) != 0) {
+ ast_log(LOG_WARNING, "%s: failed to push hangup task to serializer\n", tag);
+ }
+
+ return;
+}
+
+/*!
+ * \brief PJSIPHangup Dialplan App
+ */
+int pjsip_app_hangup(struct ast_channel *chan, const char *data)
+{
+ int response_code;
+ const char *tag = ast_channel_name(chan);
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "%s: Missing response code parameter\n", tag);
+ return -1;
+ }
+
+ response_code = response_code_validator(tag, data);
+
+ pjsip_app_hangup_handler(chan, response_code);
+
+ return -1;
+}
+
+/*!
+ * \brief PJSIPHangup Manager Action
+ */
+int pjsip_action_hangup(struct mansession *s, const struct message *m)
+{
+ return ast_manager_hangup_helper(s, m,
+ pjsip_app_hangup_handler, response_code_validator);
+}
diff --git a/channels/pjsip/dialplan_functions.xml b/channels/pjsip/dialplan_functions.xml
new file mode 100644
index 0000000000..be4ce91b96
--- /dev/null
+++ b/channels/pjsip/dialplan_functions.xml
@@ -0,0 +1,659 @@
+
+
+
+
+
+ Hangup an incoming PJSIP channel with a SIP response code
+
+
+
+ May be one of...
+
+ A numeric response code in the range 400 ->699
+ A response code name from
+ third-party/pjproject/source/pjsip/include/pjsip/sip_msg.h
+ such as USE_IDENTITY_HEADER or
+ PJSIP_SC_USE_IDENTITY_HEADER
+
+
+
+
+
+ Hangs up an incoming PJSIP channel and returns the
+ specified SIP response code in the final response to the caller.
+
+
+
+
+ This function must be called BEFORE anything that
+ might cause any other final (non 1XX) response to be sent.
+ For example calling Answer() or
+ Playback without the
+ noanswer option will cause the call
+ to be answered and a final 200 response to be sent.
+
+
+
+ As with the Hangup application,
+ the dialplan will terminate after calling this function.
+
+
+ The cause code set on the channel will be translated to
+ a standard ISDN cause code using the table defined in
+ ast_sip_hangup_sip2cause() in res_pjsip.c
+
+
+
+ same = n,PJSIPHangup(437)
+
+
+ same = n,PJSIPHangup(UNSUPPORTED_CERTIFICATE)
+
+
+ same = n,ExecIf($[${SOMEVALUE} = ${SOME_BAD_VALUE}]?PJSIPHangup(437))
+
+
+
+
+
+
+ Hangup an incoming PJSIP channel with a SIP response code
+
+
+
+
+
+
+
+
+ Hangs up an incoming PJSIP channel and returns the
+ specified SIP response code in the final response to the caller.
+
+
+
+
+ This function must be called BEFORE anything that
+ might cause any other final (non 1XX) response to be sent.
+ For example calling Answer() or
+ Playback without the
+ noanswer option will cause the call
+ to be answered and a final 200 response to be sent.
+
+
+
+ The cause code set on the channel will be translated to
+ a standard ISDN cause code using the table defined in
+ ast_sip_hangup_sip2cause() in res_pjsip.c
+
+
+
+ Action: PJSIPHangup
+ ActionID: 12345678
+ Channel: PJSIP/alice-00000002
+ Cause: 437
+
+
+ Action: PJSIPHangup
+ ActionID: 12345678
+ Channel: PJSIP/alice-00000002
+ Cause: UNSUPPORTED_CERTIFICATE
+
+
+
+
+
+
+ Return a dial string for dialing all contacts on an AOR.
+
+
+
+ Name of the endpoint
+
+
+ Name of an AOR to use, if not specified the configured AORs on the endpoint are used
+
+
+ Optional request user to use in the request URI
+
+
+
+ Returns a properly formatted dial string for dialing all contacts on an AOR.
+
+
+
+
+ Media and codec offerings to be set on an outbound SIP channel prior to dialing.
+
+
+
+ types of media offered
+
+
+
+ When read, returns the codecs offered based upon the media choice.
+ When written, sets the codecs to offer when an outbound dial attempt is made,
+ or when a session refresh is sent using PJSIP_SEND_SESSION_REFRESH.
+
+
+
+ [PJSIP_SEND_SESSION_REFRESH]
+
+
+
+
+ 13.18.0
+ 14.7.0
+ 15.1.0
+ 16.0.0
+
+
+ Get or change the DTMF mode for a SIP call.
+
+
+
+
+ When read, returns the current DTMF mode
+ When written, sets the current DTMF mode
+ This function uses the same DTMF mode naming as the dtmf_mode configuration option
+
+
+
+
+ Get or change the on-hold behavior for a SIP call.
+
+
+
+
+ When read, returns the current moh passthrough mode
+ When written, sets the current moh passthrough mode
+ If yes, on-hold re-INVITEs are sent. If no, music on hold is generated.
+ This function can be used to override the moh_passthrough configuration option
+
+
+
+
+ 13.12.0
+ 14.1.0
+ 15.0.0
+
+
+ W/O: Initiate a session refresh via an UPDATE or re-INVITE on an established media session
+
+
+
+ The type of update to send. Default is invite.
+
+
+ Send the session refresh as a re-INVITE.
+
+
+ Send the session refresh as an UPDATE.
+
+
+
+
+
+ This function will cause the PJSIP stack to immediately refresh
+ the media session for the channel. This will be done using either a
+ re-INVITE (default) or an UPDATE request.
+
+ This is most useful when combined with the PJSIP_MEDIA_OFFER
+ dialplan function, as it allows the formats in use on a channel to be
+ re-negotiated after call setup.
+
+ The formats the endpoint supports are not
+ checked or enforced by this function. Using this function to offer
+ formats not supported by the endpoint may result
+ in a loss of media.
+
+
+ ; Within some existing extension on an answered channel
+ same => n,Set(PJSIP_MEDIA_OFFER(audio)=!all,g722)
+ same => n,Set(PJSIP_SEND_SESSION_REFRESH()=invite)
+
+
+
+ [PJSIP_MEDIA_OFFER]
+
+
+
+
+ 13.24.0
+ 16.1.0
+ 17.0.0
+
+
+ Parse an uri and return a type part of the URI.
+
+
+
+ URI to parse
+
+
+ The type parameter specifies which URI part to read
+
+
+ Display name.
+
+
+ URI scheme.
+
+
+ User part.
+
+
+ Password part.
+
+
+ Host part.
+
+
+ Port number, or zero.
+
+
+ User parameter.
+
+
+ Method parameter.
+
+
+ Transport parameter.
+
+
+ TTL param, or -1.
+
+
+ Loose routing param, or zero.
+
+
+ Maddr param.
+
+
+
+
+
+ Parse an URI and return a specified part of the URI.
+
+
+
+
+
+
+ R/O Retrieve media related information.
+
+ When rtp is specified, the
+ type parameter must be provided. It specifies
+ which RTP parameter to read.
+
+
+ Retrieve the local address for RTP.
+
+
+ Retrieve the remote address for RTP.
+
+
+ If direct media is enabled, this address is the remote address
+ used for RTP.
+
+
+ Whether or not the media stream is encrypted.
+
+
+ The media stream is not encrypted.
+
+
+ The media stream is encrypted.
+
+
+
+
+ Whether or not the media stream is currently restricted
+ due to a call hold.
+
+
+ The media stream is not held.
+
+
+ The media stream is held.
+
+
+
+
+
+
+ When rtp is specified, the
+ media_type parameter may be provided. It specifies
+ which media stream the chosen RTP parameter should be retrieved
+ from.
+
+
+ Retrieve information from the audio media stream.
+ If not specified, audio is used
+ by default.
+
+
+ Retrieve information from the video media stream.
+
+
+
+
+
+ R/O Retrieve RTCP statistics.
+
+ When rtcp is specified, the
+ statistic parameter must be provided. It specifies
+ which RTCP statistic parameter to read.
+
+
+ Retrieve a summary of all RTCP statistics.
+ The following data items are returned in a semi-colon
+ delineated list:
+
+
+ Our Synchronization Source identifier
+
+
+ Their Synchronization Source identifier
+
+
+ Our lost packet count
+
+
+ Received packet jitter
+
+
+ Received packet count
+
+
+ Transmitted packet jitter
+
+
+ Transmitted packet count
+
+
+ Remote lost packet count
+
+
+ Round trip time
+
+
+ Transmitted Media Experience Score
+
+
+ Received Media Experience Score
+
+
+
+
+ Retrieve a summary of all RTCP Jitter statistics.
+ The following data items are returned in a semi-colon
+ delineated list:
+
+
+ Our minimum jitter
+
+
+ Our max jitter
+
+
+ Our average jitter
+
+
+ Our jitter standard deviation
+
+
+ Their minimum jitter
+
+
+ Their max jitter
+
+
+ Their average jitter
+
+
+ Their jitter standard deviation
+
+
+
+
+ Retrieve a summary of all RTCP packet loss statistics.
+ The following data items are returned in a semi-colon
+ delineated list:
+
+
+ Our minimum lost packets
+
+
+ Our max lost packets
+
+
+ Our average lost packets
+
+
+ Our lost packets standard deviation
+
+
+ Their minimum lost packets
+
+
+ Their max lost packets
+
+
+ Their average lost packets
+
+
+ Their lost packets standard deviation
+
+
+
+
+ Retrieve a summary of all RTCP round trip time information.
+ The following data items are returned in a semi-colon
+ delineated list:
+
+
+ Minimum round trip time
+
+
+ Maximum round trip time
+
+
+ Average round trip time
+
+
+ Standard deviation round trip time
+
+
+
+
+ Retrieve a summary of all RTCP Media Experience Score information.
+ The following data items are returned in a semi-colon
+ delineated list:
+
+
+ Minimum MES based on us analysing received packets.
+
+
+ Maximum MES based on us analysing received packets.
+
+
+ Average MES based on us analysing received packets.
+
+
+ Standard deviation MES based on us analysing received packets.
+
+
+ Minimum MES based on data we get in Sender and Receiver Reports sent by the remote end
+
+
+ Maximum MES based on data we get in Sender and Receiver Reports sent by the remote end
+
+
+ Average MES based on data we get in Sender and Receiver Reports sent by the remote end
+
+
+ Standard deviation MES based on data we get in Sender and Receiver Reports sent by the remote end
+
+
+
+ Transmitted packet count
+ Received packet count
+ Transmitted packet jitter
+ Received packet jitter
+ Their max jitter
+ Their minimum jitter
+ Their average jitter
+ Their jitter standard deviation
+ Our max jitter
+ Our minimum jitter
+ Our average jitter
+ Our jitter standard deviation
+ Transmitted packet loss
+ Received packet loss
+ Their max lost packets
+ Their minimum lost packets
+ Their average lost packets
+ Their lost packets standard deviation
+ Our max lost packets
+ Our minimum lost packets
+ Our average lost packets
+ Our lost packets standard deviation
+ Round trip time
+ Maximum round trip time
+ Minimum round trip time
+ Average round trip time
+ Standard deviation round trip time
+ Our Synchronization Source identifier
+ Their Synchronization Source identifier
+
+ Current MES based on us analyzing rtt, jitter and loss
+ in the actual received RTP stream received from the remote end.
+ I.E. This is the MES for the incoming audio stream.
+
+
+ Current MES based on rtt and the jitter and loss values in
+ RTCP sender and receiver reports we receive from the
+ remote end. I.E. This is the MES for the outgoing audio stream.
+
+ Max MES based on data we get in Sender and Receiver Reports sent by the remote end
+ Min MES based on data we get in Sender and Receiver Reports sent by the remote end
+ Average MES based on data we get in Sender and Receiver Reports sent by the remote end
+ Standard deviation MES based on data we get in Sender and Receiver Reports sent by the remote end
+ Max MES based on us analyzing the received RTP stream
+ Min MES based on us analyzing the received RTP stream
+ Average MES based on us analyzing the received RTP stream
+ Standard deviation MES based on us analyzing the received RTP stream
+
+
+
+ When rtcp is specified, the
+ media_type parameter may be provided. It specifies
+ which media stream the chosen RTCP parameter should be retrieved
+ from.
+
+
+ Retrieve information from the audio media stream.
+ If not specified, audio is used
+ by default.
+
+
+ Retrieve information from the video media stream.
+
+
+
+
+
+ R/O The name of the endpoint associated with this channel.
+ Use the PJSIP_ENDPOINT function to obtain
+ further endpoint related information.
+
+
+ R/O The name of the contact associated with this channel.
+ Use the PJSIP_CONTACT function to obtain
+ further contact related information. Note this may not be present and if so
+ is only available on outgoing legs.
+
+
+ R/O The name of the AOR associated with this channel.
+ Use the PJSIP_AOR function to obtain
+ further AOR related information. Note this may not be present and if so
+ is only available on outgoing legs.
+
+
+ R/O Obtain information about the current PJSIP channel and its
+ session.
+
+ When pjsip is specified, the
+ type parameter must be provided. It specifies
+ which signalling parameter to read.
+
+
+ The SIP call-id.
+
+
+ Whether or not the signalling uses a secure transport.
+
+ The signalling uses a non-secure transport.
+ The signalling uses a secure transport.
+
+
+
+ The contact URI where requests are sent.
+
+
+ The local URI.
+
+
+ Tag in From header
+
+
+ The remote URI.
+
+
+ Tag in To header
+
+
+ The request URI of the incoming INVITE
+ associated with the creation of this channel.
+
+
+ The current state of any T.38 fax on this channel.
+
+ T.38 faxing is disabled on this channel.
+ Asterisk has sent a re-INVITE to the remote end to initiate a T.38 fax.
+ The remote end has sent a re-INVITE to Asterisk to initiate a T.38 fax.
+ A T.38 fax session has been enabled.
+ A T.38 fax session was attempted but was rejected.
+
+
+
+ On inbound calls, the full IP address and port number that
+ the INVITE request was received on. On outbound
+ calls, the full IP address and port number that the INVITE
+ request was transmitted from.
+
+
+ On inbound calls, the full IP address and port number that
+ the INVITE request was received from. On outbound
+ calls, the full IP address and port number that the INVITE
+ request was transmitted to.
+
+
+
+
+
+
+
+
+ ; Log the current Call-ID
+ same => n,Log(NOTICE, ${CHANNEL(pjsip,call-id)})
+
+ ; Log the destination address of the audio stream
+ same => n,Log(NOTICE, ${CHANNEL(rtp,dest)})
+
+ ; Store the round-trip time associated with a
+ ; video stream in the CDR field video-rtt
+ same => n,Set(CDR(video-rtt)=${CHANNEL(rtcp,rtt,video)})
+
+
+
\ No newline at end of file
diff --git a/channels/pjsip/include/dialplan_functions.h b/channels/pjsip/include/dialplan_functions.h
index d0bf130fe8..03005d5d8f 100644
--- a/channels/pjsip/include/dialplan_functions.h
+++ b/channels/pjsip/include/dialplan_functions.h
@@ -148,4 +148,24 @@ int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char
*/
int pjsip_acf_parse_uri_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
-#endif /* _PJSIP_DIALPLAN_FUNCTIONS */
\ No newline at end of file
+/*!
+ * \brief Hang up an incoming PJSIP channel with a SIP response code
+ * \param chan The channel the function is called on
+ * \param data SIP response code or name
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+int pjsip_app_hangup(struct ast_channel *chan, const char *data);
+
+/*!
+ * \brief Manager action to hang up an incoming PJSIP channel with a SIP response code
+ * \param s session
+ * \param m message
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+int pjsip_action_hangup(struct mansession *s, const struct message *m);
+
+#endif /* _PJSIP_DIALPLAN_FUNCTIONS */
diff --git a/include/asterisk/manager.h b/include/asterisk/manager.h
index 66591c945f..1716532e55 100644
--- a/include/asterisk/manager.h
+++ b/include/asterisk/manager.h
@@ -621,4 +621,45 @@ void ast_manager_publish_event(const char *type, int class_type, struct ast_json
*/
struct stasis_message_router *ast_manager_get_message_router(void);
+/*!
+ * \brief Callback used by ast_manager_hangup_helper
+ * that will actually hangup a channel
+ *
+ * \param chan The channel to hang up
+ * \param causecode Cause code to set on the channel
+ */
+typedef void (*manager_hangup_handler_t)(struct ast_channel *chan, int causecode);
+
+/*!
+ * \brief Callback used by ast_manager_hangup_helper
+ * that will validate the cause code.
+
+ * \param channel_name Mostly for displaying log messages
+ * \param cause Cause code string
+ *
+ * \returns integer cause code
+ */
+typedef int (*manager_hangup_cause_validator_t)(const char *channel_name,
+ const char *cause);
+
+/*!
+ * \brief A manager helper function that hangs up a channel using a supplied
+ * channel type specific hangup function and cause code validator
+ *
+ * This function handles the lookup of channel(s) and the AMI interaction
+ * but uses the supplied callbacks to actually perform the hangup. It can be
+ * used to implement a custom AMI 'Hangup' action without having to duplicate
+ * all the code in the standard Hangup action.
+ *
+ * \param s Session
+ * \param m Message
+ * \param handler Function that actually performs the hangup
+ * \param cause_validator Function that validates the cause code
+ *
+ * \retval 0 on success.
+ * \retval non-zero on error.
+ */
+int ast_manager_hangup_helper(struct mansession *s, const struct message *m,
+ manager_hangup_handler_t handler, manager_hangup_cause_validator_t cause_validator);
+
#endif /* _ASTERISK_MANAGER_H */
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index 0f68a9bbcb..949f66fdc5 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -4212,5 +4212,17 @@ unsigned int ast_sip_get_all_codecs_on_empty_reinvite(void);
*/
const int ast_sip_hangup_sip2cause(int cause);
+/*!
+ * \brief Convert name to SIP response code
+ *
+ * \param name SIP response code name matching one of the
+ * enum names defined in "enum pjsip_status_code"
+ * defined in sip_msg.h. May be specified with or
+ * without the PJSIP_SC_ prefix.
+ *
+ * \retval SIP response code
+ * \retval -1 if matching code not found
+ */
+int ast_sip_str2rc(const char *name);
#endif /* _RES_PJSIP_H */
diff --git a/main/manager.c b/main/manager.c
index 47ccaa6e8f..490ac116e8 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -4649,7 +4649,9 @@ static int action_challenge(struct mansession *s, const struct message *m)
return 0;
}
-static int action_hangup(struct mansession *s, const struct message *m)
+int ast_manager_hangup_helper(struct mansession *s,
+ const struct message *m, manager_hangup_handler_t hangup_handler,
+ manager_hangup_cause_validator_t cause_validator)
{
struct ast_channel *c = NULL;
int causecode = 0; /* all values <= 0 mean 'do not set hangupcause in channel' */
@@ -4673,7 +4675,9 @@ static int action_hangup(struct mansession *s, const struct message *m)
idText[0] = '\0';
}
- if (!ast_strlen_zero(cause)) {
+ if (cause_validator) {
+ causecode = cause_validator(name_or_regex, cause);
+ } else if (!ast_strlen_zero(cause)) {
char *endptr;
causecode = strtol(cause, &endptr, 10);
if (causecode < 0 || causecode > 127 || *endptr != '\0') {
@@ -4700,7 +4704,7 @@ static int action_hangup(struct mansession *s, const struct message *m)
ast_sockaddr_stringify_addr(&s->session->addr),
ast_channel_name(c));
- ast_channel_softhangup_withcause_locked(c, causecode);
+ hangup_handler(c, causecode);
c = ast_channel_unref(c);
astman_send_ack(s, m, "Channel Hungup");
@@ -4746,7 +4750,7 @@ static int action_hangup(struct mansession *s, const struct message *m)
ast_sockaddr_stringify_addr(&s->session->addr),
ast_channel_name(c));
- ast_channel_softhangup_withcause_locked(c, causecode);
+ hangup_handler(c, causecode);
channels_matched++;
astman_append(s,
@@ -4766,6 +4770,12 @@ static int action_hangup(struct mansession *s, const struct message *m)
return 0;
}
+static int action_hangup(struct mansession *s, const struct message *m)
+{
+ return ast_manager_hangup_helper(s, m,
+ ast_channel_softhangup_withcause_locked, NULL);
+}
+
static int action_setvar(struct mansession *s, const struct message *m)
{
struct ast_channel *c = NULL;
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 781446eb2a..50bb6575fa 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -3618,6 +3618,118 @@ const int ast_sip_hangup_sip2cause(int cause)
return 0;
}
+struct response_code_map {
+ int code;
+ const char *long_name;
+ const char *short_name;
+};
+
+/*
+ * This map was generated from sip_msg.h with
+ *
+ * sed -n -r -e 's/^\s+(PJSIP_SC_([^ =]+))\s*=\s*[0-9]+,/{ \1, "\1", "\2" },/gp' \
+ * third-party/pjproject/source/pjsip/include/pjsip/sip_msg.h
+ *
+ */
+static const struct response_code_map rc_map[] = {
+ { PJSIP_SC_NULL, "PJSIP_SC_NULL", "NULL" },
+ { PJSIP_SC_TRYING, "PJSIP_SC_TRYING", "TRYING" },
+ { PJSIP_SC_RINGING, "PJSIP_SC_RINGING", "RINGING" },
+ { PJSIP_SC_CALL_BEING_FORWARDED, "PJSIP_SC_CALL_BEING_FORWARDED", "CALL_BEING_FORWARDED" },
+ { PJSIP_SC_QUEUED, "PJSIP_SC_QUEUED", "QUEUED" },
+ { PJSIP_SC_PROGRESS, "PJSIP_SC_PROGRESS", "PROGRESS" },
+ { PJSIP_SC_EARLY_DIALOG_TERMINATED, "PJSIP_SC_EARLY_DIALOG_TERMINATED", "EARLY_DIALOG_TERMINATED" },
+ { PJSIP_SC_OK, "PJSIP_SC_OK", "OK" },
+ { PJSIP_SC_ACCEPTED, "PJSIP_SC_ACCEPTED", "ACCEPTED" },
+ { PJSIP_SC_NO_NOTIFICATION, "PJSIP_SC_NO_NOTIFICATION", "NO_NOTIFICATION" },
+ { PJSIP_SC_MULTIPLE_CHOICES, "PJSIP_SC_MULTIPLE_CHOICES", "MULTIPLE_CHOICES" },
+ { PJSIP_SC_MOVED_PERMANENTLY, "PJSIP_SC_MOVED_PERMANENTLY", "MOVED_PERMANENTLY" },
+ { PJSIP_SC_MOVED_TEMPORARILY, "PJSIP_SC_MOVED_TEMPORARILY", "MOVED_TEMPORARILY" },
+ { PJSIP_SC_USE_PROXY, "PJSIP_SC_USE_PROXY", "USE_PROXY" },
+ { PJSIP_SC_ALTERNATIVE_SERVICE, "PJSIP_SC_ALTERNATIVE_SERVICE", "ALTERNATIVE_SERVICE" },
+ { PJSIP_SC_BAD_REQUEST, "PJSIP_SC_BAD_REQUEST", "BAD_REQUEST" },
+ { PJSIP_SC_UNAUTHORIZED, "PJSIP_SC_UNAUTHORIZED", "UNAUTHORIZED" },
+ { PJSIP_SC_PAYMENT_REQUIRED, "PJSIP_SC_PAYMENT_REQUIRED", "PAYMENT_REQUIRED" },
+ { PJSIP_SC_FORBIDDEN, "PJSIP_SC_FORBIDDEN", "FORBIDDEN" },
+ { PJSIP_SC_NOT_FOUND, "PJSIP_SC_NOT_FOUND", "NOT_FOUND" },
+ { PJSIP_SC_METHOD_NOT_ALLOWED, "PJSIP_SC_METHOD_NOT_ALLOWED", "METHOD_NOT_ALLOWED" },
+ { PJSIP_SC_NOT_ACCEPTABLE, "PJSIP_SC_NOT_ACCEPTABLE", "NOT_ACCEPTABLE" },
+ { PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED, "PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED", "PROXY_AUTHENTICATION_REQUIRED" },
+ { PJSIP_SC_REQUEST_TIMEOUT, "PJSIP_SC_REQUEST_TIMEOUT", "REQUEST_TIMEOUT" },
+ { PJSIP_SC_CONFLICT, "PJSIP_SC_CONFLICT", "CONFLICT" },
+ { PJSIP_SC_GONE, "PJSIP_SC_GONE", "GONE" },
+ { PJSIP_SC_LENGTH_REQUIRED, "PJSIP_SC_LENGTH_REQUIRED", "LENGTH_REQUIRED" },
+ { PJSIP_SC_CONDITIONAL_REQUEST_FAILED, "PJSIP_SC_CONDITIONAL_REQUEST_FAILED", "CONDITIONAL_REQUEST_FAILED" },
+ { PJSIP_SC_REQUEST_ENTITY_TOO_LARGE, "PJSIP_SC_REQUEST_ENTITY_TOO_LARGE", "REQUEST_ENTITY_TOO_LARGE" },
+ { PJSIP_SC_REQUEST_URI_TOO_LONG, "PJSIP_SC_REQUEST_URI_TOO_LONG", "REQUEST_URI_TOO_LONG" },
+ { PJSIP_SC_UNSUPPORTED_MEDIA_TYPE, "PJSIP_SC_UNSUPPORTED_MEDIA_TYPE", "UNSUPPORTED_MEDIA_TYPE" },
+ { PJSIP_SC_UNSUPPORTED_URI_SCHEME, "PJSIP_SC_UNSUPPORTED_URI_SCHEME", "UNSUPPORTED_URI_SCHEME" },
+ { PJSIP_SC_UNKNOWN_RESOURCE_PRIORITY, "PJSIP_SC_UNKNOWN_RESOURCE_PRIORITY", "UNKNOWN_RESOURCE_PRIORITY" },
+ { PJSIP_SC_BAD_EXTENSION, "PJSIP_SC_BAD_EXTENSION", "BAD_EXTENSION" },
+ { PJSIP_SC_EXTENSION_REQUIRED, "PJSIP_SC_EXTENSION_REQUIRED", "EXTENSION_REQUIRED" },
+ { PJSIP_SC_SESSION_TIMER_TOO_SMALL, "PJSIP_SC_SESSION_TIMER_TOO_SMALL", "SESSION_TIMER_TOO_SMALL" },
+ { PJSIP_SC_INTERVAL_TOO_BRIEF, "PJSIP_SC_INTERVAL_TOO_BRIEF", "INTERVAL_TOO_BRIEF" },
+ { PJSIP_SC_BAD_LOCATION_INFORMATION, "PJSIP_SC_BAD_LOCATION_INFORMATION", "BAD_LOCATION_INFORMATION" },
+ { PJSIP_SC_USE_IDENTITY_HEADER, "PJSIP_SC_USE_IDENTITY_HEADER", "USE_IDENTITY_HEADER" },
+ { PJSIP_SC_PROVIDE_REFERRER_HEADER, "PJSIP_SC_PROVIDE_REFERRER_HEADER", "PROVIDE_REFERRER_HEADER" },
+ { PJSIP_SC_FLOW_FAILED, "PJSIP_SC_FLOW_FAILED", "FLOW_FAILED" },
+ { PJSIP_SC_ANONIMITY_DISALLOWED, "PJSIP_SC_ANONIMITY_DISALLOWED", "ANONIMITY_DISALLOWED" },
+ { PJSIP_SC_BAD_IDENTITY_INFO, "PJSIP_SC_BAD_IDENTITY_INFO", "BAD_IDENTITY_INFO" },
+ { PJSIP_SC_UNSUPPORTED_CERTIFICATE, "PJSIP_SC_UNSUPPORTED_CERTIFICATE", "UNSUPPORTED_CERTIFICATE" },
+ { PJSIP_SC_INVALID_IDENTITY_HEADER, "PJSIP_SC_INVALID_IDENTITY_HEADER", "INVALID_IDENTITY_HEADER" },
+ { PJSIP_SC_FIRST_HOP_LACKS_OUTBOUND_SUPPORT, "PJSIP_SC_FIRST_HOP_LACKS_OUTBOUND_SUPPORT", "FIRST_HOP_LACKS_OUTBOUND_SUPPORT" },
+ { PJSIP_SC_MAX_BREADTH_EXCEEDED, "PJSIP_SC_MAX_BREADTH_EXCEEDED", "MAX_BREADTH_EXCEEDED" },
+ { PJSIP_SC_BAD_INFO_PACKAGE, "PJSIP_SC_BAD_INFO_PACKAGE", "BAD_INFO_PACKAGE" },
+ { PJSIP_SC_CONSENT_NEEDED, "PJSIP_SC_CONSENT_NEEDED", "CONSENT_NEEDED" },
+ { PJSIP_SC_TEMPORARILY_UNAVAILABLE, "PJSIP_SC_TEMPORARILY_UNAVAILABLE", "TEMPORARILY_UNAVAILABLE" },
+ { PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, "PJSIP_SC_CALL_TSX_DOES_NOT_EXIST", "CALL_TSX_DOES_NOT_EXIST" },
+ { PJSIP_SC_LOOP_DETECTED, "PJSIP_SC_LOOP_DETECTED", "LOOP_DETECTED" },
+ { PJSIP_SC_TOO_MANY_HOPS, "PJSIP_SC_TOO_MANY_HOPS", "TOO_MANY_HOPS" },
+ { PJSIP_SC_ADDRESS_INCOMPLETE, "PJSIP_SC_ADDRESS_INCOMPLETE", "ADDRESS_INCOMPLETE" },
+ { PJSIP_SC_BUSY_HERE, "PJSIP_SC_BUSY_HERE", "BUSY_HERE" },
+ { PJSIP_SC_REQUEST_TERMINATED, "PJSIP_SC_REQUEST_TERMINATED", "REQUEST_TERMINATED" },
+ { PJSIP_SC_NOT_ACCEPTABLE_HERE, "PJSIP_SC_NOT_ACCEPTABLE_HERE", "NOT_ACCEPTABLE_HERE" },
+ { PJSIP_SC_BAD_EVENT, "PJSIP_SC_BAD_EVENT", "BAD_EVENT" },
+ { PJSIP_SC_REQUEST_UPDATED, "PJSIP_SC_REQUEST_UPDATED", "REQUEST_UPDATED" },
+ { PJSIP_SC_REQUEST_PENDING, "PJSIP_SC_REQUEST_PENDING", "REQUEST_PENDING" },
+ { PJSIP_SC_UNDECIPHERABLE, "PJSIP_SC_UNDECIPHERABLE", "UNDECIPHERABLE" },
+ { PJSIP_SC_SECURITY_AGREEMENT_NEEDED, "PJSIP_SC_SECURITY_AGREEMENT_NEEDED", "SECURITY_AGREEMENT_NEEDED" },
+ { PJSIP_SC_INTERNAL_SERVER_ERROR, "PJSIP_SC_INTERNAL_SERVER_ERROR", "INTERNAL_SERVER_ERROR" },
+ { PJSIP_SC_NOT_IMPLEMENTED, "PJSIP_SC_NOT_IMPLEMENTED", "NOT_IMPLEMENTED" },
+ { PJSIP_SC_BAD_GATEWAY, "PJSIP_SC_BAD_GATEWAY", "BAD_GATEWAY" },
+ { PJSIP_SC_SERVICE_UNAVAILABLE, "PJSIP_SC_SERVICE_UNAVAILABLE", "SERVICE_UNAVAILABLE" },
+ { PJSIP_SC_SERVER_TIMEOUT, "PJSIP_SC_SERVER_TIMEOUT", "SERVER_TIMEOUT" },
+ { PJSIP_SC_VERSION_NOT_SUPPORTED, "PJSIP_SC_VERSION_NOT_SUPPORTED", "VERSION_NOT_SUPPORTED" },
+ { PJSIP_SC_MESSAGE_TOO_LARGE, "PJSIP_SC_MESSAGE_TOO_LARGE", "MESSAGE_TOO_LARGE" },
+ { PJSIP_SC_PUSH_NOTIFICATION_SERVICE_NOT_SUPPORTED, "PJSIP_SC_PUSH_NOTIFICATION_SERVICE_NOT_SUPPORTED", "PUSH_NOTIFICATION_SERVICE_NOT_SUPPORTED" },
+ { PJSIP_SC_PRECONDITION_FAILURE, "PJSIP_SC_PRECONDITION_FAILURE", "PRECONDITION_FAILURE" },
+ { PJSIP_SC_BUSY_EVERYWHERE, "PJSIP_SC_BUSY_EVERYWHERE", "BUSY_EVERYWHERE" },
+ { PJSIP_SC_DECLINE, "PJSIP_SC_DECLINE", "DECLINE" },
+ { PJSIP_SC_DOES_NOT_EXIST_ANYWHERE, "PJSIP_SC_DOES_NOT_EXIST_ANYWHERE", "DOES_NOT_EXIST_ANYWHERE" },
+ { PJSIP_SC_NOT_ACCEPTABLE_ANYWHERE, "PJSIP_SC_NOT_ACCEPTABLE_ANYWHERE", "NOT_ACCEPTABLE_ANYWHERE" },
+ { PJSIP_SC_UNWANTED, "PJSIP_SC_UNWANTED", "UNWANTED" },
+ { PJSIP_SC_REJECTED, "PJSIP_SC_REJECTED", "REJECTED" },
+};
+
+int ast_sip_str2rc(const char *name)
+{
+ int i;
+
+ if (ast_strlen_zero(name)) {
+ return -1;
+ }
+
+ for (i = 0; i < ARRAY_LEN(rc_map); i++) {
+ if (strcasecmp(rc_map[i].short_name, name) == 0 ||
+ strcasecmp(rc_map[i].long_name, name) == 0) {
+ return rc_map[i].code;
+ }
+ }
+
+ return -1;
+}
+
+
#ifdef TEST_FRAMEWORK
AST_TEST_DEFINE(xml_sanitization_end_null)
{