[Asterisk-code-review] stream: Add media stream topology definition and API (asterisk[master])
Anonymous Coward
asteriskteam at digium.com
Mon Feb 13 13:02:21 CST 2017
Anonymous Coward #1000019 has submitted this change and it was merged. ( https://gerrit.asterisk.org/4922 )
Change subject: stream: Add media stream topology definition and API
......................................................................
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
---
M include/asterisk/codec.h
M include/asterisk/stream.h
M main/format_cap.c
M main/stream.c
M res/res_pjsip_sdp_rtp.c
5 files changed, 359 insertions(+), 13 deletions(-)
Approvals:
Kevin Harwell: Looks good to me, but someone else must approve
Anonymous Coward #1000019: Verified
Joshua Colp: Looks good to me, approved
diff --git a/include/asterisk/codec.h b/include/asterisk/codec.h
index 3873324..2ae9551 100644
--- a/include/asterisk/codec.h
+++ b/include/asterisk/codec.h
@@ -33,6 +33,7 @@
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 e73ed3f..cffe6ea 100644
--- a/include/asterisk/stream.h
+++ b/include/asterisk/stream.h
@@ -39,6 +39,11 @@
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 @@
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 @@
*
* \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 @@
*
* \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 @@
* \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 @@
*
* \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 @@
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
*/
-unsigned int ast_stream_get_num(const struct ast_stream *stream);
+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
+ */
+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 1fe342b..b0897c0 100644
--- a/main/format_cap.c
+++ b/main/format_cap.c
@@ -268,6 +268,7 @@
{
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 fb3dbd5..0fabfc7 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 @@
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 @@
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,9 +80,32 @@
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)
@@ -88,41 +120,215 @@
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)
{
- return stream->num;
+ 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)
+{
+ 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 4d6a1a1..e32d2b6 100644
--- a/res/res_pjsip_sdp_rtp.c
+++ b/res/res_pjsip_sdp_rtp.c
@@ -87,7 +87,8 @@
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;
}
--
To view, visit https://gerrit.asterisk.org/4922
To unsubscribe, visit https://gerrit.asterisk.org/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Ic930232d24d5ad66dcabc14e9b359e0ff8e7f568
Gerrit-PatchSet: 5
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Anonymous Coward #1000019
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Kevin Harwell <kharwell at digium.com>
More information about the asterisk-code-review
mailing list