<p>Joshua Colp <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/6301">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Joshua Colp: Looks good to me, but someone else must approve; Approved for Submit
  George Joseph: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res/res_pjsip_session: allow SDP answer to be regenerated<br><br>If an SDP answer hasn't been sent yet, it's legal to change it.<br>This is required for PJSIP_DTMF_MODE to work correctly, and can<br>also have use in the future for updating codecs too.<br><br>ASTERISK-27209 #close<br><br>Change-Id: Idbbfb7cb3f72fbd96c94d10d93540f69bd51e7a1<br>---<br>M channels/pjsip/dialplan_functions.c<br>M include/asterisk/res_pjsip_session.h<br>M res/res_pjsip_session.c<br>M res/res_pjsip_session.exports.in<br>4 files changed, 62 insertions(+), 1 deletion(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c<br>index 13d9fab..857684a 100644<br>--- a/channels/pjsip/dialplan_functions.c<br>+++ b/channels/pjsip/dialplan_functions.c<br>@@ -1113,10 +1113,13 @@<br>         struct refresh_data *data = obj;<br> <br>   if (data->session->inv_session->state == PJSIP_INV_STATE_CONFIRMED) {<br>-               ast_debug(3, "Changing DTMF mode on channel %s after OFFER/ANSER completion. Sending session refresh\n", ast_channel_name(data->session->channel));<br>+          ast_debug(3, "Changing DTMF mode on channel %s after OFFER/ANSWER completion. Sending session refresh\n", ast_channel_name(data->session->channel));<br> <br>               ast_sip_session_refresh(data->session, NULL, NULL,<br>                         sip_session_response_cb, data->method, 1);<br>+        } else if (data->session->inv_session->state == PJSIP_INV_STATE_INCOMING) {<br>+         ast_debug(3, "Changing DTMF mode on channel %s during OFFER/ANSWER exchange. Updating SDP answer\n", ast_channel_name(data->session->channel));<br>+              ast_sip_session_regenerate_answer(data->session, NULL);<br>    }<br> <br>  return 0;<br>diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h<br>index ca331cb..d275c25 100644<br>--- a/include/asterisk/res_pjsip_session.h<br>+++ b/include/asterisk/res_pjsip_session.h<br>@@ -626,6 +626,23 @@<br>              int generate_new_sdp);<br> <br> /*!<br>+ * \brief Regenerate SDP Answer<br>+ *<br>+ * This method is used when an SDP offer has been received but an SDP answer<br>+ * has not been sent yet. It requests that a new local SDP be created and<br>+ * set as the SDP answer. As with any outgoing request in res_pjsip_session,<br>+ * this will call into registered supplements in case they wish to add anything.<br>+ *<br>+ * \param session The session on which the answer will be updated<br>+ * \param on_sdp_creation Callback called when SDP is created<br>+ * \param generate_new_sdp Boolean to indicate if a new SDP should be created<br>+ * \retval 0 Successfully updated the SDP answer<br>+ * \retval -1 Failure to updated the SDP answer<br>+ */<br>+int ast_sip_session_regenerate_answer(struct ast_sip_session *session,<br>+             ast_sip_session_sdp_creation_cb on_sdp_creation);<br>+<br>+/*!<br>  * \brief Send a SIP response<br>  *<br>  * This will send the SIP response specified in tdata and<br>diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c<br>index 2eb111c..42d37fe 100644<br>--- a/res/res_pjsip_session.c<br>+++ b/res/res_pjsip_session.c<br>@@ -968,6 +968,46 @@<br>        return 0;<br> }<br> <br>+int ast_sip_session_regenerate_answer(struct ast_sip_session *session,<br>+            ast_sip_session_sdp_creation_cb on_sdp_creation)<br>+{<br>+ pjsip_inv_session *inv_session = session->inv_session;<br>+    pjmedia_sdp_session *new_answer = NULL;<br>+      const pjmedia_sdp_session *previous_offer = NULL;<br>+<br>+ /* The SDP answer can only be regenerated if it is still pending to be sent */<br>+       if (!inv_session->neg || (pjmedia_sdp_neg_get_state(inv_session->neg) != PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER &&<br>+         pjmedia_sdp_neg_get_state(inv_session->neg) != PJMEDIA_SDP_NEG_STATE_WAIT_NEGO)) {<br>+                ast_log(LOG_WARNING, "Requested to regenerate local SDP answer for channel '%s' but negotiation in state '%s'\n",<br>+                  ast_channel_name(session->channel), pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_get_state(inv_session->neg)));<br>+           return -1;<br>+   }<br>+<br>+ pjmedia_sdp_neg_get_neg_remote(inv_session->neg, &previous_offer);<br>+    if (pjmedia_sdp_neg_get_state(inv_session->neg) == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) {<br>+             /* Transition the SDP negotiator back to when it received the remote offer */<br>+                pjmedia_sdp_neg_negotiate(inv_session->pool, inv_session->neg, 0);<br>+             pjmedia_sdp_neg_set_remote_offer(inv_session->pool, inv_session->neg, previous_offer);<br>+ }<br>+<br>+ new_answer = create_local_sdp(inv_session, session, previous_offer);<br>+ if (!new_answer) {<br>+           ast_log(LOG_WARNING, "Could not create a new local SDP answer for channel '%s'\n",<br>+                 ast_channel_name(session->channel));<br>+              return -1;<br>+   }<br>+<br>+ if (on_sdp_creation) {<br>+               if (on_sdp_creation(session, new_answer)) {<br>+                  return -1;<br>+           }<br>+    }<br>+<br>+ pjsip_inv_set_sdp_answer(inv_session, new_answer);<br>+<br>+        return 0;<br>+}<br>+<br> void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata)<br> {<br>      handle_outgoing_response(session, tdata);<br>diff --git a/res/res_pjsip_session.exports.in b/res/res_pjsip_session.exports.in<br>index fdfc5fb..5bc0bf4 100644<br>--- a/res/res_pjsip_session.exports.in<br>+++ b/res/res_pjsip_session.exports.in<br>@@ -14,6 +14,7 @@<br>                 LINKER_SYMBOL_PREFIXast_sip_session_remove_datastore;<br>                 LINKER_SYMBOL_PREFIXast_sip_session_get_identity;<br>             LINKER_SYMBOL_PREFIXast_sip_session_refresh;<br>+         LINKER_SYMBOL_PREFIXast_sip_session_regenerate_answer;<br>                LINKER_SYMBOL_PREFIXast_sip_session_send_response;<br>            LINKER_SYMBOL_PREFIXast_sip_session_send_request;<br>             LINKER_SYMBOL_PREFIXast_sip_session_create_invite;<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/6301">change 6301</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/6301"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 14 </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: Idbbfb7cb3f72fbd96c94d10d93540f69bd51e7a1 </div>
<div style="display:none"> Gerrit-Change-Number: 6301 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Torrey Searle <tsearle@gmail.com> </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </div>