summaryrefslogtreecommitdiff
path: root/tests/test_stream.c
diff options
context:
space:
mode:
authorJoshua Colp <jcolp@digium.com>2017-02-22 11:00:57 +0000
committerJoshua Colp <jcolp@digium.com>2017-02-23 18:31:15 +0000
commit6cc890b880a6d50b3236860c3ab89e26ba59a7d3 (patch)
tree2e3c881e0f076ed443d8d47230e1597a3dbb4df5 /tests/test_stream.c
parent911252d7b54f8ee7af30f71e26e7a26ef881d316 (diff)
channel: Add support for writing to a specific stream.
This change adds an ast_write_stream function which allows writing a frame to a specific media stream. It also moves ast_write() to using this underneath by writing media frames provided to it to the default streams of the channel. Existing functionality (such as audiohooks, framehooks, etc) are limited to being applied to the default stream only. Unit tests have also been added which test the behavior of both non-multistream and multistream channels to confirm that the write() and write_stream() callbacks are invoked appropriately. ASTERISK-26793 Change-Id: I4df20d1b65bd4d787fce0b4b478e19d2dfea245c
Diffstat (limited to 'tests/test_stream.c')
-rw-r--r--tests/test_stream.c419
1 files changed, 419 insertions, 0 deletions
diff --git a/tests/test_stream.c b/tests/test_stream.c
index 5134cfb50..d602d52fe 100644
--- a/tests/test_stream.c
+++ b/tests/test_stream.c
@@ -853,6 +853,421 @@ AST_TEST_DEFINE(stream_topology_channel_set)
return res;
}
+struct mock_channel_pvt {
+ unsigned int wrote;
+ unsigned int wrote_stream;
+ int stream_num;
+};
+
+static int mock_channel_write(struct ast_channel *chan, struct ast_frame *fr)
+{
+ struct mock_channel_pvt *pvt = ast_channel_tech_pvt(chan);
+
+ pvt->wrote = 1;
+
+ return 0;
+}
+
+static int mock_channel_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame *fr)
+{
+ struct mock_channel_pvt *pvt = ast_channel_tech_pvt(chan);
+
+ pvt->wrote_stream = 1;
+ pvt->stream_num = stream_num;
+
+ return 0;
+}
+
+static int mock_channel_hangup(struct ast_channel *chan)
+{
+ ast_channel_tech_pvt_set(chan, NULL);
+ return 0;
+}
+
+static const struct ast_channel_tech mock_channel_old_write_tech = {
+ .write = mock_channel_write,
+ .write_video = mock_channel_write,
+ .hangup = mock_channel_hangup,
+};
+
+AST_TEST_DEFINE(stream_write_non_multistream)
+{
+ RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
+ struct ast_channel *mock_channel;
+ struct mock_channel_pvt pvt;
+ enum ast_test_result_state res = AST_TEST_FAIL;
+ struct ast_frame frame = { 0, };
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "stream_write_non_multistream";
+ info->category = "/main/stream/";
+ info->summary = "stream writing to non-multistream capable channel test";
+ info->description =
+ "Test that writing frames to a non-multistream channel works as expected";
+ 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 channel nativeformats\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_format_cap_append(caps, ast_format_h264, 0)) {
+ ast_test_status_update(test, "Failed to append an h264 format to capabilities for channel nativeformats\n");
+ return AST_TEST_FAIL;
+ }
+
+ mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel");
+ if (!mock_channel) {
+ ast_test_status_update(test, "Failed to create a mock channel for testing\n");
+ return AST_TEST_FAIL;
+ }
+
+ ast_channel_tech_set(mock_channel, &mock_channel_old_write_tech);
+ ast_channel_nativeformats_set(mock_channel, caps);
+
+ pvt.wrote = 0;
+ ast_channel_tech_pvt_set(mock_channel, &pvt);
+ ast_channel_unlock(mock_channel);
+
+ frame.frametype = AST_FRAME_VOICE;
+ frame.subclass.format = ast_format_ulaw;
+
+ if (ast_write(mock_channel, &frame)) {
+ ast_test_status_update(test, "Failed to write a ulaw frame to the mock channel when it should be fine\n");
+ goto end;
+ }
+
+ if (!pvt.wrote) {
+ ast_test_status_update(test, "Successfully wrote a frame of ulaw but it never reached the channel driver\n");
+ goto end;
+ }
+
+ pvt.wrote = 0;
+
+ if (!ast_write_stream(mock_channel, 2, &frame) || pvt.wrote) {
+ ast_test_status_update(test, "Successfully wrote a frame of ulaw to a non-existent stream\n");
+ goto end;
+ }
+
+ frame.frametype = AST_FRAME_VIDEO;
+ frame.subclass.format = ast_format_h264;
+
+ if (ast_write(mock_channel, &frame)) {
+ ast_test_status_update(test, "Failed to write an h264 frame to the mock channel when it should be fine\n");
+ goto end;
+ }
+
+ if (!pvt.wrote) {
+ ast_test_status_update(test, "Successfully wrote a frame of h264 but it never reached the channel driver\n");
+ goto end;
+ }
+
+ res = AST_TEST_PASS;
+
+end:
+ ast_hangup(mock_channel);
+
+ return res;
+}
+
+static const struct ast_channel_tech mock_channel_write_stream_tech = {
+ .properties = AST_CHAN_TP_MULTISTREAM,
+ .write = mock_channel_write,
+ .write_video = mock_channel_write,
+ .write_stream = mock_channel_write_stream,
+ .hangup = mock_channel_hangup,
+};
+
+AST_TEST_DEFINE(stream_write_multistream)
+{
+ RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
+ struct ast_stream *stream;
+ struct ast_channel *mock_channel;
+ struct mock_channel_pvt pvt = { 0, };
+ enum ast_test_result_state res = AST_TEST_FAIL;
+ struct ast_frame frame = { 0, };
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "stream_write_multistream";
+ info->category = "/main/stream/";
+ info->summary = "stream writing to multistream capable channel test";
+ info->description =
+ "Test that writing frames to a multistream channel works as expected";
+ 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;
+ }
+
+ stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO);
+ if (!stream) {
+ ast_test_status_update(test, "Failed to create an audio stream for testing multistream writing\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_stream_topology_append_stream(topology, stream) == -1) {
+ ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
+ ast_stream_free(stream);
+ return AST_TEST_FAIL;
+ }
+
+ stream = ast_stream_alloc("audio2", AST_MEDIA_TYPE_AUDIO);
+ if (!stream) {
+ ast_test_status_update(test, "Failed to create an audio stream for testing multistream writing\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_stream_topology_append_stream(topology, stream) == -1) {
+ ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
+ ast_stream_free(stream);
+ return AST_TEST_FAIL;
+ }
+
+ stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO);
+ if (!stream) {
+ ast_test_status_update(test, "Failed to create a video stream for testing multistream writing\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_stream_topology_append_stream(topology, stream) == -1) {
+ ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
+ ast_stream_free(stream);
+ return AST_TEST_FAIL;
+ }
+
+ stream = ast_stream_alloc("video2", AST_MEDIA_TYPE_VIDEO);
+ if (!stream) {
+ ast_test_status_update(test, "Failed to create a video stream for testing multistream writing\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_stream_topology_append_stream(topology, stream) == -1) {
+ ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
+ ast_stream_free(stream);
+ return AST_TEST_FAIL;
+ }
+
+ 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 channel nativeformats\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_format_cap_append(caps, ast_format_h264, 0)) {
+ ast_test_status_update(test, "Failed to append an h264 format to capabilities for channel nativeformats\n");
+ return AST_TEST_FAIL;
+ }
+
+ mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel");
+ if (!mock_channel) {
+ ast_test_status_update(test, "Failed to create a mock channel for testing\n");
+ return AST_TEST_FAIL;
+ }
+
+ ast_channel_tech_set(mock_channel, &mock_channel_write_stream_tech);
+ ast_channel_set_stream_topology(mock_channel, topology);
+ ast_channel_nativeformats_set(mock_channel, caps);
+ topology = NULL;
+
+ ast_channel_tech_pvt_set(mock_channel, &pvt);
+ ast_channel_unlock(mock_channel);
+
+ frame.frametype = AST_FRAME_VOICE;
+ frame.subclass.format = ast_format_ulaw;
+ pvt.stream_num = -1;
+
+ if (ast_write(mock_channel, &frame)) {
+ ast_test_status_update(test, "Failed to write a ulaw frame to the mock channel when it should be fine\n");
+ goto end;
+ }
+
+ if (pvt.wrote) {
+ ast_test_status_update(test, "Successfully wrote a frame of ulaw but it ended up on the old write callback instead of write_stream\n");
+ goto end;
+ }
+
+ if (!pvt.wrote_stream) {
+ ast_test_status_update(test, "Successfully wrote a frame of ulaw but it never reached the channel driver\n");
+ goto end;
+ }
+
+ if (pvt.stream_num != 0) {
+ ast_test_status_update(test, "Successfully wrote a frame of ulaw to the default stream but it ended up on stream %d and not 0\n",
+ pvt.stream_num);
+ goto end;
+ }
+
+ pvt.wrote_stream = 0;
+ pvt.stream_num = -1;
+
+ if (ast_write_stream(mock_channel, 0, &frame)) {
+ ast_test_status_update(test, "Failed to write a ulaw frame to the first audio stream\n");
+ goto end;
+ }
+
+ if (pvt.wrote) {
+ ast_test_status_update(test, "Successfully wrote a frame of ulaw to the first audio stream but it ended up on the old write callback instead of write_stream\n");
+ goto end;
+ }
+
+ if (!pvt.wrote_stream) {
+ ast_test_status_update(test, "Successfully wrote a frame of ulaw to the first audio stream but it never reached the channel driver\n");
+ goto end;
+ }
+
+ if (pvt.stream_num != 0) {
+ ast_test_status_update(test, "Successfully wrote a frame of ulaw to the first audio stream but it ended up on stream %d and not 0\n",
+ pvt.stream_num);
+ goto end;
+ }
+
+ pvt.wrote_stream = 0;
+ pvt.stream_num = -1;
+
+ if (ast_write_stream(mock_channel, 1, &frame)) {
+ ast_test_status_update(test, "Failed to write a ulaw frame to the second audio stream\n");
+ goto end;
+ }
+
+ if (pvt.wrote) {
+ ast_test_status_update(test, "Successfully wrote a frame of ulaw to the second audio stream but it ended up on the old write callback instead of write_stream\n");
+ goto end;
+ }
+
+ if (!pvt.wrote_stream) {
+ ast_test_status_update(test, "Successfully wrote a frame of ulaw to the second audio stream but it never reached the channel driver\n");
+ goto end;
+ }
+
+ if (pvt.stream_num != 1) {
+ ast_test_status_update(test, "Successfully wrote a frame of ulaw to the second audio stream but it ended up on stream %d and not 1\n",
+ pvt.stream_num);
+ goto end;
+ }
+
+ pvt.wrote_stream = 0;
+ pvt.stream_num = -1;
+
+ frame.frametype = AST_FRAME_VIDEO;
+ frame.subclass.format = ast_format_h264;
+
+ if (ast_write(mock_channel, &frame)) {
+ ast_test_status_update(test, "Failed to write an h264 frame to the mock channel when it should be fine\n");
+ goto end;
+ }
+
+ if (pvt.wrote) {
+ ast_test_status_update(test, "Successfully wrote a frame of h264 but it ended up on the old write callback instead of write_stream\n");
+ goto end;
+ }
+
+ if (!pvt.wrote_stream) {
+ ast_test_status_update(test, "Successfully wrote a frame of h264 but it never reached the channel driver\n");
+ goto end;
+ }
+
+ if (pvt.stream_num != 2) {
+ ast_test_status_update(test, "Successfully wrote a frame of h264 to the default stream but it ended up on stream %d and not 2\n",
+ pvt.stream_num);
+ goto end;
+ }
+
+ pvt.wrote_stream = 0;
+ pvt.stream_num = -1;
+
+ if (ast_write_stream(mock_channel, 2, &frame)) {
+ ast_test_status_update(test, "Failed to write an h264 frame to the first video stream\n");
+ goto end;
+ }
+
+ if (pvt.wrote) {
+ ast_test_status_update(test, "Successfully wrote a frame of h264 to the first video stream but it ended up on the old write callback instead of write_stream\n");
+ goto end;
+ }
+
+ if (!pvt.wrote_stream) {
+ ast_test_status_update(test, "Successfully wrote a frame of h264 to the first video stream but it never reached the channel driver\n");
+ goto end;
+ }
+
+ if (pvt.stream_num != 2) {
+ ast_test_status_update(test, "Successfully wrote a frame of h264 to the first video stream but it ended up on stream %d and not 2\n",
+ pvt.stream_num);
+ goto end;
+ }
+
+ pvt.wrote_stream = 0;
+ pvt.stream_num = -1;
+
+ if (ast_write_stream(mock_channel, 3, &frame)) {
+ ast_test_status_update(test, "Failed to write an h264 frame to the second video stream\n");
+ goto end;
+ }
+
+ if (pvt.wrote) {
+ ast_test_status_update(test, "Successfully wrote a frame of h264 to the second video stream but it ended up on the old write callback instead of write_stream\n");
+ goto end;
+ }
+
+ if (!pvt.wrote_stream) {
+ ast_test_status_update(test, "Successfully wrote a frame of h264 to the second video stream but it never reached the channel driver\n");
+ goto end;
+ }
+
+ if (pvt.stream_num != 3) {
+ ast_test_status_update(test, "Successfully wrote a frame of h264 to the second video stream but it ended up on stream %d and not 3\n",
+ pvt.stream_num);
+ goto end;
+ }
+
+ pvt.wrote_stream = 0;
+ pvt.stream_num = -1;
+
+ if (!ast_write_stream(mock_channel, 9, &frame)) {
+ ast_test_status_update(test, "Successfully wrote a frame of h264 to a non-existent stream\n");
+ goto end;
+ }
+
+ if (pvt.wrote) {
+ ast_test_status_update(test, "Successfully wrote a frame of h264 to a non-existent stream and it ended up on the old write callback\n");
+ goto end;
+ }
+
+ if (pvt.wrote_stream) {
+ ast_test_status_update(test, "Successfully wrote a frame of h264 to a non-existent stream and it ended up on the write_stream callback\n");
+ goto end;
+ }
+
+ res = AST_TEST_PASS;
+
+end:
+ ast_hangup(mock_channel);
+
+ return res;
+}
+
static int unload_module(void)
{
AST_TEST_UNREGISTER(stream_create);
@@ -869,6 +1284,8 @@ static int unload_module(void)
AST_TEST_UNREGISTER(stream_topology_get_first_stream_by_type);
AST_TEST_UNREGISTER(stream_topology_create_from_channel_nativeformats);
AST_TEST_UNREGISTER(stream_topology_channel_set);
+ AST_TEST_UNREGISTER(stream_write_non_multistream);
+ AST_TEST_UNREGISTER(stream_write_multistream);
return 0;
}
@@ -887,6 +1304,8 @@ static int load_module(void)
AST_TEST_REGISTER(stream_topology_get_first_stream_by_type);
AST_TEST_REGISTER(stream_topology_create_from_channel_nativeformats);
AST_TEST_REGISTER(stream_topology_channel_set);
+ AST_TEST_REGISTER(stream_write_non_multistream);
+ AST_TEST_REGISTER(stream_write_multistream);
return AST_MODULE_LOAD_SUCCESS;
}