mirror of https://github.com/asterisk/asterisk
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: I3dbe54065b55aaa51f467e1a3bafd67fb48cac87changes/93/4893/3
parent
46147a8f30
commit
bab4885f1e
@ -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 */
|
@ -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;
|
||||
}
|
@ -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");
|
Loading…
Reference in new issue