summaryrefslogtreecommitdiff
path: root/main/channel.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 /main/channel.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 'main/channel.c')
-rw-r--r--main/channel.c54
1 files changed, 42 insertions, 12 deletions
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: