<p>Friendly Automation <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/14577">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Joshua Colp: Looks good to me, but someone else must approve
  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;">Streams:  Add features for Advanced Codec Negotiation<br><br>The Streams API becomes the home for the core ACN capabilities.<br>These include...<br><br> * Parsing and formatting of codec negotation preferences.<br> * Resolving pending streams and topologies with those configured<br>   using configured preferences.<br> * Utility functions for creating string representations of<br>   streams, topologies, and negotiation preferences.<br><br>For codec negotiation preferences:<br> * Added ast_stream_codec_prefs_parse() which takes a string<br>   representation of codec negotiation preferences, which<br>   may come from a pjsip endpoint for example, and populates<br>   a ast_stream_codec_negotiation_prefs structure.<br> * Added ast_stream_codec_prefs_to_str() which does the reverse.<br> * Added many functions to parse individual parameter name<br>   and value strings to their respectrive enum values, and the<br>   reverse.<br><br>For streams:<br> * Added ast_stream_create_resolved() which takes a "live" stream<br>   and resolves it with a configured stream and the negotiation<br>   preferences to create a new stream.<br> * Added ast_stream_to_str() which create a string representation<br>   of a stream suitable for debug or display purposes.<br><br>For topology:<br> * Added ast_stream_topology_create_resolved() which takes a "live"<br>   topology and resolves it, stream by stream, with a configured<br>   topology stream and the negotiation preferences to create a new<br>   topology.<br> * Added ast_stream_topology_to_str() which create a string<br>   representation of a topology suitable for debug or display<br>   purposes.<br> * Renamed ast_format_caps_from_topology() to<br>   ast_stream_topology_get_formats() to be more consistent with<br>   the existing ast_stream_get_formats().<br><br>Additional changes:<br> * A new function ast_format_cap_append_names() appends the results<br>   to the ast_str buffer instead of replacing buffer contents.<br><br>Change-Id: I2df77dedd0c72c52deb6e329effe057a8e06cd56<br>---<br>M channels/chan_pjsip.c<br>A doc/CHANGES-staging/ACN_streams.txt<br>A doc/UPGRADE-staging/ACN_streams.txt<br>M include/asterisk/format_cap.h<br>M include/asterisk/stream.h<br>M main/channel.c<br>M main/core_unreal.c<br>M main/format_cap.c<br>M main/stream.c<br>M tests/test_stream.c<br>10 files changed, 865 insertions(+), 15 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c</span><br><span>index afaecdf..2fc98b4 100644</span><br><span>--- a/channels/chan_pjsip.c</span><br><span>+++ b/channels/chan_pjsip.c</span><br><span>@@ -521,7 +521,7 @@</span><br><span>      struct ast_format_cap *cap_from_top;</span><br><span>         int res;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    cap_from_top = ast_format_cap_from_stream_topology(top);</span><br><span style="color: hsl(120, 100%, 40%);">+      cap_from_top = ast_stream_topology_get_formats(top);</span><br><span> </span><br><span>     if (!cap_from_top) {</span><br><span>                 return 0;</span><br><span>@@ -581,7 +581,7 @@</span><br><span>              ast_format_cap_append_from_cap(caps, session->endpoint->media.codecs, AST_MEDIA_TYPE_UNKNOWN);</span><br><span>                 topology = ast_stream_topology_clone(session->endpoint->media.topology);</span><br><span>       } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                caps = ast_format_cap_from_stream_topology(session->pending_media_state->topology);</span><br><span style="color: hsl(120, 100%, 40%);">+             caps = ast_stream_topology_get_formats(session->pending_media_state->topology);</span><br><span>                topology = ast_stream_topology_clone(session->pending_media_state->topology);</span><br><span>  }</span><br><span> </span><br><span>diff --git a/doc/CHANGES-staging/ACN_streams.txt b/doc/CHANGES-staging/ACN_streams.txt</span><br><span>new file mode 100644</span><br><span>index 0000000..6b54d71</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/ACN_streams.txt</span><br><span>@@ -0,0 +1,44 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: Core</span><br><span style="color: hsl(120, 100%, 40%);">+Master-Only: True</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+The Streams API becomes the home for the core ACN capabilities.</span><br><span style="color: hsl(120, 100%, 40%);">+These include...</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ * Parsing and formatting of codec negotation preferences.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Resolving pending streams and topologies with those configured</span><br><span style="color: hsl(120, 100%, 40%);">+   using configured preferences.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Utility functions for creating string representations of</span><br><span style="color: hsl(120, 100%, 40%);">+   streams, topologies, and negotiation preferences.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+For codec negotiation preferences:</span><br><span style="color: hsl(120, 100%, 40%);">+ * Added ast_stream_codec_prefs_parse() which takes a string</span><br><span style="color: hsl(120, 100%, 40%);">+   representation of codec negotiation preferences, which</span><br><span style="color: hsl(120, 100%, 40%);">+   may come from a pjsip endpoint for example, and populates</span><br><span style="color: hsl(120, 100%, 40%);">+   a ast_stream_codec_negotiation_prefs structure.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Added ast_stream_codec_prefs_to_str() which does the reverse.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Added many functions to parse individual parameter name</span><br><span style="color: hsl(120, 100%, 40%);">+   and value strings to their respectrive enum values, and the</span><br><span style="color: hsl(120, 100%, 40%);">+   reverse.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+For streams:</span><br><span style="color: hsl(120, 100%, 40%);">+ * Added ast_stream_create_resolved() which takes a "live" stream</span><br><span style="color: hsl(120, 100%, 40%);">+   and resolves it with a configured stream and the negotiation</span><br><span style="color: hsl(120, 100%, 40%);">+   preferences to create a new stream.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Added ast_stream_to_str() which create a string representation</span><br><span style="color: hsl(120, 100%, 40%);">+   of a stream suitable for debug or display purposes.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+For topology:</span><br><span style="color: hsl(120, 100%, 40%);">+ * Added ast_stream_topology_create_resolved() which takes a "live"</span><br><span style="color: hsl(120, 100%, 40%);">+   topology and resolves it, stream by stream, with a configured</span><br><span style="color: hsl(120, 100%, 40%);">+   topology stream and the negotiation preferences to create a new</span><br><span style="color: hsl(120, 100%, 40%);">+   topology.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Added ast_stream_topology_to_str() which create a string</span><br><span style="color: hsl(120, 100%, 40%);">+   representation of a topology suitable for debug or display</span><br><span style="color: hsl(120, 100%, 40%);">+   purposes.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Renamed ast_format_caps_from_topology() to</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_stream_topology_get_formats() to be more consistent with</span><br><span style="color: hsl(120, 100%, 40%);">+   the existing ast_stream_get_formats().</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Additional changes:</span><br><span style="color: hsl(120, 100%, 40%);">+ * A new function ast_format_cap_append_names() appends the results</span><br><span style="color: hsl(120, 100%, 40%);">+   to the ast_str buffer instead of replacing buffer contents.</span><br><span>diff --git a/doc/UPGRADE-staging/ACN_streams.txt b/doc/UPGRADE-staging/ACN_streams.txt</span><br><span>new file mode 100644</span><br><span>index 0000000..400a6d2</span><br><span>--- /dev/null</span><br><span>+++ b/doc/UPGRADE-staging/ACN_streams.txt</span><br><span>@@ -0,0 +1,5 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: Core</span><br><span style="color: hsl(120, 100%, 40%);">+Master-Only: True</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+The ast_format_cap_from_stream_topology() function has been renamed</span><br><span style="color: hsl(120, 100%, 40%);">+to ast_stream_topology_get_formats().</span><br><span>diff --git a/include/asterisk/format_cap.h b/include/asterisk/format_cap.h</span><br><span>index 37021eb..e9796bb 100644</span><br><span>--- a/include/asterisk/format_cap.h</span><br><span>+++ b/include/asterisk/format_cap.h</span><br><span>@@ -310,6 +310,17 @@</span><br><span>  */</span><br><span> const char *ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Append the names of codecs of a set of formats to an ast_str buffer</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 cap The capabilities structure containing the formats</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param buf A \c ast_str buffer to append the names of the formats to</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The contents of the buffer in \c buf</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *ast_format_cap_append_names(const struct ast_format_cap *cap, struct ast_str **buf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #ifndef AST_FORMAT_CAP_NAMES_LEN</span><br><span> /*! Buffer size for callers of ast_format_cap_get_names to allocate. */</span><br><span> #define AST_FORMAT_CAP_NAMES_LEN 384</span><br><span>diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h</span><br><span>index bbeeacb..ca637be 100644</span><br><span>--- a/include/asterisk/stream.h</span><br><span>+++ b/include/asterisk/stream.h</span><br><span>@@ -30,6 +30,23 @@</span><br><span> #include "asterisk/vector.h"</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Internal macro to assist converting enums to strings</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</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%);">+ * This macro checks that _value is in the bounds</span><br><span style="color: hsl(120, 100%, 40%);">+ * of the enum/string map.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define _stream_maps_to_str(_mapname, _value) \</span><br><span style="color: hsl(120, 100%, 40%);">+({ \</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *_rtn = ""; \</span><br><span style="color: hsl(120, 100%, 40%);">+    if (ARRAY_IN_BOUNDS(_value, _mapname)) { \</span><br><span style="color: hsl(120, 100%, 40%);">+            _rtn = _mapname[_value]; \</span><br><span style="color: hsl(120, 100%, 40%);">+    } \</span><br><span style="color: hsl(120, 100%, 40%);">+   _rtn; \</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>  * \brief Forward declaration for a stream, as it is opaque</span><br><span>  */</span><br><span> struct ast_stream;</span><br><span>@@ -75,9 +92,274 @@</span><br><span>          * \brief Set when the stream is not sending OR receiving media</span><br><span>       */</span><br><span>  AST_STREAM_STATE_INACTIVE,</span><br><span style="color: hsl(120, 100%, 40%);">+    /*!</span><br><span style="color: hsl(120, 100%, 40%);">+    * \brief Sentinel</span><br><span style="color: hsl(120, 100%, 40%);">+     */</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_STREAM_STATE_END</span><br><span> };</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Stream state enum to string map</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</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%);">+extern const char *ast_stream_state_map[AST_STREAM_STATE_END];</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 Safely get the name of a stream state</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 stream_state One of enum ast_stream_state</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns A constant string with the name of the state or an empty string</span><br><span style="color: hsl(120, 100%, 40%);">+ * if an invalid value was passed in.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define ast_stream_state_to_str(stream_state) _stream_maps_to_str(ast_stream_state_map, stream_state)</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 Advanced Codec Negotiation Preferences</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief The preference parameters themselves</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%);">+enum ast_stream_codec_negotiation_params {</span><br><span style="color: hsl(120, 100%, 40%);">+    CODEC_NEGOTIATION_PARAM_UNSPECIFIED = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+      /*! Which of the lists to "prefer" */</span><br><span style="color: hsl(120, 100%, 40%);">+       CODEC_NEGOTIATION_PARAM_PREFER,</span><br><span style="color: hsl(120, 100%, 40%);">+       /*! "operation" to perform */</span><br><span style="color: hsl(120, 100%, 40%);">+       CODEC_NEGOTIATION_PARAM_OPERATION,</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! "keep" all or only first */</span><br><span style="color: hsl(120, 100%, 40%);">+     CODEC_NEGOTIATION_PARAM_KEEP,</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Allow or prevent "transcode" */</span><br><span style="color: hsl(120, 100%, 40%);">+ CODEC_NEGOTIATION_PARAM_TRANSCODE,</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! Sentinel */</span><br><span style="color: hsl(120, 100%, 40%);">+       CODEC_NEGOTIATION_PARAM_END,</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%);">+ * \brief The "prefer" values</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%);">+enum ast_stream_codec_negotiation_prefs_prefer_values {</span><br><span style="color: hsl(120, 100%, 40%);">+  CODEC_NEGOTIATION_PREFER_UNSPECIFIED = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+     /*! Prefer the "pending" list */</span><br><span style="color: hsl(120, 100%, 40%);">+    CODEC_NEGOTIATION_PREFER_PENDING,</span><br><span style="color: hsl(120, 100%, 40%);">+     /*! Prefer the "configured" list */</span><br><span style="color: hsl(120, 100%, 40%);">+ CODEC_NEGOTIATION_PREFER_CONFIGURED,</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! Sentinel */</span><br><span style="color: hsl(120, 100%, 40%);">+       CODEC_NEGOTIATION_PREFER_END,</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%);">+ * \brief The "operation" values</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%);">+enum ast_stream_codec_negotiation_prefs_operation_values {</span><br><span style="color: hsl(120, 100%, 40%);">+   CODEC_NEGOTIATION_OPERATION_UNSPECIFIED = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! "intersect": only those codecs that appear in both lists */</span><br><span style="color: hsl(120, 100%, 40%);">+     CODEC_NEGOTIATION_OPERATION_INTERSECT,</span><br><span style="color: hsl(120, 100%, 40%);">+        /*! "union": all codecs in both lists */</span><br><span style="color: hsl(120, 100%, 40%);">+    CODEC_NEGOTIATION_OPERATION_UNION,</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! "only_preferred": only the codecs in the preferred list */</span><br><span style="color: hsl(120, 100%, 40%);">+      CODEC_NEGOTIATION_OPERATION_ONLY_PREFERRED,</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! "only_nonpreferred": only the codecs in the non-preferred list */</span><br><span style="color: hsl(120, 100%, 40%);">+       CODEC_NEGOTIATION_OPERATION_ONLY_NONPREFERRED,</span><br><span style="color: hsl(120, 100%, 40%);">+        /*! Sentinel */</span><br><span style="color: hsl(120, 100%, 40%);">+       CODEC_NEGOTIATION_OPERATION_END,</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%);">+ * \brief The "keep" values</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%);">+enum ast_stream_codec_negotiation_prefs_keep_values {</span><br><span style="color: hsl(120, 100%, 40%);">+  CODEC_NEGOTIATION_KEEP_UNSPECIFIED = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+       /*! "keep" all codecs after performing the operation */</span><br><span style="color: hsl(120, 100%, 40%);">+     CODEC_NEGOTIATION_KEEP_ALL,</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! "keep" only the first codec after performing the operation */</span><br><span style="color: hsl(120, 100%, 40%);">+   CODEC_NEGOTIATION_KEEP_FIRST,</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Sentinel */</span><br><span style="color: hsl(120, 100%, 40%);">+       CODEC_NEGOTIATION_KEEP_END,</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%);">+ * \brief The "transcode" values</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%);">+enum ast_stream_codec_negotiation_prefs_transcode_values {</span><br><span style="color: hsl(120, 100%, 40%);">+     CODEC_NEGOTIATION_TRANSCODE_UNSPECIFIED = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! "allow" transcoding */</span><br><span style="color: hsl(120, 100%, 40%);">+  CODEC_NEGOTIATION_TRANSCODE_ALLOW,</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! "prevent" transcoding */</span><br><span style="color: hsl(120, 100%, 40%);">+        CODEC_NEGOTIATION_TRANSCODE_PREVENT,</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! Sentinel */</span><br><span style="color: hsl(120, 100%, 40%);">+       CODEC_NEGOTIATION_TRANSCODE_END,</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%);">+ * \brief Preference enum to string map</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</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%);">+extern const char *ast_stream_codec_negotiation_params_map[CODEC_NEGOTIATION_PARAM_END];</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 "prefer" enum to string map</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</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%);">+extern const char *ast_stream_codec_negotiation_prefer_map[CODEC_NEGOTIATION_PREFER_END];</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 "operation" enum to string map</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</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%);">+extern const char *ast_stream_codec_negotiation_operation_map[CODEC_NEGOTIATION_OPERATION_END];</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 "keep" enum to string map</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</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%);">+extern const char *ast_stream_codec_negotiation_keep_map[CODEC_NEGOTIATION_KEEP_END];</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 "transcode" state enum to string map</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</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%);">+extern const char *ast_stream_codec_negotiation_transcode_map[CODEC_NEGOTIATION_TRANSCODE_END];</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 Safely get the name of a preference parameter</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 value One of enum \ref ast_stream_codec_negotiation_params</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns A constant string with the name of the preference or an empty string</span><br><span style="color: hsl(120, 100%, 40%);">+ * if an invalid value was passed in.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define ast_stream_codec_param_to_str(value) _stream_maps_to_str(ast_stream_codec_negotiation_params_map, value)</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 Safely get the name of a "prefer" parameter value</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 value One of enum \ref ast_stream_codec_negotiation_prefer_values</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns A constant string with the name of the value or an empty string</span><br><span style="color: hsl(120, 100%, 40%);">+ * if an invalid value was passed in.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define ast_stream_codec_prefer_to_str(value) _stream_maps_to_str(ast_stream_codec_negotiation_prefer_map, value)</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 Safely get the name of an "operation" parameter value</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 value One of enum \ref ast_stream_codec_negotiation_operation_values</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns A constant string with the name of the value or an empty string</span><br><span style="color: hsl(120, 100%, 40%);">+ * if an invalid value was passed in.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define ast_stream_codec_operation_to_str(value) _stream_maps_to_str(ast_stream_codec_negotiation_operation_map, value)</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 Safely get the name of a "keep" parameter value</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 value One of enum \ref ast_stream_codec_negotiation_keep_values</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns A constant string with the name of the value or an empty string</span><br><span style="color: hsl(120, 100%, 40%);">+ * if an invalid value was passed in.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define ast_stream_codec_keep_to_str(value) _stream_maps_to_str(ast_stream_codec_negotiation_keep_map, value)</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 Safely get the name of a "transcode" parameter value</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 value One of enum \ref ast_stream_codec_negotiation_transcode_values</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns A constant string with the name of the value or an empty string</span><br><span style="color: hsl(120, 100%, 40%);">+ * if an invalid value was passed in.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define ast_stream_codec_transcode_to_str(value) _stream_maps_to_str(ast_stream_codec_negotiation_transcode_map, value)</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</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%);">+ * The structure that makes up a codec negotiation preference object</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_stream_codec_negotiation_prefs {</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! Which codec list to prefer */</span><br><span style="color: hsl(120, 100%, 40%);">+     enum ast_stream_codec_negotiation_prefs_prefer_values prefer;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! The operation to perform on the lists */</span><br><span style="color: hsl(120, 100%, 40%);">+  enum ast_stream_codec_negotiation_prefs_operation_values operation;</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! What to keep after the operation is performed */</span><br><span style="color: hsl(120, 100%, 40%);">+  enum ast_stream_codec_negotiation_prefs_keep_values keep;</span><br><span style="color: hsl(120, 100%, 40%);">+     /*! To allow or prevent transcoding */</span><br><span style="color: hsl(120, 100%, 40%);">+        enum ast_stream_codec_negotiation_prefs_transcode_values transcode;</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%);">+ * \brief Define for allocating buffer space for to_str() functions</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%);">+#define AST_STREAM_MAX_CODEC_PREFS_LENGTH (128)</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 Return a string representing the codec preferences</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%);">+ * This function can be used for debugging purposes but is also</span><br><span style="color: hsl(120, 100%, 40%);">+ * used in pjsip_configuration as a sorcery parameter handler</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param prefs A pointer to a ast_stream_codec_negotiation_prefs structure</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param buf A pointer to an ast_str* used for the output.  See note below.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns the contents of the ast_str as a const char *.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \warning No attempt should ever be made to free the returned</span><br><span style="color: hsl(120, 100%, 40%);">+ * char * and it should be dup'd if needed after the ast_str is freed.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note</span><br><span style="color: hsl(120, 100%, 40%);">+ * buf can't be NULL but it CAN contain a NULL value.  If so, a new</span><br><span style="color: hsl(120, 100%, 40%);">+ * ast_str will be allocated and the value of buf updated with a pointer</span><br><span style="color: hsl(120, 100%, 40%);">+ * to it.  Whether the caller supplies the ast_str or it's allocated by</span><br><span style="color: hsl(120, 100%, 40%);">+ * this function, it's the caller's responsibility to free it.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Sample output:</span><br><span style="color: hsl(120, 100%, 40%);">+ * "prefer: configured, operation: union, keep:all, transcode:prevent"</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *ast_stream_codec_prefs_to_str(const struct ast_stream_codec_negotiation_prefs *prefs,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_str **buf);</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 Parses a string representing the codec prefs into a ast_stream_codec_negotiation_pref structure</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%);">+ * This function is mainly used by pjsip_configuration as a sorcery parameter handler.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param pref_string A string in the format described by ast_stream_codec_prefs_to_str().</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param prefs Pointer to a ast_stream_codec_negotiation_prefs structure to receive the parsed values.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param error_message An optional ast_str** into which parsing errors will be placed.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 if success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval -1 if failed</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \details</span><br><span style="color: hsl(120, 100%, 40%);">+ * Whitespace around the ':' and ',' separators is ignored and the parameters</span><br><span style="color: hsl(120, 100%, 40%);">+ * can be specified in any order.  Parameters missing in the input string</span><br><span style="color: hsl(120, 100%, 40%);">+ * will have their values set to the appropriate *_UNSPECIFIED value and will not</span><br><span style="color: hsl(120, 100%, 40%);">+ * be considered an error.  It's up to the caller to decide whether set a default</span><br><span style="color: hsl(120, 100%, 40%);">+ * value, return an error, etc.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Sample input:</span><br><span style="color: hsl(120, 100%, 40%);">+ * "prefer : configured , operation: union,keep:all, transcode:prevent"</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_stream_codec_prefs_parse(const char *pref_string, struct ast_stream_codec_negotiation_prefs *prefs,</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_str **error_message);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Create a new media stream representation</span><br><span>  *</span><br><span>  * \param name A name for the stream</span><br><span>@@ -167,6 +449,31 @@</span><br><span> const struct ast_format_cap *ast_stream_get_formats(const struct ast_stream *stream);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Get a string representing the stream for debugging/display purposes</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 stream A stream</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param buf A pointer to an ast_str* used for the output.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval "" (empty string) if either buf or *buf are NULL</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval "(null stream)" if *stream was NULL</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval <stream_representation> otherwise</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \warning No attempt should ever be made to free the returned</span><br><span style="color: hsl(120, 100%, 40%);">+ * char * and it should be dup'd if needed after the ast_str is freed.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \details</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Return format:</span><br><span style="color: hsl(120, 100%, 40%);">+ * <name>:<media_type>:<stream_state> (formats)</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Sample return:</span><br><span style="color: hsl(120, 100%, 40%);">+ * "audio:audio:sendrecv (ulaw,g722)"</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%);">+const char *ast_stream_to_str(const struct ast_stream *stream, struct ast_str **buf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Get the count of the current negotiated formats of a stream</span><br><span>  *</span><br><span>  * \param stream The media stream</span><br><span>@@ -311,6 +618,33 @@</span><br><span> void ast_stream_set_rtp_codecs(struct ast_stream *stream, struct ast_rtp_codecs *rtp_codecs);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Create a resolved stream from 2 streams</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 pending_stream The "live" stream created from an SDP,</span><br><span style="color: hsl(120, 100%, 40%);">+ *        passed through the core, or used to create an SDP.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param configured_stream The static stream used to validate the pending stream.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param prefs A pointer to an ast_stream_codec_negotiation_prefs structure.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param error_message If supplied, error messages will be appended.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \details</span><br><span style="color: hsl(120, 100%, 40%);">+ * The resulting stream will contain all of the attributes and metadata of the</span><br><span style="color: hsl(120, 100%, 40%);">+ * pending stream but will contain only the formats that passed the validation</span><br><span style="color: hsl(120, 100%, 40%);">+ * specified by the ast_stream_codec_negotiation_prefs structure.  This may mean</span><br><span style="color: hsl(120, 100%, 40%);">+ * that the stream's format_caps will be empty.  It's up to the caller to determine</span><br><span style="color: hsl(120, 100%, 40%);">+ * what to do with the stream in that case.  I.E. Free it, set it to the</span><br><span style="color: hsl(120, 100%, 40%);">+ * REMOVED state, etc.  A stream will always be returned unless there was</span><br><span style="color: hsl(120, 100%, 40%);">+ * some catastrophic allocation failure.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL if there was some allocation failure.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval A new, resolved stream.</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_stream *ast_stream_create_resolved(struct ast_stream *pending_stream,</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_stream *configured_stream, struct ast_stream_codec_negotiation_prefs *prefs,</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_str **error_message);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Create a stream topology</span><br><span>  *</span><br><span>  * \retval non-NULL success</span><br><span>@@ -387,6 +721,18 @@</span><br><span> int ast_stream_topology_get_count(const struct ast_stream_topology *topology);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Get the number of active (non-REMOVED) streams in a topology</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param topology The topology of streams</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return the number of active streams</span><br><span style="color: hsl(120, 100%, 40%);">+ *</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%);">+int ast_stream_topology_get_active_count(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 style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Get a specific stream from the topology</span><br><span>  *</span><br><span>  * \param topology The topology of streams</span><br><span>@@ -471,17 +817,61 @@</span><br><span>  *</span><br><span>  * \param topology The topology of streams</span><br><span>  *</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval non-NULL success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval non-NULL success (the resulting format caps must be unreffed by the caller)</span><br><span>  * \retval NULL failure</span><br><span>  *</span><br><span>  * \note The stream topology is NOT altered by this function.</span><br><span>  *</span><br><span>  * \since 15</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_format_cap *ast_format_cap_from_stream_topology(</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_format_cap *ast_stream_topology_get_formats(</span><br><span>  struct ast_stream_topology *topology);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Get a string representing the topology for debugging/display purposes</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 topology A stream topology</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param buf A pointer to an ast_str* used for the output.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval "" (empty string) if either buf or *buf are NULL</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval "(null topology)" if *topology was NULL</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval <topology_representation> otherwise</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \warning No attempt should ever be made to free the returned</span><br><span style="color: hsl(120, 100%, 40%);">+ * char * and it should be dup'd if needed after the ast_str is freed.</span><br><span style="color: hsl(120, 100%, 40%);">+  *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Return format:</span><br><span style="color: hsl(120, 100%, 40%);">+ * <final>? <stream> ...</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Sample return:</span><br><span style="color: hsl(120, 100%, 40%);">+ * "final <audio:audio:sendrecv (ulaw,g722)> <video:video:sendonly (h264)>"</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%);">+const char *ast_stream_topology_to_str(const struct ast_stream_topology *topology, struct ast_str **buf);</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 Create a format capabilities structure containing all the formats from all the streams</span><br><span style="color: hsl(120, 100%, 40%);">+ *        of a particular type in the 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%);">+ * \details</span><br><span style="color: hsl(120, 100%, 40%);">+ * A helper function that, given a stream topology and a media type, creates a format</span><br><span style="color: hsl(120, 100%, 40%);">+ * capabilities structure containing all formats from all active streams with the particular type.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param topology The topology of streams</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param type The media type</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval non-NULL success (the resulting format caps must be unreffed by the caller)</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL failure</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note The stream topology is NOT altered by this function.</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_format_cap *ast_stream_topology_get_formats_by_type(</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_stream_topology *topology, enum ast_media_type type);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Gets the first active stream of a specific type from the topology</span><br><span>  *</span><br><span>  * \param topology The topology of streams</span><br><span>@@ -534,4 +924,34 @@</span><br><span>  */</span><br><span> void ast_stream_set_group(struct ast_stream *stream, int group);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Create a resolved stream topology from 2 topologies</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 pending_topology The "live" topology created from an SDP,</span><br><span style="color: hsl(120, 100%, 40%);">+ *        passed through the core, or used to create an SDP.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param configured_topology The static topology used to validate the pending topology.</span><br><span style="color: hsl(120, 100%, 40%);">+ *        It MUST have only 1 stream per media type.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param prefs A pointer to an ast_stream_codec_negotiation_prefs structure.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param error_message If supplied, error messages will be appended.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \details</span><br><span style="color: hsl(120, 100%, 40%);">+ * The streams in the resolved topology will contain all of the attributes</span><br><span style="color: hsl(120, 100%, 40%);">+ * of the corresponding stream from the pending topology. It's format_caps</span><br><span style="color: hsl(120, 100%, 40%);">+ * however will contain only the formats that passed the validation</span><br><span style="color: hsl(120, 100%, 40%);">+ * specified by the ast_stream_codec_negotiation_prefs structure.  This may</span><br><span style="color: hsl(120, 100%, 40%);">+ * mean that some of the streams format_caps will be empty.  If that's the case,</span><br><span style="color: hsl(120, 100%, 40%);">+ * the stream will be in a REMOVED state.  With those rules in mind,</span><br><span style="color: hsl(120, 100%, 40%);">+ * a resolved topology will always be returned (unless there's some catastrophic</span><br><span style="color: hsl(120, 100%, 40%);">+ * allocation failure) and the resolved topology is guaranteed to have the same</span><br><span style="color: hsl(120, 100%, 40%);">+ * number of streams, in the same order, as the pending topology.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL if there was some allocation failure.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval The joint topology.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_stream_topology *ast_stream_topology_create_resolved(</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_stream_topology *pending_topology, struct ast_stream_topology *validation_topology,</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_stream_codec_negotiation_prefs *prefs,</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_str **error_message);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #endif /* _AST_STREAM_H */</span><br><span>diff --git a/main/channel.c b/main/channel.c</span><br><span>index 7424b81..40d7724 100644</span><br><span>--- a/main/channel.c</span><br><span>+++ b/main/channel.c</span><br><span>@@ -6227,7 +6227,7 @@</span><br><span> </span><br><span>            if (!request_cap && topology) {</span><br><span>                      /* Turn the request stream topology into capabilities */</span><br><span style="color: hsl(0, 100%, 40%);">-                        request_cap = tmp_converted_cap = ast_format_cap_from_stream_topology(topology);</span><br><span style="color: hsl(120, 100%, 40%);">+                      request_cap = tmp_converted_cap = ast_stream_topology_get_formats(topology);</span><br><span>                 }</span><br><span> </span><br><span>                /* find the best audio format to use */</span><br><span>diff --git a/main/core_unreal.c b/main/core_unreal.c</span><br><span>index bff1c3e..16414e6 100644</span><br><span>--- a/main/core_unreal.c</span><br><span>+++ b/main/core_unreal.c</span><br><span>@@ -1054,7 +1054,7 @@</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_from_stream_topology(topology);</span><br><span style="color: hsl(120, 100%, 40%);">+    unreal->reqcap = ast_stream_topology_get_formats(topology);</span><br><span>       if (!unreal->reqcap) {</span><br><span>            ao2_ref(unreal, -1);</span><br><span>                 return NULL;</span><br><span>diff --git a/main/format_cap.c b/main/format_cap.c</span><br><span>index ca60557..a97fd6d 100644</span><br><span>--- a/main/format_cap.c</span><br><span>+++ b/main/format_cap.c</span><br><span>@@ -699,11 +699,19 @@</span><br><span>        return internal_format_cap_identical(cap2, cap1);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-const char *ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf)</span><br><span style="color: hsl(120, 100%, 40%);">+static const char *__ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf, int append)</span><br><span> {</span><br><span>       int i;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      ast_str_set(buf, 0, "(");</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!buf || !*buf) {</span><br><span style="color: hsl(120, 100%, 40%);">+          return "";</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%);">+   if (append) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_str_append(buf, 0, "(");</span><br><span style="color: hsl(120, 100%, 40%);">+        } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_str_set(buf, 0, "(");</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span> </span><br><span>        if (!cap || !AST_VECTOR_SIZE(&cap->preference_order)) {</span><br><span>               ast_str_append(buf, 0, "nothing)");</span><br><span>@@ -725,6 +733,16 @@</span><br><span>         return ast_str_buffer(*buf);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+const char *ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return __ast_format_cap_get_names(cap, buf, 0);</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%);">+const char *ast_format_cap_append_names(const struct ast_format_cap *cap, struct ast_str **buf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return __ast_format_cap_get_names(cap, buf, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int ast_format_cap_empty(const struct ast_format_cap *cap)</span><br><span> {</span><br><span>      int count = ast_format_cap_count(cap);</span><br><span>diff --git a/main/stream.c b/main/stream.c</span><br><span>index c5aa5f8..a21177d 100644</span><br><span>--- a/main/stream.c</span><br><span>+++ b/main/stream.c</span><br><span>@@ -44,6 +44,40 @@</span><br><span>         char name_value[0];</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+const char *ast_stream_codec_negotiation_params_map[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+      [CODEC_NEGOTIATION_PARAM_UNSPECIFIED] = "unspecified",</span><br><span style="color: hsl(120, 100%, 40%);">+      [CODEC_NEGOTIATION_PARAM_PREFER] = "prefer",</span><br><span style="color: hsl(120, 100%, 40%);">+        [CODEC_NEGOTIATION_PARAM_OPERATION] = "operation",</span><br><span style="color: hsl(120, 100%, 40%);">+  [CODEC_NEGOTIATION_PARAM_KEEP] = "keep",</span><br><span style="color: hsl(120, 100%, 40%);">+    [CODEC_NEGOTIATION_PARAM_TRANSCODE] = "transcode",</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%);">+const char *ast_stream_codec_negotiation_prefer_map[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ [CODEC_NEGOTIATION_PREFER_UNSPECIFIED] = "unspecified",</span><br><span style="color: hsl(120, 100%, 40%);">+     [CODEC_NEGOTIATION_PREFER_PENDING] = "pending",</span><br><span style="color: hsl(120, 100%, 40%);">+     [CODEC_NEGOTIATION_PREFER_CONFIGURED] = "configured",</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%);">+const char *ast_stream_codec_negotiation_operation_map[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+   [CODEC_NEGOTIATION_OPERATION_UNSPECIFIED] = "unspecified",</span><br><span style="color: hsl(120, 100%, 40%);">+  [CODEC_NEGOTIATION_OPERATION_INTERSECT] = "intersect",</span><br><span style="color: hsl(120, 100%, 40%);">+      [CODEC_NEGOTIATION_OPERATION_UNION] = "union",</span><br><span style="color: hsl(120, 100%, 40%);">+      [CODEC_NEGOTIATION_OPERATION_ONLY_PREFERRED] = "only_preferred",</span><br><span style="color: hsl(120, 100%, 40%);">+    [CODEC_NEGOTIATION_OPERATION_ONLY_NONPREFERRED] = "only_nonpreferred",</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%);">+const char *ast_stream_codec_negotiation_keep_map[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       [CODEC_NEGOTIATION_KEEP_UNSPECIFIED] = "unspecified",</span><br><span style="color: hsl(120, 100%, 40%);">+       [CODEC_NEGOTIATION_KEEP_ALL] = "all",</span><br><span style="color: hsl(120, 100%, 40%);">+       [CODEC_NEGOTIATION_KEEP_FIRST] = "first",</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%);">+const char *ast_stream_codec_negotiation_transcode_map[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       [CODEC_NEGOTIATION_TRANSCODE_UNSPECIFIED] = "unspecified",</span><br><span style="color: hsl(120, 100%, 40%);">+  [CODEC_NEGOTIATION_TRANSCODE_ALLOW] = "allow",</span><br><span style="color: hsl(120, 100%, 40%);">+      [CODEC_NEGOTIATION_TRANSCODE_PREVENT] = "prevent",</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct ast_stream {</span><br><span>    /*!</span><br><span>   * \brief The type of media the stream is handling</span><br><span>@@ -91,6 +125,107 @@</span><br><span>     * \brief A vector of all the streams in this topology</span><br><span>        */</span><br><span>  AST_VECTOR(, struct ast_stream *) streams;</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! Indicates that this topology should not have further operations applied to it. */</span><br><span style="color: hsl(120, 100%, 40%);">+ int final;</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%);">+const char *ast_stream_codec_prefs_to_str(const struct ast_stream_codec_negotiation_prefs *prefs, struct ast_str **buf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!prefs || !buf || !*buf) {</span><br><span style="color: hsl(120, 100%, 40%);">+                return "";</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_str_append(buf, 0, "%s:%s, %s:%s, %s:%s, %s:%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_stream_codec_param_to_str(CODEC_NEGOTIATION_PARAM_PREFER),</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_stream_codec_prefer_to_str(prefs->prefer),</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_stream_codec_param_to_str(CODEC_NEGOTIATION_PARAM_OPERATION),</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_stream_codec_operation_to_str(prefs->operation),</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_stream_codec_param_to_str(CODEC_NEGOTIATION_PARAM_KEEP),</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_stream_codec_keep_to_str(prefs->keep),</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_stream_codec_param_to_str(CODEC_NEGOTIATION_PARAM_TRANSCODE),</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_stream_codec_transcode_to_str(prefs->transcode)</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%);">+  return ast_str_buffer(*buf);</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%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Sets a codec prefs member based on a the preference name and string value</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \warning This macro will cause the calling function to return if a preference name</span><br><span style="color: hsl(120, 100%, 40%);">+ * is matched but the value isn't valid for this preference.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define set_pref_value(_name, _value, _prefs, _UC, _lc, _error_message) \</span><br><span style="color: hsl(120, 100%, 40%);">+({ \</span><br><span style="color: hsl(120, 100%, 40%);">+  int _res = 0; \</span><br><span style="color: hsl(120, 100%, 40%);">+       if (strcmp(_name, ast_stream_codec_negotiation_params_map[CODEC_NEGOTIATION_PARAM_ ## _UC]) == 0) { \</span><br><span style="color: hsl(120, 100%, 40%);">+         int i; \</span><br><span style="color: hsl(120, 100%, 40%);">+              for (i = CODEC_NEGOTIATION_ ## _UC ## _UNSPECIFIED + 1; i < CODEC_NEGOTIATION_ ## _UC ## _END; i++) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (strcmp(value, ast_stream_codec_negotiation_ ## _lc ## _map[i]) == 0) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                          prefs->_lc = i; \</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%);">+           if ( prefs->_lc == CODEC_NEGOTIATION_ ## _UC ## _UNSPECIFIED) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                  _res = -1; \</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, "Codec preference '%s' has invalid value '%s'", name, value); \</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%);">+   if (_res < 0) { \</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 style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_stream_codec_prefs_parse(const char *pref_string, struct ast_stream_codec_negotiation_prefs *prefs,</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_str **error_message)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    char *initial_value = ast_strdupa(pref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+       char *current_value;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *pref;</span><br><span style="color: hsl(120, 100%, 40%);">+   char *saveptr1;</span><br><span style="color: hsl(120, 100%, 40%);">+       char *saveptr2;</span><br><span style="color: hsl(120, 100%, 40%);">+       char *name;</span><br><span style="color: hsl(120, 100%, 40%);">+   char *value;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!prefs) {</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%);">+   prefs->prefer = CODEC_NEGOTIATION_PREFER_UNSPECIFIED;</span><br><span style="color: hsl(120, 100%, 40%);">+      prefs->operation = CODEC_NEGOTIATION_OPERATION_UNSPECIFIED;</span><br><span style="color: hsl(120, 100%, 40%);">+        prefs->keep = CODEC_NEGOTIATION_KEEP_UNSPECIFIED;</span><br><span style="color: hsl(120, 100%, 40%);">+  prefs->transcode = CODEC_NEGOTIATION_TRANSCODE_UNSPECIFIED;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      for (current_value = initial_value; (pref = strtok_r(current_value, ",", &saveptr1)) != NULL; ) {</span><br><span style="color: hsl(120, 100%, 40%);">+               name = strtok_r(pref, ": ", &saveptr2);</span><br><span style="color: hsl(120, 100%, 40%);">+         value = strtok_r(NULL, ": ", &saveptr2);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!name || !value) {</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, "Codec preference '%s' is invalid", pref);</span><br><span style="color: hsl(120, 100%, 40%);">+                 }</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%);">+           set_pref_value(name, value, prefs, OPERATION, operation, error_message);</span><br><span style="color: hsl(120, 100%, 40%);">+              set_pref_value(name, value, prefs, PREFER, prefer, error_message);</span><br><span style="color: hsl(120, 100%, 40%);">+            set_pref_value(name, value, prefs, KEEP, keep, error_message);</span><br><span style="color: hsl(120, 100%, 40%);">+                set_pref_value(name, value, prefs, TRANSCODE, transcode, error_message);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            current_value = 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%);">+   return 0;</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%);">+const char *ast_stream_state_map[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        [AST_STREAM_STATE_REMOVED] = "removed",</span><br><span style="color: hsl(120, 100%, 40%);">+     [AST_STREAM_STATE_SENDRECV] = "sendrecv",</span><br><span style="color: hsl(120, 100%, 40%);">+   [AST_STREAM_STATE_SENDONLY] = "sendonly",</span><br><span style="color: hsl(120, 100%, 40%);">+   [AST_STREAM_STATE_RECVONLY] = "recvonly",</span><br><span style="color: hsl(120, 100%, 40%);">+   [AST_STREAM_STATE_INACTIVE] = "inactive",</span><br><span> };</span><br><span> </span><br><span> struct ast_stream *ast_stream_alloc(const char *name, enum ast_media_type type)</span><br><span>@@ -165,6 +300,7 @@</span><br><span>       }</span><br><span> </span><br><span>        ao2_cleanup(stream->formats);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>   ast_free(stream);</span><br><span> }</span><br><span> </span><br><span>@@ -196,6 +332,26 @@</span><br><span>    return stream->formats;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+const char *ast_stream_to_str(const struct ast_stream *stream, struct ast_str **buf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!buf || !*buf) {</span><br><span style="color: hsl(120, 100%, 40%);">+          return "";</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%);">+   if (!stream) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_str_append(buf, 0, "(null stream)");</span><br><span style="color: hsl(120, 100%, 40%);">+            return ast_str_buffer(*buf);</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_str_append(buf, 0, "%s:%s:%s ",</span><br><span style="color: hsl(120, 100%, 40%);">+         S_OR(stream->name, "noname"),</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_codec_media_type2str(stream->type),</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_stream_state_map[stream->state]);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_format_cap_append_names(stream->formats, buf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return ast_str_buffer(*buf);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int ast_stream_get_format_count(const struct ast_stream *stream)</span><br><span> {</span><br><span>   ast_assert(stream != NULL);</span><br><span>@@ -375,6 +531,108 @@</span><br><span>  stream->rtp_codecs = rtp_codecs;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_stream *ast_stream_create_resolved(struct ast_stream *pending_stream,</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_stream *validation_stream, struct ast_stream_codec_negotiation_prefs *prefs,</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_str **error_message)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_format_cap *preferred_caps = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_format_cap *nonpreferred_caps = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_format_cap *joint_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_stream *joint_stream;</span><br><span style="color: hsl(120, 100%, 40%);">+      enum ast_media_type media_type = pending_stream ? pending_stream->type : AST_MEDIA_TYPE_UNKNOWN;</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%);">+        if (!pending_stream || !validation_stream || !prefs || !joint_caps</span><br><span style="color: hsl(120, 100%, 40%);">+            || media_type == AST_MEDIA_TYPE_UNKNOWN) {</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, "Invalid arguments");</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+             ao2_cleanup(joint_caps);</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%);">+   if (prefs->prefer == CODEC_NEGOTIATION_PREFER_PENDING) {</span><br><span style="color: hsl(120, 100%, 40%);">+           preferred_caps = pending_stream->formats;</span><br><span style="color: hsl(120, 100%, 40%);">+          nonpreferred_caps = validation_stream->formats;</span><br><span style="color: hsl(120, 100%, 40%);">+    } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              preferred_caps = validation_stream->formats;</span><br><span style="color: hsl(120, 100%, 40%);">+               nonpreferred_caps = pending_stream->formats;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_format_cap_set_framing(joint_caps, ast_format_cap_get_framing(pending_stream->formats));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch(prefs->operation) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case CODEC_NEGOTIATION_OPERATION_ONLY_PREFERRED:</span><br><span style="color: hsl(120, 100%, 40%);">+              res = ast_format_cap_append_from_cap(joint_caps, preferred_caps, media_type);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CODEC_NEGOTIATION_OPERATION_ONLY_NONPREFERRED:</span><br><span style="color: hsl(120, 100%, 40%);">+           res = ast_format_cap_append_from_cap(joint_caps, nonpreferred_caps, media_type);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CODEC_NEGOTIATION_OPERATION_INTERSECT:</span><br><span style="color: hsl(120, 100%, 40%);">+           res = ast_format_cap_get_compatible(preferred_caps, nonpreferred_caps, joint_caps);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CODEC_NEGOTIATION_OPERATION_UNION:</span><br><span style="color: hsl(120, 100%, 40%);">+               res = ast_format_cap_append_from_cap(joint_caps, preferred_caps, media_type);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (res == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       res = ast_format_cap_append_from_cap(joint_caps, nonpreferred_caps, media_type);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</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%);">+   if (res) {</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 style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           ao2_cleanup(joint_caps);</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%);">+   if (!ast_format_cap_empty(joint_caps)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (prefs->keep == CODEC_NEGOTIATION_KEEP_FIRST) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 struct ast_format *single = ast_format_cap_get_format(joint_caps, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                 ast_format_cap_remove_by_type(joint_caps, AST_MEDIA_TYPE_UNKNOWN);</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_format_cap_append(joint_caps, single, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                 ao2_ref(single, -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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   joint_stream = ast_stream_clone(pending_stream, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!joint_stream) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ao2_cleanup(joint_caps);</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%);">+   /* ref to joint_caps will be transferred to the stream */</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_stream_set_formats(joint_stream, joint_caps);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (TRACE_ATLEAST(1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               struct ast_str *buf = ast_str_create((AST_FORMAT_CAP_NAMES_LEN * 3) + AST_STREAM_MAX_CODEC_PREFS_LENGTH);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (buf) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_str_set(&buf, 0, "Resolved '%s' stream ", ast_codec_media_type2str(pending_stream->type));</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_format_cap_append_names(preferred_caps, &buf);</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_str_append(&buf, 0, "<>");</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_format_cap_append_names(nonpreferred_caps, &buf);</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_str_append(&buf, 0, " to ");</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_format_cap_append_names(joint_caps, &buf);</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_str_append(&buf, 0, " with prefs: ");</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_stream_codec_prefs_to_str(prefs, &buf);</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_trace(1, "%s\n", ast_str_buffer(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_free(buf);</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%);">+   ao2_cleanup(joint_caps);</span><br><span style="color: hsl(120, 100%, 40%);">+      return joint_stream;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static void stream_topology_destroy(void *data)</span><br><span> {</span><br><span>    struct ast_stream_topology *topology = data;</span><br><span>@@ -502,6 +760,22 @@</span><br><span>  return AST_VECTOR_SIZE(&topology->streams);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int ast_stream_topology_get_active_count(const struct ast_stream_topology *topology)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        int count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_assert(topology != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         struct ast_stream *stream = AST_VECTOR_GET(&topology->streams, i);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (stream->state != AST_STREAM_STATE_REMOVED) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   count++;</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%);">+   return count;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct ast_stream *ast_stream_topology_get_stream(</span><br><span>     const struct ast_stream_topology *topology, unsigned int stream_num)</span><br><span> {</span><br><span>@@ -610,8 +884,8 @@</span><br><span>      return topology;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_format_cap *ast_format_cap_from_stream_topology(</span><br><span style="color: hsl(0, 100%, 40%);">-    struct ast_stream_topology *topology)</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_format_cap *ast_stream_topology_get_formats_by_type(</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_stream_topology *topology, enum ast_media_type type)</span><br><span> {</span><br><span>     struct ast_format_cap *caps;</span><br><span>         int i;</span><br><span>@@ -627,17 +901,51 @@</span><br><span>               struct ast_stream *stream;</span><br><span> </span><br><span>               stream = AST_VECTOR_GET(&topology->streams, i);</span><br><span style="color: hsl(0, 100%, 40%);">-          if (!stream->formats</span><br><span style="color: hsl(0, 100%, 40%);">-                 || stream->state == AST_STREAM_STATE_REMOVED) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!stream->formats || stream->state == AST_STREAM_STATE_REMOVED) {</span><br><span>                   continue;</span><br><span>            }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               ast_format_cap_append_from_cap(caps, stream->formats, AST_MEDIA_TYPE_UNKNOWN);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (type == AST_MEDIA_TYPE_UNKNOWN || type == stream->type) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_format_cap_append_from_cap(caps, stream->formats, AST_MEDIA_TYPE_UNKNOWN);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span>    }</span><br><span> </span><br><span>        return caps;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_format_cap *ast_stream_topology_get_formats(</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 style="color: hsl(120, 100%, 40%);">+  return ast_stream_topology_get_formats_by_type(topology, AST_MEDIA_TYPE_UNKNOWN);</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%);">+const char *ast_stream_topology_to_str(const struct ast_stream_topology *topology,</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_str **buf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!buf ||!*buf) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return "";</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%);">+   if (!topology) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_str_append(buf, 0, "(null topology)");</span><br><span style="color: hsl(120, 100%, 40%);">+          return ast_str_buffer(*buf);</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_str_append(buf, 0, "%s", S_COR(topology->final, "final", ""));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         struct ast_stream *stream;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          stream = AST_VECTOR_GET(&topology->streams, i);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_str_append(buf, 0, " <");</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_stream_to_str(stream, buf);</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_str_append(buf, 0, ">");</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%);">+   return ast_str_buffer(*buf);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct ast_stream *ast_stream_topology_get_first_stream_by_type(</span><br><span>        const struct ast_stream_topology *topology,</span><br><span>  enum ast_media_type type)</span><br><span>@@ -704,6 +1012,50 @@</span><br><span>    }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_stream_topology *ast_stream_topology_create_resolved(</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_stream_topology *pending_topology, struct ast_stream_topology *configured_topology,</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_stream_codec_negotiation_prefs *prefs, struct ast_str**error_message)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_stream_topology *joint_topology = ast_stream_topology_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+     int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!pending_topology || !configured_topology || !joint_topology) {</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%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (i = 0; i < AST_VECTOR_SIZE(&pending_topology->streams); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         struct ast_stream *pending_stream = AST_VECTOR_GET(&pending_topology->streams, i);</span><br><span style="color: hsl(120, 100%, 40%);">+             struct ast_stream *configured_stream =</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_stream_topology_get_first_stream_by_type(configured_topology, pending_stream->type);</span><br><span style="color: hsl(120, 100%, 40%);">+           struct ast_stream *joint_stream;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!configured_stream) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     joint_stream = ast_stream_clone(pending_stream, NULL);</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%);">+                  }</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_stream_set_state(joint_stream, AST_STREAM_STATE_REMOVED);</span><br><span style="color: hsl(120, 100%, 40%);">+         } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      joint_stream = ast_stream_create_resolved(pending_stream, configured_stream, prefs, error_message);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (ast_stream_get_format_count(joint_stream) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         ast_stream_set_state(joint_stream, AST_STREAM_STATE_REMOVED);</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%);">+           res = ast_stream_topology_append_stream(joint_topology, joint_stream);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (res < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_stream_free(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%);">+          }</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%);">+   return joint_topology;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int ast_stream_get_group(const struct ast_stream *stream)</span><br><span> {</span><br><span>        ast_assert(stream != NULL);</span><br><span>diff --git a/tests/test_stream.c b/tests/test_stream.c</span><br><span>index 50f0ccb..1333e2e 100644</span><br><span>--- a/tests/test_stream.c</span><br><span>+++ b/tests/test_stream.c</span><br><span>@@ -2142,7 +2142,7 @@</span><br><span>                 return AST_TEST_FAIL;</span><br><span>        }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   stream_caps = ast_format_cap_from_stream_topology(topology);</span><br><span style="color: hsl(120, 100%, 40%);">+  stream_caps = ast_stream_topology_get_formats(topology);</span><br><span>     if (!stream_caps) {</span><br><span>          ast_test_status_update(test, "Failed to create a format capabilities from a stream topology\n");</span><br><span>           ast_stream_topology_free(topology);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/14577">change 14577</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/+/14577"/><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: I2df77dedd0c72c52deb6e329effe057a8e06cd56 </div>
<div style="display:none"> Gerrit-Change-Number: 14577 </div>
<div style="display:none"> Gerrit-PatchSet: 5 </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: George Joseph <gjoseph@digium.com> </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-MessageType: merged </div>