From 430f6e5388b6e18b31e1a08582112838f6cc7557 Mon Sep 17 00:00:00 2001 From: Michael Walton Date: Wed, 5 Oct 2016 14:46:17 +1300 Subject: audiohooks: Remove redundant codec translations when using audiohooks The main frame read and write handlers in main/channel.c don't use the optimum placement in the processing flow for calling audiohooks callbacks, as far as codec translation is concerned. This change places the audiohooks callback code: * After the channel read translation if the frame is not linear before the translation, thereby increasing the chance that the frame is linear as required by audiohooks * Before the channel write translation if the frame is linear at this point This prevents the audiohooks code from instantiating additional translation paths to/from linear where a linear frame format is already available, saving valuable CPU cycles ASTERISK-26419 Change-Id: I6edd5771f0740e758e7eb42558b953f046c01f8f --- main/channel.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/main/channel.c b/main/channel.c index f3f79399f..c6cb925b8 100644 --- a/main/channel.c +++ b/main/channel.c @@ -3914,6 +3914,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) struct ast_frame *readq_tail = AST_LIST_LAST(ast_channel_readq(chan)); struct ast_control_read_action_payload *read_action_payload; struct ast_party_connected_line connected; + int hooked = 0; /* if the channel driver returned more than one frame, stuff the excess into the readq for the next ast_read call @@ -4191,15 +4192,22 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) break; } } - /* Send frame to audiohooks if present */ - if (ast_channel_audiohooks(chan)) { + /* + * Send frame to audiohooks if present, if frametype is linear, to preserve + * functional compatibility with previous behavior. If not linear, hold off + * until transcoding is done where we are more likely to have a linear frame + */ + if (ast_channel_audiohooks(chan) && ast_format_cache_is_slinear(f->subclass.format)) { + /* Place hooked after declaration */ struct ast_frame *old_frame = f; + hooked = 1; f = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_READ, f); if (old_frame != f) { ast_frfree(old_frame); } } + if (ast_channel_monitor(chan) && ast_channel_monitor(chan)->read_stream) { /* XXX what does this do ? */ #ifndef MONITOR_CONSTANT_DELAY @@ -4242,6 +4250,16 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) } } + /* Second chance at hooking a linear frame, also the last chance */ + if (ast_channel_audiohooks(chan) && !hooked) { + struct ast_frame *old_frame = f; + + f = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_READ, f); + if (old_frame != f) { + ast_frfree(old_frame); + } + } + /* * It is possible for the translation process on the channel to have * produced multiple frames from the single input frame we passed it; if @@ -5032,6 +5050,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) int res = -1; struct ast_frame *f = NULL; int count = 0; + int hooked = 0; /*Deadlock avoidance*/ while(ast_channel_trylock(chan)) { @@ -5149,6 +5168,22 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) apply_plc(chan, fr); } + /* + * Send frame to audiohooks if present, if frametype is linear (else, later as per + * previous behavior) + */ + if (ast_channel_audiohooks(chan)) { + if (ast_format_cache_is_slinear(fr->subclass.format)) { + struct ast_frame *old_frame; + hooked = 1; + old_frame = fr; + fr = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_WRITE, fr); + if (old_frame != fr) { + ast_frfree(old_frame); + } + } + } + /* 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) { f = fr; @@ -5186,7 +5221,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) break; } - if (ast_channel_audiohooks(chan)) { + if (ast_channel_audiohooks(chan) && !hooked) { struct ast_frame *prev = NULL, *new_frame, *cur, *dup; int freeoldlist = 0; -- cgit v1.2.3