<p>Friendly Automation <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/14688">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Joshua Colp: Looks good to me, approved
  Kevin Harwell: Looks good to me, but someone else must approve
  Friendly Automation: Approved for Submit

</div><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 include/asterisk/frame.h<br>M main/channel.c<br>M main/features.c<br>M main/frame.c<br>M main/stream.c<br>7 files changed, 155 insertions(+), 10 deletions(-)<br><br></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..9e11487 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%);">+                                             /* Answer can optionally include a topology */</span><br><span style="color: hsl(120, 100%, 40%);">+                                                if (f->subclass.topology) {</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%);">+                                                   config->answer_topology = ao2_bump(f->subclass.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, config->answer_topology,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                ast_str_tmp(256, ast_stream_topology_to_str(config->answer_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>@@ -2217,7 +2230,7 @@</span><br><span>     struct dial_head out_chans = AST_LIST_HEAD_NOLOCK_INIT_VALUE; /* list of destinations */</span><br><span>     struct chanlist *outgoing;</span><br><span>   struct chanlist *tmp;</span><br><span style="color: hsl(0, 100%, 40%);">-   struct ast_channel *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_channel *peer = NULL;</span><br><span>     int to; /* timeout */</span><br><span>        struct cause_args num = { chan, 0, 0, 0 };</span><br><span>   int cause;</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.answer_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%);">+                    peer ? ast_channel_name(peer) : "<no channel>", &config.answer_topology,</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_str_tmp(256, ast_stream_topology_to_str(config.answer_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.answer_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..baefedd 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.0.0</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,10 @@</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%);">+    /*! If the bridge answers the channel this topology should be passed to the channel</span><br><span style="color: hsl(120, 100%, 40%);">+    * and used if the channel supports the answer_with_stream_topology callback.</span><br><span style="color: hsl(120, 100%, 40%);">+  */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_stream_topology *answer_topology;</span><br><span> };</span><br><span> </span><br><span> struct chanmon;</span><br><span>@@ -1379,6 +1396,17 @@</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%);">+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 +1830,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.0.0</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 +5107,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.0.0</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/include/asterisk/frame.h b/include/asterisk/frame.h</span><br><span>index c8359ec..f5a5f2c 100644</span><br><span>--- a/include/asterisk/frame.h</span><br><span>+++ b/include/asterisk/frame.h</span><br><span>@@ -147,8 +147,12 @@</span><br><span> struct ast_frame_subclass {</span><br><span>        /*! A frame specific code */</span><br><span>         int integer;</span><br><span style="color: hsl(0, 100%, 40%);">-    /*! The asterisk media format */</span><br><span style="color: hsl(0, 100%, 40%);">-        struct ast_format *format;</span><br><span style="color: hsl(120, 100%, 40%);">+    union {</span><br><span style="color: hsl(120, 100%, 40%);">+               /*! The asterisk media format */</span><br><span style="color: hsl(120, 100%, 40%);">+              struct ast_format *format;</span><br><span style="color: hsl(120, 100%, 40%);">+            /*! The asterisk stream topology */</span><br><span style="color: hsl(120, 100%, 40%);">+           struct ast_stream_topology *topology;</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span>   /*! For video formats, an indication that a frame ended */</span><br><span>   unsigned int frame_ending;</span><br><span> };</span><br><span>diff --git a/main/channel.c b/main/channel.c</span><br><span>index 8dd008d..c26089a 100644</span><br><span>--- a/main/channel.c</span><br><span>+++ b/main/channel.c</span><br><span>@@ -1238,6 +1238,17 @@</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%);">+               .subclass.topology = (struct ast_stream_topology *)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 +2630,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 +2662,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 +2682,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..9810866 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->answer_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..3a5ee91 100644</span><br><span>--- a/main/frame.c</span><br><span>+++ b/main/frame.c</span><br><span>@@ -138,6 +138,8 @@</span><br><span>                          || fr->frametype == AST_FRAME_VIDEO</span><br><span>                               || fr->frametype == AST_FRAME_IMAGE) {</span><br><span>                            ao2_cleanup(fr->subclass.format);</span><br><span style="color: hsl(120, 100%, 40%);">+                  } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_ANSWER) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          ao2_cleanup(fr->subclass.topology);</span><br><span>                       }</span><br><span> </span><br><span>                        AST_LIST_INSERT_HEAD(&frames->list, fr, frame_list);</span><br><span>@@ -160,6 +162,8 @@</span><br><span>                    || fr->frametype == AST_FRAME_VIDEO</span><br><span>                       || fr->frametype == AST_FRAME_IMAGE) {</span><br><span>                    ao2_cleanup(fr->subclass.format);</span><br><span style="color: hsl(120, 100%, 40%);">+          } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_ANSWER) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  ao2_cleanup(fr->subclass.topology);</span><br><span>               }</span><br><span> </span><br><span>                ast_free(fr);</span><br><span>@@ -218,6 +222,8 @@</span><br><span>          if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) ||</span><br><span>                        (fr->frametype == AST_FRAME_IMAGE)) {</span><br><span>                     ao2_bump(out->subclass.format);</span><br><span style="color: hsl(120, 100%, 40%);">+            } else if (fr->frametype == AST_FRAME_VOICE && fr->subclass.integer == AST_CONTROL_ANSWER) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ao2_bump(out->subclass.topology);</span><br><span>                 }</span><br><span>            out->datalen = fr->datalen;</span><br><span>            out->samples = fr->samples;</span><br><span>@@ -348,7 +354,10 @@</span><br><span>     if ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_VIDEO) ||</span><br><span>          (f->frametype == AST_FRAME_IMAGE)) {</span><br><span>              ao2_bump(out->subclass.format);</span><br><span style="color: hsl(120, 100%, 40%);">+    } else if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_ANSWER) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ao2_bump(out->subclass.topology);</span><br><span>         }</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: 4 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@sangoma.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-CC: Richard Mudgett <rmudgett@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>