<p>George Joseph has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/14730">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_pjsip_session:  Handle re-invite collisions better<br><br>When both Asterisk and a UA send re-invites at the same time, both<br>send 491 "Transaction in progress" responses to each other and back<br>off a specified amount of time before retrying. When Asterisk<br>prepares to send its re-invite, it sets up the session's pending<br>media state with the new topology it wants, then sends the<br>re-invite.  Unfortunately, when it received the re-invite from the<br>UA, it partially processed the media in the re-invite and reset<br>the pending media state before sending the 491 losing the state it<br>set in its own re-invite.<br><br>There are 2 scenarios that need to be handled:<br><br> 1.  Asterisk is the UAS of the original INVITE transaction.<br>     Per RFC 3261, Asterisk will backoff between 0 and 2000ms<br>     before resending its re-invite and the original UAC will<br>     backoff between 2100 and 4000ms before resending its<br>     re-invite so in this case Asterisk will resend first.<br><br>   * We now do a check in session_reinvite_on_rx_request() to see if<br>     there's a pending invite transaction and if there is, we return<br>     PJ_FALSE to pjproject before we touch the media state and it<br>     pjproject continues on to send the 491.  This way when Asterisk<br>     resends the re-invite, the state is correct.<br><br> 2.  Asterisk is the UAC of the original INVITE transaction.<br>     The backoff timers are reversed now so Asterisk will<br>     backoff between 2100 and 4000ms before resending its re-invite<br>     and the original UAS will backoff between 0 and 2000ms before<br>     resending its the re-invite.  In this case, Asterisk is going<br>     to receive a re-invite before it resends its own.<br><br>   * In reschedule_reinvite(), we now create a temporary media state<br>     and clone the pending topology into it.  That then gets passed<br>     to delay_request() which already has the capability to use the<br>     state passed to it instead of the one currently on the session<br>     when the timer triggers to re-send the re-invite.  This way we<br>     can process the incoming one without losing the state of the<br>     one we sent.<br><br>Regardless of how the delayed re-invite was triggered, we need to<br>reconcile the topology that was active at the time the delayed<br>request was queued, the pending topology of the queued request,<br>and the topology currently active on the session.<br><br> * Added a new function merge_refresh_media_states() which<br>   does the above.  sip_session_refresh calls that function if<br>   all 3 of the topologies mentioned are available on the delayed<br>   request structure.<br><br> * Updated some stream topology APIs to automatically set the stream<br>   name to <type>-<position> if not specified to make searching for<br>   streams easier. There was also a code formatting fix.<br><br>Changes made for debugging purposes:<br><br> * LOTS of debugging has been added to res_pjsip_session.<br><br> * LOTS of debugging has been changed in res_pjsip_session to<br>   make debug levels consistent and to add the endpoint or<br>   channel name.<br><br> * The stream name was added to the ast_sip_session_media<br>   structure just for debugging purposes.  It allows is to<br>   confirm that the session media and the stream really match<br>   over time.<br><br>ASTERISK-29014<br><br>Change-Id: Id3440972943c611a15f652c6c569fa0e4536bfcb<br>---<br>M bridges/bridge_softmix.c<br>M include/asterisk/res_pjsip_session.h<br>M include/asterisk/stream.h<br>M main/stream.c<br>M res/res_pjsip_session.c<br>5 files changed, 1,446 insertions(+), 187 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/30/14730/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c</span><br><span>index 977cbd3..bc10ebf 100644</span><br><span>--- a/bridges/bridge_softmix.c</span><br><span>+++ b/bridges/bridge_softmix.c</span><br><span>@@ -630,6 +630,7 @@</span><br><span> </span><br><span>         joiner_video = ast_stream_topology_alloc();</span><br><span>  if (!joiner_video) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_log(LOG_ERROR, "%s: Couldn't alloc topology\n", ast_channel_name(joiner->chan));</span><br><span>                return;</span><br><span>      }</span><br><span> </span><br><span>@@ -643,6 +644,7 @@</span><br><span>  ast_channel_unlock(joiner->chan);</span><br><span> </span><br><span>     if (res || !sc->topology) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_log(LOG_ERROR, "%s: Couldn't append source streams\n", ast_channel_name(joiner->chan));</span><br><span>                 goto cleanup;</span><br><span>        }</span><br><span> </span><br><span>@@ -656,11 +658,17 @@</span><br><span>                        ast_channel_get_stream_topology(participant->chan));</span><br><span>              ast_channel_unlock(participant->chan);</span><br><span>            if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_log(LOG_ERROR, "%s/%s: Couldn't append source streams\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                           ast_channel_name(participant->chan), ast_channel_name(joiner->chan));</span><br><span>                  goto cleanup;</span><br><span>                }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ast_channel_request_stream_topology_change(joiner->chan, sc->topology, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   res = ast_channel_request_stream_topology_change(joiner->chan, sc->topology, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "%s: Couldn't request topology change\n", ast_channel_name(joiner->chan));</span><br><span style="color: hsl(120, 100%, 40%);">+                goto cleanup;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> </span><br><span>        AST_LIST_TRAVERSE(participants, participant, entry) {</span><br><span>                if (participant == joiner) {</span><br><span>@@ -669,9 +677,16 @@</span><br><span> </span><br><span>              sc = participant->tech_pvt;</span><br><span>               if (append_all_streams(sc->topology, joiner_video)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_log(LOG_ERROR, "%s/%s: Couldn't apopend streams\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         ast_channel_name(participant->chan), ast_channel_name(joiner->chan));</span><br><span>                  goto cleanup;</span><br><span>                }</span><br><span style="color: hsl(0, 100%, 40%);">-               ast_channel_request_stream_topology_change(participant->chan, sc->topology, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+              res = ast_channel_request_stream_topology_change(participant->chan, sc->topology, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_log(LOG_ERROR, "%s/%s: Couldn't request topology change\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         ast_channel_name(participant->chan), ast_channel_name(joiner->chan));</span><br><span style="color: hsl(120, 100%, 40%);">+                   goto cleanup;</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span>    }</span><br><span> </span><br><span> cleanup:</span><br><span>@@ -1086,7 +1101,7 @@</span><br><span>                             * change the name so that routing does not attempt to route video</span><br><span>                            * to this stream.</span><br><span>                            */</span><br><span style="color: hsl(0, 100%, 40%);">-                             removed = ast_stream_clone(stream, "removed");</span><br><span style="color: hsl(120, 100%, 40%);">+                              removed = ast_stream_clone(stream, NULL);</span><br><span>                            if (!removed) {</span><br><span>                                      return -1;</span><br><span>                           }</span><br><span>diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h</span><br><span>index 7988303..56a7078 100644</span><br><span>--- a/include/asterisk/res_pjsip_session.h</span><br><span>+++ b/include/asterisk/res_pjsip_session.h</span><br><span>@@ -115,6 +115,10 @@</span><br><span>        unsigned int changed;</span><br><span>        /*! \brief Remote media stream label */</span><br><span>      char *remote_mslabel;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief Remote stream label */</span><br><span style="color: hsl(120, 100%, 40%);">+     char *remote_label;</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! \brief Stream name */</span><br><span style="color: hsl(120, 100%, 40%);">+     char *stream_name;</span><br><span> };</span><br><span> </span><br><span> /*!</span><br><span>@@ -808,6 +812,16 @@</span><br><span> struct ast_sip_session_media_state *ast_sip_session_media_state_alloc(void);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Clone a session media object</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param src The source session media object</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval non-NULL success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL failure</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_sip_session_media *ast_sip_session_media_clone(struct ast_sip_session_media *src);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Allocate an ast_session_media and add it to the media state's vector.</span><br><span>  * \since 15.0.0</span><br><span>  *</span><br><span>diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h</span><br><span>index a91124b..206edbb 100644</span><br><span>--- a/include/asterisk/stream.h</span><br><span>+++ b/include/asterisk/stream.h</span><br><span>@@ -416,6 +416,8 @@</span><br><span>  * \returns the position of the stream in the topology (-1 on error)</span><br><span>  *</span><br><span>  * \since 15</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note If the stream's name is empty, it'll be set to <stream_type>-<position></span><br><span>  */</span><br><span> int ast_stream_topology_append_stream(struct ast_stream_topology *topology,</span><br><span>  struct ast_stream *stream);</span><br><span>@@ -461,6 +463,8 @@</span><br><span>  * the first unused position.  You can't set positions beyond that.</span><br><span>  *</span><br><span>  * \since 15</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note If the stream's name is empty, it'll be set to <stream_type>-<position></span><br><span>  */</span><br><span> int ast_stream_topology_set_stream(struct ast_stream_topology *topology,</span><br><span>      unsigned int position, struct ast_stream *stream);</span><br><span>diff --git a/main/stream.c b/main/stream.c</span><br><span>index 091eb1c..3274e16 100644</span><br><span>--- a/main/stream.c</span><br><span>+++ b/main/stream.c</span><br><span>@@ -101,10 +101,12 @@</span><br><span>        [AST_STREAM_STATE_INACTIVE] = "inactive",</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define MIN_STREAM_NAME_LEN 16</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct ast_stream *ast_stream_alloc(const char *name, enum ast_media_type type)</span><br><span> {</span><br><span>        struct ast_stream *stream;</span><br><span style="color: hsl(0, 100%, 40%);">-      size_t name_len = MAX(strlen(S_OR(name, "")), 7); /* Ensure there is enough room for 'removed' */</span><br><span style="color: hsl(120, 100%, 40%);">+   size_t name_len = MAX(strlen(S_OR(name, "")), MIN_STREAM_NAME_LEN); /* Ensure there is enough room for 'removed' or a type-position */</span><br><span> </span><br><span>         stream = ast_calloc(1, sizeof(*stream) + name_len + 1);</span><br><span>      if (!stream) {</span><br><span>@@ -130,7 +132,9 @@</span><br><span>         }</span><br><span> </span><br><span>        stream_name = name ?: stream->name;</span><br><span style="color: hsl(0, 100%, 40%);">-  name_len = MAX(strlen(stream_name), 7); /* Ensure there is enough room for 'removed' */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     name_len = MAX(strlen(S_OR(stream_name, "")), MIN_STREAM_NAME_LEN); /* Ensure there is enough room for 'removed' or a type-position */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>   new_stream = ast_calloc(1, sizeof(*stream) + name_len + 1);</span><br><span>  if (!new_stream) {</span><br><span>           return NULL;</span><br><span>@@ -242,6 +246,7 @@</span><br><span> </span><br><span>       stream->state = state;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#if 0</span><br><span>         /* When a stream is set to removed that means that any previous data for it</span><br><span>   * is no longer valid. We therefore change its name to removed and remove</span><br><span>     * any old metadata associated with it.</span><br><span>@@ -254,6 +259,7 @@</span><br><span>                        ast_format_cap_remove_by_type(stream->formats, AST_MEDIA_TYPE_UNKNOWN);</span><br><span>           }</span><br><span>    }</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span> }</span><br><span> </span><br><span> const char *ast_stream_state2str(enum ast_stream_state state)</span><br><span>@@ -510,6 +516,10 @@</span><br><span> </span><br><span>       stream->position = AST_VECTOR_SIZE(&topology->streams) - 1;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+     if (ast_strlen_zero(stream->name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               snprintf(stream->name, MIN_STREAM_NAME_LEN, "%s-%d", ast_codec_media_type2str(stream->type), stream->position);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  return AST_VECTOR_SIZE(&topology->streams) - 1;</span><br><span> }</span><br><span> </span><br><span>@@ -522,18 +532,18 @@</span><br><span> </span><br><span> int ast_stream_topology_get_active_count(const struct ast_stream_topology *topology)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       int i;</span><br><span style="color: hsl(0, 100%, 40%);">-       int count = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-       ast_assert(topology != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+        int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        int count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_assert(topology != NULL);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {</span><br><span style="color: hsl(0, 100%, 40%);">-               struct ast_stream *stream = AST_VECTOR_GET(&topology->streams, i);</span><br><span style="color: hsl(0, 100%, 40%);">-               if (stream->state != AST_STREAM_STATE_REMOVED) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       count++;</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         struct ast_stream *stream = AST_VECTOR_GET(&topology->streams, i);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (stream->state != AST_STREAM_STATE_REMOVED) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   count++;</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       return count;</span><br><span style="color: hsl(120, 100%, 40%);">+     return count;</span><br><span> }</span><br><span> </span><br><span> struct ast_stream *ast_stream_topology_get_stream(</span><br><span>@@ -566,6 +576,10 @@</span><br><span>          return AST_VECTOR_APPEND(&topology->streams, stream);</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_strlen_zero(stream->name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               snprintf(stream->name, MIN_STREAM_NAME_LEN, "%s-%d", ast_codec_media_type2str(stream->type), stream->position);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  return AST_VECTOR_REPLACE(&topology->streams, position, stream);</span><br><span> }</span><br><span> </span><br><span>@@ -624,12 +638,13 @@</span><br><span>                     return NULL;</span><br><span>                 }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           stream = ast_stream_alloc(ast_codec_media_type2str(type), type);</span><br><span style="color: hsl(120, 100%, 40%);">+              stream = ast_stream_alloc(NULL, type);</span><br><span>               if (!stream) {</span><br><span>                       ao2_cleanup(new_cap);</span><br><span>                        ast_stream_topology_free(topology);</span><br><span>                  return NULL;</span><br><span>                 }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>          /* We're transferring the initial ref so no bump needed */</span><br><span>               stream->formats = new_cap;</span><br><span>                stream->state = AST_STREAM_STATE_SENDRECV;</span><br><span>@@ -638,6 +653,9 @@</span><br><span>                  ast_stream_topology_free(topology);</span><br><span>                  return NULL;</span><br><span>                 }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           snprintf(stream->name, MIN_STREAM_NAME_LEN, "%s-%d", ast_codec_media_type2str(stream->type), stream->position);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         }</span><br><span> </span><br><span>        return topology;</span><br><span>diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c</span><br><span>index f89416e..d028336 100644</span><br><span>--- a/res/res_pjsip_session.c</span><br><span>+++ b/res/res_pjsip_session.c</span><br><span>@@ -74,7 +74,8 @@</span><br><span>                ast_sip_session_sdp_creation_cb on_sdp_creation,</span><br><span>             ast_sip_session_response_cb on_response,</span><br><span>             enum ast_sip_session_refresh_method method, int generate_new_sdp,</span><br><span style="color: hsl(0, 100%, 40%);">-               struct ast_sip_session_media_state *media_state,</span><br><span style="color: hsl(120, 100%, 40%);">+              struct ast_sip_session_media_state *pending_media_state,</span><br><span style="color: hsl(120, 100%, 40%);">+              struct ast_sip_session_media_state *active_media_state,</span><br><span>              int queued);</span><br><span> </span><br><span> /*! \brief NAT hook for modifying outgoing messages with SDP */</span><br><span>@@ -480,18 +481,24 @@</span><br><span> </span><br><span>      ast_free(session_media->mid);</span><br><span>     ast_free(session_media->remote_mslabel);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_free(session_media->remote_label);</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_free(session_media->stream_name);</span><br><span> }</span><br><span> </span><br><span> struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_session *session,</span><br><span>  struct ast_sip_session_media_state *media_state, enum ast_media_type type, int position)</span><br><span> {</span><br><span>        struct ast_sip_session_media *session_media = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   SCOPE_ENTER(1, "%s Adding position %d\n", ast_sip_session_get_name(session), position);</span><br><span> </span><br><span>        /* It is possible for this media state to already contain a session for the stream. If this</span><br><span>   * is the case we simply return it.</span><br><span>   */</span><br><span>  if (position < AST_VECTOR_SIZE(&media_state->sessions)) {</span><br><span style="color: hsl(0, 100%, 40%);">-             return AST_VECTOR_GET(&media_state->sessions, position);</span><br><span style="color: hsl(120, 100%, 40%);">+               session_media = AST_VECTOR_GET(&media_state->sessions, position);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (session_media) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  SCOPE_EXIT_RTN_VALUE(session_media, "Using existing media_session\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span>    }</span><br><span> </span><br><span>        /* Determine if we can reuse the session media from the active media state if present */</span><br><span>@@ -500,6 +507,7 @@</span><br><span>               /* A stream can never exist without an accompanying media session */</span><br><span>                 if (session_media->type == type) {</span><br><span>                        ao2_ref(session_media, +1);</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_trace(1, "Reusing existing media session\n");</span><br><span>                  /*</span><br><span>                    * If this session_media was previously removed, its bundle group was probably reset</span><br><span>                          * to -1 so if bundling is enabled on the endpoint, we need to reset it to 0, set</span><br><span>@@ -511,10 +519,12 @@</span><br><span>                            ast_free(session_media->mid);</span><br><span>                             if (ast_asprintf(&session_media->mid, "%s-%d", ast_codec_media_type2str(type), position) < 0) {</span><br><span>                                  ao2_ref(session_media, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-                                     return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                                  SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't alloc mid\n");</span><br><span>                            }</span><br><span>                    }</span><br><span>            } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_trace(1, "Can't reuse existing media session because the types are different. %s <> %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            ast_codec_media_type2str(type), ast_codec_media_type2str(session_media->type));</span><br><span>                   session_media = NULL;</span><br><span>                }</span><br><span>    }</span><br><span>@@ -525,6 +535,7 @@</span><br><span>              if (!session_media) {</span><br><span>                        return NULL;</span><br><span>                 }</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_trace(1, "Creating new media session\n");</span><br><span> </span><br><span>          session_media->encryption = session->endpoint->media.rtp.encryption;</span><br><span>                session_media->remote_ice = session->endpoint->media.rtp.ice_support;</span><br><span>@@ -540,7 +551,7 @@</span><br><span>                          */</span><br><span>                  if (ast_asprintf(&session_media->mid, "%s-%d", ast_codec_media_type2str(type), position) < 0) {</span><br><span>                          ao2_ref(session_media, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-                             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                          SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't alloc mid\n");</span><br><span>                    }</span><br><span>                    session_media->bundle_group = 0;</span><br><span> </span><br><span>@@ -554,18 +565,23 @@</span><br><span>              }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(session_media->stream_name);</span><br><span style="color: hsl(120, 100%, 40%);">+      session_media->stream_name = ast_strdup(ast_stream_get_name(ast_stream_topology_get_stream(media_state->topology, position)));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       if (AST_VECTOR_REPLACE(&media_state->sessions, position, session_media)) {</span><br><span>            ao2_ref(session_media, -1);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-         return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't replace media_session\n");</span><br><span>        }</span><br><span> </span><br><span>        /* If this stream will be active in some way and it is the first of this type then consider this the default media session to match */</span><br><span>       if (!media_state->default_session[type] && ast_stream_get_state(ast_stream_topology_get_stream(media_state->topology, position)) != AST_STREAM_STATE_REMOVED) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_trace(1, "Setting media session as default for %s\n", ast_codec_media_type2str(session_media->type));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>             media_state->default_session[type] = session_media;</span><br><span>       }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   return session_media;</span><br><span style="color: hsl(120, 100%, 40%);">+ SCOPE_EXIT_RTN_VALUE(session_media, "Done\n");</span><br><span> }</span><br><span> </span><br><span> static int is_stream_limitation_reached(enum ast_media_type type, const struct ast_sip_endpoint *endpoint, int *type_streams)</span><br><span>@@ -670,6 +686,8 @@</span><br><span> </span><br><span>         ast_free(session_media->remote_mslabel);</span><br><span>  session_media->remote_mslabel = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_free(session_media->remote_label);</span><br><span style="color: hsl(120, 100%, 40%);">+     session_media->remote_label = NULL;</span><br><span> </span><br><span>   for (index = 0; index < stream->attr_count; ++index) {</span><br><span>                 pjmedia_sdp_attr *attr = stream->attr[index];</span><br><span>@@ -678,8 +696,12 @@</span><br><span>              char *msid, *tmp = attr_value;</span><br><span>               static const pj_str_t STR_msid = { "msid", 4 };</span><br><span>            static const pj_str_t STR_ssrc = { "ssrc", 4 };</span><br><span style="color: hsl(120, 100%, 40%);">+             static const pj_str_t STR_label = { "label", 5 };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-         if (!pj_strcmp(&attr->name, &STR_msid)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!pj_strcmp(&attr->name, &STR_label)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 ast_copy_pj_str(attr_value, &attr->value, sizeof(attr_value));</span><br><span style="color: hsl(120, 100%, 40%);">+                 session_media->remote_label = ast_strdup(attr_value);</span><br><span style="color: hsl(120, 100%, 40%);">+              } else if (!pj_strcmp(&attr->name, &STR_msid)) {</span><br><span>                  ast_copy_pj_str(attr_value, &attr->value, sizeof(attr_value));</span><br><span>                        msid = strsep(&tmp, " ");</span><br><span>                      session_media->remote_mslabel = ast_strdup(msid);</span><br><span>@@ -741,7 +763,8 @@</span><br><span>   int type_streams[AST_MEDIA_TYPE_END] = {0};</span><br><span> </span><br><span>      if (session->inv_session && session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {</span><br><span style="color: hsl(0, 100%, 40%);">-             ast_log(LOG_ERROR, "Failed to handle incoming SDP. Session has been already disconnected\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "%s: Failed to handle incoming SDP. Session has been already disconnected\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_sip_session_get_name(session));</span><br><span>          return -1;</span><br><span>   }</span><br><span> </span><br><span>@@ -774,27 +797,37 @@</span><br><span>                }</span><br><span>            if (!stream) {</span><br><span>                       struct ast_stream *existing_stream = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                    char *stream_name = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                     const char *stream_label = NULL;</span><br><span> </span><br><span>                         if (session->active_media_state->topology &&</span><br><span>                           (i < ast_stream_topology_get_count(session->active_media_state->topology))) {</span><br><span>                               existing_stream = ast_stream_topology_get_stream(session->active_media_state->topology, i);</span><br><span style="color: hsl(120, 100%, 40%);">+                             if (ast_stream_get_state(existing_stream) != AST_STREAM_STATE_REMOVED) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      stream_name = (char *)ast_stream_get_name(existing_stream);</span><br><span style="color: hsl(120, 100%, 40%);">+                                   stream_label = ast_stream_get_metadata(existing_stream, "SDP:LABEL");</span><br><span style="color: hsl(120, 100%, 40%);">+                               }</span><br><span>                    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                   stream = ast_stream_alloc(existing_stream ? ast_stream_get_name(existing_stream) : ast_codec_media_type2str(type), type);</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (ast_strlen_zero(stream_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           if (ast_asprintf(&stream_name, "%s-%d", ast_codec_media_type2str(type), i) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                    return -1;</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%);">+                   stream = ast_stream_alloc(stream_name, type);</span><br><span>                        if (!stream) {</span><br><span>                               return -1;</span><br><span>                   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (!ast_strlen_zero(stream_label)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         ast_stream_set_metadata(stream, "SDP:LABEL", stream_label);</span><br><span style="color: hsl(120, 100%, 40%);">+                 }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                  if (ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream)) {</span><br><span>                               ast_stream_free(stream);</span><br><span>                             return -1;</span><br><span>                   }</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (existing_stream) {</span><br><span style="color: hsl(0, 100%, 40%);">-                          const char *stream_label = ast_stream_get_metadata(existing_stream, "SDP:LABEL");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                             if (!ast_strlen_zero(stream_label)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                   ast_stream_set_metadata(stream, "SDP:LABEL", stream_label);</span><br><span style="color: hsl(0, 100%, 40%);">-                           }</span><br><span style="color: hsl(0, 100%, 40%);">-                       }</span><br><span> </span><br><span>                        /* For backwards compatibility with the core the default audio stream is always sendrecv */</span><br><span>                  if (!ast_sip_session_is_pending_stream_default(session, stream) || strcmp(media, "audio")) {</span><br><span>@@ -823,8 +856,8 @@</span><br><span> </span><br><span>             /* If this stream is already declined mark it as such, or mark it as such if we've reached the limit */</span><br><span>          if (!remote_stream->desc.port || is_stream_limitation_reached(type, session->endpoint, type_streams)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   ast_debug(1, "Declining incoming SDP media stream '%s' at position '%d'\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                           ast_codec_media_type2str(type), i);</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_debug(4, "%s: Declining incoming SDP media stream '%s' at position '%d'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                             ast_sip_session_get_name(session), ast_codec_media_type2str(type), i);</span><br><span>                       remove_stream_from_bundle(session_media, stream);</span><br><span>                    continue;</span><br><span>            }</span><br><span>@@ -834,21 +867,21 @@</span><br><span> </span><br><span>                if (session_media->handler) {</span><br><span>                     handler = session_media->handler;</span><br><span style="color: hsl(0, 100%, 40%);">-                    ast_debug(1, "Negotiating incoming SDP media stream '%s' using %s SDP handler\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                             ast_codec_media_type2str(session_media->type),</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_debug(4, "%s: Negotiating incoming SDP media stream '%s' using %s SDP handler\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                               ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),</span><br><span>                                 session_media->handler->id);</span><br><span>                   res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp, i, stream);</span><br><span>                     if (res < 0) {</span><br><span>                            /* Catastrophic failure. Abort! */</span><br><span>                           return -1;</span><br><span>                   } else if (res == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                          ast_debug(1, "Declining incoming SDP media stream '%s' at position '%d'\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                   ast_codec_media_type2str(type), i);</span><br><span style="color: hsl(120, 100%, 40%);">+                           ast_debug(4, "%s: Declining incoming SDP media stream '%s' at position '%d'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                     ast_sip_session_get_name(session), ast_codec_media_type2str(type), i);</span><br><span>                               remove_stream_from_bundle(session_media, stream);</span><br><span>                            continue;</span><br><span>                    } else if (res > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                ast_debug(1, "Media stream '%s' handled by %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                     ast_codec_media_type2str(session_media->type),</span><br><span style="color: hsl(120, 100%, 40%);">+                             ast_debug(4, "%s: Media stream '%s' handled by %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                       ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),</span><br><span>                                         session_media->handler->id);</span><br><span>                           /* Handled by this handler. Move to the next stream */</span><br><span>                               handled = 1;</span><br><span>@@ -859,28 +892,28 @@</span><br><span> </span><br><span>             handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);</span><br><span>               if (!handler_list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_debug(4, "%s: No registered SDP handlers for media type '%s'\n", ast_sip_session_get_name(session), media);</span><br><span>                    continue;</span><br><span>            }</span><br><span>            AST_LIST_TRAVERSE(&handler_list->list, handler, next) {</span><br><span>                       if (handler == session_media->handler) {</span><br><span>                          continue;</span><br><span>                    }</span><br><span style="color: hsl(0, 100%, 40%);">-                       ast_debug(1, "Negotiating incoming SDP media stream '%s' using %s SDP handler\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                             ast_codec_media_type2str(session_media->type),</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_debug(4, "%s: Negotiating incoming SDP media stream '%s' using %s SDP handler\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                               ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),</span><br><span>                                 handler->id);</span><br><span>                     res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp, i, stream);</span><br><span>                     if (res < 0) {</span><br><span>                            /* Catastrophic failure. Abort! */</span><br><span>                           return -1;</span><br><span>                   } else if (res == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                          ast_debug(1, "Declining incoming SDP media stream '%s' at position '%d'\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                   ast_codec_media_type2str(type), i);</span><br><span style="color: hsl(120, 100%, 40%);">+                           ast_debug(4, "%s: Declining incoming SDP media stream '%s' at position '%d'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                     ast_sip_session_get_name(session), ast_codec_media_type2str(type), i);</span><br><span>                               remove_stream_from_bundle(session_media, stream);</span><br><span>                            continue;</span><br><span>                    } else if (res > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                ast_debug(1, "Media stream '%s' handled by %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                     ast_codec_media_type2str(session_media->type),</span><br><span style="color: hsl(120, 100%, 40%);">+                             ast_debug(4, "%s: Media stream '%s' handled by %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                       ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),</span><br><span>                                         handler->id);</span><br><span>                             /* Handled by this handler. Move to the next stream */</span><br><span>                               session_media_set_handler(session_media, handler);</span><br><span>@@ -936,13 +969,13 @@</span><br><span> </span><br><span>       handler = session_media->handler;</span><br><span>         if (handler) {</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_debug(1, "Applying negotiated SDP media stream '%s' using %s SDP handler\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                      ast_codec_media_type2str(session_media->type),</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_debug(4, "%s: Applying negotiated SDP media stream '%s' using %s SDP handler\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),</span><br><span>                         handler->id);</span><br><span>             res = handler->apply_negotiated_sdp_stream(session, session_media, local, remote, index, asterisk_stream);</span><br><span>                if (res >= 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      ast_debug(1, "Applied negotiated SDP media stream '%s' using %s SDP handler\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                               ast_codec_media_type2str(session_media->type),</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_debug(4, "%s: Applied negotiated SDP media stream '%s' using %s SDP handler\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),</span><br><span>                                 handler->id);</span><br><span>                     return 0;</span><br><span>            }</span><br><span>@@ -951,15 +984,15 @@</span><br><span> </span><br><span>        handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);</span><br><span>       if (!handler_list) {</span><br><span style="color: hsl(0, 100%, 40%);">-            ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_debug(4, "%s: No registered SDP handlers for media type '%s'\n", ast_sip_session_get_name(session), media);</span><br><span>            return -1;</span><br><span>   }</span><br><span>    AST_LIST_TRAVERSE(&handler_list->list, handler, next) {</span><br><span>               if (handler == session_media->handler) {</span><br><span>                  continue;</span><br><span>            }</span><br><span style="color: hsl(0, 100%, 40%);">-               ast_debug(1, "Applying negotiated SDP media stream '%s' using %s SDP handler\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                      ast_codec_media_type2str(session_media->type),</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_debug(4, "%s: Applying negotiated SDP media stream '%s' using %s SDP handler\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),</span><br><span>                         handler->id);</span><br><span>             res = handler->apply_negotiated_sdp_stream(session, session_media, local, remote, index, asterisk_stream);</span><br><span>                if (res < 0) {</span><br><span>@@ -967,8 +1000,8 @@</span><br><span>                     return -1;</span><br><span>           }</span><br><span>            if (res > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       ast_debug(1, "Applied negotiated SDP media stream '%s' using %s SDP handler\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                               ast_codec_media_type2str(session_media->type),</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_debug(4, "%s: Applied negotiated SDP media stream '%s' using %s SDP handler\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),</span><br><span>                                 handler->id);</span><br><span>                     /* Handled by this handler. Move to the next stream */</span><br><span>                       session_media_set_handler(session_media, handler);</span><br><span>@@ -977,8 +1010,8 @@</span><br><span>    }</span><br><span> </span><br><span>        if (session_media->handler && session_media->handler->stream_stop) {</span><br><span style="color: hsl(0, 100%, 40%);">-           ast_debug(1, "Stopping SDP media stream '%s' as it is not currently negotiated\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                    ast_codec_media_type2str(session_media->type));</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_debug(4, "%s: Stopping SDP media stream '%s' as it is not currently negotiated\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type));</span><br><span>                session_media->handler->stream_stop(session_media);</span><br><span>    }</span><br><span> </span><br><span>@@ -1003,16 +1036,16 @@</span><br><span>                      active_media_state_clone =</span><br><span>                           ast_sip_session_media_state_clone(session->active_media_state);</span><br><span>                   if (!active_media_state_clone) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                ast_log(LOG_WARNING, "Unable to clone active media state for channel '%s'\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                 session->channel ? ast_channel_name(session->channel) : "unknown");</span><br><span style="color: hsl(120, 100%, 40%);">+                           ast_log(LOG_WARNING, "%s: Unable to clone active media state\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                    ast_sip_session_get_name(session));</span><br><span>                          return -1;</span><br><span>                   }</span><br><span> </span><br><span>                        ast_sip_session_media_state_free(session->pending_media_state);</span><br><span>                   session->pending_media_state = active_media_state_clone;</span><br><span>          } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                        ast_log(LOG_WARNING, "No pending or active media state for channel '%s'\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                           session->channel ? ast_channel_name(session->channel) : "unknown");</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_log(LOG_WARNING, "%s: No pending or active media state\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                              ast_sip_session_get_name(session));</span><br><span>                  return -1;</span><br><span>           }</span><br><span>    }</span><br><span>@@ -1024,8 +1057,8 @@</span><br><span>     */</span><br><span>  if (ast_stream_topology_get_count(session->pending_media_state->topology) != local->media_count</span><br><span>             || AST_VECTOR_SIZE(&session->pending_media_state->sessions) != local->media_count) {</span><br><span style="color: hsl(0, 100%, 40%);">-               ast_log(LOG_WARNING, "Local SDP for channel '%s' contains %d media streams while we expected it to contain %u\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                     session->channel ? ast_channel_name(session->channel) : "unknown",</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_WARNING, "%s: Local SDP contains %d media streams while we expected it to contain %u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_sip_session_get_name(session),</span><br><span>                   ast_stream_topology_get_count(session->pending_media_state->topology), local->media_count);</span><br><span>                 return -1;</span><br><span>   }</span><br><span>@@ -1269,7 +1302,10 @@</span><br><span>   /*! Whether to generate new SDP */</span><br><span>   int generate_new_sdp;</span><br><span>        /*! Requested media state for the SDP */</span><br><span style="color: hsl(0, 100%, 40%);">-        struct ast_sip_session_media_state *media_state;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_sip_session_media_state *pending_media_state;</span><br><span style="color: hsl(120, 100%, 40%);">+      /*! Active media state at the time of the original request */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_session_media_state *active_media_state;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    AST_LIST_ENTRY(ast_sip_session_delayed_request) next;</span><br><span> };</span><br><span> </span><br><span>@@ -1279,7 +1315,8 @@</span><br><span>      ast_sip_session_sdp_creation_cb on_sdp_creation,</span><br><span>     ast_sip_session_response_cb on_response,</span><br><span>     int generate_new_sdp,</span><br><span style="color: hsl(0, 100%, 40%);">-   struct ast_sip_session_media_state *media_state)</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_sip_session_media_state *pending_media_state,</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_sip_session_media_state *active_media_state)</span><br><span> {</span><br><span>         struct ast_sip_session_delayed_request *delay = ast_calloc(1, sizeof(*delay));</span><br><span> </span><br><span>@@ -1291,13 +1328,15 @@</span><br><span>         delay->on_sdp_creation = on_sdp_creation;</span><br><span>         delay->on_response = on_response;</span><br><span>         delay->generate_new_sdp = generate_new_sdp;</span><br><span style="color: hsl(0, 100%, 40%);">-  delay->media_state = media_state;</span><br><span style="color: hsl(120, 100%, 40%);">+  delay->pending_media_state = pending_media_state;</span><br><span style="color: hsl(120, 100%, 40%);">+  delay->active_media_state = active_media_state;</span><br><span>   return delay;</span><br><span> }</span><br><span> </span><br><span> static void delayed_request_free(struct ast_sip_session_delayed_request *delay)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  ast_sip_session_media_state_free(delay->media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_sip_session_media_state_free(delay->pending_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_sip_session_media_state_free(delay->active_media_state);</span><br><span>      ast_free(delay);</span><br><span> }</span><br><span> </span><br><span>@@ -1313,31 +1352,35 @@</span><br><span> {</span><br><span>     int res;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    ast_debug(3, "Endpoint '%s(%s)' sending delayed %s request.\n",</span><br><span style="color: hsl(0, 100%, 40%);">-               ast_sorcery_object_get_id(session->endpoint),</span><br><span style="color: hsl(0, 100%, 40%);">-                session->channel ? ast_channel_name(session->channel) : "",</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_debug(3, "%s: sending delayed %s request\n",</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_sip_session_get_name(session),</span><br><span>           delayed_method2str(delay->method));</span><br><span> </span><br><span>   switch (delay->method) {</span><br><span>  case DELAYED_METHOD_INVITE:</span><br><span>          res = sip_session_refresh(session, delay->on_request_creation,</span><br><span>                    delay->on_sdp_creation, delay->on_response,</span><br><span style="color: hsl(0, 100%, 40%);">-                       AST_SIP_SESSION_REFRESH_METHOD_INVITE, delay->generate_new_sdp, delay->media_state, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                 AST_SIP_SESSION_REFRESH_METHOD_INVITE, delay->generate_new_sdp, delay->pending_media_state,</span><br><span style="color: hsl(120, 100%, 40%);">+                     delay->active_media_state, 1);</span><br><span>            /* Ownership of media state transitions to ast_sip_session_refresh */</span><br><span style="color: hsl(0, 100%, 40%);">-           delay->media_state = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+         delay->pending_media_state = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+         delay->active_media_state = NULL;</span><br><span>                 return res;</span><br><span>  case DELAYED_METHOD_UPDATE:</span><br><span>          res = sip_session_refresh(session, delay->on_request_creation,</span><br><span>                    delay->on_sdp_creation, delay->on_response,</span><br><span style="color: hsl(0, 100%, 40%);">-                       AST_SIP_SESSION_REFRESH_METHOD_UPDATE, delay->generate_new_sdp, delay->media_state, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                 AST_SIP_SESSION_REFRESH_METHOD_UPDATE, delay->generate_new_sdp, delay->pending_media_state,</span><br><span style="color: hsl(120, 100%, 40%);">+                     delay->active_media_state, 1);</span><br><span>            /* Ownership of media state transitions to ast_sip_session_refresh */</span><br><span style="color: hsl(0, 100%, 40%);">-           delay->media_state = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+         delay->pending_media_state = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+         delay->active_media_state = NULL;</span><br><span>                 return res;</span><br><span>  case DELAYED_METHOD_BYE:</span><br><span>             ast_sip_session_terminate(session, 0);</span><br><span>               return 0;</span><br><span>    }</span><br><span style="color: hsl(0, 100%, 40%);">-       ast_log(LOG_WARNING, "Don't know how to send delayed %s(%d) request.\n",</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_log(LOG_WARNING, "%s: Don't know how to send delayed %s(%d) request.\n",</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_sip_session_get_name(session),</span><br><span>           delayed_method2str(delay->method), delay->method);</span><br><span>     return -1;</span><br><span> }</span><br><span>@@ -1502,17 +1545,21 @@</span><br><span>    ast_sip_session_response_cb on_response,</span><br><span>     int generate_new_sdp,</span><br><span>        enum delayed_method method,</span><br><span style="color: hsl(0, 100%, 40%);">-     struct ast_sip_session_media_state *media_state)</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_sip_session_media_state *pending_media_state,</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_sip_session_media_state *active_media_state,</span><br><span style="color: hsl(120, 100%, 40%);">+       int queue_head)</span><br><span> {</span><br><span>         struct ast_sip_session_delayed_request *delay = delayed_request_alloc(method,</span><br><span style="color: hsl(0, 100%, 40%);">-                   on_request, on_sdp_creation, on_response, generate_new_sdp, media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                     on_request, on_sdp_creation, on_response, generate_new_sdp, pending_media_state,</span><br><span style="color: hsl(120, 100%, 40%);">+                      active_media_state);</span><br><span> </span><br><span>     if (!delay) {</span><br><span style="color: hsl(0, 100%, 40%);">-           ast_sip_session_media_state_free(media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_sip_session_media_state_free(pending_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_sip_session_media_state_free(active_media_state);</span><br><span>                return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (method == DELAYED_METHOD_BYE) {</span><br><span style="color: hsl(120, 100%, 40%);">+   if (method == DELAYED_METHOD_BYE || queue_head) {</span><br><span>            /* Send BYE as early as possible */</span><br><span>          AST_LIST_INSERT_HEAD(&session->delayed_requests, delay, next);</span><br><span>        } else {</span><br><span>@@ -1597,7 +1644,8 @@</span><br><span>     ast_channel_lock(session->channel);</span><br><span>       pjsip_from_domain = pbx_builtin_getvar_helper(session->channel, "SIPFROMDOMAIN");</span><br><span>       if (!ast_strlen_zero(pjsip_from_domain)) {</span><br><span style="color: hsl(0, 100%, 40%);">-              ast_debug(3, "From header domain reset by channel variable SIPFROMDOMAIN (%s)\n", pjsip_from_domain);</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_debug(3, "%s: From header domain reset by channel variable SIPFROMDOMAIN (%s)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_sip_session_get_name(session), pjsip_from_domain);</span><br><span>               pj_strdup2(dlg_pool, &dlg_info_uri->host, pjsip_from_domain);</span><br><span>         }</span><br><span>    ast_channel_unlock(session->channel);</span><br><span>@@ -1629,56 +1677,571 @@</span><br><span>     }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Helper macros for merging and validating media states</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define STREAM_REMOVED(_stream) (ast_stream_get_state(_stream) == AST_STREAM_STATE_REMOVED)</span><br><span style="color: hsl(120, 100%, 40%);">+#define STATE_REMOVED(_stream_state) (_stream_state == AST_STREAM_STATE_REMOVED)</span><br><span style="color: hsl(120, 100%, 40%);">+#define STATE_NONE(_stream_state) (_stream_state == AST_STREAM_STATE_END)</span><br><span style="color: hsl(120, 100%, 40%);">+#define GET_STREAM_SAFE(_topology, _i) (_i < ast_stream_topology_get_count(_topology) ? ast_stream_topology_get_stream(_topology, _i) : NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+#define GET_STREAM_STATE_SAFE(_stream) (_stream ? ast_stream_get_state(_stream) : AST_STREAM_STATE_END)</span><br><span style="color: hsl(120, 100%, 40%);">+#define GET_STREAM_NAME_SAFE(_stream) (_stream ? ast_stream_get_name(_stream) : "")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Thses will be moved to logger.h and refactored before final review */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef AST_DEVMODE</span><br><span style="color: hsl(120, 100%, 40%);">+#define SCOPE_ENTER_DBG(__level, ...) \</span><br><span style="color: hsl(120, 100%, 40%);">+       SCOPE_ENTER(__level, " " __VA_ARGS__); \</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_debug(__level, " " __VA_ARGS__);</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+#define SCOPE_ENTER_DBG(__level, ...) \</span><br><span style="color: hsl(120, 100%, 40%);">+        int __scope_level = __level; \</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_debug(__level, " " __VA_ARGS__);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define SCOPE_EXIT_DBG(...) \</span><br><span style="color: hsl(120, 100%, 40%);">+({ \</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(__scope_level, " " __VA_ARGS__); \</span><br><span style="color: hsl(120, 100%, 40%);">+        SCOPE_EXIT(" " __VA_ARGS__); \</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%);">+#define SCOPE_EXIT_DBG_RTN(__value, ...) \</span><br><span style="color: hsl(120, 100%, 40%);">+({ \</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_debug(__scope_level, " " __VA_ARGS__); \</span><br><span style="color: hsl(120, 100%, 40%);">+        SCOPE_EXIT_RTN_VALUE(__value, " " __VA_ARGS__); \</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%);">+#define SCOPE_EXIT_DBG_EXPR(__expr, ...) \</span><br><span style="color: hsl(120, 100%, 40%);">+({ \</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_debug(__scope_level, " " __VA_ARGS__); \</span><br><span style="color: hsl(120, 100%, 40%);">+        SCOPE_EXIT_EXPR(__expr, " " __VA_ARGS__); \</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%);">+#define SCOPE_EXIT_LOG_RTN(__value, _log_level, ...) \</span><br><span style="color: hsl(120, 100%, 40%);">+({ \</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_log(_log_level, " " __VA_ARGS__); \</span><br><span style="color: hsl(120, 100%, 40%);">+     SCOPE_EXIT_RTN_VALUE(__value, " " __VA_ARGS__); \</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%);">+#define SCOPE_EXIT_DBG_ASSERT_RTN(__value, ...) \</span><br><span style="color: hsl(120, 100%, 40%);">+({ \</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_debug(__scope_level, " " __VA_ARGS__); \</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_assert(0); \</span><br><span style="color: hsl(120, 100%, 40%);">+      SCOPE_EXIT_RTN_VALUE(__value, " " __VA_ARGS__); \</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%);">+#define SCOPE_EXIT_LOG_ASSERT_RTN(__value, _log_level, ...) \</span><br><span style="color: hsl(120, 100%, 40%);">+({ \</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_log(_log_level, " " __VA_ARGS__); \</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_assert(0); \</span><br><span style="color: hsl(120, 100%, 40%);">+      SCOPE_EXIT_RTN_VALUE(__value, " " __VA_ARGS__); \</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%);">+#define ast_trace_dbg(__level, ...) \</span><br><span style="color: hsl(120, 100%, 40%);">+({ \</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_debug(__level < 0 ? __scope_level : __level, " " __VA_ARGS__); \</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_trace(__level < 0 ? __scope_level : __level, " " __VA_ARGS__); \</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%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Validate a media state</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param state Media state</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 1 The media state is valid</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 The media state is NOT valid</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%);">+static int is_media_state_valid(const char *session_name, struct ast_sip_session_media_state *state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int stream_count = ast_stream_topology_get_count(state->topology);</span><br><span style="color: hsl(120, 100%, 40%);">+ int session_count = AST_VECTOR_SIZE(&state->sessions);</span><br><span style="color: hsl(120, 100%, 40%);">+ int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        SCOPE_ENTER_DBG(3, "%s: Topology: %s\n", session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_str_tmp(256, ast_stream_topology_to_str(state->topology, &STR_TMP)));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (session_count != stream_count) {</span><br><span style="color: hsl(120, 100%, 40%);">+          SCOPE_EXIT_DBG_ASSERT_RTN(0, "%s: %d media sessions but %d streams\n", session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                        session_count, stream_count);</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%);">+   for (i = 0; i < stream_count; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+               struct ast_sip_session_media *media = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+           struct ast_stream *stream = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+             const char *stream_name = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+               int j;</span><br><span style="color: hsl(120, 100%, 40%);">+                SCOPE_ENTER_DBG(4, "%s: Checking stream %d\n", session_name, i);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          stream = ast_stream_topology_get_stream(state->topology, i);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!stream) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        SCOPE_EXIT_DBG_ASSERT_RTN(0, "%s: stream %d is null\n", session_name, i);</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+             stream_name = ast_stream_get_name(stream);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          for (j = 0; j < stream_count; j++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       struct ast_stream *possible_dup = ast_stream_topology_get_stream(state->topology, j);</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (j == i || !possible_dup) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (!STREAM_REMOVED(stream) && ast_strings_equal(stream_name, GET_STREAM_NAME_SAFE(possible_dup))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          SCOPE_EXIT_DBG_ASSERT_RTN(0, "%s: stream %i %s is duplicated to %d\n", session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        i, stream_name, j);</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%);">+           media = AST_VECTOR_GET(&state->sessions, i);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!media) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 SCOPE_EXIT_DBG_EXPR(continue, "%s: media %d is null\n", session_name, i);</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%);">+           for (j = 0; j < session_count; j++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      struct ast_sip_session_media *possible_dup = AST_VECTOR_GET(&state->sessions, j);</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (j == i || !possible_dup) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (!ast_strlen_zero(media->label) && !ast_strlen_zero(possible_dup->label)</span><br><span style="color: hsl(120, 100%, 40%);">+                             && ast_strings_equal(media->label, possible_dup->label)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              SCOPE_EXIT_DBG_ASSERT_RTN(0, "%s: media %d %s is duplicated to %d\n", session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 i, media->label, j);</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%);">+           if (media->stream_num != i) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      SCOPE_EXIT_DBG_ASSERT_RTN(0, "%s: media %d has stream_num %d\n", session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                              i, media->stream_num);</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%);">+           if (media->type != ast_stream_get_type(stream)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  SCOPE_EXIT_DBG_ASSERT_RTN(0, "%s: media %d has type %s but stream has type %s\n", stream_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                              i, ast_codec_media_type2str(media->type), ast_codec_media_type2str(ast_stream_get_type(stream)));</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%);">+   SCOPE_EXIT_DBG_RTN(1, "%s: Valid\n", session_name);</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%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Merge media states for a delayed session refresh</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param session_name For log messages</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param delayed_pending_state The pending media state at the time the resuest was queued</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param delayed_active_state The active media state  at the time the resuest was queued</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param current_active_state The current active media state</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param run_validation Whether to run validation on the resulting media state or not</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns New merged topology or NULL if there's an error</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%);">+static struct ast_sip_session_media_state *merge_refresh_media_states(</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_sip_session_media_state *delayed_pending_state,</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_sip_session_media_state *delayed_active_state,</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_sip_session_media_state *current_active_state,</span><br><span style="color: hsl(120, 100%, 40%);">+     int run_post_validation)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   RAII_VAR(struct ast_sip_session_media_state *, new_pending_state, NULL, ast_sip_session_media_state_free);</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_sip_session_media_state *returned_media_state = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_stream_topology *delayed_pending = delayed_pending_state->topology;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_stream_topology *delayed_active = delayed_active_state->topology;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_stream_topology *current_active = current_active_state->topology;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_stream_topology *new_pending = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        int max_stream_count;</span><br><span style="color: hsl(120, 100%, 40%);">+ int res;</span><br><span style="color: hsl(120, 100%, 40%);">+      SCOPE_ENTER_DBG(2, "%s: DP: %s  DA: %s  CA: %s\n", session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_str_tmp(256, ast_stream_topology_to_str(delayed_pending, &STR_TMP)),</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_str_tmp(256, ast_stream_topology_to_str(delayed_active, &STR_TMP)),</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_str_tmp(256, ast_stream_topology_to_str(current_active, &STR_TMP))</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%);">+  max_stream_count = MAX(ast_stream_topology_get_count(delayed_pending),</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_stream_topology_get_count(delayed_active));</span><br><span style="color: hsl(120, 100%, 40%);">+       max_stream_count = MAX(max_stream_count, ast_stream_topology_get_count(current_active));</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%);">+     * The new_pending_state is always based on the currently negotiated state because</span><br><span style="color: hsl(120, 100%, 40%);">+     * the stream ordering in its topology must be preserved.</span><br><span style="color: hsl(120, 100%, 40%);">+      */</span><br><span style="color: hsl(120, 100%, 40%);">+   new_pending_state = ast_sip_session_media_state_clone(current_active_state);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!new_pending_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+             SCOPE_EXIT_LOG_RTN(NULL, LOG_ERROR, "%s: Couldn't clone current_active_state to new_pending_state\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     new_pending = new_pending_state->topology;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       for (i = 0; i < max_stream_count; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           struct ast_stream *dp_stream = GET_STREAM_SAFE(delayed_pending, i);</span><br><span style="color: hsl(120, 100%, 40%);">+           struct ast_stream *da_stream = GET_STREAM_SAFE(delayed_active, i);</span><br><span style="color: hsl(120, 100%, 40%);">+            struct ast_stream *ca_stream = GET_STREAM_SAFE(current_active, i);</span><br><span style="color: hsl(120, 100%, 40%);">+            struct ast_stream *np_stream = GET_STREAM_SAFE(new_pending, i);</span><br><span style="color: hsl(120, 100%, 40%);">+               struct ast_stream *found_da_stream = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+            struct ast_stream *found_np_stream = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+            enum ast_stream_state dp_state = GET_STREAM_STATE_SAFE(dp_stream);</span><br><span style="color: hsl(120, 100%, 40%);">+            enum ast_stream_state da_state = GET_STREAM_STATE_SAFE(da_stream);</span><br><span style="color: hsl(120, 100%, 40%);">+            enum ast_stream_state ca_state = GET_STREAM_STATE_SAFE(ca_stream);</span><br><span style="color: hsl(120, 100%, 40%);">+            enum ast_stream_state np_state = GET_STREAM_STATE_SAFE(np_stream);</span><br><span style="color: hsl(120, 100%, 40%);">+            enum ast_stream_state found_da_state = AST_STREAM_STATE_END;</span><br><span style="color: hsl(120, 100%, 40%);">+          enum ast_stream_state found_np_state = AST_STREAM_STATE_END;</span><br><span style="color: hsl(120, 100%, 40%);">+          const char *da_name = GET_STREAM_NAME_SAFE(da_stream);</span><br><span style="color: hsl(120, 100%, 40%);">+                const char *dp_name = GET_STREAM_NAME_SAFE(dp_stream);</span><br><span style="color: hsl(120, 100%, 40%);">+                const char *ca_name = GET_STREAM_NAME_SAFE(ca_stream);</span><br><span style="color: hsl(120, 100%, 40%);">+                const char *np_name = GET_STREAM_NAME_SAFE(np_stream);</span><br><span style="color: hsl(120, 100%, 40%);">+                const char *found_da_name __attribute__((unused)) = "";</span><br><span style="color: hsl(120, 100%, 40%);">+             const char *found_np_name __attribute__((unused)) = "";</span><br><span style="color: hsl(120, 100%, 40%);">+             int found_da_slot __attribute__((unused)) = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+               int found_np_slot = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+               int removed_np_slot = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+             int j;</span><br><span style="color: hsl(120, 100%, 40%);">+                SCOPE_ENTER_DBG(3, "%s: slot: %d DP: %s  DA: %s  CA: %s\n", session_name, i,</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_str_tmp(128, ast_stream_to_str(dp_stream, &STR_TMP)),</span><br><span style="color: hsl(120, 100%, 40%);">+                 ast_str_tmp(128, ast_stream_to_str(da_stream, &STR_TMP)),</span><br><span style="color: hsl(120, 100%, 40%);">+                 ast_str_tmp(128, ast_stream_to_str(ca_stream, &STR_TMP)));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              if (STATE_NONE(da_state) && STATE_NONE(dp_state) && STATE_NONE(ca_state)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   SCOPE_EXIT_DBG_EXPR(break, "%s: All gone\n", session_name);</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%);">+             * Simple cases are handled first to avoid having to search the NP and DA</span><br><span style="color: hsl(120, 100%, 40%);">+              * topologies for streams with the same name but not in the same position.</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%);">+         if (STATE_NONE(dp_state) && !STATE_NONE(da_state)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              /*</span><br><span style="color: hsl(120, 100%, 40%);">+                     * The slot in the delayed pending topology can't be empty if the delayed</span><br><span style="color: hsl(120, 100%, 40%);">+                  * active topology has a stream there.  Streams can't just go away.  They</span><br><span style="color: hsl(120, 100%, 40%);">+                  * can be reused or marked "removed" but they can't go away.</span><br><span style="color: hsl(120, 100%, 40%);">+                     */</span><br><span style="color: hsl(120, 100%, 40%);">+                   SCOPE_EXIT_LOG_RTN(NULL, LOG_WARNING, "%s: DP slot is empty but DA is not\n", session_name);</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%);">+           if (STATE_NONE(dp_state)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               /*</span><br><span style="color: hsl(120, 100%, 40%);">+                     * The current active topology can certainly have streams that weren't</span><br><span style="color: hsl(120, 100%, 40%);">+                     * in existence when the delayed request was queued.  In this case,</span><br><span style="color: hsl(120, 100%, 40%);">+                    * no action is needed since we already copied the current active topology</span><br><span style="color: hsl(120, 100%, 40%);">+                     * to the new pending one.</span><br><span style="color: hsl(120, 100%, 40%);">+                     */</span><br><span style="color: hsl(120, 100%, 40%);">+                   SCOPE_EXIT_DBG_EXPR(continue, "%s: No DP stream so use CA stream as is\n", session_name);</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%);">+           if (ast_strings_equal(dp_name, da_name) && ast_strings_equal(da_name, ca_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     /*</span><br><span style="color: hsl(120, 100%, 40%);">+                     * The delayed pending stream in this slot matches by name, the streams</span><br><span style="color: hsl(120, 100%, 40%);">+                        * in the same slot in the other two topologies.  Easy case.</span><br><span style="color: hsl(120, 100%, 40%);">+                   */</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_trace_dbg(-1, "%s: Same stream in all 3 states\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (dp_state == da_state && da_state == ca_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           /* All the same state, no need to update. */</span><br><span style="color: hsl(120, 100%, 40%);">+                          SCOPE_EXIT_DBG_EXPR(continue, "%s: All in the same state so nothing to do\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (da_state != ca_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           /*</span><br><span style="color: hsl(120, 100%, 40%);">+                             * Something set the CA state between the time this request was queued</span><br><span style="color: hsl(120, 100%, 40%);">+                                 * and now.  The CA state wins so we don't do anything.</span><br><span style="color: hsl(120, 100%, 40%);">+                            */</span><br><span style="color: hsl(120, 100%, 40%);">+                           SCOPE_EXIT_DBG_EXPR(continue, "%s: Ignoring request to change state from %s to %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                       session_name, ast_stream_state2str(ca_state), ast_stream_state2str(dp_state));</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (dp_state != da_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           /* DP needs to update the state */</span><br><span style="color: hsl(120, 100%, 40%);">+                            ast_stream_set_state(np_stream, dp_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                            SCOPE_EXIT_DBG_EXPR(continue, "%s: Changed NP stream state from %s to %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                        session_name, ast_stream_state2str(ca_state), ast_stream_state2str(dp_state));</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%);">+           /*</span><br><span style="color: hsl(120, 100%, 40%);">+             * We're done with the simple cases.  For the rest, we need to identify if the</span><br><span style="color: hsl(120, 100%, 40%);">+             * DP stream we're trying to take action on is already in the other topologies</span><br><span style="color: hsl(120, 100%, 40%);">+             * possibly in a different slot.  To do that, if the stream in the DA or CA slots</span><br><span style="color: hsl(120, 100%, 40%);">+              * doesn't match the current DP stream, we need to iterate over the topology</span><br><span style="color: hsl(120, 100%, 40%);">+               * looking for a stream with the same name.</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%);">+             * Since we already copied all of the CA streams to the NP topology, we'll use it</span><br><span style="color: hsl(120, 100%, 40%);">+          * instead of CA because we'll be updating the NP as we go.</span><br><span style="color: hsl(120, 100%, 40%);">+                */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!ast_strings_equal(dp_name, np_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   /*</span><br><span style="color: hsl(120, 100%, 40%);">+                     * The NP stream in this slot doesn't have the same name as the DP stream</span><br><span style="color: hsl(120, 100%, 40%);">+                  * so we need to see if it's in another NP slot.  We're not going to stop</span><br><span style="color: hsl(120, 100%, 40%);">+                      * when we find a matching stream because we also want to find the first</span><br><span style="color: hsl(120, 100%, 40%);">+                       * removed removed slot, if any, so we can re-use this slot.  We'll break</span><br><span style="color: hsl(120, 100%, 40%);">+                  * early if we find both before we reach the end.</span><br><span style="color: hsl(120, 100%, 40%);">+                      */</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_trace_dbg(-1, "%s: Checking if DP is already in NP somewhere\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                 for (j = 0; j < ast_stream_topology_get_count(new_pending); j++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         struct ast_stream *possible_existing = ast_stream_topology_get_stream(new_pending, j);</span><br><span style="color: hsl(120, 100%, 40%);">+                                const char *possible_existing_name = GET_STREAM_NAME_SAFE(possible_existing);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                               ast_trace_dbg(-1, "%s: Checking %s against %s\n", session_name, dp_name, possible_existing_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                           if (found_np_slot == -1 && ast_strings_equal(dp_name, possible_existing_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ast_trace_dbg(-1, "%s: Pending stream %s slot %d is in NP slot %d\n", session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 dp_name, i, j);</span><br><span style="color: hsl(120, 100%, 40%);">+                                       found_np_slot = j;</span><br><span style="color: hsl(120, 100%, 40%);">+                                    found_np_stream = possible_existing;</span><br><span style="color: hsl(120, 100%, 40%);">+                                  found_np_state = ast_stream_get_state(possible_existing);</span><br><span style="color: hsl(120, 100%, 40%);">+                                     found_np_name = ast_stream_get_name(possible_existing);</span><br><span style="color: hsl(120, 100%, 40%);">+                               }</span><br><span style="color: hsl(120, 100%, 40%);">+                             if (STREAM_REMOVED(possible_existing) && removed_np_slot == -1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                     removed_np_slot = j;</span><br><span style="color: hsl(120, 100%, 40%);">+                          }</span><br><span style="color: hsl(120, 100%, 40%);">+                             if (removed_np_slot >= 0 && found_np_slot >= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                       break;</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%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* Makes the subsequent code easier */</span><br><span style="color: hsl(120, 100%, 40%);">+                        found_np_slot = i;</span><br><span style="color: hsl(120, 100%, 40%);">+                    found_np_stream = np_stream;</span><br><span style="color: hsl(120, 100%, 40%);">+                  found_np_state = np_state;</span><br><span style="color: hsl(120, 100%, 40%);">+                    found_np_name = np_name;</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%);">+           if (!ast_strings_equal(dp_name, da_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   /*</span><br><span style="color: hsl(120, 100%, 40%);">+                     * The DA stream in this slot doesn't have the same name as the DP stream</span><br><span style="color: hsl(120, 100%, 40%);">+                  * so we need to see if it's in another DA slot.  In real life, the DA stream</span><br><span style="color: hsl(120, 100%, 40%);">+                      * in this slot could have a different name but there shouldn't be a case</span><br><span style="color: hsl(120, 100%, 40%);">+                  * where the DP stream is another slot in the DA topology.  Just in case though.</span><br><span style="color: hsl(120, 100%, 40%);">+                       * We don't care about removed slots in the DA topology.</span><br><span style="color: hsl(120, 100%, 40%);">+                   */</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_trace_dbg(-1, "%s: Checking if DP is already in DA somewhere\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                 for (j = 0; j < ast_stream_topology_get_count(delayed_active); j++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              struct ast_stream *possible_existing = ast_stream_topology_get_stream(delayed_active, j);</span><br><span style="color: hsl(120, 100%, 40%);">+                             const char *possible_existing_name = GET_STREAM_NAME_SAFE(possible_existing);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                               ast_trace_dbg(-1, "%s: Checking %s against %s\n", session_name, dp_name, possible_existing_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                           if (ast_strings_equal(dp_name, possible_existing_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                     ast_trace_dbg(-1, "%s: Pending stream %s slot %d is already in delayed active slot %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                           session_name, dp_name, i, j);</span><br><span style="color: hsl(120, 100%, 40%);">+                                 found_da_slot = j;</span><br><span style="color: hsl(120, 100%, 40%);">+                                    found_da_stream = possible_existing;</span><br><span style="color: hsl(120, 100%, 40%);">+                                  found_da_state = ast_stream_get_state(possible_existing);</span><br><span style="color: hsl(120, 100%, 40%);">+                                     found_da_name = ast_stream_get_name(possible_existing);</span><br><span style="color: hsl(120, 100%, 40%);">+                                       break;</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%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* Makes the subsequent code easier */</span><br><span style="color: hsl(120, 100%, 40%);">+                        found_da_slot = i;</span><br><span style="color: hsl(120, 100%, 40%);">+                    found_da_stream = da_stream;</span><br><span style="color: hsl(120, 100%, 40%);">+                  found_da_state = da_state;</span><br><span style="color: hsl(120, 100%, 40%);">+                    found_da_name = da_name;</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_trace_dbg(-1, "%s: Found NP slot: %d  Found removed NP slot: %d Found DA slot: %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   session_name, found_np_slot, removed_np_slot, found_da_slot);</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%);">+             * Now we know whether the DP stream is new or changing state and we know if the DP</span><br><span style="color: hsl(120, 100%, 40%);">+            * stream exists in the other topologies and if so, where in those topologies it exists.</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%);">+         if (!found_da_stream) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       /*</span><br><span style="color: hsl(120, 100%, 40%);">+                     * The DP stream isn't in the DA topology which would imply that the intention of the</span><br><span style="color: hsl(120, 100%, 40%);">+                      * request was to add the stream, not change its state.  It's possible though that</span><br><span style="color: hsl(120, 100%, 40%);">+                         * the stream was added by another request between the time this request was queued</span><br><span style="color: hsl(120, 100%, 40%);">+                    * and now so we need to check the CA topology as well.</span><br><span style="color: hsl(120, 100%, 40%);">+                        */</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_trace_dbg(-1, "%s: There was no corresponding DA stream so the request was to add a stream\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (found_np_stream) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                /*</span><br><span style="color: hsl(120, 100%, 40%);">+                             * We found it in the CA topology.  Since the intention was to add it</span><br><span style="color: hsl(120, 100%, 40%);">+                          * and it's already there, there's nothing to do.</span><br><span style="color: hsl(120, 100%, 40%);">+                              */</span><br><span style="color: hsl(120, 100%, 40%);">+                           SCOPE_EXIT_DBG_EXPR(continue, "%s: New stream requested but it's already in CA\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                       } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              /* OK, it's not in either which would again imply that the intention of the</span><br><span style="color: hsl(120, 100%, 40%);">+                                * request was to add the stream.</span><br><span style="color: hsl(120, 100%, 40%);">+                              */</span><br><span style="color: hsl(120, 100%, 40%);">+                           ast_trace_dbg(-1, "%s: There was no corresponding NP stream\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                              if (STATE_REMOVED(dp_state)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                        /*</span><br><span style="color: hsl(120, 100%, 40%);">+                                     * How can DP request to remove a stream that doesn't seem to exist anythere?</span><br><span style="color: hsl(120, 100%, 40%);">+                                      * It's not.  It's possible that the stream was already removed and the slot</span><br><span style="color: hsl(120, 100%, 40%);">+                                   * reused in the CA topology, but it would still have to exist in the DA</span><br><span style="color: hsl(120, 100%, 40%);">+                                       * topology.  Bail.</span><br><span style="color: hsl(120, 100%, 40%);">+                                    */</span><br><span style="color: hsl(120, 100%, 40%);">+                                   SCOPE_EXIT_LOG_RTN(NULL, LOG_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           "%s: Attempting to remove stream %d:%s but it doesn't exist anywhere.\n", session_name, i, dp_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                            } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      /*</span><br><span style="color: hsl(120, 100%, 40%);">+                                     * We're now sure we want to add the the stream.  Since we can re-use</span><br><span style="color: hsl(120, 100%, 40%);">+                                      * slots in the CA topology that have streams marked as "removed", we</span><br><span style="color: hsl(120, 100%, 40%);">+                                        * use the slot we saved in removed_np_slot if it exists.</span><br><span style="color: hsl(120, 100%, 40%);">+                                      */</span><br><span style="color: hsl(120, 100%, 40%);">+                                   ast_trace_dbg(-1, "%s: Checking for open slot\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                                    if (removed_np_slot >= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                                struct ast_sip_session_media *old_media = AST_VECTOR_GET(&new_pending_state->sessions, removed_np_slot);</span><br><span style="color: hsl(120, 100%, 40%);">+                                               res = ast_stream_topology_set_stream(new_pending, removed_np_slot, ast_stream_clone(dp_stream, NULL));</span><br><span style="color: hsl(120, 100%, 40%);">+                                                if (res != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   SCOPE_EXIT_LOG_RTN(NULL, LOG_WARNING, "%s: Couldn't set stream in new topology\n", session_name);</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%);">+                                             * Since we're reusing the removed_np_slot slot for something else, we need</span><br><span style="color: hsl(120, 100%, 40%);">+                                                * to free and remove any session media already in it.</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 * ast_stream_topology_set_stream() took care of freeing the old stream.</span><br><span style="color: hsl(120, 100%, 40%);">+                                               */</span><br><span style="color: hsl(120, 100%, 40%);">+                                           res = AST_VECTOR_REPLACE(&new_pending_state->sessions, removed_np_slot, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                                         if (res != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   SCOPE_EXIT_LOG_RTN(NULL, LOG_WARNING, "%s: Couldn't replace media session\n", session_name);</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%);">+                                           ao2_cleanup(old_media);</span><br><span style="color: hsl(120, 100%, 40%);">+                                               SCOPE_EXIT_DBG_EXPR(continue, "%s: Replaced removed stream in slot %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   session_name, removed_np_slot);</span><br><span style="color: hsl(120, 100%, 40%);">+                                       } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                                              int new_slot = ast_stream_topology_append_stream(new_pending, ast_stream_clone(dp_stream, NULL));</span><br><span style="color: hsl(120, 100%, 40%);">+                                             if (new_slot < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                                    SCOPE_EXIT_LOG_RTN(NULL, LOG_WARNING, "%s: Couldn't append stream in new topology\n", session_name);</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%);">+                                           res = AST_VECTOR_REPLACE(&new_pending_state->sessions, new_slot, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                                                if (res != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   SCOPE_EXIT_LOG_RTN(NULL, LOG_WARNING, "%s: Couldn't replace media session\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                                                }</span><br><span style="color: hsl(120, 100%, 40%);">+                                             SCOPE_EXIT_DBG_EXPR(continue, "%s: Appended new stream to slot %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                                       session_name, new_slot);</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%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /*</span><br><span style="color: hsl(120, 100%, 40%);">+                     * The DP stream exists in the DA topology so it's a change of some sort.</span><br><span style="color: hsl(120, 100%, 40%);">+                  */</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_trace_dbg(-1, "%s: There was a corresponding DA stream so the request was to change/remove a stream\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (dp_state == found_da_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             /* No change? Let's see if it's in CA */</span><br><span style="color: hsl(120, 100%, 40%);">+                              if (!found_np_stream) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                       /*</span><br><span style="color: hsl(120, 100%, 40%);">+                                     * The DP and DA state are the same which would imply that the stream</span><br><span style="color: hsl(120, 100%, 40%);">+                                  * already exists but it's not in the CA topology.  It's possible that</span><br><span style="color: hsl(120, 100%, 40%);">+                                         * between the time this request was queued and now the stream was removed</span><br><span style="color: hsl(120, 100%, 40%);">+                                     * from the CA topology and the slot used for something else.  Nothing</span><br><span style="color: hsl(120, 100%, 40%);">+                                         * we can do here.</span><br><span style="color: hsl(120, 100%, 40%);">+                                     */</span><br><span style="color: hsl(120, 100%, 40%);">+                                   SCOPE_EXIT_DBG_EXPR(continue, "%s: Stream doesn't exist in CA so nothing to do\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                               } else if (dp_state == found_np_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      SCOPE_EXIT_DBG_EXPR(continue, "%s: States are the same all around so nothing to do\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                               } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      SCOPE_EXIT_DBG_EXPR(continue, "%s: Something changed the CA state so we're going to leave it as is\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                           }</span><br><span style="color: hsl(120, 100%, 40%);">+                     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              /* We have a state change. */</span><br><span style="color: hsl(120, 100%, 40%);">+                         ast_trace_dbg(-1, "%s: Requesting state change to %s\n", session_name, ast_stream_state2str(dp_state));</span><br><span style="color: hsl(120, 100%, 40%);">+                             if (!found_np_stream) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                       SCOPE_EXIT_DBG_EXPR(continue, "%s: Stream doesn't exist in CA so nothing to do\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                               } else if (da_state == found_np_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ast_stream_set_state(found_np_stream, dp_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                                      SCOPE_EXIT_DBG_EXPR(continue, "%s: Changed NP stream state from %s to %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                                session_name, ast_stream_state2str(found_np_state), ast_stream_state2str(dp_state));</span><br><span style="color: hsl(120, 100%, 40%);">+                          } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      SCOPE_EXIT_DBG_EXPR(continue, "%s: Something changed the CA state so we're going to leave it as is\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                          session_name);</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           SCOPE_EXIT_DBG("%s: Done with slot %d\n", session_name, i);</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_trace_dbg(-1, "%s: Resetting default media states\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+    for (i = 0; i < AST_MEDIA_TYPE_END; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         int j;</span><br><span style="color: hsl(120, 100%, 40%);">+                new_pending_state->default_session[i] = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+              for (j = 0; j < AST_VECTOR_SIZE(&new_pending_state->sessions); j++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       struct ast_sip_session_media *media = AST_VECTOR_GET(&new_pending_state->sessions, j);</span><br><span style="color: hsl(120, 100%, 40%);">+                 struct ast_stream *stream = ast_stream_topology_get_stream(new_pending_state->topology, j);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (media && media->type == i && !STREAM_REMOVED(stream)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                new_pending_state->default_session[i] = media;</span><br><span style="color: hsl(120, 100%, 40%);">+                             break;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (run_post_validation) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_trace_dbg(-1, "%s: Running post-validation\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!is_media_state_valid(session_name, new_pending_state)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 SCOPE_EXIT_LOG_RTN(NULL, LOG_ERROR, "State not consistent\n");</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%);">+   /*</span><br><span style="color: hsl(120, 100%, 40%);">+     * We need to move the new pending state to another variable and set new_pending_state to NULL</span><br><span style="color: hsl(120, 100%, 40%);">+         * so RAII_VAR doesn't free it.</span><br><span style="color: hsl(120, 100%, 40%);">+    */</span><br><span style="color: hsl(120, 100%, 40%);">+   returned_media_state = new_pending_state;</span><br><span style="color: hsl(120, 100%, 40%);">+     new_pending_state = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     SCOPE_EXIT_DBG_RTN(returned_media_state, "%s: NP: %s\n", session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_str_tmp(256, ast_stream_topology_to_str(new_pending, &STR_TMP)));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int sip_session_refresh(struct ast_sip_session *session,</span><br><span>            ast_sip_session_request_creation_cb on_request_creation,</span><br><span>             ast_sip_session_sdp_creation_cb on_sdp_creation,</span><br><span>             ast_sip_session_response_cb on_response,</span><br><span>             enum ast_sip_session_refresh_method method, int generate_new_sdp,</span><br><span style="color: hsl(0, 100%, 40%);">-               struct ast_sip_session_media_state *media_state,</span><br><span style="color: hsl(120, 100%, 40%);">+              struct ast_sip_session_media_state *pending_media_state,</span><br><span style="color: hsl(120, 100%, 40%);">+              struct ast_sip_session_media_state *active_media_state,</span><br><span>              int queued)</span><br><span> {</span><br><span>     pjsip_inv_session *inv_session = session->inv_session;</span><br><span>    pjmedia_sdp_session *new_sdp = NULL;</span><br><span>         pjsip_tx_data *tdata;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       if (media_state && (!media_state->topology || !generate_new_sdp)) {</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_sip_session_media_state_free(media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (pending_media_state && (!pending_media_state->topology || !generate_new_sdp)) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_debug(3, "%s: Not sending reinvite because %s%s\n", ast_sip_session_get_name(session),</span><br><span style="color: hsl(120, 100%, 40%);">+                  pending_media_state->topology == NULL ? "pending topology is null " : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                              !generate_new_sdp ? "generate_new_sdp is false" : "");</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_sip_session_media_state_free(pending_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_sip_session_media_state_free(active_media_state);</span><br><span>                return -1;</span><br><span>   }</span><br><span> </span><br><span>        if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {</span><br><span>                 /* Don't try to do anything with a hung-up call */</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_debug(3, "Not sending reinvite to %s because of disconnected state...\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                         ast_sorcery_object_get_id(session->endpoint));</span><br><span style="color: hsl(0, 100%, 40%);">-               ast_sip_session_media_state_free(media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_debug(3, "%s: Not sending reinvite because of disconnected state\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            ast_sip_session_get_name(session));</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_sip_session_media_state_free(pending_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_sip_session_media_state_free(active_media_state);</span><br><span>                return 0;</span><br><span>    }</span><br><span> </span><br><span>        /* If the dialog has not yet been established we have to defer until it has */</span><br><span>       if (inv_session->dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_debug(3, "Delay sending request to %s because dialog has not been established...\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                      ast_sorcery_object_get_id(session->endpoint));</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_debug(3, "%s: Delay sending reinvite because dialog has not been established\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_sip_session_get_name(session));</span><br><span>          return delay_request(session, on_request_creation, on_sdp_creation, on_response,</span><br><span>                     generate_new_sdp,</span><br><span>                    method == AST_SIP_SESSION_REFRESH_METHOD_INVITE</span><br><span>                              ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE,</span><br><span style="color: hsl(0, 100%, 40%);">-                        media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                 pending_media_state, active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);</span><br><span>   }</span><br><span> </span><br><span>        if (method == AST_SIP_SESSION_REFRESH_METHOD_INVITE) {</span><br><span>               if (inv_session->invite_tsx) {</span><br><span>                    /* We can't send a reinvite yet, so delay it */</span><br><span style="color: hsl(0, 100%, 40%);">-                     ast_debug(3, "Delay sending reinvite to %s because of outstanding transaction...\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                  ast_sorcery_object_get_id(session->endpoint));</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_debug(3, "%s: Delay sending reinvite because of outstanding transaction\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                             ast_sip_session_get_name(session));</span><br><span>                  return delay_request(session, on_request_creation, on_sdp_creation,</span><br><span style="color: hsl(0, 100%, 40%);">-                             on_response, generate_new_sdp, DELAYED_METHOD_INVITE, media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                           on_response, generate_new_sdp, DELAYED_METHOD_INVITE, pending_media_state,</span><br><span style="color: hsl(120, 100%, 40%);">+                            active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);</span><br><span>                } else if (inv_session->state != PJSIP_INV_STATE_CONFIRMED) {</span><br><span>                     /* Initial INVITE transaction failed to progress us to a confirmed state</span><br><span>                      * which means re-invites are not possible</span><br><span>                    */</span><br><span style="color: hsl(0, 100%, 40%);">-                     ast_debug(3, "Not sending reinvite to %s because not in confirmed state...\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                        ast_sorcery_object_get_id(session->endpoint));</span><br><span style="color: hsl(0, 100%, 40%);">-                       ast_sip_session_media_state_free(media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_debug(3, "%s: Not sending reinvite because not in confirmed state\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                           ast_sip_session_get_name(session));</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_sip_session_media_state_free(pending_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_sip_session_media_state_free(active_media_state);</span><br><span>                        return 0;</span><br><span>            }</span><br><span>    }</span><br><span>@@ -1688,32 +2251,59 @@</span><br><span>          if (inv_session->neg</span><br><span>                      && pjmedia_sdp_neg_get_state(inv_session->neg)</span><br><span>                            != PJMEDIA_SDP_NEG_STATE_DONE) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        ast_debug(3, "Delay session refresh with new SDP to %s because SDP negotiation is not yet done...\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                         ast_sorcery_object_get_id(session->endpoint));</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_debug(3, "%s: Delay session refresh with new SDP because SDP negotiation is not yet done\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            ast_sip_session_get_name(session));</span><br><span>                  return delay_request(session, on_request_creation, on_sdp_creation,</span><br><span>                          on_response, generate_new_sdp,</span><br><span>                               method == AST_SIP_SESSION_REFRESH_METHOD_INVITE</span><br><span style="color: hsl(0, 100%, 40%);">-                                 ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE, media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                                        ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE, pending_media_state,</span><br><span style="color: hsl(120, 100%, 40%);">+                         active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);</span><br><span>                }</span><br><span> </span><br><span>                /* If an explicitly requested media state has been provided use it instead of any pending one */</span><br><span style="color: hsl(0, 100%, 40%);">-                if (media_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (pending_media_state) {</span><br><span>                   int index;</span><br><span>                   int type_streams[AST_MEDIA_TYPE_END] = {0};</span><br><span>                  struct ast_stream *stream;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_debug(3, "%s: Pending media state exists\n", ast_sip_session_get_name(session));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                     /* Media state conveys a desired media state, so if there are outstanding</span><br><span>                     * delayed requests we need to ensure we go into the queue and not jump</span><br><span>                       * ahead. If we sent this media state now then updates could go out of</span><br><span>                        * order.</span><br><span>                     */</span><br><span>                  if (!queued && !AST_LIST_EMPTY(&session->delayed_requests)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                            ast_debug(3, "Delay sending reinvite to %s because of outstanding requests...\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                     ast_sorcery_object_get_id(session->endpoint));</span><br><span style="color: hsl(120, 100%, 40%);">+                             ast_debug(3, "%s: Delay sending reinvite because of outstanding requests\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                        ast_sip_session_get_name(session));</span><br><span>                          return delay_request(session, on_request_creation, on_sdp_creation,</span><br><span>                                  on_response, generate_new_sdp,</span><br><span>                                       method == AST_SIP_SESSION_REFRESH_METHOD_INVITE</span><br><span style="color: hsl(0, 100%, 40%);">-                                         ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE, media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                                                ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE, pending_media_state,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);</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%);">+                   if (active_media_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             struct ast_sip_session_media_state *new_pending_state;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                              ast_debug(3, "%s: Active media state exists\n", ast_sip_session_get_name(session));</span><br><span style="color: hsl(120, 100%, 40%);">+                         ast_debug(3, "%s: DP: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(pending_media_state->topology, &STR_TMP)));</span><br><span style="color: hsl(120, 100%, 40%);">+                              ast_debug(3, "%s: DA: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(active_media_state->topology, &STR_TMP)));</span><br><span style="color: hsl(120, 100%, 40%);">+                               ast_debug(3, "%s: CP: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(session->pending_media_state->topology, &STR_TMP)));</span><br><span style="color: hsl(120, 100%, 40%);">+                          ast_debug(3, "%s: CA: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(session->active_media_state->topology, &STR_TMP)));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                         new_pending_state = merge_refresh_media_states(ast_sip_session_get_name(session),</span><br><span style="color: hsl(120, 100%, 40%);">+                                     pending_media_state, active_media_state, session->active_media_state, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                          if (new_pending_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ast_debug(3, "%s: NP: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(new_pending_state->topology, &STR_TMP)));</span><br><span style="color: hsl(120, 100%, 40%);">+                                        ast_sip_session_media_state_free(pending_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                                        pending_media_state = new_pending_state;</span><br><span style="color: hsl(120, 100%, 40%);">+                              } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ast_sip_session_media_state_reset(pending_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                                       ast_sip_session_media_state_free(active_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                                 ast_log(LOG_WARNING, "%s: Unable to merge media states\n", ast_sip_session_get_name(session));</span><br><span style="color: hsl(120, 100%, 40%);">+                                      return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+                            }</span><br><span>                    }</span><br><span> </span><br><span>                        /* Prune the media state so the number of streams fit within the configured limits - we do it here</span><br><span>@@ -1721,10 +2311,10 @@</span><br><span>                          * of the SDP when producing it we'd be in trouble. We also enforce formats here for media types that</span><br><span>                     * are configurable on the endpoint.</span><br><span>                          */</span><br><span style="color: hsl(0, 100%, 40%);">-                     for (index = 0; index < ast_stream_topology_get_count(media_state->topology); ++index) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        for (index = 0; index < ast_stream_topology_get_count(pending_media_state->topology); ++index) {</span><br><span>                               struct ast_stream *existing_stream = NULL;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                          stream = ast_stream_topology_get_stream(media_state->topology, index);</span><br><span style="color: hsl(120, 100%, 40%);">+                             stream = ast_stream_topology_get_stream(pending_media_state->topology, index);</span><br><span> </span><br><span>                                if (session->active_media_state->topology &&</span><br><span>                                   index < ast_stream_topology_get_count(session->active_media_state->topology)) {</span><br><span>@@ -1732,14 +2322,15 @@</span><br><span>                           }</span><br><span> </span><br><span>                                if (is_stream_limitation_reached(ast_stream_get_type(stream), session->endpoint, type_streams)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                    if (index < AST_VECTOR_SIZE(&media_state->sessions)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                                struct ast_sip_session_media *session_media = AST_VECTOR_GET(&media_state->sessions, index);</span><br><span style="color: hsl(120, 100%, 40%);">+                                   if (index < AST_VECTOR_SIZE(&pending_media_state->sessions)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                              struct ast_sip_session_media *session_media = AST_VECTOR_GET(&pending_media_state->sessions, index);</span><br><span> </span><br><span>                                              ao2_cleanup(session_media);</span><br><span style="color: hsl(0, 100%, 40%);">-                                             AST_VECTOR_REMOVE(&media_state->sessions, index, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                                           AST_VECTOR_REMOVE(&pending_media_state->sessions, index, 1);</span><br><span>                                  }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                                   ast_stream_topology_del_stream(media_state->topology, index);</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ast_stream_topology_del_stream(pending_media_state->topology, index);</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ast_debug(3, "%s: Droped overlimit stream %d:%s\n", ast_sip_session_get_name(session), index, ast_stream_get_name(stream));</span><br><span> </span><br><span>                                    /* A stream has potentially moved into our spot so we need to jump back so we process it */</span><br><span>                                  index -= 1;</span><br><span>@@ -1750,7 +2341,9 @@</span><br><span>                          if (ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED) {</span><br><span>                                      /* If there is no existing stream we can just not have this stream in the topology at all. */</span><br><span>                                        if (!existing_stream) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                         ast_stream_topology_del_stream(media_state->topology, index);</span><br><span style="color: hsl(120, 100%, 40%);">+                                              ast_debug(3, "%s: Dropped removed stream %d:%s\n", ast_sip_session_get_name(session), index, ast_stream_get_name(stream));</span><br><span style="color: hsl(120, 100%, 40%);">+                                          ast_stream_topology_del_stream(pending_media_state->topology, index);</span><br><span style="color: hsl(120, 100%, 40%);">+                                              /* TODO: Do we need to remove the corresponding media state? */</span><br><span>                                              index -= 1;</span><br><span>                                  }</span><br><span>                                    continue;</span><br><span>@@ -1762,7 +2355,8 @@</span><br><span> </span><br><span>                                        joint_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);</span><br><span>                                       if (!joint_cap) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                               ast_sip_session_media_state_free(media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                                                ast_sip_session_media_state_free(pending_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                                                ast_sip_session_media_state_free(active_media_state);</span><br><span>                                                return 0;</span><br><span>                                    }</span><br><span>                                    ast_format_cap_get_compatible(ast_stream_get_formats(stream), session->endpoint->media.codecs, joint_cap);</span><br><span>@@ -1773,7 +2367,8 @@</span><br><span>                                                     /* If there is no existing stream we can just not have this stream in the topology</span><br><span>                                                    * at all.</span><br><span>                                                    */</span><br><span style="color: hsl(0, 100%, 40%);">-                                                     ast_stream_topology_del_stream(media_state->topology, index);</span><br><span style="color: hsl(120, 100%, 40%);">+                                                      ast_stream_topology_del_stream(pending_media_state->topology, index);</span><br><span style="color: hsl(120, 100%, 40%);">+                                                      ast_debug(3, "%s: Dropped incompatible stream %d:%s\n", ast_sip_session_get_name(session), index, ast_stream_get_name(stream));</span><br><span>                                                    index -= 1;</span><br><span>                                                  continue;</span><br><span>                                            } else if (ast_stream_get_state(stream) != ast_stream_get_state(existing_stream) ||</span><br><span>@@ -1783,6 +2378,7 @@</span><br><span>                                                   * is preserved.</span><br><span>                                                      */</span><br><span>                                                  ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED);</span><br><span style="color: hsl(120, 100%, 40%);">+                                                       ast_debug(3, "%s: Removed incompatible stream %d:%s\n", ast_sip_session_get_name(session), index, ast_stream_get_name(stream));</span><br><span>                                                    continue;</span><br><span>                                            } else {</span><br><span>                                                     /* However if the stream is otherwise remaining the same we can keep the formats</span><br><span>@@ -1796,6 +2392,7 @@</span><br><span>                             }</span><br><span> </span><br><span>                                ++type_streams[ast_stream_get_type(stream)];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                       }</span><br><span> </span><br><span>                        if (session->active_media_state->topology) {</span><br><span>@@ -1804,30 +2401,40 @@</span><br><span>                                  * streams than are currently present we fill in the topology to match the current number of streams</span><br><span>                                  * that are active.</span><br><span>                           */</span><br><span style="color: hsl(0, 100%, 40%);">-                             for (index = ast_stream_topology_get_count(media_state->topology);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                               for (index = ast_stream_topology_get_count(pending_media_state->topology);</span><br><span>                                        index < ast_stream_topology_get_count(session->active_media_state->topology); ++index) {</span><br><span>                                    struct ast_stream *cloned;</span><br><span style="color: hsl(120, 100%, 40%);">+                                    int position;</span><br><span> </span><br><span>                                    stream = ast_stream_topology_get_stream(session->active_media_state->topology, index);</span><br><span>                                         ast_assert(stream != NULL);</span><br><span> </span><br><span>                                      cloned = ast_stream_clone(stream, NULL);</span><br><span>                                     if (!cloned) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                          ast_sip_session_media_state_free(media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                                                ast_sip_session_media_state_free(pending_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                                                ast_sip_session_media_state_free(active_media_state);</span><br><span>                                                return -1;</span><br><span>                                   }</span><br><span> </span><br><span>                                        ast_stream_set_state(cloned, AST_STREAM_STATE_REMOVED);</span><br><span style="color: hsl(0, 100%, 40%);">-                                 if (ast_stream_topology_append_stream(media_state->topology, cloned) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                     position = ast_stream_topology_append_stream(pending_media_state->topology, cloned);</span><br><span style="color: hsl(120, 100%, 40%);">+                                       if (position < 0) {</span><br><span>                                               ast_stream_free(cloned);</span><br><span style="color: hsl(0, 100%, 40%);">-                                                ast_sip_session_media_state_free(media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                                                ast_sip_session_media_state_free(pending_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                                                ast_sip_session_media_state_free(active_media_state);</span><br><span>                                                return -1;</span><br><span>                                   }</span><br><span style="color: hsl(120, 100%, 40%);">+                                     ast_debug(3, "%s: Appended empty stream in position %d to make counts match\n", ast_sip_session_get_name(session), position);</span><br><span>                              }</span><br><span> </span><br><span>                                /* If the resulting media state matches the existing active state don't bother doing a session refresh */</span><br><span style="color: hsl(0, 100%, 40%);">-                           if (ast_stream_topology_equal(session->active_media_state->topology, media_state->topology)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                 ast_sip_session_media_state_free(media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                                if (ast_stream_topology_equal(session->active_media_state->topology, pending_media_state->topology)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                       ast_debug(3, "%s: CA: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(session->active_media_state->topology, &STR_TMP)));</span><br><span style="color: hsl(120, 100%, 40%);">+                                   ast_debug(3, "%s: NP: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(pending_media_state->topology, &STR_TMP)));</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ast_debug(3, "%s: Topologies are equal. Not sending re-invite\n", ast_sip_session_get_name(session));</span><br><span style="color: hsl(120, 100%, 40%);">+                                       ast_sip_session_media_state_free(pending_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                                        ast_sip_session_media_state_free(active_media_state);</span><br><span>                                        /* For external consumers we return 0 to say success, but internally for</span><br><span>                                      * send_delayed_request we return a separate value to indicate that this</span><br><span>                                      * session refresh would be redundant so we didn't send it</span><br><span>@@ -1837,18 +2444,22 @@</span><br><span>                     }</span><br><span> </span><br><span>                        ast_sip_session_media_state_free(session->pending_media_state);</span><br><span style="color: hsl(0, 100%, 40%);">-                      session->pending_media_state = media_state;</span><br><span style="color: hsl(120, 100%, 40%);">+                        session->pending_media_state = pending_media_state;</span><br><span>               }</span><br><span> </span><br><span>                new_sdp = generate_session_refresh_sdp(session);</span><br><span>             if (!new_sdp) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 ast_log(LOG_ERROR, "Failed to generate session refresh SDP. Not sending session refresh\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_log(LOG_WARNING, "%s: Failed to generate session refresh SDP. Not sending session refresh\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                           ast_sip_session_get_name(session));</span><br><span>                  ast_sip_session_media_state_reset(session->pending_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_sip_session_media_state_free(active_media_state);</span><br><span>                        return -1;</span><br><span>           }</span><br><span>            if (on_sdp_creation) {</span><br><span>                       if (on_sdp_creation(session, new_sdp)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              ast_log(LOG_WARNING, "%s: on_sdp_creation failed\n", ast_sip_session_get_name(session));</span><br><span>                           ast_sip_session_media_state_reset(session->pending_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                           ast_sip_session_media_state_free(active_media_state);</span><br><span>                                return -1;</span><br><span>                   }</span><br><span>            }</span><br><span>@@ -1856,31 +2467,35 @@</span><br><span> </span><br><span>      if (method == AST_SIP_SESSION_REFRESH_METHOD_INVITE) {</span><br><span>               if (pjsip_inv_reinvite(inv_session, NULL, new_sdp, &tdata)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       ast_log(LOG_WARNING, "Failed to create reinvite properly.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_log(LOG_WARNING, "%s: Failed to create reinvite properly\n", ast_sip_session_get_name(session));</span><br><span>                       if (generate_new_sdp) {</span><br><span>                              ast_sip_session_media_state_reset(session->pending_media_state);</span><br><span>                  }</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_sip_session_media_state_free(active_media_state);</span><br><span>                        return -1;</span><br><span>           }</span><br><span>    } else if (pjsip_inv_update(inv_session, NULL, new_sdp, &tdata)) {</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_log(LOG_WARNING, "Failed to create UPDATE properly.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_log(LOG_WARNING, "%s: Failed to create UPDATE properly\n", ast_sip_session_get_name(session));</span><br><span>                 if (generate_new_sdp) {</span><br><span>                      ast_sip_session_media_state_reset(session->pending_media_state);</span><br><span>          }</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_sip_session_media_state_free(active_media_state);</span><br><span>                return -1;</span><br><span>   }</span><br><span>    if (on_request_creation) {</span><br><span>           if (on_request_creation(session, tdata)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_log(LOG_WARNING, "%s: on_request_creation failed.\n", ast_sip_session_get_name(session));</span><br><span>                      if (generate_new_sdp) {</span><br><span>                              ast_sip_session_media_state_reset(session->pending_media_state);</span><br><span>                  }</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_sip_session_media_state_free(active_media_state);</span><br><span>                        return -1;</span><br><span>           }</span><br><span>    }</span><br><span style="color: hsl(0, 100%, 40%);">-       ast_debug(3, "Sending session refresh SDP via %s to %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-            method == AST_SIP_SESSION_REFRESH_METHOD_INVITE ? "re-INVITE" : "UPDATE",</span><br><span style="color: hsl(0, 100%, 40%);">-           ast_sorcery_object_get_id(session->endpoint));</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_debug(3, "%s: Sending session refresh SDP via %s\n", ast_sip_session_get_name(session),</span><br><span style="color: hsl(120, 100%, 40%);">+         method == AST_SIP_SESSION_REFRESH_METHOD_INVITE ? "re-INVITE" : "UPDATE");</span><br><span>       ast_sip_session_send_request_with_cb(session, tdata, on_response);</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_sip_session_media_state_free(active_media_state);</span><br><span>        return 0;</span><br><span> }</span><br><span> </span><br><span>@@ -1892,7 +2507,7 @@</span><br><span>           struct ast_sip_session_media_state *media_state)</span><br><span> {</span><br><span>        return sip_session_refresh(session, on_request_creation, on_sdp_creation,</span><br><span style="color: hsl(0, 100%, 40%);">-               on_response, method, generate_new_sdp, media_state, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+               on_response, method, generate_new_sdp, media_state, NULL, 0);</span><br><span> }</span><br><span> </span><br><span> int ast_sip_session_regenerate_answer(struct ast_sip_session *session,</span><br><span>@@ -2054,7 +2669,7 @@</span><br><span> </span><br><span>                 handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);</span><br><span>               if (!handler_list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_debug(3, "%s: No registered SDP handlers for media type '%s'\n", ast_sip_session_get_name(session), media);</span><br><span>                    continue;</span><br><span>            }</span><br><span>            AST_LIST_TRAVERSE(&handler_list->list, handler, next) {</span><br><span>@@ -2102,6 +2717,11 @@</span><br><span>              return PJ_FALSE;</span><br><span>     }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (session->inv_session->invite_tsx) {</span><br><span style="color: hsl(120, 100%, 40%);">+         /* There's a transaction in progress so bail now and let pjproject send 491 */</span><br><span style="color: hsl(120, 100%, 40%);">+            return PJ_FALSE;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  if (session->deferred_reinvite) {</span><br><span>                 pj_str_t key, deferred_key;</span><br><span>          pjsip_tx_data *tdata;</span><br><span>@@ -2307,7 +2927,7 @@</span><br><span>        const char *endpoint_name = session->endpoint ?</span><br><span>           ast_strdupa(ast_sorcery_object_get_id(session->endpoint)) : "<none>";</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    ast_debug(3, "Destroying SIP session with endpoint %s\n", endpoint_name);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_debug(3, "%s: Destroying SIP session\n", ast_sip_session_get_name(session));</span><br><span> </span><br><span>       ast_test_suite_event_notify("SESSION_DESTROYING",</span><br><span>          "Endpoint: %s\r\n"</span><br><span>@@ -2624,18 +3244,19 @@</span><br><span>       }</span><br><span> </span><br><span>        inv = pjsip_dlg_get_inv_session(dlg);</span><br><span style="color: hsl(120, 100%, 40%);">+ session = inv->mod_data[session_module.id];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     if (PJSIP_INV_STATE_CONFIRMED <= inv->state) {</span><br><span>                 /*</span><br><span>            * We cannot handle reINVITE authentication at this</span><br><span>           * time because the reINVITE transaction is still in</span><br><span>                  * progress.</span><br><span>                  */</span><br><span style="color: hsl(0, 100%, 40%);">-             ast_debug(1, "A reINVITE is being challenged.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_debug(3, "%s: A reINVITE is being challenged\n", ast_sip_session_get_name(session));</span><br><span>           return PJ_FALSE;</span><br><span>     }</span><br><span style="color: hsl(0, 100%, 40%);">-       ast_debug(1, "Initial INVITE is being challenged.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_debug(3, "%s: Initial INVITE is being challenged.\n", ast_sip_session_get_name(session));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     session = inv->mod_data[session_module.id];</span><br><span> </span><br><span>   if (ast_sip_create_request_with_auth(&session->endpoint->outbound_auths, rdata,</span><br><span>            tsx->last_tx, &tdata)) {</span><br><span>@@ -2886,12 +3507,12 @@</span><br><span>            break;</span><br><span>       case PJSIP_INV_STATE_CONFIRMED:</span><br><span>              if (session->inv_session->invite_tsx) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   ast_debug(3, "Delay sending BYE to %s because of outstanding transaction...\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                       ast_sorcery_object_get_id(session->endpoint));</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_debug(3, "%s: Delay sending BYE because of outstanding transaction...\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                               ast_sip_session_get_name(session));</span><br><span>                  /* If this is delayed the only thing that will happen is a BYE request so we don't</span><br><span>                        * actually need to store the response code for when it happens.</span><br><span>                      */</span><br><span style="color: hsl(0, 100%, 40%);">-                     delay_request(session, NULL, NULL, NULL, 0, DELAYED_METHOD_BYE, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                        delay_request(session, NULL, NULL, NULL, 0, DELAYED_METHOD_BYE, NULL, NULL, 1);</span><br><span>                      break;</span><br><span>               }</span><br><span>            /* Fall through */</span><br><span>@@ -3009,7 +3630,7 @@</span><br><span> </span><br><span>       if (session->ended_while_deferred) {</span><br><span>              /* Complete the session end started by the remote hangup. */</span><br><span style="color: hsl(0, 100%, 40%);">-            ast_debug(3, "Ending session (%p) after being deferred\n", session);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_debug(3, "%s: Ending session after being deferred\n", ast_sip_session_get_name(session));</span><br><span>              session->ended_while_deferred = 0;</span><br><span>                session_end(session);</span><br><span>        }</span><br><span>@@ -3073,7 +3694,8 @@</span><br><span> </span><br><span>        pickup_cfg = ast_get_chan_features_pickup_config(session->channel);</span><br><span>       if (!pickup_cfg) {</span><br><span style="color: hsl(0, 100%, 40%);">-              ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "%s: Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 ast_sip_session_get_name(session));</span><br><span>          pickupexten = "";</span><br><span>  } else {</span><br><span>             pickupexten = ast_strdupa(pickup_cfg->pickupexten);</span><br><span>@@ -3175,7 +3797,8 @@</span><br><span>        */</span><br><span> </span><br><span>      if (invite->session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {</span><br><span style="color: hsl(0, 100%, 40%);">-             ast_log(LOG_ERROR, "Session already DISCONNECTED [reason=%d (%s)]\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "%s: Session already DISCONNECTED [reason=%d (%s)]\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_sip_session_get_name(invite->session),</span><br><span>                        invite->session->inv_session->cause,</span><br><span>                        pjsip_get_status_text(invite->session->inv_session->cause)->ptr);</span><br><span> #ifdef HAVE_PJSIP_INV_SESSION_REF</span><br><span>@@ -3196,8 +3819,8 @@</span><br><span>           }</span><br><span>            goto end;</span><br><span>    case SIP_GET_DEST_EXTEN_PARTIAL:</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_debug(1, "Call from '%s' (%s:%s) to extension '%s' - partial match\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                    ast_sorcery_object_get_id(invite->session->endpoint),</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_debug(3, "%s: Call (%s:%s) to extension '%s' - partial match\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_sip_session_get_name(invite->session),</span><br><span>                        invite->rdata->tp_info.transport->type_name,</span><br><span>                        pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),</span><br><span>                   invite->session->exten);</span><br><span>@@ -3210,8 +3833,8 @@</span><br><span>               goto end;</span><br><span>    case SIP_GET_DEST_EXTEN_NOT_FOUND:</span><br><span>   default:</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_log(LOG_NOTICE, "Call from '%s' (%s:%s) to extension '%s' rejected because extension not found in context '%s'.\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                       ast_sorcery_object_get_id(invite->session->endpoint),</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_log(LOG_NOTICE, "%s: Call (%s:%s) to extension '%s' rejected because extension not found in context '%s'.\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_sip_session_get_name(invite->session),</span><br><span>                        invite->rdata->tp_info.transport->type_name,</span><br><span>                        pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),</span><br><span>                   invite->session->exten,</span><br><span>@@ -3418,9 +4041,8 @@</span><br><span> {</span><br><span>   struct ast_sip_session *session = entry->user_data;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      ast_debug(3, "Endpoint '%s(%s)' re-INVITE collision timer expired.\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_sorcery_object_get_id(session->endpoint),</span><br><span style="color: hsl(0, 100%, 40%);">-                session->channel ? ast_channel_name(session->channel) : "");</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_debug(3, "%s: re-INVITE collision timer expired.\n",</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_sip_session_get_name(session));</span><br><span> </span><br><span>      if (AST_LIST_EMPTY(&session->delayed_requests)) {</span><br><span>             /* No delayed request pending, so just return */</span><br><span>@@ -3440,18 +4062,36 @@</span><br><span> {</span><br><span>      pjsip_inv_session *inv = session->inv_session;</span><br><span>    pj_time_val tv;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_sip_session_media_state *pending_media_state;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_sip_session_media_state *active_media_state;</span><br><span style="color: hsl(120, 100%, 40%);">+       const char *session_name = ast_sip_session_get_name(session);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       ast_debug(3, "Endpoint '%s(%s)' re-INVITE collision.\n",</span><br><span style="color: hsl(0, 100%, 40%);">-              ast_sorcery_object_get_id(session->endpoint),</span><br><span style="color: hsl(0, 100%, 40%);">-                session->channel ? ast_channel_name(session->channel) : "");</span><br><span style="color: hsl(0, 100%, 40%);">-    if (delay_request(session, NULL, NULL, on_response, 1, DELAYED_METHOD_INVITE, NULL)) {</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_debug(3, "%s re-INVITE collision.\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  pending_media_state = ast_sip_session_media_state_clone(session->pending_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!pending_media_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_log(LOG_ERROR, "%s: Failed to clone pending media state\n", session_name);</span><br><span>             return;</span><br><span>      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   active_media_state = ast_sip_session_media_state_clone(session->active_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!active_media_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_sip_session_media_state_free(pending_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_log(LOG_ERROR, "%s: Failed to clone active media state\n", session_name);</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%);">+   if (delay_request(session, NULL, NULL, on_response, 1, DELAYED_METHOD_INVITE, pending_media_state,</span><br><span style="color: hsl(120, 100%, 40%);">+            active_media_state, 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_sip_session_media_state_free(pending_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_sip_session_media_state_free(active_media_state);</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_log(LOG_ERROR, "%s: Failed to add delayed request\n", session_name);</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>  if (pj_timer_entry_running(&session->rescheduled_reinvite)) {</span><br><span>                 /* Timer already running.  Something weird is going on. */</span><br><span style="color: hsl(0, 100%, 40%);">-              ast_debug(1, "Endpoint '%s(%s)' re-INVITE collision while timer running!!!\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                        ast_sorcery_object_get_id(session->endpoint),</span><br><span style="color: hsl(0, 100%, 40%);">-                        session->channel ? ast_channel_name(session->channel) : "");</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_log(LOG_ERROR, "%s: re-INVITE collision while timer running!!!\n", session_name);</span><br><span>              return;</span><br><span>      }</span><br><span> </span><br><span>@@ -3467,6 +4107,7 @@</span><br><span>        if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(),</span><br><span>                 &session->rescheduled_reinvite, &tv) != PJ_SUCCESS) {</span><br><span>             ao2_ref(session, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_log(LOG_ERROR, "%s: Couldn't schedule timer\n", session_name);</span><br><span>     }</span><br><span> }</span><br><span> </span><br><span>@@ -3576,8 +4217,8 @@</span><br><span>   struct ast_sip_session_supplement *supplement;</span><br><span>       struct pjsip_status_line status = rdata->msg_info.msg->line.status;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ast_debug(3, "Response is %d %.*s\n", status.code, (int) pj_strlen(&status.reason),</span><br><span style="color: hsl(0, 100%, 40%);">-                       pj_strbuf(&status.reason));</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_debug(3, "%s: Response is %d %.*s\n", ast_sip_session_get_name(session),</span><br><span style="color: hsl(120, 100%, 40%);">+                status.code, (int) pj_strlen(&status.reason), pj_strbuf(&status.reason));</span><br><span> </span><br><span>        AST_LIST_TRAVERSE(&session->supplements, supplement, next) {</span><br><span>          if (!(supplement->response_priority & response_priority)) {</span><br><span>@@ -3592,7 +4233,7 @@</span><br><span> static int handle_incoming(struct ast_sip_session *session, pjsip_rx_data *rdata,</span><br><span>              enum ast_sip_session_response_priority response_priority)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  ast_debug(3, "Received %s\n", rdata->msg_info.msg->type == PJSIP_REQUEST_MSG ?</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_debug(3, "%s: Received %s\n", ast_sip_session_get_name(session), rdata->msg_info.msg->type == PJSIP_REQUEST_MSG ?</span><br><span>                        "request" : "response");</span><br><span> </span><br><span>     if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {</span><br><span>@@ -3609,7 +4250,8 @@</span><br><span>  struct ast_sip_session_supplement *supplement;</span><br><span>       struct pjsip_request_line req = tdata->msg->line.req;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ast_debug(3, "Method is %.*s\n", (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name));</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_debug(3, "%s: Method is %.*s\n", ast_sip_session_get_name(session),</span><br><span style="color: hsl(120, 100%, 40%);">+             (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name));</span><br><span>     AST_LIST_TRAVERSE(&session->supplements, supplement, next) {</span><br><span>          if (supplement->outgoing_request && does_method_match(&req.method.name, supplement->method)) {</span><br><span>                     supplement->outgoing_request(session, tdata);</span><br><span>@@ -3624,11 +4266,13 @@</span><br><span>   pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);</span><br><span> </span><br><span>    if (!cseq) {</span><br><span style="color: hsl(0, 100%, 40%);">-            ast_log(LOG_ERROR, "Cannot send response due to missing sequence header");</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_log(LOG_ERROR, "%s: Cannot send response due to missing sequence header",</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_sip_session_get_name(session));</span><br><span>          return;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ast_debug(3, "Method is %.*s, Response is %d %.*s\n", (int) pj_strlen(&cseq->method.name),</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_debug(3, "%s: Method is %.*s, Response is %d %.*s\n", ast_sip_session_get_name(session),</span><br><span style="color: hsl(120, 100%, 40%);">+                (int) pj_strlen(&cseq->method.name),</span><br><span>          pj_strbuf(&cseq->method.name), status.code, (int) pj_strlen(&status.reason),</span><br><span>              pj_strbuf(&status.reason));</span><br><span> </span><br><span>@@ -3716,9 +4360,8 @@</span><br><span>           * SDP answer.</span><br><span>                */</span><br><span>          ast_debug(1,</span><br><span style="color: hsl(0, 100%, 40%);">-                    "Endpoint '%s(%s)': Ending session due to incomplete SDP negotiation.  %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                 ast_sorcery_object_get_id(session->endpoint),</span><br><span style="color: hsl(0, 100%, 40%);">-                        session->channel ? ast_channel_name(session->channel) : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                   "%s: Ending session due to incomplete SDP negotiation.  %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_sip_session_get_name(session),</span><br><span>                   pjsip_rx_data_get_info(rdata));</span><br><span>              if (pjsip_inv_end_session(inv, 400, NULL, &tdata) == PJ_SUCCESS</span><br><span>                  && tdata) {</span><br><span>@@ -3755,7 +4398,8 @@</span><br><span>          handle_incoming_before_media(inv, session, e->body.rx_msg.rdata);</span><br><span>                 break;</span><br><span>       case PJSIP_EVENT_TSX_STATE:</span><br><span style="color: hsl(0, 100%, 40%);">-             ast_debug(3, "Source of transaction state change is %s\n", pjsip_event_str(e->body.tsx_state.type));</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_debug(3, "%s: Source of transaction state change is %s\n", ast_sip_session_get_name(session),</span><br><span style="color: hsl(120, 100%, 40%);">+                   pjsip_event_str(e->body.tsx_state.type));</span><br><span>                 /* Transaction state changes are prompted by some other underlying event. */</span><br><span>                 switch(e->body.tsx_state.type) {</span><br><span>          case PJSIP_EVENT_TX_MSG:</span><br><span>@@ -3791,7 +4435,7 @@</span><br><span> </span><br><span>         if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {</span><br><span>                 if (session->defer_end) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    ast_debug(3, "Deferring session (%p) end\n", session);</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_debug(3, "%s: Deferring session end\n", ast_sip_session_get_name(session));</span><br><span>                    session->ended_while_deferred = 1;</span><br><span>                        return;</span><br><span>              }</span><br><span>@@ -3897,7 +4541,8 @@</span><br><span>                                            return;</span><br><span>                                      }</span><br><span>                                    if (inv->state == PJSIP_INV_STATE_CONFIRMED) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                               ast_debug(1, "reINVITE received final response code %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                          ast_debug(1, "%s: reINVITE received final response code %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                                      ast_sip_session_get_name(session),</span><br><span>                                                   tsx->status_code);</span><br><span>                                                if ((tsx->status_code == 401 || tsx->status_code == 407)</span><br><span>                                                       && !ast_sip_create_request_with_auth(</span><br><span>@@ -3950,15 +4595,13 @@</span><br><span>                                                      pjsip_rx_data_get_info(e->body.tsx_state.src.rdata),</span><br><span>                                                      sdp_negotiation_done ? "complete" : "incomplete");</span><br><span>                                               if (!sdp_negotiation_done) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                                    ast_debug(1, "Endpoint '%s(%s)': Incomplete SDP negotiation cancelled session.  %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                                                ast_sorcery_object_get_id(session->endpoint),</span><br><span style="color: hsl(0, 100%, 40%);">-                                                                session->channel ? ast_channel_name(session->channel) : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   ast_debug(1, "%s: Incomplete SDP negotiation cancelled session.  %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                                             ast_sip_session_get_name(session),</span><br><span>                                                           pjsip_rx_data_get_info(e->body.tsx_state.src.rdata));</span><br><span>                                             } else if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS</span><br><span>                                                   && tdata) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                                     ast_debug(1, "Endpoint '%s(%s)': Ending session due to RFC5407 race condition.  %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                                                ast_sorcery_object_get_id(session->endpoint),</span><br><span style="color: hsl(0, 100%, 40%);">-                                                                session->channel ? ast_channel_name(session->channel) : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   ast_debug(1, "%s: Ending session due to RFC5407 race condition.  %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                                             ast_sip_session_get_name(session),</span><br><span>                                                           pjsip_rx_data_get_info(e->body.tsx_state.src.rdata));</span><br><span>                                                     ast_sip_session_send_request(session, tdata);</span><br><span>                                                }</span><br><span>@@ -3970,7 +4613,8 @@</span><br><span>                    if (tsx->role == PJSIP_ROLE_UAC) {</span><br><span>                                if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {</span><br><span>                                    /* This means we got a final response to our outgoing method */</span><br><span style="color: hsl(0, 100%, 40%);">-                                 ast_debug(1, "%.*s received final response code %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ast_debug(1, "%s: %.*s received final response code %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                          ast_sip_session_get_name(session),</span><br><span>                                           (int) pj_strlen(&tsx->method.name), pj_strbuf(&tsx->method.name),</span><br><span>                                              tsx->status_code);</span><br><span>                                        if ((tsx->status_code == 401 || tsx->status_code == 407)</span><br><span>@@ -4012,9 +4656,8 @@</span><br><span> </span><br><span>   if (tsx->method.id == PJSIP_INVITE_METHOD) {</span><br><span>              if (tsx->state == PJSIP_TSX_STATE_PROCEEDING) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      ast_debug(3, "Endpoint '%s(%s)' INVITE delay check. tsx-state:%s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                          ast_sorcery_object_get_id(session->endpoint),</span><br><span style="color: hsl(0, 100%, 40%);">-                                session->channel ? ast_channel_name(session->channel) : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_debug(3, "%s: INVITE delay check. tsx-state:%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                              ast_sip_session_get_name(session),</span><br><span>                           pjsip_tsx_state_str(tsx->state));</span><br><span>                         check_delayed_requests(session, invite_proceeding);</span><br><span>          } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {</span><br><span>@@ -4023,18 +4666,16 @@</span><br><span>                   * queuing delayed requests, no matter what event caused</span><br><span>                      * the transaction to terminate.</span><br><span>                      */</span><br><span style="color: hsl(0, 100%, 40%);">-                     ast_debug(3, "Endpoint '%s(%s)' INVITE delay check. tsx-state:%s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                          ast_sorcery_object_get_id(session->endpoint),</span><br><span style="color: hsl(0, 100%, 40%);">-                                session->channel ? ast_channel_name(session->channel) : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_debug(3, "%s: INVITE delay check. tsx-state:%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                              ast_sip_session_get_name(session),</span><br><span>                           pjsip_tsx_state_str(tsx->state));</span><br><span>                         check_delayed_requests(session, invite_terminated);</span><br><span>          }</span><br><span>    } else if (tsx->role == PJSIP_ROLE_UAC</span><br><span>            && tsx->state == PJSIP_TSX_STATE_COMPLETED</span><br><span>                && !pj_strcmp2(&tsx->method.name, "UPDATE")) {</span><br><span style="color: hsl(0, 100%, 40%);">-         ast_debug(3, "Endpoint '%s(%s)' UPDATE delay check. tsx-state:%s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                  ast_sorcery_object_get_id(session->endpoint),</span><br><span style="color: hsl(0, 100%, 40%);">-                        session->channel ? ast_channel_name(session->channel) : "",</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_debug(3, "%s: UPDATE delay check. tsx-state:%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_sip_session_get_name(session),</span><br><span>                   pjsip_tsx_state_str(tsx->state));</span><br><span>                 check_delayed_requests(session, update_completed);</span><br><span>   }</span><br><span>@@ -4172,11 +4813,13 @@</span><br><span>  int stream;</span><br><span> </span><br><span>      if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {</span><br><span style="color: hsl(0, 100%, 40%);">-            ast_log(LOG_ERROR, "Failed to create session SDP. Session has been already disconnected\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_log(LOG_ERROR, "%s: Failed to create session SDP. Session has been already disconnected\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_sip_session_get_name(session));</span><br><span>          return NULL;</span><br><span>         }</span><br><span> </span><br><span>        if (!inv->pool_prov || !(local = PJ_POOL_ZALLOC_T(inv->pool_prov, pjmedia_sdp_session))) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_ERROR, "%s: Pool allocation failure\n", ast_sip_session_get_name(session));</span><br><span>            return NULL;</span><br><span>         }</span><br><span> </span><br><span>@@ -4202,6 +4845,7 @@</span><br><span>                        session->pending_media_state->topology = ast_stream_topology_clone(session->endpoint->media.topology);</span><br><span>           }</span><br><span>            if (!session->pending_media_state->topology) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_log(LOG_ERROR, "%s: No pending media state topology\n", ast_sip_session_get_name(session));</span><br><span>                    return NULL;</span><br><span>                 }</span><br><span>    }</span><br><span>@@ -4219,10 +4863,12 @@</span><br><span> </span><br><span>              session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_stream_get_type(stream), i);</span><br><span>           if (!session_media) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 ast_log(LOG_ERROR, "%s: Couldn't alloc/add session media\n", ast_sip_session_get_name(session));</span><br><span>                       return NULL;</span><br><span>                 }</span><br><span> </span><br><span>                if (add_sdp_streams(session_media, session, local, offer, stream)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_log(LOG_ERROR, "%s: Couldn't add sdp streams\n", ast_sip_session_get_name(session));</span><br><span>                       return NULL;</span><br><span>                 }</span><br><span> </span><br><span>@@ -4353,18 +4999,18 @@</span><br><span> </span><br><span>          if (inv->following_fork) {</span><br><span>                        if (session->endpoint->media.rtp.follow_early_media_fork) {</span><br><span style="color: hsl(0, 100%, 40%);">-                               ast_debug(3, "Following early media fork with different To tags\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                                ast_debug(3, "%s: Following early media fork with different To tags\n", ast_sip_session_get_name(session));</span><br><span>                        } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                                ast_debug(3, "Not following early media fork with different To tags\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                            ast_debug(3, "%s: Not following early media fork with different To tags\n", ast_sip_session_get_name(session));</span><br><span>                            bail = 1;</span><br><span>                    }</span><br><span>            }</span><br><span> #ifdef HAVE_PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS</span><br><span>               else if (inv->updated_sdp_answer) {</span><br><span>                       if (session->endpoint->media.rtp.accept_multiple_sdp_answers) {</span><br><span style="color: hsl(0, 100%, 40%);">-                           ast_debug(3, "Accepting updated SDP with same To tag\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                           ast_debug(3, "%s: Accepting updated SDP with same To tag\n", ast_sip_session_get_name(session));</span><br><span>                   } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                                ast_debug(3, "Ignoring updated SDP answer with same To tag\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                             ast_debug(3, "%s: Ignoring updated SDP answer with same To tag\n", ast_sip_session_get_name(session));</span><br><span>                             bail = 1;</span><br><span>                    }</span><br><span>            }</span><br><span>@@ -4454,6 +5100,8 @@</span><br><span>    struct ast_sip_nat_hook *hook = ast_sip_mod_data_get(</span><br><span>                tdata->mod_data, session_module.id, MOD_DATA_NAT_HOOK);</span><br><span>   struct pjmedia_sdp_session *sdp;</span><br><span style="color: hsl(120, 100%, 40%);">+      pjsip_dialog *dlg = pjsip_tdata_get_dlg(tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_sip_session *session = dlg ? ast_sip_dialog_get_session(dlg) : NULL;</span><br><span>      int stream;</span><br><span> </span><br><span>      /* SDP produced by us directly will never be multipart */</span><br><span>@@ -4477,7 +5125,8 @@</span><br><span>             * outgoing session IP is local. If it is, we'll do</span><br><span>               * rewriting. No localnet configured? Always rewrite. */</span><br><span>             if (ast_sip_transport_is_local(transport_state, &our_sdp_addr) || !transport_state->localnet) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  ast_debug(5, "Setting external media address to %s\n", ast_sockaddr_stringify_host(&transport_state->external_media_address));</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_debug(5, "%s: Setting external media address to %s\n", ast_sip_session_get_name(session),</span><br><span style="color: hsl(120, 100%, 40%);">+                               ast_sockaddr_stringify_host(&transport_state->external_media_address));</span><br><span>                       pj_strdup2(tdata->pool, &sdp->conn->addr, ast_sockaddr_stringify_host(&transport_state->external_media_address));</span><br><span>                        pj_strassign(&sdp->origin.addr, &sdp->conn->addr);</span><br><span>          }</span><br><span>@@ -4494,7 +5143,8 @@</span><br><span> </span><br><span>                handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);</span><br><span>               if (!handler_list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_debug(4, "%s: No registered SDP handlers for media type '%s'\n",  ast_sip_session_get_name(session),</span><br><span style="color: hsl(120, 100%, 40%);">+                            media);</span><br><span>                      continue;</span><br><span>            }</span><br><span>            AST_LIST_TRAVERSE(&handler_list->list, handler, next) {</span><br><span>@@ -4508,6 +5158,558 @@</span><br><span>     ast_sip_mod_data_set(tdata->pool, tdata->mod_data, session_module.id, MOD_DATA_NAT_HOOK, nat_hook);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef TEST_FRAMEWORK</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_stream *test_stream_alloc(const char *name, enum ast_media_type type, enum ast_stream_state state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_stream *stream;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  stream = ast_stream_alloc(name, type);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!stream) {</span><br><span style="color: hsl(120, 100%, 40%);">+                return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_stream_set_state(stream, state);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return stream;</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%);">+static struct ast_sip_session_media *test_media_add(</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_sip_session_media_state *media_state, const char *name, enum ast_media_type type,</span><br><span style="color: hsl(120, 100%, 40%);">+  enum ast_stream_state state, int position)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_session_media *session_media = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_stream *stream = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   stream = test_stream_alloc(name, type, state);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!stream) {</span><br><span style="color: hsl(120, 100%, 40%);">+                return NULL;</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%);">+   if (position >= 0 && position < ast_stream_topology_get_count(media_state->topology)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_stream_topology_set_stream(media_state->topology, position, stream);</span><br><span style="color: hsl(120, 100%, 40%);">+   } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              position = ast_stream_topology_append_stream(media_state->topology, stream);</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%);">+   session_media = ao2_alloc_options(sizeof(*session_media), session_media_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!session_media) {</span><br><span style="color: hsl(120, 100%, 40%);">+         return NULL;</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%);">+   session_media->keepalive_sched_id = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    session_media->timeout_sched_id = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+      session_media->type = type;</span><br><span style="color: hsl(120, 100%, 40%);">+        session_media->stream_num = position;</span><br><span style="color: hsl(120, 100%, 40%);">+      session_media->bundle_group = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+  strcpy(session_media->label, name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (AST_VECTOR_REPLACE(&media_state->sessions, position, session_media)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             ao2_ref(session_media, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         return NULL;</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%);">+   /* If this stream will be active in some way and it is the first of this type then consider this the default media session to match */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!media_state->default_session[type] && ast_stream_get_state(ast_stream_topology_get_stream(media_state->topology, position)) != AST_STREAM_STATE_REMOVED) {</span><br><span style="color: hsl(120, 100%, 40%);">+         media_state->default_session[type] = session_media;</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%);">+   return session_media;</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%);">+static int test_is_media_session_equal(struct ast_sip_session_media *left, struct ast_sip_session_media *right)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (left == right) {</span><br><span style="color: hsl(120, 100%, 40%);">+          return 1;</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%);">+   if (!left) {</span><br><span style="color: hsl(120, 100%, 40%);">+          return 1;</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%);">+   if (!right) {</span><br><span style="color: hsl(120, 100%, 40%);">+         return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return memcmp(left, right, sizeof(*left)) == 0;</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%);">+static int test_is_media_state_equal(struct ast_sip_session_media_state *left, struct ast_sip_session_media_state *right,</span><br><span style="color: hsl(120, 100%, 40%);">+       int assert_on_failure)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        SCOPE_ENTER(2);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (left == right) {</span><br><span style="color: hsl(120, 100%, 40%);">+          SCOPE_EXIT_RTN_VALUE(1, "equal\n");</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%);">+   if (!(left && right)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_assert(!assert_on_failure);</span><br><span style="color: hsl(120, 100%, 40%);">+               SCOPE_EXIT_RTN_VALUE(0, "one is null: left: %p  right: %p\n", left, right);</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%);">+   if (!ast_stream_topology_equal(left->topology, right->topology)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_assert(!assert_on_failure);</span><br><span style="color: hsl(120, 100%, 40%);">+               SCOPE_EXIT_RTN_VALUE(0, "topologies differ\n");</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (AST_VECTOR_SIZE(&left->sessions) != AST_VECTOR_SIZE(&right->sessions)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_assert(!assert_on_failure);</span><br><span style="color: hsl(120, 100%, 40%);">+               SCOPE_EXIT_RTN_VALUE(0, "session vector sizes different: left %lu != right %lu\n", AST_VECTOR_SIZE(&left->sessions),</span><br><span style="color: hsl(120, 100%, 40%);">+                 AST_VECTOR_SIZE(&right->sessions));</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (AST_VECTOR_SIZE(&left->read_callbacks) != AST_VECTOR_SIZE(&right->read_callbacks)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_assert(!assert_on_failure);</span><br><span style="color: hsl(120, 100%, 40%);">+               SCOPE_EXIT_RTN_VALUE(0, "read_callback vector sizes different: left %lu != right %lu\n", AST_VECTOR_SIZE(&left->read_callbacks),</span><br><span style="color: hsl(120, 100%, 40%);">+                     AST_VECTOR_SIZE(&right->read_callbacks));</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%);">+   for (i = 0; i < AST_VECTOR_SIZE(&left->sessions) ; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!test_is_media_session_equal(AST_VECTOR_GET(&left->sessions, i), AST_VECTOR_GET(&right->sessions, i))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_assert(!assert_on_failure);</span><br><span style="color: hsl(120, 100%, 40%);">+                       SCOPE_EXIT_RTN_VALUE(0, "Media session %d different\n", i);</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%);">+   for (i = 0; i < AST_VECTOR_SIZE(&left->read_callbacks) ; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (memcmp(AST_VECTOR_GET_ADDR(&left->read_callbacks, i),</span><br><span style="color: hsl(120, 100%, 40%);">+                              AST_VECTOR_GET_ADDR(&right->read_callbacks, i),</span><br><span style="color: hsl(120, 100%, 40%);">+                                sizeof(struct ast_sip_session_media_read_callback_state)) != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_assert(!assert_on_failure);</span><br><span style="color: hsl(120, 100%, 40%);">+                       SCOPE_EXIT_RTN_VALUE(0, "read_callback %d different\n", i);</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%);">+   for (i = 0; i < AST_MEDIA_TYPE_END; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!(left->default_session[i] && right->default_session[i])) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!left->default_session[i] || !right->default_session[i]</span><br><span style="color: hsl(120, 100%, 40%);">+                     || left->default_session[i]->stream_num != right->default_session[i]->stream_num) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_assert(!assert_on_failure);</span><br><span style="color: hsl(120, 100%, 40%);">+                       SCOPE_EXIT_RTN_VALUE(0, "Default media session %d different.  Left: %s  Right: %s\n", i,</span><br><span style="color: hsl(120, 100%, 40%);">+                            left->default_session[i] ? left->default_session[i]->label : "null",</span><br><span style="color: hsl(120, 100%, 40%);">+                               right->default_session[i] ? right->default_session[i]->label : "null");</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%);">+   SCOPE_EXIT_RTN_VALUE(1, "equal\n");</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_TEST_DEFINE(test_merge_refresh_media_states)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+#define FREE_STATE() \</span><br><span style="color: hsl(120, 100%, 40%);">+({ \</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_session_media_state_free(new_pending_state); \</span><br><span style="color: hsl(120, 100%, 40%);">+        new_pending_state = NULL; \</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_sip_session_media_state_free(delayed_pending_state); \</span><br><span style="color: hsl(120, 100%, 40%);">+    delayed_pending_state = NULL; \</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_sip_session_media_state_free(delayed_active_state); \</span><br><span style="color: hsl(120, 100%, 40%);">+     delayed_active_state = NULL; \</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_sip_session_media_state_free(current_active_state); \</span><br><span style="color: hsl(120, 100%, 40%);">+     current_active_state = NULL; \</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_sip_session_media_state_free(expected_pending_state); \</span><br><span style="color: hsl(120, 100%, 40%);">+   expected_pending_state = NULL; \</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%);">+#define RESET_STATE(__num) \</span><br><span style="color: hsl(120, 100%, 40%);">+({ \</span><br><span style="color: hsl(120, 100%, 40%);">+    testnum=__num; \</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_trace(__num, "Test %d\n", testnum); \</span><br><span style="color: hsl(120, 100%, 40%);">+   test_failed = 0; \</span><br><span style="color: hsl(120, 100%, 40%);">+    delayed_pending_state = ast_sip_session_media_state_alloc(); \</span><br><span style="color: hsl(120, 100%, 40%);">+        delayed_pending_state->topology = ast_stream_topology_alloc(); \</span><br><span style="color: hsl(120, 100%, 40%);">+   delayed_active_state = ast_sip_session_media_state_alloc(); \</span><br><span style="color: hsl(120, 100%, 40%);">+ delayed_active_state->topology = ast_stream_topology_alloc(); \</span><br><span style="color: hsl(120, 100%, 40%);">+    current_active_state = ast_sip_session_media_state_alloc(); \</span><br><span style="color: hsl(120, 100%, 40%);">+ current_active_state->topology = ast_stream_topology_alloc(); \</span><br><span style="color: hsl(120, 100%, 40%);">+    expected_pending_state = ast_sip_session_media_state_alloc(); \</span><br><span style="color: hsl(120, 100%, 40%);">+       expected_pending_state->topology = ast_stream_topology_alloc(); \</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%);">+#define CHECKER() \</span><br><span style="color: hsl(120, 100%, 40%);">+({ \</span><br><span style="color: hsl(120, 100%, 40%);">+ new_pending_state = merge_refresh_media_states("unittest", delayed_pending_state, delayed_active_state, current_active_state, 1); \</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!test_is_media_state_equal(new_pending_state, expected_pending_state, 0)) { \</span><br><span style="color: hsl(120, 100%, 40%);">+             res = AST_TEST_FAIL; \</span><br><span style="color: hsl(120, 100%, 40%);">+                test_failed = 1; \</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_test_status_update(test, "da: %s\n", ast_str_tmp(256, ast_stream_topology_to_str(delayed_active_state->topology, &STR_TMP))); \</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_test_status_update(test, "dp: %s\n", ast_str_tmp(256, ast_stream_topology_to_str(delayed_pending_state->topology, &STR_TMP))); \</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_test_status_update(test, "ca: %s\n", ast_str_tmp(256, ast_stream_topology_to_str(current_active_state->topology, &STR_TMP))); \</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_test_status_update(test, "ep: %s\n", ast_str_tmp(256, ast_stream_topology_to_str(expected_pending_state->topology, &STR_TMP))); \</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_test_status_update(test, "np: %s\n", ast_str_tmp(256, ast_stream_topology_to_str(new_pending_state->topology, &STR_TMP))); \</span><br><span style="color: hsl(120, 100%, 40%);">+     } \</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_test_status_update(test, "Test %d %s\n", testnum, test_failed ? "FAILED" : "passed"); \</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_trace(1, "Test %d %s\n", testnum, test_failed ? "FAILED" : "passed"); \</span><br><span style="color: hsl(120, 100%, 40%);">+     test_failed = 0; \</span><br><span style="color: hsl(120, 100%, 40%);">+    FREE_STATE(); \</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%);">+       struct ast_sip_session_media_state * delayed_pending_state = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_sip_session_media_state * delayed_active_state = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_sip_session_media_state * current_active_state = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_sip_session_media_state * new_pending_state = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_sip_session_media_state * expected_pending_state = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ enum ast_test_result_state res = AST_TEST_PASS;</span><br><span style="color: hsl(120, 100%, 40%);">+       int test_failed = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  int testnum = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case TEST_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+               info->name = "merge_refresh_topologies";</span><br><span style="color: hsl(120, 100%, 40%);">+         info->category = "/res/res_pjsip_session/";</span><br><span style="color: hsl(120, 100%, 40%);">+              info->summary = "Test merging of delayed request topologies";</span><br><span style="color: hsl(120, 100%, 40%);">+            info->description = "Test merging of delayed request topologies";</span><br><span style="color: hsl(120, 100%, 40%);">+                return AST_TEST_NOT_RUN;</span><br><span style="color: hsl(120, 100%, 40%);">+      case TEST_EXECUTE:</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</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%);">+   RESET_STATE(1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECKER();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  RESET_STATE(2);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECKER();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  RESET_STATE(3);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "myvideo5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECKER();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  RESET_STATE(4);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECKER();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  RESET_STATE(5);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECKER();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  RESET_STATE(6);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(current_active_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECKER();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  RESET_STATE(7);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "myvideo5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "myvideo6", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo6", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECKER();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  RESET_STATE(8);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECKER();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  RESET_STATE(9);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECKER();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  RESET_STATE(10);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECKER();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  RESET_STATE(11);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_active_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECKER();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  RESET_STATE(12);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "292-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "296-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "292-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "296-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "297-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "294-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "292-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "296-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "290-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "297-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "292-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "296-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "290-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "297-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "294-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       CHECKER();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  RESET_STATE(13);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "293-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "292-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "294-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "295-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "296-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "293-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "292-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "294-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "295-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "296-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "298-7", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "293-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "292-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "294-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "295-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "296-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "290-6", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "293-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "292-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "294-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "295-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "296-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "290-6", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "298-7", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       CHECKER();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  RESET_STATE(14);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "297-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "294-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "295-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "297-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "291-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "294-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "297-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "291-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "294-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "295-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       CHECKER();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  RESET_STATE(15);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(delayed_active_state, "297-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDONLY, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "294-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_media_add(delayed_pending_state, "295-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "297-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "291-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "294-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ test_media_add(current_active_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "297-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "291-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "294-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDONLY, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       test_media_add(expected_pending_state, "295-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       CHECKER();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return res;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif /* TEST_FRAMEWORK */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int load_module(void)</span><br><span> {</span><br><span>         pjsip_endpoint *endpt;</span><br><span>@@ -4536,12 +5738,18 @@</span><br><span>     ast_sip_register_service(&outbound_invite_auth_module);</span><br><span> </span><br><span>      ast_module_shutdown_ref(ast_module_info->self);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef TEST_FRAMEWORK</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_TEST_REGISTER(test_merge_refresh_media_states);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>  return AST_MODULE_LOAD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span> static int unload_module(void)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef TEST_FRAMEWORK</span><br><span style="color: hsl(120, 100%, 40%);">+        AST_TEST_UNREGISTER(test_merge_refresh_media_states);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      ast_sip_unregister_service(&outbound_invite_auth_module);</span><br><span>        ast_sip_unregister_service(&session_reinvite_module);</span><br><span>    ast_sip_unregister_service(&session_module);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/14730">change 14730</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/+/14730"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: certified/16.8 </div>
<div style="display:none"> Gerrit-Change-Id: Id3440972943c611a15f652c6c569fa0e4536bfcb </div>
<div style="display:none"> Gerrit-Change-Number: 14730 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>