]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
stream: Add media stream definition and API with unit tests. 93/4893/3
authorJoshua Colp <jcolp@digium.com>
Tue, 7 Feb 2017 12:56:41 +0000 (12:56 +0000)
committerGeorge Joseph <gjoseph@digium.com>
Fri, 10 Feb 2017 16:58:03 +0000 (09:58 -0700)
This change adds the media stream definition and API for
accessing and using it. Unit tests have also been written
which exercise aspects of the API.

ASTERISK-26773

Change-Id: I3dbe54065b55aaa51f467e1a3bafd67fb48cac87

include/asterisk/stream.h [new file with mode: 0644]
main/stream.c [new file with mode: 0644]
tests/test_stream.c [new file with mode: 0644]

diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h
new file mode 100644 (file)
index 0000000..e73ed3f
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2017, Digium, Inc.
+ *
+ * Joshua Colp <jcolp@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Media Stream API
+ *
+ * \author Joshua Colp <jcolp@digium.com>
+ */
+
+#ifndef _AST_STREAM_H_
+#define _AST_STREAM_H_
+
+#include "asterisk/codec.h"
+
+/*!
+ * \brief Forward declaration for a stream, as it is opaque
+ */
+struct ast_stream;
+
+/*!
+ * \brief Forward declaration for a format capability
+ */
+struct ast_format_cap;
+
+/*!
+ * \brief States that a stream may be in
+ */
+enum ast_stream_state {
+    /*!
+     * \brief Set when the stream has been removed
+     */
+    AST_STREAM_STATE_REMOVED = 0,
+    /*!
+     * \brief Set when the stream is sending and receiving media
+     */
+    AST_STREAM_STATE_SENDRECV,
+    /*!
+     * \brief Set when the stream is sending media only
+     */
+    AST_STREAM_STATE_SENDONLY,
+    /*!
+     * \brief Set when the stream is receiving media only
+     */
+    AST_STREAM_STATE_RECVONLY,
+    /*!
+     * \brief Set when the stream is not sending OR receiving media
+     */
+    AST_STREAM_STATE_INACTIVE,
+};
+
+/*!
+ * \brief Create a new media stream representation
+ *
+ * \param name A name for the stream
+ * \param type The media type the stream is handling
+ *
+ * \retval non-NULL success
+ * \retval NULL failure
+ *
+ * \note This is NOT an AO2 object and has no locking. It is expected that a higher level object provides protection.
+ *
+ * \note The stream will default to an inactive state until changed.
+ *
+ * \since 15
+ */
+struct ast_stream *ast_stream_create(const char *name, enum ast_media_type type);
+
+/*!
+ * \brief Destroy a media stream representation
+ *
+ * \param stream The media stream
+ *
+ * \since 15
+ */
+void ast_stream_destroy(struct ast_stream *stream);
+
+/*!
+ * \brief Get the name of a stream
+ *
+ * \param stream The media stream
+ *
+ * \return The name of the stream
+ *
+ * \since 15
+ */
+const char *ast_stream_get_name(const struct ast_stream *stream);
+
+/*!
+ * \brief Get the media type of a stream
+ *
+ * \param stream The media stream
+ *
+ * \return The media type of the stream
+ *
+ * \since 15
+ */
+enum ast_media_type ast_stream_get_type(const struct ast_stream *stream);
+
+/*!
+ * \brief Change the media type of a stream
+ *
+ * \param stream The media stream
+ * \param type The new media type
+ *
+ * \since 15
+ */
+void ast_stream_set_type(struct ast_stream *stream, enum ast_media_type type);
+
+/*!
+ * \brief Get the current negotiated formats of a stream
+ *
+ * \param stream The media stream
+ *
+ * \return The negotiated media formats
+ *
+ * \note The reference count is not increased
+ *
+ * \since 15
+ */
+struct ast_format_cap *ast_stream_get_formats(const struct ast_stream *stream);
+
+/*!
+ * \brief Set the current negotiated formats of a stream
+ *
+ * \param stream The media stream
+ * \param caps The current negotiated formats
+ *
+ * \since 15
+ */
+void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps);
+
+/*!
+ * \brief Get the current state of a stream
+ *
+ * \param stream The media stream
+ *
+ * \return The state of the stream
+ *
+ * \since 15
+ */
+enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream);
+
+/*!
+ * \brief Set the state of a stream
+ *
+ * \param stream The media stream
+ * \param state The new state that the stream is in
+ *
+ * \note Used by stream creator to update internal state
+ *
+ * \since 15
+ */
+void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state);
+
+/*!
+ * \brief Get the number of the stream
+ *
+ * \param stream The media stream
+ *
+ * \return The number of the stream
+ *
+ * \since 15
+ */
+unsigned int ast_stream_get_num(const struct ast_stream *stream);
+
+#endif /* _AST_STREAM_H */
diff --git a/main/stream.c b/main/stream.c
new file mode 100644 (file)
index 0000000..fb3dbd5
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2017, Digium, Inc.
+ *
+ * Joshua Colp <jcolp@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Media Stream API
+ *
+ * \author Joshua Colp <jcolp@digium.com>
+ */
+
+/*** MODULEINFO
+       <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include "asterisk/logger.h"
+#include "asterisk/stream.h"
+#include "asterisk/strings.h"
+
+struct ast_stream {
+       /*!
+        * \brief The type of media the stream is handling
+        */
+       enum ast_media_type type;
+
+       /*!
+        * \brief Unique number for the stream within the context of the channel it is on
+        */
+       unsigned int num;
+
+       /*!
+        * \brief Current formats negotiated on the stream
+        */
+       struct ast_format_cap *formats;
+
+       /*!
+        * \brief The current state of the stream
+        */
+       enum ast_stream_state state;
+
+       /*!
+        * \brief Name for the stream within the context of the channel it is on
+        */
+       char name[0];
+};
+
+struct ast_stream *ast_stream_create(const char *name, enum ast_media_type type)
+{
+       struct ast_stream *stream;
+
+       stream = ast_calloc(1, sizeof(*stream) + strlen(S_OR(name, "")) + 1);
+       if (!stream) {
+               return NULL;
+       }
+
+       stream->type = type;
+       stream->state = AST_STREAM_STATE_INACTIVE;
+       strcpy(stream->name, S_OR(name, ""));
+
+       return stream;
+}
+
+void ast_stream_destroy(struct ast_stream *stream)
+{
+       if (!stream) {
+               return;
+       }
+
+       ao2_cleanup(stream->formats);
+       ast_free(stream);
+}
+
+const char *ast_stream_get_name(const struct ast_stream *stream)
+{
+       return stream->name;
+}
+
+enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
+{
+       return stream->type;
+}
+
+void ast_stream_set_type(struct ast_stream *stream, enum ast_media_type type)
+{
+       stream->type = type;
+}
+
+struct ast_format_cap *ast_stream_get_formats(const struct ast_stream *stream)
+{
+       return stream->formats;
+}
+
+void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps)
+{
+       ao2_cleanup(stream->formats);
+       stream->formats = ao2_bump(caps);
+}
+
+enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
+{
+       return stream->state;
+}
+
+void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
+{
+       stream->state = state;
+}
+
+unsigned int ast_stream_get_num(const struct ast_stream *stream)
+{
+       return stream->num;
+}
diff --git a/tests/test_stream.c b/tests/test_stream.c
new file mode 100644 (file)
index 0000000..fd78dda
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2017, Digium, Inc.
+ *
+ * Joshua Colp <jcolp@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Media Stream API Unit Tests
+ *
+ * \author Joshua Colp <jcolp@digium.com>
+ *
+ */
+
+/*** MODULEINFO
+       <depend>TEST_FRAMEWORK</depend>
+       <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include "asterisk/test.h"
+#include "asterisk/module.h"
+#include "asterisk/stream.h"
+#include "asterisk/format.h"
+#include "asterisk/format_cap.h"
+
+AST_TEST_DEFINE(stream_create)
+{
+       RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_destroy);
+
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "stream_create";
+               info->category = "/main/stream/";
+               info->summary = "stream create unit test";
+               info->description =
+                       "Test that creating a stream results in a stream with the expected values";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       stream = ast_stream_create("test", AST_MEDIA_TYPE_AUDIO);
+       if (!stream) {
+               ast_test_status_update(test, "Failed to create media stream given proper arguments\n");
+               return AST_TEST_FAIL;
+       }
+
+       if (ast_stream_get_state(stream) != AST_STREAM_STATE_INACTIVE) {
+               ast_test_status_update(test, "Newly created stream does not have expected inactive stream state\n");
+               return AST_TEST_FAIL;
+       }
+
+       if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_AUDIO) {
+               ast_test_status_update(test, "Newly created stream does not have expected audio media type\n");
+               return AST_TEST_FAIL;
+       }
+
+       if (strcmp(ast_stream_get_name(stream), "test")) {
+               ast_test_status_update(test, "Newly created stream does not have expected name of test\n");
+               return AST_TEST_FAIL;
+       }
+
+       return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(stream_create_no_name)
+{
+       RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_destroy);
+
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "stream_create_no_name";
+               info->category = "/main/stream/";
+               info->summary = "stream create (without a name) unit test";
+               info->description =
+                       "Test that creating a stream with no name works";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       stream = ast_stream_create(NULL, AST_MEDIA_TYPE_AUDIO);
+       if (!stream) {
+               ast_test_status_update(test, "Failed to create media stream given proper arguments\n");
+               return AST_TEST_FAIL;
+       }
+
+       return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(stream_set_type)
+{
+       RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_destroy);
+
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "stream_set_type";
+               info->category = "/main/stream/";
+               info->summary = "stream type setting unit test";
+               info->description =
+                       "Test that changing the type of a stream works";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       stream = ast_stream_create("test", AST_MEDIA_TYPE_AUDIO);
+       if (!stream) {
+               ast_test_status_update(test, "Failed to create media stream given proper arguments\n");
+               return AST_TEST_FAIL;
+       }
+
+       if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_AUDIO) {
+               ast_test_status_update(test, "Newly created stream does not have expected audio media type\n");
+               return AST_TEST_FAIL;
+       }
+
+       ast_stream_set_type(stream, AST_MEDIA_TYPE_VIDEO);
+
+       if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_VIDEO) {
+               ast_test_status_update(test, "Changed stream does not have expected video media type\n");
+               return AST_TEST_FAIL;
+       }
+
+       return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(stream_set_formats)
+{
+       RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_destroy);
+       RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
+
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "stream_set_formats";
+               info->category = "/main/stream/";
+               info->summary = "stream formats setting unit test";
+               info->description =
+                       "Test that changing the formats of a stream works";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+       if (!caps) {
+               ast_test_status_update(test, "Failed to create a format capabilities structure for testing\n");
+               return AST_TEST_FAIL;
+       }
+
+       stream = ast_stream_create("test", AST_MEDIA_TYPE_AUDIO);
+       if (!stream) {
+               ast_test_status_update(test, "Failed to create media stream given proper arguments\n");
+               return AST_TEST_FAIL;
+       }
+
+       ast_stream_set_formats(stream, caps);
+
+       if (ast_stream_get_formats(stream) != caps) {
+               ast_test_status_update(test, "Changed stream does not have expected formats\n");
+               return AST_TEST_FAIL;
+       }
+
+       ast_stream_set_formats(stream, NULL);
+
+       if (ast_stream_get_formats(stream)) {
+               ast_test_status_update(test, "Retrieved formats from stream despite removing them\n");
+               return AST_TEST_FAIL;
+       }
+
+       return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(stream_set_state)
+{
+       RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_destroy);
+
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "stream_set_state";
+               info->category = "/main/stream/";
+               info->summary = "stream state setting unit test";
+               info->description =
+                       "Test that changing the state of a stream works";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       stream = ast_stream_create("test", AST_MEDIA_TYPE_AUDIO);
+       if (!stream) {
+               ast_test_status_update(test, "Failed to create media stream given proper arguments\n");
+               return AST_TEST_FAIL;
+       }
+
+       if (ast_stream_get_state(stream) != AST_STREAM_STATE_INACTIVE) {
+               ast_test_status_update(test, "Newly created stream does not have expected inactive stream state\n");
+               return AST_TEST_FAIL;
+       }
+
+       ast_stream_set_state(stream, AST_STREAM_STATE_SENDRECV);
+
+       if (ast_stream_get_state(stream) != AST_STREAM_STATE_SENDRECV) {
+               ast_test_status_update(test, "Changed stream does not have expected sendrecv state\n");
+               return AST_TEST_FAIL;
+       }
+
+       return AST_TEST_PASS;
+}
+
+static int unload_module(void)
+{
+       AST_TEST_UNREGISTER(stream_create);
+       AST_TEST_UNREGISTER(stream_create_no_name);
+       AST_TEST_UNREGISTER(stream_set_type);
+       AST_TEST_UNREGISTER(stream_set_formats);
+       AST_TEST_UNREGISTER(stream_set_state);
+       return 0;
+}
+
+static int load_module(void)
+{
+       AST_TEST_REGISTER(stream_create);
+       AST_TEST_REGISTER(stream_create_no_name);
+       AST_TEST_REGISTER(stream_set_type);
+       AST_TEST_REGISTER(stream_set_formats);
+       AST_TEST_REGISTER(stream_set_state);
+       return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Media Stream API test module");