summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/asterisk/channel.h28
-rw-r--r--main/channel.c54
-rw-r--r--main/channel_internal_api.c9
-rw-r--r--tests/test_stream.c419
4 files changed, 498 insertions, 12 deletions
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 4170a8af4..80476a4e0 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -670,6 +670,9 @@ struct ast_channel_tech {
/*! \brief Write a frame, in standard format (see frame.h) */
int (* const write)(struct ast_channel *chan, struct ast_frame *frame);
+ /*! \brief Write a frame on a specific stream, in standard format (see frame.h) */
+ int (* const write_stream)(struct ast_channel *chan, int stream_num, struct ast_frame *frame);
+
/*! \brief Display or transmit text */
int (* const send_text)(struct ast_channel *chan, const char *text);
@@ -1968,6 +1971,18 @@ int ast_write_video(struct ast_channel *chan, struct ast_frame *frame);
*/
int ast_write_text(struct ast_channel *chan, struct ast_frame *frame);
+/*!
+ * \brief Write a frame to a stream
+ * This function writes the given frame to the indicated stream on the channel.
+ * \param chan destination channel of the frame
+ * \param stream_num destination stream on the channel
+ * \param frame frame that will be written
+ * \return It returns 0 on success, -1 on failure.
+ * \note If -1 is provided as the stream number and a media frame is provided the
+ * function will write to the default stream of the type of media.
+ */
+int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame *frame);
+
/*! \brief Send empty audio to prime a channel driver */
int ast_prod(struct ast_channel *chan);
@@ -4768,4 +4783,17 @@ struct ast_stream_topology *ast_channel_get_stream_topology(
struct ast_stream_topology *ast_channel_set_stream_topology(
struct ast_channel *chan, struct ast_stream_topology *topology);
+/*!
+ * \brief Retrieve the default stream of a specific media type on a channel
+ *
+ * \param channel The channel to get the stream from
+ * \param type The media type of the default stream
+ *
+ * \pre chan is locked
+ *
+ * \retval non-NULL success
+ * \retval NULL failure
+ */
+struct ast_stream *ast_channel_get_default_stream(struct ast_channel *chan, enum ast_media_type type);
+
#endif /* _ASTERISK_CHANNEL_H */
diff --git a/main/channel.c b/main/channel.c
index 1e7bc563e..183f8936f 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -5125,6 +5125,12 @@ static void apply_plc(struct ast_channel *chan, struct ast_frame *frame)
int ast_write(struct ast_channel *chan, struct ast_frame *fr)
{
+ return ast_write_stream(chan, -1, fr);
+}
+
+int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame *fr)
+{
+ struct ast_stream *stream = NULL, *default_stream = NULL;
int res = -1;
struct ast_frame *f = NULL;
int count = 0;
@@ -5139,13 +5145,28 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
}
usleep(1);
}
+
/* Stop if we're a zombie or need a soft hangup */
- if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) || ast_check_hangup(chan))
+ if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) || ast_check_hangup(chan)) {
goto done;
+ }
+
+ /* If this frame is writing an audio or video frame get the stream information */
+ if (fr->frametype == AST_FRAME_VOICE || fr->frametype == AST_FRAME_VIDEO) {
+ /* Initially use the default stream unless an explicit stream is provided */
+ stream = default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(fr->subclass.format));
+
+ if (stream_num >= 0) {
+ if (stream_num >= ast_stream_topology_get_count(ast_channel_get_stream_topology(chan))) {
+ goto done;
+ }
+ stream = ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), stream_num);
+ }
+ }
/* Perform the framehook write event here. After the frame enters the framehook list
* there is no telling what will happen, how awesome is that!!! */
- if (!(fr = ast_framehook_list_write_event(ast_channel_framehooks(chan), fr))) {
+ if ((stream == default_stream) && !(fr = ast_framehook_list_write_event(ast_channel_framehooks(chan), fr))) {
res = 0;
goto done;
}
@@ -5231,17 +5252,20 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
break;
case AST_FRAME_VIDEO:
/* XXX Handle translation of video codecs one day XXX */
- res = (ast_channel_tech(chan)->write_video == NULL) ? 0 :
- ast_channel_tech(chan)->write_video(chan, fr);
+ if (ast_channel_tech(chan)->write_stream) {
+ res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), fr);
+ } else if ((stream == default_stream) && ast_channel_tech(chan)->write_video) {
+ res = ast_channel_tech(chan)->write_video(chan, fr);
+ } else {
+ res = 0;
+
+ }
break;
case AST_FRAME_MODEM:
res = (ast_channel_tech(chan)->write == NULL) ? 0 :
ast_channel_tech(chan)->write(chan, fr);
break;
case AST_FRAME_VOICE:
- if (ast_channel_tech(chan)->write == NULL)
- break; /*! \todo XXX should return 0 maybe ? */
-
if (ast_opt_generic_plc && ast_format_cmp(fr->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) {
apply_plc(chan, fr);
}
@@ -5250,7 +5274,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
* Send frame to audiohooks if present, if frametype is linear (else, later as per
* previous behavior)
*/
- if (ast_channel_audiohooks(chan)) {
+ if ((stream == default_stream) && ast_channel_audiohooks(chan)) {
if (ast_format_cache_is_slinear(fr->subclass.format)) {
struct ast_frame *old_frame;
hooked = 1;
@@ -5263,7 +5287,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
}
/* If the frame is in the raw write format, then it's easy... just use the frame - otherwise we will have to translate */
- if (ast_format_cmp(fr->subclass.format, ast_channel_rawwriteformat(chan)) == AST_FORMAT_CMP_EQUAL) {
+ if ((stream != default_stream) || ast_format_cmp(fr->subclass.format, ast_channel_rawwriteformat(chan)) == AST_FORMAT_CMP_EQUAL) {
f = fr;
} else {
if (ast_format_cmp(ast_channel_writeformat(chan), fr->subclass.format) != AST_FORMAT_CMP_EQUAL) {
@@ -5299,7 +5323,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
break;
}
- if (ast_channel_audiohooks(chan) && !hooked) {
+ if ((stream == default_stream) && ast_channel_audiohooks(chan) && !hooked) {
struct ast_frame *prev = NULL, *new_frame, *cur, *dup;
int freeoldlist = 0;
@@ -5348,7 +5372,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
/* the translator on chan->writetrans may have returned multiple frames
from the single frame we passed in; if so, feed each one of them to the
monitor */
- if (ast_channel_monitor(chan) && ast_channel_monitor(chan)->write_stream) {
+ if ((stream == default_stream) && ast_channel_monitor(chan) && ast_channel_monitor(chan)->write_stream) {
struct ast_frame *cur;
for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
@@ -5415,7 +5439,13 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
/* reset f so the code below doesn't attempt to free it */
f = NULL;
} else {
- res = ast_channel_tech(chan)->write(chan, f);
+ if (ast_channel_tech(chan)->write_stream) {
+ res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), f);
+ } else if ((stream == default_stream) && ast_channel_tech(chan)->write) {
+ res = ast_channel_tech(chan)->write(chan, f);
+ } else {
+ res = 0;
+ }
}
break;
case AST_FRAME_NULL:
diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c
index 1934eb9a4..362bd1a3d 100644
--- a/main/channel_internal_api.c
+++ b/main/channel_internal_api.c
@@ -1816,6 +1816,15 @@ struct ast_stream_topology *ast_channel_set_stream_topology(struct ast_channel *
return new_topology;
}
+struct ast_stream *ast_channel_get_default_stream(struct ast_channel *chan,
+ enum ast_media_type type)
+{
+ ast_assert(chan != NULL);
+ ast_assert(type < AST_MEDIA_TYPE_END);
+
+ return chan->default_streams[type];
+}
+
void ast_channel_internal_swap_stream_topology(struct ast_channel *chan1,
struct ast_channel *chan2)
{
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;
}