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

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_pjsip_session:  Add ability to accept multiple sdp answers<br><br>pjproject by default currently will follow media forked during an INVITE<br>on outbound calls if the To tag is different on a subsequent response as<br>that on an earlier response.  We handle this correctly.  There have<br>been reported cases where the To tag is the same but we still need to<br>follow the media.  The pjproject patch in this commit adds the<br>capability to sip_inv and also adds the capability to control it at<br>runtime.  The original "different tag" behavior was always controllable<br>at runtime but we never did anything with it and left it to default to<br>TRUE.<br><br>So, along with the pjproject patch, this commit adds options to both the<br>system and endpoint objects to control the two behaviors, and a small<br>logic change to session_inv_on_media_update in res_pjsip_session to<br>control the behavior at the endpoint level.<br><br>The default behavior for "different tags" remains the same at TRUE and<br>the default for "same tag" is FALSE.<br><br>Change-Id: I64d071942b79adb2f0a4e13137389b19404fe3d6<br>ASTERISK-27936<br>Reported-by: Ross Beer<br>---<br>M CHANGES<br>M configs/samples/pjsip.conf.sample<br>M configure<br>M configure.ac<br>A contrib/ast-db-manage/config/versions/0be05c3a8225_add_early_media_options.py<br>M include/asterisk/autoconfig.h.in<br>M include/asterisk/res_pjsip.h<br>M res/res_pjsip.c<br>M res/res_pjsip/config_system.c<br>M res/res_pjsip/pjsip_configuration.c<br>M res/res_pjsip_session.c<br>M third-party/pjproject/configure.m4<br>A third-party/pjproject/patches/0100-sip_inv-Add-option-to-accept-updated-SDP-on-same-To-.patch<br>13 files changed, 505 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/CHANGES b/CHANGES<br>index 0a510af..a99fd37 100644<br>--- a/CHANGES<br>+++ b/CHANGES<br>@@ -40,6 +40,30 @@<br>    ConfbridgeWelcome has been added that will send a list of all<br>    current participants to a new participant.<br> <br>+res_pjsip<br>+------------------<br>+  * Two new options have been added to the system and endpoint objects to<br>+    control whether, on outbound calls, Asterisk will accept updated SDP answers<br>+    during the initial INVITE transaction when 100rel is not in effect.<br>+    This usually happens when the INVITE is forked to multiple UASs and more<br>+    than one sends an SDP answer or when a single UAS needs to change a media<br>+    port to switch from custom ringback to the actual media destination.<br>+<br>+    The 'follow_early_media_forked' option sets whether Asterisk will accept<br>+    the updated SDP when the To tag on the subsequent response is different than<br>+    that on the the previous response.  This usually occurs in the forked INVITE<br>+    scenario. The default value is "yes" which is the current behavior.<br>+<br>+    The 'accept_multiple_sdp_answers' flag sets whether Asterisk will accept the<br>+    updated SDP when the To tag on the subsequent response is the same as that<br>+    on the previous response. This can occur when a UAS needs to switch media<br>+    ports from custom ringback to the final media path.  The default value is<br>+    "no" which is the current behavior.<br>+<br>+    These options have to be enabled system-wide in the system config section<br>+    of pjsip.conf as well as on individual endpoints that require the<br>+    functionality.<br>+<br> ------------------------------------------------------------------------------<br> --- Functionality changes from Asterisk 15.3.0 to Asterisk 15.4.0 ------------<br> ------------------------------------------------------------------------------<br>diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample<br>index a39a867..9b64001 100644<br>--- a/configs/samples/pjsip.conf.sample<br>+++ b/configs/samples/pjsip.conf.sample<br>@@ -809,6 +809,27 @@<br>                         ; this mailbox will be used when notifying other modules<br>                         ; of MWI status changes.  If not set, incoming MWI<br>                         ; NOTIFYs are ignored.<br>+;follow_early_media_fork = ; On outgoing calls, if the UAS responds with<br>+                           ; different SDP attributes on subsequent 18X or 2XX<br>+                           ; responses (such as a port update) AND the To tag<br>+                           ; on the subsequent response is different than that<br>+                           ; on the previous one, follow it.  This usually<br>+                           ; happens when the INVITE is forked to multiple UASs<br>+                           ; and more than 1 sends an SDP answer.<br>+                           ; This option must also be enabled in the system<br>+                           ; section.<br>+                           ; (default: yes)<br>+;accept_multiple_sdp_answers =<br>+                           ; On outgoing calls, if the UAS responds with<br>+                           ; different SDP attributes on non-100rel 18X or 2XX<br>+                           ; responses (such as a port update) AND the To tag on<br>+                           ; the subsequent response is the same as that on the<br>+                           ; previous one, process it. This can happen when the<br>+                           ; UAS needs to change ports for some reason such as<br>+                           ; using a separate port for custom ringback.<br>+                           ; This option must also be enabled in the system<br>+                           ; section.<br>+                           ; (default: no)<br> <br> ;==========================AUTH SECTION OPTIONS=========================<br> ;[auth]<br>@@ -961,6 +982,27 @@<br>                         ; Disabling this option has been known to cause interoperability<br>                         ; issues, so disable at your own risk.<br>                         ; (default: "yes")<br>+;follow_early_media_fork = ; On outgoing calls, if the UAS responds with<br>+                           ; different SDP attributes on subsequent 18X or 2XX<br>+                           ; responses (such as a port update) AND the To tag<br>+                           ; on the subsequent response is different than that<br>+                           ; on the previous one, follow it.  This usually<br>+                           ; happens when the INVITE is forked to multiple UASs<br>+                           ; and more than 1 sends an SDP answer.<br>+                           ; This option must also be enabled on endpoints that<br>+                           ; require this functionality.<br>+                           ; (default: yes)<br>+;accept_multiple_sdp_answers =<br>+                           ; On outgoing calls, if the UAS responds with<br>+                           ; different SDP attributes on non-100rel 18X or 2XX<br>+                           ; responses (such as a port update) AND the To tag on<br>+                           ; the subsequent response is the same as that on the<br>+                           ; previous one, process it. This can happen when the<br>+                           ; UAS needs to change ports for some reason such as<br>+                           ; using a separate port for custom ringback.<br>+                           ; This option must also be enabled on endpoints that<br>+                           ; require this functionality.<br>+                           ; (default: no)<br> ;type=  ; Must be of type system (default: "")<br> <br> ;==========================GLOBAL SECTION OPTIONS=========================<br>diff --git a/configure b/configure<br>index 5d52867..720d9ad 100755<br>--- a/configure<br>+++ b/configure<br>@@ -934,6 +934,10 @@<br> POPT_DIR<br> POPT_INCLUDE<br> POPT_LIB<br>+PBX_PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS<br>+PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS_DIR<br>+PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS_INCLUDE<br>+PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS_LIB<br> PBX_PJSIP_TSX_LAYER_FIND_TSX2<br> PJSIP_TSX_LAYER_FIND_TSX2_DIR<br> PJSIP_TSX_LAYER_FIND_TSX2_INCLUDE<br>@@ -9293,6 +9297,9 @@<br> $as_echo "#define HAVE_PJSIP_TSX_LAYER_FIND_TSX2 1" >>confdefs.h<br> <br> <br>+$as_echo "#define HAVE_PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS 1" >>confdefs.h<br>+<br>+<br> <br> <br> <br>@@ -11449,6 +11456,18 @@<br> PJSIP_TSX_LAYER_FIND_TSX2_DIR=${PJPROJECT_DIR}<br> <br> PBX_PJSIP_TSX_LAYER_FIND_TSX2=0<br>+<br>+<br>+<br>+<br>+<br>+<br>+<br>+PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS_DESCRIP="PJSIP INVITE Accept Multiple SDP Answers"<br>+PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS_OPTION=pjsip<br>+PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS_DIR=${PJPROJECT_DIR}<br>+<br>+PBX_PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS=0<br> <br> <br> <br>@@ -25649,6 +25668,46 @@<br>       CPPFLAGS="${saved_cppflags}"<br>     fi<br> <br>+<br>+    if test "x${PBX_PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS}" != "x1" -a "${USE_PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS}" != "no"; then<br>+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if \"pjsip_cfg()->endpt.accept_multiple_sdp_answers = 0;\" compiles using pjsip.h" >&5<br>+$as_echo_n "checking if \"pjsip_cfg()->endpt.accept_multiple_sdp_answers = 0;\" compiles using pjsip.h... " >&6; }<br>+    saved_cppflags="${CPPFLAGS}"<br>+       if test "x${PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS_DIR}" != "x"; then<br>+         PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS_INCLUDE="-I${PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS_DIR}/include"<br>+ fi<br>+   CPPFLAGS="${CPPFLAGS} ${PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS_INCLUDE}"<br>+<br>+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext<br>+/* end confdefs.h.  */<br>+ #include <pjsip.h><br>+int<br>+main ()<br>+{<br>+ pjsip_cfg()->endpt.accept_multiple_sdp_answers = 0;;<br>+<br>+  ;<br>+  return 0;<br>+}<br>+_ACEOF<br>+if ac_fn_c_try_compile "$LINENO"; then :<br>+     { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5<br>+$as_echo "yes" >&6; }<br>+         PBX_PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS=1<br>+<br>+$as_echo "#define HAVE_PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS 1" >>confdefs.h<br>+<br>+<br>+<br>+else<br>+         { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5<br>+$as_echo "no" >&6; }<br>+<br>+fi<br>+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext<br>+    CPPFLAGS="${saved_cppflags}"<br>+    fi<br>+<br>       LIBS="${saved_libs}"<br>       CPPFLAGS="${saved_cppflags}"<br> <br>diff --git a/configure.ac b/configure.ac<br>index 67f04e5..50fe260 100644<br>--- a/configure.ac<br>+++ b/configure.ac<br>@@ -516,6 +516,7 @@<br> AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_INV_SESSION_REF], [PJSIP INVITE Session Reference Count support], [PJPROJECT], [pjsip])<br> AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_AUTH_CLT_DEINIT], [pjsip_auth_clt_deinit support], [PJPROJECT], [pjsip])<br> AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_TSX_LAYER_FIND_TSX2], [pjsip_tsx_layer_find_tsx2 support], [PJPROJECT], [pjsip])<br>+AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS], [PJSIP INVITE Accept Multiple SDP Answers], [PJPROJECT], [pjsip])<br> fi<br> <br> AST_EXT_LIB_SETUP([POPT], [popt], [popt])<br>@@ -2374,6 +2375,7 @@<br>       CPPFLAGS="${CPPFLAGS} ${PJPROJECT_CFLAGS}"<br>       LIBS="${LIBS} ${PJPROJECT_LIB}"<br>       AST_C_COMPILE_CHECK([PJSIP_TLS_TRANSPORT_PROTO], [struct pjsip_tls_setting setting; int proto; proto = setting.proto;], [pjsip.h])<br>+      AST_C_COMPILE_CHECK([PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS], [pjsip_cfg()->endpt.accept_multiple_sdp_answers = 0;], [pjsip.h])<br>       LIBS="${saved_libs}"<br>       CPPFLAGS="${saved_cppflags}"<br> <br>diff --git a/contrib/ast-db-manage/config/versions/0be05c3a8225_add_early_media_options.py b/contrib/ast-db-manage/config/versions/0be05c3a8225_add_early_media_options.py<br>new file mode 100644<br>index 0000000..d82b1d2<br>--- /dev/null<br>+++ b/contrib/ast-db-manage/config/versions/0be05c3a8225_add_early_media_options.py<br>@@ -0,0 +1,37 @@<br>+"""Add early media options<br>+<br>+Revision ID: 0be05c3a8225<br>+Revises: d3e4284f8707<br>+Create Date: 2018-06-18 17:26:16.737692<br>+<br>+"""<br>+<br>+# revision identifiers, used by Alembic.<br>+revision = '0be05c3a8225'<br>+down_revision = 'd3e4284f8707'<br>+<br>+from alembic import op<br>+import sqlalchemy as sa<br>+from sqlalchemy.dialects.postgresql import ENUM<br>+<br>+YESNO_NAME = 'yesno_values'<br>+YESNO_VALUES = ['yes', 'no']<br>+<br>+def upgrade():<br>+    yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)<br>+<br>+    op.add_column('ps_systems', sa.Column('follow_early_media_fork', yesno_values))<br>+    op.add_column('ps_systems', sa.Column('accept_multiple_sdp_answers', yesno_values))<br>+    op.add_column('ps_endpoints', sa.Column('follow_early_media_fork', yesno_values))<br>+    op.add_column('ps_endpoints', sa.Column('accept_multiple_sdp_answers', yesno_values))<br>+<br>+def downgrade():<br>+    if op.get_context().bind.dialect.name == 'mssql':<br>+        op.drop_constraint('ck_ps_systems_follow_early_media_fork_yesno_values','ps_systems')<br>+        op.drop_constraint('ck_ps_systems_accept_multiple_sdp_answers_yesno_values','ps_systems')<br>+        op.drop_constraint('ck_ps_endpoints_follow_early_media_fork_yesno_values','ps_endpoints')<br>+        op.drop_constraint('ck_ps_endpoints_accept_multiple_sdp_answers_yesno_values','ps_endpoints')<br>+    op.drop_column('ps_systems', 'follow_early_media_fork')<br>+    op.drop_column('ps_systems', 'accept_multiple_sdp_answers')<br>+    op.drop_column('ps_endpoints', 'follow_early_media_fork')<br>+    op.drop_column('ps_endpoints', 'accept_multiple_sdp_answers')<br>diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in<br>index ff82b67..4c07fc7 100644<br>--- a/include/asterisk/autoconfig.h.in<br>+++ b/include/asterisk/autoconfig.h.in<br>@@ -626,6 +626,10 @@<br> /* Define to 1 if PJPROJECT has the pjsip_get_dest_info support feature. */<br> #undef HAVE_PJSIP_GET_DEST_INFO<br> <br>+/* Define if your system has the PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS<br>+   headers. */<br>+#undef HAVE_PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS<br>+<br> /* Define to 1 if PJPROJECT has the PJSIP INVITE Session Reference Count<br>    support feature. */<br> #undef HAVE_PJSIP_INV_SESSION_REF<br>diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h<br>index d9c74fd..a678cd8 100644<br>--- a/include/asterisk/res_pjsip.h<br>+++ b/include/asterisk/res_pjsip.h<br>@@ -805,6 +805,10 @@<br>   unsigned int notify_early_inuse_ringing;<br>      /*! If set, we'll push incoming MWI NOTIFYs to stasis using this mailbox */<br>       AST_STRING_FIELD_EXTENDED(incoming_mwi_mailbox);<br>+     /*! Follow forked media with a different To tag */<br>+   unsigned int follow_early_media_fork;<br>+        /*! Accept updated SDPs on non-100rel 18X and 2XX responses with the same To tag */<br>+  unsigned int accept_multiple_sdp_answers;<br> };<br> <br> /*! URI parameter for symmetric transport */<br>diff --git a/res/res_pjsip.c b/res/res_pjsip.c<br>index b45fbd4..1f9e126 100644<br>--- a/res/res_pjsip.c<br>+++ b/res/res_pjsip.c<br>@@ -1080,6 +1080,36 @@<br>                                                 changes.  If not set, incoming MWI NOTIFYs are ignored.<br>                                       </para></description><br>                             </configOption><br>+                                <configOption name="follow_early_media_fork"><br>+                                        <synopsis>Follow SDP forked media when To tag is different</synopsis><br>+                                    <description><para><br>+                                              On outgoing calls, if the UAS responds with different SDP attributes<br>+                                         on subsequent 18X or 2XX responses (such as a port update) AND the<br>+                                           To tag on the subsequent response is different than that on the previous<br>+                                             one, follow it. This usually happens when the INVITE is forked to multiple<br>+                                           UASs and more than one sends an SDP answer.<br>+                                          </para><br>+                                                <note><para><br>+                                                     This option must also be enabled in the <literal>system</literal><br>+                                                        section for it to take effect here.<br>+                                          </para></note><br>+                                   </description><br>+                         </configOption><br>+                                <configOption name="accept_multiple_sdp_answers" default="no"><br>+                                     <synopsis>Accept multiple SDP answers on non-100rel responses</synopsis><br>+                                 <description><para><br>+                                              On outgoing calls, if the UAS responds with different SDP attributes<br>+                                         on non-100rel 18X or 2XX responses (such as a port update) AND the<br>+                                           To tag on the subsequent response is the same as that on the previous one,<br>+                                           process the updated SDP.  This can happen when the UAS needs to change ports<br>+                                         for some reason such as using a separate port for custom ringback.<br>+                                           </para><br>+                                                <note><para><br>+                                                     This option must also be enabled in the <literal>system</literal><br>+                                                        section for it to take effect here.<br>+                                          </para></note><br>+                                   </description><br>+                         </configOption><br>                         </configObject><br>                         <configObject name="auth"><br>                            <synopsis>Authentication type</synopsis><br>@@ -1647,6 +1677,34 @@<br>                                          request is too large.  See RFC 3261 section 18.1.1.<br>                                   </para></description><br>                             </configOption><br>+                                <configOption name="follow_early_media_fork"><br>+                                        <synopsis>Follow SDP forked media when To tag is different</synopsis><br>+                                    <description><para><br>+                                              On outgoing calls, if the UAS responds with different SDP attributes<br>+                                         on subsequent 18X or 2XX responses (such as a port update) AND the<br>+                                           To tag on the subsequent response is different than that on the previous<br>+                                             one, follow it.<br>+                                              </para><br>+                                                <note><para><br>+                                                     This option must also be enabled on endpoints that require<br>+                                                   this functionality.<br>+                                          </para></note><br>+                                   </description><br>+                         </configOption><br>+                                <configOption name="accept_multiple_sdp_answers"><br>+                                    <synopsis>Follow SDP forked media when To tag is the same</synopsis><br>+                                     <description><para><br>+                                              On outgoing calls, if the UAS responds with different SDP attributes<br>+                                         on non-100rel 18X or 2XX responses (such as a port update) AND the<br>+                                           To tag on the subsequent response is the same as that on the previous one,<br>+                                           process the updated SDP.<br>+                                             </para><br>+                                                <note><para><br>+                                                     This option must also be enabled on endpoints that require<br>+                                                   this functionality.<br>+                                          </para></note><br>+                                   </description><br>+                         </configOption><br>                                 <configOption name="type"><br>                                    <synopsis>Must be of type 'system'.</synopsis><br>                            </configOption><br>diff --git a/res/res_pjsip/config_system.c b/res/res_pjsip/config_system.c<br>index ed2b5d2..65e4e2c 100644<br>--- a/res/res_pjsip/config_system.c<br>+++ b/res/res_pjsip/config_system.c<br>@@ -52,6 +52,13 @@<br>        } threadpool;<br>         /*! Nonzero to disable switching from UDP to TCP transport */<br>         unsigned int disable_tcp_switch;<br>+     /*!<br>+   * Although early media is enabled in pjproject by default, it's only<br>+     * enabled when the To tags are different. These options allow turning<br>+        * on or off the feature for different tags and same tags.<br>+    */<br>+  unsigned int follow_early_media_fork;<br>+        unsigned int accept_multiple_sdp_answers;<br> };<br> <br> static struct ast_threadpool_options sip_threadpool_options = {<br>@@ -95,6 +102,16 @@<br> <br>   pjsip_cfg()->tsx.t1 = system->timert1;<br>  pjsip_cfg()->tsx.td = system->timerb;<br>+<br>+       pjsip_cfg()->endpt.follow_early_media_fork = system->follow_early_media_fork;<br>+#ifdef HAVE_PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS<br>+      pjsip_cfg()->endpt.accept_multiple_sdp_answers = system->accept_multiple_sdp_answers;<br>+#else<br>+  if (system->accept_multiple_sdp_answers) {<br>+                ast_log(LOG_WARNING,<br>+                 "The accept_multiple_sdp_answers flag is not supported in this version of pjproject. Ignoring\n");<br>+ }<br>+#endif<br> <br>         if (system->compactheaders) {<br>              extern pj_bool_t pjsip_use_compact_form;<br>@@ -184,6 +201,10 @@<br>                        OPT_UINT_T, 0, FLDSET(struct system_config, threadpool.max_size));<br>    ast_sorcery_object_field_register(system_sorcery, "system", "disable_tcp_switch", "yes",<br>                        OPT_BOOL_T, 1, FLDSET(struct system_config, disable_tcp_switch));<br>+    ast_sorcery_object_field_register(system_sorcery, "system", "follow_early_media_fork", "yes",<br>+                  OPT_BOOL_T, 1, FLDSET(struct system_config, follow_early_media_fork));<br>+       ast_sorcery_object_field_register(system_sorcery, "system", "accept_multiple_sdp_answers", "no",<br>+                       OPT_BOOL_T, 1, FLDSET(struct system_config, accept_multiple_sdp_answers));<br> <br>         ast_sorcery_load(system_sorcery);<br> <br>diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c<br>index 5be9845..c214508 100644<br>--- a/res/res_pjsip/pjsip_configuration.c<br>+++ b/res/res_pjsip/pjsip_configuration.c<br>@@ -1902,6 +1902,8 @@<br>      ast_sorcery_object_field_register(sip_sorcery, "endpoint", "bundle", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.bundle));<br>       ast_sorcery_object_field_register(sip_sorcery, "endpoint", "webrtc", "no", OPT_YESNO_T, 1, FLDSET(struct ast_sip_endpoint, media.webrtc));<br>      ast_sorcery_object_field_register(sip_sorcery, "endpoint", "incoming_mwi_mailbox", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, incoming_mwi_mailbox));<br>+        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "follow_early_media_fork", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, follow_early_media_fork));<br>+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "accept_multiple_sdp_answers", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, accept_multiple_sdp_answers));<br> <br>        if (ast_sip_initialize_sorcery_transport()) {<br>                 ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");<br>diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c<br>index 034d65e..90198e2 100644<br>--- a/res/res_pjsip_session.c<br>+++ b/res/res_pjsip_session.c<br>@@ -4054,6 +4054,42 @@<br>                 return;<br>       }<br> <br>+ if (session->endpoint) {<br>+          int bail = 0;<br>+<br>+             /*<br>+            * If following_fork is set, then this is probably the result of a<br>+            * forked INVITE and SDP asnwers coming from the different fork UAS<br>+           * destinations.  In this case updated_sdp_answer will also be set.<br>+           *<br>+            * If only updated_sdp_answer is set, then this is the non-forking<br>+            * scenario where the same UAS just needs to change something like<br>+            * the media port.<br>+            */<br>+<br>+               if (inv->following_fork) {<br>+                        if (session->endpoint->follow_early_media_fork) {<br>+                              ast_debug(3, "Following early media fork with different To tags\n");<br>+                       } else {<br>+                             ast_debug(3, "Not following early media fork with different To tags\n");<br>+                           bail = 1;<br>+                    }<br>+            }<br>+#ifdef HAVE_PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS<br>+                else if (inv->updated_sdp_answer) {<br>+                       if (session->endpoint->accept_multiple_sdp_answers) {<br>+                          ast_debug(3, "Accepting updated SDP with same To tag\n");<br>+                  } else {<br>+                             ast_debug(3, "Ignoring updated SDP answer with same To tag\n");<br>+                            bail = 1;<br>+                    }<br>+            }<br>+#endif<br>+           if (bail) {<br>+                  return;<br>+              }<br>+    }<br>+<br>  if ((status != PJ_SUCCESS) || (pjmedia_sdp_neg_get_active_local(inv->neg, &local) != PJ_SUCCESS) ||<br>            (pjmedia_sdp_neg_get_active_remote(inv->neg, &remote) != PJ_SUCCESS)) {<br>                ast_channel_hangupcause_set(session->channel, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);<br>diff --git a/third-party/pjproject/configure.m4 b/third-party/pjproject/configure.m4<br>index 42482b2..9b70e09 100644<br>--- a/third-party/pjproject/configure.m4<br>+++ b/third-party/pjproject/configure.m4<br>@@ -87,6 +87,7 @@<br>    AC_DEFINE([HAVE_PJSIP_INV_SESSION_REF], 1, [Define if your system has PJSIP_INV_SESSION_REF])<br>         AC_DEFINE([HAVE_PJSIP_AUTH_CLT_DEINIT], 1, [Define if your system has pjsip_auth_clt_deinit declared.])<br>       AC_DEFINE([HAVE_PJSIP_TSX_LAYER_FIND_TSX2], 1, [Define if your system has pjsip_tsx_layer_find_tsx2 declared.])<br>+      AC_DEFINE([HAVE_PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS], 1, [Define if your system has HAVE_PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS declared.])<br> <br>       AC_SUBST([PJPROJECT_BUNDLED])<br>         AC_SUBST([PJPROJECT_DIR])<br>diff --git a/third-party/pjproject/patches/0100-sip_inv-Add-option-to-accept-updated-SDP-on-same-To-.patch b/third-party/pjproject/patches/0100-sip_inv-Add-option-to-accept-updated-SDP-on-same-To-.patch<br>new file mode 100644<br>index 0000000..cfcc9e8<br>--- /dev/null<br>+++ b/third-party/pjproject/patches/0100-sip_inv-Add-option-to-accept-updated-SDP-on-same-To-.patch<br>@@ -0,0 +1,215 @@<br>+From 13e20772cd3c8735a6b78e30391a33f3eba4c023 Mon Sep 17 00:00:00 2001<br>+From: George Joseph <gjoseph@digium.com><br>+Date: Fri, 22 Jun 2018 09:33:34 -0600<br>+Subject: [PATCH] sip_inv:  Add option to accept updated SDP on same To tag<br>+<br>+Currently, setting pjsip_cfg()->endpt.follow_early_media_fork allows<br>+sip_inv to process media updates when the To tag is different.  There<br>+are some cases where media updates need to be processed when the tags<br>+are the same.  Since removing the requirement for different tags would<br>+change default behavior, a new option "accept_multiple_sdp_answers"<br>+has been added along with a new pjsip_inv_session flag<br>+"updated_sdp_answer" to indicate under which condition we're<br>+updating.<br>+<br>+The logic was also updated to more closely follow RFC6337 in that<br>+if 100rel is efffect, do not accept updated SDPs.<br>+<br>+See<br>+https://tools.ietf.org/html/rfc6337#section-3.1.1<br>+for more information.<br>+---<br>+ pjsip/include/pjsip-ua/sip_inv.h |  2 ++<br>+ pjsip/include/pjsip/sip_config.h | 25 ++++++++++++++++<br>+ pjsip/src/pjsip-ua/sip_inv.c     | 62 +++++++++++++++++++++++++---------------<br>+ pjsip/src/pjsip/sip_config.c     |  3 +-<br>+ 4 files changed, 68 insertions(+), 24 deletions(-)<br>+<br>+diff --git a/pjsip/include/pjsip-ua/sip_inv.h b/pjsip/include/pjsip-ua/sip_inv.h<br>+index 1bb7b8adc..77ef070c3 100644<br>+--- a/pjsip/include/pjsip-ua/sip_inv.h<br>++++ b/pjsip/include/pjsip-ua/sip_inv.h<br>+@@ -442,6 +442,8 @@ struct pjsip_inv_session<br>+     pj_bool_t            following_fork;            /**< Internal, following<br>+                                                       forked media?      */<br>+     pj_atomic_t               *ref_cnt;                   /**< Reference counter. */<br>++    pj_bool_t            updated_sdp_answer;        /**< SDP answer just been<br>++                                                        updated?           */<br>+ };<br>+ <br>+ <br>+diff --git a/pjsip/include/pjsip/sip_config.h b/pjsip/include/pjsip/sip_config.h<br>+index b3a9468e2..b7cf6feed 100644<br>+--- a/pjsip/include/pjsip/sip_config.h<br>++++ b/pjsip/include/pjsip/sip_config.h<br>+@@ -157,6 +157,17 @@ typedef struct pjsip_cfg_t<br>+       */<br>+  pj_bool_t disable_secure_dlg_check;<br>+ <br>++        /**<br>++         * Accept multiple SDP answers on non-reliable 18X responses and the 2XX<br>++         * response when they are all received from the same source (same To tag).<br>++         *<br>++         * See also:<br>++         * https://tools.ietf.org/html/rfc6337#section-3.1.1<br>++         *<br>++         * Default is PJSIP_ACCEPT_MULTIPLE_SDP_ANSWERS.<br>++         */<br>++        pj_bool_t accept_multiple_sdp_answers;<br>++<br>+     } endpt;<br>+ <br>+     /** Transaction layer settings. */<br>+@@ -402,6 +413,20 @@ PJ_INLINE(pjsip_cfg_t*) pjsip_cfg(void)<br>+ #endif<br>+ <br>+ <br>++/**<br>++ * Accept multiple SDP answers on non-reliable 18X responses and the 2XX<br>++ * response when they are all received from the same source (same To tag).<br>++ *<br>++ * This option can also be controlled at run-time by the<br>++ * \a accept_multiple_sdp_answers setting in pjsip_cfg_t.<br>++ *<br>++ * Default is PJ_FALSE.<br>++ */<br>++#ifndef PJSIP_ACCEPT_MULTIPLE_SDP_ANSWERS<br>++#   define PJSIP_ACCEPT_MULTIPLE_SDP_ANSWERS        PJ_TRUE<br>++#endif<br>++<br>++<br>+ /**<br>+  * Specify whether "alias" param should be added to the Via header<br>+  * in any outgoing request with connection oriented transport.<br>+diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c<br>+index c9686a088..c22726bad 100644<br>+--- a/pjsip/src/pjsip-ua/sip_inv.c<br>++++ b/pjsip/src/pjsip-ua/sip_inv.c<br>+@@ -162,6 +162,7 @@ struct tsx_inv_data<br>+     pj_bool_t          retrying;  /* Resend (e.g. due to 401/407)         */<br>+     pj_str_t           done_tag;  /* To tag in RX response with answer    */<br>+     pj_bool_t          done_early;/* Negotiation was done for early med?  */<br>++    pj_bool_t          done_early_rel;/* Early med was realiable?         */<br>+     pj_bool_t          has_sdp;   /* Message with SDP?                    */<br>+ };<br>+ <br>+@@ -2000,18 +2001,20 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,<br>+ <br>+     /* Initialize info that we are following forked media */<br>+     inv->following_fork = PJ_FALSE;<br>++    inv->updated_sdp_answer = PJ_FALSE;<br>+ <br>+     /* MUST NOT do multiple SDP offer/answer in a single transaction,<br>+-     * EXCEPT if:<br>+-     *    - this is an initial UAC INVITE transaction (i.e. not re-INVITE), and<br>+-     * - the previous negotiation was done on an early media (18x) and<br>+-     *    this response is a final/2xx response, and<br>+-     *  - the 2xx response has different To tag than the 18x response<br>+-     *    (i.e. the request has forked).<br>++     * EXCEPT previous nego was in 18x (early media) and any of the following<br>++     * condition is met:<br>++     *  - Non-forking scenario:<br>++     *    - 'accept_multiple_sdp_answers' is set, and<br>++     *    - previous early response was not reliable (rfc6337 section 3.1.1).<br>++     *  - Forking scenario:<br>++     *    - This response has different To tag than the previous response, and<br>++     *    - This response is 18x/2xx (early or final). If this is 18x,<br>++     *      only do multiple SDP nego if 'follow_early_media_fork' is set.<br>+      *<br>+-     * The exception above is to add a rudimentary support for early media<br>+-     * forking (sample case: custom ringback). See this ticket for more<br>+-     * info: http://trac.pjsip.org/repos/ticket/657<br>++     * See also ticket #657, #1644, #1764 for more info.<br>+      */<br>+     if (tsx_inv_data->sdp_done) {<br>+     pj_str_t res_tag;<br>+@@ -2020,21 +2023,29 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,<br>+        res_tag = rdata->msg_info.to->tag;<br>+     st_code = rdata->msg_info.msg->line.status.code;<br>+ <br>+-  /* Allow final/early response after SDP has been negotiated in early<br>+-         * media, IF this response is a final/early response with different<br>+-  * tag.<br>+-         * See ticket #1644 and #1764 for forked early media case.<br>+-        */<br>+- if (tsx->role == PJSIP_ROLE_UAC &&<br>+-           (st_code/100 == 2 ||<br>+-         (st_code/10 == 18 /* st_code == 18x */<br>+-              && pjsip_cfg()->endpt.follow_early_media_fork)) &&<br>+-      tsx_inv_data->done_early &&<br>+-      pj_stricmp(&tsx_inv_data->done_tag, &res_tag))<br>++       if (tsx->role == PJSIP_ROLE_UAC && tsx_inv_data->done_early &&<br>++               (<br>++               /* Non-forking scenario */<br>++                  (<br>++                       !tsx_inv_data->done_early_rel &&<br>++                 (st_code/100 == 2 || st_code/10 == 18) &&<br>++                       pjsip_cfg()->endpt.accept_multiple_sdp_answers &&<br>++                    !pj_stricmp(&tsx_inv_data->done_tag, &res_tag)<br>++               )<br>++                   ||<br>++                  /* Forking scenario */<br>++              (<br>++                       (st_code/100 == 2 ||<br>++                    (st_code/10 == 18 &&<br>++                            pjsip_cfg()->endpt.follow_early_media_fork)) &&<br>++                  pj_stricmp(&tsx_inv_data->done_tag, &res_tag)<br>++                )<br>++               )<br>++       )<br>+         {<br>+        const pjmedia_sdp_session *reoffer_sdp = NULL;<br>+ <br>+-          PJ_LOG(4,(inv->obj_name, "Received forked %s response "<br>++        PJ_LOG(4,(inv->obj_name, "Received %s response "<br>+                  "after SDP negotiation has been done in early "<br>+                    "media. Renegotiating SDP..",<br>+                      (st_code/10==18? "early" : "final" )));<br>+@@ -2054,7 +2065,9 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,<br>+          return status;<br>+           }<br>+ <br>+-       inv->following_fork = PJ_TRUE;<br>++           inv->following_fork = !!pj_stricmp(&tsx_inv_data->done_tag,<br>++                                          &res_tag);<br>++           inv->updated_sdp_answer = PJ_TRUE;<br>+ <br>+        } else {<br>+ <br>+@@ -2135,6 +2148,7 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,<br>+               PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) <br>+     {<br>+         int status_code;<br>++    pjsip_msg *msg = rdata->msg_info.msg;<br>+ <br>+         /* This is an answer. <br>+        * Process and negotiate remote answer.<br>+@@ -2161,8 +2175,10 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,<br>+    */<br>+ <br>+      tsx_inv_data->sdp_done = 1;<br>+-      status_code = rdata->msg_info.msg->line.status.code;<br>++  status_code = msg->line.status.code;<br>+      tsx_inv_data->done_early = (status_code/100==1);<br>++ tsx_inv_data->done_early_rel = tsx_inv_data->done_early &&<br>++                                   pjsip_100rel_is_reliable(rdata);<br>+      pj_strdup(tsx->pool, &tsx_inv_data->done_tag, <br>+               &rdata->msg_info.to->tag);<br>+ <br>+diff --git a/pjsip/src/pjsip/sip_config.c b/pjsip/src/pjsip/sip_config.c<br>+index 3576f351e..316824a00 100644<br>+--- a/pjsip/src/pjsip/sip_config.c<br>++++ b/pjsip/src/pjsip/sip_config.c<br>+@@ -34,7 +34,8 @@ pjsip_cfg_t pjsip_sip_cfg_var =<br>+        PJSIP_FOLLOW_EARLY_MEDIA_FORK,<br>+        PJSIP_REQ_HAS_VIA_ALIAS,<br>+        PJSIP_RESOLVE_HOSTNAME_TO_GET_INTERFACE,<br>+-       0<br>++       0,<br>++       PJSIP_ACCEPT_MULTIPLE_SDP_ANSWERS<br>+     },<br>+ <br>+     /* Transaction settings */<br>+-- <br>+2.14.4<br>+<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/9276">change 9276</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/9276"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 15 </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I64d071942b79adb2f0a4e13137389b19404fe3d6 </div>
<div style="display:none"> Gerrit-Change-Number: 9276 </div>
<div style="display:none"> Gerrit-PatchSet: 3 </div>
<div style="display:none"> Gerrit-Owner: 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>
<div style="display:none"> Gerrit-Reviewer: Richard Mudgett <rmudgett@digium.com> </div>