]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
stream: Add media stream topology definition and API 22/4922/5
authorGeorge Joseph <gjoseph@digium.com>
Fri, 10 Feb 2017 21:45:43 +0000 (14:45 -0700)
committerGeorge Joseph <gjoseph@digium.com>
Mon, 13 Feb 2017 14:49:25 +0000 (07:49 -0700)
This change adds the media stream topology definition and API for
accessing and using it.

Some refactoring of the stream was also done.

ASTERISK-26786

Change-Id: Ic930232d24d5ad66dcabc14e9b359e0ff8e7f568

include/asterisk/codec.h
include/asterisk/stream.h
main/format_cap.c
main/stream.c
res/res_pjsip_sdp_rtp.c

index 3873324b14399b453ae9bd5ab57e9695358acff2..2ae9551816ddd0674a2e321758e60fa331201db5 100644 (file)
@@ -33,6 +33,7 @@ enum ast_media_type {
        AST_MEDIA_TYPE_VIDEO,
        AST_MEDIA_TYPE_IMAGE,
        AST_MEDIA_TYPE_TEXT,
+       AST_MEDIA_TYPE_END,
 };
 
 struct ast_module;
index e73ed3fe7a7881bc350f441f8621ab7e66be3943..cffe6ea4cb138b56617970f2419c10386df38239 100644 (file)
@@ -38,6 +38,11 @@ struct ast_stream;
  */
 struct ast_format_cap;
 
+/*!
+ * \brief The topology of a set of streams
+ */
+struct ast_stream_topology;
+
 /*!
  * \brief States that a stream may be in
  */
@@ -90,12 +95,25 @@ struct ast_stream *ast_stream_create(const char *name, enum ast_media_type type)
  */
 void ast_stream_destroy(struct ast_stream *stream);
 
+/*!
+ * \brief Create a deep clone of an existing stream
+ *
+ * \param stream The existing stream
+ *
+ * \retval non-NULL success
+ * \retval NULL failure
+ *
+ * \since 15
+ */
+struct ast_stream *ast_stream_clone(const struct ast_stream *stream);
+
 /*!
  * \brief Get the name of a stream
  *
  * \param stream The media stream
  *
- * \return The name of the stream
+ * \retval non-NULL success
+ * \retval NULL failure
  *
  * \since 15
  */
@@ -106,7 +124,7 @@ const char *ast_stream_get_name(const struct ast_stream *stream);
  *
  * \param stream The media stream
  *
- * \return The media type of the stream
+ * \return The media type of the stream (AST_MEDIA_TYPE_UNKNOWN on error)
  *
  * \since 15
  */
@@ -127,7 +145,8 @@ void ast_stream_set_type(struct ast_stream *stream, enum ast_media_type type);
  *
  * \param stream The media stream
  *
- * \return The negotiated media formats
+ * \retval non-NULL success
+ * \retval NULL failure
  *
  * \note The reference count is not increased
  *
@@ -141,6 +160,9 @@ struct ast_format_cap *ast_stream_get_formats(const struct ast_stream *stream);
  * \param stream The media stream
  * \param caps The current negotiated formats
  *
+ * \note The new format capabilities structure has its refcount bumped and
+ * any existing format capabilities structure has its refcount decremented.
+ *
  * \since 15
  */
 void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps);
@@ -150,7 +172,7 @@ void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *ca
  *
  * \param stream The media stream
  *
- * \return The state of the stream
+ * \return The state of the stream (AST_STREAM_STATE_UNKNOWN on error)
  *
  * \since 15
  */
@@ -169,14 +191,129 @@ enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream);
 void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state);
 
 /*!
- * \brief Get the number of the stream
+ * \brief Get the position of the stream in the topology
  *
  * \param stream The media stream
  *
- * \return The number of the stream
+ * \return The position of the stream (-1 on error)
+ *
+ * \since 15
+ */
+int ast_stream_get_position(const struct ast_stream *stream);
+
+/*!
+ * \brief Create a stream topology
+ *
+ * \retval non-NULL success
+ * \retval NULL failure
+ *
+ * \since 15
+ */
+struct ast_stream_topology *ast_stream_topology_create(void);
+
+/*!
+ * \brief Create a deep clone of an existing stream topology
+ *
+ * \param topology The existing topology of streams
+ *
+ * \retval non-NULL success
+ * \retval NULL failure
+ *
+ * \since 15
+ */
+struct ast_stream_topology *ast_stream_topology_clone(
+       const struct ast_stream_topology *topology);
+
+/*!
+ * \brief Destroy a stream topology
+ *
+ * \param topology The topology of streams
+ *
+ * \note All streams contained within the topology will be destroyed
+ *
+ * \since 15
+ */
+void ast_stream_topology_destroy(struct ast_stream_topology *topology);
+
+/*!
+ * \brief Append a stream to the topology
+ *
+ * \param topology The topology of streams
+ * \param stream The stream to append
+ *
+ * \returns the position of the stream in the topology (-1 on error)
+ *
+ * \since 15
+ */
+int ast_stream_topology_append_stream(struct ast_stream_topology *topology,
+       struct ast_stream *stream);
+
+/*!
+ * \brief Get the number of streams in a topology
+ *
+ * \param topology The topology of streams
+ *
+ * \return the number of streams (-1 on error)
+ *
+ * \since 15
+ */
+int ast_stream_topology_get_count(const struct ast_stream_topology *topology);
+
+/*!
+ * \brief Get a specific stream from the topology
+ *
+ * \param topology The topology of streams
+ * \param position The topology position to get
+ *
+ * \retval non-NULL success
+ * \retval NULL failure
+ *
+ * \since 15
+ */
+struct ast_stream *ast_stream_topology_get_stream(
+       const struct ast_stream_topology *topology, unsigned int position);
+
+/*!
+ * \brief Set a specific position in a topology
+ *
+ * \param topology The topology of streams
+ * \param position The topology position to set
+ * \param stream The stream to put in its place
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ *
+ * \note If an existing stream exists it will be destroyed
+ *
+ * \note You can overwrite an existing position in the topology or set
+ * the first unused position.  You can't set positions beyond that.
+ *
+ * \since 15
+ */
+int ast_stream_topology_set_stream(struct ast_stream_topology *topology,
+       unsigned int position, struct ast_stream *stream);
+
+/*!
+ * \brief A helper function that, given a format capabilities structure,
+ * creates a topology and separates the media types in format_cap into
+ * separate streams.
+ *
+ * \param caps The format capabilities structure
+ *
+ * \retval non-NULL success
+ * \retval NULL failure
+ *
+ * \note The format capabilities reference is NOT altered by this function
+ * since a new format capabilities structure is created for each media type.
+ *
+ * \note Each stream will have its name set to the corresponding media type.
+ * For example: "AST_MEDIA_TYPE_AUDIO".
+ *
+ * \note Each stream will be set to the sendrecv state.
  *
  * \since 15
  */
-unsigned int ast_stream_get_num(const struct ast_stream *stream);
+struct ast_stream_topology *ast_stream_topology_create_from_format_cap(
+       struct ast_format_cap *cap);
 
 #endif /* _AST_STREAM_H */
index 1fe342b3107066b91d4dfdaf283b2f246bf39d59..b0897c001c0e9f77640dffd6b362760506a33648 100644 (file)
@@ -268,6 +268,7 @@ int ast_format_cap_append_from_cap(struct ast_format_cap *dst, const struct ast_
 {
        int idx, res = 0;
 
+       /* NOTE:  The streams API is dependent on the formats being in "preference" order */
        for (idx = 0; (idx < AST_VECTOR_SIZE(&src->preference_order)) && !res; ++idx) {
                struct format_cap_framed *framed = AST_VECTOR_GET(&src->preference_order, idx);
 
index fb3dbd5ce5d274ba986ea8e1af0db4f71b53bd66..0fabfc7387d86522368387dff6a066dd313158da 100644 (file)
@@ -32,6 +32,8 @@
 #include "asterisk/logger.h"
 #include "asterisk/stream.h"
 #include "asterisk/strings.h"
+#include "asterisk/format.h"
+#include "asterisk/format_cap.h"
 
 struct ast_stream {
        /*!
@@ -40,9 +42,9 @@ struct ast_stream {
        enum ast_media_type type;
 
        /*!
-        * \brief Unique number for the stream within the context of the channel it is on
+        * \brief The position of the stream in the topology
         */
-       unsigned int num;
+       unsigned int position;
 
        /*!
         * \brief Current formats negotiated on the stream
@@ -60,6 +62,13 @@ struct ast_stream {
        char name[0];
 };
 
+struct ast_stream_topology {
+       /*!
+        * \brief A vector of all the streams in this topology
+        */
+       AST_VECTOR(, struct ast_stream *) streams;
+};
+
 struct ast_stream *ast_stream_create(const char *name, enum ast_media_type type)
 {
        struct ast_stream *stream;
@@ -71,11 +80,34 @@ struct ast_stream *ast_stream_create(const char *name, enum ast_media_type type)
 
        stream->type = type;
        stream->state = AST_STREAM_STATE_INACTIVE;
-       strcpy(stream->name, S_OR(name, ""));
+       strcpy(stream->name, S_OR(name, "")); /* Safe */
 
        return stream;
 }
 
+struct ast_stream *ast_stream_clone(const struct ast_stream *stream)
+{
+       struct ast_stream *new_stream;
+       size_t stream_size;
+
+       if (!stream) {
+               return NULL;
+       }
+
+       stream_size = sizeof(*stream) + strlen(stream->name) + 1;
+       new_stream = ast_calloc(1, stream_size);
+       if (!new_stream) {
+               return NULL;
+       }
+
+       memcpy(new_stream, stream, stream_size);
+       if (new_stream->formats) {
+               ao2_ref(new_stream->formats, +1);
+       }
+
+       return new_stream;
+}
+
 void ast_stream_destroy(struct ast_stream *stream)
 {
        if (!stream) {
@@ -88,41 +120,215 @@ void ast_stream_destroy(struct ast_stream *stream)
 
 const char *ast_stream_get_name(const struct ast_stream *stream)
 {
+       ast_assert(stream != NULL);
+
        return stream->name;
 }
 
 enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
 {
+       ast_assert(stream != NULL);
+
        return stream->type;
 }
 
 void ast_stream_set_type(struct ast_stream *stream, enum ast_media_type type)
 {
+       ast_assert(stream != NULL);
+
        stream->type = type;
 }
 
 struct ast_format_cap *ast_stream_get_formats(const struct ast_stream *stream)
 {
+       ast_assert(stream != NULL);
+
        return stream->formats;
 }
 
 void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps)
 {
+       ast_assert(stream != NULL);
+
        ao2_cleanup(stream->formats);
        stream->formats = ao2_bump(caps);
 }
 
 enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
 {
+       ast_assert(stream != NULL);
+
        return stream->state;
 }
 
 void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
 {
+       ast_assert(stream != NULL);
+
        stream->state = state;
 }
 
-unsigned int ast_stream_get_num(const struct ast_stream *stream)
+int ast_stream_get_position(const struct ast_stream *stream)
+{
+       ast_assert(stream != NULL);
+
+       return stream->position;
+}
+
+#define TOPOLOGY_INITIAL_STREAM_COUNT 2
+struct ast_stream_topology *ast_stream_topology_create(void)
+{
+       struct ast_stream_topology *topology;
+
+       topology = ast_calloc(1, sizeof(*topology));
+       if (!topology) {
+               return NULL;
+       }
+
+       if (AST_VECTOR_INIT(&topology->streams, TOPOLOGY_INITIAL_STREAM_COUNT)) {
+               ast_free(topology);
+               topology = NULL;
+       }
+
+       return topology;
+}
+
+struct ast_stream_topology *ast_stream_topology_clone(
+       const struct ast_stream_topology *topology)
+{
+       struct ast_stream_topology *new_topology;
+       int i;
+
+       ast_assert(topology != NULL);
+
+       new_topology = ast_stream_topology_create();
+       if (!new_topology) {
+               return NULL;
+       }
+
+       for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
+               struct ast_stream *stream =
+                       ast_stream_clone(AST_VECTOR_GET(&topology->streams, i));
+
+               if (!stream || AST_VECTOR_APPEND(&new_topology->streams, stream)) {
+                       ast_stream_destroy(stream);
+                       ast_stream_topology_destroy(new_topology);
+                       return NULL;
+               }
+       }
+
+       return new_topology;
+}
+
+void ast_stream_topology_destroy(struct ast_stream_topology *topology)
+{
+       if (!topology) {
+               return;
+       }
+
+       AST_VECTOR_CALLBACK_VOID(&topology->streams, ast_stream_destroy);
+       AST_VECTOR_FREE(&topology->streams);
+       ast_free(topology);
+}
+
+int ast_stream_topology_append_stream(struct ast_stream_topology *topology, struct ast_stream *stream)
+{
+       ast_assert(topology && stream);
+
+       if (AST_VECTOR_APPEND(&topology->streams, stream)) {
+               return -1;
+       }
+
+       return AST_VECTOR_SIZE(&topology->streams) - 1;
+}
+
+int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
+{
+       ast_assert(topology != NULL);
+
+       return AST_VECTOR_SIZE(&topology->streams);
+}
+
+struct ast_stream *ast_stream_topology_get_stream(
+       const struct ast_stream_topology *topology, unsigned int stream_num)
+{
+       ast_assert(topology != NULL);
+
+       return AST_VECTOR_GET(&topology->streams, stream_num);
+}
+
+int ast_stream_topology_set_stream(struct ast_stream_topology *topology,
+       unsigned int position, struct ast_stream *stream)
 {
-       return stream->num;
+       struct ast_stream *existing_stream;
+
+       ast_assert(topology && stream);
+
+       if (position > AST_VECTOR_SIZE(&topology->streams)) {
+               return -1;
+       }
+
+       existing_stream = AST_VECTOR_GET(&topology->streams, position);
+       ast_stream_destroy(existing_stream);
+
+       if (position == AST_VECTOR_SIZE(&topology->streams)) {
+               AST_VECTOR_APPEND(&topology->streams, stream);
+               return 0;
+       }
+
+       stream->position = position;
+       return AST_VECTOR_REPLACE(&topology->streams, position, stream);
+}
+
+struct ast_stream_topology *ast_stream_topology_create_from_format_cap(
+       struct ast_format_cap *cap)
+{
+       struct ast_stream_topology *topology;
+       enum ast_media_type type;
+
+       ast_assert(cap != NULL);
+
+       topology = ast_stream_topology_create();
+       if (!topology) {
+               return NULL;
+       }
+
+       for (type = AST_MEDIA_TYPE_UNKNOWN + 1; type < AST_MEDIA_TYPE_END; type++) {
+               struct ast_format_cap *new_cap;
+               struct ast_stream *stream;
+
+               if (!ast_format_cap_has_type(cap, type)) {
+                       continue;
+               }
+
+               new_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+               if (!new_cap) {
+                       ast_stream_topology_destroy(topology);
+                       return NULL;
+               }
+
+               ast_format_cap_set_framing(new_cap, ast_format_cap_get_framing(cap));
+               if (ast_format_cap_append_from_cap(new_cap, cap, type)) {
+                       ao2_cleanup(new_cap);
+                       ast_stream_topology_destroy(topology);
+                       return NULL;
+               }
+
+               stream = ast_stream_create(ast_codec_media_type2str(type), type);
+               if (!stream) {
+                       ao2_cleanup(new_cap);
+                       ast_stream_topology_destroy(topology);
+                       return NULL;
+               }
+               /* We're transferring the initial ref so no bump needed */
+               stream->formats = new_cap;
+               stream->state = AST_STREAM_STATE_SENDRECV;
+               if (!ast_stream_topology_append_stream(topology, stream)) {
+                       ast_stream_destroy(stream);
+                       ast_stream_topology_destroy(topology);
+                       return NULL;
+               }
+       }
+
+       return topology;
 }
index 4d6a1a168b98a17838e8561d064747adc260587a..e32d2b65f8d91b9e59f2b0094033d5a12334d21e 100644 (file)
@@ -87,7 +87,8 @@ static int media_type_to_fdno(enum ast_media_type media_type)
        case AST_MEDIA_TYPE_VIDEO: return FD_VIDEO;
        case AST_MEDIA_TYPE_TEXT:
        case AST_MEDIA_TYPE_UNKNOWN:
-       case AST_MEDIA_TYPE_IMAGE: break;
+       case AST_MEDIA_TYPE_IMAGE:
+       case AST_MEDIA_TYPE_END: break;
        }
        return -1;
 }