summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Joseph <gjoseph@digium.com>2017-02-10 14:45:43 -0700
committerGeorge Joseph <gjoseph@digium.com>2017-02-13 07:49:25 -0700
commit8b72ec312bd9fc439383a24d3f5c29b638758fd3 (patch)
tree4d3ca86c7ec86a9c7d5f297d8d012bb590b8e2fb
parentbab4885f1e923a252209db8b6011cf8a2fcb30c5 (diff)
stream: Add media stream topology definition and API
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
-rw-r--r--include/asterisk/codec.h1
-rw-r--r--include/asterisk/stream.h151
-rw-r--r--main/format_cap.c1
-rw-r--r--main/stream.c216
-rw-r--r--res/res_pjsip_sdp_rtp.c3
5 files changed, 359 insertions, 13 deletions
diff --git a/include/asterisk/codec.h b/include/asterisk/codec.h
index 3873324b1..2ae955181 100644
--- a/include/asterisk/codec.h
+++ b/include/asterisk/codec.h
@@ -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;
diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h
index e73ed3fe7..cffe6ea4c 100644
--- a/include/asterisk/stream.h
+++ b/include/asterisk/stream.h
@@ -39,6 +39,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
*/
enum ast_stream_state {
@@ -91,11 +96,24 @@ 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 */
diff --git a/main/format_cap.c b/main/format_cap.c
index 1fe342b31..b0897c001 100644
--- a/main/format_cap.c
+++ b/main/format_cap.c
@@ -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);
diff --git a/main/stream.c b/main/stream.c
index fb3dbd5ce..0fabfc738 100644
--- a/main/stream.c
+++ b/main/stream.c
@@ -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;
}
diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c
index 4d6a1a168..e32d2b65f 100644
--- a/res/res_pjsip_sdp_rtp.c
+++ b/res/res_pjsip_sdp_rtp.c
@@ -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;
}