<p>George Joseph has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/14688">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">ACN: Changes specific to the core<br><br>Allow passing a topology from the called channel back to the<br>calling channel.<br><br> * Added a new function ast_queue_answer() that accepts a stream<br>   topology and queues an ANSWER CONTROL frame with it as the<br>   data.  This allows the called channel to indicate its resolved<br>   topology.<br><br> * Added a new virtual function to the channel tech structure<br>   answer_with_stream_topology() that allows the calling channel<br>   to receive the called channel's topology.  Added<br>   ast_raw_answer_with_stream_topology() that invokes that virtual<br>   function.<br><br> * Modified app_dial.c and features.c to grab the topology from the<br>   ANSWER frame queued by the answering channel and send it to<br>   the calling channel with ast_raw_answer_with_stream_topology().<br><br> * Modified frame.c to automatically cleanup the reference<br>   to the topology on ANSWER frames.<br><br>Added a few debugging messages to stream.c.<br><br>Change-Id: I0115d2ed68d6bae0f87e85abcf16c771bdaf992c<br>---<br>M apps/app_dial.c<br>M include/asterisk/channel.h<br>M main/channel.c<br>M main/features.c<br>M main/frame.c<br>M main/stream.c<br>6 files changed, 179 insertions(+), 7 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/88/14688/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/apps/app_dial.c b/apps/app_dial.c</span><br><span>index 95f36d7..54a59d1 100644</span><br><span>--- a/apps/app_dial.c</span><br><span>+++ b/apps/app_dial.c</span><br><span>@@ -1204,7 +1204,8 @@</span><br><span>      struct privacy_args *pa,</span><br><span>     const struct cause_args *num_in, int *result, char *dtmf_progress,</span><br><span>   const int ignore_cc,</span><br><span style="color: hsl(0, 100%, 40%);">-    struct ast_party_id *forced_clid, struct ast_party_id *stored_clid)</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_party_id *forced_clid, struct ast_party_id *stored_clid,</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_bridge_config *config)</span><br><span> {</span><br><span>       struct cause_args num = *num_in;</span><br><span>     int prestart = num.busy + num.congestion + num.nochan;</span><br><span>@@ -1418,6 +1419,18 @@</span><br><span>                                                      }</span><br><span>                                            }</span><br><span>                                            peer = c;</span><br><span style="color: hsl(120, 100%, 40%);">+                                             if (f->data.ptr != NULL && f->datalen == sizeof(struct ast_stream_topology *)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                                        config->peer_topology = *((struct ast_stream_topology **)f->data.ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+                                                  /*</span><br><span style="color: hsl(120, 100%, 40%);">+                                                     * We need to bump the refcount on the topology to prevent it</span><br><span style="color: hsl(120, 100%, 40%);">+                                                  * from being cleaned up when the frame is cleaned up.</span><br><span style="color: hsl(120, 100%, 40%);">+                                                         */</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   ao2_bump(config->peer_topology);</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   ast_trace(2, "%s Found topology in frame: %p %p %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                                              ast_channel_name(peer), f->data.ptr, config->peer_topology,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                             ast_str_tmp(256, ast_stream_topology_to_str(config->peer_topology, &STR_TMP)));</span><br><span style="color: hsl(120, 100%, 40%);">+                                                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                                          /* Inform everyone else that they've been canceled.</span><br><span>                                               * The dial end event for the peer will be sent out after</span><br><span>                                             * other Dial options have been handled.</span><br><span>@@ -2838,7 +2851,7 @@</span><br><span>     }</span><br><span> </span><br><span>        peer = wait_for_answer(chan, &out_chans, &to, peerflags, opt_args, &pa, &num, &result,</span><br><span style="color: hsl(0, 100%, 40%);">-              dtmf_progress, ignore_cc, &forced_clid, &stored_clid);</span><br><span style="color: hsl(120, 100%, 40%);">+                dtmf_progress, ignore_cc, &forced_clid, &stored_clid, &config);</span><br><span> </span><br><span>      if (!peer) {</span><br><span>                 if (result) {</span><br><span>@@ -3267,6 +3280,7 @@</span><br><span>                                ast_channel_setoption(chan, AST_OPTION_OPRMODE, &oprmode, sizeof(oprmode), 0);</span><br><span>                   }</span><br><span>                    setup_peer_after_bridge_goto(chan, peer, &opts, opt_args);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                     res = ast_bridge_call(chan, peer, &config);</span><br><span>              }</span><br><span>    }</span><br><span>@@ -3304,6 +3318,18 @@</span><br><span>   }</span><br><span> </span><br><span> done:</span><br><span style="color: hsl(120, 100%, 40%);">+        if (config.peer_topology) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_trace(2, "%s Cleaning up topology: %p %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_channel_name(peer), &config.peer_topology,</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_str_tmp(256, ast_stream_topology_to_str(config.peer_topology, &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%);">+             * At this point, the channel driver that answered should have bumped the</span><br><span style="color: hsl(120, 100%, 40%);">+              * topology refcount for itself.  Here we're cleaning up the reference we added</span><br><span style="color: hsl(120, 100%, 40%);">+            * in wait_for_answer().</span><br><span style="color: hsl(120, 100%, 40%);">+               */</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_stream_topology_free(config.peer_topology);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span>    if (config.warning_sound) {</span><br><span>          ast_free((char *)config.warning_sound);</span><br><span>      }</span><br><span>diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h</span><br><span>index cc90c83..e150215 100644</span><br><span>--- a/include/asterisk/channel.h</span><br><span>+++ b/include/asterisk/channel.h</span><br><span>@@ -708,6 +708,19 @@</span><br><span>        int (* const answer)(struct ast_channel *chan);</span><br><span> </span><br><span>  /*!</span><br><span style="color: hsl(120, 100%, 40%);">+    * \brief Answer the channel with topology</span><br><span style="color: hsl(120, 100%, 40%);">+     * \since 18</span><br><span style="color: hsl(120, 100%, 40%);">+   *</span><br><span style="color: hsl(120, 100%, 40%);">+     * \param chan The channel to answer</span><br><span style="color: hsl(120, 100%, 40%);">+   * \param topology The topology to use, probably the peer's.</span><br><span style="color: hsl(120, 100%, 40%);">+       *</span><br><span style="color: hsl(120, 100%, 40%);">+     * \note The topology may be NULL when the peer doesn't support streams</span><br><span style="color: hsl(120, 100%, 40%);">+    * or, in the case where transcoding is in effect, when this channel should use</span><br><span style="color: hsl(120, 100%, 40%);">+        * its existing topology.</span><br><span style="color: hsl(120, 100%, 40%);">+      */</span><br><span style="color: hsl(120, 100%, 40%);">+   int (* const answer_with_stream_topology)(struct ast_channel *chan, struct ast_stream_topology *topology);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /*!</span><br><span>   * \brief Read a frame (or chain of frames from the same stream), in standard format (see frame.h)</span><br><span>    *</span><br><span>    * \param chan channel to read frames from</span><br><span>@@ -1081,6 +1094,12 @@</span><br><span>   * exist when the end_bridge_callback is called, then it needs to be fixed up properly</span><br><span>        */</span><br><span>  void (*end_bridge_callback_data_fixup)(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator);</span><br><span style="color: hsl(120, 100%, 40%);">+    /*!</span><br><span style="color: hsl(120, 100%, 40%);">+    * When the peer queues an ANSWER control frame, it can indicate it's resolved topology.</span><br><span style="color: hsl(120, 100%, 40%);">+   * If the calling channel implements the answer_with_stream_topology callback, the</span><br><span style="color: hsl(120, 100%, 40%);">+     * peer's topology will be passed to the calling channel.</span><br><span style="color: hsl(120, 100%, 40%);">+  */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_stream_topology *peer_topology;</span><br><span> };</span><br><span> </span><br><span> struct chanmon;</span><br><span>@@ -1379,6 +1398,23 @@</span><br><span>                        const void *data, size_t datalen);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Queue an ANSWER control frame with topology</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param chan channel to queue frame onto</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param topology topology to be passed through the core to the peer channel</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval non-zero failure</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note The channel does not need to be locked before calling this function.</span><br><span style="color: hsl(120, 100%, 40%);">+ * The topology does NOT have it's reference count bumped automatically so</span><br><span style="color: hsl(120, 100%, 40%);">+ * bump it yourself if you need to.</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%);">+/*! \brief Queue an ANSWER control frame with topology */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_queue_answer(struct ast_channel *chan, const struct ast_stream_topology *topology);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Change channel name</span><br><span>  *</span><br><span>  * \pre Absolutely all channels _MUST_ be unlocked before calling this function.</span><br><span>@@ -1802,6 +1838,31 @@</span><br><span> int ast_raw_answer(struct ast_channel *chan);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Answer a channel passing in a stream topology</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 18</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param chan channel to answer</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param topology the peer's stream topology</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This function answers a channel and handles all necessary call</span><br><span style="color: hsl(120, 100%, 40%);">+ * setup functions.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note The channel passed does not need to be locked, but is locked</span><br><span style="color: hsl(120, 100%, 40%);">+ * by the function when needed.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note Unlike ast_answer(), this function will not wait for media</span><br><span style="color: hsl(120, 100%, 40%);">+ * flow to begin. The caller should be careful before sending media</span><br><span style="color: hsl(120, 100%, 40%);">+ * to the channel before incoming media arrives, as the outgoing</span><br><span style="color: hsl(120, 100%, 40%);">+ * media may be lost.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note The topology is usually that of the peer channel and may be NULL.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 on success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval non-zero on failure</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_raw_answer_with_stream_topology(struct ast_channel *chan, struct ast_stream_topology *topology);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Answer a channel, with a selectable delay before returning</span><br><span>  *</span><br><span>  * \param chan channel to answer</span><br><span>@@ -5054,4 +5115,18 @@</span><br><span>  */</span><br><span> void *ast_channel_get_stream_topology_change_source(struct ast_channel *chan);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Checks if a channel's technology implements a particular callback function</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 18</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param chan The channel</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param function The function to look for</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 1 if the channel has a technology set and it implements the function</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 if the channel doesn't have a technology set or it doesn't implement the function</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define ast_channel_has_tech_function(chan, function) \</span><br><span style="color: hsl(120, 100%, 40%);">+    (ast_channel_tech(chan) ? ast_channel_tech(chan)->function != NULL : 0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #endif /* _ASTERISK_CHANNEL_H */</span><br><span>diff --git a/main/channel.c b/main/channel.c</span><br><span>index 8dd008d..bb82ee2 100644</span><br><span>--- a/main/channel.c</span><br><span>+++ b/main/channel.c</span><br><span>@@ -1238,6 +1238,25 @@</span><br><span>     return ast_queue_frame(chan, &f);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Queue an ANSWER control frame with topology */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_queue_answer(struct ast_channel *chan, const struct ast_stream_topology *topology)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_frame f = {</span><br><span style="color: hsl(120, 100%, 40%);">+                AST_FRAME_CONTROL,</span><br><span style="color: hsl(120, 100%, 40%);">+            .subclass.integer = AST_CONTROL_ANSWER,</span><br><span style="color: hsl(120, 100%, 40%);">+               /*</span><br><span style="color: hsl(120, 100%, 40%);">+             * Passing the address of the topology pointer may seem odd but __ast_queue_frame</span><br><span style="color: hsl(120, 100%, 40%);">+              * copies the _contents_ of the address to the data portion of the frame so the pointer</span><br><span style="color: hsl(120, 100%, 40%);">+                * to the topology is what's stored in the data.  Then it sets f->data.ptr to point</span><br><span style="color: hsl(120, 100%, 40%);">+             * to that. When the frame is read, you can get the pointer to the topology like so...</span><br><span style="color: hsl(120, 100%, 40%);">+                 * struct ast_stream_topology *topology = *((struct ast_stream_topology **)f->data.ptr)</span><br><span style="color: hsl(120, 100%, 40%);">+             */</span><br><span style="color: hsl(120, 100%, 40%);">+           .data.ptr = (void *) &topology,</span><br><span style="color: hsl(120, 100%, 40%);">+           .datalen = sizeof(topology)</span><br><span style="color: hsl(120, 100%, 40%);">+   };</span><br><span style="color: hsl(120, 100%, 40%);">+    return ast_queue_frame(chan, &f);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \brief Set defer DTMF flag on channel */</span><br><span> int ast_channel_defer_dtmf(struct ast_channel *chan)</span><br><span> {</span><br><span>@@ -2619,7 +2638,8 @@</span><br><span>      }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-int ast_raw_answer(struct ast_channel *chan)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_raw_answer_with_stream_topology(struct ast_channel *chan, struct ast_stream_topology *topology)</span><br><span> {</span><br><span>       int res = 0;</span><br><span>         SCOPE_TRACE(1, "%s\n", ast_channel_name(chan));</span><br><span>@@ -2650,7 +2670,10 @@</span><br><span>   case AST_STATE_RINGING:</span><br><span>      case AST_STATE_RING:</span><br><span>                 ast_channel_lock(chan);</span><br><span style="color: hsl(0, 100%, 40%);">-         if (ast_channel_tech(chan)->answer) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (ast_channel_tech(chan)->answer_with_stream_topology) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 res = ast_channel_tech(chan)->answer_with_stream_topology(chan, topology);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               } else if (ast_channel_tech(chan)->answer) {</span><br><span>                      res = ast_channel_tech(chan)->answer(chan);</span><br><span>               }</span><br><span>            ast_setstate(chan, AST_STATE_UP);</span><br><span>@@ -2667,6 +2690,11 @@</span><br><span>   return res;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int ast_raw_answer(struct ast_channel *chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return ast_raw_answer_with_stream_topology(chan, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int __ast_answer(struct ast_channel *chan, unsigned int delay)</span><br><span> {</span><br><span>  int res = 0;</span><br><span>diff --git a/main/features.c b/main/features.c</span><br><span>index 51cc3ed..20ed8f4 100644</span><br><span>--- a/main/features.c</span><br><span>+++ b/main/features.c</span><br><span>@@ -76,6 +76,7 @@</span><br><span> #include "asterisk/stasis_channels.h"</span><br><span> #include "asterisk/features_config.h"</span><br><span> #include "asterisk/max_forwards.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/stream.h"</span><br><span> </span><br><span> /*** DOCUMENTATION</span><br><span>    <application name="Bridge" language="en_US"></span><br><span>@@ -558,12 +559,17 @@</span><br><span>       set_config_flags(chan, config);</span><br><span> </span><br><span>  /* Answer if need be */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>   if (ast_channel_state(chan) != AST_STATE_UP) {</span><br><span style="color: hsl(0, 100%, 40%);">-          if (ast_raw_answer(chan)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           res = ast_raw_answer_with_stream_topology(chan, config->peer_topology);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (res != 0) {</span><br><span>                      return -1;</span><br><span>           }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #ifdef FOR_DEBUG</span><br><span>  /* show the two channels and cdrs involved in the bridge for debug & devel purposes */</span><br><span>   ast_channel_log("Pre-bridge CHAN Channel info", chan);</span><br><span>diff --git a/main/frame.c b/main/frame.c</span><br><span>index 4eeb3b6..cd723a2 100644</span><br><span>--- a/main/frame.c</span><br><span>+++ b/main/frame.c</span><br><span>@@ -139,6 +139,11 @@</span><br><span>                                 || fr->frametype == AST_FRAME_IMAGE) {</span><br><span>                            ao2_cleanup(fr->subclass.format);</span><br><span>                         }</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_ANSWER</span><br><span style="color: hsl(120, 100%, 40%);">+                            && fr->datalen == sizeof(struct ast_stream_topology *)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          struct ast_stream_topology *topology = *((struct ast_stream_topology **)fr->data.ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+                             ao2_cleanup(topology);</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span> </span><br><span>                        AST_LIST_INSERT_HEAD(&frames->list, fr, frame_list);</span><br><span>                  frames->size++;</span><br><span>@@ -147,6 +152,12 @@</span><br><span>    }</span><br><span> #endif</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+       if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_ANSWER</span><br><span style="color: hsl(120, 100%, 40%);">+            && fr->datalen == sizeof(struct ast_stream_topology *)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct ast_stream_topology *topology = *((struct ast_stream_topology **)fr->data.ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+             ao2_cleanup(topology);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  if (fr->mallocd & AST_MALLOCD_DATA) {</span><br><span>                 if (fr->data.ptr) {</span><br><span>                       ast_free(fr->data.ptr - fr->offset);</span><br><span>@@ -208,6 +219,12 @@</span><br><span>            return fr;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_ANSWER</span><br><span style="color: hsl(120, 100%, 40%);">+            && fr->datalen == sizeof(struct ast_stream_topology *)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct ast_stream_topology *topology = *((struct ast_stream_topology **)fr->data.ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+             ao2_bump(topology);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  if (!(fr->mallocd & AST_MALLOCD_HDR)) {</span><br><span>               /* Allocate a new header if needed */</span><br><span>                if (!(out = ast_frame_header_new(file, line, func))) {</span><br><span>@@ -349,6 +366,13 @@</span><br><span>                (f->frametype == AST_FRAME_IMAGE)) {</span><br><span>              ao2_bump(out->subclass.format);</span><br><span>   }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_ANSWER</span><br><span style="color: hsl(120, 100%, 40%);">+              && f->datalen == sizeof(struct ast_stream_topology *)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           struct ast_stream_topology *topology = *((struct ast_stream_topology **)f->data.ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+              ao2_bump(topology);</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>        out->datalen = f->datalen;</span><br><span>     out->samples = f->samples;</span><br><span>     out->delivery = f->delivery;</span><br><span>diff --git a/main/stream.c b/main/stream.c</span><br><span>index a21177d..01b07ca 100644</span><br><span>--- a/main/stream.c</span><br><span>+++ b/main/stream.c</span><br><span>@@ -602,6 +602,16 @@</span><br><span>                   ast_format_cap_append(joint_caps, single, 0);</span><br><span>                        ao2_ref(single, -1);</span><br><span>                 }</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (error_message) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_str_append(error_message, 0, "No common formats available for media type '%s' ",</span><br><span style="color: hsl(120, 100%, 40%);">+                                ast_codec_media_type2str(pending_stream->type));</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_format_cap_append_names(preferred_caps, error_message);</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_str_append(error_message, 0, "<>");</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_format_cap_append_names(nonpreferred_caps, error_message);</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_str_append(error_message, 0, " with prefs: ");</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_stream_codec_prefs_to_str(prefs, error_message);</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span>    }</span><br><span> </span><br><span>        joint_stream = ast_stream_clone(pending_stream, NULL);</span><br><span>@@ -613,7 +623,7 @@</span><br><span>         /* ref to joint_caps will be transferred to the stream */</span><br><span>    ast_stream_set_formats(joint_stream, joint_caps);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (TRACE_ATLEAST(1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+       if (TRACE_ATLEAST(3)) {</span><br><span>              struct ast_str *buf = ast_str_create((AST_FORMAT_CAP_NAMES_LEN * 3) + AST_STREAM_MAX_CODEC_PREFS_LENGTH);</span><br><span>            if (buf) {</span><br><span>                   ast_str_set(&buf, 0, "Resolved '%s' stream ", ast_codec_media_type2str(pending_stream->type));</span><br><span>@@ -1040,7 +1050,10 @@</span><br><span>                     ast_stream_set_state(joint_stream, AST_STREAM_STATE_REMOVED);</span><br><span>                } else {</span><br><span>                     joint_stream = ast_stream_create_resolved(pending_stream, configured_stream, prefs, error_message);</span><br><span style="color: hsl(0, 100%, 40%);">-                     if (ast_stream_get_format_count(joint_stream) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (!joint_stream) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          ao2_cleanup(joint_topology);</span><br><span style="color: hsl(120, 100%, 40%);">+                          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                  } else if (ast_stream_get_format_count(joint_stream) == 0) {</span><br><span>                                 ast_stream_set_state(joint_stream, AST_STREAM_STATE_REMOVED);</span><br><span>                        }</span><br><span>            }</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/14688">change 14688</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/+/14688"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I0115d2ed68d6bae0f87e85abcf16c771bdaf992c </div>
<div style="display:none"> Gerrit-Change-Number: 14688 </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>