|  |  |  | @ -1061,6 +1061,26 @@ struct ast_channel *ast_dummy_channel_alloc(void) | 
			
		
	
		
			
				
					|  |  |  |  | 	return tmp; | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | void ast_channel_start_defer_frames(struct ast_channel *chan, int defer_hangups) | 
			
		
	
		
			
				
					|  |  |  |  | { | 
			
		
	
		
			
				
					|  |  |  |  | 	ast_set_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES); | 
			
		
	
		
			
				
					|  |  |  |  | 	ast_set2_flag(ast_channel_flags(chan), defer_hangups, AST_FLAG_DEFER_HANGUP_FRAMES); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | void ast_channel_stop_defer_frames(struct ast_channel *chan) | 
			
		
	
		
			
				
					|  |  |  |  | { | 
			
		
	
		
			
				
					|  |  |  |  | 	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))); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	/* 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) | 
			
		
	
		
			
				
					|  |  |  |  | { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct ast_frame *f; | 
			
		
	
	
		
			
				
					|  |  |  | @ -1533,6 +1553,10 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c | 
			
		
	
		
			
				
					|  |  |  |  | 		silgen = ast_channel_start_silence_generator(chan); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	ast_channel_lock(chan); | 
			
		
	
		
			
				
					|  |  |  |  | 	ast_channel_start_defer_frames(chan, 0); | 
			
		
	
		
			
				
					|  |  |  |  | 	ast_channel_unlock(chan); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	start = ast_tvnow(); | 
			
		
	
		
			
				
					|  |  |  |  | 	while ((ms = ast_remaining_ms(start, timeout_ms))) { | 
			
		
	
		
			
				
					|  |  |  |  | 		struct ast_frame *dup_f = NULL; | 
			
		
	
	
		
			
				
					|  |  |  | @ -3885,6 +3909,36 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) | 
			
		
	
		
			
				
					|  |  |  |  | 	if (!AST_LIST_EMPTY(ast_channel_readq(chan))) { | 
			
		
	
		
			
				
					|  |  |  |  | 		int skip_dtmf = should_skip_dtmf(chan); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES)) { | 
			
		
	
		
			
				
					|  |  |  |  | 			AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_readq(chan), f, frame_list) { | 
			
		
	
		
			
				
					|  |  |  |  | 				if (ast_is_deferrable_frame(f)) { | 
			
		
	
		
			
				
					|  |  |  |  | 					if(f->frametype == AST_FRAME_CONTROL &&  | 
			
		
	
		
			
				
					|  |  |  |  | 						(f->subclass.integer == AST_CONTROL_HANGUP || | 
			
		
	
		
			
				
					|  |  |  |  | 						 f->subclass.integer == AST_CONTROL_END_OF_Q)) { | 
			
		
	
		
			
				
					|  |  |  |  | 						/* Hangup is a special case. We want to defer the frame, but we also do not
 | 
			
		
	
		
			
				
					|  |  |  |  | 						 * want to remove it from the frame queue. So rather than just moving the frame | 
			
		
	
		
			
				
					|  |  |  |  | 						 * over, we duplicate it and move the copy to the deferred readq. | 
			
		
	
		
			
				
					|  |  |  |  | 						 * | 
			
		
	
		
			
				
					|  |  |  |  | 						 * The reason for this? This way, whoever calls ast_read() will get a NULL return | 
			
		
	
		
			
				
					|  |  |  |  | 						 * immediately and can tell the channel has hung up and do what it needs to. Also, | 
			
		
	
		
			
				
					|  |  |  |  | 						 * when frame deferral finishes, then whoever calls ast_read() next will also get | 
			
		
	
		
			
				
					|  |  |  |  | 						 * the hangup. | 
			
		
	
		
			
				
					|  |  |  |  | 						 */ | 
			
		
	
		
			
				
					|  |  |  |  | 						if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_HANGUP_FRAMES)) { | 
			
		
	
		
			
				
					|  |  |  |  | 							struct ast_frame *dup; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 							dup = ast_frdup(f); | 
			
		
	
		
			
				
					|  |  |  |  | 							AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), dup, frame_list); | 
			
		
	
		
			
				
					|  |  |  |  | 						} | 
			
		
	
		
			
				
					|  |  |  |  | 					} else { | 
			
		
	
		
			
				
					|  |  |  |  | 						AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), f, frame_list); | 
			
		
	
		
			
				
					|  |  |  |  | 						AST_LIST_REMOVE_CURRENT(frame_list); | 
			
		
	
		
			
				
					|  |  |  |  | 					} | 
			
		
	
		
			
				
					|  |  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 			AST_LIST_TRAVERSE_SAFE_END; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_readq(chan), f, frame_list) { | 
			
		
	
		
			
				
					|  |  |  |  | 			/* We have to be picky about which frame we pull off of the readq because
 | 
			
		
	
		
			
				
					|  |  |  |  | 			 * there are cases where we want to leave DTMF frames on the queue until | 
			
		
	
	
		
			
				
					|  |  |  | @ -10216,6 +10270,7 @@ int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struc | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		ast_party_connected_line_copy(ast_channel_connected(macro_chan), connected); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	ast_channel_start_defer_frames(macro_chan, 0); | 
			
		
	
		
			
				
					|  |  |  |  | 	ast_channel_unlock(macro_chan); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args); | 
			
		
	
	
		
			
				
					|  |  |  | @ -10266,6 +10321,7 @@ int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct a | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		ast_party_redirecting_copy(ast_channel_redirecting(macro_chan), redirecting); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	ast_channel_start_defer_frames(macro_chan, 0); | 
			
		
	
		
			
				
					|  |  |  |  | 	ast_channel_unlock(macro_chan); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args); | 
			
		
	
	
		
			
				
					|  |  |  | @ -10309,6 +10365,7 @@ int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		ast_party_connected_line_copy(ast_channel_connected(sub_chan), connected); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	ast_channel_start_defer_frames(sub_chan, 0); | 
			
		
	
		
			
				
					|  |  |  |  | 	ast_channel_unlock(sub_chan); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0); | 
			
		
	
	
		
			
				
					|  |  |  | @ -10352,6 +10409,7 @@ int ast_channel_redirecting_sub(struct ast_channel *autoservice_chan, struct ast | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		ast_party_redirecting_copy(ast_channel_redirecting(sub_chan), redirecting); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	ast_channel_start_defer_frames(sub_chan, 0); | 
			
		
	
		
			
				
					|  |  |  |  | 	ast_channel_unlock(sub_chan); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0); | 
			
		
	
	
		
			
				
					|  |  |  | 
 |