[Asterisk-code-review] channels/chan pjsip: Add PJSIP SEND SESSION REFRESH (asterisk[13])
Matt Jordan
asteriskteam at digium.com
Mon Aug 8 12:04:35 CDT 2016
Matt Jordan has uploaded a new change for review.
https://gerrit.asterisk.org/3426
Change subject: channels/chan_pjsip: Add PJSIP_SEND_SESSION_REFRESH
......................................................................
channels/chan_pjsip: Add PJSIP_SEND_SESSION_REFRESH
This patch adds a new PJSIP specific dialplan function,
PJSIP_SEND_SESSION_REFRESH. When invoked on a PJSIP channel, the media
session will be refreshed via either an UPDATE or re-INVITE request.
When used in conjunction with the PJSIP_MEDIA_OFFER dialplan function,
the formats in use on a PJSIP channel can be re-negotiated and changed
dynamically after call setup.
ASTERISK-26277 #close
Change-Id: Ib98fe09ba889aafe26d58d32f0fd1323f8fd9b1b
---
M channels/chan_pjsip.c
M channels/pjsip/dialplan_functions.c
M channels/pjsip/include/dialplan_functions.h
3 files changed, 139 insertions(+), 1 deletion(-)
git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/26/3426/1
diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
index 98b4cf8..82f716f 100644
--- a/channels/chan_pjsip.c
+++ b/channels/chan_pjsip.c
@@ -2384,6 +2384,11 @@
.write = pjsip_acf_media_offer_write
};
+static struct ast_custom_function session_refresh_function = {
+ .name = "PJSIP_SEND_SESSION_REFRESH",
+ .write = pjsip_acf_session_refresh_write,
+};
+
/*!
* \brief Load the module
*
@@ -2420,6 +2425,11 @@
if (ast_custom_function_register(&media_offer_function)) {
ast_log(LOG_WARNING, "Unable to register PJSIP_MEDIA_OFFER dialplan function\n");
+ goto end;
+ }
+
+ if (ast_custom_function_register(&session_refresh_function)) {
+ ast_log(LOG_WARNING, "Unable to register PJSIP_SEND_SESSION_REFRESH dialplan function\n");
goto end;
}
@@ -2479,6 +2489,7 @@
pjsip_uids_onhold = NULL;
ast_custom_function_unregister(&media_offer_function);
ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
+ ast_custom_function_unregister(&session_refresh_function);
ast_channel_unregister(&chan_pjsip_tech);
ast_rtp_glue_unregister(&chan_pjsip_rtp_glue);
@@ -2500,6 +2511,7 @@
ast_custom_function_unregister(&media_offer_function);
ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
+ ast_custom_function_unregister(&session_refresh_function);
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 b566503..7962a75 100644
--- a/channels/pjsip/dialplan_functions.c
+++ b/channels/pjsip/dialplan_functions.c
@@ -59,8 +59,55 @@
</parameter>
</syntax>
<description>
- <para>Returns the codecs offered based upon the media choice</para>
+ <para>When read, returns the codecs offered based upon the media choice.</para>
+ <para>When written, sets the codecs to offer when an outbound dial attempt is made,
+ or when a session refresh is sent using <replaceable>PJSIP_SEND_SESSION_REFRESH</replaceable>.
+ </para>
</description>
+ <see-also>
+ <ref type="function">PJSIP_SEND_SESSION_REFRESH</ref>
+ </see-also>
+</function>
+<function name="PJSIP_SEND_SESSION_REFRESH" language="en_US">
+ <synopsis>
+ W/O: Initiate a session refresh via an UPDATE or re-INVITE on an established media session
+ </synopsis>
+ <syntax>
+ <parameter name="update_type" required="false">
+ <para>The type of update to send. Default is <literal>invite</literal>.</para>
+ <enumlist>
+ <enum name="invite">
+ <para>Send the session refresh as a re-INVITE.</para>
+ </enum>
+ <enum name="update">
+ <para>Send the session refresh as an UPDATE.</para>
+ </enum>
+ </enumlist>
+ </parameter>
+ </syntax>
+ <description>
+ <para>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.
+ </para>
+ <para>This is most useful when combined with the <replaceable>PJSIP_MEDIA_OFFER</replaceable>
+ dialplan function, as it allows the formats in use on a channel to be
+ re-negotiated after call setup.</para>
+ <warning>
+ <para>The formats the endpoint supports are <emphasis>not</emphasis>
+ checked or enforced by this function. Using this function to offer
+ formats not supported by the endpoint <emphasis>may</emphasis> result
+ in a loss of media.</para>
+ </warning>
+ <example title="Re-negotiate format to g722">
+ ; 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)
+ </example>
+ </description>
+ <see-also>
+ <ref type="function">PJSIP_MEDIA_OFFER</ref>
+ </see-also>
</function>
<info name="PJSIPCHANNEL" language="en_US" tech="PJSIP">
<enumlist>
@@ -961,3 +1008,70 @@
return ast_sip_push_task_synchronous(channel->session->serializer, media_offer_write_av, &mdata);
}
+
+struct refresh_data {
+ struct ast_sip_session *session;
+ enum ast_sip_session_refresh_method method;
+};
+
+static int sip_session_response_cb(struct ast_sip_session *session, pjsip_rx_data *rdata)
+{
+ struct ast_format *fmt;
+
+ if (!session->channel) {
+ /* Egads! */
+ return 0;
+ }
+
+ fmt = ast_format_cap_get_best_by_type(ast_channel_nativeformats(session->channel), AST_MEDIA_TYPE_AUDIO);
+ if (!fmt) {
+ /* No format? That's weird. */
+ return 0;
+ }
+ ast_channel_set_writeformat(session->channel, fmt);
+ ast_channel_set_rawwriteformat(session->channel, fmt);
+ ast_channel_set_readformat(session->channel, fmt);
+ ast_channel_set_rawreadformat(session->channel, fmt);
+ ao2_ref(fmt, -1);
+
+ return 0;
+}
+
+static int refresh_write_cb(void *obj)
+{
+ struct refresh_data *data = obj;
+
+ ast_sip_session_refresh(data->session, NULL, NULL,
+ sip_session_response_cb, data->method, 1);
+
+ return 0;
+}
+
+int pjsip_acf_session_refresh_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
+{
+ struct ast_sip_channel_pvt *channel;
+ struct refresh_data rdata = {
+ .method = AST_SIP_SESSION_REFRESH_METHOD_INVITE,
+ };
+
+ if (!chan) {
+ ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
+ return -1;
+ }
+
+ if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
+ ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
+ return -1;
+ }
+
+ channel = ast_channel_tech_pvt(chan);
+ rdata.session = channel->session;
+
+ if (!strcmp(value, "invite")) {
+ rdata.method = AST_SIP_SESSION_REFRESH_METHOD_INVITE;
+ } else if (!strcmp(value, "update")) {
+ rdata.method = AST_SIP_SESSION_REFRESH_METHOD_UPDATE;
+ }
+
+ return ast_sip_push_task_synchronous(channel->session->serializer, refresh_write_cb, &rdata);
+}
diff --git a/channels/pjsip/include/dialplan_functions.h b/channels/pjsip/include/dialplan_functions.h
index cbc06f0..8b80bfa 100644
--- a/channels/pjsip/include/dialplan_functions.h
+++ b/channels/pjsip/include/dialplan_functions.h
@@ -61,6 +61,18 @@
int pjsip_acf_media_offer_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
/*!
+ * \brief PJSIP_SEND_SESSION_REFRESH function write callback
+ * \param chan The channel the function is called on
+ * \param cmd the Name of the function
+ * \param data Arguments passed to the function
+ * \param value Value to be set by the function
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+int pjsip_acf_session_refresh_write(struct ast_channel *chan, const char *cmd, char *data, const char *value);
+
+/*!
* \brief PJSIP_DIAL_CONTACTS function read callback
* \param chan The channel the function is called on
* \param cmd The name of the function
--
To view, visit https://gerrit.asterisk.org/3426
To unsubscribe, visit https://gerrit.asterisk.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib98fe09ba889aafe26d58d32f0fd1323f8fd9b1b
Gerrit-PatchSet: 1
Gerrit-Project: asterisk
Gerrit-Branch: 13
Gerrit-Owner: Matt Jordan <mjordan at digium.com>
More information about the asterisk-code-review
mailing list