2004-07-16 19:56:36 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/***
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-19 21:53:48 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								  This file is part of PulseAudio.
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-02-13 15:35:19 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								  Copyright 2004-2006 Lennart Poettering
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-19 21:53:48 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								  PulseAudio is free software; you can redistribute it and/or modify
							 | 
						
					
						
							
								
									
										
										
										
											2004-11-14 14:58:54 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								  it under the terms of the GNU Lesser General Public License as published
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-03 20:23:02 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								  by the Free Software Foundation; either version 2.1 of the License,
							 | 
						
					
						
							
								
									
										
										
										
											2004-07-16 19:56:36 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								  or (at your option) any later version.
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-19 21:53:48 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								  PulseAudio is distributed in the hope that it will be useful, but
							 | 
						
					
						
							
								
									
										
										
										
											2004-07-16 19:56:36 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								  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.
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2004-11-14 14:58:54 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								  You should have received a copy of the GNU Lesser General Public License
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-19 21:53:48 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								  along with PulseAudio; if not, write to the Free Software
							 | 
						
					
						
							
								
									
										
										
										
											2004-07-16 19:56:36 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  USA.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								***/
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2004-07-16 19:16:42 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#ifdef HAVE_CONFIG_H
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <config.h>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#endif
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-05-17 22:31:10 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <stdio.h>
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <stdlib.h>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <string.h>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-19 21:53:48 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <pulse/introspect.h>
							 | 
						
					
						
							
								
									
										
										
										
											2011-08-10 10:30:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <pulse/format.h>
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-19 21:53:48 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <pulse/utf8.h>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <pulse/xmalloc.h>
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <pulse/timeval.h>
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-22 00:15:19 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <pulse/util.h>
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <pulse/rtclock.h>
							 | 
						
					
						
							
								
									
										
										
										
											2011-02-28 13:00:20 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <pulse/internal.h>
							 | 
						
					
						
							
								
									
										
										
										
											2006-05-16 23:47:38 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-08-10 10:30:15 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <pulsecore/i18n.h>
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-19 21:53:48 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <pulsecore/sink-input.h>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <pulsecore/namereg.h>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <pulsecore/core-util.h>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <pulsecore/sample-util.h>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <pulsecore/core-subscribe.h>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <pulsecore/log.h>
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <pulsecore/macro.h>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <pulsecore/play-memblockq.h>
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <pulsecore/flist.h>
							 | 
						
					
						
							
								
									
										
										
										
											2006-02-17 12:10:58 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include "sink.h"
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-15 17:05:03 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#define MAX_MIX_CHANNELS 32
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#define MIX_BUFFER_LENGTH (PA_PAGE_SIZE)
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-24 21:06:57 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#define ABSOLUTE_MIN_LATENCY (500)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-10 01:26:04 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC)
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-21 21:27:44 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								PA_DEFINE_PUBLIC_CLASS(pa_sink, pa_msgobject);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								struct pa_sink_volume_change {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_usec_t at;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_cvolume hw_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    PA_LLIST_FIELDS(pa_sink_volume_change);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								struct sink_message_set_port {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_device_port *port;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    int ret;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void sink_free(pa_object *s);
							 | 
						
					
						
							
								
									
										
										
										
											2006-05-16 23:47:38 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void pa_sink_volume_change_push(pa_sink *s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static void pa_sink_volume_change_flush(pa_sink *s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static void pa_sink_volume_change_rewind(pa_sink *s, size_t nbytes);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								pa_sink_new_data* pa_sink_new_data_init(pa_sink_new_data *data) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(data);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_zero(*data);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    data->proplist = pa_proplist_new();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return data;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_sink_new_data_set_name(pa_sink_new_data *data, const char *name) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(data);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_xfree(data->name);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    data->name = pa_xstrdup(name);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_sink_new_data_set_sample_spec(pa_sink_new_data *data, const pa_sample_spec *spec) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(data);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if ((data->sample_spec_is_set = !!spec))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        data->sample_spec = *spec;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_sink_new_data_set_channel_map(pa_sink_new_data *data, const pa_channel_map *map) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(data);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if ((data->channel_map_is_set = !!map))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        data->channel_map = *map;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_sink_new_data_set_volume(pa_sink_new_data *data, const pa_cvolume *volume) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(data);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if ((data->volume_is_set = !!volume))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        data->volume = *volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_sink_new_data_set_muted(pa_sink_new_data *data, pa_bool_t mute) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(data);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    data->muted_is_set = TRUE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    data->muted = !!mute;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-17 03:45:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_new_data_set_port(pa_sink_new_data *data, const char *port) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(data);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_xfree(data->active_port);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    data->active_port = pa_xstrdup(port);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_new_data_done(pa_sink_new_data *data) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(data);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_proplist_free(data->proplist);
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-17 03:45:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (data->ports) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_device_port *p;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        while ((p = pa_hashmap_steal_first(data->ports)))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_device_port_free(p);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_hashmap_free(data->ports, NULL, NULL);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_xfree(data->name);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_xfree(data->active_port);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								pa_device_port *pa_device_port_new(const char *name, const char *description, size_t extra) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_device_port *p;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(name);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    p = pa_xmalloc(PA_ALIGN(sizeof(pa_device_port)) + extra);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    p->name = pa_xstrdup(name);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    p->description = pa_xstrdup(description);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    p->priority = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return p;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_device_port_free(pa_device_port *p) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(p);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_xfree(p->name);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_xfree(p->description);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_xfree(p);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main context */
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void reset_callbacks(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->set_state = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->get_volume = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->set_volume = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->get_mute = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->set_mute = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->request_rewind = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->update_requested_latency = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-17 03:45:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->set_port = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2011-02-28 13:00:20 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->get_formats = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main context */
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-27 16:25:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								pa_sink* pa_sink_new(
							 | 
						
					
						
							
								
									
										
										
										
											2006-05-16 23:47:38 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_core *core,
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_sink_new_data *data,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_flags_t flags) {
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-11 01:17:39 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink *s;
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    const char *name;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_source_new_data source_data;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    const char *dn;
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-30 02:25:49 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    char *pt;
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(core);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(data);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(data->name);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s = pa_msgobject_new(pa_sink);
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-27 16:25:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SINK, s, data->namereg_fail))) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-18 03:40:47 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_log_debug("Failed to register name %s.", data->name);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_xfree(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_new_data_set_name(data, name);
							 | 
						
					
						
							
								
									
										
										
										
											2006-05-16 23:47:38 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_NEW], data) < 0) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_xfree(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_namereg_unregister(core, name);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-17 03:45:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* FIXME, need to free s here on failure */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-27 22:42:17 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (!data->channel_map_is_set)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* FIXME: There should probably be a general function for checking whether
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * the sink volume is allowed to be set, like there is for sink inputs. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!data->volume_is_set || !(flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (!data->volume_is_set) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_cvolume_reset(&data->volume, data->sample_spec.channels);
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        data->save_volume = FALSE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_return_null_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec));
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (!data->muted_is_set)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        data->muted = FALSE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-15 20:27:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (data->card)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->card->proplist);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-01 21:34:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_device_init_description(data->proplist);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_device_init_icon(data->proplist, TRUE);
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-08 16:58:45 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_device_init_intended_roles(data->proplist);
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-01 21:34:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_FIXATE], data) < 0) {
							 | 
						
					
						
							
								
									
										
										
										
											2004-08-04 16:39:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_xfree(s);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_namereg_unregister(core, name);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-27 22:42:17 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2004-09-14 20:53:25 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->parent.parent.free = sink_free;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->parent.process_msg = pa_sink_process_msg;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-27 16:25:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->core = core;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->state = PA_SINK_INIT;
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->flags = flags;
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-28 23:30:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->priority = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-05 19:05:07 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->suspend_cause = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-27 16:25:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->name = pa_xstrdup(name);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->proplist = pa_proplist_copy(data->proplist);
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-22 00:15:19 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->module = data->module;
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-15 18:29:16 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->card = data->card;
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-27 16:25:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-29 04:31:33 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->priority = pa_device_init_priority(s->proplist);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->sample_spec = data->sample_spec;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->channel_map = data->channel_map;
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2004-07-03 23:35:12 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->inputs = pa_idxset_new(NULL, NULL);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->n_corked = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2011-02-07 18:35:51 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->input_to_master = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->reference_volume = s->real_volume = data->volume;
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
							 | 
						
					
						
							
								
									
										
										
										
											2008-12-24 00:49:43 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->base_volume = PA_VOLUME_NORM;
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->n_volume_steps = PA_VOLUME_NORM+1;
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->muted = data->muted;
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->refresh_volume = s->refresh_muted = FALSE;
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    reset_callbacks(s);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-15 17:05:03 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->userdata = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->asyncmsgq = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2004-08-11 00:11:12 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-17 03:45:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* As a minor optimization we just steal the list instead of
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * copying it here */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->ports = data->ports;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    data->ports = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->active_port = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->save_port = FALSE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (data->active_port && s->ports)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if ((s->active_port = pa_hashmap_get(s->ports, data->active_port)))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            s->save_port = data->save_port;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (!s->active_port && s->ports) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        void *state;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_device_port *p;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        PA_HASHMAP_FOREACH(p, s->ports, state)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (!s->active_port || p->priority > s->active_port->priority)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                s->active_port = p;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->save_volume = data->save_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->save_muted = data->save_muted;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_silence_memchunk_get(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            &core->silence_cache,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            core->mempool,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            &s->silence,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            &s->sample_spec,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            0);
							 | 
						
					
						
							
								
									
										
										
										
											2006-08-11 17:53:34 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:26:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.rtpoll = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.soft_volume =  s->soft_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.soft_muted = s->muted;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.state = s->state;
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.rewind_nbytes = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-26 02:56:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.rewind_requested = FALSE;
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.max_rewind = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.max_request = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.requested_latency_valid = FALSE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.requested_latency = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-25 00:25:17 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.min_latency = ABSOLUTE_MIN_LATENCY;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.max_latency = ABSOLUTE_MAX_LATENCY;
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:48:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.fixed_latency = flags & PA_SINK_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY;
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    PA_LLIST_HEAD_INIT(pa_sink_volume_change, s->thread_info.volume_changes);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.volume_changes_tail = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sw_cvolume_multiply(&s->thread_info.current_hw_volume, &s->soft_volume, &s->real_volume);
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:17 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.volume_change_safety_margin = core->sync_volume_safety_margin_usec;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.volume_change_extra_delay = core->sync_volume_extra_delay_usec;
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-16 00:45:56 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* FIXME: This should probably be moved to pa_sink_put() */
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-15 18:29:16 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->card)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_assert_se(pa_idxset_put(s->card->sinks, s, NULL) >= 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-30 02:25:49 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pt = pa_proplist_to_string_sep(s->proplist, "\n    ");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_log_info("Created sink %u \"%s\" with sample spec %s and channel map %s\n    %s",
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                s->index,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                s->name,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-30 02:25:49 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pt);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_xfree(pt);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_source_new_data_init(&source_data);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_source_new_data_set_sample_spec(&source_data, &s->sample_spec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_source_new_data_set_channel_map(&source_data, &s->channel_map);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    source_data.name = pa_sprintf_malloc("%s.monitor", name);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    source_data.driver = data->driver;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    source_data.module = data->module;
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-15 18:29:16 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    source_data.card = data->card;
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    dn = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Monitor of %s", dn ? dn : s->name);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "monitor");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-05-08 02:02:06 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->monitor_source = pa_source_new(core, &source_data,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                      ((flags & PA_SINK_LATENCY) ? PA_SOURCE_LATENCY : 0) |
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                      ((flags & PA_SINK_DYNAMIC_LATENCY) ? PA_SOURCE_DYNAMIC_LATENCY : 0));
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_source_new_data_done(&source_data);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (!s->monitor_source) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_unlink(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_unref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->monitor_source->monitor_of = s;
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_source_set_latency_range(s->monitor_source, s->thread_info.min_latency, s->thread_info.max_latency);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:48:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_source_set_fixed_latency(s->monitor_source, s->thread_info.fixed_latency);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind);
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return s;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main context */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    int ret;
							 | 
						
					
						
							
								
									
										
										
										
											2007-11-21 01:30:40 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_bool_t suspend_change;
							 | 
						
					
						
							
								
									
										
										
										
											2008-07-23 16:50:16 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_state_t original_state;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->state == state)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-07-23 16:50:16 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    original_state = s->state;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-11-21 01:30:40 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    suspend_change =
							 | 
						
					
						
							
								
									
										
										
										
											2008-07-23 16:50:16 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        (original_state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(state)) ||
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        (PA_SINK_IS_OPENED(original_state) && state == PA_SINK_SUSPENDED);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->set_state)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if ((ret = s->set_state(s, state)) < 0)
							 | 
						
					
						
							
								
									
										
										
										
											2008-07-23 16:50:16 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            return ret;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->asyncmsgq)
							 | 
						
					
						
							
								
									
										
										
										
											2008-07-23 16:50:16 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (s->set_state)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                s->set_state(s, original_state);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return ret;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->state = state;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-03 02:23:46 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (state != PA_SINK_UNLINKED) { /* if we enter UNLINKED state pa_sink_unlink() will fire the apropriate events */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-11-21 01:30:40 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (suspend_change) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        uint32_t idx;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        /* We're suspending or resuming, tell everyone about it */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:12:53 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        PA_IDXSET_FOREACH(i, s->inputs, idx)
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-03 02:23:46 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (s->state == PA_SINK_SUSPENDED &&
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:12:53 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                (i->flags & PA_SINK_INPUT_KILL_ON_SUSPEND))
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-03 02:23:46 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                pa_sink_input_kill(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            else if (i->suspend)
							 | 
						
					
						
							
								
									
										
										
										
											2007-11-21 01:30:40 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                i->suspend(i, state == PA_SINK_SUSPENDED);
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-04 05:27:14 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (s->monitor_source)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_source_sync_suspend(s->monitor_source);
							 | 
						
					
						
							
								
									
										
										
										
											2007-11-21 01:30:40 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-17 15:29:29 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_get_volume_callback(pa_sink *s, pa_sink_cb_t cb) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->get_volume = cb;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_set_volume_callback(pa_sink *s, pa_sink_cb_t cb) {
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-02 16:23:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_flags_t flags;
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-17 15:29:29 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-02 16:23:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s);
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-05 23:44:06 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!s->write_volume || cb);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-17 15:29:29 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->set_volume = cb;
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-05 23:44:06 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-02 16:23:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* Save the current flags so we can tell if they've changed */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    flags = s->flags;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (cb) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        /* The sink implementor is responsible for setting decibel volume support */
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-05 23:44:06 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        s->flags |= PA_SINK_HW_VOLUME_CTRL;
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-02 16:23:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    } else {
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-05 23:44:06 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        s->flags &= ~PA_SINK_HW_VOLUME_CTRL;
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-02 16:23:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        /* See note below in pa_sink_put() about volume sharing and decibel volumes */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_enable_decibel_volume(s, !(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* If the flags have changed after init, let any clients know via a change event */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->state != PA_SINK_INIT && flags != s->flags)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-17 15:29:29 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_write_volume_callback(pa_sink *s, pa_sink_cb_t cb) {
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-02 16:23:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_flags_t flags;
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-17 15:29:29 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-02 16:23:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s);
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-05 23:44:06 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!cb || s->set_volume);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-17 15:29:29 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->write_volume = cb;
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-05 23:44:06 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-02 16:23:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* Save the current flags so we can tell if they've changed */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    flags = s->flags;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-05 23:44:06 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (cb)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->flags |= PA_SINK_SYNC_VOLUME;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->flags &= ~PA_SINK_SYNC_VOLUME;
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-02 16:23:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* If the flags have changed after init, let any clients know via a change event */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->state != PA_SINK_INIT && flags != s->flags)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-17 15:29:29 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_get_mute_callback(pa_sink *s, pa_sink_cb_t cb) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->get_mute = cb;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_set_mute_callback(pa_sink *s, pa_sink_cb_t cb) {
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-02 16:23:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_flags_t flags;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-17 15:29:29 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->set_mute = cb;
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-05 23:44:06 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-02 16:23:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* Save the current flags so we can tell if they've changed */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    flags = s->flags;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-05 23:44:06 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (cb)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->flags |= PA_SINK_HW_MUTE_CTRL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->flags &= ~PA_SINK_HW_MUTE_CTRL;
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-02 16:23:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* If the flags have changed after init, let any clients know via a change event */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->state != PA_SINK_INIT && flags != s->flags)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static void enable_flat_volume(pa_sink *s, pa_bool_t enable) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_flags_t flags;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* Always follow the overall user preference here */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    enable = enable && s->core->flat_volumes;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* Save the current flags so we can tell if they've changed */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    flags = s->flags;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (enable)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->flags |= PA_SINK_FLAT_VOLUME;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->flags &= ~PA_SINK_FLAT_VOLUME;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* If the flags have changed after init, let any clients know via a change event */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->state != PA_SINK_INIT && flags != s->flags)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_sink_enable_decibel_volume(pa_sink *s, pa_bool_t enable) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_flags_t flags;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* Save the current flags so we can tell if they've changed */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    flags = s->flags;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (enable) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->flags |= PA_SINK_DECIBEL_VOLUME;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        enable_flat_volume(s, TRUE);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    } else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->flags &= ~PA_SINK_DECIBEL_VOLUME;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        enable_flat_volume(s, FALSE);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* If the flags have changed after init, let any clients know via a change event */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->state != PA_SINK_INIT && flags != s->flags)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-17 15:29:29 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main context */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_put(pa_sink* s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s->state == PA_SINK_INIT);
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) || s->input_to_master);
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* The following fields must be initialized properly when calling _put() */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s->asyncmsgq);
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-24 21:06:57 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-05-08 02:16:10 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* Generally, flags should be initialized via pa_sink_new(). As a
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-05 23:44:06 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								     * special exception we allow some volume related flags to be set
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * between _new() and _put() by the callback setter functions above.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * Thus we implement a couple safeguards here which ensure the above
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * setters were used (or at least the implementor made manual changes
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * in a compatible way).
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * Note: All of these flags set here can change over the life time
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * of the sink. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!(s->flags & PA_SINK_HW_VOLUME_CTRL) || s->set_volume);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!(s->flags & PA_SINK_SYNC_VOLUME) || s->write_volume);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!(s->flags & PA_SINK_HW_MUTE_CTRL) || s->set_mute);
							 | 
						
					
						
							
								
									
										
										
										
											2009-05-08 02:16:10 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* XXX: Currently decibel volume is disabled for all sinks that use volume
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * sharing. When the master sink supports decibel volume, it would be good
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * to have the flag also in the filter sink, but currently we don't do that
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * so that the flags of the filter sink never change when it's moved from
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * a master sink to another. One solution for this problem would be to
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * remove user-visible volume altogether from filter sinks when volume
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * sharing is used, but the current approach was easier to implement... */
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-05 23:44:06 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* We always support decibel volumes in software, otherwise we leave it to
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * the sink implementor to set this flag as needed.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * Note: This flag can also change over the life time of the sink. */
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (!(s->flags & PA_SINK_HW_VOLUME_CTRL) && !(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-02 16:23:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_sink_enable_decibel_volume(s, TRUE);
							 | 
						
					
						
							
								
									
										
										
										
											2009-05-08 02:16:10 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-07-02 16:23:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* If the sink implementor support DB volumes by itself, we should always
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * try and enable flat volumes too */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if ((s->flags & PA_SINK_DECIBEL_VOLUME))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        enable_flat_volume(s, TRUE);
							 | 
						
					
						
							
								
									
										
										
										
											2009-05-08 02:16:10 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink *root_sink = s->input_to_master->sink;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            root_sink = root_sink->input_to_master->sink;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->reference_volume = root_sink->reference_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_cvolume_remap(&s->reference_volume, &root_sink->channel_map, &s->channel_map);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->real_volume = root_sink->real_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_cvolume_remap(&s->real_volume, &root_sink->channel_map, &s->channel_map);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    } else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        /* We assume that if the sink implementor changed the default
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * volume he did so in real_volume, because that is the usual
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * place where he is supposed to place his changes.  */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->reference_volume = s->real_volume;
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-13 22:50:24 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.soft_volume = s->soft_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.soft_muted = s->muted;
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sw_cvolume_multiply(&s->thread_info.current_hw_volume, &s->soft_volume, &s->real_volume);
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-13 22:50:24 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert((s->flags & PA_SINK_HW_VOLUME_CTRL)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              || (s->base_volume == PA_VOLUME_NORM
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                  && ((s->flags & PA_SINK_DECIBEL_VOLUME || (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)))));
							 | 
						
					
						
							
								
									
										
										
										
											2009-05-08 02:02:06 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!(s->flags & PA_SINK_DECIBEL_VOLUME) || s->n_volume_steps == PA_VOLUME_NORM+1);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:48:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == (s->thread_info.fixed_latency != 0));
							 | 
						
					
						
							
								
									
										
										
										
											2009-05-08 02:02:06 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!(s->flags & PA_SINK_LATENCY) == !(s->monitor_source->flags & PA_SOURCE_LATENCY));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == !(s->monitor_source->flags & PA_SOURCE_DYNAMIC_LATENCY));
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-10 01:26:04 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:48:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s->monitor_source->thread_info.fixed_latency == s->thread_info.fixed_latency);
							 | 
						
					
						
							
								
									
										
										
										
											2009-05-08 02:02:06 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s->monitor_source->thread_info.min_latency == s->thread_info.min_latency);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s->monitor_source->thread_info.max_latency == s->thread_info.max_latency);
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-25 16:30:28 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_source_put(s->monitor_source);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PUT], s);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main context */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_unlink(pa_sink* s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_bool_t linked;
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-11 01:17:39 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i, *j = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* Please note that pa_sink_unlink() does more than simply
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * reversing pa_sink_put(). It also undoes the registrations
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * already done in pa_sink_new()! */
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* All operations here shall be idempotent, i.e. pa_sink_unlink()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * may be called multiple times on the same sink without bad
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * effects. */
							 | 
						
					
						
							
								
									
										
										
										
											2006-08-13 17:33:32 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    linked = PA_SINK_IS_LINKED(s->state);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (linked)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK], s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->state != PA_SINK_UNLINKED)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_namereg_unregister(s->core, s->name);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_idxset_remove_by_data(s->core->sinks, s, NULL);
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-15 18:29:16 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->card)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_idxset_remove_by_data(s->card->sinks, s, NULL);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2004-07-03 23:35:12 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    while ((i = pa_idxset_first(s->inputs, NULL))) {
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_assert(i != j);
							 | 
						
					
						
							
								
									
										
										
										
											2004-07-03 23:35:12 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_sink_input_kill(i);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-14 20:30:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        j = i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-15 17:05:03 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (linked)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        sink_set_state(s, PA_SINK_UNLINKED);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->state = PA_SINK_UNLINKED;
							 | 
						
					
						
							
								
									
										
										
										
											2004-09-14 20:53:25 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    reset_callbacks(s);
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->monitor_source)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_source_unlink(s->monitor_source);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (linked) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2004-09-14 20:53:25 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main context */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void sink_free(pa_object *o) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink *s = PA_SINK(o);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(pa_sink_refcnt(s) == 0);
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (PA_SINK_IS_LINKED(s->state))
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_sink_unlink(s);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-11 21:30:16 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_log_info("Freeing sink %u \"%s\"", s->index, s->name);
							 | 
						
					
						
							
								
									
										
										
										
											2004-08-11 00:11:12 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-08-11 17:53:34 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->monitor_source) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_source_unref(s->monitor_source);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->monitor_source = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2004-09-14 20:53:25 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_idxset_free(s->inputs, NULL, NULL);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    while ((i = pa_hashmap_steal_first(s->thread_info.inputs)))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_input_unref(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_hashmap_free(s->thread_info.inputs, NULL, NULL);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->silence.memblock)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_memblock_unref(s->silence.memblock);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2004-08-04 16:39:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_xfree(s->name);
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-27 16:25:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_xfree(s->driver);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->proplist)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_proplist_free(s->proplist);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-17 03:45:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->ports) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_device_port *p;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        while ((p = pa_hashmap_steal_first(s->ports)))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_device_port_free(p);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_hashmap_free(s->ports, NULL, NULL);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2004-08-04 16:39:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_xfree(s);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 03:41:13 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main context, and not while the IO thread is active, please */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->asyncmsgq = q;
							 | 
						
					
						
							
								
									
										
										
										
											2004-09-14 20:53:25 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->monitor_source)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_source_set_asyncmsgq(s->monitor_source, q);
							 | 
						
					
						
							
								
									
										
										
										
											2004-09-14 20:53:25 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 03:41:13 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main context, and not while the IO thread is active, please */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_sink_update_flags(pa_sink *s, pa_sink_flags_t mask, pa_sink_flags_t value) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (mask == 0)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* For now, allow only a minimal set of flags to be changed. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert((mask & ~(PA_SINK_DYNAMIC_LATENCY|PA_SINK_LATENCY)) == 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->flags = (s->flags & ~mask) | (value & mask);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_source_update_flags(s->monitor_source,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                           ((mask & PA_SINK_LATENCY) ? PA_SOURCE_LATENCY : 0) |
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                           ((mask & PA_SINK_DYNAMIC_LATENCY) ? PA_SOURCE_DYNAMIC_LATENCY : 0),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                           ((value & PA_SINK_LATENCY) ? PA_SOURCE_LATENCY : 0) |
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                           ((value & PA_SINK_DYNAMIC_LATENCY) ? PA_SINK_DYNAMIC_LATENCY : 0));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:26:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from IO context, or before _put() from main context */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:26:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:26:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.rtpoll = p;
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-17 03:45:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->monitor_source)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_source_set_rtpoll(s->monitor_source, p);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main context */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								int pa_sink_update_status(pa_sink*s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->state == PA_SINK_SUSPENDED)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main context */
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-05 19:05:07 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								int pa_sink_suspend(pa_sink *s, pa_bool_t suspend, pa_suspend_cause_t cause) {
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-05 19:05:07 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(cause != 0);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-06 15:32:45 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (suspend) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-05 19:05:07 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        s->suspend_cause |= cause;
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-06 15:32:45 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        s->monitor_source->suspend_cause |= cause;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    } else {
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-05 19:05:07 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        s->suspend_cause &= ~cause;
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-06 15:32:45 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        s->monitor_source->suspend_cause &= ~cause;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-05 19:05:07 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-06 15:31:46 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if ((pa_sink_get_state(s) == PA_SINK_SUSPENDED) == !!s->suspend_cause)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-05 19:05:07 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_log_debug("Suspend cause of sink %s is 0x%04x, %s", s->name, s->suspend_cause, s->suspend_cause ? "suspending" : "resuming");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->suspend_cause)
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return sink_set_state(s, PA_SINK_SUSPENDED);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
							 | 
						
					
						
							
								
									
										
										
										
											2004-09-14 20:53:25 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-23 22:40:02 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main context */
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-17 03:45:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								pa_queue *pa_sink_move_all_start(pa_sink *s, pa_queue *q) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-23 22:40:02 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i, *n;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    uint32_t idx;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-23 22:40:02 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-17 03:45:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (!q)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        q = pa_queue_new();
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-23 22:40:02 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = n) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        n = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-10 01:21:16 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_sink_input_ref(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-23 22:40:02 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (pa_sink_input_start_move(i) >= 0)
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-10 01:21:16 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_queue_push(q, i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_sink_input_unref(i);
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-23 22:40:02 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return q;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Called from main context */
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 23:35:55 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-23 22:40:02 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-23 22:40:02 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(q);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 23:35:55 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (pa_sink_input_finish_move(i, s, save) < 0)
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:03:50 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_sink_input_fail_move(i);
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-23 22:40:02 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_input_unref(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_queue_free(q, NULL, NULL);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Called from main context */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_sink_move_all_fail(pa_queue *q) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-23 22:40:02 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(q);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:03:50 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_sink_input_fail_move(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_input_unref(i);
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-23 22:40:02 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_queue_free(q, NULL, NULL);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from IO thread context */
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    void *state = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-07 23:58:45 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:45:54 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* If nobody requested this and this is actually no real rewind
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-07 23:58:45 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								     * then we can short cut this. Please note that this means that
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * not all rewind requests triggered upstream will always be
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * translated in actual requests! */
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:45:54 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (!s->thread_info.rewind_requested && nbytes <= 0)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-26 02:56:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.rewind_nbytes = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.rewind_requested = FALSE;
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:45:00 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->thread_info.state == PA_SINK_SUSPENDED)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-01-13 16:44:42 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (nbytes > 0) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-26 02:56:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_log_debug("Processing rewind...");
							 | 
						
					
						
							
								
									
										
										
										
											2011-01-13 16:44:42 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (s->flags & PA_SINK_SYNC_VOLUME)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_sink_volume_change_rewind(s, nbytes);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-07 23:58:45 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_sink_input_assert_ref(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_input_process_rewind(i, nbytes);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (nbytes > 0) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:45:00 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-26 02:56:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_source_process_rewind(s->monitor_source, nbytes);
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from IO thread context */
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, unsigned maxinfo) {
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-11 01:17:39 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-15 17:05:03 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    unsigned n = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    void *state = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    size_t mixlength = *length;
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(info);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxinfo > 0) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_input_assert_ref(i);
							 | 
						
					
						
							
								
									
										
										
										
											2004-09-14 20:53:25 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-03 03:11:31 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_sink_input_peek(i, *length, &info->chunk, &info->volume);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (mixlength == 0 || info->chunk.length < mixlength)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            mixlength = info->chunk.length;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (pa_memblock_is_silence(info->chunk.memblock)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_memblock_unref(info->chunk.memblock);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-15 15:18:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            continue;
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-15 00:29:01 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        info->userdata = pa_sink_input_ref(i);
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_assert(info->chunk.memblock);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_assert(info->chunk.length > 0);
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-15 15:18:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        info++;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        n++;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        maxinfo--;
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (mixlength > 0)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        *length = mixlength;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-15 15:18:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return n;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from IO thread context */
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-13 21:56:19 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *result) {
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							
								
									
										
										
										
											2009-09-03 00:21:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    void *state;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    unsigned p = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    unsigned n_unreffed = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-13 21:56:19 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(result);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(result->memblock);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(result->length > 0);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* We optimize for the case where the order of the inputs has not changed */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-09-02 00:54:22 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        unsigned j;
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-13 21:56:19 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_mix_info* m = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_input_assert_ref(i);
							 | 
						
					
						
							
								
									
										
										
										
											2004-08-27 01:29:49 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        /* Let's try to find the matching entry info the pa_mix_info array */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        for (j = 0; j < n; j ++) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (info[p].userdata == i) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                m = info + p;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                break;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            p++;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (p >= n)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                p = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-27 16:25:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        /* Drop read data */
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-13 21:56:19 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_sink_input_drop(i, result->length);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:45:00 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state)) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-13 21:56:19 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (pa_hashmap_size(i->thread_info.direct_outputs) > 0) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                void *ostate = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_source_output *o;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_memchunk c;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                if (m && m->chunk.memblock) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    c = m->chunk;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    pa_memblock_ref(c.memblock);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    pa_assert(result->length <= c.length);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    c.length = result->length;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    pa_memchunk_make_writable(&c, 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    pa_volume_memchunk(&c, &s->sample_spec, &m->volume);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                } else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    c = s->silence;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    pa_memblock_ref(c.memblock);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    pa_assert(result->length <= c.length);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    c.length = result->length;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                while ((o = pa_hashmap_iterate(i->thread_info.direct_outputs, &ostate, NULL))) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    pa_source_output_assert_ref(o);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    pa_assert(o->direct_on_input == i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    pa_source_post_direct(s->monitor_source, o, &c);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_memblock_unref(c.memblock);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2004-09-14 20:53:25 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (m) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (m->chunk.memblock)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_memblock_unref(m->chunk.memblock);
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-13 21:56:19 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                pa_memchunk_reset(&m->chunk);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_sink_input_unref(m->userdata);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            m->userdata = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            n_unreffed += 1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* Now drop references to entries that are included in the
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * pa_mix_info array but don't exist anymore */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (n_unreffed < n) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        for (; n > 0; info++, n--) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (info->userdata)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_sink_input_unref(info->userdata);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (info->chunk.memblock)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_memblock_unref(info->chunk.memblock);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-15 15:18:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-13 21:56:19 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:45:00 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-13 21:56:19 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_source_post(s->monitor_source, result);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from IO thread context */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-11 01:17:39 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_mix_info info[MAX_MIX_CHANNELS];
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-15 15:18:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    unsigned n;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    size_t block_size_max;
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:45:00 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(pa_frame_aligned(length, &s->sample_spec));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(result);
							 | 
						
					
						
							
								
									
										
										
										
											2004-09-06 18:55:47 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-26 02:56:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!s->thread_info.rewind_requested);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s->thread_info.rewind_nbytes == 0);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:45:00 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->thread_info.state == PA_SINK_SUSPENDED) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        result->memblock = pa_memblock_ref(s->silence.memblock);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        result->index = s->silence.index;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        result->length = PA_MIN(s->silence.length, length);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-09-02 00:54:22 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_ref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (length <= 0)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        length = pa_frame_align(MIX_BUFFER_LENGTH, &s->sample_spec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    block_size_max = pa_mempool_block_size_max(s->core->mempool);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (length > block_size_max)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        length = pa_frame_align(block_size_max, &s->sample_spec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(length > 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-15 00:07:38 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (n == 0) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        *result = s->silence;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_memblock_ref(result->memblock);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (result->length > length)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            result->length = length;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    } else if (n == 1) {
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-27 16:25:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_cvolume volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-15 15:18:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        *result = info[0].chunk;
							 | 
						
					
						
							
								
									
										
										
										
											2004-07-03 23:35:12 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_memblock_ref(result->memblock);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-15 15:18:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (result->length > length)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            result->length = length;
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-10-29 12:47:42 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_memblock_unref(result->memblock);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_silence_memchunk_get(&s->core->silence_cache,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                    s->core->mempool,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                    result,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                    &s->sample_spec,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                    result->length);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        } else if (!pa_cvolume_is_norm(&volume)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_memchunk_make_writable(result, 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_volume_memchunk(result, &s->sample_spec, &volume);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-29 20:37:24 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-15 15:18:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    } else {
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        void *ptr;
							 | 
						
					
						
							
								
									
										
										
										
											2006-08-18 19:55:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        result->memblock = pa_memblock_new(s->core->mempool, length);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        ptr = pa_memblock_acquire(result->memblock);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        result->length = pa_mix(info, n,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                ptr, length,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                &s->sample_spec,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                &s->thread_info.soft_volume,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                s->thread_info.soft_muted);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_memblock_release(result->memblock);
							 | 
						
					
						
							
								
									
										
										
										
											2006-02-20 04:05:16 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-15 15:18:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        result->index = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-15 00:07:38 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    inputs_drop(s, info, n, result);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-16 00:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2004-09-14 20:53:25 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_unref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from IO thread context */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-11 01:17:39 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_mix_info info[MAX_MIX_CHANNELS];
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-15 15:18:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    unsigned n;
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    size_t length, block_size_max;
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:45:00 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(target);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(target->memblock);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(target->length > 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
							 | 
						
					
						
							
								
									
										
										
										
											2004-09-14 20:53:25 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-26 02:56:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!s->thread_info.rewind_requested);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s->thread_info.rewind_nbytes == 0);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:45:00 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->thread_info.state == PA_SINK_SUSPENDED) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_silence_memchunk(target, &s->sample_spec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-09-02 00:54:22 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_ref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    length = target->length;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    block_size_max = pa_mempool_block_size_max(s->core->mempool);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (length > block_size_max)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        length = pa_frame_align(block_size_max, &s->sample_spec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-13 21:56:19 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(length > 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-15 00:07:38 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-08 23:54:24 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (n == 0) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (target->length > length)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            target->length = length;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_silence_memchunk(target, &s->sample_spec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    } else if (n == 1) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_cvolume volume;
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (target->length > length)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            target->length = length;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_silence_memchunk(target, &s->sample_spec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else {
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_memchunk vchunk;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            vchunk = info[0].chunk;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_memblock_ref(vchunk.memblock);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-13 21:56:19 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (vchunk.length > length)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                vchunk.length = length;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (!pa_cvolume_is_norm(&volume)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_memchunk_make_writable(&vchunk, 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_volume_memchunk(&vchunk, &s->sample_spec, &volume);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_memchunk_memcpy(target, &vchunk);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_memblock_unref(vchunk.memblock);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    } else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        void *ptr;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ptr = pa_memblock_acquire(target->memblock);
							 | 
						
					
						
							
								
									
										
										
										
											2006-02-23 12:04:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-27 16:25:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        target->length = pa_mix(info, n,
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                                (uint8_t*) ptr + target->index, length,
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-27 16:25:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                                &s->sample_spec,
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                                &s->thread_info.soft_volume,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                s->thread_info.soft_muted);
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_memblock_release(target->memblock);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2006-08-11 17:53:34 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-15 00:07:38 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    inputs_drop(s, info, n, target);
							 | 
						
					
						
							
								
									
										
										
										
											2004-09-14 20:53:25 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_unref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-15 15:18:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-16 00:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from IO thread context */
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-11 01:17:39 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_memchunk chunk;
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-16 00:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    size_t l, d;
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:45:00 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(target);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(target->memblock);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(target->length > 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-16 00:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-26 02:56:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!s->thread_info.rewind_requested);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s->thread_info.rewind_nbytes == 0);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-09-02 00:54:22 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->thread_info.state == PA_SINK_SUSPENDED) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_silence_memchunk(target, &s->sample_spec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_ref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-16 00:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    l = target->length;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    d = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    while (l > 0) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        chunk = *target;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        chunk.index += d;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        chunk.length -= d;
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_sink_render_into(s, &chunk);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-16 00:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        d += chunk.length;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        l -= chunk.length;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2004-09-14 20:53:25 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_unref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-16 00:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from IO thread context */
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-11 01:17:39 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:45:00 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(length > 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(pa_frame_aligned(length, &s->sample_spec));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(result);
							 | 
						
					
						
							
								
									
										
										
										
											2004-09-01 00:23:51 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-26 02:56:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!s->thread_info.rewind_requested);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s->thread_info.rewind_nbytes == 0);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-09-02 00:54:22 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-05-07 19:55:56 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-09-02 00:54:22 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_render(s, length, result);
							 | 
						
					
						
							
								
									
										
										
										
											2009-05-07 19:55:56 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (result->length < length) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-08 00:12:20 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_memchunk chunk;
							 | 
						
					
						
							
								
									
										
										
										
											2009-09-01 22:19:30 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-08 00:12:20 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_memchunk_make_writable(result, length);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-09-01 22:19:30 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        chunk.memblock = result->memblock;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        chunk.index = result->index + result->length;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        chunk.length = length - result->length;
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-08 00:12:20 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-09-01 22:19:30 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_sink_render_into_full(s, &chunk);
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-08 00:12:20 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        result->length = length;
							 | 
						
					
						
							
								
									
										
										
										
											2009-05-07 19:55:56 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_unref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2004-09-01 00:23:51 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-11 01:17:39 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								pa_usec_t pa_sink_get_latency(pa_sink *s) {
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_usec_t usec = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-16 00:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* The returned value is supposed to be in the time domain of the sound card! */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:45:00 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->state == PA_SINK_SUSPENDED)
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return 0;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-12-24 00:58:34 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (!(s->flags & PA_SINK_LATENCY))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-16 00:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return usec;
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-16 00:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2004-06-18 00:22:37 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-05 02:46:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from IO thread */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_usec_t usec = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_msgobject *o;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-05 02:46:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* The returned value is supposed to be in the time domain of the sound card! */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->thread_info.state == PA_SINK_SUSPENDED)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (!(s->flags & PA_SINK_LATENCY))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    o = PA_MSGOBJECT(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:26:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* FIXME: We probably should make this a proper vtable callback instead of going through process_msg() */
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-05 02:46:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (o->process_msg(o, PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return -1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return usec;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from the main thread (and also from the IO thread while the main
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * thread is waiting).
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * When a sink uses volume sharing, it never has the PA_SINK_FLAT_VOLUME flag
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * set. Instead, flat volume mode is detected by checking whether the root sink
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * has the flag set. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								pa_bool_t pa_sink_flat_volume_enabled(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2010-02-23 18:41:18 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    while (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s = s->input_to_master->sink;
							 | 
						
					
						
							
								
									
										
										
										
											2010-02-23 18:41:18 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return (s->flags & PA_SINK_FLAT_VOLUME);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2010-02-23 18:41:18 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-03-02 02:06:54 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main context */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								pa_bool_t pa_sink_is_passthrough(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *alt_i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    uint32_t idx;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* one and only one PASSTHROUGH input can possibly be connected */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (pa_idxset_size(s->inputs) == 1) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        alt_i = pa_idxset_first(s->inputs, &idx);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-03-16 16:08:23 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (pa_sink_input_is_passthrough(alt_i))
							 | 
						
					
						
							
								
									
										
										
										
											2011-03-02 02:06:54 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            return TRUE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return FALSE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main context. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static void compute_reference_ratio(pa_sink_input *i) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    unsigned c = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_cvolume remapped;
							 | 
						
					
						
							
								
									
										
										
										
											2010-02-23 18:41:18 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(pa_sink_flat_volume_enabled(i->sink));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * Calculates the reference ratio from the sink's reference
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * volume. This basically calculates:
							 | 
						
					
						
							
								
									
										
										
										
											2010-02-23 18:41:18 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								     *
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								     * i->reference_ratio = i->volume / i->sink->reference_volume
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     */
							 | 
						
					
						
							
								
									
										
										
										
											2010-02-23 18:41:18 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    remapped = i->sink->reference_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_cvolume_remap(&remapped, &i->sink->channel_map, &i->channel_map);
							 | 
						
					
						
							
								
									
										
										
										
											2010-02-23 18:41:18 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    i->reference_ratio.channels = i->sample_spec.channels;
							 | 
						
					
						
							
								
									
										
										
										
											2010-02-23 18:41:18 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    for (c = 0; c < i->sample_spec.channels; c++) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        /* We don't update when the sink volume is 0 anyway */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (remapped.values[c] <= PA_VOLUME_MUTED)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            continue;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        /* Don't update the reference ratio unless necessary */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (pa_sw_volume_multiply(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    i->reference_ratio.values[c],
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    remapped.values[c]) == i->volume.values[c])
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            continue;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        i->reference_ratio.values[c] = pa_sw_volume_divide(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                i->volume.values[c],
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                remapped.values[c]);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2010-02-23 18:41:18 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main context. Only called for the root sink in volume sharing
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * cases, except for internal recursive calls. */
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void compute_reference_ratios(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    uint32_t idx;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-07 04:47:58 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(pa_sink_flat_volume_enabled(s));
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-07 04:47:58 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    PA_IDXSET_FOREACH(i, s->inputs, idx) {
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        compute_reference_ratio(i);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            compute_reference_ratios(i->origin_sink);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main context. Only called for the root sink in volume sharing
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * cases, except for internal recursive calls. */
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void compute_real_ratios(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    uint32_t idx;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(pa_sink_flat_volume_enabled(s));
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    PA_IDXSET_FOREACH(i, s->inputs, idx) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        unsigned c;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_cvolume remapped;
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-07 04:47:58 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            /* The origin sink uses volume sharing, so this input's real ratio
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * is handled as a special case - the real ratio must be 0 dB, and
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * as a result i->soft_volume must equal i->volume_factor. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_cvolume_reset(&i->real_ratio, i->real_ratio.channels);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            i->soft_volume = i->volume_factor;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            compute_real_ratios(i->origin_sink);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            continue;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        /*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * This basically calculates:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * i->real_ratio := i->volume / s->real_volume
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * i->soft_volume := i->real_ratio * i->volume_factor
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         */
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-07 04:47:58 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        remapped = s->real_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_cvolume_remap(&remapped, &s->channel_map, &i->channel_map);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        i->real_ratio.channels = i->sample_spec.channels;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        i->soft_volume.channels = i->sample_spec.channels;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        for (c = 0; c < i->sample_spec.channels; c++) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (remapped.values[c] <= PA_VOLUME_MUTED) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                /* We leave i->real_ratio untouched */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                i->soft_volume.values[c] = PA_VOLUME_MUTED;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                continue;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            /* Don't lose accuracy unless necessary */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (pa_sw_volume_multiply(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        i->real_ratio.values[c],
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        remapped.values[c]) != i->volume.values[c])
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                i->real_ratio.values[c] = pa_sw_volume_divide(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        i->volume.values[c],
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        remapped.values[c]);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            i->soft_volume.values[c] = pa_sw_volume_multiply(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    i->real_ratio.values[c],
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    i->volume_factor.values[c]);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        /* We don't copy the soft_volume to the thread_info data
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * here. That must be done by the caller */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-07 04:47:58 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static pa_cvolume *cvolume_remap_minimal_impact(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_cvolume *v,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const pa_cvolume *template,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const pa_channel_map *from,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const pa_channel_map *to) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_cvolume t;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(v);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(template);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(from);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(to);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(pa_cvolume_compatible_with_channel_map(v, from));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(pa_cvolume_compatible_with_channel_map(template, to));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* Much like pa_cvolume_remap(), but tries to minimize impact when
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * mapping from sink input to sink volumes:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * If template is a possible remapping from v it is used instead
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * of remapping anew.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * If the channel maps don't match we set an all-channel volume on
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * the sink to ensure that changing a volume on one stream has no
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * effect that cannot be compensated for in another stream that
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * does not have the same channel map as the sink. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (pa_channel_map_equal(from, to))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return v;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    t = *template;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (pa_cvolume_equal(pa_cvolume_remap(&t, to, from), v)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        *v = *template;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return v;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_cvolume_set(v, to->channels, pa_cvolume_max(v));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return v;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread. Only called for the root sink in volume sharing
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * cases, except for internal recursive calls. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static void get_maximum_input_volume(pa_sink *s, pa_cvolume *max_volume, const pa_channel_map *channel_map) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    uint32_t idx;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(max_volume);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(channel_map);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(pa_sink_flat_volume_enabled(s));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    PA_IDXSET_FOREACH(i, s->inputs, idx) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_cvolume remapped;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            get_maximum_input_volume(i->origin_sink, max_volume, channel_map);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            /* Ignore this input. The origin sink uses volume sharing, so this
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * input's volume will be set to be equal to the root sink's real
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * volume. Obviously this input's current volume must not then
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * affect what the root sink's real volume will be. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            continue;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        remapped = i->volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        cvolume_remap_minimal_impact(&remapped, max_volume, &i->channel_map, channel_map);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_cvolume_merge(max_volume, max_volume, &remapped);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread. Only called for the root sink in volume sharing
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * cases, except for internal recursive calls. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static pa_bool_t has_inputs(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    uint32_t idx;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    PA_IDXSET_FOREACH(i, s->inputs, idx) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (!i->origin_sink || !(i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) || has_inputs(i->origin_sink))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return TRUE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return FALSE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread. Only called for the root sink in volume sharing
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * cases, except for internal recursive calls. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static void update_real_volume(pa_sink *s, const pa_cvolume *new_volume, pa_channel_map *channel_map) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    uint32_t idx;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(new_volume);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(channel_map);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->real_volume = *new_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_cvolume_remap(&s->real_volume, channel_map, &s->channel_map);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    PA_IDXSET_FOREACH(i, s->inputs, idx) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (pa_sink_flat_volume_enabled(s)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_cvolume old_volume = i->volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                /* Follow the root sink's real volume. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                i->volume = *new_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_cvolume_remap(&i->volume, channel_map, &i->channel_map);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                compute_reference_ratio(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                /* The volume changed, let's tell people so */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                if (!pa_cvolume_equal(&old_volume, &i->volume)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    if (i->volume_changed)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        i->volume_changed(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            update_real_volume(i->origin_sink, new_volume, channel_map);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread. Only called for the root sink in shared volume
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * cases. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static void compute_real_volume(pa_sink *s) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:27:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:27:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(pa_sink_flat_volume_enabled(s));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:27:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* This determines the maximum volume of all streams and sets
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * s->real_volume accordingly. */
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (!has_inputs(s)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        /* In the special case that we have no sink inputs we leave the
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:27:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         * volume unmodified. */
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        update_real_volume(s, &s->reference_volume, &s->channel_map);
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:27:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_cvolume_mute(&s->real_volume, s->channel_map.channels);
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* First let's determine the new maximum volume of all inputs
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * connected to this sink */
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    get_maximum_input_volume(s, &s->real_volume, &s->channel_map);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    update_real_volume(s, &s->real_volume, &s->channel_map);
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* Then, let's update the real ratios/soft volumes of all inputs
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * connected to this sink */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    compute_real_ratios(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread. Only called for the root sink in shared volume
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * cases, except for internal recursive calls. */
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void propagate_reference_volume(pa_sink *s) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    uint32_t idx;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:45:00 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(pa_sink_flat_volume_enabled(s));
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* This is called whenever the sink volume changes that is not
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * caused by a sink input volume change. We need to fix up the
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * sink input volumes accordingly */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    PA_IDXSET_FOREACH(i, s->inputs, idx) {
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_cvolume old_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            propagate_reference_volume(i->origin_sink);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            /* Since the origin sink uses volume sharing, this input's volume
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * needs to be updated to match the root sink's real volume, but
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * that will be done later in update_shared_real_volume(). */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            continue;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        old_volume = i->volume;
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        /* This basically calculates:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * i->volume := s->reference_volume * i->reference_ratio  */
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        i->volume = s->reference_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_cvolume_remap(&i->volume, &s->channel_map, &i->channel_map);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sw_cvolume_multiply(&i->volume, &i->volume, &i->reference_ratio);
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-21 02:56:17 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        /* The volume changed, let's tell people so */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (!pa_cvolume_equal(&old_volume, &i->volume)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (i->volume_changed)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                i->volume_changed(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-21 02:56:17 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread. Only called for the root sink in volume sharing
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * cases, except for internal recursive calls. The return value indicates
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * whether any reference volume actually changed. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static pa_bool_t update_reference_volume(pa_sink *s, const pa_cvolume *v, const pa_channel_map *channel_map, pa_bool_t save) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_cvolume volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_bool_t reference_volume_changed;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    uint32_t idx;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(v);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(channel_map);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(pa_cvolume_valid(v));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    volume = *v;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_cvolume_remap(&volume, channel_map, &s->channel_map);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    reference_volume_changed = !pa_cvolume_equal(&volume, &s->reference_volume);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->reference_volume = volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->save_volume = (!reference_volume_changed && s->save_volume) || save;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (reference_volume_changed)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else if (!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        /* If the root sink's volume doesn't change, then there can't be any
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * changes in the other sinks in the sink tree either.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * It's probably theoretically possible that even if the root sink's
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * volume changes slightly, some filter sink doesn't change its volume
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * due to rounding errors. If that happens, we still want to propagate
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * the changed root sink volume to the sinks connected to the
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * intermediate sink that didn't change its volume. This theoretical
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * possiblity is the reason why we have that !(s->flags &
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * PA_SINK_SHARE_VOLUME_WITH_MASTER) condition. Probably nobody would
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * notice even if we returned here FALSE always if
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * reference_volume_changed is FALSE. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return FALSE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    PA_IDXSET_FOREACH(i, s->inputs, idx) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            update_reference_volume(i->origin_sink, v, channel_map, FALSE);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return TRUE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_volume(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink *s,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const pa_cvolume *volume,
							 | 
						
					
						
							
								
									
										
										
										
											2009-10-30 03:32:38 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_bool_t send_msg,
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_bool_t save) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_cvolume new_reference_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink *root_sink = s;
							 | 
						
					
						
							
								
									
										
										
										
											2006-08-12 02:19:36 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!volume || pa_cvolume_valid(volume));
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(volume || pa_sink_flat_volume_enabled(s));
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-31 21:40:59 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!volume || volume->channels == 1 || pa_cvolume_compatible(volume, &s->sample_spec));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-07-16 16:46:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* make sure we don't change the volume when a PASSTHROUGH input is connected */
							 | 
						
					
						
							
								
									
										
										
										
											2011-03-02 02:06:54 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (pa_sink_is_passthrough(s)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        /* FIXME: Need to notify client that volume control is disabled */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_log_warn("Cannot change volume, Sink is connected to PASSTHROUGH input");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							
								
									
										
										
										
											2010-07-16 16:46:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* In case of volume sharing, the volume is set for the root sink first,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * from which it's then propagated to the sharing sinks. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        root_sink = root_sink->input_to_master->sink;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-31 21:40:59 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* As a special exception we accept mono volumes on all sinks --
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * even on those with more complex channel maps */
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (volume) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (pa_cvolume_compatible(volume, &s->sample_spec))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            new_reference_volume = *volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            new_reference_volume = s->reference_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_cvolume_scale(&new_reference_volume, pa_cvolume_max(volume));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_cvolume_remap(&new_reference_volume, &s->channel_map, &root_sink->channel_map);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* If volume is NULL we synchronize the sink's real and reference
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * volumes with the stream volumes. If it is not NULL we update
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * the reference_volume with it. */
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (volume) {
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (update_reference_volume(root_sink, &new_reference_volume, &root_sink->channel_map, save)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (pa_sink_flat_volume_enabled(root_sink)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                /* OK, propagate this volume change back to the inputs */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                propagate_reference_volume(root_sink);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                /* And now recalculate the real volume */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                compute_real_volume(root_sink);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            } else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                update_real_volume(root_sink, &root_sink->reference_volume, &root_sink->channel_map);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    } else {
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_assert(pa_sink_flat_volume_enabled(root_sink));
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        /* Ok, let's determine the new real volume */
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        compute_real_volume(root_sink);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        /* Let's 'push' the reference volume if necessary */
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_cvolume_merge(&new_reference_volume, &s->reference_volume, &root_sink->real_volume);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        update_reference_volume(root_sink, &new_reference_volume, &root_sink->channel_map, save);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        /* Now that the reference volume is updated, we can update the streams'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * reference ratios. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        compute_reference_ratios(root_sink);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (root_sink->set_volume) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        /* If we have a function set_volume(), then we do not apply a
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-13 22:50:24 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         * soft volume by default. However, set_volume() is free to
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         * apply one to root_sink->soft_volume */
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-07 22:47:32 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_cvolume_reset(&root_sink->soft_volume, root_sink->sample_spec.channels);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (!(root_sink->flags & PA_SINK_SYNC_VOLUME))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            root_sink->set_volume(root_sink);
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-07 01:37:38 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    } else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        /* If we have no function set_volume(), then the soft volume
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         * becomes the real volume */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        root_sink->soft_volume = root_sink->real_volume;
							 | 
						
					
						
							
								
									
										
										
										
											2004-07-10 20:56:38 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* This tells the sink that soft volume and/or real volume changed */
							 | 
						
					
						
							
								
									
										
										
										
											2009-10-30 03:32:38 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (send_msg)
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_assert_se(pa_asyncmsgq_send(root_sink->asyncmsgq, PA_MSGOBJECT(root_sink), PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL) == 0);
							 | 
						
					
						
							
								
									
										
										
										
											2004-07-10 20:56:38 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2004-08-12 23:25:28 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from the io thread if sync volume is used, otherwise from the main thread.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Only to be called by sink implementor */
							 | 
						
					
						
							
								
									
										
										
										
											2008-08-13 13:55:58 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
							 | 
						
					
						
							
								
									
										
										
										
											2011-05-17 19:50:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-08-13 13:55:58 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
							 | 
						
					
						
							
								
									
										
										
										
											2011-05-17 19:50:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->flags & PA_SINK_SYNC_VOLUME)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_assert_io_context(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2008-08-13 13:55:58 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (!volume)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->soft_volume = *volume;
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (PA_SINK_IS_LINKED(s->state) && !(s->flags & PA_SINK_SYNC_VOLUME))
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
							 | 
						
					
						
							
								
									
										
										
										
											2008-08-13 13:55:58 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    else
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        s->thread_info.soft_volume = s->soft_volume;
							 | 
						
					
						
							
								
									
										
										
										
											2008-08-13 13:55:58 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from the main thread. Only called for the root sink in volume sharing
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * cases, except for internal recursive calls. */
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    uint32_t idx;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(old_real_volume);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-27 16:25:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* This is called when the hardware's real volume changes due to
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * some external event. We copy the real volume into our
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * reference volume and then rebuild the stream volumes based on
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * i->real_ratio which should stay fixed. */
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-27 16:25:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (pa_cvolume_equal(old_real_volume, &s->real_volume))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return;
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        /* 1. Make the real volume the reference volume */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        update_reference_volume(s, &s->real_volume, &s->channel_map, TRUE);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (pa_sink_flat_volume_enabled(s)) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-13 22:50:24 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        PA_IDXSET_FOREACH(i, s->inputs, idx) {
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_cvolume old_volume = i->volume;
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-27 16:25:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            /* 2. Since the sink's reference and real volumes are equal
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * now our ratios should be too. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            i->reference_ratio = i->real_ratio;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            /* 3. Recalculate the new stream reference volume based on the
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * reference ratio and the sink's reference volume.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * This basically calculates:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * i->volume = s->reference_volume * i->reference_ratio
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * This is identical to propagate_reference_volume() */
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            i->volume = s->reference_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_cvolume_remap(&i->volume, &s->channel_map, &i->channel_map);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_sw_cvolume_multiply(&i->volume, &i->volume, &i->reference_ratio);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            /* Notify if something changed */
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-21 02:56:17 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (!pa_cvolume_equal(&old_volume, &i->volume)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                if (i->volume_changed)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    i->volume_changed(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-21 02:56:17 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                propagate_real_volume(i->origin_sink, old_real_volume);
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-27 16:25:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* Something got changed in the hardware. It probably makes sense
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * to save changed hw settings given that hw volume changes not
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * triggered by PA are almost certainly done by the user. */
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->save_volume = TRUE;
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-27 16:25:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from io thread */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_sink_update_volume_and_mute(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_UPDATE_VOLUME_AND_MUTE, NULL, 0, NULL, NULL);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-21 02:45:31 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-21 02:45:31 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-21 02:45:31 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->refresh_volume || force_refresh) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        struct pa_cvolume old_real_volume;
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-21 02:45:31 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        old_real_volume = s->real_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (!(s->flags & PA_SINK_SYNC_VOLUME) && s->get_volume)
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            s->get_volume(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-13 22:50:24 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        update_real_volume(s, &s->real_volume, &s->channel_map);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        propagate_real_volume(s, &old_real_volume);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-13 22:50:24 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return &s->reference_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread. In volume sharing cases, only the root sink may
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * call this. */
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_real_volume) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_cvolume old_real_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* The sink implementor may call this if the volume changed to make sure everyone is notified */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    old_real_volume = s->real_volume;
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    update_real_volume(s, new_real_volume, &s->channel_map);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-19 02:55:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    propagate_real_volume(s, &old_real_volume);
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-21 02:45:31 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-17 03:45:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_mute(pa_sink *s, pa_bool_t mute, pa_bool_t save) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_bool_t old_muted;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-27 16:25:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    old_muted = s->muted;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->muted = mute;
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-17 03:45:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->save_muted = (old_muted == s->muted && s->save_muted) || save;
							 | 
						
					
						
							
								
									
										
										
										
											2006-01-27 16:25:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (!(s->flags & PA_SINK_SYNC_VOLUME) && s->set_mute)
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        s->set_mute(s);
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (old_muted != s->muted)
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
							 | 
						
					
						
							
								
									
										
										
										
											2004-08-12 23:25:28 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2006-02-23 12:04:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							
								
									
										
										
										
											2008-08-13 13:55:58 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							
								
									
										
										
										
											2006-02-23 12:04:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-08-13 13:55:58 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->refresh_muted || force_refresh) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_bool_t old_muted = s->muted;
							 | 
						
					
						
							
								
									
										
										
										
											2006-02-23 12:04:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (!(s->flags & PA_SINK_SYNC_VOLUME) && s->get_mute)
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            s->get_mute(s);
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
							 | 
						
					
						
							
								
									
										
										
										
											2006-02-23 12:04:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-08 00:02:15 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (old_muted != s->muted) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-07 23:55:06 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            s->save_muted = TRUE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-08 00:02:15 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            /* Make sure the soft mute status stays in sync */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2006-02-23 12:04:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return s->muted;
							 | 
						
					
						
							
								
									
										
										
										
											2006-02-23 12:04:31 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-21 02:45:31 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-07 23:55:06 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-21 02:45:31 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-21 02:45:31 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* The sink implementor may call this if the volume changed to make sure everyone is notified */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-07 23:55:06 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->muted == new_muted)
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-21 02:45:31 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->muted = new_muted;
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-07 23:55:06 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->save_muted = TRUE;
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-17 03:45:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-21 02:45:31 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-13 19:06:10 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-31 02:33:28 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-31 02:33:28 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-24 21:17:55 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (p)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_proplist_update(s->proplist, mode, p);
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-31 02:33:28 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (PA_SINK_IS_LINKED(s->state)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return TRUE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* FIXME -- this should be dropped and be merged into pa_sink_update_proplist() */
							 | 
						
					
						
							
								
									
										
										
										
											2006-08-11 17:53:34 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_description(pa_sink *s, const char *description) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    const char *old;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2006-08-11 17:53:34 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
							 | 
						
					
						
							
								
									
										
										
										
											2006-08-11 17:53:34 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (old && description && pa_streq(old, description))
							 | 
						
					
						
							
								
									
										
										
										
											2006-08-11 17:53:34 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (description)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
							 | 
						
					
						
							
								
									
										
										
										
											2006-08-11 17:53:34 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->monitor_source) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        char *n;
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        n = pa_sprintf_malloc("Monitor Source of %s", description ? description : s->name);
							 | 
						
					
						
							
								
									
										
										
										
											2006-08-11 17:53:34 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_source_set_description(s->monitor_source, n);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_xfree(n);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2007-01-04 13:43:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (PA_SINK_IS_LINKED(s->state)) {
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2006-08-11 17:53:34 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2006-08-12 16:50:58 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								unsigned pa_sink_linked_by(pa_sink *s) {
							 | 
						
					
						
							
								
									
										
										
										
											2006-08-12 16:50:58 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    unsigned ret;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							
								
									
										
										
										
											2006-08-12 16:50:58 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    ret = pa_idxset_size(s->inputs);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* We add in the number of streams connected to us here. Please
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-26 19:32:04 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								     * note the asymmmetry to pa_sink_used_by()! */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-08-12 16:50:58 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->monitor_source)
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        ret += pa_source_linked_by(s->monitor_source);
							 | 
						
					
						
							
								
									
										
										
										
											2006-08-12 16:50:58 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return ret;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								unsigned pa_sink_used_by(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    unsigned ret;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    ret = pa_idxset_size(s->inputs);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(ret >= s->n_corked);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* Streams connected to our monitor source do not matter for
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * pa_sink_used_by()!.*/
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return ret - s->n_corked;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-26 19:32:04 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								unsigned pa_sink_check_suspend(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    unsigned ret;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    uint32_t idx;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2008-12-17 21:03:17 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (!PA_SINK_IS_LINKED(s->state))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return 0;
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-26 19:32:04 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    ret = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-17 03:45:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    PA_IDXSET_FOREACH(i, s->inputs, idx) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-26 19:32:04 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_sink_input_state_t st;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        st = pa_sink_input_get_state(i);
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-01 01:26:43 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        /* We do not assert here. It is perfectly valid for a sink input to
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * be in the INIT state (i.e. created, marked done but not yet put)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * and we should not care if it's unlinked as it won't contribute
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * towarards our busy status.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (!PA_SINK_INPUT_IS_LINKED(st))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            continue;
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-26 19:32:04 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (st == PA_SINK_INPUT_CORKED)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            continue;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            continue;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ret ++;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->monitor_source)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ret += pa_source_check_suspend(s->monitor_source);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return ret;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from the IO thread */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static void sync_input_volumes_within_thread(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    void *state = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            continue;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-02-27 23:02:10 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        i->thread_info.soft_volume = i->soft_volume;
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from the IO thread. Only called for the root sink in volume sharing
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * cases, except for internal recursive calls. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static void set_shared_volume_within_thread(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    void *state = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            set_shared_volume_within_thread(i->origin_sink);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from IO thread, except when it is not */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink *s = PA_SINK(o);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    switch ((pa_sink_message_t) code) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_ADD_INPUT: {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_sink_input *i = PA_SINK_INPUT(userdata);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            /* If you change anything here, make sure to change the
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * sink input handling a few lines down at
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * PA_SINK_MESSAGE_FINISH_MOVE, too. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            /* Since the caller sleeps in pa_sink_input_put(), we can
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * safely access data outside of thread_info even though
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * it is mutable */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if ((i->thread_info.sync_prev = i->sync_prev)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_assert(i->sink == i->thread_info.sync_prev->sink);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_assert(i->sync_prev->sync_next == i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                i->thread_info.sync_prev->thread_info.sync_next = i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if ((i->thread_info.sync_next = i->sync_next)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_assert(i->sink == i->thread_info.sync_next->sink);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_assert(i->sync_next->sync_prev == i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                i->thread_info.sync_next->thread_info.sync_prev = i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_assert(!i->thread_info.attached);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            i->thread_info.attached = TRUE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (i->attach)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                i->attach(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_sink_input_set_state_within_thread(i, i->state);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-08-29 01:20:25 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            /* The requested latency of the sink input needs to be
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * fixed up and then configured on the sink */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_sink_input_update_max_request(i, s->thread_info.max_request);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            /* We don't rewind here automatically. This is left to the
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * sink input implementor because some sink inputs need a
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * slow start, i.e. need some time to buffer client
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * samples before beginning streaming. */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            /* In flat volume mode we need to update the volume as
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * well */
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_REMOVE_INPUT: {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_sink_input *i = PA_SINK_INPUT(userdata);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            /* If you change anything here, make sure to change the
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * sink input handling a few lines down at
							 | 
						
					
						
							
								
									
										
										
										
											2011-03-03 18:35:14 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								             * PA_SINK_MESSAGE_START_MOVE, too. */
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (i->detach)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                i->detach(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-21 02:24:59 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_sink_input_set_state_within_thread(i, i->state);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_assert(i->thread_info.attached);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            i->thread_info.attached = FALSE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            /* Since the caller sleeps in pa_sink_input_unlink(),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * we can safely access data outside of thread_info even
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * though it is mutable */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-27 00:28:42 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_assert(!i->sync_prev);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_assert(!i->sync_next);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (i->thread_info.sync_prev) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                i->thread_info.sync_prev->thread_info.sync_next = i->thread_info.sync_prev->sync_next;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                i->thread_info.sync_prev = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (i->thread_info.sync_next) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                i->thread_info.sync_next->thread_info.sync_prev = i->thread_info.sync_next->sync_prev;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                i->thread_info.sync_next = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_sink_input_unref(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:48:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_sink_invalidate_requested_latency(s, TRUE);
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-26 02:56:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_sink_request_rewind(s, (size_t) -1);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            /* In flat volume mode we need to update the volume as
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * well */
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_START_MOVE: {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_sink_input *i = PA_SINK_INPUT(userdata);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            /* We don't support moving synchronized streams. */
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_assert(!i->sync_prev);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_assert(!i->sync_next);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_assert(!i->thread_info.sync_next);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_assert(!i->thread_info.sync_prev);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_usec_t usec = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                size_t sink_nbytes, total_nbytes;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                /* Get the latency of the sink */
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:52:50 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                usec = pa_sink_get_latency_within_thread(s);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                sink_nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                total_nbytes = sink_nbytes + pa_memblockq_get_length(i->thread_info.render_memblockq);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                if (total_nbytes > 0) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    i->thread_info.rewrite_nbytes = i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, total_nbytes) : total_nbytes;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    i->thread_info.rewrite_flush = TRUE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    pa_sink_input_process_rewind(i, sink_nbytes);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (i->detach)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                i->detach(i);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_assert(i->thread_info.attached);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            i->thread_info.attached = FALSE;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            /* Let's remove the sink input ...*/
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_sink_input_unref(i);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:48:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_sink_invalidate_requested_latency(s, TRUE);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_log_debug("Requesting rewind due to started move");
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-26 02:56:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_sink_request_rewind(s, (size_t) -1);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            /* In flat volume mode we need to update the volume as
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * well */
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_FINISH_MOVE: {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_sink_input *i = PA_SINK_INPUT(userdata);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            /* We don't support moving synchronized streams. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_assert(!i->sync_prev);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_assert(!i->sync_next);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_assert(!i->thread_info.sync_next);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_assert(!i->thread_info.sync_prev);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_assert(!i->thread_info.attached);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            i->thread_info.attached = TRUE;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (i->attach)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                i->attach(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-08-29 01:20:25 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_sink_input_update_max_request(i, s->thread_info.max_request);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_usec_t usec = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                size_t nbytes;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                /* Get the latency of the sink */
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:52:50 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                usec = pa_sink_get_latency_within_thread(s);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                if (nbytes > 0)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    pa_sink_input_drop(i, nbytes);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_log_debug("Requesting rewind due to finished move");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_sink_request_rewind(s, nbytes);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												Implement the "volume sharing" feature.
When we have a filter sink that does some processing, currently the
benefits of the flat volume feature are not really available. That's
because if you have a music player that is connected to the filter sink,
the hardware sink doesn't have any idea of the music player's stream
volume.
This problem is solved by this "volume sharing" feature. The volume
sharing feature works so that the filter sinks that want to avoid the
previously described problem declare that they don't want to have
independent volume, but they follow the master sink volume instead.
The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
declaration. Then the volume logic is changed so that the hardware
sink calculates its real volume using also the streams connected to the
filter sink in addition to the streams that are connected directly to
the hardware sink. Basically we're trying to create an illusion that
from volume point of view all streams are connected directly to the
hardware sink.
For that illusion to work, the volumes of the filter sinks and their
virtual streams have to be managed carefully according to a set of
rules:
If a filter sink follows the hardware sink volume, then the filter sink's
 * reference_volume always equals the hw sink's reference_volume
 * real_volume always equals the hw sink's real_volume
 * soft_volume is always 0dB (ie. no soft volume)
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's
 * reference_volume can be whatever (completely independent from the hw sink)
 * real_volume always equals reference_volume
 * soft_volume always equals real_volume (and reference_volume)
If a filter sink follows the hardware sink volume, and the hardware sink
supports flat volume, then the filter sink's virtual stream's
 * volume always equals the hw sink's real_volume
 * reference_ratio is calculated normally from the stream volume and the hw
   sink's reference_volume
 * real_ratio always equals 0dB (follows from the first point)
 * soft_volume always equals volume_factor (follows from the previous point)
If a filter sink follows the hardware sink volume, and the hardware sink
doesn't support flat volume, then the filter sink's virtual stream's
 * volume is always 0dB
 * reference_ratio is always 0dB
 * real_ratio is always 0dB
 * soft_volume always equals volume_factor
If a filter sink doesn't follow the hardware sink volume, then the filter
sink's virtual stream is handled as a regular stream.
Since the volumes of the virtual streams are controlled by a set of rules,
the user is not allowed to change the virtual streams' volumes. It would
probably also make sense to forbid changing the filter sinks' volume, but
that's not strictly necessary, and currently changing a filter sink's volume
changes actually the hardware sink's volume, and from there it propagates to
all filter sinks ("funny" effects are expected when adjusting a single
channel in cases where all sinks don't have the same channel maps).
This patch is based on the work of Marc-André Lureau, who did the
initial implementation for Pulseaudio 0.9.15.
											
										 
										
											2011-02-24 16:16:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_SET_SHARED_VOLUME: {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_sink *root_sink = s;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                root_sink = root_sink->input_to_master->sink;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            set_shared_volume_within_thread(root_sink);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_SET_VOLUME_SYNCED:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (s->flags & PA_SINK_SYNC_VOLUME) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                s->set_volume(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_sink_volume_change_push(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            /* Fall through ... */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_SET_VOLUME:
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (!pa_cvolume_equal(&s->thread_info.soft_volume, &s->soft_volume)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                s->thread_info.soft_volume = s->soft_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_sink_request_rewind(s, (size_t) -1);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-07 04:47:58 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            /* Fall through ... */
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-07 04:47:58 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_SYNC_VOLUMES:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            sync_input_volumes_within_thread(s);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_GET_VOLUME:
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if ((s->flags & PA_SINK_SYNC_VOLUME) && s->get_volume) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                s->get_volume(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_sink_volume_change_flush(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_sw_cvolume_divide(&s->thread_info.current_hw_volume, &s->real_volume, &s->soft_volume);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            /* In case sink implementor reset SW volume. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (!pa_cvolume_equal(&s->thread_info.soft_volume, &s->soft_volume)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                s->thread_info.soft_volume = s->soft_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_sink_request_rewind(s, (size_t) -1);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_SET_MUTE:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 01:51:27 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (s->thread_info.soft_muted != s->muted) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                s->thread_info.soft_muted = s->muted;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_sink_request_rewind(s, (size_t) -1);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (s->flags & PA_SINK_SYNC_VOLUME && s->set_mute)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                s->set_mute(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_GET_MUTE:
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (s->flags & PA_SINK_SYNC_VOLUME && s->get_mute)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                s->get_mute(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-07 00:46:20 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_SET_STATE: {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_bool_t suspend_change =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                (s->thread_info.state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(PA_PTR_TO_UINT(userdata))) ||
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                (PA_SINK_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SINK_SUSPENDED);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            s->thread_info.state = PA_PTR_TO_UINT(userdata);
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:46:11 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-04 02:51:30 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (s->thread_info.state == PA_SINK_SUSPENDED) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                s->thread_info.rewind_nbytes = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:46:11 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                s->thread_info.rewind_requested = FALSE;
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-04 02:51:30 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:46:11 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-07 00:46:20 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (suspend_change) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                void *state = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    if (i->suspend_within_thread)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        i->suspend_within_thread(i, s->thread_info.state == PA_SINK_SUSPENDED);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-07 00:46:20 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_DETACH:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            /* Detach all streams */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_sink_detach_within_thread(s);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_ATTACH:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            /* Reattach all streams */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_sink_attach_within_thread(s);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_GET_REQUESTED_LATENCY: {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_usec_t *usec = userdata;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            *usec = pa_sink_get_requested_latency_within_thread(s);
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:54:25 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            /* Yes, that's right, the IO thread will see -1 when no
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * explicit requested latency is configured, the main
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * thread will see max_latency */
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (*usec == (pa_usec_t) -1)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                *usec = s->thread_info.max_latency;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_SET_LATENCY_RANGE: {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_usec_t *r = userdata;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-24 21:06:57 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_sink_set_latency_range_within_thread(s, r[0], r[1]);
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_GET_LATENCY_RANGE: {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_usec_t *r = userdata;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            r[0] = s->thread_info.min_latency;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            r[1] = s->thread_info.max_latency;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:48:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_GET_FIXED_LATENCY:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            *((pa_usec_t*) userdata) = s->thread_info.fixed_latency;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_SET_FIXED_LATENCY:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_sink_set_fixed_latency_within_thread(s, (pa_usec_t) offset);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_GET_MAX_REWIND:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            *((size_t*) userdata) = s->thread_info.max_rewind;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_GET_MAX_REQUEST:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            *((size_t*) userdata) = s->thread_info.max_request;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-24 21:13:41 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_SET_MAX_REWIND:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_sink_set_max_rewind_within_thread(s, (size_t) offset);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_SET_MAX_REQUEST:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_sink_set_max_request_within_thread(s, (size_t) offset);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_SET_PORT:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_assert(userdata);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (s->set_port) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                struct sink_message_set_port *msg_data = userdata;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                msg_data->ret = s->set_port(s, msg_data->port);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_UPDATE_VOLUME_AND_MUTE:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            /* This message is sent from IO-thread and handled in main thread. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_assert_ctl_context();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_sink_get_volume(s, TRUE);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pa_sink_get_mute(s, TRUE);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_GET_LATENCY:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        case PA_SINK_MESSAGE_MAX:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            ;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return -1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-05 19:05:07 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause) {
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink *sink;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    uint32_t idx;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    int ret = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_core_assert_ref(c);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-05 19:05:07 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(cause != 0);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    PA_IDXSET_FOREACH(sink, c->sinks, idx) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-04 05:27:49 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        int r;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-05 19:05:07 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if ((r = pa_sink_suspend(sink, suspend, cause)) < 0)
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-04 05:27:49 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            ret = r;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return ret;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_detach(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_DETACH, NULL, 0, NULL) == 0);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_attach(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from IO thread */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_detach_within_thread(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    void *state = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (i->detach)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            i->detach(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->monitor_source)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_source_detach_within_thread(s->monitor_source);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from IO thread */
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_attach_within_thread(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    void *state = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-28 19:13:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (i->attach)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            i->attach(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->monitor_source)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_source_attach_within_thread(s->monitor_source);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from IO thread */
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_request_rewind(pa_sink*s, size_t nbytes) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:45:00 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->thread_info.state == PA_SINK_SUSPENDED)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-26 02:56:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (nbytes == (size_t) -1)
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        nbytes = s->thread_info.max_rewind;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    nbytes = PA_MIN(nbytes, s->thread_info.max_rewind);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-26 02:56:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->thread_info.rewind_requested &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        nbytes <= s->thread_info.rewind_nbytes)
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.rewind_nbytes = nbytes;
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-26 02:56:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.rewind_requested = TRUE;
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->request_rewind)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->request_rewind(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from IO thread */
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_usec_t result = (pa_usec_t) -1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    void *state = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-17 09:14:47 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_usec_t monitor_latency;
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-10 01:26:04 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (!(s->flags & PA_SINK_DYNAMIC_LATENCY))
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:48:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return PA_CLAMP(s->thread_info.fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-10 01:26:04 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->thread_info.requested_latency_valid)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return s->thread_info.requested_latency;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:48:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (i->thread_info.requested_sink_latency != (pa_usec_t) -1 &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            (result == (pa_usec_t) -1 || result > i->thread_info.requested_sink_latency))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            result = i->thread_info.requested_sink_latency;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-17 09:14:47 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    monitor_latency = pa_source_get_requested_latency_within_thread(s->monitor_source);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (monitor_latency != (pa_usec_t) -1 &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        (result == (pa_usec_t) -1 || result > monitor_latency))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        result = monitor_latency;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-10 01:26:04 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (result != (pa_usec_t) -1)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        result = PA_CLAMP(result, s->thread_info.min_latency, s->thread_info.max_latency);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-05-08 02:02:36 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (PA_SINK_IS_LINKED(s->thread_info.state)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        /* Only cache if properly initialized */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->thread_info.requested_latency = result;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->thread_info.requested_latency_valid = TRUE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return result;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								pa_usec_t pa_sink_get_requested_latency(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_usec_t usec = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(PA_SINK_IS_LINKED(s->state));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-02 00:45:00 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->state == PA_SINK_SUSPENDED)
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
							 | 
						
					
						
							
								
									
										
										
										
											2011-05-17 22:31:10 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return usec;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-04 02:51:30 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from IO as well as the main thread -- the latter only before the IO thread started up */
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-24 21:13:41 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_max_rewind_within_thread(pa_sink *s, size_t max_rewind) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    void *state = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (max_rewind == s->thread_info.max_rewind)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.max_rewind = max_rewind;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (PA_SINK_IS_LINKED(s->thread_info.state))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->monitor_source)
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-30 20:19:32 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_source_set_max_rewind_within_thread(s->monitor_source, s->thread_info.max_rewind);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-24 21:13:41 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-24 21:13:41 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (PA_SINK_IS_LINKED(s->state))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_set_max_rewind_within_thread(s, max_rewind);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-04 02:51:30 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from IO as well as the main thread -- the latter only before the IO thread started up */
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-24 21:13:41 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_max_request_within_thread(pa_sink *s, size_t max_request) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    void *state = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (max_request == s->thread_info.max_request)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.max_request = max_request;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (PA_SINK_IS_LINKED(s->thread_info.state)) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-08-29 01:20:25 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_sink_input_update_max_request(i, s->thread_info.max_request);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-24 21:13:41 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_max_request(pa_sink *s, size_t max_request) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-24 21:13:41 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (PA_SINK_IS_LINKED(s->state))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MAX_REQUEST, NULL, max_request, NULL) == 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_set_max_request_within_thread(s, max_request);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from IO thread */
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:48:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_invalidate_requested_latency(pa_sink *s, pa_bool_t dynamic) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    void *state = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:48:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if ((s->flags & PA_SINK_DYNAMIC_LATENCY))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->thread_info.requested_latency_valid = FALSE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else if (dynamic)
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-10 01:26:04 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-25 00:33:35 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (PA_SINK_IS_LINKED(s->thread_info.state)) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-25 00:33:35 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (s->update_requested_latency)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            s->update_requested_latency(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-25 00:33:35 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (i->update_sink_requested_latency)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                i->update_sink_requested_latency(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-15 23:34:41 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-17 09:14:47 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-17 09:14:47 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-17 09:14:47 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* min_latency == 0:           no limit
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * min_latency anything else:  specified limit
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     * Similar for max_latency */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-24 21:06:57 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (min_latency < ABSOLUTE_MIN_LATENCY)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        min_latency = ABSOLUTE_MIN_LATENCY;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-25 00:25:17 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (max_latency <= 0 ||
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        max_latency > ABSOLUTE_MAX_LATENCY)
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-24 21:06:57 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        max_latency = ABSOLUTE_MAX_LATENCY;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(min_latency <= max_latency);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-17 09:14:47 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-25 00:30:54 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* Hmm, let's see if someone forgot to set PA_SINK_DYNAMIC_LATENCY here... */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								               max_latency == ABSOLUTE_MAX_LATENCY) ||
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              (s->flags & PA_SINK_DYNAMIC_LATENCY));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (PA_SINK_IS_LINKED(s->state)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_usec_t r[2];
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        r[0] = min_latency;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        r[1] = max_latency;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-25 00:33:35 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    } else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_set_latency_range_within_thread(s, min_latency, max_latency);
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
							 | 
						
					
						
							
								
									
										
										
										
											2011-03-02 12:41:26 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(min_latency);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(max_latency);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (PA_SINK_IS_LINKED(s->state)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_usec_t r[2] = { 0, 0 };
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        *min_latency = r[0];
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        *max_latency = r[1];
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    } else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        *min_latency = s->thread_info.min_latency;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        *max_latency = s->thread_info.max_latency;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Called from IO thread */
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-24 21:06:57 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-24 21:06:57 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(min_latency <= max_latency);
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-19 03:58:52 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-25 00:30:54 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    /* Hmm, let's see if someone forgot to set PA_SINK_DYNAMIC_LATENCY here... */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								               max_latency == ABSOLUTE_MAX_LATENCY) ||
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              (s->flags & PA_SINK_DYNAMIC_LATENCY));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:54:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->thread_info.min_latency == min_latency &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->thread_info.max_latency == max_latency)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.min_latency = min_latency;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.max_latency = max_latency;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-25 00:33:35 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (PA_SINK_IS_LINKED(s->thread_info.state)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_input *i;
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:54:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        void *state = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-25 00:33:35 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-25 00:33:35 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (i->update_sink_latency_range)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                i->update_sink_latency_range(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:48:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_invalidate_requested_latency(s, FALSE);
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-24 21:06:57 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_source_set_latency_range_within_thread(s->monitor_source, min_latency, max_latency);
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:48:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							
								
									
										
										
										
											2009-05-08 01:56:21 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_fixed_latency(pa_sink *s, pa_usec_t latency) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:48:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->flags & PA_SINK_DYNAMIC_LATENCY) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_assert(latency == 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2009-05-08 01:56:21 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (latency < ABSOLUTE_MIN_LATENCY)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        latency = ABSOLUTE_MIN_LATENCY;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (latency > ABSOLUTE_MAX_LATENCY)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        latency = ABSOLUTE_MAX_LATENCY;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:48:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (PA_SINK_IS_LINKED(s->state))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_FIXED_LATENCY, NULL, (int64_t) latency, NULL) == 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->thread_info.fixed_latency = latency;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-05-08 01:56:21 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_source_set_fixed_latency(s->monitor_source, latency);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-15 00:48:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main thread */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								pa_usec_t pa_sink_get_fixed_latency(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_usec_t latency;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->flags & PA_SINK_DYNAMIC_LATENCY)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (PA_SINK_IS_LINKED(s->state))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_FIXED_LATENCY, &latency, 0, NULL) == 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        latency = s->thread_info.fixed_latency;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return latency;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Called from IO thread */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_sink_set_fixed_latency_within_thread(pa_sink *s, pa_usec_t latency) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_io_context(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->flags & PA_SINK_DYNAMIC_LATENCY) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_assert(latency == 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(latency >= ABSOLUTE_MIN_LATENCY);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(latency <= ABSOLUTE_MAX_LATENCY);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->thread_info.fixed_latency == latency)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.fixed_latency = latency;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (PA_SINK_IS_LINKED(s->thread_info.state)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_input *i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        void *state = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (i->update_sink_fixed_latency)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                i->update_sink_fixed_latency(i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_invalidate_requested_latency(s, FALSE);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_source_set_fixed_latency_within_thread(s->monitor_source, latency);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main context */
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								size_t pa_sink_get_max_rewind(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    size_t r;
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2011-05-17 22:31:10 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (!PA_SINK_IS_LINKED(s->state))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return s->thread_info.max_rewind;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return r;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-27 04:39:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main context */
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								size_t pa_sink_get_max_request(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    size_t r;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (!PA_SINK_IS_LINKED(s->state))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return s->thread_info.max_request;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REQUEST, &r, 0, NULL) == 0);
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-17 09:14:47 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-06-20 22:32:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return r;
							 | 
						
					
						
							
								
									
										
										
										
											2008-05-17 09:14:47 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-01 21:34:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-17 03:45:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from main context */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								int pa_sink_set_port(pa_sink *s, const char *name, pa_bool_t save) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_device_port *port;
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    int ret;
							 | 
						
					
						
							
								
									
										
										
										
											2011-05-17 22:31:10 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-13 02:14:19 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_assert_ref(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert_ctl_context();
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-17 03:45:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (!s->set_port) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_log_debug("set_port() operation not implemented for sink %u \"%s\"", s->index, s->name);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return -PA_ERR_NOTIMPLEMENTED;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (!s->ports)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return -PA_ERR_NOENTITY;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (!(port = pa_hashmap_get(s->ports, name)))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return -PA_ERR_NOENTITY;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->active_port == port) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->save_port = s->save_port || save;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (s->flags & PA_SINK_SYNC_VOLUME) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        struct sink_message_set_port msg = { .port = port, .ret = 0 };
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_PORT, &msg, 0, NULL) == 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ret = msg.ret;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ret = s->set_port(s, port);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (ret < 0)
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-17 03:45:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return -PA_ERR_NOENTITY;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_log_info("Changed port of sink %u \"%s\" to %s", s->index, s->name, port->name);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->active_port = port;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->save_port = save;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 09:25:12 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED], s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-17 03:45:14 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-01 21:34:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-04 18:37:14 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    const char *ff, *c, *t = NULL, *s = "", *profile, *bus;
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-01 21:34:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(p);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (pa_proplist_contains(p, PA_PROP_DEVICE_ICON_NAME))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return TRUE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if ((ff = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR))) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (pa_streq(ff, "microphone"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            t = "audio-input-microphone";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else if (pa_streq(ff, "webcam"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            t = "camera-web";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else if (pa_streq(ff, "computer"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            t = "computer";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else if (pa_streq(ff, "handset"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            t = "phone";
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-04 18:37:14 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        else if (pa_streq(ff, "portable"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            t = "multimedia-player";
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-19 12:38:59 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        else if (pa_streq(ff, "tv"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            t = "video-display";
							 | 
						
					
						
							
								
									
										
										
										
											2009-05-13 01:00:39 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        /*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * The following icons are not part of the icon naming spec,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * because Rodney Dawes sucks as the maintainer of that spec.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         * http://lists.freedesktop.org/archives/xdg/2009-May/010397.html
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else if (pa_streq(ff, "headset"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            t = "audio-headset";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else if (pa_streq(ff, "headphone"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            t = "audio-headphones";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else if (pa_streq(ff, "speaker"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            t = "audio-speakers";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else if (pa_streq(ff, "hands-free"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            t = "audio-handsfree";
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-01 21:34:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-04 18:37:14 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (!t)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if ((c = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (pa_streq(c, "modem"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                t = "modem";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-01 21:34:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (!t) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (is_sink)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            t = "audio-card";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            t = "audio-input-microphone";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if ((profile = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_NAME))) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (strstr(profile, "analog"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            s = "-analog";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else if (strstr(profile, "iec958"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            s = "-iec958";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else if (strstr(profile, "hdmi"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            s = "-hdmi";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    bus = pa_proplist_gets(p, PA_PROP_DEVICE_BUS);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_proplist_setf(p, PA_PROP_DEVICE_ICON_NAME, "%s%s%s%s", t, pa_strempty(s), bus ? "-" : "", pa_strempty(bus));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return TRUE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								pa_bool_t pa_device_init_description(pa_proplist *p) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-18 04:38:59 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    const char *s, *d = NULL, *k;
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-01 21:34:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_assert(p);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (pa_proplist_contains(p, PA_PROP_DEVICE_DESCRIPTION))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return TRUE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR)))
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-18 04:38:59 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (pa_streq(s, "internal"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            d = _("Internal Audio");
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-01 21:34:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-18 04:38:59 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (!d)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (pa_streq(s, "modem"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                d = _("Modem");
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-04 18:37:14 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-18 04:38:59 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (!d)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        d = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_NAME);
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-01 21:34:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-18 04:38:59 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (!d)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return FALSE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    k = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_DESCRIPTION);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (d && k)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_proplist_setf(p, PA_PROP_DEVICE_DESCRIPTION, _("%s %s"), d, k);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else if (d)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, d);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return TRUE;
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-01 21:34:01 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-08 16:58:45 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								pa_bool_t pa_device_init_intended_roles(pa_proplist *p) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    const char *s;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(p);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (pa_proplist_contains(p, PA_PROP_DEVICE_INTENDED_ROLES))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return TRUE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR)))
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-16 12:26:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (pa_streq(s, "handset") || pa_streq(s, "hands-free")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            || pa_streq(s, "headset")) {
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-08 16:58:45 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_proplist_sets(p, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return TRUE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return FALSE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-29 04:31:33 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								unsigned pa_device_init_priority(pa_proplist *p) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    const char *s;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    unsigned priority = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(p);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS))) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (pa_streq(s, "sound"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            priority += 9000;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else if (!pa_streq(s, "modem"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            priority += 1000;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR))) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (pa_streq(s, "internal"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            priority += 900;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else if (pa_streq(s, "speaker"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            priority += 500;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else if (pa_streq(s, "headphone"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            priority += 400;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_BUS))) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (pa_streq(s, "pci"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            priority += 50;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else if (pa_streq(s, "usb"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            priority += 40;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else if (pa_streq(s, "bluetooth"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            priority += 30;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_NAME))) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (pa_startswith(s, "analog-"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            priority += 9;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else if (pa_startswith(s, "iec958-"))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            priority += 8;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return priority;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								PA_STATIC_FLIST_DECLARE(pa_sink_volume_change, 0, pa_xfree);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Called from the IO thread. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static pa_sink_volume_change *pa_sink_volume_change_new(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_volume_change *c;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (!(c = pa_flist_pop(PA_STATIC_FLIST_GET(pa_sink_volume_change))))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        c = pa_xnew(pa_sink_volume_change, 1);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    PA_LLIST_INIT(pa_sink_volume_change, c);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    c->at = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_cvolume_reset(&c->hw_volume, s->sample_spec.channels);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return c;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Called from the IO thread. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static void pa_sink_volume_change_free(pa_sink_volume_change *c) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(c);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (pa_flist_push(PA_STATIC_FLIST_GET(pa_sink_volume_change), c) < 0)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_xfree(c);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Called from the IO thread. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void pa_sink_volume_change_push(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_volume_change *c = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_volume_change *nc = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    uint32_t safety_margin = s->thread_info.volume_change_safety_margin;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    const char *direction = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    nc = pa_sink_volume_change_new(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* NOTE: There is already more different volumes in pa_sink that I can remember.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     *       Adding one more volume for HW would get us rid of this, but I am trying
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     *       to survive with the ones we already have. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sw_cvolume_divide(&nc->hw_volume, &s->real_volume, &s->soft_volume);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (!s->thread_info.volume_changes && pa_cvolume_equal(&nc->hw_volume, &s->thread_info.current_hw_volume)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_log_debug("Volume not changing");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_volume_change_free(nc);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-01-13 16:44:43 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    nc->at = pa_sink_get_latency_within_thread(s);
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    nc->at += pa_rtclock_now() + s->thread_info.volume_change_extra_delay;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->thread_info.volume_changes_tail) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        for (c = s->thread_info.volume_changes_tail; c; c = c->prev) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            /* If volume is going up let's do it a bit late. If it is going
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								             * down let's do it a bit early. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (pa_cvolume_avg(&nc->hw_volume) > pa_cvolume_avg(&c->hw_volume)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                if (nc->at + safety_margin > c->at) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    nc->at += safety_margin;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    direction = "up";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    break;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            else if (nc->at - safety_margin > c->at) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    nc->at -= safety_margin;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    direction = "down";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    break;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (c == NULL) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (pa_cvolume_avg(&nc->hw_volume) > pa_cvolume_avg(&s->thread_info.current_hw_volume)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            nc->at += safety_margin;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            direction = "up";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        } else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            nc->at -= safety_margin;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            direction = "down";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        PA_LLIST_PREPEND(pa_sink_volume_change, s->thread_info.volume_changes, nc);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        PA_LLIST_INSERT_AFTER(pa_sink_volume_change, s->thread_info.volume_changes, c, nc);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-02-27 13:21:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_log_debug("Volume going %s to %d at %llu", direction, pa_cvolume_avg(&nc->hw_volume), (long long unsigned) nc->at);
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* We can ignore volume events that came earlier but should happen later than this. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    PA_LLIST_FOREACH(c, nc->next) {
							 | 
						
					
						
							
								
									
										
										
										
											2011-02-27 13:21:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_log_debug("Volume change to %d at %llu was dropped", pa_cvolume_avg(&c->hw_volume), (long long unsigned) c->at);
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_sink_volume_change_free(c);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    nc->next = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.volume_changes_tail = nc;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Called from the IO thread. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static void pa_sink_volume_change_flush(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_volume_change *c = s->thread_info.volume_changes;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.volume_changes = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    s->thread_info.volume_changes_tail = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    while (c) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_volume_change *next = c->next;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_volume_change_free(c);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        c = next;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Called from the IO thread. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								pa_bool_t pa_sink_volume_change_apply(pa_sink *s, pa_usec_t *usec_to_next) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_usec_t now = pa_rtclock_now();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_bool_t ret = FALSE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s->write_volume);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    while (s->thread_info.volume_changes && now >= s->thread_info.volume_changes->at) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_volume_change *c = s->thread_info.volume_changes;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        PA_LLIST_REMOVE(pa_sink_volume_change, s->thread_info.volume_changes, c);
							 | 
						
					
						
							
								
									
										
										
										
											2011-02-27 13:21:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_log_debug("Volume change to %d at %llu was written %llu usec late",
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                     pa_cvolume_avg(&c->hw_volume), (long long unsigned) c->at, (long long unsigned) (now - c->at));
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        ret = TRUE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->thread_info.current_hw_volume = c->hw_volume;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_sink_volume_change_free(c);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->write_volume && ret)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->write_volume(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->thread_info.volume_changes) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (usec_to_next)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            *usec_to_next = s->thread_info.volume_changes->at - now;
							 | 
						
					
						
							
								
									
										
										
										
											2011-01-22 01:08:36 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (pa_log_ratelimit(PA_LOG_DEBUG))
							 | 
						
					
						
							
								
									
										
										
										
											2011-02-27 13:21:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pa_log_debug("Next volume change in %lld usec", (long long) (s->thread_info.volume_changes->at - now));
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (usec_to_next)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            *usec_to_next = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        s->thread_info.volume_changes_tail = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return ret;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Called from the IO thread. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static void pa_sink_volume_change_rewind(pa_sink *s, size_t nbytes) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    /* All the queued volume events later than current latency are shifted to happen earlier. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_sink_volume_change *c;
							 | 
						
					
						
							
								
									
										
										
										
											2011-01-13 16:44:42 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_volume_t prev_vol = pa_cvolume_avg(&s->thread_info.current_hw_volume);
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_usec_t rewound = pa_bytes_to_usec(nbytes, &s->sample_spec);
							 | 
						
					
						
							
								
									
										
										
										
											2011-01-13 16:44:43 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_usec_t limit = pa_sink_get_latency_within_thread(s);
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-02-27 13:21:41 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_log_debug("latency = %lld", (long long) limit);
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    limit += pa_rtclock_now() + s->thread_info.volume_change_extra_delay;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    PA_LLIST_FOREACH(c, s->thread_info.volume_changes) {
							 | 
						
					
						
							
								
									
										
										
										
											2011-01-13 16:44:42 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_usec_t modified_limit = limit;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (prev_vol > pa_cvolume_avg(&c->hw_volume))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            modified_limit -= s->thread_info.volume_change_safety_margin;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            modified_limit += s->thread_info.volume_change_safety_margin;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (c->at > modified_limit) {
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            c->at -= rewound;
							 | 
						
					
						
							
								
									
										
										
										
											2011-01-13 16:44:42 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if (c->at < modified_limit)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                c->at = modified_limit;
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2011-01-13 16:44:42 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        prev_vol = pa_cvolume_avg(&c->hw_volume);
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2011-01-13 16:44:42 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_sink_volume_change_apply(s, NULL);
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-15 13:05:14 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2011-02-28 13:00:20 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Called from the main thread */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Gets the list of formats supported by the sink. The members and idxset must
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * be freed by the caller. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								pa_idxset* pa_sink_get_formats(pa_sink *s) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_idxset *ret;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (s->get_formats) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        /* Sink supports format query, all is good */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ret = s->get_formats(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    } else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        /* Sink doesn't support format query, so assume it does PCM */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_format_info *f = pa_format_info_new();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        f->encoding = PA_ENCODING_PCM;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ret = pa_idxset_new(NULL, NULL);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_idxset_put(ret, f, NULL);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return ret;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-03-02 11:38:01 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from the main thread */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Checks if the sink can accept this format */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								pa_bool_t pa_sink_check_format(pa_sink *s, pa_format_info *f)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2011-05-17 19:50:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_idxset *formats = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2011-03-02 11:38:01 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_bool_t ret = FALSE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(f);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-05-17 19:50:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    formats = pa_sink_get_formats(s);
							 | 
						
					
						
							
								
									
										
										
										
											2011-03-02 11:38:01 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-05-17 19:50:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (formats) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_format_info *finfo_device;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        uint32_t i;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        PA_IDXSET_FOREACH(finfo_device, formats, i) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (pa_format_info_is_compatible(finfo_device, f)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                ret = TRUE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                break;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							
								
									
										
										
										
											2011-03-02 11:38:01 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-05-17 19:50:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2011-03-02 11:38:01 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return ret;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-02-28 13:00:20 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Called from the main thread */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* Calculates the intersection between formats supported by the sink and
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * in_formats, and returns these, in the order of the sink's formats. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								pa_idxset* pa_sink_check_formats(pa_sink *s, pa_idxset *in_formats) {
							 | 
						
					
						
							
								
									
										
										
										
											2011-03-02 11:16:48 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_idxset *out_formats = pa_idxset_new(NULL, NULL), *sink_formats = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2011-02-28 13:00:20 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pa_format_info *f_sink, *f_in;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    uint32_t i, j;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pa_assert(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (!in_formats || pa_idxset_isempty(in_formats))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        goto done;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    sink_formats = pa_sink_get_formats(s);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    PA_IDXSET_FOREACH(f_sink, sink_formats, i) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        PA_IDXSET_FOREACH(f_in, in_formats, j) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if (pa_format_info_is_compatible(f_sink, f_in))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                pa_idxset_put(out_formats, pa_format_info_copy(f_in), NULL);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								done:
							 | 
						
					
						
							
								
									
										
										
										
											2011-03-02 11:16:48 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (sink_formats)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pa_idxset_free(sink_formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-02-28 13:00:20 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return out_formats;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 |