2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								/***
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    This  file  is  part  of  PulseAudio . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    Copyright  2010  Intel  Corporation 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    Contributor :  Pierre - Louis  Bossart  < pierre - louis . bossart @ intel . com > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    PulseAudio  is  free  software ;  you  can  redistribute  it  and / or  modify 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    it  under  the  terms  of  the  GNU  Lesser  General  Public  License  as  published 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    by  the  Free  Software  Foundation ;  either  version  2.1  of  the  License , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    or  ( at  your  option )  any  later  version . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    PulseAudio  is  distributed  in  the  hope  that  it  will  be  useful ,  but 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    WITHOUT  ANY  WARRANTY ;  without  even  the  implied  warranty  of 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    MERCHANTABILITY  or  FITNESS  FOR  A  PARTICULAR  PURPOSE .  See  the  GNU 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    General  Public  License  for  more  details . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    You  should  have  received  a  copy  of  the  GNU  Lesser  General  Public  License 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    along  with  PulseAudio ;  if  not ,  write  to  the  Free  Software 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    Foundation ,  Inc . ,  59  Temple  Place ,  Suite  330 ,  Boston ,  MA  02111 - 1307 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    USA . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								* * */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* TODO: Some plugins cause latency, and some even report it by using a control
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								   out  port .  We  don ' t  currently  use  the  latency  information .  */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# ifdef HAVE_CONFIG_H 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <config.h> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# endif 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <pulse/xmalloc.h> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <pulse/i18n.h> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <pulsecore/core-error.h> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <pulsecore/namereg.h> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <pulsecore/sink.h> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <pulsecore/module.h> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <pulsecore/core-util.h> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <pulsecore/modargs.h> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <pulsecore/log.h> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <pulsecore/thread.h> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <pulsecore/thread-mq.h> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <pulsecore/rtpoll.h> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <pulsecore/sample-util.h> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <pulsecore/ltdl-helper.h> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  "module-virtual-sink-symdef.h" 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								PA_MODULE_AUTHOR ( " Pierre-Louis Bossart " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								PA_MODULE_DESCRIPTION ( _ ( " Virtual sink " ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								PA_MODULE_VERSION ( PACKAGE_VERSION ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								PA_MODULE_LOAD_ONCE ( FALSE ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								PA_MODULE_USAGE ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        _ ( " sink_name=<name for the sink>  " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          " sink_properties=<properties for the sink>  " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          " master=<name of sink to filter>  " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          " format=<sample format>  " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          " rate=<sample rate>  " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          " channels=<number of channels>  " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          " channel_map=<channel map>  " 
							 
						 
					
						
							
								
									
										
										
										
											2011-02-24 16:16:39 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								          " use_volume_sharing=<yes or no>  " 
							 
						 
					
						
							
								
									
										
										
										
											2011-02-24 16:16:40 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								          " force_flat_volume=<yes or no>  " 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								        ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# define MEMBLOCKQ_MAXLENGTH (16*1024*1024) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								struct  userdata  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_module  * module ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink  * sink ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input  * sink_input ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_memblockq  * memblockq ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_bool_t  auto_desc ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    unsigned  channels ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  const  char *  const  valid_modargs [ ]  =  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    " sink_name " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    " sink_properties " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    " master " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    " format " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    " rate " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    " channels " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    " channel_map " , 
							 
						 
					
						
							
								
									
										
										
										
											2011-02-24 16:16:39 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    " use_volume_sharing " , 
							 
						 
					
						
							
								
									
										
										
										
											2011-02-24 16:16:40 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    " force_flat_volume " , 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								    NULL 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from I/O thread context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  int  sink_process_msg_cb ( pa_msgobject  * o ,  int  code ,  void  * data ,  int64_t  offset ,  pa_memchunk  * chunk )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u  =  PA_SINK ( o ) - > userdata ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    switch  ( code )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        case  PA_SINK_MESSAGE_GET_LATENCY : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            /* The sink is _put() before the sink input is, so let's
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								             *  make  sure  we  don ' t  access  it  in  that  time .  Also ,  the 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								             *  sink  input  is  first  shut  down ,  the  sink  second .  */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            if  ( ! PA_SINK_IS_LINKED ( u - > sink - > thread_info . state )  | | 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                ! PA_SINK_INPUT_IS_LINKED ( u - > sink_input - > thread_info . state ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                * ( ( pa_usec_t * )  data )  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            * ( ( pa_usec_t * )  data )  = 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                /* Get the latency of the master sink */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                pa_sink_get_latency_within_thread ( u - > sink_input - > sink )  + 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                /* Add the latency internal to our sink input on top */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                pa_bytes_to_usec ( pa_memblockq_get_length ( u - > sink_input - > thread_info . render_memblockq ) ,  & u - > sink_input - > sink - > sample_spec ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  pa_sink_process_msg ( o ,  code ,  data ,  offset ,  chunk ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from main context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  int  sink_set_state_cb ( pa_sink  * s ,  pa_sink_state_t  state )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_assert_ref ( s ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  s - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ! PA_SINK_IS_LINKED ( state )  | | 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        ! PA_SINK_INPUT_IS_LINKED ( pa_sink_input_get_state ( u - > sink_input ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_cork ( u - > sink_input ,  state  = =  PA_SINK_SUSPENDED ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from I/O thread context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  sink_request_rewind_cb ( pa_sink  * s )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_assert_ref ( s ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  s - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ! PA_SINK_IS_LINKED ( u - > sink - > thread_info . state )  | | 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        ! PA_SINK_INPUT_IS_LINKED ( u - > sink_input - > thread_info . state ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    /* Just hand this one over to the master sink */ 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-25 00:39:56 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    pa_sink_input_request_rewind ( u - > sink_input , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                                 s - > thread_info . rewind_nbytes  + 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                                 pa_memblockq_get_length ( u - > memblockq ) ,  TRUE ,  FALSE ,  FALSE ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from I/O thread context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  sink_update_requested_latency_cb ( pa_sink  * s )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_assert_ref ( s ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  s - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ! PA_SINK_IS_LINKED ( u - > sink - > thread_info . state )  | | 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        ! PA_SINK_INPUT_IS_LINKED ( u - > sink_input - > thread_info . state ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    /* Just hand this one over to the master sink */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_set_requested_latency_within_thread ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            u - > sink_input , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            pa_sink_get_requested_latency_within_thread ( s ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from main context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  sink_set_volume_cb ( pa_sink  * s )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_assert_ref ( s ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  s - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ! PA_SINK_IS_LINKED ( pa_sink_get_state ( s ) )  | | 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        ! PA_SINK_INPUT_IS_LINKED ( pa_sink_input_get_state ( u - > sink_input ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_set_volume ( u - > sink_input ,  & s - > real_volume ,  s - > save_volume ,  TRUE ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from main context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  sink_set_mute_cb ( pa_sink  * s )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_assert_ref ( s ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  s - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ! PA_SINK_IS_LINKED ( pa_sink_get_state ( s ) )  | | 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        ! PA_SINK_INPUT_IS_LINKED ( pa_sink_input_get_state ( u - > sink_input ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_set_mute ( u - > sink_input ,  s - > muted ,  s - > save_muted ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from I/O thread context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  int  sink_input_pop_cb ( pa_sink_input  * i ,  size_t  nbytes ,  pa_memchunk  * chunk )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    float  * src ,  * dst ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    size_t  fs ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    unsigned  n ,  c ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_memchunk  tchunk ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-25 02:26:03 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    pa_usec_t  current_latency ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_assert_ref ( i ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert ( chunk ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  i - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    /* Hmm, process any rewind request that might be queued up */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_process_rewind ( u - > sink ,  0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2010-02-25 02:26:03 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    /* (1) IF YOU NEED A FIXED BLOCK SIZE USE
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								     *  pa_memblockq_peek_fixed_size ( )  HERE  INSTEAD .  NOTE  THAT  FILTERS 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								     *  WHICH  CAN  DEAL  WITH  DYNAMIC  BLOCK  SIZES  ARE  HIGHLY 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								     *  PREFERRED .  */ 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								    while  ( pa_memblockq_peek ( u - > memblockq ,  & tchunk )  <  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_memchunk  nchunk ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_sink_render ( u - > sink ,  nbytes ,  & nchunk ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_memblockq_push ( u - > memblockq ,  & nchunk ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_memblock_unref ( nchunk . memblock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2010-02-25 02:26:03 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    /* (2) IF YOU NEED A FIXED BLOCK SIZE, THIS NEXT LINE IS NOT
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								     *  NECESSARY  */ 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								    tchunk . length  =  PA_MIN ( nbytes ,  tchunk . length ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert ( tchunk . length  >  0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    fs  =  pa_frame_size ( & i - > sample_spec ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    n  =  ( unsigned )  ( tchunk . length  /  fs ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert ( n  >  0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    chunk - > index  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    chunk - > length  =  n * fs ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    chunk - > memblock  =  pa_memblock_new ( i - > sink - > core - > mempool ,  chunk - > length ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_memblockq_drop ( u - > memblockq ,  chunk - > length ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    src  =  ( float * )  ( ( uint8_t * )  pa_memblock_acquire ( tchunk . memblock )  +  tchunk . index ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dst  =  ( float * )  pa_memblock_acquire ( chunk - > memblock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2010-02-25 02:26:03 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    /* (3) PUT YOUR CODE HERE TO DO SOMETHING WITH THE DATA */ 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-25 00:39:56 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    /* As an example, copy input to output */ 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								    for  ( c  =  0 ;  c  <  u - > channels ;  c + + )  { 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-25 00:39:56 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								        pa_sample_clamp ( PA_SAMPLE_FLOAT32NE , 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-25 02:10:45 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								                        dst + c ,  u - > channels  *  sizeof ( float ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                        src + c ,  u - > channels  *  sizeof ( float ) , 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-25 00:39:56 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								                        n ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-25 00:39:56 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								    pa_memblock_release ( tchunk . memblock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_memblock_release ( chunk - > memblock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_memblock_unref ( tchunk . memblock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2010-02-25 02:26:03 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    /* (4) IF YOU NEED THE LATENCY FOR SOMETHING ACQUIRE IT LIKE THIS: */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    current_latency  = 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								        /* Get the latency of the master sink */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_sink_get_latency_within_thread ( i - > sink )  + 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        /* Add the latency internal to our sink input on top */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_bytes_to_usec ( pa_memblockq_get_length ( i - > thread_info . render_memblockq ) ,  & i - > sink - > sample_spec ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from I/O thread context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  sink_input_process_rewind_cb ( pa_sink_input  * i ,  size_t  nbytes )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    size_t  amount  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_assert_ref ( i ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  i - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( u - > sink - > thread_info . rewind_nbytes  >  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        size_t  max_rewrite ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        max_rewrite  =  nbytes  +  pa_memblockq_get_length ( u - > memblockq ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        amount  =  PA_MIN ( u - > sink - > thread_info . rewind_nbytes ,  max_rewrite ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        u - > sink - > thread_info . rewind_nbytes  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if  ( amount  >  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            pa_memblockq_seek ( u - > memblockq ,  -  ( int64_t )  amount ,  PA_SEEK_RELATIVE ,  TRUE ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2010-02-25 02:26:03 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								            /* (5) PUT YOUR CODE HERE TO RESET YOUR FILTER  */ 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_process_rewind ( u - > sink ,  amount ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_memblockq_rewind ( u - > memblockq ,  nbytes ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from I/O thread context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  sink_input_update_max_rewind_cb ( pa_sink_input  * i ,  size_t  nbytes )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_assert_ref ( i ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  i - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_memblockq_set_maxrewind ( u - > memblockq ,  nbytes ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_set_max_rewind_within_thread ( u - > sink ,  nbytes ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from I/O thread context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  sink_input_update_max_request_cb ( pa_sink_input  * i ,  size_t  nbytes )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_assert_ref ( i ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  i - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2010-02-25 02:26:03 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    /* (6) IF YOU NEED A FIXED BLOCK SIZE ROUND nbytes UP TO MULTIPLES
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								     *  OF  IT  HERE .  THE  PA_ROUND_UP  MACRO  IS  USEFUL  FOR  THAT .  */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_set_max_request_within_thread ( u - > sink ,  nbytes ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from I/O thread context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  sink_input_update_sink_latency_range_cb ( pa_sink_input  * i )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_assert_ref ( i ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  i - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_set_latency_range_within_thread ( u - > sink ,  i - > sink - > thread_info . min_latency ,  i - > sink - > thread_info . max_latency ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from I/O thread context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  sink_input_update_sink_fixed_latency_cb ( pa_sink_input  * i )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_assert_ref ( i ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  i - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2010-02-25 02:26:03 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    /* (7) IF YOU NEED A FIXED BLOCK SIZE ADD THE LATENCY FOR ONE
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								     *  BLOCK  MINUS  ONE  SAMPLE  HERE .  pa_usec_to_bytes_round_up ( )  IS 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								     *  USEFUL  FOR  THAT .  */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_set_fixed_latency_within_thread ( u - > sink ,  i - > sink - > thread_info . fixed_latency ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from I/O thread context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  sink_input_detach_cb ( pa_sink_input  * i )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_assert_ref ( i ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  i - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_detach_within_thread ( u - > sink ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_set_rtpoll ( u - > sink ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from I/O thread context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  sink_input_attach_cb ( pa_sink_input  * i )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_assert_ref ( i ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  i - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_set_rtpoll ( u - > sink ,  i - > sink - > thread_info . rtpoll ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_set_latency_range_within_thread ( u - > sink ,  i - > sink - > thread_info . min_latency ,  i - > sink - > thread_info . max_latency ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-25 02:26:03 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    /* (8.1) IF YOU NEED A FIXED BLOCK SIZE ADD THE LATENCY FOR ONE
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								     *  BLOCK  MINUS  ONE  SAMPLE  HERE .  SEE  ( 7 )  */ 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_set_fixed_latency_within_thread ( u - > sink ,  i - > sink - > thread_info . fixed_latency ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-25 02:26:03 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    /* (8.2) IF YOU NEED A FIXED BLOCK SIZE ROUND
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								     *  pa_sink_input_get_max_request ( i )  UP  TO  MULTIPLES  OF  IT 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								     *  HERE .  SEE  ( 6 )  */ 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_set_max_request_within_thread ( u - > sink ,  pa_sink_input_get_max_request ( i ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_set_max_rewind_within_thread ( u - > sink ,  pa_sink_input_get_max_rewind ( i ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_attach_within_thread ( u - > sink ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from main context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  sink_input_kill_cb ( pa_sink_input  * i )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_assert_ref ( i ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  i - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    /* The order here matters! We first kill the sink input, followed
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								     *  by  the  sink .  That  means  the  sink  callbacks  must  be  protected 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								     *  against  an  unconnected  sink  input !  */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_unlink ( u - > sink_input ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_unlink ( u - > sink ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_unref ( u - > sink_input ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink_input  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_unref ( u - > sink ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_module_unload_request ( u - > module ,  TRUE ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from IO thread context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  sink_input_state_change_cb ( pa_sink_input  * i ,  pa_sink_input_state_t  state )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_assert_ref ( i ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  i - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    /* If we are added for the first time, ask for a rewinding so that
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								     *  we  are  heard  right - away .  */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( PA_SINK_INPUT_IS_LINKED ( state )  & & 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        i - > thread_info . state  = =  PA_SINK_INPUT_INIT )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_log_debug ( " Requesting rewind due to state change. " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_sink_input_request_rewind ( i ,  0 ,  FALSE ,  TRUE ,  TRUE ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from main context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  pa_bool_t  sink_input_may_move_to_cb ( pa_sink_input  * i ,  pa_sink  * dest )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_assert_ref ( i ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  i - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  u - > sink  ! =  dest ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from main context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  sink_input_moving_cb ( pa_sink_input  * i ,  pa_sink  * dest )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_assert_ref ( i ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  i - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( dest )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_sink_set_asyncmsgq ( u - > sink ,  dest - > asyncmsgq ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_sink_update_flags ( u - > sink ,  PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY ,  dest - > flags ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    }  else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_sink_set_asyncmsgq ( u - > sink ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( u - > auto_desc  & &  dest )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        const  char  * z ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_proplist  * pl ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pl  =  pa_proplist_new ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        z  =  pa_proplist_gets ( dest - > proplist ,  PA_PROP_DEVICE_DESCRIPTION ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_proplist_setf ( pl ,  PA_PROP_DEVICE_DESCRIPTION ,  " Virtual Sink %s on %s " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                         pa_proplist_gets ( u - > sink - > proplist ,  " device.vsink.name " ) ,  z  ?  z  :  dest - > name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_sink_update_proplist ( u - > sink ,  PA_UPDATE_REPLACE ,  pl ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_proplist_free ( pl ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from main context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  sink_input_volume_changed_cb ( pa_sink_input  * i )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_assert_ref ( i ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  i - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_volume_changed ( u - > sink ,  & i - > volume ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Called from main context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  sink_input_mute_changed_cb ( pa_sink_input  * i )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_assert_ref ( i ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  i - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_mute_changed ( u - > sink ,  i - > muted ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								int  pa__init ( pa_module * m )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sample_spec  ss ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_channel_map  map ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_modargs  * ma ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink  * master = NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_new_data  sink_input_data ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_new_data  sink_data ; 
							 
						 
					
						
							
								
									
										
										
										
											2011-02-24 16:16:39 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    pa_bool_t  use_volume_sharing  =  FALSE ; 
							 
						 
					
						
							
								
									
										
										
										
											2011-02-24 16:16:40 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    pa_bool_t  force_flat_volume  =  FALSE ; 
							 
						 
					
						
							
								
									
										
											 
										 
										
											
												virtual-sink: Fix a crash when moving the sink to a new master right after setup.
If the virtual sink is moved to a new master right after it has been created,
then the virtual sink input's memblockq can be rewound to a negative read
index. The data written prior to the move starts from index zero, so after the
rewind there's a bit of silence. If the memblockq doesn't have a silence
memchunk set, then pa_memblockq_peek() will return zero in such case, and the
returned memchunk's memblock pointer will be NULL.
That scenario wasn't taken into account in the implementation of
sink_input_pop_cb. Setting a silence memchunk for the memblockq solves this
problem, because pa_memblock_peek() will now return a valid memblock if the
read index happens to point to a hole in the memblockq.
I believe this isn't the best possible solution, though. It doesn't really make
sense to rewind the sink input's memblockq beyond index 0 in the first place,
because now when the stream starts to play to the new master sink, there's some
unnecessary silence before the actual data starts. This is a small problem,
though, and I don't grok the rewinding system well enough to know how to fix
this issue properly.
I went through all files that call pa_memblockq_peek() to see if there are more
similar bugs. play-memblockq.c was the only one that looked to me like it might
be broken in the same way. I didn't try reproducing the bug with
play-memblockq.c, though, so I just added a FIXME comment there.
											 
										 
										
											2011-02-24 16:16:43 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    pa_memchunk  silence ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert ( m ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ! ( ma  =  pa_modargs_new ( m - > argument ,  valid_modargs ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_log ( " Failed to parse module arguments. " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        goto  fail ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ! ( master  =  pa_namereg_get ( m - > core ,  pa_modargs_get_value ( ma ,  " master " ,  NULL ) ,  PA_NAMEREG_SINK ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_log ( " Master sink not found " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        goto  fail ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert ( master ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    ss  =  master - > sample_spec ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    ss . format  =  PA_SAMPLE_FLOAT32 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    map  =  master - > channel_map ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( pa_modargs_get_sample_spec_and_channel_map ( ma ,  & ss ,  & map ,  PA_CHANNEL_MAP_DEFAULT )  <  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_log ( " Invalid sample format specification or channel map " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        goto  fail ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2011-02-24 16:16:39 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    if  ( pa_modargs_get_value_boolean ( ma ,  " use_volume_sharing " ,  & use_volume_sharing )  <  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_log ( " use_volume_sharing= expects a boolean argument " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        goto  fail ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2011-02-24 16:16:40 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    if  ( pa_modargs_get_value_boolean ( ma ,  " force_flat_volume " ,  & force_flat_volume )  <  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_log ( " force_flat_volume= expects a boolean argument " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        goto  fail ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( use_volume_sharing  & &  force_flat_volume )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_log ( " Flat volume can't be forced when using volume sharing. " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        goto  fail ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								    u  =  pa_xnew0 ( struct  userdata ,  1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > module  =  m ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    m - > userdata  =  u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > channels  =  ss . channels ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    /* Create sink */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_new_data_init ( & sink_data ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    sink_data . driver  =  __FILE__ ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    sink_data . module  =  m ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ! ( sink_data . name  =  pa_xstrdup ( pa_modargs_get_value ( ma ,  " sink_name " ,  NULL ) ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        sink_data . name  =  pa_sprintf_malloc ( " %s.vsink " ,  master - > name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_new_data_set_sample_spec ( & sink_data ,  & ss ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_new_data_set_channel_map ( & sink_data ,  & map ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_proplist_sets ( sink_data . proplist ,  PA_PROP_DEVICE_MASTER_DEVICE ,  master - > name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_proplist_sets ( sink_data . proplist ,  PA_PROP_DEVICE_CLASS ,  " filter " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_proplist_sets ( sink_data . proplist ,  " device.vsink.name " ,  sink_data . name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( pa_modargs_get_proplist ( ma ,  " sink_properties " ,  sink_data . proplist ,  PA_UPDATE_REPLACE )  <  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_log ( " Invalid properties " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_sink_new_data_done ( & sink_data ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        goto  fail ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ( u - > auto_desc  =  ! pa_proplist_contains ( sink_data . proplist ,  PA_PROP_DEVICE_DESCRIPTION ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        const  char  * z ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        z  =  pa_proplist_gets ( master - > proplist ,  PA_PROP_DEVICE_DESCRIPTION ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_proplist_setf ( sink_data . proplist ,  PA_PROP_DEVICE_DESCRIPTION ,  " Virtual Sink %s on %s " ,  sink_data . name ,  z  ?  z  :  master - > name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2011-02-24 16:16:39 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    u - > sink  =  pa_sink_new ( m - > core ,  & sink_data ,  ( master - > flags  &  ( PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2011-02-24 16:16:40 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								                                               |  ( use_volume_sharing  ?  PA_SINK_SHARE_VOLUME_WITH_MASTER  :  0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                                               |  ( force_flat_volume  ?  PA_SINK_FLAT_VOLUME  :  0 ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_new_data_done ( & sink_data ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ! u - > sink )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_log ( " Failed to create sink. " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        goto  fail ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink - > parent . process_msg  =  sink_process_msg_cb ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink - > set_state  =  sink_set_state_cb ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink - > update_requested_latency  =  sink_update_requested_latency_cb ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink - > request_rewind  =  sink_request_rewind_cb ; 
							 
						 
					
						
							
								
									
										
										
										
											2011-02-24 16:16:39 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    u - > sink - > set_volume  =  use_volume_sharing  ?  NULL  :  sink_set_volume_cb ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink - > set_mute  =  sink_set_mute_cb ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink - > userdata  =  u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_set_asyncmsgq ( u - > sink ,  master - > asyncmsgq ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    /* Create sink input */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_new_data_init ( & sink_input_data ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    sink_input_data . driver  =  __FILE__ ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    sink_input_data . module  =  m ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    sink_input_data . sink  =  master ; 
							 
						 
					
						
							
								
									
										
										
										
											2011-02-07 18:35:51 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    sink_input_data . origin_sink  =  u - > sink ; 
							 
						 
					
						
							
								
									
										
										
										
											2011-02-24 16:16:41 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    pa_proplist_setf ( sink_input_data . proplist ,  PA_PROP_MEDIA_NAME ,  " Virtual Sink Stream from %s " ,  pa_proplist_gets ( u - > sink - > proplist ,  PA_PROP_DEVICE_DESCRIPTION ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								    pa_proplist_sets ( sink_input_data . proplist ,  PA_PROP_MEDIA_ROLE ,  " filter " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_new_data_set_sample_spec ( & sink_input_data ,  & ss ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_new_data_set_channel_map ( & sink_input_data ,  & map ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_new ( & u - > sink_input ,  m - > core ,  & sink_input_data ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_new_data_done ( & sink_input_data ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ! u - > sink_input ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        goto  fail ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink_input - > pop  =  sink_input_pop_cb ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink_input - > process_rewind  =  sink_input_process_rewind_cb ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink_input - > update_max_rewind  =  sink_input_update_max_rewind_cb ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink_input - > update_max_request  =  sink_input_update_max_request_cb ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink_input - > update_sink_latency_range  =  sink_input_update_sink_latency_range_cb ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink_input - > update_sink_fixed_latency  =  sink_input_update_sink_fixed_latency_cb ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink_input - > kill  =  sink_input_kill_cb ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink_input - > attach  =  sink_input_attach_cb ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink_input - > detach  =  sink_input_detach_cb ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink_input - > state_change  =  sink_input_state_change_cb ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink_input - > may_move_to  =  sink_input_may_move_to_cb ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink_input - > moving  =  sink_input_moving_cb ; 
							 
						 
					
						
							
								
									
										
										
										
											2011-02-24 16:16:39 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    u - > sink_input - > volume_changed  =  use_volume_sharing  ?  NULL  :  sink_input_volume_changed_cb ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink_input - > mute_changed  =  sink_input_mute_changed_cb ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > sink_input - > userdata  =  u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2011-02-07 18:35:51 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    u - > sink - > input_to_master  =  u - > sink_input ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										 
										
											
												virtual-sink: Fix a crash when moving the sink to a new master right after setup.
If the virtual sink is moved to a new master right after it has been created,
then the virtual sink input's memblockq can be rewound to a negative read
index. The data written prior to the move starts from index zero, so after the
rewind there's a bit of silence. If the memblockq doesn't have a silence
memchunk set, then pa_memblockq_peek() will return zero in such case, and the
returned memchunk's memblock pointer will be NULL.
That scenario wasn't taken into account in the implementation of
sink_input_pop_cb. Setting a silence memchunk for the memblockq solves this
problem, because pa_memblock_peek() will now return a valid memblock if the
read index happens to point to a hole in the memblockq.
I believe this isn't the best possible solution, though. It doesn't really make
sense to rewind the sink input's memblockq beyond index 0 in the first place,
because now when the stream starts to play to the new master sink, there's some
unnecessary silence before the actual data starts. This is a small problem,
though, and I don't grok the rewinding system well enough to know how to fix
this issue properly.
I went through all files that call pa_memblockq_peek() to see if there are more
similar bugs. play-memblockq.c was the only one that looked to me like it might
be broken in the same way. I didn't try reproducing the bug with
play-memblockq.c, though, so I just added a FIXME comment there.
											 
										 
										
											2011-02-24 16:16:43 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    pa_sink_input_get_silence ( u - > sink_input ,  & silence ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    u - > memblockq  =  pa_memblockq_new ( 0 ,  MEMBLOCKQ_MAXLENGTH ,  0 ,  pa_frame_size ( & ss ) ,  1 ,  1 ,  0 ,  & silence ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_memblock_unref ( silence . memblock ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-25 02:41:09 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										 
										
											
												virtual-sink: Fix a crash when moving the sink to a new master right after setup.
If the virtual sink is moved to a new master right after it has been created,
then the virtual sink input's memblockq can be rewound to a negative read
index. The data written prior to the move starts from index zero, so after the
rewind there's a bit of silence. If the memblockq doesn't have a silence
memchunk set, then pa_memblockq_peek() will return zero in such case, and the
returned memchunk's memblock pointer will be NULL.
That scenario wasn't taken into account in the implementation of
sink_input_pop_cb. Setting a silence memchunk for the memblockq solves this
problem, because pa_memblock_peek() will now return a valid memblock if the
read index happens to point to a hole in the memblockq.
I believe this isn't the best possible solution, though. It doesn't really make
sense to rewind the sink input's memblockq beyond index 0 in the first place,
because now when the stream starts to play to the new master sink, there's some
unnecessary silence before the actual data starts. This is a small problem,
though, and I don't grok the rewinding system well enough to know how to fix
this issue properly.
I went through all files that call pa_memblockq_peek() to see if there are more
similar bugs. play-memblockq.c was the only one that looked to me like it might
be broken in the same way. I didn't try reproducing the bug with
play-memblockq.c, though, so I just added a FIXME comment there.
											 
										 
										
											2011-02-24 16:16:43 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    /* (9) INITIALIZE ANYTHING ELSE YOU NEED HERE */ 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-25 02:26:03 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_put ( u - > sink ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_sink_input_put ( u - > sink_input ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_modargs_free ( ma ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2011-03-02 12:41:26 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								fail : 
							 
						 
					
						
							
								
									
										
										
										
											2010-02-11 15:44:11 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ma ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_modargs_free ( ma ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa__done ( m ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								int  pa__get_n_used ( pa_module  * m )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert ( m ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert_se ( u  =  m - > userdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  pa_sink_linked_by ( u - > sink ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								void  pa__done ( pa_module * m )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  userdata  * u ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_assert ( m ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ! ( u  =  m - > userdata ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    /* See comments in sink_input_kill_cb() above regarding
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								     *  destruction  order !  */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( u - > sink_input ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_sink_input_unlink ( u - > sink_input ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( u - > sink ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_sink_unlink ( u - > sink ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( u - > sink_input ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_sink_input_unref ( u - > sink_input ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( u - > sink ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_sink_unref ( u - > sink ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( u - > memblockq ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        pa_memblockq_free ( u - > memblockq ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pa_xfree ( u ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								}