From 621d886ca70dc12cdce52c6c7a0813d580e8988c Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 30 Nov 2016 10:48:39 -0600 Subject: Frame deferral: Re-queue deferred frames one-at-a-time. The recent change that made frame deferral into an API had a behavior change to it. When frame deferral was completed, we would take all of the deferred frames and queue them all onto the channel in one call to ast_queue_frame_head(). Before frame deferral was API-ized, places that performed manual frame deferral would actually take each deferred frame and queue them onto the channel. This change in behavior caused the confbridge_recording test to start failing consistently. Without going too crazily deep into the details, a channel was getting "stuck" in an ast_safe_sleep(). An AMI redirect was attempting to break it out of the sleep, but because there were more frames in the channel read queue than expected, the channel ended up being unable to break from its sleep loop. By restoring the behavior of individual frame queuing after deferral, the test starts passing again. Note, this points to a potential underlying issue pointing to an "unbalance" that can occur when queuing multiple frames at once, and so a follow-up issue is being created to investigate that possibility. Change-Id: Ied5dacacda06d343dea751ed5814a03364fe5a7d --- main/channel.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'main/channel.c') diff --git a/main/channel.c b/main/channel.c index bcfb8afa9..00cfa31aa 100644 --- a/main/channel.c +++ b/main/channel.c @@ -1070,16 +1070,15 @@ void ast_channel_start_defer_frames(struct ast_channel *chan, int defer_hangups) void ast_channel_stop_defer_frames(struct ast_channel *chan) { + struct ast_frame *f; + ast_clear_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES); /* Move the deferred frames onto the channel read queue, ahead of other queued frames */ - ast_queue_frame_head(chan, AST_LIST_FIRST(ast_channel_deferred_readq(chan))); - /* ast_frfree will mosey down the list and free them all */ - if (!AST_LIST_EMPTY(ast_channel_deferred_readq(chan))) { - ast_frfree(AST_LIST_FIRST(ast_channel_deferred_readq(chan))); + while ((f = AST_LIST_REMOVE_HEAD(ast_channel_deferred_readq(chan), frame_list))) { + ast_queue_frame_head(chan, f); + ast_frfree(f); } - /* Reset the list to be empty */ - AST_LIST_HEAD_INIT_NOLOCK(ast_channel_deferred_readq(chan)); } static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int head, struct ast_frame *after) @@ -3901,10 +3900,10 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) struct ast_frame *dup; dup = ast_frdup(f); - AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), dup, frame_list); + AST_LIST_INSERT_HEAD(ast_channel_deferred_readq(chan), dup, frame_list); } } else { - AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), f, frame_list); + AST_LIST_INSERT_HEAD(ast_channel_deferred_readq(chan), f, frame_list); AST_LIST_REMOVE_CURRENT(frame_list); } } -- cgit v1.2.3