From 5f815f9dbaf78680fd7b21af27ed7fde900264fa Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Sun, 7 Aug 2016 09:58:59 -0500 Subject: 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 --- channels/pjsip/dialplan_functions.c | 116 +++++++++++++++++++++++++++- channels/pjsip/include/dialplan_functions.h | 12 +++ 2 files changed, 127 insertions(+), 1 deletion(-) (limited to 'channels/pjsip') diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index b5665039a..7962a7566 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -59,8 +59,55 @@ - Returns the codecs offered based upon the media choice + 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 + + + + + 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 + @@ -961,3 +1008,70 @@ int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char 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 cbc06f076..8b80bfa74 100644 --- a/channels/pjsip/include/dialplan_functions.h +++ b/channels/pjsip/include/dialplan_functions.h @@ -60,6 +60,18 @@ int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char */ 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 -- cgit v1.2.3