@ -1064,6 +1064,25 @@ struct ast_channel *__ast_dummy_channel_alloc(const char *file, int line, const
 
			
		
	
		
			
				
						return  tmp ; 
 
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					void  ast_channel_start_defer_frames ( struct  ast_channel  * chan )  
			
		
	
		
			
				
					{  
			
		
	
		
			
				
						ast_set_flag ( ast_channel_flags ( chan ) ,  AST_FLAG_DEFER_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 ; 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -1527,19 +1546,18 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c
 
			
		
	
		
			
				
						int  res  =  0 ; 
 
			
		
	
		
			
				
						struct  timeval  start ; 
 
			
		
	
		
			
				
						int  ms ; 
 
			
		
	
		
			
				
						AST_LIST_HEAD_NOLOCK ( ,  ast_frame )  deferred_frames ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						AST_LIST_HEAD_INIT_NOLOCK ( & deferred_frames ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						/* If no other generator is present, start silencegen while waiting */ 
 
			
		
	
		
			
				
						if  ( ast_opt_transmit_silence  & &  ! ast_channel_generatordata ( chan ) )  { 
 
			
		
	
		
			
				
							silgen  =  ast_channel_start_silence_generator ( chan ) ; 
 
			
		
	
		
			
				
						} 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						ast_channel_lock ( chan ) ; 
 
			
		
	
		
			
				
						ast_channel_start_defer_frames ( chan ) ; 
 
			
		
	
		
			
				
						ast_channel_unlock ( chan ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						start  =  ast_tvnow ( ) ; 
 
			
		
	
		
			
				
						while  ( ( ms  =  ast_remaining_ms ( start ,  timeout_ms ) ) )  { 
 
			
		
	
		
			
				
							struct  ast_frame  * dup_f  =  NULL ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
							if  ( cond  & &  ( ( * cond ) ( data )  = =  0 ) )  { 
 
			
		
	
		
			
				
								break ; 
 
			
		
	
		
			
				
							} 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1554,18 +1572,7 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c
 
			
		
	
		
			
				
									res  =  - 1 ; 
 
			
		
	
		
			
				
									break ; 
 
			
		
	
		
			
				
								} 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
								if  ( ! ast_is_deferrable_frame ( f ) )  { 
 
			
		
	
		
			
				
									ast_frfree ( f ) ; 
 
			
		
	
		
			
				
									continue ; 
 
			
		
	
		
			
				
								} 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
								if  ( ( dup_f  =  ast_frisolate ( f ) ) )  { 
 
			
		
	
		
			
				
									if  ( dup_f  ! =  f )  { 
 
			
		
	
		
			
				
										ast_frfree ( f ) ; 
 
			
		
	
		
			
				
									} 
 
			
		
	
		
			
				
									AST_LIST_INSERT_HEAD ( & deferred_frames ,  dup_f ,  frame_list ) ; 
 
			
		
	
		
			
				
								} 
 
			
		
	
		
			
				
								ast_frfree ( f ) ; 
 
			
		
	
		
			
				
							} 
 
			
		
	
		
			
				
						} 
 
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1574,17 +1581,8 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c
 
			
		
	
		
			
				
							ast_channel_stop_silence_generator ( chan ,  silgen ) ; 
 
			
		
	
		
			
				
						} 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						/* We need to free all the deferred frames, but we only need to
 
 
			
		
	
		
			
				
						 *  queue  the  deferred  frames  if  there  was  no  error  and  no 
 
			
		
	
		
			
				
						 *  hangup  was  received 
 
			
		
	
		
			
				
						 */ 
 
			
		
	
		
			
				
						ast_channel_lock ( chan ) ; 
 
			
		
	
		
			
				
						while  ( ( f  =  AST_LIST_REMOVE_HEAD ( & deferred_frames ,  frame_list ) ) )  { 
 
			
		
	
		
			
				
							if  ( ! res )  { 
 
			
		
	
		
			
				
								ast_queue_frame_head ( chan ,  f ) ; 
 
			
		
	
		
			
				
							} 
 
			
		
	
		
			
				
							ast_frfree ( f ) ; 
 
			
		
	
		
			
				
						} 
 
			
		
	
		
			
				
						ast_channel_stop_defer_frames ( chan ) ; 
 
			
		
	
		
			
				
						ast_channel_unlock ( chan ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						return  res ; 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -3885,6 +3883,32 @@ 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 )  { 
 
			
		
	
		
			
				
											struct  ast_frame  * dup ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
											/* 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 . 
 
			
		
	
		
			
				
											 */ 
 
			
		
	
		
			
				
											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,9 +10240,15 @@ 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 ) ; 
 
			
		
	
		
			
				
						ast_channel_unlock ( macro_chan ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						retval  =  ast_app_run_macro ( autoservice_chan ,  macro_chan ,  macro ,  macro_args ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						ast_channel_lock ( macro_chan ) ; 
 
			
		
	
		
			
				
						ast_channel_stop_defer_frames ( macro_chan ) ; 
 
			
		
	
		
			
				
						ast_channel_unlock ( macro_chan ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						if  ( ! retval )  { 
 
			
		
	
		
			
				
							struct  ast_party_connected_line  saved_connected ; 
 
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -10266,9 +10296,15 @@ 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 ) ; 
 
			
		
	
		
			
				
						ast_channel_unlock ( macro_chan ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						retval  =  ast_app_run_macro ( autoservice_chan ,  macro_chan ,  macro ,  macro_args ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						ast_channel_lock ( macro_chan ) ; 
 
			
		
	
		
			
				
						ast_channel_stop_defer_frames ( macro_chan ) ; 
 
			
		
	
		
			
				
						ast_channel_unlock ( macro_chan ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						if  ( ! retval )  { 
 
			
		
	
		
			
				
							struct  ast_party_redirecting  saved_redirecting ; 
 
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -10309,9 +10345,15 @@ 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 ) ; 
 
			
		
	
		
			
				
						ast_channel_unlock ( sub_chan ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						retval  =  ast_app_run_sub ( autoservice_chan ,  sub_chan ,  sub ,  sub_args ,  0 ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						ast_channel_lock ( sub_chan ) ; 
 
			
		
	
		
			
				
						ast_channel_stop_defer_frames ( sub_chan ) ; 
 
			
		
	
		
			
				
						ast_channel_unlock ( sub_chan ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						if  ( ! retval )  { 
 
			
		
	
		
			
				
							struct  ast_party_connected_line  saved_connected ; 
 
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -10352,9 +10394,15 @@ 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 ) ; 
 
			
		
	
		
			
				
						ast_channel_unlock ( sub_chan ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						retval  =  ast_app_run_sub ( autoservice_chan ,  sub_chan ,  sub ,  sub_args ,  0 ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						ast_channel_lock ( sub_chan ) ; 
 
			
		
	
		
			
				
						ast_channel_stop_defer_frames ( sub_chan ) ; 
 
			
		
	
		
			
				
						ast_channel_unlock ( sub_chan ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						if  ( ! retval )  { 
 
			
		
	
		
			
				
							struct  ast_party_redirecting  saved_redirecting ;