<p>Joshua Colp has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/15432">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_pjsip_session: Always produce offer on re-INVITE without SDP.<br><br>When PJSIP receives a re-INVITE without an SDP offer the INVITE<br>session library will first call the on_create_offer callback and<br>if unavailable then use the active negotiated SDP as the offer.<br><br>In some cases this would result in a different SDP then was<br>previously used without an incremented SDP version number. The two<br>known cases are:<br><br>1. Sending an initial INVITE with a set of codecs and having the<br>remote side answer with a subset. The active negotiated SDP would<br>have the pruned list but would not have an incremented SDP version<br>number.<br><br>2. Using re-INVITE for unhold. We would modify the active negotiated<br>SDP but would not increment the SDP version.<br><br>To solve these, and potential other unknown cases, the on_create_offer<br>callback has now been implemented which produces a fresh offer with<br>incremented SDP version number. This better fits within the model<br>provided by the INVITE session library.<br><br>ASTERISK-28452<br><br>Change-Id: I2d81048d54edcb80fe38fdbb954a86f0a58281a1<br>---<br>M res/res_pjsip_session.c<br>1 file changed, 62 insertions(+), 53 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/32/15432/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c</span><br><span>index d841aca..d953dc0 100644</span><br><span>--- a/res/res_pjsip_session.c</span><br><span>+++ b/res/res_pjsip_session.c</span><br><span>@@ -2782,56 +2782,6 @@</span><br><span>    }</span><br><span> </span><br><span>        if (!sdp_info->sdp) {</span><br><span style="color: hsl(0, 100%, 40%);">-                const pjmedia_sdp_session *local;</span><br><span style="color: hsl(0, 100%, 40%);">-               int i;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_queue_unhold(session->channel);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-          pjmedia_sdp_neg_get_active_local(session->inv_session->neg, &local);</span><br><span style="color: hsl(0, 100%, 40%);">-          if (!local) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   return PJ_FALSE;</span><br><span style="color: hsl(0, 100%, 40%);">-                }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               /*</span><br><span style="color: hsl(0, 100%, 40%);">-               * Some devices indicate hold with deferred SDP reinvites (i.e. no SDP in the reinvite).</span><br><span style="color: hsl(0, 100%, 40%);">-                 * When hold is initially indicated, we</span><br><span style="color: hsl(0, 100%, 40%);">-          * - Receive an INVITE with no SDP</span><br><span style="color: hsl(0, 100%, 40%);">-               * - Send a 200 OK with SDP, indicating sendrecv in the media streams</span><br><span style="color: hsl(0, 100%, 40%);">-            * - Receive an ACK with SDP, indicating sendonly in the media streams</span><br><span style="color: hsl(0, 100%, 40%);">-           *</span><br><span style="color: hsl(0, 100%, 40%);">-               * At this point, the pjmedia negotiator saves the state of the media direction so that</span><br><span style="color: hsl(0, 100%, 40%);">-          * if we are to send any offers, we'll offer recvonly in the media streams. This is</span><br><span style="color: hsl(0, 100%, 40%);">-          * problematic if the device is attempting to unhold, though. If the device unholds</span><br><span style="color: hsl(0, 100%, 40%);">-              * by sending a reinvite with no SDP, then we will respond with a 200 OK with recvonly.</span><br><span style="color: hsl(0, 100%, 40%);">-          * According to RFC 3264, if an offerer offers recvonly, then the answerer MUST respond</span><br><span style="color: hsl(0, 100%, 40%);">-          * with sendonly or inactive. The result of this is that the stream is not off hold.</span><br><span style="color: hsl(0, 100%, 40%);">-             *</span><br><span style="color: hsl(0, 100%, 40%);">-               * Therefore, in this case, when we receive a reinvite while the stream is on hold, we</span><br><span style="color: hsl(0, 100%, 40%);">-           * need to be sure to offer sendrecv. This way, the answerer can respond with sendrecv</span><br><span style="color: hsl(0, 100%, 40%);">-           * in order to get the stream off hold. If this is actually a different purpose reinvite</span><br><span style="color: hsl(0, 100%, 40%);">-                 * (like a session timer refresh), then the answerer can respond to our sendrecv with</span><br><span style="color: hsl(0, 100%, 40%);">-            * sendonly, keeping the stream on hold.</span><br><span style="color: hsl(0, 100%, 40%);">-                 */</span><br><span style="color: hsl(0, 100%, 40%);">-             for (i = 0; i < local->media_count; ++i) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        pjmedia_sdp_media *m = local->media[i];</span><br><span style="color: hsl(0, 100%, 40%);">-                      pjmedia_sdp_attr *recvonly;</span><br><span style="color: hsl(0, 100%, 40%);">-                     pjmedia_sdp_attr *inactive;</span><br><span style="color: hsl(0, 100%, 40%);">-                     pjmedia_sdp_attr *sendonly;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                     recvonly = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "recvonly", NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-                    inactive = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "inactive", NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-                    sendonly = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "sendonly", NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-                    if (recvonly || inactive || sendonly) {</span><br><span style="color: hsl(0, 100%, 40%);">-                         pjmedia_sdp_attr *to_remove = recvonly ?: inactive ?: sendonly;</span><br><span style="color: hsl(0, 100%, 40%);">-                         pjmedia_sdp_attr *sendrecv;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                             pjmedia_sdp_attr_remove(&m->attr_count, m->attr, to_remove);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                          sendrecv = pjmedia_sdp_attr_create(session->inv_session->pool, "sendrecv", NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-                               pjmedia_sdp_media_add_attr(m, sendrecv);</span><br><span style="color: hsl(0, 100%, 40%);">-                        }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>            return PJ_FALSE;</span><br><span>     }</span><br><span> </span><br><span>@@ -5281,12 +5231,70 @@</span><br><span>      SCOPE_EXIT_RTN("%s: create_local_sdp failed\n", ast_sip_session_get_name(session));</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#if 0</span><br><span> static void session_inv_on_create_offer(pjsip_inv_session *inv, pjmedia_sdp_session **p_offer)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-      /* XXX STUB */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_sip_session *session = inv->mod_data[session_module.id];</span><br><span style="color: hsl(120, 100%, 40%);">+        const pjmedia_sdp_session *previous_sdp = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       pjmedia_sdp_session *offer;</span><br><span style="color: hsl(120, 100%, 40%);">+   int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (inv->neg) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (pjmedia_sdp_neg_was_answer_remote(inv->neg)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 pjmedia_sdp_neg_get_active_remote(inv->neg, &previous_sdp);</span><br><span style="color: hsl(120, 100%, 40%);">+            } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      pjmedia_sdp_neg_get_active_local(inv->neg, &previous_sdp);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   offer = create_local_sdp(inv, session, previous_sdp);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!offer) {</span><br><span style="color: hsl(120, 100%, 40%);">+         return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_queue_unhold(session->channel);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /*</span><br><span style="color: hsl(120, 100%, 40%);">+     * Some devices indicate hold with deferred SDP reinvites (i.e. no SDP in the reinvite).</span><br><span style="color: hsl(120, 100%, 40%);">+       * When hold is initially indicated, we</span><br><span style="color: hsl(120, 100%, 40%);">+        * - Receive an INVITE with no SDP</span><br><span style="color: hsl(120, 100%, 40%);">+     * - Send a 200 OK with SDP, indicating sendrecv in the media streams</span><br><span style="color: hsl(120, 100%, 40%);">+  * - Receive an ACK with SDP, indicating sendonly in the media streams</span><br><span style="color: hsl(120, 100%, 40%);">+         *</span><br><span style="color: hsl(120, 100%, 40%);">+     * At this point, the pjmedia negotiator saves the state of the media direction so that</span><br><span style="color: hsl(120, 100%, 40%);">+        * if we are to send any offers, we'll offer recvonly in the media streams. This is</span><br><span style="color: hsl(120, 100%, 40%);">+        * problematic if the device is attempting to unhold, though. If the device unholds</span><br><span style="color: hsl(120, 100%, 40%);">+    * by sending a reinvite with no SDP, then we will respond with a 200 OK with recvonly.</span><br><span style="color: hsl(120, 100%, 40%);">+        * According to RFC 3264, if an offerer offers recvonly, then the answerer MUST respond</span><br><span style="color: hsl(120, 100%, 40%);">+        * with sendonly or inactive. The result of this is that the stream is not off hold.</span><br><span style="color: hsl(120, 100%, 40%);">+   *</span><br><span style="color: hsl(120, 100%, 40%);">+     * Therefore, in this case, when we receive a reinvite while the stream is on hold, we</span><br><span style="color: hsl(120, 100%, 40%);">+         * need to be sure to offer sendrecv. This way, the answerer can respond with sendrecv</span><br><span style="color: hsl(120, 100%, 40%);">+         * in order to get the stream off hold. If this is actually a different purpose reinvite</span><br><span style="color: hsl(120, 100%, 40%);">+       * (like a session timer refresh), then the answerer can respond to our sendrecv with</span><br><span style="color: hsl(120, 100%, 40%);">+  * sendonly, keeping the stream on hold.</span><br><span style="color: hsl(120, 100%, 40%);">+       */</span><br><span style="color: hsl(120, 100%, 40%);">+   for (i = 0; i < offer->media_count; ++i) {</span><br><span style="color: hsl(120, 100%, 40%);">+              pjmedia_sdp_media *m = offer->media[i];</span><br><span style="color: hsl(120, 100%, 40%);">+            pjmedia_sdp_attr *recvonly;</span><br><span style="color: hsl(120, 100%, 40%);">+           pjmedia_sdp_attr *inactive;</span><br><span style="color: hsl(120, 100%, 40%);">+           pjmedia_sdp_attr *sendonly;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         recvonly = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "recvonly", NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+          inactive = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "inactive", NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+          sendonly = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "sendonly", NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (recvonly || inactive || sendonly) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       pjmedia_sdp_attr *to_remove = recvonly ?: inactive ?: sendonly;</span><br><span style="color: hsl(120, 100%, 40%);">+                       pjmedia_sdp_attr *sendrecv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                 pjmedia_sdp_attr_remove(&m->attr_count, m->attr, to_remove);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                      sendrecv = pjmedia_sdp_attr_create(session->inv_session->pool, "sendrecv", NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                     pjmedia_sdp_media_add_attr(m, sendrecv);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   *p_offer = offer;</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span> </span><br><span> static void session_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status)</span><br><span> {</span><br><span>@@ -5415,6 +5423,7 @@</span><br><span>         .on_new_session = session_inv_on_new_session,</span><br><span>        .on_tsx_state_changed = session_inv_on_tsx_state_changed,</span><br><span>    .on_rx_offer = session_inv_on_rx_offer,</span><br><span style="color: hsl(120, 100%, 40%);">+       .on_create_offer = session_inv_on_create_offer,</span><br><span>      .on_media_update = session_inv_on_media_update,</span><br><span>      .on_redirected = session_inv_on_redirected,</span><br><span> };</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/15432">change 15432</a>. To unsubscribe, or for help writing mail filters, 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/c/asterisk/+/15432"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 18 </div>
<div style="display:none"> Gerrit-Change-Id: I2d81048d54edcb80fe38fdbb954a86f0a58281a1 </div>
<div style="display:none"> Gerrit-Change-Number: 15432 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Joshua Colp <jcolp@sangoma.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>