<p>Joshua Colp has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/14505">View Change</a></p><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, 189 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/05/14505/1</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 fa69169..5788668 100644</span><br><span>--- a/main/core_local.c</span><br><span>+++ b/main/core_local.c</span><br><span>@@ -48,6 +48,7 @@</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> </span><br><span> /*** DOCUMENTATION</span><br><span>     <manager name="LocalOptimizeAway" language="en_US"></span><br><span>@@ -136,6 +137,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 +173,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 +862,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 +920,30 @@</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>      struct local_pvt *p;</span><br><span>         struct ast_channel *chan;</span><br><span>    ast_callid callid;</span><br><span> </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, topology);</span><br><span>     if (!p) {</span><br><span>            return NULL;</span><br><span>         }</span><br><span>@@ -937,6 +958,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..03664d9 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,13 @@</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 style="color: hsl(120, 100%, 40%);">+      if (stream_num == 3) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_log(LOG_NOTICE, "Wrote video in!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+   }</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 +543,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 +676,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 +1014,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 +1052,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 +1080,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 +1098,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 +1118,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 +1132,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 +1190,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/+/14505">change 14505</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/+/14505"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 16 </div>
<div style="display:none"> Gerrit-Change-Id: I4e9d94da5230d4bd046dc755651493fce1d87186 </div>
<div style="display:none"> Gerrit-Change-Number: 14505 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Joshua Colp <jcolp@sangoma.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>