Skip to content
Snippets Groups Projects
test_stream.c 77 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * 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"
    
    #include "asterisk/format_cache.h"
    
    #include "asterisk/channel.h"
    
    #include "asterisk/uuid.h"
    
    	RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_free);
    
    
    	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_alloc("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_free);
    
    
    	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_alloc(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_free);
    
    
    	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_alloc("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_free);
    
    	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_alloc("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_free);
    
    
    	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_alloc("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;
    }
    
    
    AST_TEST_DEFINE(stream_metadata)
    {
    	RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_free);
    	char track_label[AST_UUID_STR_LEN + 1];
    	const char *stream_track_label;
    	int rc;
    
    	switch (cmd) {
    	case TEST_INIT:
    		info->name = "stream_metadata";
    		info->category = "/main/stream/";
    		info->summary = "stream metadata unit test";
    		info->description =
    			"Test that metadata operations on a stream works";
    		return AST_TEST_NOT_RUN;
    	case TEST_EXECUTE:
    		break;
    	}
    
    	stream = ast_stream_alloc("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;
    	}
    
    	stream_track_label = ast_stream_get_metadata(stream, "AST_STREAM_METADATA_TRACK_LABEL");
    	if (stream_track_label) {
    		ast_test_status_update(test, "New stream HAD a track label\n");
    		return AST_TEST_FAIL;
    	}
    
    	ast_uuid_generate_str(track_label, sizeof(track_label));
    	rc = ast_stream_set_metadata(stream, "AST_STREAM_METADATA_TRACK_LABEL", track_label);
    	if (rc != 0) {
    		ast_test_status_update(test, "Failed to add track label\n");
    		return AST_TEST_FAIL;
    	}
    
    	stream_track_label = ast_stream_get_metadata(stream, "AST_STREAM_METADATA_TRACK_LABEL");
    	if (!stream_track_label) {
    		ast_test_status_update(test, "Changed stream does not have a track label\n");
    		return AST_TEST_FAIL;
    	}
    
    	if (strcmp(stream_track_label, track_label) != 0) {
    		ast_test_status_update(test, "Changed stream did not return same track label\n");
    		return AST_TEST_FAIL;
    	}
    
    	rc = ast_stream_set_metadata(stream, "AST_STREAM_METADATA_TRACK_LABEL", NULL);
    	if (rc != 0) {
    		ast_test_status_update(test, "Failed to remove track label\n");
    		return AST_TEST_FAIL;
    	}
    
    	stream_track_label = ast_stream_get_metadata(stream, "AST_STREAM_METADATA_TRACK_LABEL");
    	if (stream_track_label) {
    		ast_test_status_update(test, "Changed stream still had a track label after we removed it\n");
    		return AST_TEST_FAIL;
    	}
    
    	return AST_TEST_PASS;
    }
    
    
    AST_TEST_DEFINE(stream_topology_create)
    {
    
    	RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
    
    
    	switch (cmd) {
    	case TEST_INIT:
    		info->name = "stream_topology_create";
    		info->category = "/main/stream/";
    		info->summary = "stream topology creation unit test";
    		info->description =
    			"Test that creating a stream topology works";
    		return AST_TEST_NOT_RUN;
    	case TEST_EXECUTE:
    		break;
    	}
    
    
    	topology = ast_stream_topology_alloc();
    
    	if (!topology) {
    		ast_test_status_update(test, "Failed to create media stream topology\n");
    		return AST_TEST_FAIL;
    	}
    
    	return AST_TEST_PASS;
    }
    
    AST_TEST_DEFINE(stream_topology_clone)
    {
    
    	RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
    	RAII_VAR(struct ast_stream_topology *, cloned, NULL, ast_stream_topology_free);
    
    	struct ast_stream *audio_stream, *video_stream;
    
    	char audio_track_label[AST_UUID_STR_LEN + 1];
    	char video_track_label[AST_UUID_STR_LEN + 1];
    	const char *original_track_label;
    	const char *cloned_track_label;
    	int rc;
    
    
    	switch (cmd) {
    	case TEST_INIT:
    		info->name = "stream_topology_clone";
    		info->category = "/main/stream/";
    		info->summary = "stream topology cloning unit test";
    		info->description =
    			"Test that cloning a stream topology results in a clone with the same contents";
    		return AST_TEST_NOT_RUN;
    	case TEST_EXECUTE:
    		break;
    	}
    
    
    	topology = ast_stream_topology_alloc();
    
    	if (!topology) {
    		ast_test_status_update(test, "Failed to create media stream topology\n");
    		return AST_TEST_FAIL;
    	}
    
    
    	audio_stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO);
    
    	if (!audio_stream) {
    		ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n");
    		return AST_TEST_FAIL;
    	}
    
    
    	ast_uuid_generate_str(audio_track_label, sizeof(audio_track_label));
    	rc = ast_stream_set_metadata(audio_stream, "AST_STREAM_METADATA_TRACK_LABEL", audio_track_label);
    	if (rc != 0) {
    		ast_test_status_update(test, "Failed to add track label\n");
    		return AST_TEST_FAIL;
    	}
    
    
    	if (ast_stream_topology_append_stream(topology, audio_stream) == -1) {
    		ast_test_status_update(test, "Failed to append valid audio stream to stream topology\n");
    
    		ast_stream_free(audio_stream);
    
    	video_stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO);
    
    	if (!video_stream) {
    		ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n");
    		return AST_TEST_FAIL;
    	}
    
    
    	ast_uuid_generate_str(video_track_label, sizeof(video_track_label));
    	rc = ast_stream_set_metadata(video_stream, "AST_STREAM_METADATA_TRACK_LABEL", video_track_label);
    	if (rc != 0) {
    		ast_test_status_update(test, "Failed to add track label\n");
    		return AST_TEST_FAIL;
    	}
    
    
    	if (ast_stream_topology_append_stream(topology, video_stream) == -1) {
    		ast_test_status_update(test, "Failed to append valid video stream to stream topology\n");
    
    		ast_stream_free(video_stream);
    
    		return AST_TEST_FAIL;
    	}
    
    	cloned = ast_stream_topology_clone(topology);
    	if (!cloned) {
    		ast_test_status_update(test, "Failed to clone a perfectly good stream topology\n");
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_get_count(cloned) != ast_stream_topology_get_count(topology)) {
    		ast_test_status_update(test, "Cloned stream topology does not contain same number of streams as original\n");
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_get_type(ast_stream_topology_get_stream(cloned, 0)) != ast_stream_get_type(ast_stream_topology_get_stream(topology, 0))) {
    		ast_test_status_update(test, "Cloned audio stream does not contain same type as original\n");
    		return AST_TEST_FAIL;
    	}
    
    
    	original_track_label = ast_stream_get_metadata(ast_stream_topology_get_stream(topology, 0),
    		"AST_STREAM_METADATA_TRACK_LABEL");
    	if (!original_track_label) {
    		ast_test_status_update(test, "Original topology stream 0 does not contain metadata\n");
    		return AST_TEST_FAIL;
    	}
    	cloned_track_label = ast_stream_get_metadata(ast_stream_topology_get_stream(cloned, 0),
    		"AST_STREAM_METADATA_TRACK_LABEL");
    	if (!cloned_track_label) {
    		ast_test_status_update(test, "Cloned topology stream 0 does not contain metadata\n");
    		return AST_TEST_FAIL;
    	}
    	if (strcmp(original_track_label, cloned_track_label) != 0) {
    		ast_test_status_update(test, "Cloned topology stream 0 track label was not the same as the original\n");
    		return AST_TEST_FAIL;
    	}
    
    
    	if (ast_stream_get_type(ast_stream_topology_get_stream(cloned, 1)) != ast_stream_get_type(ast_stream_topology_get_stream(topology, 1))) {
    		ast_test_status_update(test, "Cloned video stream does not contain same type as original\n");
    		return AST_TEST_FAIL;
    	}
    
    
    	original_track_label = ast_stream_get_metadata(ast_stream_topology_get_stream(topology, 1),
    		"AST_STREAM_METADATA_TRACK_LABEL");
    	if (!original_track_label) {
    		ast_test_status_update(test, "Original topology stream 1 does not contain metadata\n");
    		return AST_TEST_FAIL;
    	}
    	cloned_track_label = ast_stream_get_metadata(ast_stream_topology_get_stream(cloned, 1),
    		"AST_STREAM_METADATA_TRACK_LABEL");
    	if (!cloned_track_label) {
    		ast_test_status_update(test, "Cloned topology stream 1 does not contain metadata\n");
    		return AST_TEST_FAIL;
    	}
    	if (strcmp(original_track_label, cloned_track_label) != 0) {
    		ast_test_status_update(test, "Cloned topology stream 1 track label was not the same as the original\n");
    		return AST_TEST_FAIL;
    	}
    
    
    	return AST_TEST_PASS;
    }
    
    AST_TEST_DEFINE(stream_topology_append_stream)
    {
    
    	RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
    
    	struct ast_stream *audio_stream, *video_stream;
    	int position;
    
    	switch (cmd) {
    	case TEST_INIT:
    		info->name = "stream_topology_append_stream";
    		info->category = "/main/stream/";
    		info->summary = "stream topology stream appending unit test";
    		info->description =
    			"Test that appending streams to a stream topology works";
    		return AST_TEST_NOT_RUN;
    	case TEST_EXECUTE:
    		break;
    	}
    
    
    	topology = ast_stream_topology_alloc();
    
    	if (!topology) {
    		ast_test_status_update(test, "Failed to create media stream topology\n");
    		return AST_TEST_FAIL;
    	}
    
    
    	audio_stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO);
    
    	if (!audio_stream) {
    		ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n");
    		return AST_TEST_FAIL;
    	}
    
    	position = ast_stream_topology_append_stream(topology, audio_stream);
    	if (position == -1) {
    		ast_test_status_update(test, "Failed to append valid audio stream to stream topology\n");
    
    		ast_stream_free(audio_stream);
    
    		return AST_TEST_FAIL;
    	} else if (position != 0) {
    		ast_test_status_update(test, "Appended audio stream to stream topology but position is '%d' instead of 0\n",
    			position);
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_get_count(topology) != 1) {
    		ast_test_status_update(test, "Appended an audio stream to the stream topology but stream count is '%d' on it, not 1\n",
    			ast_stream_topology_get_count(topology));
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_get_stream(topology, 0) != audio_stream) {
    		ast_test_status_update(test, "Appended an audio stream to the stream topology but returned stream doesn't match\n");
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_get_position(audio_stream) != 0) {
    		ast_test_status_update(test, "Appended audio stream says it is at position '%d' instead of 0\n",
    			ast_stream_get_position(audio_stream));
    		return AST_TEST_FAIL;
    	}
    
    
    	video_stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO);
    
    	if (!video_stream) {
    		ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n");
    		return AST_TEST_FAIL;
    	}
    
    	position = ast_stream_topology_append_stream(topology, video_stream);
    	if (position == -1) {
    		ast_test_status_update(test, "Failed to append valid video stream to stream topology\n");
    
    		ast_stream_free(video_stream);
    
    		return AST_TEST_FAIL;
    	} else if (position != 1) {
    		ast_test_status_update(test, "Appended video stream to stream topology but position is '%d' instead of 1\n",
    			position);
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_get_count(topology) != 2) {
    		ast_test_status_update(test, "Appended a video stream to the stream topology but stream count is '%d' on it, not 2\n",
    			ast_stream_topology_get_count(topology));
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_get_stream(topology, 1) != video_stream) {
    		ast_test_status_update(test, "Appended a video stream to the stream topology but returned stream doesn't match\n");
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_get_position(video_stream) != 1) {
    		ast_test_status_update(test, "Appended video stream says it is at position '%d' instead of 1\n",
    			ast_stream_get_position(video_stream));
    		return AST_TEST_FAIL;
    	}
    
    	return AST_TEST_PASS;
    }
    
    AST_TEST_DEFINE(stream_topology_set_stream)
    {
    
    	RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
    
    	struct ast_stream *audio_stream, *video_stream;
    
    	switch (cmd) {
    	case TEST_INIT:
    		info->name = "stream_topology_set_stream";
    		info->category = "/main/stream/";
    		info->summary = "stream topology stream setting unit test";
    		info->description =
    			"Test that setting streams at a specific position in a topology works";
    		return AST_TEST_NOT_RUN;
    	case TEST_EXECUTE:
    		break;
    	}
    
    
    	topology = ast_stream_topology_alloc();
    
    	if (!topology) {
    		ast_test_status_update(test, "Failed to create media stream topology\n");
    		return AST_TEST_FAIL;
    	}
    
    
    	audio_stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO);
    
    	if (!audio_stream) {
    		ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n");
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_set_stream(topology, 0, audio_stream)) {
    		ast_test_status_update(test, "Failed to set an audio stream to a position where it is permitted\n");
    
    		ast_stream_free(audio_stream);
    
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_get_count(topology) != 1) {
    		ast_test_status_update(test, "Set an audio stream on the stream topology but stream count is '%d' on it, not 1\n",
    			ast_stream_topology_get_count(topology));
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_get_stream(topology, 0) != audio_stream) {
    		ast_test_status_update(test, "Set an audio stream on the stream topology but returned stream doesn't match\n");
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_get_position(audio_stream) != 0) {
    		ast_test_status_update(test, "Set audio stream says it is at position '%d' instead of 0\n",
    			ast_stream_get_position(audio_stream));
    		return AST_TEST_FAIL;
    	}
    
    
    	video_stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO);
    
    	if (!video_stream) {
    		ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n");
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_set_stream(topology, 0, video_stream)) {
    		ast_test_status_update(test, "Failed to set a video stream to a position where it is permitted\n");
    
    		ast_stream_free(video_stream);
    
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_get_count(topology) != 1) {
    		ast_test_status_update(test, "Set a video stream on the stream topology but stream count is '%d' on it, not 1\n",
    			ast_stream_topology_get_count(topology));
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_get_stream(topology, 0) != video_stream) {
    		ast_test_status_update(test, "Set a video stream on the stream topology but returned stream doesn't match\n");
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_get_position(video_stream) != 0) {
    		ast_test_status_update(test, "Set video stream says it is at position '%d' instead of 0\n",
    			ast_stream_get_position(video_stream));
    		return AST_TEST_FAIL;
    	}
    
    
    	audio_stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO);
    
    	if (!audio_stream) {
    		ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n");
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_set_stream(topology, 1, audio_stream)) {
    		ast_test_status_update(test, "Failed to set an audio stream to a position where it is permitted\n");
    
    		ast_stream_free(audio_stream);
    
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_get_count(topology) != 2) {
    		ast_test_status_update(test, "Set an audio stream on the stream topology but stream count is '%d' on it, not 2\n",
    			ast_stream_topology_get_count(topology));
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_get_stream(topology, 1) != audio_stream) {
    		ast_test_status_update(test, "Set an audio stream on the stream topology but returned stream doesn't match\n");
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_get_position(audio_stream) != 1) {
    		ast_test_status_update(test, "Set audio stream says it is at position '%d' instead of 1\n",
    			ast_stream_get_position(audio_stream));
    		return AST_TEST_FAIL;
    	}
    
    	return AST_TEST_PASS;
    }
    
    
    static int check_stream_positions(struct ast_test *test, const struct ast_stream_topology *topology)
    {
    	const struct ast_stream *stream;
    	int idx;
    	int pos;
    	enum ast_media_type type;
    
    	for (idx = 0; idx < ast_stream_topology_get_count(topology); ++idx) {
    		stream = ast_stream_topology_get_stream(topology, idx);
    		pos = ast_stream_get_position(stream);
    		if (idx != pos) {
    			type = ast_stream_get_type(stream);
    			ast_test_status_update(test, "Failed: '%s' stream says it is at position %d instead of %d\n",
    				ast_codec_media_type2str(type), pos, idx);
    			return -1;
    		}
    	}
    	return 0;
    }
    
    AST_TEST_DEFINE(stream_topology_del_stream)
    {
    	RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
    	struct ast_stream *stream;
    	enum ast_media_type type;
    	int idx;
    
    	switch (cmd) {
    	case TEST_INIT:
    		info->name = "stream_topology_del_stream";
    		info->category = "/main/stream/";
    		info->summary = "stream topology stream delete unit test";
    		info->description =
    			"Test that deleting streams at a specific position in a topology works";
    		return AST_TEST_NOT_RUN;
    	case TEST_EXECUTE:
    		break;
    	}
    
    	topology = ast_stream_topology_alloc();
    	if (!topology) {
    		ast_test_status_update(test, "Failed to create media stream topology\n");
    		return AST_TEST_FAIL;
    	}
    
    	/* Create streams */
    	for (type = AST_MEDIA_TYPE_UNKNOWN; type < AST_MEDIA_TYPE_END; ++type) {
    		stream = ast_stream_alloc(ast_codec_media_type2str(type), type);
    		if (!stream) {
    			ast_test_status_update(test, "Failed to create '%s' stream for testing stream topology\n",
    				ast_codec_media_type2str(type));
    			return AST_TEST_FAIL;
    		}
    		if (ast_stream_topology_append_stream(topology, stream) == -1) {
    			ast_test_status_update(test, "Failed to append '%s' stream to topology\n",
    				ast_codec_media_type2str(type));
    			ast_stream_free(stream);
    			return AST_TEST_FAIL;
    		}
    	}
    
    	/* Check initial stream positions and types for sanity. */
    	type = AST_MEDIA_TYPE_UNKNOWN;
    	for (idx = 0; idx < ast_stream_topology_get_count(topology); ++idx, ++type) {
    		stream = ast_stream_topology_get_stream(topology, idx);
    		if (type != ast_stream_get_type(stream)) {
    			ast_test_status_update(test, "Initial topology types failed: Expected:%s Got:%s\n",
    				ast_codec_media_type2str(type),
    				ast_codec_media_type2str(ast_stream_get_type(stream)));
    			return AST_TEST_FAIL;
    		}
    	}
    	if (check_stream_positions(test, topology)) {
    		ast_test_status_update(test, "Initial topology positions failed.\n");
    		return AST_TEST_FAIL;
    	}
    
    	/* Try to delete outside of topology size */
    	if (!ast_stream_topology_del_stream(topology, ast_stream_topology_get_count(topology))) {
    		ast_test_status_update(test, "Deleting stream outside of topology succeeded!\n");
    		return AST_TEST_FAIL;
    	}
    
    	/* Try to delete the last topology stream */
    	if (ast_stream_topology_del_stream(topology, ast_stream_topology_get_count(topology) - 1)) {
    		ast_test_status_update(test, "Failed deleting last stream of topology.\n");
    		return AST_TEST_FAIL;
    	}
    	if (check_stream_positions(test, topology)) {
    		ast_test_status_update(test, "Last stream delete topology positions failed.\n");
    		return AST_TEST_FAIL;
    	}
    	stream = ast_stream_topology_get_stream(topology, ast_stream_topology_get_count(topology) - 1);
    	type = ast_stream_get_type(stream);
    	if (type != AST_MEDIA_TYPE_END - 2) {
    		ast_test_status_update(test, "Last stream delete types failed: Expected:%s Got:%s\n",
    			ast_codec_media_type2str(AST_MEDIA_TYPE_END - 2),
    			ast_codec_media_type2str(type));
    		return AST_TEST_FAIL;
    	}
    
    	/* Try to delete the second stream in the topology */
    	if (ast_stream_topology_del_stream(topology, 1)) {
    		ast_test_status_update(test, "Failed deleting second stream in topology.\n");
    		return AST_TEST_FAIL;
    	}
    	if (check_stream_positions(test, topology)) {
    		ast_test_status_update(test, "Second stream delete topology positions failed.\n");
    		return AST_TEST_FAIL;
    	}
    	stream = ast_stream_topology_get_stream(topology, 1);
    	type = ast_stream_get_type(stream);
    	if (type != AST_MEDIA_TYPE_UNKNOWN + 2) {
    		ast_test_status_update(test, "Second stream delete types failed: Expected:%s Got:%s\n",
    			ast_codec_media_type2str(AST_MEDIA_TYPE_UNKNOWN + 2),
    			ast_codec_media_type2str(type));
    		return AST_TEST_FAIL;
    	}
    
    	/* Try to delete the first stream in the topology */
    	if (ast_stream_topology_del_stream(topology, 0)) {
    		ast_test_status_update(test, "Failed deleting first stream in topology.\n");
    		return AST_TEST_FAIL;
    	}
    	if (check_stream_positions(test, topology)) {
    		ast_test_status_update(test, "First stream delete topology positions failed.\n");
    		return AST_TEST_FAIL;
    	}
    	stream = ast_stream_topology_get_stream(topology, 0);
    	type = ast_stream_get_type(stream);
    	if (type != AST_MEDIA_TYPE_UNKNOWN + 2) {
    		ast_test_status_update(test, "First stream delete types failed: Expected:%s Got:%s\n",
    			ast_codec_media_type2str(AST_MEDIA_TYPE_UNKNOWN + 2),
    			ast_codec_media_type2str(type));
    		return AST_TEST_FAIL;
    	}
    
    	return AST_TEST_PASS;
    }
    
    
    AST_TEST_DEFINE(stream_topology_create_from_format_cap)
    {
    
    	RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
    
    	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
    
    	switch (cmd) {
    	case TEST_INIT:
    		info->name = "stream_topology_create_from_format_cap";
    		info->category = "/main/stream/";
    		info->summary = "stream topology creation from format capabilities unit test";
    		info->description =
    			"Test that creating a stream topology from format capabilities results in the expected streams";
    		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, "Could not allocate an empty format capabilities structure\n");
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_format_cap_append(caps, ast_format_ulaw, 0)) {
    		ast_test_status_update(test, "Failed to append a ulaw format to capabilities for stream topology creation\n");
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_format_cap_append(caps, ast_format_alaw, 0)) {
    		ast_test_status_update(test, "Failed to append an alaw format to capabilities for stream topology creation\n");
    		return AST_TEST_FAIL;
    	}
    
    	topology = ast_stream_topology_create_from_format_cap(caps);
    	if (!topology) {
    		ast_test_status_update(test, "Failed to create a stream topology using a perfectly good format capabilities\n");
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_get_count(topology) != 1) {
    		ast_test_status_update(test, "Expected a stream topology with 1 stream but it has %d streams\n",
    			ast_stream_topology_get_count(topology));
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_get_type(ast_stream_topology_get_stream(topology, 0)) != AST_MEDIA_TYPE_AUDIO) {
    		ast_test_status_update(test, "Produced stream topology has a single stream of type %s instead of audio\n",
    			ast_codec_media_type2str(ast_stream_get_type(ast_stream_topology_get_stream(topology, 0))));
    		return AST_TEST_FAIL;
    	}
    
    
    	ast_stream_topology_free(topology);
    
    	topology = NULL;
    
    	ast_format_cap_append(caps, ast_format_h264, 0);
    
    	topology = ast_stream_topology_create_from_format_cap(caps);
    	if (!topology) {
    		ast_test_status_update(test, "Failed to create a stream topology using a perfectly good format capabilities\n");
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_get_count(topology) != 2) {
    		ast_test_status_update(test, "Expected a stream topology with 2 streams but it has %d streams\n",
    			ast_stream_topology_get_count(topology));
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_get_type(ast_stream_topology_get_stream(topology, 0)) != AST_MEDIA_TYPE_AUDIO) {
    		ast_test_status_update(test, "Produced stream topology has a first stream of type %s instead of audio\n",
    			ast_codec_media_type2str(ast_stream_get_type(ast_stream_topology_get_stream(topology, 0))));
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_get_type(ast_stream_topology_get_stream(topology, 1)) != AST_MEDIA_TYPE_VIDEO) {
    		ast_test_status_update(test, "Produced stream topology has a second stream of type %s instead of video\n",
    			ast_codec_media_type2str(ast_stream_get_type(ast_stream_topology_get_stream(topology, 1))));
    		return AST_TEST_FAIL;
    	}
    
    	return AST_TEST_PASS;
    }
    
    
    AST_TEST_DEFINE(stream_topology_get_first_stream_by_type)
    {
    
    	RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
    
    	struct ast_stream *first_stream;
    	struct ast_stream *second_stream;
    	struct ast_stream *third_stream;
    	struct ast_stream *fourth_stream;
    	struct ast_stream *fifth_stream;
    	struct ast_stream *sixth_stream;
    
    
    	switch (cmd) {
    	case TEST_INIT:
    		info->name = "stream_topology_get_first_stream_by_type";
    		info->category = "/main/stream/";
    		info->summary = "stream topology getting first stream by type unit test";
    		info->description =
    			"Test that getting the first stream by type from a topology actually returns the first stream";
    		return AST_TEST_NOT_RUN;
    	case TEST_EXECUTE:
    		break;
    	}
    
    
    	topology = ast_stream_topology_alloc();
    
    	if (!topology) {
    		ast_test_status_update(test, "Failed to create media stream topology\n");
    		return AST_TEST_FAIL;
    	}
    
    
    	first_stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO);
    
    	if (!first_stream) {
    		ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n");
    		return AST_TEST_FAIL;
    	}
    
    	ast_stream_set_state(first_stream, AST_STREAM_STATE_REMOVED);
    
    
    	if (ast_stream_topology_append_stream(topology, first_stream) == -1) {
    		ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
    
    		ast_stream_free(first_stream);
    
    	second_stream = ast_stream_alloc("audio2", AST_MEDIA_TYPE_AUDIO);
    
    	if (!second_stream) {
    		ast_test_status_update(test, "Failed to create a second audio stream for testing stream topology\n");
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_append_stream(topology, second_stream) == -1) {
    		ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
    
    		ast_stream_free(second_stream);
    
    	third_stream = ast_stream_alloc("audio3", AST_MEDIA_TYPE_AUDIO);
    
    	if (!third_stream) {
    
    		ast_test_status_update(test, "Failed to create a third audio stream for testing stream topology\n");
    
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_append_stream(topology, third_stream) == -1) {
    		ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
    
    		ast_stream_free(third_stream);
    
    	fourth_stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO);
    
    	if (!fourth_stream) {
    
    		ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n");
    
    		return AST_TEST_FAIL;
    	}
    
    	ast_stream_set_state(fourth_stream, AST_STREAM_STATE_REMOVED);
    
    
    	if (ast_stream_topology_append_stream(topology, fourth_stream) == -1) {
    		ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
    
    		ast_stream_free(fourth_stream);
    
    	fifth_stream = ast_stream_alloc("video2", AST_MEDIA_TYPE_VIDEO);
    	if (!fifth_stream) {
    		ast_test_status_update(test, "Failed to create a second video stream for testing stream topology\n");
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_append_stream(topology, fifth_stream) == -1) {
    		ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
    		ast_stream_free(fifth_stream);
    		return AST_TEST_FAIL;
    	}
    
    	sixth_stream = ast_stream_alloc("video3", AST_MEDIA_TYPE_VIDEO);
    	if (!sixth_stream) {
    		ast_test_status_update(test, "Failed to create a third video stream for testing stream topology\n");
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_append_stream(topology, sixth_stream) == -1) {
    		ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
    		ast_stream_free(sixth_stream);
    		return AST_TEST_FAIL;
    	}
    
    	if (ast_stream_topology_get_first_stream_by_type(topology, AST_MEDIA_TYPE_AUDIO) != second_stream) {
    
    		ast_test_status_update(test, "Retrieved first audio stream from topology but it is not the correct one\n");
    		return AST_TEST_FAIL;
    	}
    
    
    	if (ast_stream_topology_get_first_stream_by_type(topology, AST_MEDIA_TYPE_VIDEO) != fifth_stream) {
    
    		ast_test_status_update(test, "Retrieved first video stream from topology but it is not the correct one\n");
    		return AST_TEST_FAIL;
    	}
    
    	return AST_TEST_PASS;
    }
    
    static const struct ast_channel_tech mock_channel_tech = {
    };
    
    AST_TEST_DEFINE(stream_topology_create_from_channel_nativeformats)
    {
    
    	RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
    
    	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
    	struct ast_channel *mock_channel;
    	enum ast_test_result_state res = AST_TEST_FAIL;
    	struct ast_str *codec_have_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
    	struct ast_str *codec_wanted_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
    
    	switch (cmd) {