<p>Friendly Automation <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/14526">View Change</a></p><div style="white-space:pre-wrap">Approvals:
Kevin Harwell: Looks good to me, but someone else must approve
George Joseph: Looks good to me, approved
Friendly Automation: Approved for Submit
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">core_unreal / core_local: Add multistream and re-negotiation.<br><br>When requesting a Local channel the requested stream topology<br>or a converted stream topology will now be placed onto the<br>resulting channels.<br><br>Frames written in on streams will now also preserve the stream<br>identifier as they are queued on the opposite channel.<br><br>Finally when a stream topology change is requested it is<br>immediately accepted and reflected on both channels. Each<br>channel also receives a queued frame to indicate that the<br>topology has changed.<br><br>ASTERISK-28938<br><br>Change-Id: I4e9d94da5230d4bd046dc755651493fce1d87186<br>---<br>M include/asterisk/core_unreal.h<br>M main/core_local.c<br>M main/core_unreal.c<br>3 files changed, 251 insertions(+), 7 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/asterisk/core_unreal.h b/include/asterisk/core_unreal.h</span><br><span>index 35fc87e..a28d39d 100644</span><br><span>--- a/include/asterisk/core_unreal.h</span><br><span>+++ b/include/asterisk/core_unreal.h</span><br><span>@@ -40,6 +40,7 @@</span><br><span> </span><br><span> /* Forward declare some struct names */</span><br><span> struct ast_format_cap;</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_stream_topology;</span><br><span> </span><br><span> /* ------------------------------------------------------------------- */</span><br><span> </span><br><span>@@ -96,6 +97,7 @@</span><br><span> unsigned int flags; /*!< Private option flags */</span><br><span> /*! Base name of the unreal channels. exten@context or other name. */</span><br><span> char name[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2];</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_stream_topology *reqtopology; /*!< Requested stream topology */</span><br><span> };</span><br><span> </span><br><span> #define AST_UNREAL_IS_OUTBOUND(a, b) ((a) == (b)->chan ? 1 : 0)</span><br><span>@@ -146,6 +148,9 @@</span><br><span> /*! Unreal channel framework struct ast_channel_tech.write callback */</span><br><span> int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! Unreal channel framework struct ast_channel_tech.write_stream callback */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_unreal_write_stream(struct ast_channel *ast, int stream_num, struct ast_frame *f);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! Unreal channel framework struct ast_channel_tech.indicate callback */</span><br><span> int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);</span><br><span> </span><br><span>@@ -188,6 +193,20 @@</span><br><span> struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Allocate the base unreal struct for a derivative.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.12.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 17.6.0</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param size Size of the unreal struct to allocate.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param destructor Destructor callback.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param cap Format capabilities to give the unreal private struct.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval pvt on success.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL on error.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_unreal_pvt *ast_unreal_alloc_stream_topology(size_t size, ao2_destructor_fn destructor, 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 Create the semi1 and semi2 unreal channels.</span><br><span> * \since 12.0.0</span><br><span> *</span><br><span>diff --git a/main/core_local.c b/main/core_local.c</span><br><span>index 0193c71..07a6ff7 100644</span><br><span>--- a/main/core_local.c</span><br><span>+++ b/main/core_local.c</span><br><span>@@ -48,6 +48,8 @@</span><br><span> #include "asterisk/stasis_channels.h"</span><br><span> #include "asterisk/_private.h"</span><br><span> #include "asterisk/stasis_channels.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/stream.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/translate.h"</span><br><span> </span><br><span> /*** DOCUMENTATION</span><br><span> <manager name="LocalOptimizeAway" language="en_US"></span><br><span>@@ -136,6 +138,7 @@</span><br><span> static struct ao2_container *locals;</span><br><span> </span><br><span> static struct ast_channel *local_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_channel *local_request_with_stream_topology(const char *type, struct ast_stream_topology *topology, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);</span><br><span> static int local_call(struct ast_channel *ast, const char *dest, int timeout);</span><br><span> static int local_hangup(struct ast_channel *ast);</span><br><span> static int local_devicestate(const char *data);</span><br><span>@@ -171,14 +174,15 @@</span><br><span> .type = "Local",</span><br><span> .description = tdesc,</span><br><span> .requester = local_request,</span><br><span style="color: hsl(120, 100%, 40%);">+ .requester_with_stream_topology = local_request_with_stream_topology,</span><br><span> .send_digit_begin = ast_unreal_digit_begin,</span><br><span> .send_digit_end = ast_unreal_digit_end,</span><br><span> .call = local_call,</span><br><span> .hangup = local_hangup,</span><br><span> .answer = ast_unreal_answer,</span><br><span style="color: hsl(0, 100%, 40%);">- .read = ast_unreal_read,</span><br><span style="color: hsl(120, 100%, 40%);">+ .read_stream = ast_unreal_read,</span><br><span> .write = ast_unreal_write,</span><br><span style="color: hsl(0, 100%, 40%);">- .write_video = ast_unreal_write,</span><br><span style="color: hsl(120, 100%, 40%);">+ .write_stream = ast_unreal_write_stream,</span><br><span> .exception = ast_unreal_read,</span><br><span> .indicate = ast_unreal_indicate,</span><br><span> .fixup = ast_unreal_fixup,</span><br><span>@@ -859,14 +863,14 @@</span><br><span> }</span><br><span> </span><br><span> /*! \brief Create a call structure */</span><br><span style="color: hsl(0, 100%, 40%);">-static struct local_pvt *local_alloc(const char *data, struct ast_format_cap *cap)</span><br><span style="color: hsl(120, 100%, 40%);">+static struct local_pvt *local_alloc(const char *data, struct ast_stream_topology *topology)</span><br><span> {</span><br><span> struct local_pvt *pvt;</span><br><span> char *parse;</span><br><span> char *context;</span><br><span> char *opts;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- pvt = (struct local_pvt *) ast_unreal_alloc(sizeof(*pvt), local_pvt_destructor, cap);</span><br><span style="color: hsl(120, 100%, 40%);">+ pvt = (struct local_pvt *) ast_unreal_alloc_stream_topology(sizeof(*pvt), local_pvt_destructor, topology);</span><br><span> if (!pvt) {</span><br><span> return NULL;</span><br><span> }</span><br><span>@@ -917,12 +921,95 @@</span><br><span> /*! \brief Part of PBX interface */</span><br><span> static struct ast_channel *local_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_stream_topology *topology;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel *chan;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ topology = ast_stream_topology_create_from_format_cap(cap);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!topology) {</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%);">+ chan = local_request_with_stream_topology(type, topology, assignedids, requestor, data, cause);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_stream_topology_free(topology);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return chan;</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 Part of PBX interface */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_channel *local_request_with_stream_topology(const char *type, struct ast_stream_topology *topology, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_stream_topology *audio_filtered_topology;</span><br><span style="color: hsl(120, 100%, 40%);">+ int i;</span><br><span> struct local_pvt *p;</span><br><span> struct ast_channel *chan;</span><br><span> ast_callid callid;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Create a copy of the requested topology as we don't have ownership over</span><br><span style="color: hsl(120, 100%, 40%);">+ * the one that is passed in.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ audio_filtered_topology = ast_stream_topology_clone(topology);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!audio_filtered_topology) {</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%);">+ /* Some users of Local channels request every known format in the</span><br><span style="color: hsl(120, 100%, 40%);">+ * universe. The core itself automatically pruned this list down to a single</span><br><span style="color: hsl(120, 100%, 40%);">+ * "best" format for audio in non-multistream. We replicate the logic here to</span><br><span style="color: hsl(120, 100%, 40%);">+ * do the same thing.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < ast_stream_topology_get_count(audio_filtered_topology); ++i) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_stream *stream;</span><br><span style="color: hsl(120, 100%, 40%);">+ int res;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_format *tmp_fmt = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_format *best_audio_fmt = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_format_cap *caps;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ stream = ast_stream_topology_get_stream(audio_filtered_topology, i);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_AUDIO) {</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Respect the immutable state of formats on the stream and create a new</span><br><span style="color: hsl(120, 100%, 40%);">+ * format capabilities to replace the existing one.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!caps) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(audio_filtered_topology, -1);</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%);">+ /* The ast_translator_best_choice function treats both caps as const</span><br><span style="color: hsl(120, 100%, 40%);">+ * but does not declare it in the API.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ res = ast_translator_best_choice((struct ast_format_cap *)ast_stream_get_formats(stream), local_tech.capabilities,</span><br><span style="color: hsl(120, 100%, 40%);">+ &tmp_fmt, &best_audio_fmt);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (res < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_str *tech_codecs = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_str *request_codecs = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "No translator path exists for channel type %s (native %s) to %s\n", type,</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_format_cap_get_names(local_tech.capabilities, &tech_codecs),</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_format_cap_get_names(ast_stream_get_formats(stream), &request_codecs));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If there are no formats then we abort */</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(caps, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(audio_filtered_topology, -1);</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%);">+ ast_format_cap_append(caps, best_audio_fmt, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_stream_set_formats(stream, caps);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(caps, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(tmp_fmt, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(best_audio_fmt, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Allocate a new private structure and then Asterisk channels */</span><br><span style="color: hsl(0, 100%, 40%);">- p = local_alloc(data, cap);</span><br><span style="color: hsl(120, 100%, 40%);">+ p = local_alloc(data, audio_filtered_topology);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(audio_filtered_topology, -1);</span><br><span> if (!p) {</span><br><span> return NULL;</span><br><span> }</span><br><span>@@ -937,6 +1024,7 @@</span><br><span> return chan;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \brief CLI command "local show channels" */</span><br><span> static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span> {</span><br><span>diff --git a/main/core_unreal.c b/main/core_unreal.c</span><br><span>index 763be4f..bff1c3e 100644</span><br><span>--- a/main/core_unreal.c</span><br><span>+++ b/main/core_unreal.c</span><br><span>@@ -40,6 +40,7 @@</span><br><span> #include "asterisk/astobj2.h"</span><br><span> #include "asterisk/bridge.h"</span><br><span> #include "asterisk/core_unreal.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/stream.h"</span><br><span> </span><br><span> static unsigned int name_sequence = 0;</span><br><span> </span><br><span>@@ -316,6 +317,11 @@</span><br><span> </span><br><span> int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ return ast_unreal_write_stream(ast, -1, f);</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%);">+int ast_unreal_write_stream(struct ast_channel *ast, int stream_num, struct ast_frame *f)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span> struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);</span><br><span> int res = -1;</span><br><span> </span><br><span>@@ -337,6 +343,9 @@</span><br><span> }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Update the frame to reflect the stream */</span><br><span style="color: hsl(120, 100%, 40%);">+ f->stream_num = stream_num;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Just queue for delivery to the other side */</span><br><span> ao2_ref(p, 1);</span><br><span> ao2_lock(p);</span><br><span>@@ -530,6 +539,86 @@</span><br><span> return res;</span><br><span> }</span><br><span> </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 Handle stream topology change request.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.12.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 17.6.0</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param p Unreal private structure.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ast Channel indicating the condition.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param topology The requested topology.</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 -1 on error.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int unreal_colp_stream_topology_request_change(struct ast_unreal_pvt *p, struct ast_channel *ast, 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_stream_topology *this_channel_topology;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_stream_topology *the_other_channel_topology;</span><br><span style="color: hsl(120, 100%, 40%);">+ int i;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_stream *stream;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel *my_chan;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel *my_owner;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel *this_channel;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel *the_other_channel;</span><br><span style="color: hsl(120, 100%, 40%);">+ int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ this_channel_topology = ast_stream_topology_clone(topology);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!this_channel_topology) {</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%);">+ the_other_channel_topology = ast_stream_topology_clone(topology);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!the_other_channel_topology) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_stream_topology_free(this_channel_topology);</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%);">+ /* We swap the stream state on the other channel because it is as if the channel is</span><br><span style="color: hsl(120, 100%, 40%);">+ * connected to an external endpoint, so the perspective changes.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < ast_stream_topology_get_count(the_other_channel_topology); ++i) {</span><br><span style="color: hsl(120, 100%, 40%);">+ stream = ast_stream_topology_get_stream(the_other_channel_topology, i);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_stream_get_state(stream) == AST_STREAM_STATE_RECVONLY) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_stream_set_state(stream, AST_STREAM_STATE_SENDONLY);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (ast_stream_get_state(stream) == AST_STREAM_STATE_SENDONLY) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_stream_set_state(stream, AST_STREAM_STATE_RECVONLY);</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%);">+ ast_channel_unlock(ast);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_unreal_lock_all(p, &my_chan, &my_owner);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (AST_UNREAL_IS_OUTBOUND(ast, p)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ this_channel = p->chan;</span><br><span style="color: hsl(120, 100%, 40%);">+ the_other_channel = p->owner;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ this_channel = p->owner;</span><br><span style="color: hsl(120, 100%, 40%);">+ the_other_channel = p->chan;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (this_channel) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_set_stream_topology(this_channel, this_channel_topology);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_queue_control(this_channel, AST_CONTROL_STREAM_TOPOLOGY_CHANGED);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (the_other_channel) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_set_stream_topology(the_other_channel, the_other_channel_topology);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_stream_topology_changed_externally(the_other_channel);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (my_chan) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unlock(my_chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unref(my_chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (my_owner) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unlock(my_owner);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unref(my_owner);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(p);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_lock(ast);</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%);">+</span><br><span> int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)</span><br><span> {</span><br><span> struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);</span><br><span>@@ -583,6 +672,11 @@</span><br><span> unreal_queue_indicate(p, ast, condition, data, datalen);</span><br><span> res = -1;</span><br><span> break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE:</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_channel_is_multistream(ast)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ res = unreal_colp_stream_topology_request_change(p, ast, data);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span> default:</span><br><span> res = unreal_queue_indicate(p, ast, condition, data, datalen);</span><br><span> break;</span><br><span>@@ -916,10 +1010,29 @@</span><br><span> </span><br><span> ao2_cleanup(doomed->reqcap);</span><br><span> doomed->reqcap = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_stream_topology_free(doomed->reqtopology);</span><br><span style="color: hsl(120, 100%, 40%);">+ doomed->reqtopology = NULL;</span><br><span> }</span><br><span> </span><br><span> struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_stream_topology *topology;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_unreal_pvt *unreal;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ topology = ast_stream_topology_create_from_format_cap(cap);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!topology) {</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%);">+ unreal = ast_unreal_alloc_stream_topology(size, destructor, topology);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_stream_topology_free(topology);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return unreal;</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_unreal_pvt *ast_unreal_alloc_stream_topology(size_t size, ao2_destructor_fn destructor, struct ast_stream_topology *topology)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span> struct ast_unreal_pvt *unreal;</span><br><span> </span><br><span> static const struct ast_jb_conf jb_conf = {</span><br><span>@@ -935,12 +1048,17 @@</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- unreal->reqcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);</span><br><span style="color: hsl(120, 100%, 40%);">+ unreal->reqtopology = ast_stream_topology_clone(topology);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!unreal->reqtopology) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(unreal, -1);</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%);">+ unreal->reqcap = ast_format_cap_from_stream_topology(topology);</span><br><span> if (!unreal->reqcap) {</span><br><span> ao2_ref(unreal, -1);</span><br><span> return NULL;</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">- ast_format_cap_append_from_cap(unreal->reqcap, cap, AST_MEDIA_TYPE_UNKNOWN);</span><br><span> </span><br><span> memcpy(&unreal->jb_conf, &jb_conf, sizeof(unreal->jb_conf));</span><br><span> </span><br><span>@@ -958,6 +1076,7 @@</span><br><span> struct ast_assigned_ids id1 = {NULL, NULL};</span><br><span> struct ast_assigned_ids id2 = {NULL, NULL};</span><br><span> int generated_seqno = ast_atomic_fetchadd_int((int *) &name_sequence, +1);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_stream_topology *topology;</span><br><span> </span><br><span> /* set unique ids for the two channels */</span><br><span> if (assignedids && !ast_strlen_zero(assignedids->uniqueid)) {</span><br><span>@@ -975,6 +1094,14 @@</span><br><span> id2.uniqueid = uniqueid2;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* We need to create a topology to place on the first channel, as we can't</span><br><span style="color: hsl(120, 100%, 40%);">+ * share a single one between both.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ topology = ast_stream_topology_clone(p->reqtopology);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!topology) {</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> /*</span><br><span> * Allocate two new Asterisk channels</span><br><span> *</span><br><span>@@ -987,6 +1114,7 @@</span><br><span> "%s/%s-%08x;1", tech->type, p->name, (unsigned)generated_seqno);</span><br><span> if (!owner) {</span><br><span> ast_log(LOG_WARNING, "Unable to allocate owner channel structure\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_stream_topology_free(topology);</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span>@@ -1000,6 +1128,10 @@</span><br><span> </span><br><span> ast_channel_nativeformats_set(owner, p->reqcap);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_channel_is_multistream(owner)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_set_stream_topology(owner, topology);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Determine our read/write format and set it on each channel */</span><br><span> fmt = ast_format_cap_get_format(p->reqcap, 0);</span><br><span> if (!fmt) {</span><br><span>@@ -1054,6 +1186,11 @@</span><br><span> </span><br><span> ast_channel_nativeformats_set(chan, p->reqcap);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_channel_is_multistream(chan)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_set_stream_topology(chan, p->reqtopology);</span><br><span style="color: hsl(120, 100%, 40%);">+ p->reqtopology = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Format was already determined when setting up owner */</span><br><span> ast_channel_set_writeformat(chan, fmt);</span><br><span> ast_channel_set_rawwriteformat(chan, fmt);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/14526">change 14526</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/+/14526"/><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: I4e9d94da5230d4bd046dc755651493fce1d87186 </div>
<div style="display:none"> Gerrit-Change-Number: 14526 </div>
<div style="display:none"> Gerrit-PatchSet: 4 </div>
<div style="display:none"> Gerrit-Owner: Joshua Colp <jcolp@sangoma.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>