<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>