diff options
Diffstat (limited to 'src')
99 files changed, 2989 insertions, 942 deletions
diff --git a/src/.gitignore b/src/.gitignore index 6cd173c0..64ab2973 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -63,4 +63,5 @@ thread-test utf8-test voltest start-pulseaudio-x11 +start-pulseaudio-kde vector-test diff --git a/src/Makefile.am b/src/Makefile.am index 98c04683..3be28692 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -125,26 +125,7 @@ EXTRA_DIST = \ daemon/pulseaudio.desktop.in \ daemon/pulseaudio-kde.desktop.in \ map-file \ - daemon/pulseaudio-system.conf \ - modules/alsa/mixer/profile-sets/default.conf \ - modules/alsa/mixer/profile-sets/native-instruments-audio4dj.conf \ - modules/alsa/mixer/profile-sets/native-instruments-audio8dj.conf \ - modules/alsa/mixer/profile-sets/90-pulseaudio.rules \ - modules/alsa/mixer/paths/analog-input-aux.conf \ - modules/alsa/mixer/paths/analog-input.conf \ - modules/alsa/mixer/paths/analog-input.conf.common \ - modules/alsa/mixer/paths/analog-input-fm.conf \ - modules/alsa/mixer/paths/analog-input-linein.conf \ - modules/alsa/mixer/paths/analog-input-mic.conf \ - modules/alsa/mixer/paths/analog-input-mic.conf.common \ - modules/alsa/mixer/paths/analog-input-mic-line.conf \ - modules/alsa/mixer/paths/analog-input-tvtuner.conf \ - modules/alsa/mixer/paths/analog-input-video.conf \ - modules/alsa/mixer/paths/analog-output.conf \ - modules/alsa/mixer/paths/analog-output.conf.common \ - modules/alsa/mixer/paths/analog-output-headphones.conf \ - modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf \ - modules/alsa/mixer/paths/analog-output-mono.conf + daemon/pulseaudio-system.conf pulseconf_DATA = \ default.pa \ @@ -1086,17 +1067,17 @@ modlibexec_LTLIBRARIES += \ module-alsa-source.la \ module-alsa-card.la -alsaprofilesets_DATA = \ +dist_alsaprofilesets_DATA = \ modules/alsa/mixer/profile-sets/default.conf \ modules/alsa/mixer/profile-sets/native-instruments-audio4dj.conf \ modules/alsa/mixer/profile-sets/native-instruments-audio8dj.conf if HAVE_UDEV -udevrules_DATA = \ +dist_udevrules_DATA = \ modules/alsa/mixer/profile-sets/90-pulseaudio.rules endif -alsapaths_DATA = \ +dist_alsapaths_DATA = \ modules/alsa/mixer/paths/analog-input-aux.conf \ modules/alsa/mixer/paths/analog-input.conf \ modules/alsa/mixer/paths/analog-input.conf.common \ @@ -1108,8 +1089,10 @@ alsapaths_DATA = \ modules/alsa/mixer/paths/analog-input-tvtuner.conf \ modules/alsa/mixer/paths/analog-input-video.conf \ modules/alsa/mixer/paths/analog-output.conf \ + modules/alsa/mixer/paths/analog-output-speaker.conf \ modules/alsa/mixer/paths/analog-output.conf.common \ modules/alsa/mixer/paths/analog-output-headphones.conf \ + modules/alsa/mixer/paths/analog-output-headphones-2.conf \ modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf \ modules/alsa/mixer/paths/analog-output-mono.conf @@ -1202,6 +1185,7 @@ endif if HAVE_FFTW modlibexec_LTLIBRARIES += \ module-equalizer-sink.la +bin_SCRIPTS += utils/qpaeq endif # These are generated by an M4 script diff --git a/src/daemon/.gitignore b/src/daemon/.gitignore index 0efa55ba..54e4299b 100644 --- a/src/daemon/.gitignore +++ b/src/daemon/.gitignore @@ -1,2 +1,3 @@ org.pulseaudio.policy pulseaudio.desktop +pulseaudio-kde.desktop diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c index c2877ecf..f5042a75 100644 --- a/src/daemon/cpulimit.c +++ b/src/daemon/cpulimit.c @@ -188,15 +188,13 @@ int pa_cpu_limit_init(pa_mainloop_api *m) { last_time = pa_rtclock_now(); /* Prepare the main loop pipe */ - if (pipe(the_pipe) < 0) { + if (pa_pipe_cloexec(the_pipe) < 0) { pa_log("pipe() failed: %s", pa_cstrerror(errno)); return -1; } pa_make_fd_nonblock(the_pipe[0]); pa_make_fd_nonblock(the_pipe[1]); - pa_make_fd_cloexec(the_pipe[0]); - pa_make_fd_cloexec(the_pipe[1]); api = m; io_event = api->io_new(m, the_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 571faae4..bfd5c118 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -577,7 +577,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { c->config_file = NULL; f = filename ? - fopen(c->config_file = pa_xstrdup(filename), "r") : + pa_fopen_cloexec(c->config_file = pa_xstrdup(filename), "r") : pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file); if (!f && errno != ENOENT) { @@ -652,7 +652,7 @@ FILE *pa_daemon_conf_open_default_script_file(pa_daemon_conf *c) { else f = pa_open_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE, &c->default_script_file); } else - f = fopen(c->default_script_file, "r"); + f = pa_fopen_cloexec(c->default_script_file, "r"); return f; } diff --git a/src/daemon/main.c b/src/daemon/main.c index 9e5647a8..e6568364 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -425,21 +425,24 @@ int main(int argc, char *argv[]) { pa_set_env("LD_BIND_NOW", "1"); - canonical_rp = pa_realpath(PA_BINARY); + if ((canonical_rp = pa_realpath(PA_BINARY))) { - if ((rp = pa_readlink("/proc/self/exe"))) { + if ((rp = pa_readlink("/proc/self/exe"))) { - if (pa_streq(rp, canonical_rp)) - pa_assert_se(execv(rp, argv) == 0); - else - pa_log_warn("/proc/self/exe does not point to %s, cannot self execute. Are you playing games?", canonical_rp); + if (pa_streq(rp, canonical_rp)) + pa_assert_se(execv(rp, argv) == 0); + else + pa_log_warn("/proc/self/exe does not point to %s, cannot self execute. Are you playing games?", canonical_rp); - pa_xfree(rp); + pa_xfree(rp); - } else - pa_log_warn("Couldn't read /proc/self/exe, cannot self execute. Running in a chroot()?"); + } else + pa_log_warn("Couldn't read /proc/self/exe, cannot self execute. Running in a chroot()?"); + + pa_xfree(canonical_rp); - pa_xfree(canonical_rp); + } else + pa_log_warn("Couldn't canonicalize binary path, cannot self execute."); } #endif @@ -534,6 +537,12 @@ int main(int argc, char *argv[]) { goto finish; case PA_CMD_DUMP_CONF: { + + if (d < argc) { + pa_log("Too many arguments.\n"); + goto finish; + } + s = pa_daemon_conf_dump(conf); fputs(s, stdout); pa_xfree(s); @@ -544,6 +553,11 @@ int main(int argc, char *argv[]) { case PA_CMD_DUMP_RESAMPLE_METHODS: { int i; + if (d < argc) { + pa_log("Too many arguments.\n"); + goto finish; + } + for (i = 0; i < PA_RESAMPLER_MAX; i++) if (pa_resample_method_supported(i)) printf("%s\n", pa_resample_method_to_string(i)); @@ -558,6 +572,12 @@ int main(int argc, char *argv[]) { goto finish; case PA_CMD_VERSION : + + if (d < argc) { + pa_log("Too many arguments.\n"); + goto finish; + } + printf(PACKAGE_NAME" "PACKAGE_VERSION"\n"); retval = 0; goto finish; @@ -565,6 +585,11 @@ int main(int argc, char *argv[]) { case PA_CMD_CHECK: { pid_t pid; + if (d < argc) { + pa_log("Too many arguments.\n"); + goto finish; + } + if (pa_pid_file_check_running(&pid, "pulseaudio") < 0) pa_log_info(_("Daemon not running")); else { @@ -577,6 +602,11 @@ int main(int argc, char *argv[]) { } case PA_CMD_KILL: + if (d < argc) { + pa_log("Too many arguments.\n"); + goto finish; + } + if (pa_pid_file_kill(SIGINT, NULL, "pulseaudio") < 0) pa_log(_("Failed to kill daemon: %s"), pa_cstrerror(errno)); else @@ -586,6 +616,11 @@ int main(int argc, char *argv[]) { case PA_CMD_CLEANUP_SHM: + if (d < argc) { + pa_log("Too many arguments.\n"); + goto finish; + } + if (pa_shm_cleanup() >= 0) retval = 0; @@ -595,6 +630,11 @@ int main(int argc, char *argv[]) { pa_assert(conf->cmd == PA_CMD_DAEMON || conf->cmd == PA_CMD_START); } + if (d < argc) { + pa_log("Too many arguments.\n"); + goto finish; + } + if (getuid() == 0 && !conf->system_instance) pa_log_warn(_("This program is not intended to be run as root (unless --system is specified).")); #ifndef HAVE_DBUS /* A similar, only a notice worthy check was done earlier, if D-Bus is enabled. */ @@ -645,7 +685,6 @@ int main(int argc, char *argv[]) { if (conf->daemonize) { pid_t child; - int tty_fd; if (pa_stdio_acquire() < 0) { pa_log(_("Failed to acquire stdio.")); @@ -654,7 +693,7 @@ int main(int argc, char *argv[]) { #ifdef HAVE_FORK if (pipe(daemon_pipe) < 0) { - pa_log(_("pipe failed: %s"), pa_cstrerror(errno)); + pa_log(_("pipe() failed: %s"), pa_cstrerror(errno)); goto finish; } @@ -705,22 +744,27 @@ int main(int argc, char *argv[]) { pa_log_set_target(PA_LOG_SYSLOG); #ifdef HAVE_SETSID - setsid(); -#endif -#ifdef HAVE_SETPGID - setpgid(0,0); + if (setsid() < 0) { + pa_log(_("setsid() failed: %s"), pa_cstrerror(errno)); + goto finish; + } #endif -#ifndef OS_IS_WIN32 - pa_close(0); - pa_close(1); - pa_close(2); + /* We now are a session and process group leader. Let's fork + * again and let the father die, so that we'll become a + * process that can never acquire a TTY again, in a session and + * process group without leader */ - pa_assert_se(open("/dev/null", O_RDONLY) == 0); - pa_assert_se(open("/dev/null", O_WRONLY) == 1); - pa_assert_se(open("/dev/null", O_WRONLY) == 2); -#else - FreeConsole(); +#ifdef HAVE_FORK + if ((child = fork()) < 0) { + pa_log(_("fork() failed: %s"), pa_cstrerror(errno)); + goto finish; + } + + if (child != 0) { + retval = 0; + goto finish; + } #endif #ifdef SIGTTOU @@ -733,12 +777,7 @@ int main(int argc, char *argv[]) { signal(SIGTSTP, SIG_IGN); #endif -#ifdef TIOCNOTTY - if ((tty_fd = open("/dev/tty", O_RDWR)) >= 0) { - ioctl(tty_fd, TIOCNOTTY, (char*) 0); - pa_assert_se(pa_close(tty_fd) == 0); - } -#endif + pa_nullify_stdfds(); } pa_set_env_and_record("PULSE_INTERNAL", "1"); @@ -778,6 +817,8 @@ int main(int argc, char *argv[]) { pa_log_debug(_("Running in valgrind mode: %s"), pa_yes_no(pa_in_valgrind())); + pa_log_debug(_("Running in VM: %s"), pa_yes_no(pa_running_in_vm())); + #ifdef __OPTIMIZE__ pa_log_debug(_("Optimized build: yes")); #else diff --git a/src/map-file b/src/map-file index 6f7bdace..1fffaff9 100644 --- a/src/map-file +++ b/src/map-file @@ -66,6 +66,7 @@ pa_context_get_source_info_list; pa_context_get_source_output_info; pa_context_get_source_output_info_list; pa_context_get_state; +pa_context_get_tile_size; pa_context_is_local; pa_context_is_pending; pa_context_kill_client; @@ -129,6 +130,7 @@ pa_cvolume_get_balance; pa_cvolume_get_fade; pa_cvolume_get_position; pa_cvolume_inc; +pa_cvolume_inc_clamp; pa_cvolume_init; pa_cvolume_max; pa_cvolume_max_mask; diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index f3ce681f..8b13239c 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -1712,7 +1712,9 @@ static int option_verify(pa_alsa_option *o) { { "input-boost-on", N_("Boost") }, { "input-boost-off", N_("No Boost") }, { "output-amplifier-on", N_("Amplifier") }, - { "output-amplifier-off", N_("No Amplifier") } + { "output-amplifier-off", N_("No Amplifier") }, + { "output-speaker", N_("Speaker") }, + { "output-headphones", N_("Headphones") } }; pa_assert(o); @@ -1770,15 +1772,17 @@ static int element_verify(pa_alsa_element *e) { static int path_verify(pa_alsa_path *p) { static const struct description_map well_known_descriptions[] = { - { "analog-input", N_("Analog Input") }, - { "analog-input-microphone", N_("Analog Microphone") }, - { "analog-input-linein", N_("Analog Line-In") }, - { "analog-input-radio", N_("Analog Radio") }, - { "analog-input-video", N_("Analog Video") }, - { "analog-output", N_("Analog Output") }, - { "analog-output-headphones", N_("Analog Headphones") }, - { "analog-output-lfe-on-mono", N_("Analog Output (LFE)") }, - { "analog-output-mono", N_("Analog Mono Output") } + { "analog-input", N_("Analog Input") }, + { "analog-input-microphone", N_("Analog Microphone") }, + { "analog-input-linein", N_("Analog Line-In") }, + { "analog-input-radio", N_("Analog Radio") }, + { "analog-input-video", N_("Analog Video") }, + { "analog-output", N_("Analog Output") }, + { "analog-output-headphones", N_("Analog Headphones") }, + { "analog-output-lfe-on-mono", N_("Analog Output (LFE)") }, + { "analog-output-mono", N_("Analog Mono Output") }, + { "analog-output-headphones-2", N_("Analog Headphones 2") }, + { "analog-output-speaker", N_("Analog Speaker") } }; pa_alsa_element *e; diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 37419d98..ed16c834 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -983,7 +983,7 @@ static int unsuspend(struct userdata *u) { buffer_size*u->frame_size != u->hwbuf_size) { pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu/%lu, New %lu/%lu)", (unsigned long) u->hwbuf_size, (unsigned long) u->fragment_size, - (unsigned long) (buffer_size*u->fragment_size), (unsigned long) (period_size*u->frame_size)); + (unsigned long) (buffer_size*u->frame_size), (unsigned long) (period_size*u->frame_size)); goto fail; } @@ -1698,10 +1698,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca goto fail; } - if (use_tsched && !pa_rtclock_hrtimer()) { - pa_log_notice("Disabling timer-based scheduling because high-resolution timers are not available from the kernel."); - use_tsched = FALSE; - } + use_tsched = pa_alsa_may_tsched(use_tsched); u = pa_xnew0(struct userdata, 1); u->core = m->core; diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 37dd6476..157698e3 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -930,7 +930,7 @@ static int unsuspend(struct userdata *u) { buffer_size*u->frame_size != u->hwbuf_size) { pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu/%lu, New %lu/%lu)", (unsigned long) u->hwbuf_size, (unsigned long) u->fragment_size, - (unsigned long) (buffer_size*u->fragment_size), (unsigned long) (period_size*u->frame_size)); + (unsigned long) (buffer_size*u->frame_size), (unsigned long) (period_size*u->frame_size)); goto fail; } @@ -1541,10 +1541,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p goto fail; } - if (use_tsched && !pa_rtclock_hrtimer()) { - pa_log_notice("Disabling timer-based scheduling because high-resolution timers are not available from the kernel."); - use_tsched = FALSE; - } + use_tsched = pa_alsa_may_tsched(use_tsched); u = pa_xnew0(struct userdata, 1); u->core = m->core; diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index 0e22d17e..52f12599 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -43,6 +43,7 @@ #include <pulsecore/once.h> #include <pulsecore/thread.h> #include <pulsecore/conf-parser.h> +#include <pulsecore/core-rtclock.h> #include "alsa-util.h" #include "alsa-mixer.h" @@ -258,6 +259,10 @@ int pa_alsa_set_hw_params( goto finish; } + /* We ignore very small sampling rate deviations */ + if (_ss.rate >= ss->rate*.95 && _ss.rate <= ss->rate*1.05) + _ss.rate = ss->rate; + if (require_exact_channel_number) { if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, _ss.channels)) < 0) { pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret)); @@ -302,7 +307,7 @@ int pa_alsa_set_hw_params( if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 && set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 && snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) { - pa_log_debug("Set buffer size first, period size second."); + pa_log_debug("Set buffer size first (to %lu samples), period size second (to %lu samples).", (unsigned long) _buffer_size, (unsigned long) _period_size); goto success; } @@ -310,7 +315,7 @@ int pa_alsa_set_hw_params( if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 && set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 && snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) { - pa_log_debug("Set period size first, buffer size second."); + pa_log_debug("Set period size first (to %lu samples), buffer size second (to %lu samples).", (unsigned long) _period_size, (unsigned long) _buffer_size); goto success; } } @@ -321,7 +326,7 @@ int pa_alsa_set_hw_params( /* Third try: set only buffer size */ if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 && snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) { - pa_log_debug("Set only buffer size second."); + pa_log_debug("Set only buffer size (to %lu samples).", (unsigned long) _buffer_size); goto success; } } @@ -332,7 +337,7 @@ int pa_alsa_set_hw_params( /* Fourth try: set only period size */ if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 && snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) { - pa_log_debug("Set only period size second."); + pa_log_debug("Set only period size (to %lu samples).", (unsigned long) _period_size); goto success; } } @@ -373,9 +378,7 @@ success: goto finish; } - /* If the sample rate deviates too much, we need to resample */ - if (_ss.rate < ss->rate*.95 || _ss.rate > ss->rate*1.05) - ss->rate = _ss.rate; + ss->rate = _ss.rate; ss->channels = _ss.channels; ss->format = _ss.format; @@ -1308,3 +1311,26 @@ const char* pa_alsa_strerror(int errnum) { return translated; } + +pa_bool_t pa_alsa_may_tsched(pa_bool_t want) { + + if (!want) + return FALSE; + + if (!pa_rtclock_hrtimer()) { + /* We cannot depend on being woken up in time when the timers + are inaccurate, so let's fallback to classic IO based playback + then. */ + pa_log_notice("Disabling timer-based scheduling because high-resolution timers are not available from the kernel."); + return FALSE; } + + if (pa_running_in_vm()) { + /* We cannot depend on being woken up when we ask for in a VM, + * so let's fallback to classic IO based playback then. */ + pa_log_notice("Disabling timer-based scheduling because running inside a VM."); + return FALSE; + } + + + return TRUE; +} diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h index f6206fe2..1d1256bd 100644 --- a/src/modules/alsa/alsa-util.h +++ b/src/modules/alsa/alsa-util.h @@ -142,4 +142,6 @@ pa_bool_t pa_alsa_pcm_is_modem(snd_pcm_t *pcm); const char* pa_alsa_strerror(int errnum); +pa_bool_t pa_alsa_may_tsched(pa_bool_t want); + #endif diff --git a/src/modules/alsa/mixer/paths/analog-input.conf.common b/src/modules/alsa/mixer/paths/analog-input.conf.common index 87af38b3..951e11fa 100644 --- a/src/modules/alsa/mixer/paths/analog-input.conf.common +++ b/src/modules/alsa/mixer/paths/analog-input.conf.common @@ -98,7 +98,11 @@ priority = 18 name = input-docking priority = 17 -;;; ' Capture Source' +[Option Input Source:AUX IN] +name = input +priority = 10 + +;;; 'Capture Source' [Element Capture Source] enumeration = select @@ -244,6 +248,31 @@ name = input-docking [Option Capture Source:Dock Mic] name = input-docking-microphone +;;; 'Mic Jack Mode' + +[Element Mic Jack Mode] +enumeration = select + +[Option Mic Jack Mode:Mic In] +name = input-microphone + +[Option Mic Jack Mode:Line In] +name = input-linein + +;;; 'Digital Input Source' + +[Element Digital Input Source] +enumeration = select + +[Option Digital Input Source:Analog Inputs] +name = input + +[Option Digital Input Source:Digital Mic 1] +name = input-microphone + +[Option Digital Input Source:Digital Mic 2] +name = input-microphone + ;;; Various Boosts [Element Capture Boost] diff --git a/src/modules/alsa/mixer/paths/analog-output-headphones-2.conf b/src/modules/alsa/mixer/paths/analog-output-headphones-2.conf new file mode 100644 index 00000000..f2fd31c7 --- /dev/null +++ b/src/modules/alsa/mixer/paths/analog-output-headphones-2.conf @@ -0,0 +1,82 @@ +# This file is part of PulseAudio. +# +# PulseAudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of the +# License, or (at your option) any later version. +# +# PulseAudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with PulseAudio; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + +; Path for mixers that have a 'Headphone2' control +; +; See analog-output.conf.common for an explanation on the directives + +[General] +priority = 89 + +[Element Hardware Master] +switch = mute +volume = merge +override-map.1 = all +override-map.2 = all-left,all-right + +[Element Master] +switch = mute +volume = merge +override-map.1 = all +override-map.2 = all-left,all-right + +[Element Master Mono] +switch = off +volume = off + +; This profile path is intended to control the second headphones, not +; the first headphones. But it should not hurt if we leave the +; headphone jack enabled nonetheless. +[Element Headphone] +switch = mute +volume = zero + +[Element Headphone2] +required = any +switch = mute +volume = merge +override-map.1 = all +override-map.2 = all-left,all-right + +[Element Speaker] +switch = off +volume = off + +[Element Front] +switch = off +volume = off + +[Element Rear] +switch = off +volume = off + +[Element Surround] +switch = off +volume = off + +[Element Side] +switch = off +volume = off + +[Element Center] +switch = off +volume = off + +[Element LFE] +switch = off +volume = off + +.include analog-output.conf.common diff --git a/src/modules/alsa/mixer/paths/analog-output-headphones.conf b/src/modules/alsa/mixer/paths/analog-output-headphones.conf index 61d2e297..2131cfe8 100644 --- a/src/modules/alsa/mixer/paths/analog-output-headphones.conf +++ b/src/modules/alsa/mixer/paths/analog-output-headphones.conf @@ -44,6 +44,13 @@ volume = merge override-map.1 = all override-map.2 = all-left,all-right +; This profile path is intended to control the first headphones, not +; the second headphones. But it should not hurt if we leave the second +; headphone jack enabled nonetheless. +[Element Headphone2] +switch = mute +volume = zero + [Element Speaker] switch = off volume = off diff --git a/src/modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf b/src/modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf index 911361d7..0a43e271 100644 --- a/src/modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf +++ b/src/modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf @@ -48,6 +48,10 @@ override-map.2 = lfe,lfe switch = mute volume = zero +[Element Headphone2] +switch = mute +volume = zero + [Element Speaker] switch = mute volume = merge diff --git a/src/modules/alsa/mixer/paths/analog-output-mono.conf b/src/modules/alsa/mixer/paths/analog-output-mono.conf index 2fbc60b7..542edc40 100644 --- a/src/modules/alsa/mixer/paths/analog-output-mono.conf +++ b/src/modules/alsa/mixer/paths/analog-output-mono.conf @@ -45,6 +45,10 @@ override-map.2 = all-left,all-right switch = mute volume = zero +[Element Headphone2] +switch = mute +volume = zero + [Element Speaker] switch = mute volume = merge diff --git a/src/modules/alsa/mixer/paths/analog-output-speaker.conf b/src/modules/alsa/mixer/paths/analog-output-speaker.conf new file mode 100644 index 00000000..aea78534 --- /dev/null +++ b/src/modules/alsa/mixer/paths/analog-output-speaker.conf @@ -0,0 +1,94 @@ +# This file is part of PulseAudio. +# +# PulseAudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of the +# License, or (at your option) any later version. +# +# PulseAudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with PulseAudio; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + +; Path for mixers that have a 'Speaker' control +; +; See analog-output.conf.common for an explanation on the directives + +[General] +priority = 100 + +[Element Hardware Master] +switch = mute +volume = merge +override-map.1 = all +override-map.2 = all-left,all-right + +[Element Master] +switch = mute +volume = merge +override-map.1 = all +override-map.2 = all-left,all-right + +[Element Master Mono] +switch = off +volume = off + +; This profile path is intended to control the speaker, not the +; headphones. But it should not hurt if we leave the headphone jack +; enabled nonetheless. +[Element Headphone] +switch = mute +volume = zero + +[Element Headphone2] +switch = mute +volume = zero + +[Element Speaker] +required = any +switch = mute +volume = merge +override-map.1 = all +override-map.2 = all-left,all-right + +[Element Front] +switch = mute +volume = merge +override-map.1 = all-front +override-map.2 = front-left,front-right + +[Element Rear] +switch = mute +volume = merge +override-map.1 = all-rear +override-map.2 = rear-left,rear-right + +[Element Surround] +switch = mute +volume = merge +override-map.1 = all-rear +override-map.2 = rear-left,rear-right + +[Element Side] +switch = mute +volume = merge +override-map.1 = all-side +override-map.2 = side-left,side-right + +[Element Center] +switch = mute +volume = merge +override-map.1 = all-center +override-map.2 = all-center,all-center + +[Element LFE] +switch = mute +volume = merge +override-map.1 = lfe +override-map.2 = lfe,lfe + +.include analog-output.conf.common diff --git a/src/modules/alsa/mixer/paths/analog-output.conf b/src/modules/alsa/mixer/paths/analog-output.conf index f71a05a1..d7c1223b 100644 --- a/src/modules/alsa/mixer/paths/analog-output.conf +++ b/src/modules/alsa/mixer/paths/analog-output.conf @@ -14,12 +14,13 @@ # along with PulseAudio; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -; Intended for the 'default' output +; Intended for the 'default' output. Note that a-o-speaker.conf has a +; higher priority than this ; ; See analog-output.conf.common for an explanation on the directives [General] -priority = 100 +priority = 99 [Element Hardware Master] switch = mute @@ -37,18 +38,20 @@ override-map.2 = all-left,all-right switch = off volume = off -; This profile path is intended to control the speaker, not the +; This profile path is intended to control the default output, not the ; headphones. But it should not hurt if we leave the headphone jack ; enabled nonetheless. [Element Headphone] switch = mute volume = zero +[Element Headphone2] +switch = mute +volume = zero + [Element Speaker] switch = mute -volume = merge -override-map.1 = all -override-map.2 = all-left,all-right +volume = off [Element Front] switch = mute diff --git a/src/modules/alsa/mixer/paths/analog-output.conf.common b/src/modules/alsa/mixer/paths/analog-output.conf.common index 3c6ce803..fd7f0cfb 100644 --- a/src/modules/alsa/mixer/paths/analog-output.conf.common +++ b/src/modules/alsa/mixer/paths/analog-output.conf.common @@ -109,3 +109,20 @@ priority = 10 [Option External Amplifier:off] name = output-amplifier-off priority = 0 + +;;; 'Analog Output' + +[Element Analog Output] +enumeration = select + +[Option Analog Output:Speakers] +name = output-speaker +priority = 10 + +[Option Analog Output:Headphones] +name = output-headphones +priority = 9 + +[Option Analog Output:FP Headphones] +name = output-headphones +priority = 8 diff --git a/src/modules/alsa/mixer/profile-sets/default.conf b/src/modules/alsa/mixer/profile-sets/default.conf index ac41a8d3..046938fc 100644 --- a/src/modules/alsa/mixer/profile-sets/default.conf +++ b/src/modules/alsa/mixer/profile-sets/default.conf @@ -62,42 +62,42 @@ auto-profiles = yes [Mapping analog-mono] device-strings = hw:%f channel-map = mono -paths-output = analog-output analog-output-headphones analog-output-mono analog-output-lfe-on-mono +paths-output = analog-output analog-output-speaker analog-output-headphones analog-output-headphones-2 analog-output-mono analog-output-lfe-on-mono paths-input = analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line priority = 1 [Mapping analog-stereo] device-strings = front:%f hw:%f channel-map = left,right -paths-output = analog-output analog-output-headphones analog-output-mono analog-output-lfe-on-mono +paths-output = analog-output analog-output-speaker analog-output-headphones analog-output-headphones-2 analog-output-mono analog-output-lfe-on-mono paths-input = analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line priority = 10 [Mapping analog-surround-40] device-strings = surround40:%f channel-map = front-left,front-right,rear-left,rear-right -paths-output = analog-output analog-output-lfe-on-mono +paths-output = analog-output analog-output-speaker analog-output-lfe-on-mono priority = 7 direction = output [Mapping analog-surround-41] device-strings = surround41:%f channel-map = front-left,front-right,rear-left,rear-right,lfe -paths-output = analog-output analog-output-lfe-on-mono +paths-output = analog-output analog-output-speaker analog-output-lfe-on-mono priority = 8 direction = output [Mapping analog-surround-50] device-strings = surround50:%f channel-map = front-left,front-right,rear-left,rear-right,front-center -paths-output = analog-output analog-output-lfe-on-mono +paths-output = analog-output analog-output-speaker analog-output-lfe-on-mono priority = 7 direction = output [Mapping analog-surround-51] device-strings = surround51:%f channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe -paths-output = analog-output analog-output-lfe-on-mono +paths-output = analog-output analog-output-speaker analog-output-lfe-on-mono priority = 8 direction = output @@ -105,7 +105,7 @@ direction = output device-strings = surround71:%f channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right description = Analog Surround 7.1 -paths-output = analog-output analog-output-lfe-on-mono +paths-output = analog-output analog-output-speaker analog-output-lfe-on-mono priority = 7 direction = output diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c index f8c5b778..47d62005 100644 --- a/src/modules/bluetooth/bluetooth-util.c +++ b/src/modules/bluetooth/bluetooth-util.c @@ -723,12 +723,14 @@ const pa_bluetooth_device* pa_bluetooth_discovery_get_by_address(pa_bluetooth_di while ((d = pa_hashmap_iterate(y->devices, &state, NULL))) if (pa_streq(d->address, address)) - return d; + return device_is_audio(d) ? d : NULL; return NULL; } const pa_bluetooth_device* pa_bluetooth_discovery_get_by_path(pa_bluetooth_discovery *y, const char* path) { + pa_bluetooth_device *d; + pa_assert(y); pa_assert(PA_REFCNT_VALUE(y) > 0); pa_assert(path); @@ -736,7 +738,11 @@ const pa_bluetooth_device* pa_bluetooth_discovery_get_by_path(pa_bluetooth_disco if (!pa_hook_is_firing(&y->hook)) pa_bluetooth_discovery_sync(y); - return pa_hashmap_get(y->devices, path); + if ((d = pa_hashmap_get(y->devices, path))) + if (device_is_audio(d)) + return d; + + return NULL; } static int setup_dbus(pa_bluetooth_discovery *y) { diff --git a/src/modules/dbus/iface-card.c b/src/modules/dbus/iface-card.c index 1714df36..d99c8b95 100644 --- a/src/modules/dbus/iface-card.c +++ b/src/modules/dbus/iface-card.c @@ -452,7 +452,7 @@ static void handle_get_profile_by_name(DBusConnection *conn, DBusMessage *msg, v static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { pa_dbusiface_card *c = userdata; - DBusMessage *signal = NULL; + DBusMessage *signal_msg = NULL; pa_assert(core); pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_CARD); @@ -472,14 +472,14 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 c->active_profile = c->card->active_profile; object_path = pa_dbusiface_card_profile_get_path(pa_hashmap_get(c->profiles, c->active_profile->name)); - pa_assert_se(signal = dbus_message_new_signal(c->path, - PA_DBUSIFACE_CARD_INTERFACE, - signals[SIGNAL_ACTIVE_PROFILE_UPDATED].name)); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_assert_se(signal_msg = dbus_message_new_signal(c->path, + PA_DBUSIFACE_CARD_INTERFACE, + signals[SIGNAL_ACTIVE_PROFILE_UPDATED].name)); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(c->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } if (!pa_proplist_equal(c->proplist, c->card->proplist)) { @@ -487,15 +487,15 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 pa_proplist_update(c->proplist, PA_UPDATE_SET, c->card->proplist); - pa_assert_se(signal = dbus_message_new_signal(c->path, - PA_DBUSIFACE_CARD_INTERFACE, - signals[SIGNAL_PROPERTY_LIST_UPDATED].name)); - dbus_message_iter_init_append(signal, &msg_iter); + pa_assert_se(signal_msg = dbus_message_new_signal(c->path, + PA_DBUSIFACE_CARD_INTERFACE, + signals[SIGNAL_PROPERTY_LIST_UPDATED].name)); + dbus_message_iter_init_append(signal_msg, &msg_iter); pa_dbus_append_proplist(&msg_iter, c->proplist); - pa_dbus_protocol_send_signal(c->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } } diff --git a/src/modules/dbus/iface-client.c b/src/modules/dbus/iface-client.c index 2b6f0d0d..e6675449 100644 --- a/src/modules/dbus/iface-client.c +++ b/src/modules/dbus/iface-client.c @@ -391,7 +391,7 @@ static void handle_remove_properties(DBusConnection *conn, DBusMessage *msg, voi static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { pa_dbusiface_client *c = userdata; - DBusMessage *signal = NULL; + DBusMessage *signal_msg = NULL; pa_assert(core); pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_CLIENT); @@ -410,15 +410,15 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 pa_proplist_update(c->proplist, PA_UPDATE_SET, c->client->proplist); - pa_assert_se(signal = dbus_message_new_signal(c->path, - PA_DBUSIFACE_CLIENT_INTERFACE, - signals[SIGNAL_PROPERTY_LIST_UPDATED].name)); - dbus_message_iter_init_append(signal, &msg_iter); + pa_assert_se(signal_msg = dbus_message_new_signal(c->path, + PA_DBUSIFACE_CLIENT_INTERFACE, + signals[SIGNAL_PROPERTY_LIST_UPDATED].name)); + dbus_message_iter_init_append(signal_msg, &msg_iter); pa_dbus_append_proplist(&msg_iter, c->proplist); - pa_dbus_protocol_send_signal(c->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } } diff --git a/src/modules/dbus/iface-core.c b/src/modules/dbus/iface-core.c index 169e8e55..497b59b5 100644 --- a/src/modules/dbus/iface-core.c +++ b/src/modules/dbus/iface-core.c @@ -1488,7 +1488,7 @@ static void handle_exit(DBusConnection *conn, DBusMessage *msg, void *userdata) static void handle_listen_for_signal(DBusConnection *conn, DBusMessage *msg, void *userdata) { pa_dbusiface_core *c = userdata; - const char *signal; + const char *signal_str; char **objects = NULL; int n_objects; @@ -1497,11 +1497,11 @@ static void handle_listen_for_signal(DBusConnection *conn, DBusMessage *msg, voi pa_assert(c); pa_assert_se(dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &signal, + DBUS_TYPE_STRING, &signal_str, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &objects, &n_objects, DBUS_TYPE_INVALID)); - pa_dbus_protocol_add_signal_listener(c->dbus_protocol, conn, *signal ? signal : NULL, objects, n_objects); + pa_dbus_protocol_add_signal_listener(c->dbus_protocol, conn, *signal_str ? signal_str : NULL, objects, n_objects); pa_dbus_send_empty_reply(conn, msg); @@ -1510,15 +1510,15 @@ static void handle_listen_for_signal(DBusConnection *conn, DBusMessage *msg, voi static void handle_stop_listening_for_signal(DBusConnection *conn, DBusMessage *msg, void *userdata) { pa_dbusiface_core *c = userdata; - const char *signal; + const char *signal_str; pa_assert(conn); pa_assert(msg); pa_assert(c); - pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &signal, DBUS_TYPE_INVALID)); + pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &signal_str, DBUS_TYPE_INVALID)); - pa_dbus_protocol_remove_signal_listener(c->dbus_protocol, conn, *signal ? signal : NULL); + pa_dbus_protocol_remove_signal_listener(c->dbus_protocol, conn, *signal_str ? signal_str : NULL); pa_dbus_send_empty_reply(conn, msg); } @@ -1531,7 +1531,7 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 pa_dbusiface_sample *sample_iface = NULL; pa_dbusiface_module *module_iface = NULL; pa_dbusiface_client *client_iface = NULL; - DBusMessage *signal = NULL; + DBusMessage *signal_msg = NULL; const char *object_path = NULL; pa_sink *new_fallback_sink = NULL; pa_source *new_fallback_source = NULL; @@ -1552,21 +1552,21 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 && (device_iface = pa_hashmap_get(c->sinks_by_index, PA_UINT32_TO_PTR(new_fallback_sink->index)))) { object_path = pa_dbusiface_device_get_path(device_iface); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_FALLBACK_SINK_UPDATED].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(c->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_FALLBACK_SINK_UPDATED].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } else if (!new_fallback_sink) { - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_FALLBACK_SINK_UNSET].name))); - pa_dbus_protocol_send_signal(c->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_FALLBACK_SINK_UNSET].name))); + pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } } @@ -1579,21 +1579,21 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 && (device_iface = pa_hashmap_get(c->sources_by_index, PA_UINT32_TO_PTR(new_fallback_source->index)))) { object_path = pa_dbusiface_device_get_path(device_iface); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_FALLBACK_SOURCE_UPDATED].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(c->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_FALLBACK_SOURCE_UPDATED].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } else if (!new_fallback_source) { - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_FALLBACK_SOURCE_UNSET].name))); - pa_dbus_protocol_send_signal(c->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_FALLBACK_SOURCE_UNSET].name))); + pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } } break; @@ -1612,10 +1612,10 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 object_path = pa_dbusiface_card_get_path(card_iface); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_NEW_CARD].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_NEW_CARD].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { if (!(card_iface = pa_hashmap_remove(c->cards, PA_UINT32_TO_PTR(idx)))) @@ -1623,10 +1623,10 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 object_path = pa_dbusiface_card_get_path(card_iface); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_CARD_REMOVED].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_CARD_REMOVED].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); pa_dbusiface_card_free(card_iface); } @@ -1647,28 +1647,28 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 object_path = pa_dbusiface_device_get_path(device_iface); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_NEW_SINK].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_NEW_SINK].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(c->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; if (c->fallback_sink && pa_streq(c->fallback_sink->name, sink->name)) { /* We have got default sink change event, but at that point * the D-Bus sink object wasn't created yet. Now that the * object is created, let's send the fallback sink change * signal. */ - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_FALLBACK_SINK_UPDATED].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); - - pa_dbus_protocol_send_signal(c->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_FALLBACK_SINK_UPDATED].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + + pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { @@ -1678,10 +1678,10 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 object_path = pa_dbusiface_device_get_path(device_iface); pa_assert_se(pa_hashmap_remove(c->sinks_by_path, object_path)); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_SINK_REMOVED].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_SINK_REMOVED].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); pa_dbusiface_device_free(device_iface); } @@ -1702,28 +1702,28 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 object_path = pa_dbusiface_device_get_path(device_iface); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_NEW_SOURCE].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_NEW_SOURCE].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(c->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; if (c->fallback_source && pa_streq(c->fallback_source->name, source->name)) { /* We have got default source change event, but at that * point the D-Bus source object wasn't created yet. Now * that the object is created, let's send the fallback * source change signal. */ - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_FALLBACK_SOURCE_UPDATED].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); - - pa_dbus_protocol_send_signal(c->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_FALLBACK_SOURCE_UPDATED].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + + pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { @@ -1733,10 +1733,10 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 object_path = pa_dbusiface_device_get_path(device_iface); pa_assert_se(pa_hashmap_remove(c->sources_by_path, object_path)); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_SOURCE_REMOVED].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_SOURCE_REMOVED].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); pa_dbusiface_device_free(device_iface); } @@ -1756,10 +1756,10 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 object_path = pa_dbusiface_stream_get_path(stream_iface); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_NEW_PLAYBACK_STREAM].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_NEW_PLAYBACK_STREAM].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { if (!(stream_iface = pa_hashmap_remove(c->playback_streams, PA_UINT32_TO_PTR(idx)))) @@ -1767,10 +1767,10 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 object_path = pa_dbusiface_stream_get_path(stream_iface); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_PLAYBACK_STREAM_REMOVED].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_PLAYBACK_STREAM_REMOVED].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); pa_dbusiface_stream_free(stream_iface); } @@ -1790,10 +1790,10 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 object_path = pa_dbusiface_stream_get_path(stream_iface); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_NEW_RECORD_STREAM].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_NEW_RECORD_STREAM].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { if (!(stream_iface = pa_hashmap_remove(c->record_streams, PA_UINT32_TO_PTR(idx)))) @@ -1801,10 +1801,10 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 object_path = pa_dbusiface_stream_get_path(stream_iface); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_RECORD_STREAM_REMOVED].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_RECORD_STREAM_REMOVED].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); pa_dbusiface_stream_free(stream_iface); } @@ -1824,10 +1824,10 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 object_path = pa_dbusiface_sample_get_path(sample_iface); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_NEW_SAMPLE].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_NEW_SAMPLE].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { if (!(sample_iface = pa_hashmap_remove(c->samples, PA_UINT32_TO_PTR(idx)))) @@ -1835,10 +1835,10 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 object_path = pa_dbusiface_sample_get_path(sample_iface); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_SAMPLE_REMOVED].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_SAMPLE_REMOVED].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); pa_dbusiface_sample_free(sample_iface); } @@ -1858,10 +1858,10 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 object_path = pa_dbusiface_module_get_path(module_iface); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_NEW_MODULE].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_NEW_MODULE].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { if (!(module_iface = pa_hashmap_remove(c->modules, PA_UINT32_TO_PTR(idx)))) @@ -1869,10 +1869,10 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 object_path = pa_dbusiface_module_get_path(module_iface); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_MODULE_REMOVED].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_MODULE_REMOVED].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); pa_dbusiface_module_free(module_iface); } @@ -1892,10 +1892,10 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 object_path = pa_dbusiface_client_get_path(client_iface); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_NEW_CLIENT].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_NEW_CLIENT].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { if (!(client_iface = pa_hashmap_remove(c->clients, PA_UINT32_TO_PTR(idx)))) @@ -1903,37 +1903,37 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 object_path = pa_dbusiface_client_get_path(client_iface); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_CLIENT_REMOVED].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_CLIENT_REMOVED].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); pa_dbusiface_client_free(client_iface); } break; } - if (signal) { - pa_dbus_protocol_send_signal(c->dbus_protocol, signal); - dbus_message_unref(signal); + if (signal_msg) { + pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); } } static pa_hook_result_t extension_registered_cb(void *hook_data, void *call_data, void *slot_data) { pa_dbusiface_core *c = slot_data; const char *ext_name = call_data; - DBusMessage *signal = NULL; + DBusMessage *signal_msg = NULL; pa_assert(c); pa_assert(ext_name); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_NEW_EXTENSION].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_STRING, &ext_name, DBUS_TYPE_INVALID)); + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_NEW_EXTENSION].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_STRING, &ext_name, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(c->dbus_protocol, signal); - dbus_message_unref(signal); + pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); return PA_HOOK_OK; } @@ -1941,18 +1941,18 @@ static pa_hook_result_t extension_registered_cb(void *hook_data, void *call_data static pa_hook_result_t extension_unregistered_cb(void *hook_data, void *call_data, void *slot_data) { pa_dbusiface_core *c = slot_data; const char *ext_name = call_data; - DBusMessage *signal = NULL; + DBusMessage *signal_msg = NULL; pa_assert(c); pa_assert(ext_name); - pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, - PA_DBUS_CORE_INTERFACE, - signals[SIGNAL_EXTENSION_REMOVED].name))); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_STRING, &ext_name, DBUS_TYPE_INVALID)); + pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH, + PA_DBUS_CORE_INTERFACE, + signals[SIGNAL_EXTENSION_REMOVED].name))); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_STRING, &ext_name, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(c->dbus_protocol, signal); - dbus_message_unref(signal); + pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); return PA_HOOK_OK; } diff --git a/src/modules/dbus/iface-device.c b/src/modules/dbus/iface-device.c index 3a747a44..bb91d71f 100644 --- a/src/modules/dbus/iface-device.c +++ b/src/modules/dbus/iface-device.c @@ -1063,7 +1063,7 @@ static void handle_source_get_all(DBusConnection *conn, DBusMessage *msg, void * static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { pa_dbusiface_device *d = userdata; - DBusMessage *signal = NULL; + DBusMessage *signal_msg = NULL; const pa_cvolume *new_volume = NULL; pa_bool_t new_mute = FALSE; pa_sink_state_t new_sink_state = 0; @@ -1099,16 +1099,16 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t for (i = 0; i < d->volume.channels; ++i) volume[i] = d->volume.values[i]; - pa_assert_se(signal = dbus_message_new_signal(d->path, - PA_DBUSIFACE_DEVICE_INTERFACE, - signals[SIGNAL_VOLUME_UPDATED].name)); - pa_assert_se(dbus_message_append_args(signal, + pa_assert_se(signal_msg = dbus_message_new_signal(d->path, + PA_DBUSIFACE_DEVICE_INTERFACE, + signals[SIGNAL_VOLUME_UPDATED].name)); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, d->volume.channels, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(d->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_dbus_protocol_send_signal(d->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } new_mute = (d->type == DEVICE_TYPE_SINK) ? pa_sink_get_mute(d->sink, FALSE) : pa_source_get_mute(d->source, FALSE); @@ -1116,14 +1116,14 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t if (d->mute != new_mute) { d->mute = new_mute; - pa_assert_se(signal = dbus_message_new_signal(d->path, - PA_DBUSIFACE_DEVICE_INTERFACE, - signals[SIGNAL_MUTE_UPDATED].name)); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_BOOLEAN, &d->mute, DBUS_TYPE_INVALID)); + pa_assert_se(signal_msg = dbus_message_new_signal(d->path, + PA_DBUSIFACE_DEVICE_INTERFACE, + signals[SIGNAL_MUTE_UPDATED].name)); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_BOOLEAN, &d->mute, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(d->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_dbus_protocol_send_signal(d->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } if (d->type == DEVICE_TYPE_SINK) @@ -1142,14 +1142,14 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t state = (d->type == DEVICE_TYPE_SINK) ? d->sink_state : d->source_state; - pa_assert_se(signal = dbus_message_new_signal(d->path, - PA_DBUSIFACE_DEVICE_INTERFACE, - signals[SIGNAL_STATE_UPDATED].name)); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID)); + pa_assert_se(signal_msg = dbus_message_new_signal(d->path, + PA_DBUSIFACE_DEVICE_INTERFACE, + signals[SIGNAL_STATE_UPDATED].name)); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(d->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_dbus_protocol_send_signal(d->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } new_active_port = (d->type == DEVICE_TYPE_SINK) ? d->sink->active_port : d->source->active_port; @@ -1160,14 +1160,14 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t d->active_port = new_active_port; object_path = pa_dbusiface_device_port_get_path(pa_hashmap_get(d->ports, d->active_port->name)); - pa_assert_se(signal = dbus_message_new_signal(d->path, - PA_DBUSIFACE_DEVICE_INTERFACE, - signals[SIGNAL_ACTIVE_PORT_UPDATED].name)); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); + pa_assert_se(signal_msg = dbus_message_new_signal(d->path, + PA_DBUSIFACE_DEVICE_INTERFACE, + signals[SIGNAL_ACTIVE_PORT_UPDATED].name)); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(d->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_dbus_protocol_send_signal(d->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } new_proplist = (d->type == DEVICE_TYPE_SINK) ? d->sink->proplist : d->source->proplist; @@ -1177,15 +1177,15 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t pa_proplist_update(d->proplist, PA_UPDATE_SET, new_proplist); - pa_assert_se(signal = dbus_message_new_signal(d->path, - PA_DBUSIFACE_DEVICE_INTERFACE, - signals[SIGNAL_PROPERTY_LIST_UPDATED].name)); - dbus_message_iter_init_append(signal, &msg_iter); + pa_assert_se(signal_msg = dbus_message_new_signal(d->path, + PA_DBUSIFACE_DEVICE_INTERFACE, + signals[SIGNAL_PROPERTY_LIST_UPDATED].name)); + dbus_message_iter_init_append(signal_msg, &msg_iter); pa_dbus_append_proplist(&msg_iter, d->proplist); - pa_dbus_protocol_send_signal(d->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_dbus_protocol_send_signal(d->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } } diff --git a/src/modules/dbus/iface-module.c b/src/modules/dbus/iface-module.c index e8aea50f..9973166c 100644 --- a/src/modules/dbus/iface-module.c +++ b/src/modules/dbus/iface-module.c @@ -268,7 +268,7 @@ static void handle_unload(DBusConnection *conn, DBusMessage *msg, void *userdata static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { pa_dbusiface_module *m = userdata; - DBusMessage *signal = NULL; + DBusMessage *signal_msg = NULL; pa_assert(core); pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_MODULE); @@ -287,15 +287,15 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3 pa_proplist_update(m->proplist, PA_UPDATE_SET, m->module->proplist); - pa_assert_se(signal = dbus_message_new_signal(m->path, - PA_DBUSIFACE_MODULE_INTERFACE, - signals[SIGNAL_PROPERTY_LIST_UPDATED].name)); - dbus_message_iter_init_append(signal, &msg_iter); + pa_assert_se(signal_msg = dbus_message_new_signal(m->path, + PA_DBUSIFACE_MODULE_INTERFACE, + signals[SIGNAL_PROPERTY_LIST_UPDATED].name)); + dbus_message_iter_init_append(signal_msg, &msg_iter); pa_dbus_append_proplist(&msg_iter, m->proplist); - pa_dbus_protocol_send_signal(m->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_dbus_protocol_send_signal(m->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } } diff --git a/src/modules/dbus/iface-sample.c b/src/modules/dbus/iface-sample.c index b0542a60..c1fa193c 100644 --- a/src/modules/dbus/iface-sample.c +++ b/src/modules/dbus/iface-sample.c @@ -450,7 +450,7 @@ static void handle_remove(DBusConnection *conn, DBusMessage *msg, void *userdata static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { pa_dbusiface_sample *s = userdata; - DBusMessage *signal = NULL; + DBusMessage *signal_msg = NULL; pa_assert(c); pa_assert(s); @@ -468,15 +468,15 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t pa_proplist_update(s->proplist, PA_UPDATE_SET, s->sample->proplist); - pa_assert_se(signal = dbus_message_new_signal(s->path, - PA_DBUSIFACE_SAMPLE_INTERFACE, - signals[SIGNAL_PROPERTY_LIST_UPDATED].name)); - dbus_message_iter_init_append(signal, &msg_iter); + pa_assert_se(signal_msg = dbus_message_new_signal(s->path, + PA_DBUSIFACE_SAMPLE_INTERFACE, + signals[SIGNAL_PROPERTY_LIST_UPDATED].name)); + dbus_message_iter_init_append(signal_msg, &msg_iter); pa_dbus_append_proplist(&msg_iter, s->proplist); - pa_dbus_protocol_send_signal(s->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } } diff --git a/src/modules/dbus/iface-stream.c b/src/modules/dbus/iface-stream.c index 04a45e6c..0255be4b 100644 --- a/src/modules/dbus/iface-stream.c +++ b/src/modules/dbus/iface-stream.c @@ -632,7 +632,7 @@ static void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata) static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { pa_dbusiface_stream *s = userdata; - DBusMessage *signal = NULL; + DBusMessage *signal_msg = NULL; const char *new_device_path = NULL; uint32_t new_sample_rate = 0; pa_proplist *new_proplist = NULL; @@ -662,14 +662,14 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t new_device_path = pa_dbusiface_core_get_sink_path(s->core, new_sink); - pa_assert_se(signal = dbus_message_new_signal(s->path, - PA_DBUSIFACE_STREAM_INTERFACE, - signals[SIGNAL_DEVICE_UPDATED].name)); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID)); + pa_assert_se(signal_msg = dbus_message_new_signal(s->path, + PA_DBUSIFACE_STREAM_INTERFACE, + signals[SIGNAL_DEVICE_UPDATED].name)); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(s->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } } else { pa_source *new_source = s->source_output->source; @@ -680,14 +680,14 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t new_device_path = pa_dbusiface_core_get_source_path(s->core, new_source); - pa_assert_se(signal = dbus_message_new_signal(s->path, - PA_DBUSIFACE_STREAM_INTERFACE, - signals[SIGNAL_DEVICE_UPDATED].name)); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID)); + pa_assert_se(signal_msg = dbus_message_new_signal(s->path, + PA_DBUSIFACE_STREAM_INTERFACE, + signals[SIGNAL_DEVICE_UPDATED].name)); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(s->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } } @@ -696,14 +696,14 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t if (s->sample_rate != new_sample_rate) { s->sample_rate = new_sample_rate; - pa_assert_se(signal = dbus_message_new_signal(s->path, - PA_DBUSIFACE_STREAM_INTERFACE, - signals[SIGNAL_SAMPLE_RATE_UPDATED].name)); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_UINT32, &s->sample_rate, DBUS_TYPE_INVALID)); + pa_assert_se(signal_msg = dbus_message_new_signal(s->path, + PA_DBUSIFACE_STREAM_INTERFACE, + signals[SIGNAL_SAMPLE_RATE_UPDATED].name)); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_UINT32, &s->sample_rate, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(s->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } if (s->type == STREAM_TYPE_PLAYBACK) { @@ -721,16 +721,16 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t for (i = 0; i < s->volume.channels; ++i) volume[i] = s->volume.values[i]; - pa_assert_se(signal = dbus_message_new_signal(s->path, - PA_DBUSIFACE_STREAM_INTERFACE, - signals[SIGNAL_VOLUME_UPDATED].name)); - pa_assert_se(dbus_message_append_args(signal, + pa_assert_se(signal_msg = dbus_message_new_signal(s->path, + PA_DBUSIFACE_STREAM_INTERFACE, + signals[SIGNAL_VOLUME_UPDATED].name)); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, s->volume.channels, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(s->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } new_mute = pa_sink_input_get_mute(s->sink_input); @@ -738,14 +738,14 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t if (s->mute != new_mute) { s->mute = new_mute; - pa_assert_se(signal = dbus_message_new_signal(s->path, - PA_DBUSIFACE_STREAM_INTERFACE, - signals[SIGNAL_MUTE_UPDATED].name)); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_BOOLEAN, &s->mute, DBUS_TYPE_INVALID)); + pa_assert_se(signal_msg = dbus_message_new_signal(s->path, + PA_DBUSIFACE_STREAM_INTERFACE, + signals[SIGNAL_MUTE_UPDATED].name)); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_BOOLEAN, &s->mute, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(s->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } } @@ -756,21 +756,21 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t pa_proplist_update(s->proplist, PA_UPDATE_SET, new_proplist); - pa_assert_se(signal = dbus_message_new_signal(s->path, - PA_DBUSIFACE_STREAM_INTERFACE, - signals[SIGNAL_PROPERTY_LIST_UPDATED].name)); - dbus_message_iter_init_append(signal, &msg_iter); + pa_assert_se(signal_msg = dbus_message_new_signal(s->path, + PA_DBUSIFACE_STREAM_INTERFACE, + signals[SIGNAL_PROPERTY_LIST_UPDATED].name)); + dbus_message_iter_init_append(signal_msg, &msg_iter); pa_dbus_append_proplist(&msg_iter, s->proplist); - pa_dbus_protocol_send_signal(s->dbus_protocol, signal); - dbus_message_unref(signal); - signal = NULL; + pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); + signal_msg = NULL; } } static pa_hook_result_t send_event_cb(void *hook_data, void *call_data, void *slot_data) { pa_dbusiface_stream *s = slot_data; - DBusMessage *signal = NULL; + DBusMessage *signal_msg = NULL; DBusMessageIter msg_iter; const char *name = NULL; pa_proplist *property_list = NULL; @@ -796,15 +796,15 @@ static pa_hook_result_t send_event_cb(void *hook_data, void *call_data, void *sl property_list = data->data; } - pa_assert_se(signal = dbus_message_new_signal(s->path, - PA_DBUSIFACE_STREAM_INTERFACE, - signals[SIGNAL_STREAM_EVENT].name)); - dbus_message_iter_init_append(signal, &msg_iter); + pa_assert_se(signal_msg = dbus_message_new_signal(s->path, + PA_DBUSIFACE_STREAM_INTERFACE, + signals[SIGNAL_STREAM_EVENT].name)); + dbus_message_iter_init_append(signal_msg, &msg_iter); pa_assert_se(dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name)); pa_dbus_append_proplist(&msg_iter, property_list); - pa_dbus_protocol_send_signal(s->dbus_protocol, signal); - dbus_message_unref(signal); + pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); return PA_HOOK_OK; } diff --git a/src/modules/dbus/module-dbus-protocol.c b/src/modules/dbus/module-dbus-protocol.c index 11064c33..acc6ca04 100644 --- a/src/modules/dbus/module-dbus-protocol.c +++ b/src/modules/dbus/module-dbus-protocol.c @@ -126,7 +126,7 @@ static void client_kill_cb(pa_client *c) { /* Called from pa_client_send_event(). */ static void client_send_event_cb(pa_client *c, const char *name, pa_proplist *data) { struct connection *conn = NULL; - DBusMessage *signal = NULL; + DBusMessage *signal_msg = NULL; DBusMessageIter msg_iter; pa_assert(c); @@ -136,15 +136,15 @@ static void client_send_event_cb(pa_client *c, const char *name, pa_proplist *da conn = c->userdata; - pa_assert_se(signal = dbus_message_new_signal(pa_dbusiface_core_get_client_path(conn->server->userdata->core_iface, c), - PA_DBUSIFACE_CLIENT_INTERFACE, - "ClientEvent")); - dbus_message_iter_init_append(signal, &msg_iter); + pa_assert_se(signal_msg = dbus_message_new_signal(pa_dbusiface_core_get_client_path(conn->server->userdata->core_iface, c), + PA_DBUSIFACE_CLIENT_INTERFACE, + "ClientEvent")); + dbus_message_iter_init_append(signal_msg, &msg_iter); pa_assert_se(dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name)); pa_dbus_append_proplist(&msg_iter, data); - pa_assert_se(dbus_connection_send(pa_dbus_wrap_connection_get(conn->wrap_conn), signal, NULL)); - dbus_message_unref(signal); + pa_assert_se(dbus_connection_send(pa_dbus_wrap_connection_get(conn->wrap_conn), signal_msg, NULL)); + dbus_message_unref(signal_msg); } /* Called by D-Bus at the authentication phase. */ diff --git a/src/modules/jack/module-jack-sink.c b/src/modules/jack/module-jack-sink.c index fc976fa7..9f3e071f 100644 --- a/src/modules/jack/module-jack-sink.c +++ b/src/modules/jack/module-jack-sink.c @@ -334,7 +334,7 @@ int pa__init(pa_module*m) { goto fail; } - ports = jack_get_ports(u->client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); + ports = jack_get_ports(u->client, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical|JackPortIsInput); channels = 0; for (p = ports; *p; p++) diff --git a/src/modules/jack/module-jack-source.c b/src/modules/jack/module-jack-source.c index a898e0e5..6c68527b 100644 --- a/src/modules/jack/module-jack-source.c +++ b/src/modules/jack/module-jack-source.c @@ -286,7 +286,7 @@ int pa__init(pa_module*m) { goto fail; } - ports = jack_get_ports(u->client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput); + ports = jack_get_ports(u->client, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical|JackPortIsOutput); channels = 0; for (p = ports; *p; p++) diff --git a/src/modules/module-cli.c b/src/modules/module-cli.c index 6bd0f4fc..c5ff4564 100644 --- a/src/modules/module-cli.c +++ b/src/modules/module-cli.c @@ -105,7 +105,7 @@ int pa__init(pa_module*m) { * of log messages, particularly because if stdout and stderr are * dup'ed they share the same O_NDELAY, too. */ - if ((fd = open("/dev/tty", O_RDWR|O_CLOEXEC|O_NONBLOCK)) >= 0) { + if ((fd = pa_open_cloexec("/dev/tty", O_RDWR|O_NONBLOCK, 0)) >= 0) { io = pa_iochannel_new(m->core->mainloop, fd, fd); pa_log_debug("Managed to open /dev/tty."); } else { diff --git a/src/modules/module-default-device-restore.c b/src/modules/module-default-device-restore.c index 27ae60e5..94f589e9 100644 --- a/src/modules/module-default-device-restore.c +++ b/src/modules/module-default-device-restore.c @@ -60,7 +60,7 @@ static void load(struct userdata *u) { if (u->core->default_sink) pa_log_info("Manually configured default sink, not overwriting."); - else if ((f = fopen(u->sink_filename, "r"))) { + else if ((f = pa_fopen_cloexec(u->sink_filename, "r"))) { char ln[256] = ""; pa_sink *s; @@ -81,7 +81,7 @@ static void load(struct userdata *u) { if (u->core->default_source) pa_log_info("Manually configured default source, not overwriting."); - else if ((f = fopen(u->source_filename, "r"))) { + else if ((f = pa_fopen_cloexec(u->source_filename, "r"))) { char ln[256] = ""; pa_source *s; @@ -108,7 +108,7 @@ static void save(struct userdata *u) { return; if (u->sink_filename) { - if ((f = fopen(u->sink_filename, "w"))) { + if ((f = pa_fopen_cloexec(u->sink_filename, "w"))) { pa_sink *s = pa_namereg_get_default_sink(u->core); fprintf(f, "%s\n", s ? s->name : ""); fclose(f); @@ -117,7 +117,7 @@ static void save(struct userdata *u) { } if (u->source_filename) { - if ((f = fopen(u->source_filename, "w"))) { + if ((f = pa_fopen_cloexec(u->source_filename, "w"))) { pa_source *s = pa_namereg_get_default_source(u->core); fprintf(f, "%s\n", s ? s->name : ""); fclose(f); diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index b1f24e15..1fe8eb8b 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -63,7 +63,7 @@ static int detect_alsa(pa_core *c, int just_one) { FILE *f; int n = 0, n_sink = 0, n_source = 0; - if (!(f = fopen("/proc/asound/devices", "r"))) { + if (!(f = pa_fopen_cloexec("/proc/asound/devices", "r"))) { if (errno != ENOENT) pa_log_error("open(\"/proc/asound/devices\") failed: %s", pa_cstrerror(errno)); @@ -124,9 +124,9 @@ static int detect_oss(pa_core *c, int just_one) { FILE *f; int n = 0, b = 0; - if (!(f = fopen("/dev/sndstat", "r")) && - !(f = fopen("/proc/sndstat", "r")) && - !(f = fopen("/proc/asound/oss/sndstat", "r"))) { + if (!(f = pa_fopen_cloexec("/dev/sndstat", "r")) && + !(f = pa_fopen_cloexec("/proc/sndstat", "r")) && + !(f = pa_fopen_cloexec("/proc/asound/oss/sndstat", "r"))) { if (errno != ENOENT) pa_log_error("failed to open OSS sndstat device: %s", pa_cstrerror(errno)); diff --git a/src/modules/module-device-manager.c b/src/modules/module-device-manager.c index e3158644..8d61ff4c 100644 --- a/src/modules/module-device-manager.c +++ b/src/modules/module-device-manager.c @@ -1032,33 +1032,33 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio if ((e = read_entry(u, name))) { uint32_t idx; - char *devname; - uint32_t index = PA_INVALID_INDEX; + char *device_name; + uint32_t found_index = PA_INVALID_INDEX; - if ((devname = get_name(name, "sink:"))) { + if ((device_name = get_name(name, "sink:"))) { pa_sink* s; PA_IDXSET_FOREACH(s, u->core->sinks, idx) { - if (strcmp(s->name, devname) == 0) { - index = s->index; + if (strcmp(s->name, device_name) == 0) { + found_index = s->index; break; } } - pa_xfree(devname); - } else if ((devname = get_name(name, "source:"))) { + pa_xfree(device_name); + } else if ((device_name = get_name(name, "source:"))) { pa_source* s; PA_IDXSET_FOREACH(s, u->core->sources, idx) { - if (strcmp(s->name, devname) == 0) { - index = s->index; + if (strcmp(s->name, device_name) == 0) { + found_index = s->index; break; } } - pa_xfree(devname); + pa_xfree(device_name); } pa_tagstruct_puts(reply, name); pa_tagstruct_puts(reply, e->description); pa_tagstruct_puts(reply, e->icon); - pa_tagstruct_putu32(reply, index); + pa_tagstruct_putu32(reply, found_index); pa_tagstruct_putu32(reply, NUM_ROLES); for (uint32_t i = ROLE_NONE; i < NUM_ROLES; ++i) { diff --git a/src/modules/module-equalizer-sink.c b/src/modules/module-equalizer-sink.c index 3a28b497..0a2860b0 100755..100644 --- a/src/modules/module-equalizer-sink.c +++ b/src/modules/module-equalizer-sink.c @@ -113,8 +113,11 @@ struct userdata { float **Xs; float ***Hs;//thread updatable copies of the freq response filters (magintude based) pa_aupdate **a_H; - pa_memchunk conv_buffer; pa_memblockq *input_q; + char *output_buffer; + size_t output_buffer_length; + size_t output_buffer_max_length; + pa_memblockq *output_q; pa_bool_t first_iteration; pa_dbus_protocol *dbus_protocol; @@ -250,10 +253,11 @@ static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t of pa_sink_get_latency_within_thread(u->sink_input->sink) + /* Add the latency internal to our sink input on top */ - pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec); + pa_bytes_to_usec(pa_memblockq_get_length(u->output_q), &u->sink_input->sink->sample_spec) + + pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec) + + pa_bytes_to_usec(pa_memblockq_get_length(u->input_q), &u->sink_input->sink->sample_spec); // pa_bytes_to_usec(u->samples_gathered * fs, &u->sink->sample_spec); //+ pa_bytes_to_usec(u->latency * fs, ss) - //+ pa_bytes_to_usec(pa_memblockq_get_length(u->input_q), ss); return 0; } } @@ -337,7 +341,7 @@ static void sink_set_mute_cb(pa_sink *s) { pa_sink_input_set_mute(u->sink_input, s->muted, s->save_muted); } - +#if 1 //reference implementation static void dsp_logic( float * restrict dst,//used as a temp array too, needs to be fft_length! @@ -351,12 +355,12 @@ static void dsp_logic( fftwf_complex * restrict output_window,//The transformed window'd src struct userdata *u){ //use a linear-phase sliding STFT and overlap-add method (for each channel) - //zero padd the data - memset(dst + u->window_size, 0, (u->fft_size - u->window_size) * sizeof(float)); //window the data for(size_t j = 0; j < u->window_size; ++j){ dst[j] = X * W[j] * src[j]; } + //zero padd the the remaining fft window + memset(dst + u->window_size, 0, (u->fft_size - u->window_size) * sizeof(float)); //Processing is done here! //do fft fftwf_execute_dft_r2c(u->forward_plan, dst, output_window); @@ -390,125 +394,141 @@ static void dsp_logic( (u->samples_gathered - u->R) * sizeof(float) ); } - +#else typedef float v4sf __attribute__ ((__aligned__(v_size * sizeof(float)))); typedef union float_vector { float f[v_size]; v4sf v; -#ifdef __SSE2__ __m128 m; -#endif } float_vector_t; -////regardless of sse enabled, the loops in here assume -////16 byte aligned addresses and memory allocations divisible by v_size -//void dsp_logic( -// float * restrict dst,//used as a temp array too, needs to be fft_length! -// float * restrict src,/*input data w/ overlap at start, -// *automatically cycled in routine -// */ -// float * restrict overlap,//The size of the overlap -// const float X,//multipliar -// const float * restrict H,//The freq. magnitude scalers filter -// const float * restrict W,//The windowing function -// fftwf_complex * restrict output_window,//The transformed window'd src -// struct userdata *u){//Collection of constants - //float_vector_t x = {X, X, X, X}; -// const size_t window_size = PA_ROUND_UP(u->window_size,v_size); -// const size_t fft_h = PA_ROUND_UP(FILTER_SIZE, v_size / 2); -// //const size_t R = PA_ROUND_UP(u->R, v_size); -// const size_t overlap_size = PA_ROUND_UP(u->overlap_size, v_size); -// overlap_size = PA_ROUND_UP(u->overlap_size, v_size); -// -// //assert(u->samples_gathered >= u->R); -// //zero out the bit beyond the real overlap so we don't add garbage -// for(size_t j = overlap_size; j > u->overlap_size; --j){ -// overlap[j-1] = 0; -// } -// //use a linear-phase sliding STFT and overlap-add method -// //zero padd the data -// memset(dst + u->window_size, 0, (u->fft_size - u->window_size)*sizeof(float)); -// //window the data -// for(size_t j = 0; j < window_size; j += v_size){ -// //dst[j] = W[j]*src[j]; -// float_vector_t *d = (float_vector_t*) (dst+j); -// float_vector_t *w = (float_vector_t*) (W+j); -// float_vector_t *s = (float_vector_t*) (src+j); +//regardless of sse enabled, the loops in here assume +//16 byte aligned addresses and memory allocations divisible by v_size +static void dsp_logic( + float * restrict dst,//used as a temp array too, needs to be fft_length! + float * restrict src,/*input data w/ overlap at start, + *automatically cycled in routine + */ + float * restrict overlap,//The size of the overlap + const float X,//multipliar + const float * restrict H,//The freq. magnitude scalers filter + const float * restrict W,//The windowing function + fftwf_complex * restrict output_window,//The transformed window'd src + struct userdata *u){//Collection of constants + const size_t overlap_size = PA_ROUND_UP(u->overlap_size, v_size); + float_vector_t x; + x.f[0] = x.f[1] = x.f[2] = x.f[3] = X; + + //assert(u->samples_gathered >= u->R); + //use a linear-phase sliding STFT and overlap-add method + for(size_t j = 0; j < u->window_size; j += v_size){ + //dst[j] = W[j] * src[j]; + float_vector_t *d = (float_vector_t*) (dst + j); + float_vector_t *w = (float_vector_t*) (W + j); + float_vector_t *s = (float_vector_t*) (src + j); //#if __SSE2__ -// d->m = _mm_mul_ps(x->m, _mm_mul_ps(w->m, s->m)); -//#else + d->m = _mm_mul_ps(x.m, _mm_mul_ps(w->m, s->m)); // d->v = x->v * w->v * s->v; //#endif -// } -// //Processing is done here! -// //do fft -// fftwf_execute_dft_r2c(u->forward_plan, dst, output_window); -// -// -// //perform filtering - purely magnitude based -// for(size_t j = 0;j < fft_h; j+=v_size/2){ -// //output_window[j][0]*=H[j]; -// //output_window[j][1]*=H[j]; -// float_vector_t *d = (float_vector_t*)(output_window+j); -// float_vector_t h; -// h.f[0] = h.f[1] = H[j]; -// h.f[2] = h.f[3] = H[j+1]; + } + //zero padd the the remaining fft window + memset(dst + u->window_size, 0, (u->fft_size - u->window_size) * sizeof(float)); + + //Processing is done here! + //do fft + fftwf_execute_dft_r2c(u->forward_plan, dst, output_window); + //perform filtering - purely magnitude based + for(size_t j = 0; j < FILTER_SIZE; j += v_size / 2){ + //output_window[j][0]*=H[j]; + //output_window[j][1]*=H[j]; + float_vector_t *d = (float_vector_t*)( ((float *) output_window) + 2 * j); + float_vector_t h; + h.f[0] = h.f[1] = H[j]; + h.f[2] = h.f[3] = H[j + 1]; //#if __SSE2__ -// d->m = _mm_mul_ps(d->m, h.m); + d->m = _mm_mul_ps(d->m, h.m); //#else -// d->v = d->v*h->v; +// d->v = d->v * h.v; //#endif -// } -// //inverse fft -// fftwf_execute_dft_c2r(u->inverse_plan, output_window, dst); -// -// ////debug: tests overlaping add -// ////and negates ALL PREVIOUS processing -// ////yields a perfect reconstruction if COLA is held -// //for(size_t j = 0; j < u->window_size; ++j){ -// // dst[j] = W[j]*src[j]; -// //} -// -// //overlap add and preserve overlap component from this window (linear phase) -// for(size_t j = 0; j < overlap_size; j+=v_size){ -// //dst[j]+=overlap[j]; -// //overlap[j]+=dst[j+R]; -// float_vector_t *d = (float_vector_t*)(dst+j); -// float_vector_t *o = (float_vector_t*)(overlap+j); + } + + //inverse fft + fftwf_execute_dft_c2r(u->inverse_plan, output_window, dst); + + ////debug: tests overlaping add + ////and negates ALL PREVIOUS processing + ////yields a perfect reconstruction if COLA is held + //for(size_t j = 0; j < u->window_size; ++j){ + // dst[j] = W[j] * src[j]; + //} + + //overlap add and preserve overlap component from this window (linear phase) + for(size_t j = 0; j < overlap_size; j += v_size){ + //dst[j]+=overlap[j]; + //overlap[j]+=dst[j+R]; + float_vector_t *d = (float_vector_t*)(dst + j); + float_vector_t *o = (float_vector_t*)(overlap + j); //#if __SSE2__ -// d->m = _mm_add_ps(d->m, o->m); -// o->m = ((float_vector_t*)(dst+u->R+j))->m; + d->m = _mm_add_ps(d->m, o->m); + o->m = ((float_vector_t*)(dst + u->R + j))->m; //#else -// d->v = d->v+o->v; -// o->v = ((float_vector_t*)(dst+u->R+j))->v; +// d->v = d->v + o->v; +// o->v = ((float_vector_t*)(dst + u->R + j))->v; //#endif -// } -// //memcpy(overlap, dst+u->R, u->overlap_size*sizeof(float)); -// -// //////debug: tests if basic buffering works -// //////shouldn't modify the signal AT ALL (beyond roundoff) -// //for(size_t j = 0; j < u->window_size; ++j){ -// // dst[j] = src[j]; -// //} -// -// //preseve the needed input for the next window's overlap -// memmove(src, src + u->R, -// u->overlap_size * sizeof(float) -// ); -//} - -static void process_samples(struct userdata *u, pa_memchunk *tchunk){ + } + //memcpy(overlap, dst+u->R, u->overlap_size * sizeof(float)); //overlap preserve (debug) + //zero out the bit beyond the real overlap so we don't add garbage next iteration + memset(overlap + u->overlap_size, 0, overlap_size - u->overlap_size); + + ////debug: tests if basic buffering works + ////shouldn't modify the signal AT ALL (beyond roundoff) + //for(size_t j = 0; j < u->window_size; ++j){ + // dst[j] = src[j]; + //} + + //preseve the needed input for the next window's overlap + memmove(src, src + u->R, + (u->samples_gathered - u->R) * sizeof(float) + ); +} +#endif + +static void flatten_to_memblockq(struct userdata *u){ + size_t mbs = pa_mempool_block_size_max(u->sink->core->mempool); + pa_memchunk tchunk; + char *dst; + size_t i = 0; + while(i < u->output_buffer_length){ + tchunk.index = 0; + tchunk.length = PA_MIN((u->output_buffer_length - i), mbs); + tchunk.memblock = pa_memblock_new(u->sink->core->mempool, tchunk.length); + //pa_log_debug("pushing %ld into the q", tchunk.length); + dst = pa_memblock_acquire(tchunk.memblock); + memcpy(dst, u->output_buffer + i, tchunk.length); + pa_memblock_release(tchunk.memblock); + pa_memblockq_push(u->output_q, &tchunk); + pa_memblock_unref(tchunk.memblock); + i += tchunk.length; + } +} + +static void process_samples(struct userdata *u){ size_t fs = pa_frame_size(&(u->sink->sample_spec)); - float *dst; unsigned a_i; float *H, X; size_t iterations, offset; pa_assert(u->samples_gathered >= u->window_size); iterations = (u->samples_gathered - u->overlap_size) / u->R; - tchunk->index = 0; - tchunk->length = iterations * u->R * fs; - tchunk->memblock = pa_memblock_new(u->sink->core->mempool, tchunk->length); - dst = ((float*) pa_memblock_acquire(tchunk->memblock)); + //make sure there is enough buffer memory allocated + if(iterations * u->R * fs > u->output_buffer_max_length){ + u->output_buffer_max_length = iterations * u->R * fs; + if(u->output_buffer){ + pa_xfree(u->output_buffer); + } + u->output_buffer = pa_xmalloc(u->output_buffer_max_length); + } + u->output_buffer_length = iterations * u->R * fs; + for(size_t iter = 0; iter < iterations; ++iter){ offset = iter * u->R * fs; for(size_t c = 0;c < u->channels; c++) { @@ -534,14 +554,14 @@ static void process_samples(struct userdata *u, pa_memchunk *tchunk){ u->work_buffer[i] = u->W[i] <= FLT_EPSILON ? u->work_buffer[i] : u->work_buffer[i] / u->W[i]; } } - pa_sample_clamp(PA_SAMPLE_FLOAT32NE, (uint8_t *) (dst + c) + offset, fs, u->work_buffer, sizeof(float), u->R); + pa_sample_clamp(PA_SAMPLE_FLOAT32NE, (uint8_t *) (((float *)u->output_buffer) + c) + offset, fs, u->work_buffer, sizeof(float), u->R); } if(u->first_iteration){ u->first_iteration = FALSE; } u->samples_gathered -= u->R; } - pa_memblock_release(tchunk->memblock); + flatten_to_memblockq(u); } static void input_buffer(struct userdata *u, pa_memchunk *in){ @@ -565,36 +585,49 @@ static void input_buffer(struct userdata *u, pa_memchunk *in){ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) { struct userdata *u; size_t fs, target_samples; - struct timeval start, end; + size_t mbs; + //struct timeval start, end; pa_memchunk tchunk; pa_sink_input_assert_ref(i); pa_assert_se(u = i->userdata); pa_assert(chunk); pa_assert(u->sink); fs = pa_frame_size(&(u->sink->sample_spec)); + mbs = pa_mempool_block_size_max(u->sink->core->mempool); + if(pa_memblockq_get_length(u->output_q) > 0){ + //pa_log_debug("qsize is %ld", pa_memblockq_get_length(u->output_q)); + goto END; + } + //nbytes = PA_MIN(nbytes, pa_mempool_block_size_max(u->sink->core->mempool)); target_samples = PA_ROUND_UP(nbytes / fs, u->R); + ////pa_log_debug("vanilla mbs = %ld",mbs); + //mbs = PA_ROUND_DOWN(mbs / fs, u->R); + //mbs = PA_MAX(mbs, u->R); + //target_samples = PA_MAX(target_samples, mbs); + //pa_log_debug("target samples: %ld", target_samples); if(u->first_iteration){ //allocate request_size target_samples = PA_MAX(target_samples, u->window_size); }else{ //allocate request_size + overlap target_samples += u->overlap_size; - alloc_input_buffers(u, target_samples); } alloc_input_buffers(u, target_samples); + //pa_log_debug("post target samples: %ld", target_samples); chunk->memblock = NULL; /* Hmm, process any rewind request that might be queued up */ pa_sink_process_rewind(u->sink, 0); //pa_log_debug("start output-buffered %ld, input-buffered %ld, requested %ld",buffered_samples,u->samples_gathered,samples_requested); - pa_rtclock_get(&start); + //pa_rtclock_get(&start); do{ size_t input_remaining = target_samples - u->samples_gathered; + // pa_log_debug("input remaining %ld samples", input_remaining); pa_assert(input_remaining > 0); while(pa_memblockq_peek(u->input_q, &tchunk) < 0){ //pa_sink_render(u->sink, input_remaining * fs, &tchunk); - pa_sink_render_full(u->sink, input_remaining * fs, &tchunk); + pa_sink_render_full(u->sink, PA_MIN(input_remaining * fs, mbs), &tchunk); pa_assert(tchunk.memblock); pa_memblockq_push(u->input_q, &tchunk); pa_memblock_unref(tchunk.memblock); @@ -605,25 +638,27 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk //pa_log_debug("asked for %ld input samples, got %ld samples",input_remaining,buffer->length/fs); /* copy new input */ //pa_rtclock_get(start); + // pa_log_debug("buffering %ld bytes", tchunk.length); input_buffer(u, &tchunk); //pa_rtclock_get(&end); //pa_log_debug("Took %0.5f seconds to setup", pa_timeval_diff(end, start) / (double) PA_USEC_PER_SEC); pa_memblock_unref(tchunk.memblock); }while(u->samples_gathered < target_samples); - pa_rtclock_get(&end); - pa_log_debug("Took %0.6f seconds to get data", (double) pa_timeval_diff(&end, &start) / PA_USEC_PER_SEC); + //pa_rtclock_get(&end); + //pa_log_debug("Took %0.6f seconds to get data", (double) pa_timeval_diff(&end, &start) / PA_USEC_PER_SEC); pa_assert(u->fft_size >= u->window_size); pa_assert(u->R < u->window_size); - /* set the H filter */ - pa_rtclock_get(&start); + //pa_rtclock_get(&start); /* process a block */ - process_samples(u, chunk); - pa_rtclock_get(&end); - pa_log_debug("Took %0.6f seconds to process", (double) pa_timeval_diff(&end, &start) / PA_USEC_PER_SEC); - + process_samples(u); + //pa_rtclock_get(&end); + //pa_log_debug("Took %0.6f seconds to process", (double) pa_timeval_diff(&end, &start) / PA_USEC_PER_SEC); +END: + pa_assert_se(pa_memblockq_peek(u->output_q, chunk) >= 0); pa_assert(chunk->memblock); + pa_memblockq_drop(u->output_q, chunk->length); //pa_log_debug("gave %ld", chunk->length/fs); //pa_log_debug("end pop"); return 0; @@ -685,7 +720,7 @@ static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) { //invalidate the output q pa_memblockq_seek(u->input_q, - (int64_t) amount, PA_SEEK_RELATIVE, TRUE); pa_log("Resetting filter"); - reset_filter(u); + //reset_filter(u); //this is the "proper" thing to do... } } @@ -814,33 +849,35 @@ static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t s static void pack(char **strs, size_t len, char **packed, size_t *length){ size_t t_len = 0; size_t headers = (1+len) * sizeof(uint16_t); - size_t offset = sizeof(uint16_t); + char *p; for(size_t i = 0; i < len; ++i){ t_len += strlen(strs[i]); } *length = headers + t_len; - *packed = pa_xmalloc0(*length); - ((uint16_t *) *packed)[0] = (uint16_t) len; + p = *packed = pa_xmalloc0(*length); + *((uint16_t *) p) = (uint16_t) len; + p += sizeof(uint16_t); for(size_t i = 0; i < len; ++i){ uint16_t l = strlen(strs[i]); - *((uint16_t *)(*packed + offset)) = l; - offset += sizeof(uint16_t); - memcpy(*packed + offset, strs[i], l); - offset += l; + *((uint16_t *) p) = (uint16_t) l; + p += sizeof(uint16_t); + memcpy(p, strs[i], l); + p += l; } } static void unpack(char *str, size_t length, char ***strs, size_t *len){ - size_t offset = sizeof(uint16_t); - *len = ((uint16_t *)str)[0]; + char *p = str; + *len = *((uint16_t *) p); + p += sizeof(uint16_t); *strs = pa_xnew(char *, *len); + for(size_t i = 0; i < *len; ++i){ - size_t l = *((uint16_t *)(str+offset)); - size_t e = PA_MIN(offset + l, length) - offset; - offset = PA_MIN(offset + sizeof(uint16_t), length); - (*strs)[i] = pa_xnew(char, e + 1); - memcpy((*strs)[i], str + offset, e); - (*strs)[i][e] = '\0'; - offset += l; + size_t l = *((uint16_t *) p); + p += sizeof(uint16_t); + (*strs)[i] = pa_xnew(char, l + 1); + memcpy((*strs)[i], p, l); + (*strs)[i][l] = '\0'; + p += l; } } static void save_profile(struct userdata *u, size_t channel, char *name){ @@ -885,17 +922,17 @@ static void save_state(struct userdata *u){ pack(u->base_profiles, u->channels, &packed, &packed_length); state = (float *) pa_xmalloc0(filter_state_size + packed_length); + memcpy(state + FILTER_STATE_SIZE, packed, packed_length); + pa_xfree(packed); for(size_t c = 0; c < u->channels; ++c){ a_i = pa_aupdate_read_begin(u->a_H[c]); - state[c * CHANNEL_PROFILE_SIZE] = u->Xs[a_i][c]; + state[c * CHANNEL_PROFILE_SIZE] = u->Xs[c][a_i]; H = u->Hs[c][a_i]; - H_n = state + c * CHANNEL_PROFILE_SIZE + 1; + H_n = &state[c * CHANNEL_PROFILE_SIZE + 1]; memcpy(H_n, H, FILTER_SIZE * sizeof(float)); pa_aupdate_read_end(u->a_H[c]); } - memcpy(((char *)state) + filter_state_size, packed, packed_length); - pa_xfree(packed); key.data = state_name; key.size = strlen(key.data); @@ -978,13 +1015,13 @@ static void load_state(struct userdata *u){ memcpy(u->Hs[c][a_i], H, FILTER_SIZE * sizeof(float)); pa_aupdate_write_end(u->a_H[c]); } - //unpack(((char *)value.data) + FILTER_STATE_SIZE, value.size - FILTER_STATE_SIZE, &names, &n_profs); - //n_profs = PA_MIN(n_profs, u->channels); - //for(size_t c = 0; c < n_profs; ++c){ - // pa_xfree(u->base_profiles[c]); - // u->base_profiles[c] = names[c]; - //} - //pa_xfree(names); + unpack(((char *)value.data) + FILTER_STATE_SIZE * sizeof(float), value.size - FILTER_STATE_SIZE * sizeof(float), &names, &n_profs); + n_profs = PA_MIN(n_profs, u->channels); + for(size_t c = 0; c < n_profs; ++c){ + pa_xfree(u->base_profiles[c]); + u->base_profiles[c] = names[c]; + } + pa_xfree(names); } pa_datum_free(&value); }else{ @@ -1062,9 +1099,12 @@ int pa__init(pa_module*m) { pa_modargs_get_value_boolean(ma, "set_default", &u->set_default); u->channels = ss.channels; - u->fft_size = pow(2, ceil(log(ss.rate)/log(2)));//probably unstable near corner cases of powers of 2 + u->fft_size = pow(2, ceil(log(ss.rate) / log(2)));//probably unstable near corner cases of powers of 2 pa_log_debug("fft size: %ld", u->fft_size); u->window_size = 15999; + if(u->window_size % 2 == 0){ + u->window_size--; + } u->R = (u->window_size + 1) / 2; u->overlap_size = u->window_size - u->R; u->samples_gathered = 0; @@ -1088,7 +1128,6 @@ int pa__init(pa_module*m) { u->a_H[c] = pa_aupdate_new(); u->input[c] = NULL; u->overlap_accum[c] = alloc(u->overlap_size, sizeof(float)); - memset(u->overlap_accum[c], 0, u->overlap_size*sizeof(float)); } u->output_window = alloc((FILTER_SIZE), sizeof(fftwf_complex)); u->forward_plan = fftwf_plan_dft_r2c_1d(u->fft_size, u->work_buffer, u->output_window, FFTW_ESTIMATE); @@ -1139,6 +1178,10 @@ int pa__init(pa_module*m) { u->sink->set_mute = sink_set_mute_cb; u->sink->userdata = u; u->input_q = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, fs, 1, 1, 0, &u->sink->silence); + u->output_q = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, fs, 1, 1, 0, NULL); + u->output_buffer = NULL; + u->output_buffer_length = 0; + u->output_buffer_max_length = 0; pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq); //pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(u->R*fs, &ss)); @@ -1251,6 +1294,10 @@ void pa__done(pa_module*m) { if (u->sink) pa_sink_unref(u->sink); + if(u->output_buffer){ + pa_xfree(u->output_buffer); + } + pa_memblockq_free(u->output_q); pa_memblockq_free(u->input_q); fftwf_destroy_plan(u->inverse_plan); diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c index d0e902f6..e9778620 100644 --- a/src/modules/module-lirc.c +++ b/src/modules/module-lirc.c @@ -45,12 +45,14 @@ PA_MODULE_AUTHOR("Lennart Poettering"); PA_MODULE_DESCRIPTION("LIRC volume control"); PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(TRUE); -PA_MODULE_USAGE("config=<config file> sink=<sink name> appname=<lirc application name>"); +PA_MODULE_USAGE("config=<config file> sink=<sink name> appname=<lirc application name> volume_limit=<volume limit> volume_step=<volume change step>"); static const char* const valid_modargs[] = { "config", "sink", "appname", + "volume_limit", + "volume_step", NULL, }; @@ -61,10 +63,10 @@ struct userdata { char *sink_name; pa_module *module; float mute_toggle_save; + pa_volume_t volume_limit; + pa_volume_t volume_step; }; -#define DELTA (PA_VOLUME_NORM/20) - static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void*userdata) { struct userdata *u = userdata; char *name = NULL, *code = NULL; @@ -125,12 +127,12 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event switch (volchange) { case UP: - pa_cvolume_inc(&cv, DELTA); + pa_cvolume_inc_clamp(&cv, u->volume_step, u->volume_limit); pa_sink_set_volume(s, &cv, TRUE, TRUE); break; case DOWN: - pa_cvolume_dec(&cv, DELTA); + pa_cvolume_dec(&cv, u->volume_step); pa_sink_set_volume(s, &cv, TRUE, TRUE); break; @@ -170,6 +172,8 @@ fail: int pa__init(pa_module*m) { pa_modargs *ma = NULL; struct userdata *u; + pa_volume_t volume_limit = PA_VOLUME_NORM*3/2; + pa_volume_t volume_step = PA_VOLUME_NORM/20; pa_assert(m); @@ -178,6 +182,16 @@ int pa__init(pa_module*m) { goto fail; } + if (pa_modargs_get_value_u32(ma, "volume_limit", &volume_limit) < 0) { + pa_log("Failed to parse volume limit"); + goto fail; + } + + if (pa_modargs_get_value_u32(ma, "volume_step", &volume_step) < 0) { + pa_log("Failed to parse volume step"); + goto fail; + } + m->userdata = u = pa_xnew(struct userdata, 1); u->module = m; u->io = NULL; @@ -185,6 +199,8 @@ int pa__init(pa_module*m) { u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); u->lirc_fd = -1; u->mute_toggle_save = 0; + u->volume_limit = volume_limit; + u->volume_step = volume_step; if ((u->lirc_fd = lirc_init((char*) pa_modargs_get_value(ma, "appname", "pulseaudio"), 1)) < 0) { pa_log("lirc_init() failed."); diff --git a/src/modules/module-match.c b/src/modules/module-match.c index 0bd781d2..b1693f18 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -85,7 +85,7 @@ static int load_rules(struct userdata *u, const char *filename) { pa_assert(u); if (filename) - f = fopen(fn = pa_xstrdup(filename), "r"); + f = pa_fopen_cloexec(fn = pa_xstrdup(filename), "r"); else f = pa_open_config_file(DEFAULT_MATCH_TABLE_FILE, DEFAULT_MATCH_TABLE_FILE_USER, NULL, &fn); diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c index 516bf413..193c1f40 100644 --- a/src/modules/module-mmkbd-evdev.c +++ b/src/modules/module-mmkbd-evdev.c @@ -48,13 +48,15 @@ PA_MODULE_AUTHOR("Lennart Poettering"); PA_MODULE_DESCRIPTION("Multimedia keyboard support via Linux evdev"); PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(FALSE); -PA_MODULE_USAGE("device=<evdev device> sink=<sink name>"); +PA_MODULE_USAGE("device=<evdev device> sink=<sink name> volume_limit=<volume limit> volume_step=<volume change step>"); #define DEFAULT_DEVICE "/dev/input/event0" static const char* const valid_modargs[] = { "device", "sink", + "volume_limit", + "volume_step", NULL, }; @@ -63,10 +65,10 @@ struct userdata { pa_io_event *io; char *sink_name; pa_module *module; + pa_volume_t volume_limit; + pa_volume_t volume_step; }; -#define DELTA (PA_VOLUME_NORM/20) - static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void*userdata) { struct userdata *u = userdata; @@ -120,12 +122,12 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event switch (volchange) { case UP: - pa_cvolume_inc(&cv, DELTA); + pa_cvolume_inc_clamp(&cv, u->volume_step, u->volume_limit); pa_sink_set_volume(s, &cv, TRUE, TRUE); break; case DOWN: - pa_cvolume_dec(&cv, DELTA); + pa_cvolume_dec(&cv, u->volume_step); pa_sink_set_volume(s, &cv, TRUE, TRUE); break; @@ -160,6 +162,8 @@ int pa__init(pa_module*m) { struct input_id input_id; char name[256]; uint8_t evtype_bitmask[EV_MAX/8 + 1]; + pa_volume_t volume_limit = PA_VOLUME_NORM*3/2; + pa_volume_t volume_step = PA_VOLUME_NORM/20; pa_assert(m); @@ -168,14 +172,26 @@ int pa__init(pa_module*m) { goto fail; } + if (pa_modargs_get_value_u32(ma, "volume_limit", &volume_limit) < 0) { + pa_log("Failed to parse volume limit"); + goto fail; + } + + if (pa_modargs_get_value_u32(ma, "volume_step", &volume_step) < 0) { + pa_log("Failed to parse volume step"); + goto fail; + } + m->userdata = u = pa_xnew(struct userdata, 1); u->module = m; u->io = NULL; u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); u->fd = -1; u->fd_type = 0; + u->volume_limit = volume_limit; + u->volume_step = volume_step; - if ((u->fd = open(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), O_RDONLY|O_NOCTTY)) < 0) { + if ((u->fd = pa_open_cloexec(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), O_RDONLY, 0)) < 0) { pa_log("Failed to open evdev device: %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index 9c169327..7a4e730f 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -34,6 +34,10 @@ #include <sys/ioctl.h> #include <poll.h> +#ifdef HAVE_SYS_FILIO_H +#include <sys/filio.h> +#endif + #include <pulse/xmalloc.h> #include <pulsecore/core-error.h> @@ -101,9 +105,10 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse case PA_SINK_MESSAGE_GET_LATENCY: { size_t n = 0; - int l; #ifdef FIONREAD + int l; + if (ioctl(u->fd, FIONREAD, &l) >= 0 && l > 0) n = (size_t) l; #endif @@ -253,12 +258,11 @@ int pa__init(pa_module*m) { u->filename = pa_runtime_path(pa_modargs_get_value(ma, "file", DEFAULT_FILE_NAME)); mkfifo(u->filename, 0666); - if ((u->fd = open(u->filename, O_RDWR|O_NOCTTY)) < 0) { + if ((u->fd = pa_open_cloexec(u->filename, O_RDWR, 0)) < 0) { pa_log("open('%s'): %s", u->filename, pa_cstrerror(errno)); goto fail; } - pa_make_fd_cloexec(u->fd); pa_make_fd_nonblock(u->fd); if (fstat(u->fd, &st) < 0) { diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index 49104f8d..933f0294 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -34,6 +34,10 @@ #include <sys/ioctl.h> #include <sys/poll.h> +#ifdef HAVE_SYS_FILIO_H +#include <sys/filio.h> +#endif + #include <pulse/xmalloc.h> #include <pulsecore/core-error.h> @@ -105,9 +109,10 @@ static int source_process_msg( case PA_SOURCE_MESSAGE_GET_LATENCY: { size_t n = 0; - int l; #ifdef FIONREAD + int l; + if (ioctl(u->fd, FIONREAD, &l) >= 0 && l > 0) n = (size_t) l; #endif @@ -238,12 +243,11 @@ int pa__init(pa_module*m) { u->filename = pa_runtime_path(pa_modargs_get_value(ma, "file", DEFAULT_FILE_NAME)); mkfifo(u->filename, 0666); - if ((u->fd = open(u->filename, O_RDWR|O_NOCTTY)) < 0) { + if ((u->fd = pa_open_cloexec(u->filename, O_RDWR, 0)) < 0) { pa_log("open('%s'): %s", u->filename, pa_cstrerror(errno)); goto fail; } - pa_make_fd_cloexec(u->fd); pa_make_fd_nonblock(u->fd); if (fstat(u->fd, &st) < 0) { diff --git a/src/modules/module-rygel-media-server.c b/src/modules/module-rygel-media-server.c index 4c02e958..82bcd14c 100644 --- a/src/modules/module-rygel-media-server.c +++ b/src/modules/module-rygel-media-server.c @@ -464,8 +464,18 @@ static char **child_array(struct userdata *u, const char *path, unsigned *n) { if (pa_streq(path, OBJECT_SINKS)) m = pa_idxset_size(u->core->sinks); - else + else { + unsigned k; + m = pa_idxset_size(u->core->sources); + k = pa_idxset_size(u->core->sinks); + + pa_assert(m >= k); + + /* Subtract the monitor sources from the numbers of + * sources. There is one monitor source for each sink */ + m -= k; + } array = pa_xnew(char*, m); *n = 0; @@ -473,14 +483,20 @@ static char **child_array(struct userdata *u, const char *path, unsigned *n) { if (pa_streq(path, OBJECT_SINKS)) { pa_sink *sink; - PA_IDXSET_FOREACH(sink, u->core->sinks, idx) + PA_IDXSET_FOREACH(sink, u->core->sinks, idx) { + pa_assert((*n) < m); array[(*n)++] = pa_sprintf_malloc(OBJECT_SINKS "/%u", sink->index); + } } else { pa_source *source; - PA_IDXSET_FOREACH(source, u->core->sources, idx) - if (!source->monitor_of) + PA_IDXSET_FOREACH(source, u->core->sources, idx) { + + if (!source->monitor_of) { + pa_assert((*n) < m); array[(*n)++] = pa_sprintf_malloc(OBJECT_SOURCES "/%u", source->index); + } + } } pa_assert((*n) <= m); @@ -529,16 +545,20 @@ static DBusHandlerResult sinks_and_sources_handler(DBusConnection *c, DBusMessag free_child_array(array, n); } else if (message_is_property_get(m, "org.gnome.UPnP.MediaContainer1", "ItemCount")) { + unsigned n, k; + + n = pa_idxset_size(u->core->sinks); + k = pa_idxset_size(u->core->sources); + pa_assert(k >= n); + pa_assert_se(r = dbus_message_new_method_return(m)); append_variant_unsigned(r, NULL, - pa_streq(path, OBJECT_SINKS) ? - pa_idxset_size(u->core->sinks) : - pa_idxset_size(u->core->sources)); + pa_streq(path, OBJECT_SINKS) ? n : k - n); } else if (message_is_property_get_all(m, "org.gnome.UPnP.MediaContainer1")) { DBusMessageIter iter, sub; char **array; - unsigned n; + unsigned n, k; pa_assert_se(r = dbus_message_new_method_return(m)); dbus_message_iter_init_append(r, &iter); @@ -550,10 +570,13 @@ static DBusHandlerResult sinks_and_sources_handler(DBusConnection *c, DBusMessag array = child_array(u, path, &n); append_property_dict_entry_object_array(r, &sub, "Items", (const char**) array, n); free_child_array(array, n); + + n = pa_idxset_size(u->core->sinks); + k = pa_idxset_size(u->core->sources); + pa_assert(k >= n); + append_property_dict_entry_unsigned(r, &sub, "ItemCount", - pa_streq(path, OBJECT_SINKS) ? - pa_idxset_size(u->core->sinks) : - pa_idxset_size(u->core->sources)); + pa_streq(path, OBJECT_SINKS) ? n : k - n); pa_assert_se(dbus_message_iter_close_container(&iter, &sub)); diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index b0d4db43..396094ce 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -327,7 +327,7 @@ static int open_audio_device(struct userdata *u, pa_sample_spec *ss) { pa_assert(u); pa_assert(ss); - if ((u->fd = open(u->device_name, u->mode | O_NONBLOCK)) < 0) { + if ((u->fd = pa_open_cloexec(u->device_name, u->mode | O_NONBLOCK, 0)) < 0) { pa_log_warn("open %s failed (%s)", u->device_name, pa_cstrerror(errno)); return -1; } diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index 788f458b..02c312e3 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -433,29 +433,29 @@ static void append_volume_variant(DBusMessageIter *iter, struct entry *e) { } static void send_new_entry_signal(struct dbus_entry *entry) { - DBusMessage *signal; + DBusMessage *signal_msg; pa_assert(entry); - pa_assert_se(signal = dbus_message_new_signal(OBJECT_PATH, INTERFACE_STREAM_RESTORE, signals[SIGNAL_NEW_ENTRY].name)); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &entry->object_path, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(entry->userdata->dbus_protocol, signal); - dbus_message_unref(signal); + pa_assert_se(signal_msg = dbus_message_new_signal(OBJECT_PATH, INTERFACE_STREAM_RESTORE, signals[SIGNAL_NEW_ENTRY].name)); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &entry->object_path, DBUS_TYPE_INVALID)); + pa_dbus_protocol_send_signal(entry->userdata->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); } static void send_entry_removed_signal(struct dbus_entry *entry) { - DBusMessage *signal; + DBusMessage *signal_msg; pa_assert(entry); - pa_assert_se(signal = dbus_message_new_signal(OBJECT_PATH, INTERFACE_STREAM_RESTORE, signals[SIGNAL_ENTRY_REMOVED].name)); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &entry->object_path, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(entry->userdata->dbus_protocol, signal); - dbus_message_unref(signal); + pa_assert_se(signal_msg = dbus_message_new_signal(OBJECT_PATH, INTERFACE_STREAM_RESTORE, signals[SIGNAL_ENTRY_REMOVED].name)); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &entry->object_path, DBUS_TYPE_INVALID)); + pa_dbus_protocol_send_signal(entry->userdata->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); } static void send_device_updated_signal(struct dbus_entry *de, struct entry *e) { - DBusMessage *signal; + DBusMessage *signal_msg; const char *device; pa_assert(de); @@ -463,28 +463,28 @@ static void send_device_updated_signal(struct dbus_entry *de, struct entry *e) { device = e->device_valid ? e->device : ""; - pa_assert_se(signal = dbus_message_new_signal(de->object_path, INTERFACE_ENTRY, entry_signals[ENTRY_SIGNAL_DEVICE_UPDATED].name)); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_STRING, &device, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(de->userdata->dbus_protocol, signal); - dbus_message_unref(signal); + pa_assert_se(signal_msg = dbus_message_new_signal(de->object_path, INTERFACE_ENTRY, entry_signals[ENTRY_SIGNAL_DEVICE_UPDATED].name)); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_STRING, &device, DBUS_TYPE_INVALID)); + pa_dbus_protocol_send_signal(de->userdata->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); } static void send_volume_updated_signal(struct dbus_entry *de, struct entry *e) { - DBusMessage *signal; + DBusMessage *signal_msg; DBusMessageIter msg_iter; pa_assert(de); pa_assert(e); - pa_assert_se(signal = dbus_message_new_signal(de->object_path, INTERFACE_ENTRY, entry_signals[ENTRY_SIGNAL_VOLUME_UPDATED].name)); - dbus_message_iter_init_append(signal, &msg_iter); + pa_assert_se(signal_msg = dbus_message_new_signal(de->object_path, INTERFACE_ENTRY, entry_signals[ENTRY_SIGNAL_VOLUME_UPDATED].name)); + dbus_message_iter_init_append(signal_msg, &msg_iter); append_volume(&msg_iter, e); - pa_dbus_protocol_send_signal(de->userdata->dbus_protocol, signal); - dbus_message_unref(signal); + pa_dbus_protocol_send_signal(de->userdata->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); } static void send_mute_updated_signal(struct dbus_entry *de, struct entry *e) { - DBusMessage *signal; + DBusMessage *signal_msg; dbus_bool_t muted; pa_assert(de); @@ -494,10 +494,10 @@ static void send_mute_updated_signal(struct dbus_entry *de, struct entry *e) { muted = e->muted; - pa_assert_se(signal = dbus_message_new_signal(de->object_path, INTERFACE_ENTRY, entry_signals[ENTRY_SIGNAL_MUTE_UPDATED].name)); - pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_BOOLEAN, &muted, DBUS_TYPE_INVALID)); - pa_dbus_protocol_send_signal(de->userdata->dbus_protocol, signal); - dbus_message_unref(signal); + pa_assert_se(signal_msg = dbus_message_new_signal(de->object_path, INTERFACE_ENTRY, entry_signals[ENTRY_SIGNAL_MUTE_UPDATED].name)); + pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_BOOLEAN, &muted, DBUS_TYPE_INVALID)); + pa_dbus_protocol_send_signal(de->userdata->dbus_protocol, signal_msg); + dbus_message_unref(signal_msg); } static void handle_get_interface_revision(DBusConnection *conn, DBusMessage *msg, void *userdata) { diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c index 1b1e9c1a..a12f7c93 100644 --- a/src/modules/module-udev-detect.c +++ b/src/modules/module-udev-detect.c @@ -172,7 +172,7 @@ static pa_bool_t is_card_busy(const char *id) { if (status_file) fclose(status_file); - if (!(status_file = fopen(sub_status, "r"))) { + if (!(status_file = pa_fopen_cloexec(sub_status, "r"))) { pa_log_warn("Failed to open %s: %s", sub_status, pa_cstrerror(errno)); continue; } diff --git a/src/modules/oss/oss-util.c b/src/modules/oss/oss-util.c index 5a109ae9..b95023c3 100644 --- a/src/modules/oss/oss-util.c +++ b/src/modules/oss/oss-util.c @@ -55,7 +55,7 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { pcaps = ∩︀ if (*mode == O_RDWR) { - if ((fd = open(device, O_RDWR|O_NDELAY|O_NOCTTY)) >= 0) { + if ((fd = pa_open_cloexec(device, O_RDWR|O_NDELAY, 0)) >= 0) { ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { @@ -71,14 +71,14 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { pa_close(fd); } - if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY|O_NOCTTY)) < 0) { - if ((fd = open(device, (*mode = O_RDONLY)|O_NDELAY|O_NOCTTY)) < 0) { + if ((fd = pa_open_cloexec(device, (*mode = O_WRONLY)|O_NDELAY, 0)) < 0) { + if ((fd = pa_open_cloexec(device, (*mode = O_RDONLY)|O_NDELAY, 0)) < 0) { pa_log("open('%s'): %s", device, pa_cstrerror(errno)); goto fail; } } } else { - if ((fd = open(device, *mode|O_NDELAY|O_NOCTTY)) < 0) { + if ((fd = pa_open_cloexec(device, *mode|O_NDELAY, 0)) < 0) { pa_log("open('%s'): %s", device, pa_cstrerror(errno)); goto fail; } @@ -145,8 +145,6 @@ success: pa_log_debug("capabilities:%s", t); pa_xfree(t); - pa_make_fd_cloexec(fd); - return fd; fail: @@ -351,9 +349,9 @@ int pa_oss_get_hw_description(const char *dev, char *name, size_t l) { if ((n = get_device_number(dev)) < 0) return -1; - if (!(f = fopen("/dev/sndstat", "r")) && - !(f = fopen("/proc/sndstat", "r")) && - !(f = fopen("/proc/asound/oss/sndstat", "r"))) { + if (!(f = pa_fopen_cloexec("/dev/sndstat", "r")) && + !(f = pa_fopen_cloexec("/proc/sndstat", "r")) && + !(f = pa_fopen_cloexec("/proc/asound/oss/sndstat", "r"))) { if (errno != ENOENT) pa_log_warn("failed to open OSS sndstat device: %s", pa_cstrerror(errno)); @@ -403,7 +401,7 @@ int pa_oss_get_hw_description(const char *dev, char *name, size_t l) { static int open_mixer(const char *mixer) { int fd; - if ((fd = open(mixer, O_RDWR|O_NDELAY|O_NOCTTY)) >= 0) + if ((fd = pa_open_cloexec(mixer, O_RDWR|O_NDELAY, 0)) >= 0) return fd; return -1; diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index 1a05f57d..7dbb1efa 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -390,7 +390,7 @@ static int mcast_socket(const struct sockaddr* sa, socklen_t salen) { pa_assert(salen > 0); af = sa->sa_family; - if ((fd = socket(af, SOCK_DGRAM, 0)) < 0) { + if ((fd = pa_socket_cloexec(af, SOCK_DGRAM, 0)) < 0) { pa_log("Failed to create socket: %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 8e1cfe36..ab815223 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -262,7 +262,7 @@ int pa__init(pa_module*m) { goto fail; } - if ((fd = socket(af, SOCK_DGRAM, 0)) < 0) { + if ((fd = pa_socket_cloexec(af, SOCK_DGRAM, 0)) < 0) { pa_log("socket() failed: %s", pa_cstrerror(errno)); goto fail; } @@ -277,7 +277,7 @@ int pa__init(pa_module*m) { #endif } - if ((sap_fd = socket(af, SOCK_DGRAM, 0)) < 0) { + if ((sap_fd = pa_socket_cloexec(af, SOCK_DGRAM, 0)) < 0) { pa_log("socket() failed: %s", pa_cstrerror(errno)); goto fail; } @@ -316,8 +316,6 @@ int pa__init(pa_module*m) { /* If the socket queue is full, let's drop packets */ pa_make_fd_nonblock(fd); pa_make_udp_socket_low_delay(fd); - pa_make_fd_cloexec(fd); - pa_make_fd_cloexec(sap_fd); pa_source_output_new_data_init(&data); pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, "RTP Monitor Stream"); diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c index 62c06f6a..3eaca4d9 100644 --- a/src/pulse/client-conf.c +++ b/src/pulse/client-conf.c @@ -110,7 +110,7 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { if (filename) { - if (!(f = fopen(filename, "r"))) { + if (!(f = pa_fopen_cloexec(filename, "r"))) { pa_log(_("Failed to open configuration file '%s': %s"), fn, pa_cstrerror(errno)); goto finish; } diff --git a/src/pulse/context.c b/src/pulse/context.c index 7468d0a9..e33143d9 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -1488,6 +1488,7 @@ pa_time_event* pa_context_rttime_new(pa_context *c, pa_usec_t usec, pa_time_even struct timeval tv; pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); pa_assert(c->mainloop); if (usec == PA_USEC_INVALID) @@ -1502,8 +1503,10 @@ void pa_context_rttime_restart(pa_context *c, pa_time_event *e, pa_usec_t usec) struct timeval tv; pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); pa_assert(c->mainloop); + if (usec == PA_USEC_INVALID) c->mainloop->time_restart(e, NULL); else { @@ -1511,3 +1514,17 @@ void pa_context_rttime_restart(pa_context *c, pa_time_event *e, pa_usec_t usec) c->mainloop->time_restart(e, &tv); } } + +size_t pa_context_get_tile_size(pa_context *c, const pa_sample_spec *ss) { + size_t fs, mbs; + + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + + PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, (size_t) -1); + PA_CHECK_VALIDITY_RETURN_ANY(c, !ss || pa_sample_spec_valid(ss), PA_ERR_INVALID, (size_t) -1); + + fs = ss ? pa_frame_size(ss) : 1; + mbs = PA_ROUND_DOWN(pa_mempool_block_size_max(c->mempool), fs); + return PA_MAX(mbs, fs); +} diff --git a/src/pulse/context.h b/src/pulse/context.h index ecff58df..6ac8ee56 100644 --- a/src/pulse/context.h +++ b/src/pulse/context.h @@ -255,12 +255,28 @@ pa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[] uint32_t pa_context_get_index(pa_context *s); /** Create a new timer event source for the specified time (wrapper - for mainloop->time_new). \since 0.9.16 */ + * for mainloop->time_new). \since 0.9.16 */ pa_time_event* pa_context_rttime_new(pa_context *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata); -/** Restart a running or expired timer event source (wrapper - for mainloop->time_restart). \since 0.9.16 */ + +/** Restart a running or expired timer event source (wrapper for + * mainloop->time_restart). \since 0.9.16 */ void pa_context_rttime_restart(pa_context *c, pa_time_event *e, pa_usec_t usec); +/* Return the optimal block size for passing around audio buffers. It + * is recommended to allocate buffers of the size returned here when + * writing audio data to playback streams, if the latency constraints + * permit this. It is not recommended writing larger blocks than this + * because usually they will then be split up internally into chunks + * of this size. It is not recommended writing smaller blocks than + * this (unless required due to latency demands) because this + * increases CPU usage. If ss is NULL you will be returned the + * byte-exact tile size. If you pass a valid ss, then the tile size + * will be rounded down to multiple of the frame size. This is + * supposed to be used in a construct such as + * pa_context_get_tile_size(pa_stream_get_context(s), + * pa_stream_get_sample_spec(ss)); \since 0.9.20 */ +size_t pa_context_get_tile_size(pa_context *c, const pa_sample_spec *ss); + PA_C_DECL_END #endif diff --git a/src/pulse/def.h b/src/pulse/def.h index 5d0a0b4b..30a076d5 100644 --- a/src/pulse/def.h +++ b/src/pulse/def.h @@ -276,11 +276,18 @@ typedef enum pa_stream_flags { * whether to create the stream in muted or in unmuted * state. \since 0.9.15 */ - PA_STREAM_FAIL_ON_SUSPEND = 0x20000U + PA_STREAM_FAIL_ON_SUSPEND = 0x20000U, /**< If the sink/source this stream is connected to is suspended * during the creation of this stream, cause it to fail. If the * sink/source is being suspended during creation of this stream, * make sure this stream is terminated. \since 0.9.15 */ + + PA_STREAM_RELATIVE_VOLUME = 0x40000U, + /**< If a volume is passed when this stream is created, consider + * it relative to the sink's current volume, never as absolute + * device volume. If this is not specified the volume will be + * consider absolute when the sink is in flat volume mode, + * relative otherwise. \since 0.9.20 */ } pa_stream_flags_t; /** \cond fulldocs */ @@ -307,6 +314,7 @@ typedef enum pa_stream_flags { #define PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND #define PA_STREAM_START_UNMUTED PA_STREAM_START_UNMUTED #define PA_STREAM_FAIL_ON_SUSPEND PA_STREAM_FAIL_ON_SUSPEND +#define PA_STREAM_RELATIVE_VOLUME PA_STREAM_RELATIVE_VOLUME /** \endcond */ diff --git a/src/pulse/ext-device-manager.h b/src/pulse/ext-device-manager.h index 1442a1a9..df0ab92f 100644 --- a/src/pulse/ext-device-manager.h +++ b/src/pulse/ext-device-manager.h @@ -39,7 +39,7 @@ typedef struct pa_ext_device_manager_role_priority_info { } pa_ext_device_manager_role_priority_info; /** Stores information about one device in the device database that is - * maintained by module-device-manager. \since 0.9.19 */ + * maintained by module-device-manager. \since 0.9.21 */ typedef struct pa_ext_device_manager_info { const char *name; /**< Identifier string of the device. A string like "sink:" or similar followed by the name of the device. */ const char *description; /**< The description of the device when it was last seen, if applicable and saved */ @@ -49,32 +49,32 @@ typedef struct pa_ext_device_manager_info { pa_ext_device_manager_role_priority_info *role_priorities; /**< An array of role priority structures or NULL */ } pa_ext_device_manager_info; -/** Callback prototype for pa_ext_device_manager_test(). \since 0.9.19 */ +/** Callback prototype for pa_ext_device_manager_test(). \since 0.9.21 */ typedef void (*pa_ext_device_manager_test_cb_t)( pa_context *c, uint32_t version, void *userdata); -/** Test if this extension module is available in the server. \since 0.9.19 */ +/** Test if this extension module is available in the server. \since 0.9.21 */ pa_operation *pa_ext_device_manager_test( pa_context *c, pa_ext_device_manager_test_cb_t cb, void *userdata); -/** Callback prototype for pa_ext_device_manager_read(). \since 0.9.19 */ +/** Callback prototype for pa_ext_device_manager_read(). \since 0.9.21 */ typedef void (*pa_ext_device_manager_read_cb_t)( pa_context *c, const pa_ext_device_manager_info *info, int eol, void *userdata); -/** Read all entries from the device database. \since 0.9.19 */ +/** Read all entries from the device database. \since 0.9.21 */ pa_operation *pa_ext_device_manager_read( pa_context *c, pa_ext_device_manager_read_cb_t cb, void *userdata); -/** Sets the description for a device. \since 0.9.19 */ +/** Sets the description for a device. \since 0.9.21 */ pa_operation *pa_ext_device_manager_set_device_description( pa_context *c, const char* device, @@ -82,21 +82,21 @@ pa_operation *pa_ext_device_manager_set_device_description( pa_context_success_cb_t cb, void *userdata); -/** Delete entries from the device database. \since 0.9.19 */ +/** Delete entries from the device database. \since 0.9.21 */ pa_operation *pa_ext_device_manager_delete( pa_context *c, const char *const s[], pa_context_success_cb_t cb, void *userdata); -/** Enable the role-based device-priority routing mode. \since 0.9.19 */ +/** Enable the role-based device-priority routing mode. \since 0.9.21 */ pa_operation *pa_ext_device_manager_enable_role_device_priority_routing( pa_context *c, int enable, pa_context_success_cb_t cb, void *userdata); -/** Prefer a given device in the priority list. \since 0.9.19 */ +/** Prefer a given device in the priority list. \since 0.9.21 */ pa_operation *pa_ext_device_manager_reorder_devices_for_role( pa_context *c, const char* role, @@ -104,20 +104,20 @@ pa_operation *pa_ext_device_manager_reorder_devices_for_role( pa_context_success_cb_t cb, void *userdata); -/** Subscribe to changes in the device database. \since 0.9.19 */ +/** Subscribe to changes in the device database. \since 0.9.21 */ pa_operation *pa_ext_device_manager_subscribe( pa_context *c, int enable, pa_context_success_cb_t cb, void *userdata); -/** Callback prototype for pa_ext_device_manager_set_subscribe_cb(). \since 0.9.19 */ +/** Callback prototype for pa_ext_device_manager_set_subscribe_cb(). \since 0.9.21 */ typedef void (*pa_ext_device_manager_subscribe_cb_t)( pa_context *c, void *userdata); /** Set the subscription callback that is called when - * pa_ext_device_manager_subscribe() was called. \since 0.9.19 */ + * pa_ext_device_manager_subscribe() was called. \since 0.9.21 */ void pa_ext_device_manager_set_subscribe_cb( pa_context *c, pa_ext_device_manager_subscribe_cb_t cb, diff --git a/src/pulse/mainloop-signal.c b/src/pulse/mainloop-signal.c index 3dc74398..70c0122c 100644 --- a/src/pulse/mainloop-signal.c +++ b/src/pulse/mainloop-signal.c @@ -124,15 +124,13 @@ int pa_signal_init(pa_mainloop_api *a) { pa_assert(signal_pipe[1] == -1); pa_assert(!io_event); - if (pipe(signal_pipe) < 0) { + if (pa_pipe_cloexec(signal_pipe) < 0) { pa_log("pipe(): %s", pa_cstrerror(errno)); return -1; } pa_make_fd_nonblock(signal_pipe[0]); pa_make_fd_nonblock(signal_pipe[1]); - pa_make_fd_cloexec(signal_pipe[0]); - pa_make_fd_cloexec(signal_pipe[1]); api = a; diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c index 090ac8c2..6cd089ef 100644 --- a/src/pulse/mainloop.c +++ b/src/pulse/mainloop.c @@ -482,7 +482,7 @@ pa_mainloop *pa_mainloop_new(void) { m = pa_xnew0(pa_mainloop, 1); - if (pipe(m->wakeup_pipe) < 0) { + if (pa_pipe_cloexec(m->wakeup_pipe) < 0) { pa_log_error("ERROR: cannot create wakeup pipe"); pa_xfree(m); return NULL; @@ -490,8 +490,6 @@ pa_mainloop *pa_mainloop_new(void) { pa_make_fd_nonblock(m->wakeup_pipe[0]); pa_make_fd_nonblock(m->wakeup_pipe[1]); - pa_make_fd_cloexec(m->wakeup_pipe[0]); - pa_make_fd_cloexec(m->wakeup_pipe[1]); m->rebuild_pollfds = TRUE; diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 2bc2b1e4..4dea5670 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -387,9 +387,26 @@ static void check_smoother_status(pa_stream *s, pa_bool_t aposteriori, pa_bool_t if (s->suspended || s->corked || force_stop) pa_smoother_pause(s->smoother, x); - else if (force_start || s->buffer_attr.prebuf == 0) - pa_smoother_resume(s->smoother, x, TRUE); + else if (force_start || s->buffer_attr.prebuf == 0) { + + if (!s->timing_info_valid && + !aposteriori && + !force_start && + !force_stop && + s->context->version >= 13) { + + /* If the server supports STARTED events we take them as + * indications when audio really starts/stops playing, if + * we don't have any timing info yet -- instead of trying + * to be smart and guessing the server time. Otherwise the + * unknown transport delay add too much noise to our time + * calculations. */ + + return; + } + pa_smoother_resume(s->smoother, x, TRUE); + } /* Please note that we have no idea if playback actually started * if prebuf is non-zero! */ @@ -1025,7 +1042,8 @@ static int create_stream( PA_STREAM_EARLY_REQUESTS| PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND| PA_STREAM_START_UNMUTED| - PA_STREAM_FAIL_ON_SUSPEND)), PA_ERR_INVALID); + PA_STREAM_FAIL_ON_SUSPEND| + PA_STREAM_RELATIVE_VOLUME)), PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, s->context->version >= 12 || !(flags & PA_STREAM_VARIABLE_RATE), PA_ERR_NOTSUPPORTED); PA_CHECK_VALIDITY(s->context, s->context->version >= 13 || !(flags & PA_STREAM_PEAK_DETECT), PA_ERR_NOTSUPPORTED); @@ -1158,6 +1176,13 @@ static int create_stream( pa_tagstruct_put_boolean(t, flags & PA_STREAM_FAIL_ON_SUSPEND); } + if (s->context->version >= 17) { + + if (s->direction == PA_STREAM_PLAYBACK) + pa_tagstruct_put_boolean(t, flags & PA_STREAM_RELATIVE_VOLUME); + + } + pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL); @@ -1457,6 +1482,11 @@ pa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *us PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); + /* Ask for a timing update before we cork/uncork to get the best + * accuracy for the transport latency suitable for the + * check_smoother_status() call in the started callback */ + request_auto_timing_update(s, TRUE); + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command(s->context, PA_COMMAND_DRAIN_PLAYBACK_STREAM, &tag); @@ -1464,6 +1494,10 @@ pa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *us pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + /* This might cause the read index to conitnue again, hence + * let's request a timing update */ + request_auto_timing_update(s, TRUE); + return o; } @@ -2012,6 +2046,11 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, voi PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + /* Ask for a timing update before we cork/uncork to get the best + * accuracy for the transport latency suitable for the + * check_smoother_status() call in the started callback */ + request_auto_timing_update(s, TRUE); + s->corked = b; o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); @@ -2027,8 +2066,8 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, voi check_smoother_status(s, FALSE, FALSE, FALSE); - /* This might cause the indexes to hang/start again, hence - * let's request a timing update */ + /* This might cause the indexes to hang/start again, hence let's + * request a timing update, after the cork/uncork, too */ request_auto_timing_update(s, TRUE); return o; @@ -2065,6 +2104,11 @@ pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *use PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + /* Ask for a timing update *before* the flush, so that the + * transport usec is as up to date as possible when we get the + * underflow message and update the smoother status*/ + request_auto_timing_update(s, TRUE); + if (!(o = stream_send_simple_command(s, (uint32_t) (s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM), cb, userdata))) return NULL; @@ -2099,6 +2143,11 @@ pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *us PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); + /* Ask for a timing update before we cork/uncork to get the best + * accuracy for the transport latency suitable for the + * check_smoother_status() call in the started callback */ + request_auto_timing_update(s, TRUE); + if (!(o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata))) return NULL; @@ -2120,6 +2169,11 @@ pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *u PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); + /* Ask for a timing update before we cork/uncork to get the best + * accuracy for the transport latency suitable for the + * check_smoother_status() call in the started callback */ + request_auto_timing_update(s, TRUE); + if (!(o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata))) return NULL; @@ -2371,6 +2425,11 @@ pa_operation* pa_stream_set_buffer_attr(pa_stream *s, const pa_buffer_attr *attr PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->context->version >= 12, PA_ERR_NOTSUPPORTED); + /* Ask for a timing update before we cork/uncork to get the best + * accuracy for the transport latency suitable for the + * check_smoother_status() call in the started callback */ + request_auto_timing_update(s, TRUE); + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command( diff --git a/src/pulse/stream.h b/src/pulse/stream.h index 2e8e71a0..bc54a118 100644 --- a/src/pulse/stream.h +++ b/src/pulse/stream.h @@ -401,7 +401,22 @@ int pa_stream_is_suspended(pa_stream *s); * not, and negative on error. \since 0.9.11 */ int pa_stream_is_corked(pa_stream *s); -/** Connect the stream to a sink */ +/** Connect the stream to a sink. It is strongly recommended to pass + * NULL in both dev and volume and not to set either + * PA_STREAM_START_MUTED nor PA_STREAM_START_UNMUTED -- unless these + * options are directly dependant on user input or configuration. If + * you follow this rule then the sound server will have the full + * flexibility to choose the device, volume and mute status + * automatically, based on server-side policies, heuristics and stored + * information from previous uses. Also the server may choose to + * reconfigure audio devices to make other sinks/sources or + * capabilities available to be able to accept the stream. Before + * 0.9.20 it was not defined whether the 'volume' parameter was + * interpreted relative to the sink's current volume or treated as + * absolute device volume. Since 0.9.20 it is an absolute volume when + * the sink is in flat volume mode, and relative otherwise, thus + * making sure the volume passed here has always the same semantics as + * the volume passed to pa_context_set_sink_input_volume(). */ int pa_stream_connect_playback( pa_stream *s /**< The stream to connect to a sink */, const char *dev /**< Name of the sink to connect to, or NULL for default */ , diff --git a/src/pulse/util.c b/src/pulse/util.c index 9440f5de..ca766dab 100644 --- a/src/pulse/util.c +++ b/src/pulse/util.c @@ -189,7 +189,18 @@ char *pa_get_binary_name(char *s, size_t l) { return s; } } +#endif +#ifdef __FreeBSD__ + { + char *rp; + + if ((rp = pa_readlink("/proc/curproc/file"))) { + pa_strlcpy(s, pa_path_get_filename(rp), l); + pa_xfree(rp); + return s; + } + } #endif #if defined(HAVE_SYS_PRCTL_H) && defined(PR_GET_NAME) diff --git a/src/pulse/volume.c b/src/pulse/volume.c index 2d2bba25..59e9a189 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -885,7 +885,7 @@ pa_cvolume* pa_cvolume_merge(pa_cvolume *dest, const pa_cvolume *a, const pa_cvo return dest; } -pa_cvolume* pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc) { +pa_cvolume* pa_cvolume_inc_clamp(pa_cvolume *v, pa_volume_t inc, pa_volume_t limit) { pa_volume_t m; pa_assert(v); @@ -895,14 +895,18 @@ pa_cvolume* pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc) { m = pa_cvolume_max(v); - if (m >= PA_VOLUME_MAX - inc) - m = PA_VOLUME_MAX; + if (m >= limit - inc) + m = limit; else m += inc; return pa_cvolume_scale(v, m); } +pa_cvolume* pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc){ + return pa_cvolume_inc_clamp(v, inc, PA_VOLUME_MAX); +} + pa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec) { pa_volume_t m; diff --git a/src/pulse/volume.h b/src/pulse/volume.h index c964020a..ded4422e 100644 --- a/src/pulse/volume.h +++ b/src/pulse/volume.h @@ -348,6 +348,10 @@ pa_volume_t pa_cvolume_get_position(pa_cvolume *cv, const pa_channel_map *map, p * and dest may point to the same structure. \since 0.9.16 */ pa_cvolume* pa_cvolume_merge(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b); +/** Increase the volume passed in by 'inc', but not exceeding 'limit'. + * The proportions between the channels are kept. \since 0.9.19 */ +pa_cvolume* pa_cvolume_inc_clamp(pa_cvolume *v, pa_volume_t inc, pa_volume_t limit); + /** Increase the volume passed in by 'inc'. The proportions between * the channels are kept. \since 0.9.16 */ pa_cvolume* pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc); diff --git a/src/pulsecore/atomic.h b/src/pulsecore/atomic.h index 119c445b..51d08210 100644 --- a/src/pulsecore/atomic.h +++ b/src/pulsecore/atomic.h @@ -180,6 +180,110 @@ static inline pa_bool_t pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, v return r == old_p; } +#elif defined(__FreeBSD__) + +#include <sys/cdefs.h> +#include <sys/types.h> +#include <sys/param.h> +#include <machine/atomic.h> + +#if __FreeBSD_version < 600000 +#if defined(__i386__) || defined(__amd64__) +#if defined(__amd64__) +#define atomic_load_acq_64 atomic_load_acq_long +#endif +static inline u_int atomic_fetchadd_int(volatile u_int *p, u_int v) { + __asm __volatile( + " " __XSTRING(MPLOCKED) " " + " xaddl %0, %1 ; " + "# atomic_fetchadd_int" + : "+r" (v), + "=m" (*p) + : "m" (*p)); + + return (v); +} +#elif defined(__sparc64__) +#define atomic_load_acq_64 atomic_load_acq_long +#define atomic_fetchadd_int atomic_add_int +#elif defined(__ia64__) +#define atomic_load_acq_64 atomic_load_acq_long +static inline uint32_t +atomic_fetchadd_int(volatile uint32_t *p, uint32_t v) { + uint32_t value; + + do { + value = *p; + } while (!atomic_cmpset_32(p, value, value + v)); + return (value); +} +#endif +#endif + +typedef struct pa_atomic { + volatile unsigned long value; +} pa_atomic_t; + +#define PA_ATOMIC_INIT(v) { .value = (v) } + +static inline int pa_atomic_load(const pa_atomic_t *a) { + return (int) atomic_load_acq_int((unsigned int *) &a->value); +} + +static inline void pa_atomic_store(pa_atomic_t *a, int i) { + atomic_store_rel_int((unsigned int *) &a->value, i); +} + +static inline int pa_atomic_add(pa_atomic_t *a, int i) { + return atomic_fetchadd_int((unsigned int *) &a->value, i); +} + +static inline int pa_atomic_sub(pa_atomic_t *a, int i) { + return atomic_fetchadd_int((unsigned int *) &a->value, -(i)); +} + +static inline int pa_atomic_inc(pa_atomic_t *a) { + return atomic_fetchadd_int((unsigned int *) &a->value, 1); +} + +static inline int pa_atomic_dec(pa_atomic_t *a) { + return atomic_fetchadd_int((unsigned int *) &a->value, -1); +} + +static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) { + return atomic_cmpset_int((unsigned int *) &a->value, old_i, new_i); +} + +typedef struct pa_atomic_ptr { + volatile unsigned long value; +} pa_atomic_ptr_t; + +#define PA_ATOMIC_PTR_INIT(v) { .value = (unsigned long) (v) } + +static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) { +#ifdef atomic_load_acq_64 + return (void*) atomic_load_acq_ptr((unsigned long *) &a->value); +#else + return (void*) atomic_load_acq_ptr((unsigned int *) &a->value); +#endif +} + +static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) { +#ifdef atomic_load_acq_64 + atomic_store_rel_ptr(&a->value, (unsigned long) p); +#else + atomic_store_rel_ptr((unsigned int *) &a->value, (unsigned int) p); +#endif +} + +static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) { +#ifdef atomic_load_acq_64 + return atomic_cmpset_ptr(&a->value, (unsigned long) old_p, (unsigned long) new_p); +#else + return atomic_cmpset_ptr((unsigned int *) &a->value, (unsigned int) old_p, (unsigned int) new_p); +#endif +} + #elif defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__)) #warn "The native atomic operations implementation for AMD64 has not been tested thoroughly. libatomic_ops is known to not work properly on AMD64 and your gcc version is too old for the gcc-builtin atomic ops support. You have three options now: test the native atomic operations implementation for AMD64, fix libatomic_ops, or upgrade your GCC." diff --git a/src/pulsecore/authkey.c b/src/pulsecore/authkey.c index 15613e27..d671e367 100644 --- a/src/pulsecore/authkey.c +++ b/src/pulsecore/authkey.c @@ -70,10 +70,6 @@ static int generate(int fd, void *ret_data, size_t length) { #define O_BINARY 0 #endif -#ifndef O_NOCTTY -#define O_NOCTTY 0 -#endif - /* Load an euthorization cookie from file fn and store it in data. If * the cookie file doesn't exist, create it */ static int load(const char *fn, void *data, size_t length) { @@ -86,9 +82,9 @@ static int load(const char *fn, void *data, size_t length) { pa_assert(data); pa_assert(length > 0); - if ((fd = open(fn, O_RDWR|O_CREAT|O_BINARY|O_NOCTTY, S_IRUSR|S_IWUSR)) < 0) { + if ((fd = pa_open_cloexec(fn, O_RDWR|O_CREAT|O_BINARY, S_IRUSR|S_IWUSR)) < 0) { - if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY|O_NOCTTY)) < 0) { + if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY)) < 0) { pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } else @@ -204,7 +200,7 @@ int pa_authkey_save(const char *fn, const void *data, size_t length) { if (!(p = normalize_path(fn))) return -2; - if ((fd = open(p, O_RDWR|O_CREAT|O_NOCTTY, S_IRUSR|S_IWUSR)) < 0) { + if ((fd = pa_open_cloexec(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index b57919a4..82a44d84 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -1804,7 +1804,7 @@ int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, pa_b if (!fail) fail = &_fail; - if (!(f = fopen(fn, "r"))) { + if (!(f = pa_fopen_cloexec(fn, "r"))) { pa_strbuf_printf(buf, "open('%s') failed: %s\n", fn, pa_cstrerror(errno)); if (!*fail) ret = 0; diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c index dd4a99ee..34b4d6fe 100644 --- a/src/pulsecore/conf-parser.c +++ b/src/pulsecore/conf-parser.c @@ -168,7 +168,7 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void pa_assert(filename); pa_assert(t); - if (!f && !(f = fopen(filename, "r"))) { + if (!f && !(f = pa_fopen_cloexec(filename, "r"))) { if (errno == ENOENT) { pa_log_debug("Failed to open configuration file '%s': %s", filename, pa_cstrerror(errno)); r = 0; diff --git a/src/pulsecore/core-rtclock.c b/src/pulsecore/core-rtclock.c index 1420470a..4fe0a47b 100644 --- a/src/pulsecore/core-rtclock.c +++ b/src/pulsecore/core-rtclock.c @@ -33,6 +33,12 @@ #include <sys/prctl.h> #endif +#ifdef OS_IS_DARWIN +#include <CoreServices/CoreServices.h> +#include <mach/mach.h> +#include <mach/mach_time.h> +#endif + #include <pulse/timeval.h> #include <pulsecore/macro.h> #include <pulsecore/core-error.h> @@ -47,7 +53,8 @@ pa_usec_t pa_rtclock_age(const struct timeval *tv) { } struct timeval *pa_rtclock_get(struct timeval *tv) { -#ifdef HAVE_CLOCK_GETTIME + +#if defined(HAVE_CLOCK_GETTIME) struct timespec ts; #ifdef CLOCK_MONOTONIC @@ -59,7 +66,7 @@ struct timeval *pa_rtclock_get(struct timeval *tv) { no_monotonic = TRUE; if (no_monotonic) -#endif +#endif /* CLOCK_MONOTONIC */ pa_assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0); pa_assert(tv); @@ -69,7 +76,30 @@ struct timeval *pa_rtclock_get(struct timeval *tv) { return tv; -#else /* HAVE_CLOCK_GETTIME */ +#elif defined(OS_IS_DARWIN) + static mach_timebase_info_data_t tbi; + uint64_t nticks; + uint64_t time_nsec; + + /* Refer Apple ADC QA1398 + Also: http://devworld.apple.com/documentation/Darwin/Conceptual/KernelProgramming/services/services.html + + Note: argument is timespec NOT timeval (timespec uses nsec, timeval uses usec) + */ + + /* try and be a mite efficient - maybe I should keep the N/D as a float !? */ + if (tbi.denom == 0) + mach_timebase_info(&tbi); + + nticks = mach_absolute_time(); + time_nsec = nticks * tbi.numer / tbi.denom; // see above + + tv->tv_sec = time_nsec / PA_NSEC_PER_SEC; + tv->tv_usec = time_nsec / PA_NSEC_PER_USEC; + + return tv; + +#else /* OS_IS_DARWIN */ return pa_gettimeofday(tv); @@ -77,19 +107,30 @@ struct timeval *pa_rtclock_get(struct timeval *tv) { } pa_bool_t pa_rtclock_hrtimer(void) { -#ifdef HAVE_CLOCK_GETTIME + +#if defined(HAVE_CLOCK_GETTIME) struct timespec ts; #ifdef CLOCK_MONOTONIC + if (clock_getres(CLOCK_MONOTONIC, &ts) >= 0) return ts.tv_sec == 0 && ts.tv_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC); -#endif +#endif /* CLOCK_MONOTONIC */ pa_assert_se(clock_getres(CLOCK_REALTIME, &ts) == 0); return ts.tv_sec == 0 && ts.tv_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC); -#else /* HAVE_CLOCK_GETTIME */ +#elif defined (OS_IS_DARWIN) + mach_timebase_info_data_t tbi; + uint64_t time_nsec; + + mach_timebase_info(&tbi); + /* nsec = nticks * (N/D) - we want 1 tick == resolution !? */ + time_nsec = tbi.numer / tbi.denom; + return time_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC); + +#else /* OS_IS_DARWIN */ return FALSE; #endif @@ -98,6 +139,7 @@ pa_bool_t pa_rtclock_hrtimer(void) { #define TIMER_SLACK_NS (int) ((500 * PA_NSEC_PER_USEC)) void pa_rtclock_hrtimer_enable(void) { + #ifdef PR_SET_TIMERSLACK int slack_ns; diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 27e09cbc..d596c481 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -117,6 +117,7 @@ #include <pulsecore/strbuf.h> #include <pulsecore/usergroup.h> #include <pulsecore/strlist.h> +#include <pulsecore/cpu-x86.h> #include "core-util.h" @@ -1200,10 +1201,7 @@ int pa_lock_lockfile(const char *fn) { for (;;) { struct stat st; - if ((fd = open(fn, O_CREAT|O_RDWR -#ifdef O_NOCTTY - |O_NOCTTY -#endif + if ((fd = pa_open_cloexec(fn, O_CREAT|O_RDWR #ifdef O_NOFOLLOW |O_NOFOLLOW #endif @@ -1603,7 +1601,7 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env fn = buf; #endif - if ((f = fopen(fn, "r"))) { + if ((f = pa_fopen_cloexec(fn, "r"))) { if (result) *result = pa_xstrdup(fn); @@ -1637,7 +1635,7 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env fn = buf; #endif - if ((f = fopen(fn, "r"))) { + if ((f = pa_fopen_cloexec(fn, "r"))) { if (result) *result = pa_xstrdup(fn); @@ -1664,7 +1662,7 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env global = buf; #endif - if ((f = fopen(global, "r"))) { + if ((f = pa_fopen_cloexec(global, "r"))) { if (result) *result = pa_xstrdup(global); @@ -2563,7 +2561,7 @@ char *pa_machine_id(void) { * since it fits perfectly our needs and is not as volatile as the * hostname which might be set from dhcp. */ - if ((f = fopen(PA_MACHINE_ID, "r"))) { + if ((f = pa_fopen_cloexec(PA_MACHINE_ID, "r"))) { char ln[34] = "", *r; r = fgets(ln, sizeof(ln)-1, f); @@ -2889,3 +2887,224 @@ const char *pa_get_temp_dir(void) { return "/tmp"; } + +int pa_open_cloexec(const char *fn, int flags, mode_t mode) { + int fd; + +#ifdef O_NOCTTY + flags |= O_NOCTTY; +#endif + +#ifdef O_CLOEXEC + if ((fd = open(fn, flags|O_CLOEXEC, mode)) >= 0) + goto finish; + + if (errno != EINVAL) + return fd; +#endif + + if ((fd = open(fn, flags, mode)) < 0) + return fd; + +finish: + /* Some implementations might simply ignore O_CLOEXEC if it is not + * understood, make sure FD_CLOEXEC is enabled anyway */ + + pa_make_fd_cloexec(fd); + return fd; +} + +int pa_socket_cloexec(int domain, int type, int protocol) { + int fd; + +#ifdef SOCK_CLOEXEC + if ((fd = socket(domain, type | SOCK_CLOEXEC, protocol)) >= 0) + goto finish; + + if (errno != EINVAL) + return fd; +#endif + + if ((fd = socket(domain, type, protocol)) < 0) + return fd; + +finish: + /* Some implementations might simply ignore SOCK_CLOEXEC if it is + * not understood, make sure FD_CLOEXEC is enabled anyway */ + + pa_make_fd_cloexec(fd); + return fd; +} + +int pa_pipe_cloexec(int pipefd[2]) { + int r; + +#ifdef HAVE_PIPE2 + if ((r = pipe2(pipefd, O_CLOEXEC)) >= 0) + goto finish; + + if (errno != EINVAL && errno != ENOSYS) + return r; + +#endif + + if ((r = pipe(pipefd)) < 0) + return r; + +finish: + pa_make_fd_cloexec(pipefd[0]); + pa_make_fd_cloexec(pipefd[1]); + + return 0; +} + +int pa_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { + int fd; + +#ifdef HAVE_ACCEPT4 + if ((fd = accept4(sockfd, addr, addrlen, SOCK_CLOEXEC)) >= 0) + goto finish; + + if (errno != EINVAL && errno != ENOSYS) + return fd; + +#endif + + if ((fd = accept(sockfd, addr, addrlen)) < 0) + return fd; + +finish: + pa_make_fd_cloexec(fd); + return fd; +} + +FILE* pa_fopen_cloexec(const char *path, const char *mode) { + FILE *f; + char *m; + + m = pa_sprintf_malloc("%se", mode); + + errno = 0; + if ((f = fopen(path, m))) { + pa_xfree(m); + goto finish; + } + + pa_xfree(m); + + if (errno != EINVAL) + return NULL; + + if (!(f = fopen(path, mode))) + return NULL; + +finish: + pa_make_fd_cloexec(fileno(f)); + return f; +} + +void pa_nullify_stdfds(void) { + +#ifndef OS_IS_WIN32 + pa_close(STDIN_FILENO); + pa_close(STDOUT_FILENO); + pa_close(STDERR_FILENO); + + pa_assert_se(open("/dev/null", O_RDONLY) == STDIN_FILENO); + pa_assert_se(open("/dev/null", O_WRONLY) == STDOUT_FILENO); + pa_assert_se(open("/dev/null", O_WRONLY) == STDERR_FILENO); +#else + FreeConsole(); +#endif + +} + +char *pa_read_line_from_file(const char *fn) { + FILE *f; + char ln[256] = "", *r; + + if (!(f = pa_fopen_cloexec(fn, "r"))) + return NULL; + + r = fgets(ln, sizeof(ln)-1, f); + fclose(f); + + if (!r) { + errno = EIO; + return NULL; + } + + pa_strip_nl(ln); + return pa_xstrdup(ln); +} + +pa_bool_t pa_running_in_vm(void) { + +#if defined(__i386__) || defined(__x86_64__) + + /* Both CPUID and DMI are x86 specific interfaces... */ + + uint32_t eax = 0x40000000; + union { + uint32_t sig32[3]; + char text[13]; + } sig; + +#ifdef __linux__ + const char *const dmi_vendors[] = { + "/sys/class/dmi/id/sys_vendor", + "/sys/class/dmi/id/board_vendor", + "/sys/class/dmi/id/bios_vendor" + }; + + unsigned i; + + for (i = 0; i < PA_ELEMENTSOF(dmi_vendors); i++) { + char *s; + + if ((s = pa_read_line_from_file(dmi_vendors[i]))) { + + if (pa_startswith(s, "QEMU") || + /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ + pa_startswith(s, "VMware") || + pa_startswith(s, "VMW") || + pa_startswith(s, "Microsoft Corporation") || + pa_startswith(s, "innotek GmbH") || + pa_startswith(s, "Xen")) { + + pa_xfree(s); + return TRUE; + } + + pa_xfree(s); + } + } + +#endif + + /* http://lwn.net/Articles/301888/ */ + pa_zero(sig); + + __asm__ __volatile__ ( + /* ebx/rbx is being used for PIC! */ + " push %%"PA_REG_b" \n\t" + " cpuid \n\t" + " mov %%ebx, %1 \n\t" + " pop %%"PA_REG_b" \n\t" + + : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2]) + : "0" (eax) + ); + + if (pa_streq(sig.text, "XenVMMXenVMM") || + pa_streq(sig.text, "KVMKVMKVM") || + /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ + pa_streq(sig.text, "VMwareVMware") || + /* http://msdn.microsoft.com/en-us/library/bb969719.aspx */ + pa_streq(sig.text, "Microsoft Hv")) + return TRUE; + +#endif + + return FALSE; +} diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index 9986b14a..31a83bcc 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -28,6 +28,7 @@ #include <stdarg.h> #include <stdio.h> #include <string.h> +#include <sys/socket.h> #ifdef HAVE_SYS_RESOURCE_H #include <sys/resource.h> @@ -258,4 +259,15 @@ pa_bool_t pa_run_from_build_tree(void); const char *pa_get_temp_dir(void); +int pa_open_cloexec(const char *fn, int flags, mode_t mode); +int pa_socket_cloexec(int domain, int type, int protocol); +int pa_pipe_cloexec(int pipefd[2]); +int pa_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen); +FILE* pa_fopen_cloexec(const char *path, const char *mode); + +void pa_nullify_stdfds(void); + +char *pa_read_line_from_file(const char *fn); +pa_bool_t pa_running_in_vm(void); + #endif diff --git a/src/pulsecore/cpu-arm.c b/src/pulsecore/cpu-arm.c index 453b7848..6bb2eadd 100644 --- a/src/pulsecore/cpu-arm.c +++ b/src/pulsecore/cpu-arm.c @@ -62,7 +62,7 @@ static char *get_cpuinfo(void) { cpuinfo = pa_xmalloc(MAX_BUFFER); - if ((fd = open("/proc/cpuinfo", O_RDONLY)) < 0) { + if ((fd = pa_open_cloexec("/proc/cpuinfo", O_RDONLY, 0)) < 0) { pa_xfree(cpuinfo); return NULL; } diff --git a/src/pulsecore/database-simple.c b/src/pulsecore/database-simple.c index 1f4caf71..754930db 100644 --- a/src/pulsecore/database-simple.c +++ b/src/pulsecore/database-simple.c @@ -237,7 +237,7 @@ pa_database* pa_database_open(const char *fn, pa_bool_t for_write) { path = pa_sprintf_malloc("%s."CANONICAL_HOST".simple", fn); errno = 0; - f = fopen(path, "r"); + f = pa_fopen_cloexec(path, "r"); if (f || errno == ENOENT) { /* file not found is ok */ db = pa_xnew0(simple_data, 1); @@ -480,7 +480,7 @@ int pa_database_sync(pa_database *database) { errno = 0; - f = fopen(db->tmp_filename, "w"); + f = pa_fopen_cloexec(db->tmp_filename, "w"); if (!f) goto fail; diff --git a/src/pulsecore/database-tdb.c b/src/pulsecore/database-tdb.c index b79d2837..4e782d65 100644 --- a/src/pulsecore/database-tdb.c +++ b/src/pulsecore/database-tdb.c @@ -66,6 +66,39 @@ void pa_datum_free(pa_datum *d) { pa_zero(d); } +static struct tdb_context *tdb_open_cloexec( + const char *name, + int hash_size, + int tdb_flags, + int open_flags, + mode_t mode) { + + /* Mimics pa_open_cloexec() */ + + struct tdb_context *c; + +#ifdef O_NOCTTY + open_flags |= O_NOCTTY; +#endif + +#ifdef O_CLOEXEC + errno = 0; + if ((c = tdb_open(name, hash_size, tdb_flags, open_flags | O_CLOEXEC, mode))) + goto finish; + + if (errno != EINVAL) + return NULL; +#endif + + errno = 0; + if (!(c = tdb_open(name, hash_size, tdb_flags, open_flags, mode))) + return NULL; + +finish: + pa_make_fd_cloexec(tdb_fd(c)); + return c; +} + pa_database* pa_database_open(const char *fn, pa_bool_t for_write) { struct tdb_context *c; char *path; @@ -73,15 +106,7 @@ pa_database* pa_database_open(const char *fn, pa_bool_t for_write) { pa_assert(fn); path = pa_sprintf_malloc("%s.tdb", fn); - errno = 0; - c = tdb_open(path, 0, TDB_NOSYNC|TDB_NOLOCK, - (for_write ? O_RDWR|O_CREAT : O_RDONLY)|O_NOCTTY -#ifdef O_CLOEXEC - |O_CLOEXEC -#endif - , 0644); - - if (c) + if ((c = tdb_open_cloexec(path, 0, TDB_NOSYNC|TDB_NOLOCK, (for_write ? O_RDWR|O_CREAT : O_RDONLY), 0644))) pa_log_debug("Opened TDB database '%s'", path); pa_xfree(path); diff --git a/src/pulsecore/envelope.c b/src/pulsecore/envelope.c index fd6a9487..0eca8115 100644 --- a/src/pulsecore/envelope.c +++ b/src/pulsecore/envelope.c @@ -177,7 +177,7 @@ static int32_t item_get_int(pa_envelope_item *i, pa_usec_t x) { pa_assert(i->j > 0); pa_assert(i->def->points_x[i->j-1] <= x); - pa_assert(x < i->def->points_x[i->j]); + pa_assert(x <= i->def->points_x[i->j]); return linear_interpolate_int(i->def->points_x[i->j-1], i->def->points_y.i[i->j-1], i->def->points_x[i->j], i->def->points_y.i[i->j], x); @@ -200,7 +200,7 @@ static float item_get_float(pa_envelope_item *i, pa_usec_t x) { pa_assert(i->j > 0); pa_assert(i->def->points_x[i->j-1] <= x); - pa_assert(x < i->def->points_x[i->j]); + pa_assert(x <= i->def->points_x[i->j]); return linear_interpolate_float(i->def->points_x[i->j-1], i->def->points_y.f[i->j-1], i->def->points_x[i->j], i->def->points_y.f[i->j], x); @@ -550,7 +550,7 @@ static int32_t linear_get_int(pa_envelope *e, int v) { e->points[v].cached_valid = TRUE; } - return e->points[v].y.i[e->points[v].n_current] + (e->points[v].cached_dy_i * (int32_t) (e->x - e->points[v].x[e->points[v].n_current])) / (int32_t) e->points[v].cached_dx; + return e->points[v].y.i[e->points[v].n_current] + ((float)e->points[v].cached_dy_i * (int32_t) (e->x - e->points[v].x[e->points[v].n_current])) / (int32_t) e->points[v].cached_dx; } static float linear_get_float(pa_envelope *e, int v) { @@ -597,34 +597,60 @@ void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) { fs = pa_frame_size(&e->sample_spec); n = chunk->length; + pa_log_debug("Envelop position %d applying factor %d=%f, sample spec is %d, chunk's length is %d, fs is %d\n", e->x, linear_get_int(e, v), ((float) linear_get_int(e,v))/0x10000, e->sample_spec.format, n, fs); + switch (e->sample_spec.format) { case PA_SAMPLE_U8: { - uint8_t *t; + uint8_t *d, *s; + unsigned channel; + int32_t factor = linear_get_int(e, v); - for (t = p; n > 0; n -= fs) { - int32_t factor = linear_get_int(e, v); - unsigned c; - e->x += fs; + s = (uint8_t*) p + n; - for (c = 0; c < e->sample_spec.channels; c++, t++) - *t = (uint8_t) (((factor * ((int16_t) *t - 0x80)) / 0x10000) + 0x80); + for (channel = 0, d = p; d < s; d++) { + int32_t t, hi, lo; + + hi = factor >> 16; + lo = factor & 0xFFFF; + + t = (int32_t) *d - 0x80; + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F); + *d = (uint8_t) (t + 0x80); + + if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) { + channel = 0; + e->x += fs; + factor = linear_get_int(e, v); + } } break; } case PA_SAMPLE_ULAW: { - uint8_t *t; + uint8_t *d, *s; + unsigned channel; + int32_t factor = linear_get_int(e, v); - for (t = p; n > 0; n -= fs) { - int32_t factor = linear_get_int(e, v); - unsigned c; - e->x += fs; + s = (uint8_t*) p + n; - for (c = 0; c < e->sample_spec.channels; c++, t++) { - int16_t k = st_ulaw2linear16(*t); - *t = (uint8_t) st_14linear2ulaw((int16_t) (((factor * k) / 0x10000) >> 2)); + for (channel = 0, d = p; d < s; d++) { + int32_t t, hi, lo; + + hi = factor >> 16; + lo = factor & 0xFFFF; + + t = (int32_t) st_ulaw2linear16(*d); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *d = (uint8_t) st_14linear2ulaw((int16_t) t >> 2); + + if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) { + channel = 0; + e->x += fs; + factor = linear_get_int(e, v); } } @@ -632,16 +658,27 @@ void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) { } case PA_SAMPLE_ALAW: { - uint8_t *t; + uint8_t *d, *s; + unsigned channel; + int32_t factor = linear_get_int(e, v); - for (t = p; n > 0; n -= fs) { - int32_t factor = linear_get_int(e, v); - unsigned c; - e->x += fs; + s = (uint8_t*) p + n; - for (c = 0; c < e->sample_spec.channels; c++, t++) { - int16_t k = st_alaw2linear16(*t); - *t = (uint8_t) st_13linear2alaw((int16_t) (((factor * k) / 0x10000) >> 3)); + for (channel = 0, d = p; d < s; d++) { + int32_t t, hi, lo; + + hi = factor >> 16; + lo = factor & 0xFFFF; + + t = (int32_t) st_alaw2linear16(*d); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *d = (uint8_t) st_13linear2alaw((int16_t) t >> 3); + + if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) { + channel = 0; + e->x += fs; + factor = linear_get_int(e, v); } } @@ -649,31 +686,55 @@ void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) { } case PA_SAMPLE_S16NE: { - int16_t *t; + int16_t *d, *s; + unsigned channel; + int32_t factor = linear_get_int(e, v); - for (t = p; n > 0; n -= fs) { - int32_t factor = linear_get_int(e, v); - unsigned c; - e->x += fs; + s = (int16_t*) p + n/sizeof(int16_t); - for (c = 0; c < e->sample_spec.channels; c++, t++) - *t = (int16_t) ((factor * *t) / 0x10000); + for (channel = 0, d = p; d < s; d++) { + int32_t t, hi, lo; + + hi = factor >> 16; + lo = factor & 0xFFFF; + + t = (int32_t)(*d); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *d = (int16_t) t; + + if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) { + channel = 0; + e->x += fs; + factor = linear_get_int(e, v); + } } break; } case PA_SAMPLE_S16RE: { - int16_t *t; + int16_t *d, *s; + unsigned channel; + int32_t factor = linear_get_int(e, v); - for (t = p; n > 0; n -= fs) { - int32_t factor = linear_get_int(e, v); - unsigned c; - e->x += fs; + s = (int16_t*) p + n/sizeof(int16_t); - for (c = 0; c < e->sample_spec.channels; c++, t++) { - int16_t r = (int16_t) ((factor * PA_INT16_SWAP(*t)) / 0x10000); - *t = PA_INT16_SWAP(r); + for (channel = 0, d = p; d < s; d++) { + int32_t t, hi, lo; + + hi = factor >> 16; + lo = factor & 0xFFFF; + + t = (int32_t) PA_INT16_SWAP(*d); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *d = PA_INT16_SWAP((int16_t) t); + + if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) { + channel = 0; + e->x += fs; + factor = linear_get_int(e, v); } } @@ -681,31 +742,49 @@ void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) { } case PA_SAMPLE_S32NE: { - int32_t *t; + int32_t *d, *s; + unsigned channel; + int32_t factor = linear_get_int(e, v); - for (t = p; n > 0; n -= fs) { - int32_t factor = linear_get_int(e, v); - unsigned c; - e->x += fs; + s = (int32_t*) p + n/sizeof(int32_t); - for (c = 0; c < e->sample_spec.channels; c++, t++) - *t = (int32_t) (((int64_t) factor * (int64_t) *t) / 0x10000); + for (channel = 0, d = p; d < s; d++) { + int64_t t; + + t = (int64_t)(*d); + t = (t * factor) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *d = (int32_t) t; + + if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) { + channel = 0; + e->x += fs; + factor = linear_get_int(e, v); + } } break; } case PA_SAMPLE_S32RE: { - int32_t *t; + int32_t *d, *s; + unsigned channel; + int32_t factor = linear_get_int(e, v); - for (t = p; n > 0; n -= fs) { - int32_t factor = linear_get_int(e, v); - unsigned c; - e->x += fs; + s = (int32_t*) p + n/sizeof(int32_t); - for (c = 0; c < e->sample_spec.channels; c++, t++) { - int32_t r = (int32_t) (((int64_t) factor * (int64_t) PA_INT32_SWAP(*t)) / 0x10000); - *t = PA_INT32_SWAP(r); + for (channel = 0, d = p; d < s; d++) { + int64_t t; + + t = (int64_t) PA_INT32_SWAP(*d); + t = (t * factor) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *d = PA_INT32_SWAP((int32_t) t); + + if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) { + channel = 0; + e->x += fs; + factor = linear_get_int(e, v); } } @@ -713,6 +792,7 @@ void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) { } case PA_SAMPLE_FLOAT32NE: { + /*Seems the FLOAT32NE part of pa_volume_memchunk not right, do not reuse here*/ float *t; for (t = p; n > 0; n -= fs) { @@ -728,6 +808,7 @@ void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) { } case PA_SAMPLE_FLOAT32RE: { + /*Seems the FLOAT32RE part of pa_volume_memchunk not right, do not reuse here*/ float *t; for (t = p; n > 0; n -= fs) { @@ -744,10 +825,101 @@ void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) { break; } - case PA_SAMPLE_S24LE: - case PA_SAMPLE_S24BE: - case PA_SAMPLE_S24_32LE: - case PA_SAMPLE_S24_32BE: + case PA_SAMPLE_S24NE: { + uint8_t *d, *s; + unsigned channel; + int32_t factor = linear_get_int(e, v); + + s = (uint8_t*) p + n/3; + + for (channel = 0, d = p; d < s; d++) { + int64_t t; + + t = (int64_t)((int32_t) (PA_READ24NE(d) << 8)); + t = (t * factor) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + PA_WRITE24NE(d, ((uint32_t) (int32_t) t) >> 8); + + if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) { + channel = 0; + e->x += fs; + factor = linear_get_int(e, v); + } + } + + break; + } + case PA_SAMPLE_S24RE: { + uint8_t *d, *s; + unsigned channel; + int32_t factor = linear_get_int(e, v); + + s = (uint8_t*) p + n/3; + + for (channel = 0, d = p; d < s; d++) { + int64_t t; + + t = (int64_t)((int32_t) (PA_READ24RE(d) << 8)); + t = (t * factor) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + PA_WRITE24RE(d, ((uint32_t) (int32_t) t) >> 8); + + if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) { + channel = 0; + e->x += fs; + factor = linear_get_int(e, v); + } + } + + break; + } + case PA_SAMPLE_S24_32NE: { + uint32_t *d, *s; + unsigned channel; + int32_t factor = linear_get_int(e, v); + + s = (uint32_t*) p + n/sizeof(uint32_t); + + for (channel = 0, d = p; d < s; d++) { + int64_t t; + + t = (int64_t) ((int32_t) (*d << 8)); + t = (t * factor) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *d = ((uint32_t) ((int32_t) t)) >> 8; + + if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) { + channel = 0; + e->x += fs; + factor = linear_get_int(e, v); + } + } + + break; + } + case PA_SAMPLE_S24_32RE: { + uint32_t *d, *s; + unsigned channel; + int32_t factor = linear_get_int(e, v); + + s = (uint32_t*) p + n/sizeof(uint32_t); + + for (channel = 0, d = p; d < s; d++) { + int64_t t; + + t = (int64_t) ((int32_t) (PA_UINT32_SWAP(*d) << 8)); + t = (t * factor) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *d = PA_UINT32_SWAP(((uint32_t) ((int32_t) t)) >> 8); + + if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) { + channel = 0; + e->x += fs; + factor = linear_get_int(e, v); + } + } + break; + } /* FIXME */ pa_assert_not_reached(); @@ -757,8 +929,6 @@ void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) { } pa_memblock_release(chunk->memblock); - - e->x += chunk->length; } else { /* When we have no envelope to apply we reset our origin */ e->x = 0; @@ -774,13 +944,48 @@ void pa_envelope_rewind(pa_envelope *e, size_t n_bytes) { envelope_begin_read(e, &v); - if (n_bytes < e->x) - e->x -= n_bytes; + if (e->x - n_bytes <= e->points[v].x[0]) + e->x = e->points[v].x[0]; else - e->x = 0; + e->x -= n_bytes; e->points[v].n_current = 0; e->points[v].cached_valid = FALSE; envelope_commit_read(e, v); } + +void pa_envelope_restart(pa_envelope* e) { + int v; + pa_assert(e); + + envelope_begin_read(e, &v); + e->x = e->points[v].x[0]; + envelope_commit_read(e, v); +} + +pa_bool_t pa_envelope_is_finished(pa_envelope* e) { + pa_assert(e); + + int v; + pa_bool_t finished; + + envelope_begin_read(e, &v); + finished = (e->x >= e->points[v].x[e->points[v].n_points-1]); + envelope_commit_read(e, v); + + return finished; +} + +int32_t pa_envelope_length(pa_envelope *e) { + pa_assert(e); + + int v; + size_t size; + + envelope_begin_read(e, &v); + size = e->points[v].x[e->points[v].n_points-1] - e->points[v].x[0]; + envelope_commit_read(e, v); + + return size; +} diff --git a/src/pulsecore/envelope.h b/src/pulsecore/envelope.h index 5296415a..4fa36579 100644 --- a/src/pulsecore/envelope.h +++ b/src/pulsecore/envelope.h @@ -49,5 +49,8 @@ pa_envelope_item *pa_envelope_replace(pa_envelope *e, pa_envelope_item *i, const void pa_envelope_remove(pa_envelope *e, pa_envelope_item *i); void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk); void pa_envelope_rewind(pa_envelope *e, size_t n_bytes); +void pa_envelope_restart(pa_envelope* e); +pa_bool_t pa_envelope_is_finished(pa_envelope* e); +int32_t pa_envelope_length(pa_envelope *e); #endif diff --git a/src/pulsecore/fdsem.c b/src/pulsecore/fdsem.c index 380f34f5..ea14e8a7 100644 --- a/src/pulsecore/fdsem.c +++ b/src/pulsecore/fdsem.c @@ -62,19 +62,15 @@ pa_fdsem *pa_fdsem_new(void) { f = pa_xmalloc(PA_ALIGN(sizeof(pa_fdsem)) + PA_ALIGN(sizeof(pa_fdsem_data))); #ifdef HAVE_SYS_EVENTFD_H - if ((f->efd = eventfd(0, 0)) >= 0) { - pa_make_fd_cloexec(f->efd); + if ((f->efd = eventfd(0, EFD_CLOEXEC)) >= 0) f->fds[0] = f->fds[1] = -1; - } else + else #endif { - if (pipe(f->fds) < 0) { + if (pa_pipe_cloexec(f->fds) < 0) { pa_xfree(f); return NULL; } - - pa_make_fd_cloexec(f->fds[0]); - pa_make_fd_cloexec(f->fds[1]); } f->data = (pa_fdsem_data*) ((uint8_t*) f + PA_ALIGN(sizeof(pa_fdsem))); @@ -114,12 +110,11 @@ pa_fdsem *pa_fdsem_new_shm(pa_fdsem_data *data, int* event_fd) { f = pa_xnew(pa_fdsem, 1); - if ((f->efd = eventfd(0, 0)) < 0) { + if ((f->efd = eventfd(0, EFD_CLOEXEC)) < 0) { pa_xfree(f); return NULL; } - pa_make_fd_cloexec(f->efd); f->fds[0] = f->fds[1] = -1; f->data = data; diff --git a/src/pulsecore/lock-autospawn.c b/src/pulsecore/lock-autospawn.c index c0df7938..65e35634 100644 --- a/src/pulsecore/lock-autospawn.c +++ b/src/pulsecore/lock-autospawn.c @@ -87,12 +87,9 @@ static int ref(void) { pa_assert(pipe_fd[0] < 0); pa_assert(pipe_fd[1] < 0); - if (pipe(pipe_fd) < 0) + if (pa_pipe_cloexec(pipe_fd) < 0) return -1; - pa_make_fd_cloexec(pipe_fd[0]); - pa_make_fd_cloexec(pipe_fd[1]); - pa_make_fd_nonblock(pipe_fd[1]); pa_make_fd_nonblock(pipe_fd[0]); diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index eac4a59b..f38b17c6 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -54,7 +54,7 @@ * stored in SHM and our OS does not commit the memory before we use * it for the first time. */ #define PA_MEMPOOL_SLOTS_MAX 1024 -#define PA_MEMPOOL_SLOT_SIZE (128*1024) +#define PA_MEMPOOL_SLOT_SIZE (64*1024) #define PA_MEMEXPORT_SLOTS_MAX 128 diff --git a/src/pulsecore/pid.c b/src/pulsecore/pid.c index 996946c2..213e7983 100644 --- a/src/pulsecore/pid.c +++ b/src/pulsecore/pid.c @@ -88,10 +88,7 @@ static int open_pid_file(const char *fn, int mode) { for (;;) { struct stat st; - if ((fd = open(fn, mode -#ifdef O_NOCTTY - |O_NOCTTY -#endif + if ((fd = pa_open_cloexec(fn, mode #ifdef O_NOFOLLOW |O_NOFOLLOW #endif @@ -146,7 +143,7 @@ static int proc_name_ours(pid_t pid, const char *procname) { pa_snprintf(bn, sizeof(bn), "/proc/%lu/stat", (unsigned long) pid); - if (!(f = fopen(bn, "r"))) { + if (!(f = pa_fopen_cloexec(bn, "r"))) { pa_log_info("Failed to open %s: %s", bn, pa_cstrerror(errno)); return -1; } else { diff --git a/src/pulsecore/protocol-dbus.c b/src/pulsecore/protocol-dbus.c index 5c1127be..e427bb19 100644 --- a/src/pulsecore/protocol-dbus.c +++ b/src/pulsecore/protocol-dbus.c @@ -958,7 +958,7 @@ pa_client *pa_dbus_protocol_get_client(pa_dbus_protocol *p, DBusConnection *conn void pa_dbus_protocol_add_signal_listener( pa_dbus_protocol *p, DBusConnection *conn, - const char *signal, + const char *signal_name, char **objects, unsigned n_objects) { struct connection_entry *conn_entry; @@ -978,18 +978,18 @@ void pa_dbus_protocol_add_signal_listener( while ((object_path = pa_idxset_steal_first(conn_entry->all_signals_objects, NULL))) pa_xfree(object_path); - if (signal) { + if (signal_name) { conn_entry->listening_for_all_signals = FALSE; /* Replace the old object list with a new one. */ - if ((object_set = pa_hashmap_remove(conn_entry->listening_signals, signal))) + if ((object_set = pa_hashmap_remove(conn_entry->listening_signals, signal_name))) pa_idxset_free(object_set, free_listened_object_name_cb, NULL); object_set = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); for (i = 0; i < n_objects; ++i) pa_idxset_put(object_set, pa_xstrdup(objects[i]), NULL); - pa_hashmap_put(conn_entry->listening_signals, signal, object_set); + pa_hashmap_put(conn_entry->listening_signals, signal_name, object_set); } else { conn_entry->listening_for_all_signals = TRUE; @@ -1004,7 +1004,7 @@ void pa_dbus_protocol_add_signal_listener( } } -void pa_dbus_protocol_remove_signal_listener(pa_dbus_protocol *p, DBusConnection *conn, const char *signal) { +void pa_dbus_protocol_remove_signal_listener(pa_dbus_protocol *p, DBusConnection *conn, const char *signal_name) { struct connection_entry *conn_entry; pa_idxset *object_set; @@ -1013,8 +1013,8 @@ void pa_dbus_protocol_remove_signal_listener(pa_dbus_protocol *p, DBusConnection pa_assert_se((conn_entry = pa_hashmap_get(p->connections, conn))); - if (signal) { - if ((object_set = pa_hashmap_get(conn_entry->listening_signals, signal))) + if (signal_name) { + if ((object_set = pa_hashmap_get(conn_entry->listening_signals, signal_name))) pa_idxset_free(object_set, free_listened_object_name_cb, NULL); } else { @@ -1030,7 +1030,7 @@ void pa_dbus_protocol_remove_signal_listener(pa_dbus_protocol *p, DBusConnection } } -void pa_dbus_protocol_send_signal(pa_dbus_protocol *p, DBusMessage *signal) { +void pa_dbus_protocol_send_signal(pa_dbus_protocol *p, DBusMessage *signal_name) { struct connection_entry *conn_entry; void *state = NULL; pa_idxset *object_set; @@ -1038,24 +1038,24 @@ void pa_dbus_protocol_send_signal(pa_dbus_protocol *p, DBusMessage *signal) { char *signal_string; pa_assert(p); - pa_assert(signal); - pa_assert(dbus_message_get_type(signal) == DBUS_MESSAGE_TYPE_SIGNAL); - pa_assert_se(dbus_message_get_interface(signal)); - pa_assert_se(dbus_message_get_member(signal)); + pa_assert(signal_name); + pa_assert(dbus_message_get_type(signal_name) == DBUS_MESSAGE_TYPE_SIGNAL); + pa_assert_se(dbus_message_get_interface(signal_name)); + pa_assert_se(dbus_message_get_member(signal_name)); - signal_string = pa_sprintf_malloc("%s.%s", dbus_message_get_interface(signal), dbus_message_get_member(signal)); + signal_string = pa_sprintf_malloc("%s.%s", dbus_message_get_interface(signal_name), dbus_message_get_member(signal_name)); PA_HASHMAP_FOREACH(conn_entry, p->connections, state) { if ((conn_entry->listening_for_all_signals /* Case 1: listening for all signals */ - && (pa_idxset_get_by_data(conn_entry->all_signals_objects, dbus_message_get_path(signal), NULL) + && (pa_idxset_get_by_data(conn_entry->all_signals_objects, dbus_message_get_path(signal_name), NULL) || pa_idxset_isempty(conn_entry->all_signals_objects))) || (!conn_entry->listening_for_all_signals /* Case 2: not listening for all signals */ && (object_set = pa_hashmap_get(conn_entry->listening_signals, signal_string)) - && (pa_idxset_get_by_data(object_set, dbus_message_get_path(signal), NULL) + && (pa_idxset_get_by_data(object_set, dbus_message_get_path(signal_name), NULL) || pa_idxset_isempty(object_set)))) { - pa_assert_se(signal_copy = dbus_message_copy(signal)); + pa_assert_se(signal_copy = dbus_message_copy(signal_name)); pa_assert_se(dbus_connection_send(conn_entry->connection, signal_copy, NULL)); dbus_message_unref(signal_copy); } diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index d06dd4eb..d49a78e5 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -1002,6 +1002,7 @@ static playback_stream* playback_stream_new( pa_proplist *p, pa_bool_t adjust_latency, pa_bool_t early_requests, + pa_bool_t relative_volume, int *ret) { playback_stream *s, *ssync; @@ -1044,13 +1045,21 @@ static playback_stream* playback_stream_new( data.driver = __FILE__; data.module = c->options->module; data.client = c->client; - data.sink = sink; + if (sink) { + data.sink = sink; + data.save_sink = TRUE; + } pa_sink_input_new_data_set_sample_spec(&data, ss); pa_sink_input_new_data_set_channel_map(&data, map); - if (volume) + if (volume) { pa_sink_input_new_data_set_volume(&data, volume); - if (muted_set) + data.volume_is_absolute = !relative_volume; + data.save_volume = TRUE; + } + if (muted_set) { pa_sink_input_new_data_set_muted(&data, muted); + data.save_muted = TRUE; + } data.sync_base = ssync ? ssync->sink_input : NULL; data.flags = flags; @@ -1838,7 +1847,8 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u early_requests = FALSE, dont_inhibit_auto_suspend = FALSE, muted_set = FALSE, - fail_on_suspend = FALSE; + fail_on_suspend = FALSE, + relative_volume = FALSE; pa_sink_input_flags_t flags = 0; pa_proplist *p; pa_bool_t volume_set = TRUE; @@ -1931,6 +1941,15 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u } } + if (c->version >= 17) { + + if (pa_tagstruct_get_boolean(t, &relative_volume) < 0) { + protocol_error(c); + pa_proplist_free(p); + return; + } + } + if (!pa_tagstruct_eof(t)) { protocol_error(c); pa_proplist_free(p); @@ -1970,7 +1989,7 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u * flag. For older versions we synthesize it here */ muted_set = muted_set || muted; - s = playback_stream_new(c, sink, &ss, &map, &attr, volume_set ? &volume : NULL, muted, muted_set, syncid, &missing, flags, p, adjust_latency, early_requests, &ret); + s = playback_stream_new(c, sink, &ss, &map, &attr, volume_set ? &volume : NULL, muted, muted_set, syncid, &missing, flags, p, adjust_latency, early_requests, relative_volume, &ret); pa_proplist_free(p); CHECK_VALIDITY(c->pstream, s, tag, ret); @@ -2612,7 +2631,7 @@ static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint3 pa_tagstruct_put_usec(reply, s->current_monitor_latency); pa_tagstruct_put_usec(reply, s->current_source_latency + - pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->sample_spec)); + pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->source->sample_spec)); pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING && pa_source_output_get_state(s->source_output) == PA_SOURCE_OUTPUT_RUNNING); diff --git a/src/pulsecore/random.c b/src/pulsecore/random.c index 518c281a..a87d24e3 100644 --- a/src/pulsecore/random.c +++ b/src/pulsecore/random.c @@ -62,11 +62,7 @@ static int random_proper(void *ret_data, size_t length) { while (*device) { ret = 0; - if ((fd = open(*device, O_RDONLY -#ifdef O_NOCTTY - | O_NOCTTY -#endif - )) >= 0) { + if ((fd = pa_open_cloexec(*device, O_RDONLY, 0)) >= 0) { if ((r = pa_loop_read(fd, ret_data, length, NULL)) < 0 || (size_t) r != length) ret = -1; diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index a26dc876..74600dec 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -1007,7 +1007,7 @@ void pa_memchunk_dump_to_file(pa_memchunk *c, const char *fn) { /* Only for debugging purposes */ - f = fopen(fn, "a"); + f = pa_fopen_cloexec(fn, "a"); if (!f) { pa_log_warn("Failed to open '%s': %s", fn, pa_cstrerror(errno)); diff --git a/src/pulsecore/semaphore-osx.c b/src/pulsecore/semaphore-osx.c new file mode 100644 index 00000000..73f43559 --- /dev/null +++ b/src/pulsecore/semaphore-osx.c @@ -0,0 +1,63 @@ +/*** + This file is part of PulseAudio. + + Copyright 2009 Kim Lester <kim@dfusion.com.au> + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Multiprocessing.h> + +#include <pulse/xmalloc.h> +#include <pulsecore/macro.h> + +#include "semaphore.h" + +struct pa_semaphore +{ + MPSemaphoreID sema; +}; + +pa_semaphore* pa_semaphore_new(unsigned int value) { + /* NOTE: Can't assume boolean - ie value = 0,1, so use UINT_MAX (boolean more efficient ?) */ + pa_semaphore *s; + + s = pa_xnew(pa_semaphore, 1); + pa_assert_se(MPCreateSemaphore(UINT_MAX, value, &s->sema) == 0); + + return s; +} + +void pa_semaphore_free(pa_semaphore *s) { + pa_assert(s); + pa_assert_se(MPDeleteSemaphore(s->sema) == 0); + pa_xfree(s); +} + +void pa_semaphore_post(pa_semaphore *s) { + pa_assert(s); + pa_assert_se(MPSignalSemaphore(s->sema) == 0); +} + +void pa_semaphore_wait(pa_semaphore *s) { + pa_assert(s); + /* should probably check return value (-ve is error), noErr is ok. */ + pa_assert_se(MPWaitOnSemaphore(s->sema, kDurationForever) == 0); +} diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 1af2823f..35e3d4a9 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -38,6 +38,7 @@ #include <pulsecore/play-memblockq.h> #include <pulsecore/namereg.h> #include <pulsecore/core-util.h> +#include <pulse/timeval.h> #include "sink-input.h" @@ -48,6 +49,11 @@ PA_DEFINE_PUBLIC_CLASS(pa_sink_input, pa_msgobject); static void sink_input_free(pa_object *o); static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v); +static void sink_input_set_ramping_info(pa_sink_input* i, pa_volume_t pre_virtual_volume, pa_volume_t target_virtual_volume, pa_usec_t t); +static void sink_input_set_ramping_info_for_mute(pa_sink_input* i, pa_bool_t mute, pa_usec_t t); +static void sink_input_volume_ramping(pa_sink_input* i, pa_memchunk* chunk); +static void sink_input_rewind_ramp_info(pa_sink_input *i, size_t nbytes); +static void sink_input_release_envelope(pa_sink_input *i); pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data) { pa_assert(data); @@ -323,6 +329,16 @@ int pa_sink_input_new( reset_callbacks(i); i->userdata = NULL; + /* Set Ramping info */ + i->thread_info.ramp_info.is_ramping = FALSE; + i->thread_info.ramp_info.envelope_dead = TRUE; + i->thread_info.ramp_info.envelope = NULL; + i->thread_info.ramp_info.item = NULL; + i->thread_info.ramp_info.envelope_dying = 0; + + pa_atomic_store(&i->before_ramping_v, 0); + pa_atomic_store(&i->before_ramping_m, 0); + i->thread_info.state = i->state; i->thread_info.attached = FALSE; pa_atomic_store(&i->thread_info.drained, 1); @@ -510,6 +526,12 @@ static void sink_input_free(pa_object *o) { * "half-moved" or are connected to sinks that have no asyncmsgq * and are hence half-destructed themselves! */ + if (i->thread_info.ramp_info.envelope) { + pa_log_debug ("Freeing envelope\n"); + pa_envelope_free(i->thread_info.ramp_info.envelope); + i->thread_info.ramp_info.envelope = NULL; + } + if (i->thread_info.render_memblockq) pa_memblockq_free(i->thread_info.render_memblockq); @@ -597,6 +619,7 @@ pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency) { void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, pa_memchunk *chunk, pa_cvolume *volume) { pa_bool_t do_volume_adj_here, need_volume_factor_sink; pa_bool_t volume_is_norm; + pa_bool_t ramping; size_t block_size_max_sink, block_size_max_sink_input; size_t ilength; @@ -641,7 +664,7 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p * to adjust the volume *before* we resample. Otherwise we can do * it after and leave it for the sink code */ - do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map); + do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map) || i->thread_info.ramp_info.is_ramping; volume_is_norm = pa_cvolume_is_norm(&i->thread_info.soft_volume) && !i->thread_info.muted; need_volume_factor_sink = !pa_cvolume_is_norm(&i->volume_factor_sink); @@ -684,7 +707,7 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p wchunk.length = block_size_max_sink_input; /* It might be necessary to adjust the volume here */ - if (do_volume_adj_here && !volume_is_norm) { + if (do_volume_adj_here && !volume_is_norm && !i->thread_info.ramp_info.is_ramping) { pa_memchunk_make_writable(&wchunk, 0); if (i->thread_info.muted) { @@ -717,14 +740,15 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p pa_memchunk rchunk; pa_resampler_run(i->thread_info.resampler, &wchunk, &rchunk); - if (nvfs) { - pa_memchunk_make_writable(&rchunk, 0); - pa_volume_memchunk(&rchunk, &i->sink->sample_spec, &i->volume_factor_sink); - } - /* pa_log_debug("pushing %lu", (unsigned long) rchunk.length); */ if (rchunk.memblock) { + + if (nvfs) { + pa_memchunk_make_writable(&rchunk, 0); + pa_volume_memchunk(&rchunk, &i->sink->sample_spec, &i->volume_factor_sink); + } + pa_memblockq_push_align(i->thread_info.render_memblockq, &rchunk); pa_memblock_unref(rchunk.memblock); } @@ -749,6 +773,23 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p if (chunk->length > block_size_max_sink) chunk->length = block_size_max_sink; + ramping = i->thread_info.ramp_info.is_ramping; + if (ramping) + sink_input_volume_ramping(i, chunk); + + if (!i->thread_info.ramp_info.envelope_dead) { + i->thread_info.ramp_info.envelope_dying += chunk->length; + pa_log_debug("Envelope dying is %d, chunk length is %d, dead thresholder is %d\n", i->thread_info.ramp_info.envelope_dying, + chunk->length, + i->sink->thread_info.max_rewind + pa_envelope_length(i->thread_info.ramp_info.envelope)); + + if (i->thread_info.ramp_info.envelope_dying >= (i->sink->thread_info.max_rewind + pa_envelope_length(i->thread_info.ramp_info.envelope))) { + pa_log_debug("RELEASE Envelop"); + i->thread_info.ramp_info.envelope_dead = TRUE; + sink_input_release_envelope(i); + } + } + /* Let's see if we had to apply the volume adjustment ourselves, * or if this can be done by the sink for us */ @@ -793,6 +834,7 @@ void pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in sink sam if (nbytes > 0 && !i->thread_info.dont_rewind_render) { pa_log_debug("Have to rewind %lu bytes on render memblockq.", (unsigned long) nbytes); pa_memblockq_rewind(i->thread_info.render_memblockq, nbytes); + sink_input_rewind_ramp_info(i, nbytes); } if (i->thread_info.rewrite_nbytes == (size_t) -1) { @@ -978,59 +1020,8 @@ static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v) { /* Called from main context */ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute) { - pa_cvolume v; - - pa_sink_input_assert_ref(i); - pa_assert_ctl_context(); - pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); - pa_assert(volume); - pa_assert(pa_cvolume_valid(volume)); - pa_assert(volume->channels == 1 || pa_cvolume_compatible(volume, &i->sample_spec)); - - if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) { - v = i->sink->reference_volume; - pa_cvolume_remap(&v, &i->sink->channel_map, &i->channel_map); - - if (pa_cvolume_compatible(volume, &i->sample_spec)) - volume = pa_sw_cvolume_multiply(&v, &v, volume); - else - volume = pa_sw_cvolume_multiply_scalar(&v, &v, pa_cvolume_max(volume)); - } else { - - if (!pa_cvolume_compatible(volume, &i->sample_spec)) { - v = i->volume; - volume = pa_cvolume_scale(&v, pa_cvolume_max(volume)); - } - } - - if (pa_cvolume_equal(volume, &i->volume)) { - i->save_volume = i->save_volume || save; - return; - } - - i->volume = *volume; - i->save_volume = save; - - if (i->sink->flags & PA_SINK_FLAT_VOLUME) - /* We are in flat volume mode, so let's update all sink input - * volumes and update the flat volume of the sink */ - - pa_sink_set_volume(i->sink, NULL, TRUE, save); - - else { - /* OK, we are in normal volume mode. The volume only affects - * ourselves */ - set_real_ratio(i, volume); - - /* Copy the new soft_volume to the thread_info struct */ - pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME, NULL, 0, NULL) == 0); - } - - /* The volume changed, let's tell people so */ - if (i->volume_changed) - i->volume_changed(i); - - pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); + /* test ramping -> return pa_sink_input_set_volume_with_ramping(i, volume, save, absolute, 2000 * PA_USEC_PER_MSEC); */ + return pa_sink_input_set_volume_with_ramping(i, volume, save, absolute, 0); } /* Called from main context */ @@ -1049,23 +1040,8 @@ pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bo /* Called from main context */ void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save) { - pa_sink_input_assert_ref(i); - pa_assert_ctl_context(); - pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); - - if (!i->muted == !mute) - return; - - i->muted = mute; - i->save_muted = save; - - pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE, NULL, 0, NULL) == 0); - - /* The mute status changed, let's tell people so */ - if (i->mute_changed) - i->mute_changed(i); - - pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); + /* test ramping -> return pa_sink_input_set_mute_with_ramping(i, mute, save, 2000 * PA_USEC_PER_MSEC); */ + return pa_sink_input_set_mute_with_ramping(i, mute, save, 0); } /* Called from main context */ @@ -1441,15 +1417,23 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t switch (code) { case PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME: + if (pa_atomic_load(&i->before_ramping_v)) + i->thread_info.future_soft_volume = i->soft_volume; + if (!pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume)) { - i->thread_info.soft_volume = i->soft_volume; + if (!pa_atomic_load(&i->before_ramping_v)) + i->thread_info.soft_volume = i->soft_volume; pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE); } return 0; case PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE: + if (pa_atomic_load(&i->before_ramping_m)) + i->thread_info.future_muted = i->muted; + if (i->thread_info.muted != i->muted) { - i->thread_info.muted = i->muted; + if (!pa_atomic_load(&i->before_ramping_m)) + i->thread_info.muted = i->muted; pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE); } return 0; @@ -1497,6 +1481,26 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t *r = i->thread_info.requested_sink_latency; return 0; } + + case PA_SINK_INPUT_MESSAGE_SET_ENVELOPE: { + if (!i->thread_info.ramp_info.envelope) + i->thread_info.ramp_info.envelope = pa_envelope_new(&i->sink->sample_spec); + + if (i->thread_info.ramp_info.envelope && i->thread_info.ramp_info.item) { + pa_envelope_remove(i->thread_info.ramp_info.envelope, i->thread_info.ramp_info.item); + i->thread_info.ramp_info.item = NULL; + } + + i->thread_info.ramp_info.item = pa_envelope_add(i->thread_info.ramp_info.envelope, &i->using_def); + i->thread_info.ramp_info.is_ramping = TRUE; + i->thread_info.ramp_info.envelope_dead = FALSE; + i->thread_info.ramp_info.envelope_dying = 0; + + if (i->thread_info.ramp_info.envelope) + pa_envelope_restart(i->thread_info.ramp_info.envelope); + + return 0; + } } return -PA_ERR_NOTIMPLEMENTED; @@ -1659,3 +1663,235 @@ finish: if (pl) pa_proplist_free(pl); } + +/* Called from IO context */ +static void sink_input_volume_ramping(pa_sink_input* i, pa_memchunk* chunk) { + pa_assert(i); + pa_assert(chunk); + pa_assert(chunk->memblock); + pa_assert(i->thread_info.ramp_info.is_ramping); + + /* Volume is adjusted with ramping effect here */ + pa_envelope_apply(i->thread_info.ramp_info.envelope, chunk); + + if (pa_envelope_is_finished(i->thread_info.ramp_info.envelope)) { + i->thread_info.ramp_info.is_ramping = FALSE; + if (pa_atomic_load(&i->before_ramping_v)) { + i->thread_info.soft_volume = i->thread_info.future_soft_volume; + pa_atomic_store(&i->before_ramping_v, 0); + } + else if (pa_atomic_load(&i->before_ramping_m)) { + i->thread_info.muted = i->thread_info.future_muted; + pa_atomic_store(&i->before_ramping_m, 0); + } + } +} + +/* + * Called from main context + * This function should be called inside pa_sink_input_set_volume_with_ramping + * should be called after soft_volume of sink_input and sink are all adjusted + */ +static void sink_input_set_ramping_info(pa_sink_input* i, pa_volume_t pre_virtual_volume, pa_volume_t target_virtual_volume, pa_usec_t t) { + + int32_t target_abs_vol, target_apply_vol, pre_apply_vol; + pa_assert(i); + + pa_log_debug("Sink input's soft volume is %d= %f ", pa_cvolume_avg(&i->soft_volume), pa_sw_volume_to_linear(pa_cvolume_avg(&i->soft_volume))); + + /* Calculation formula are target_abs_vol := i->soft_volume + * target_apply_vol := lrint(pa_sw_volume_to_linear(target_abs_vol) * 0x10000) + * pre_apply_vol := ( previous_virtual_volume / target_virtual_volume ) * target_apply_vol + * + * Will do volume adjustment inside pa_sink_input_peek + */ + target_abs_vol = pa_cvolume_avg(&i->soft_volume); + target_apply_vol = (int32_t) lrint(pa_sw_volume_to_linear(target_abs_vol) * 0x10000); + pre_apply_vol = (int32_t) ((pa_sw_volume_to_linear(pre_virtual_volume) / pa_sw_volume_to_linear(target_virtual_volume)) * target_apply_vol); + + i->using_def.n_points = 2; + i->using_def.points_x[0] = 0; + i->using_def.points_x[1] = t; + i->using_def.points_y.i[0] = pre_apply_vol; + i->using_def.points_y.i[1] = target_apply_vol; + i->using_def.points_y.f[0] = ((float) i->using_def.points_y.i[0]) /0x10000; + i->using_def.points_y.f[1] = ((float) i->using_def.points_y.i[1]) /0x10000; + + pa_log_debug("Volume Ramping: Point 1 is %d=%f, Point 2 is %d=%f\n", i->using_def.points_y.i[0], i->using_def.points_y.f[0], + i->using_def.points_y.i[1], i->using_def.points_y.f[1]); + + pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_ENVELOPE, NULL, 0, NULL) == 0); +} + +/* Called from main context */ +static void sink_input_set_ramping_info_for_mute(pa_sink_input* i, pa_bool_t mute, pa_usec_t t) { + + int32_t cur_vol; + pa_assert(i); + + i->using_def.n_points = 2; + i->using_def.points_x[0] = 0; + i->using_def.points_x[1] = t; + cur_vol = (int32_t) lrint( pa_sw_volume_to_linear(pa_cvolume_avg(&i->soft_volume)) * 0x10000); + + if (mute) { + i->using_def.points_y.i[0] = cur_vol; + i->using_def.points_y.i[1] = 0; + } else { + i->using_def.points_y.i[0] = 0; + i->using_def.points_y.i[1] = cur_vol; + } + + i->using_def.points_y.f[0] = ((float) i->using_def.points_y.i[0]) /0x10000; + i->using_def.points_y.f[1] = ((float) i->using_def.points_y.i[1]) /0x10000; + + pa_log_debug("Mute Ramping: Point 1 is %d=%f, Point 2 is %d=%f\n", i->using_def.points_y.i[0], i->using_def.points_y.f[0], + i->using_def.points_y.i[1], i->using_def.points_y.f[1]); + + pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_ENVELOPE, NULL, 0, NULL) == 0); +} + +/* Called from IO context */ +static void sink_input_release_envelope(pa_sink_input *i) { + pa_assert(i); + pa_assert(!i->thread_info.ramp_info.is_ramping); + pa_assert(i->thread_info.ramp_info.envelope_dead); + + pa_envelope_free(i->thread_info.ramp_info.envelope); + i->thread_info.ramp_info.envelope = NULL; + i->thread_info.ramp_info.item = NULL; +} + +/* Called from IO context */ +static void sink_input_rewind_ramp_info(pa_sink_input *i, size_t nbytes) { + pa_assert(i); + + if (!i->thread_info.ramp_info.envelope_dead) { + pa_assert(i->thread_info.ramp_info.envelope); + + int32_t envelope_length = pa_envelope_length(i->thread_info.ramp_info.envelope); + + if (i->thread_info.ramp_info.envelope_dying > envelope_length) { + if ((i->thread_info.ramp_info.envelope_dying - nbytes) < envelope_length) { + pa_log_debug("Envelope Become Alive"); + pa_envelope_rewind(i->thread_info.ramp_info.envelope, envelope_length - (i->thread_info.ramp_info.envelope_dying - nbytes)); + i->thread_info.ramp_info.is_ramping = TRUE; + } + } else if (i->thread_info.ramp_info.envelope_dying < envelope_length) { + if ((i->thread_info.ramp_info.envelope_dying - nbytes) <= 0) { + pa_log_debug("Envelope Restart"); + pa_envelope_restart(i->thread_info.ramp_info.envelope); + } + else { + pa_log_debug("Envelope Simple Rewind"); + pa_envelope_rewind(i->thread_info.ramp_info.envelope, nbytes); + } + } + + i->thread_info.ramp_info.envelope_dying -= nbytes; + if (i->thread_info.ramp_info.envelope_dying <= 0) + i->thread_info.ramp_info.envelope_dying = 0; + } +} + +void pa_sink_input_set_volume_with_ramping(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute, pa_usec_t t){ + pa_cvolume v; + pa_volume_t previous_virtual_volume, target_virtual_volume; + + pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); + pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); + pa_assert(volume); + pa_assert(pa_cvolume_valid(volume)); + pa_assert(volume->channels == 1 || pa_cvolume_compatible(volume, &i->sample_spec)); + + if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) { + v = i->sink->reference_volume; + pa_cvolume_remap(&v, &i->sink->channel_map, &i->channel_map); + + if (pa_cvolume_compatible(volume, &i->sample_spec)) + volume = pa_sw_cvolume_multiply(&v, &v, volume); + else + volume = pa_sw_cvolume_multiply_scalar(&v, &v, pa_cvolume_max(volume)); + } else { + + if (!pa_cvolume_compatible(volume, &i->sample_spec)) { + v = i->volume; + volume = pa_cvolume_scale(&v, pa_cvolume_max(volume)); + } + } + + if (pa_cvolume_equal(volume, &i->volume)) { + i->save_volume = i->save_volume || save; + return; + } + + previous_virtual_volume = pa_cvolume_avg(&i->volume); + target_virtual_volume = pa_cvolume_avg(volume); + + if (t > 0 && target_virtual_volume > 0) + pa_log_debug("SetVolumeWithRamping: Virtual Volume From %u=%f to %u=%f\n", previous_virtual_volume, pa_sw_volume_to_linear(previous_virtual_volume), + target_virtual_volume, pa_sw_volume_to_linear(target_virtual_volume)); + + i->volume = *volume; + i->save_volume = save; + + /* Set this flag before the following code modify i->thread_info.soft_volume */ + if (t > 0 && target_virtual_volume > 0) + pa_atomic_store(&i->before_ramping_v, 1); + + if (i->sink->flags & PA_SINK_FLAT_VOLUME) { + /* We are in flat volume mode, so let's update all sink input + * volumes and update the flat volume of the sink */ + + pa_sink_set_volume(i->sink, NULL, TRUE, save); + + } else { + /* OK, we are in normal volume mode. The volume only affects + * ourselves */ + set_real_ratio(i, volume); + + /* Copy the new soft_volume to the thread_info struct */ + pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME, NULL, 0, NULL) == 0); + } + + if (t > 0 && target_virtual_volume > 0) + sink_input_set_ramping_info(i, previous_virtual_volume, target_virtual_volume, t); + + /* The volume changed, let's tell people so */ + if (i->volume_changed) + i->volume_changed(i); + + /* The virtual volume changed, let's tell people so */ + pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); +} + +void pa_sink_input_set_mute_with_ramping(pa_sink_input *i, pa_bool_t mute, pa_bool_t save, pa_usec_t t){ + + pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); + pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); + + if (!i->muted == !mute) { + i->save_muted = i->save_muted || mute; + return; + } + + i->muted = mute; + i->save_muted = save; + + /* Set this flag before the following code modify i->thread_info.muted, otherwise distortion will be heard */ + if (t > 0) + pa_atomic_store(&i->before_ramping_m, 1); + + pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE, NULL, 0, NULL) == 0); + + if (t > 0) + sink_input_set_ramping_info_for_mute(i, mute, t); + + /* The mute status changed, let's tell people so */ + if (i->mute_changed) + i->mute_changed(i); + + pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); +} diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 415a801f..56ac3d60 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -35,6 +35,7 @@ typedef struct pa_sink_input pa_sink_input; #include <pulsecore/client.h> #include <pulsecore/sink.h> #include <pulsecore/core.h> +#include <pulsecore/envelope.h> typedef enum pa_sink_input_state { PA_SINK_INPUT_INIT, /*< The stream is not active yet, because pa_sink_put() has not been called yet */ @@ -232,8 +233,23 @@ struct pa_sink_input { pa_usec_t requested_sink_latency; pa_hashmap *direct_outputs; + + struct { + pa_bool_t is_ramping:1; + pa_bool_t envelope_dead:1; + int32_t envelope_dying; /* Increasing while envelop is not dead. Reduce it while process_rewind. */ + pa_envelope *envelope; + pa_envelope_item *item; + } ramp_info; + pa_cvolume future_soft_volume; + pa_bool_t future_muted; + } thread_info; + pa_atomic_t before_ramping_v; /* Indicates future volume */ + pa_atomic_t before_ramping_m; /* Indicates future mute */ + pa_envelope_def using_def; + void *userdata; }; @@ -248,6 +264,7 @@ enum { PA_SINK_INPUT_MESSAGE_SET_STATE, PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY, + PA_SINK_INPUT_MESSAGE_SET_ENVELOPE, PA_SINK_INPUT_MESSAGE_MAX }; @@ -384,4 +401,8 @@ pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret); #define pa_sink_input_assert_io_context(s) \ pa_assert(pa_thread_mq_get() || !PA_SINK_INPUT_IS_LINKED((s)->state)) +/* Volume ramping*/ +void pa_sink_input_set_volume_with_ramping(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute, pa_usec_t t); +void pa_sink_input_set_mute_with_ramping(pa_sink_input *i, pa_bool_t mute, pa_bool_t save, pa_usec_t t); + #endif diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index bda92fcc..24fad34d 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -926,18 +926,16 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume); - if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) { - 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 { - pa_memchunk_make_writable(result, 0); - pa_volume_memchunk(result, &s->sample_spec, &volume); - } + 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); } } else { void *ptr; @@ -1342,7 +1340,7 @@ static void propagate_reference_volume(pa_sink *s) { void pa_sink_set_volume( pa_sink *s, const pa_cvolume *volume, - pa_bool_t sendmsg, + pa_bool_t send_msg, pa_bool_t save) { pa_cvolume old_reference_volume; @@ -1411,7 +1409,7 @@ void pa_sink_set_volume( s->soft_volume = s->real_volume; /* This tells the sink that soft and/or virtual volume changed */ - if (sendmsg) + if (send_msg) pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0); if (reference_changed) @@ -1733,10 +1731,14 @@ static void sync_input_volumes_within_thread(pa_sink *s) { pa_sink_assert_io_context(s); PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) { + if (pa_atomic_load(&i->before_ramping_v)) + i->thread_info.future_soft_volume = i->soft_volume; + if (pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume)) continue; - i->thread_info.soft_volume = i->soft_volume; + if (!pa_atomic_load(&i->before_ramping_v)) + i->thread_info.soft_volume = i->soft_volume; pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE); } } diff --git a/src/pulsecore/socket-client.c b/src/pulsecore/socket-client.c index b9d69505..ef3c29ee 100644 --- a/src/pulsecore/socket-client.c +++ b/src/pulsecore/socket-client.c @@ -257,13 +257,11 @@ static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size c->local = pa_socket_address_is_local(sa); - if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) { + if ((c->fd = pa_socket_cloexec(sa->sa_family, SOCK_STREAM, 0)) < 0) { pa_log("socket(): %s", pa_cstrerror(errno)); return -1; } - pa_make_fd_cloexec(c->fd); - #ifdef HAVE_IPV6 if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) #else diff --git a/src/pulsecore/socket-server.c b/src/pulsecore/socket-server.c index e660700c..5d55de3e 100644 --- a/src/pulsecore/socket-server.c +++ b/src/pulsecore/socket-server.c @@ -104,13 +104,11 @@ static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, pa_io_ev pa_socket_server_ref(s); - if ((nfd = accept(fd, NULL, NULL)) < 0) { + if ((nfd = pa_accept_cloexec(fd, NULL, NULL)) < 0) { pa_log("accept(): %s", pa_cstrerror(errno)); goto finish; } - pa_make_fd_cloexec(nfd); - if (!s->on_connection) { pa_close(nfd); goto finish; @@ -186,13 +184,11 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file pa_assert(m); pa_assert(filename); - if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + if ((fd = pa_socket_cloexec(PF_UNIX, SOCK_STREAM, 0)) < 0) { pa_log("socket(): %s", pa_cstrerror(errno)); goto fail; } - pa_make_fd_cloexec(fd); - memset(&sa, 0, sizeof(sa)); sa.sun_family = AF_UNIX; pa_strlcpy(sa.sun_path, filename, sizeof(sa.sun_path)); @@ -246,13 +242,11 @@ pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address pa_assert(m); pa_assert(port); - if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { + if ((fd = pa_socket_cloexec(PF_INET, SOCK_STREAM, 0)) < 0) { pa_log("socket(PF_INET): %s", pa_cstrerror(errno)); goto fail; } - pa_make_fd_cloexec(fd); - #ifdef SO_REUSEADDR if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) pa_log("setsockopt(): %s", pa_cstrerror(errno)); @@ -299,13 +293,11 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad pa_assert(m); pa_assert(port > 0); - if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) { + if ((fd = pa_socket_cloexec(PF_INET6, SOCK_STREAM, 0)) < 0) { pa_log("socket(PF_INET6): %s", pa_cstrerror(errno)); goto fail; } - pa_make_fd_cloexec(fd); - #ifdef IPV6_V6ONLY on = 1; if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) diff --git a/src/pulsecore/socket-util.c b/src/pulsecore/socket-util.c index 5fd5dd67..2cc9882a 100644 --- a/src/pulsecore/socket-util.c +++ b/src/pulsecore/socket-util.c @@ -85,12 +85,11 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) { #ifndef OS_IS_WIN32 pa_assert_se(fstat(fd, &st) == 0); -#endif -#ifndef OS_IS_WIN32 if (S_ISSOCK(st.st_mode)) { #endif union { + struct sockaddr_storage storage; struct sockaddr sa; struct sockaddr_in in; #ifdef HAVE_IPV6 @@ -152,7 +151,7 @@ void pa_make_socket_low_delay(int fd) { pa_assert(fd >= 0); priority = 6; - if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (void*)&priority, sizeof(priority)) < 0) + if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) pa_log_warn("SO_PRIORITY failed: %s", pa_cstrerror(errno)); #endif } @@ -166,9 +165,9 @@ void pa_make_tcp_socket_low_delay(int fd) { { int on = 1; #if defined(SOL_TCP) - if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0) + if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) #else - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0) + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) #endif pa_log_warn("TCP_NODELAY failed: %s", pa_cstrerror(errno)); } @@ -178,9 +177,9 @@ void pa_make_tcp_socket_low_delay(int fd) { { int tos = IPTOS_LOWDELAY; #ifdef SOL_IP - if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) + if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0) #else - if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) + if (setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) #endif pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno)); } @@ -196,9 +195,9 @@ void pa_make_udp_socket_low_delay(int fd) { { int tos = IPTOS_LOWDELAY; #ifdef SOL_IP - if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) + if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0) #else - if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) + if (setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) #endif pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno)); } @@ -206,11 +205,11 @@ void pa_make_udp_socket_low_delay(int fd) { } int pa_socket_set_rcvbuf(int fd, size_t l) { - int bufsz = (int)l; + int bufsz = (int) l; pa_assert(fd >= 0); - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&bufsz, sizeof(bufsz)) < 0) { + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsz, sizeof(bufsz)) < 0) { pa_log_warn("SO_RCVBUF: %s", pa_cstrerror(errno)); return -1; } @@ -219,12 +218,12 @@ int pa_socket_set_rcvbuf(int fd, size_t l) { } int pa_socket_set_sndbuf(int fd, size_t l) { - int bufsz = (int)l; + int bufsz = (int) l; pa_assert(fd >= 0); - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&bufsz, sizeof(bufsz)) < 0) { - pa_log("SO_SNDBUF: %s", pa_cstrerror(errno)); + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bufsz, sizeof(bufsz)) < 0) { + pa_log_warn("SO_SNDBUF: %s", pa_cstrerror(errno)); return -1; } @@ -239,7 +238,7 @@ int pa_unix_socket_is_stale(const char *fn) { pa_assert(fn); - if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + if ((fd = pa_socket_cloexec(PF_UNIX, SOCK_STREAM, 0)) < 0) { pa_log("socket(): %s", pa_cstrerror(errno)); goto finish; } @@ -315,6 +314,7 @@ pa_bool_t pa_socket_address_is_local(const struct sockaddr *sa) { pa_bool_t pa_socket_is_local(int fd) { union { + struct sockaddr_storage storage; struct sockaddr sa; struct sockaddr_in in; #ifdef HAVE_IPV6 diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index 16de4923..53674ba1 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -252,11 +252,7 @@ int pa_play_file( u->readf_function = NULL; u->memblockq = NULL; - if ((fd = open(fname, O_RDONLY -#ifdef O_NOCTTY - |O_NOCTTY -#endif - )) < 0) { + if ((fd = pa_open_cloexec(fname, O_RDONLY, 0)) < 0) { pa_log("Failed to open file %s: %s", fname, pa_cstrerror(errno)); goto fail; } diff --git a/src/pulsecore/sound-file.c b/src/pulsecore/sound-file.c index 2d9b76ad..d8c10b1e 100644 --- a/src/pulsecore/sound-file.c +++ b/src/pulsecore/sound-file.c @@ -62,11 +62,7 @@ int pa_sound_file_load( pa_memchunk_reset(chunk); - if ((fd = open(fname, O_RDONLY -#ifdef O_NOCTTY - |O_NOCTTY -#endif - )) < 0) { + if ((fd = pa_open_cloexec(fname, O_RDONLY, 0)) < 0) { pa_log("Failed to open file %s: %s", fname, pa_cstrerror(errno)); goto finish; } diff --git a/src/pulsecore/svolume_mmx.c b/src/pulsecore/svolume_mmx.c index 745c7de0..a011789c 100644 --- a/src/pulsecore/svolume_mmx.c +++ b/src/pulsecore/svolume_mmx.c @@ -25,6 +25,8 @@ #endif #include <pulse/timeval.h> +#include <pulse/rtclock.h> + #include <pulsecore/random.h> #include <pulsecore/macro.h> #include <pulsecore/g711.h> @@ -60,7 +62,9 @@ " movq "#s", %%mm5 \n\t" \ " pmulhw "#v", "#s" \n\t" /* .. | 0 | vl*p0 | */ \ " paddw %%mm4, "#s" \n\t" /* .. | 0 | vl*p0 | + sign correct */ \ + " pslld $16, "#s" \n\t" /* .. | vl*p0 | 0 | */ \ " psrld $16, "#v" \n\t" /* .. | 0 | vh | */ \ + " psrad $16, "#s" \n\t" /* .. | vl*p0 | sign extend */ \ " pmaddwd %%mm5, "#v" \n\t" /* .. | p0 * vh | */ \ " paddd "#s", "#v" \n\t" /* .. | p0 * v0 | */ \ " packssdw "#v", "#v" \n\t" /* .. | p1*v1 | p0*v0 | */ @@ -255,11 +259,14 @@ static void run_test (void) { printf ("checking MMX %zd\n", sizeof (samples)); pa_random (samples, sizeof (samples)); + /* for (i = 0; i < SAMPLES; i++) + samples[i] = -1; */ memcpy (samples_ref, samples, sizeof (samples)); memcpy (samples_orig, samples, sizeof (samples)); for (i = 0; i < CHANNELS; i++) volumes[i] = rand() >> 1; + /* volumes[i] = 0x0000ffff; */ for (padding = 0; padding < PADDING; padding++, i++) volumes[i] = volumes[padding]; @@ -267,7 +274,7 @@ static void run_test (void) { pa_volume_s16ne_mmx (samples, volumes, CHANNELS, sizeof (samples)); for (i = 0; i < SAMPLES; i++) { if (samples[i] != samples_ref[i]) { - printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], + printf ("%d: %04x != %04x (%04x * %08x)\n", i, samples[i], samples_ref[i], samples_orig[i], volumes[i % CHANNELS]); } } @@ -287,6 +294,8 @@ static void run_test (void) { } stop = pa_rtclock_now(); pa_log_info("ref: %llu usec.", (long long unsigned int)(stop - start)); + + pa_assert_se(memcmp(samples_ref, samples, sizeof(samples)) == 0); } #endif diff --git a/src/pulsecore/svolume_sse.c b/src/pulsecore/svolume_sse.c index 1cc4e0aa..620524fa 100644 --- a/src/pulsecore/svolume_sse.c +++ b/src/pulsecore/svolume_sse.c @@ -25,6 +25,8 @@ #endif #include <pulse/timeval.h> +#include <pulse/rtclock.h> + #include <pulsecore/random.h> #include <pulsecore/macro.h> #include <pulsecore/g711.h> @@ -261,7 +263,7 @@ static void run_test (void) { func = pa_get_volume_func (PA_SAMPLE_S16NE); - printf ("checking SSE %zd\n", sizeof (samples)); + printf ("checking SSE2 %zd\n", sizeof (samples)); pa_random (samples, sizeof (samples)); memcpy (samples_ref, samples, sizeof (samples)); @@ -273,7 +275,7 @@ static void run_test (void) { volumes[i] = volumes[padding]; func (samples_ref, volumes, CHANNELS, sizeof (samples)); - pa_volume_s16ne_sse (samples, volumes, CHANNELS, sizeof (samples)); + pa_volume_s16ne_sse2 (samples, volumes, CHANNELS, sizeof (samples)); for (i = 0; i < SAMPLES; i++) { if (samples[i] != samples_ref[i]) { printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], @@ -284,7 +286,7 @@ static void run_test (void) { start = pa_rtclock_now(); for (j = 0; j < TIMES; j++) { memcpy (samples, samples_orig, sizeof (samples)); - pa_volume_s16ne_sse (samples, volumes, CHANNELS, sizeof (samples)); + pa_volume_s16ne_sse2 (samples, volumes, CHANNELS, sizeof (samples)); } stop = pa_rtclock_now(); pa_log_info("SSE: %llu usec.", (long long unsigned int)(stop - start)); @@ -296,6 +298,8 @@ static void run_test (void) { } stop = pa_rtclock_now(); pa_log_info("ref: %llu usec.", (long long unsigned int)(stop - start)); + + pa_assert_se(memcmp(samples_ref, samples, sizeof(samples)) == 0); } #endif #endif /* defined (__i386__) || defined (__amd64__) */ diff --git a/src/pulsecore/time-smoother.c b/src/pulsecore/time-smoother.c index d6c37878..1371ad56 100644 --- a/src/pulsecore/time-smoother.c +++ b/src/pulsecore/time-smoother.c @@ -196,6 +196,13 @@ static double avg_gradient(pa_smoother *s, pa_usec_t x) { int64_t ax = 0, ay = 0, k, t; double r; + /* FIXME: Optimization: Jason Newton suggested that instead of + * going through the history on each iteration we could calculated + * avg_gradient() as we go. + * + * Second idea: it might make sense to weight history entries: + * more recent entries should matter more than old ones. */ + /* Too few measurements, assume gradient of 1 */ if (s->n_history < s->min_history) return 1; diff --git a/src/pulsecore/x11prop.c b/src/pulsecore/x11prop.c index 873a76e7..dc8ec294 100644 --- a/src/pulsecore/x11prop.c +++ b/src/pulsecore/x11prop.c @@ -32,12 +32,12 @@ void pa_x11_set_prop(Display *d, const char *name, const char *data) { Atom a = XInternAtom(d, name, False); - XChangeProperty(d, RootWindow(d, 0), a, XA_STRING, 8, PropModeReplace, (const unsigned char*) data, (int) (strlen(data)+1)); + XChangeProperty(d, DefaultRootWindow(d), a, XA_STRING, 8, PropModeReplace, (const unsigned char*) data, (int) (strlen(data)+1)); } void pa_x11_del_prop(Display *d, const char *name) { Atom a = XInternAtom(d, name, False); - XDeleteProperty(d, RootWindow(d, 0), a); + XDeleteProperty(d, DefaultRootWindow(d), a); } char* pa_x11_get_prop(Display *d, const char *name, char *p, size_t l) { @@ -47,13 +47,21 @@ char* pa_x11_get_prop(Display *d, const char *name, char *p, size_t l) { unsigned long nbytes_after; unsigned char *prop = NULL; char *ret = NULL; + int window_ret; Atom a = XInternAtom(d, name, False); - if (XGetWindowProperty(d, RootWindow(d, 0), a, 0, (long) ((l+2)/4), False, XA_STRING, &actual_type, &actual_format, &nitems, &nbytes_after, &prop) != Success) - goto finish; - if (actual_type != XA_STRING) - goto finish; + window_ret = XGetWindowProperty(d, DefaultRootWindow(d), a, 0, (long) ((l+2)/4), False, XA_STRING, &actual_type, &actual_format, &nitems, &nbytes_after, &prop); + + if (window_ret != Success || actual_type != XA_STRING) { + if (DefaultScreen(d) != 0) { + window_ret = XGetWindowProperty(d, RootWindow(d, 0), a, 0, (long) ((l+2)/4), False, XA_STRING, &actual_type, &actual_format, &nitems, &nbytes_after, &prop); + + if (window_ret != Success || actual_type != XA_STRING) + goto finish; + } else + goto finish; + } memcpy(p, prop, nitems); p[nitems] = 0; diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 5f29ba39..d348c16a 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -906,7 +906,7 @@ int main(int argc, char *argv[]) { filename = argv[optind]; - if ((fd = open(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) { + if ((fd = pa_open_cloexec(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) { pa_log(_("open(): %s"), strerror(errno)); goto quit; } diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c index 5ef57e3b..ef58e9ce 100644 --- a/src/utils/pacmd.c +++ b/src/utils/pacmd.c @@ -70,7 +70,7 @@ int main(int argc, char*argv[]) { goto fail; } - if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + if ((fd = pa_socket_cloexec(PF_UNIX, SOCK_STREAM, 0)) < 0) { pa_log(_("socket(PF_UNIX, SOCK_STREAM, 0): %s"), strerror(errno)); goto fail; } diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 141ab5b1..ee67c425 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -44,8 +44,6 @@ #include <pulsecore/log.h> #include <pulsecore/sndfile-util.h> -#define BUFSIZE (16*1024) - static pa_context *context = NULL; static pa_mainloop_api *mainloop_api = NULL; @@ -158,10 +156,23 @@ static void get_server_info_callback(pa_context *c, const pa_server_info *i, voi return; } + printf(_("Server String: %s\n" + "Library Protocol Version: %u\n" + "Server Protocol Version: %u\n" + "Is Local: %s\n" + "Client Index: %u\n" + "Tile Size: %zu\n"), + pa_context_get_server(c), + pa_context_get_protocol_version(c), + pa_context_get_server_protocol_version(c), + pa_yes_no(pa_context_is_local(c)), + pa_context_get_index(c), + pa_context_get_tile_size(c, NULL)); + pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec); pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map); - printf(_("User name: %s\n" + printf(_("User Name: %s\n" "Host Name: %s\n" "Server Name: %s\n" "Server Version: %s\n" @@ -169,7 +180,7 @@ static void get_server_info_callback(pa_context *c, const pa_server_info *i, voi "Default Channel Map: %s\n" "Default Sink: %s\n" "Default Source: %s\n" - "Cookie: %08x\n"), + "Cookie: %04x:%04x\n"), i->user_name, i->host_name, i->server_name, @@ -178,7 +189,8 @@ static void get_server_info_callback(pa_context *c, const pa_server_info *i, voi cm, i->default_sink_name, i->default_source_name, - i->cookie); + i->cookie >> 16, + i->cookie & 0xFFFFU); complete_action(); } diff --git a/src/utils/pasuspender.c b/src/utils/pasuspender.c index c327ee41..534b77b4 100644 --- a/src/utils/pasuspender.c +++ b/src/utils/pasuspender.c @@ -45,8 +45,6 @@ #include <pulse/pulseaudio.h> #include <pulsecore/macro.h> -#define BUFSIZE 1024 - static pa_context *context = NULL; static pa_mainloop_api *mainloop_api = NULL; static char **child_argv = NULL; diff --git a/src/utils/qpaeq b/src/utils/qpaeq new file mode 100755 index 00000000..a8a9fda8 --- /dev/null +++ b/src/utils/qpaeq @@ -0,0 +1,560 @@ +#!/usr/bin/env python +# qpaeq is a equalizer interface for pulseaudio's equalizer sinks +# Copyright (C) 2009 Jason Newton <nevion@gmail.com +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +import os,math,sys +try: + import PyQt4,sip + from PyQt4 import QtGui,QtCore + import dbus.mainloop.qt + import dbus +except ImportError,e: + print 'There was an error importing need libraries' + print 'Make sure you haveqt4 and dbus forthon installed' + print 'The error that occured was' + print '\t%s' %(str(e)) + import sys + sys.exit(-1) + +from functools import partial + +import signal +signal.signal(signal.SIGINT, signal.SIG_DFL) +SYNC_TIMEOUT = 4*1000 + +CORE_PATH = "/org/pulseaudio/core1" +CORE_IFACE = "org.PulseAudio.Core1" +def connect(): + try: + if 'PULSE_DBUS_SERVER' in os.environ: + address = os.environ['PULSE_DBUS_SERVER'] + else: + bus = dbus.SessionBus() # Should be UserBus, but D-Bus doesn't implement that yet. + server_lookup = bus.get_object('org.PulseAudio1', '/org/pulseaudio/server_lookup1') + address = server_lookup.Get('org.PulseAudio.ServerLookup1', 'Address', dbus_interface='org.freedesktop.DBus.Properties') + return dbus.connection.Connection(address) + except Exception,e: + print 'There was an error connecting to pulseaudio, please make sure you have the pulseaudio dbus' + print 'and equalizer modules loaded, exiting...' + import sys + sys.exit(-1) + + +#TODO: signals: sink Filter changed, sink reconfigured (window size) (sink iface) +#TODO: manager signals: new sink, removed sink, new profile, removed profile +#TODO: add support for changing of window_size 1000-fft_size (adv option) +#TODO: reconnect support loop 1 second trying to reconnect +#TODO: just resample the filters for profiles when loading to different sizes +#TODO: add preamp +prop_iface='org.freedesktop.DBus.Properties' +eq_iface='org.PulseAudio.Ext.Equalizing1.Equalizer' +device_iface='org.PulseAudio.Core1.Device' +class QPaeq(QtGui.QWidget): + manager_path='/org/pulseaudio/equalizing1' + manager_iface='org.PulseAudio.Ext.Equalizing1.Manager' + core_iface='org.PulseAudio.Core1' + core_path='/org/pulseaudio/core1' + def __init__(self): + QtGui.QWidget.__init__(self) + self.setWindowTitle('qpaeq') + self.slider_widget=None + self.sink_name=None + self.filter_state=None + + self.create_layout() + + self.set_connection() + self.connect_to_sink(self.sinks[0]) + self.set_callbacks() + self.setMinimumSize(self.sizeHint()) + + def create_layout(self): + self.main_layout=QtGui.QVBoxLayout() + self.setLayout(self.main_layout) + toprow_layout=QtGui.QHBoxLayout() + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + #sizePolicy.setHeightForWidth(self.profile_box.sizePolicy().hasHeightForWidth()) + + toprow_layout.addWidget(QtGui.QLabel('Sink')) + self.sink_box = QtGui.QComboBox() + self.sink_box.setSizePolicy(sizePolicy) + self.sink_box.setDuplicatesEnabled(False) + self.sink_box.setInsertPolicy(QtGui.QComboBox.InsertAlphabetically) + #self.sink_box.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents) + toprow_layout.addWidget(self.sink_box) + + toprow_layout.addWidget(QtGui.QLabel('Channel')) + self.channel_box = QtGui.QComboBox() + self.channel_box.setSizePolicy(sizePolicy) + toprow_layout.addWidget(self.channel_box) + + toprow_layout.addWidget(QtGui.QLabel('Preset')) + self.profile_box = QtGui.QComboBox() + self.profile_box.setSizePolicy(sizePolicy) + self.profile_box.setInsertPolicy(QtGui.QComboBox.InsertAlphabetically) + #self.profile_box.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents) + toprow_layout.addWidget(self.profile_box) + + large_icon_size=self.style().pixelMetric(QtGui.QStyle.PM_LargeIconSize) + large_icon_size=QtCore.QSize(large_icon_size,large_icon_size) + save_profile=QtGui.QToolButton() + save_profile.setIcon(self.style().standardIcon(QtGui.QStyle.SP_DriveFDIcon)) + save_profile.setIconSize(large_icon_size) + save_profile.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly) + save_profile.clicked.connect(self.save_profile) + remove_profile=QtGui.QToolButton() + remove_profile.setIcon(self.style().standardIcon(QtGui.QStyle.SP_TrashIcon)) + remove_profile.setIconSize(large_icon_size) + remove_profile.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly) + remove_profile.clicked.connect(self.remove_profile) + toprow_layout.addWidget(save_profile) + toprow_layout.addWidget(remove_profile) + + reset_button = QtGui.QPushButton('Reset') + reset_button.clicked.connect(self.reset) + toprow_layout.addStretch() + toprow_layout.addWidget(reset_button) + self.layout().addLayout(toprow_layout) + + self.profile_box.activated.connect(self.load_profile) + self.channel_box.activated.connect(self.select_channel) + def connect_to_sink(self,name): + #TODO: clear slots for profile buttons + + #flush any pending saves for other sinks + if self.filter_state is not None: + self.filter_state.flush_state() + sink=self.connection.get_object(object_path=name) + self.sink_props=dbus.Interface(sink,dbus_interface=prop_iface) + self.sink=dbus.Interface(sink,dbus_interface=eq_iface) + self.filter_state=FilterState(sink) + #sample_rate,filter_rate,channels,channel) + + self.channel_box.clear() + self.channel_box.addItem('All',self.filter_state.channels) + for i in xrange(self.filter_state.channels): + self.channel_box.addItem('%d' %(i+1,),i) + self.setMinimumSize(self.sizeHint()) + + self.set_slider_widget(SliderArray(self.filter_state)) + + self.sink_name=name + #set the signal listener for this sink + core=self._get_core() + #temporary hack until signal filtering works properly + core.ListenForSignal('',[dbus.ObjectPath(self.sink_name),dbus.ObjectPath(self.manager_path)]) + #for x in ['FilterChanged']: + # core.ListenForSignal("%s.%s" %(self.eq_iface,x),[dbus.ObjectPath(self.sink_name)]) + #core.ListenForSignal(self.eq_iface,[dbus.ObjectPath(self.sink_name)]) + self.sink.connect_to_signal('FilterChanged',self.read_filter) + + def set_slider_widget(self,widget): + layout=self.layout() + if self.slider_widget is not None: + i=layout.indexOf(self.slider_widget) + layout.removeWidget(self.slider_widget) + self.slider_widget.deleteLater() + layout.insertWidget(i,self.slider_widget) + else: + layout.addWidget(widget) + self.slider_widget=widget + self.read_filter() + def _get_core(self): + core_obj=self.connection.get_object(object_path=self.core_path) + core=dbus.Interface(core_obj,dbus_interface=self.core_iface) + return core + def sink_added(self,sink): + #TODO: preserve selected sink + self.update_sinks() + def sink_removed(self,sink): + #TODO: preserve selected sink, try connecting to backup otherwise + if sink==self.sink_name: + #connect to new sink? + pass + self.update_sinks() + def save_profile(self): + #popup dialog box for name + current=self.profile_box.currentIndex() + profile,ok=QtGui.QInputDialog.getItem(self,'Preset Name','Preset',self.profiles,current) + if not ok or profile=='': + return + if profile in self.profiles: + mbox=QtGui.QMessageBox(self) + mbox.setText('%s preset already exists'%(profile,)) + mbox.setInformativeText('Do you want to save over it?') + mbox.setStandardButtons(mbox.Save|mbox.Discard|mbox.Cancel) + mbox.setDefaultButton(mbox.Save) + ret=mbox.exec_() + if ret!=mbox.Save: + return + self.sink.SaveProfile(self.filter_state.channel,dbus.String(profile)) + if self.filter_state.channel==self.filter_state.channels: + for x in range(1,self.filter_state.channels): + self.sink.LoadProfile(x,dbus.String(profile)) + def remove_profile(self): + #find active profile name, remove it + profile=self.profile_box.currentText() + manager=dbus.Interface(self.manager_obj,dbus_interface=self.manager_iface) + manager.RemoveProfile(dbus.String(profile)) + def load_profile(self,x): + profile=self.profile_box.itemText(x) + self.filter_state.load_profile(profile) + def select_channel(self,x): + self.filter_state.channel = self.channel_box.itemData(x).toPyObject() + self._set_profile_name() + self.filter_state.readback() + + #TODO: add back in preamp! + #print frequencies + #main_layout.addLayout(self.create_slider(partial(self.update_coefficient,0), + # 'Preamp')[0] + #) + def set_connection(self): + self.connection=connect() + self.manager_obj=self.connection.get_object(object_path=self.manager_path) + manager_props=dbus.Interface(self.manager_obj,dbus_interface=prop_iface) + self.sinks=manager_props.Get(self.manager_iface,'EqualizedSinks') + def set_callbacks(self): + manager=dbus.Interface(self.manager_obj,dbus_interface=self.manager_iface) + manager.connect_to_signal('ProfilesChanged',self.update_profiles) + manager.connect_to_signal('SinkAdded',self.sink_added) + manager.connect_to_signal('SinkRemoved',self.sink_removed) + #self._get_core().ListenForSignal(self.manager_iface,[]) + #self._get_core().ListenForSignal(self.manager_iface,[dbus.ObjectPath(self.manager_path)]) + #core=self._get_core() + #for x in ['ProfilesChanged','SinkAdded','SinkRemoved']: + # core.ListenForSignal("%s.%s" %(self.manager_iface,x),[dbus.ObjectPath(self.manager_path)]) + self.update_profiles() + self.update_sinks() + def update_profiles(self): + #print 'update profiles called!' + manager_props=dbus.Interface(self.manager_obj,dbus_interface=prop_iface) + self.profiles=manager_props.Get(self.manager_iface,'Profiles') + self.profile_box.blockSignals(True) + self.profile_box.clear() + self.profile_box.addItems(self.profiles) + self.profile_box.blockSignals(False) + self._set_profile_name() + def update_sinks(self): + self.sink_box.blockSignals(True) + self.sink_box.clear() + for x in self.sinks: + sink=self.connection.get_object(object_path=x) + sink_props=dbus.Interface(sink,dbus_interface=prop_iface) + simple_name=sink_props.Get(device_iface,'Name') + self.sink_box.addItem(simple_name,x) + self.sink_box.blockSignals(False) + self.sink_box.setMinimumSize(self.sink_box.sizeHint()) + def read_filter(self): + #print self.filter_frequencies + self.filter_state.readback() + def reset(self): + coefs=dbus.Array([1/math.sqrt(2.0)]*(self.filter_state.filter_rate//2+1)) + preamp=1.0 + self.filter_state.set_filter(preamp,coefs) + def _set_profile_name(self): + self.profile_box.blockSignals(True) + profile_name=self.sink.BaseProfile(self.filter_state.channel) + if profile_name is not None: + i=self.profile_box.findText(profile_name) + if i>=0: + self.profile_box.setCurrentIndex(i) + self.profile_box.blockSignals(False) + + +class SliderArray(QtGui.QWidget): + def __init__(self,filter_state,parent=None): + super(SliderArray,self).__init__(parent) + #self.setStyleSheet('padding: 0px; border-width: 0px; margin: 0px;') + #self.setStyleSheet('font-size: 7pt; font-family: monospace;'+outline%('blue')) + self.filter_state=filter_state + self.setLayout(QtGui.QHBoxLayout()) + self.sub_array=None + self.set_sub_array(SliderArraySub(self.filter_state)) + self.inhibit_resize=0 + def set_sub_array(self,widget): + if self.sub_array is not None: + self.layout().removeWidget(self.sub_array) + self.sub_array.disconnect_signals() + self.sub_array.deleteLater() + self.sub_array=widget + self.layout().addWidget(self.sub_array) + self.sub_array.connect_signals() + self.filter_state.readback() + def resizeEvent(self,event): + super(SliderArray,self).resizeEvent(event) + if self.inhibit_resize==0: + self.inhibit_resize+=1 + #self.add_sliders_to_fit() + t=QtCore.QTimer(self) + t.setSingleShot(True) + t.setInterval(0) + t.timeout.connect(partial(self.add_sliders_to_fit,event)) + t.start() + def add_sliders_to_fit(self,event): + if event.oldSize().width()>0 and event.size().width()>0: + i=len(self.filter_state.frequencies)*int(round(float(event.size().width())/event.oldSize().width())) + else: + i=len(self.filter_state.frequencies) + + t_w=self.size().width() + def evaluate(filter_state, target, variable): + base_freqs=self.filter_state.freq_proper(self.filter_state.DEFAULT_FREQUENCIES) + filter_state._set_frequency_values(subdivide(base_freqs,variable)) + new_widget=SliderArraySub(filter_state) + w=new_widget.sizeHint().width() + return w-target + def searcher(initial,evaluator): + i=initial + def d(e): return 1 if e>=0 else -1 + error=evaluator(i) + old_direction=d(error) + i-=old_direction + while True: + error=evaluator(i) + direction=d(error) + if direction!=old_direction: + k=i-1 + #while direction<0 and error!=0: + # k-=1 + # error=evaluator(i) + # direction=d(error) + return k, evaluator(k) + i-=direction + old_direction=direction + searcher(i,partial(evaluate,self.filter_state,t_w)) + self.set_sub_array(SliderArraySub(self.filter_state)) + self.inhibit_resize-=1 + +class SliderArraySub(QtGui.QWidget): + def __init__(self,filter_state,parent=None): + super(SliderArraySub,self).__init__(parent) + self.filter_state=filter_state + self.setLayout(QtGui.QGridLayout()) + self.slider=[None]*len(self.filter_state.frequencies) + self.label=[None]*len(self.slider) + #self.setStyleSheet('padding: 0px; border-width: 0px; margin: 0px;') + #self.setStyleSheet('font-size: 7pt; font-family: monospace;'+outline%('blue')) + qt=QtCore.Qt + #self.layout().setHorizontalSpacing(1) + def add_slider(slider,label, c): + self.layout().addWidget(slider,0,c,qt.AlignHCenter) + self.layout().addWidget(label,1,c,qt.AlignHCenter) + self.layout().setColumnMinimumWidth(c,max(label.sizeHint().width(),slider.sizeHint().width())) + def create_slider(slider_label): + slider=QtGui.QSlider(QtCore.Qt.Vertical,self) + label=SliderLabel(slider_label,filter_state,self) + slider.setRange(-1000,2000) + slider.setSingleStep(1) + return (slider,label) + self.preamp_slider,self.preamp_label=create_slider('Preamp') + add_slider(self.preamp_slider,self.preamp_label,0) + for i,hz in enumerate(self.filter_state.frequencies): + slider,label=create_slider(self.hz2label(hz)) + self.slider[i]=slider + #slider.setStyleSheet('font-size: 7pt; font-family: monospace;'+outline%('red',)) + self.label[i]=label + c=i+1 + add_slider(slider,label,i+1) + def hz2label(self, hz): + if hz==0: + label_text='DC' + elif hz==self.filter_state.sample_rate//2: + label_text='Coda' + else: + label_text=hz2str(hz) + return label_text + + def connect_signals(self): + def connect(writer,reader,slider,label): + slider.valueChanged.connect(writer) + self.filter_state.readFilter.connect(reader) + label_cb=partial(slider.setValue,0) + label.clicked.connect(label_cb) + return label_cb + + self.preamp_writer_cb=self.write_preamp + self.preamp_reader_cb=self.sync_preamp + self.preamp_label_cb=connect(self.preamp_writer_cb, + self.preamp_reader_cb, + self.preamp_slider, + self.preamp_label) + self.writer_callbacks=[None]*len(self.slider) + self.reader_callbacks=[None]*len(self.slider) + self.label_callbacks=[None]*len(self.label) + for i in range(len(self.slider)): + self.writer_callbacks[i]=partial(self.write_coefficient,i) + self.reader_callbacks[i]=partial(self.sync_coefficient,i) + self.label_callbacks[i]=connect(self.writer_callbacks[i], + self.reader_callbacks[i], + self.slider[i], + self.label[i]) + def disconnect_signals(self): + def disconnect(writer,reader,label_cb,slider,label): + slider.valueChanged.disconnect(writer) + self.filter_state.readFilter.disconnect(reader) + label.clicked.disconnect(label_cb) + disconnect(self.preamp_writer_cb, self.preamp_reader_cb, + self.preamp_label_cb, self.preamp_slider, self.preamp_label) + for i in range(len(self.slider)): + disconnect(self.writer_callbacks[i], + self.reader_callbacks[i], + self.label_callbacks[i], + self.slider[i], + self.label[i]) + + def write_preamp(self, v): + self.filter_state.preamp=self.slider2coef(v) + self.filter_state.seed() + def sync_preamp(self): + self.preamp_slider.blockSignals(True) + self.preamp_slider.setValue(self.coef2slider(self.filter_state.preamp)) + self.preamp_slider.blockSignals(False) + + + def write_coefficient(self,i,v): + self.filter_state.coefficients[i]=self.slider2coef(v)/math.sqrt(2.0) + self.filter_state.seed() + def sync_coefficient(self,i): + slider=self.slider[i] + slider.blockSignals(True) + slider.setValue(self.coef2slider(math.sqrt(2.0)*self.filter_state.coefficients[i])) + slider.blockSignals(False) + @staticmethod + def slider2coef(x): + return (1.0+(x/1000.0)) + @staticmethod + def coef2slider(x): + return int((x-1.0)*1000) +outline='border-width: 1px; border-style: solid; border-color: %s;' + +class SliderLabel(QtGui.QLabel): + clicked=QtCore.pyqtSignal() + def __init__(self,label_text,filter_state,parent=None): + super(SliderLabel,self).__init__(parent) + self.setStyleSheet('font-size: 7pt; font-family: monospace;') + self.setText(label_text) + self.setMinimumSize(self.sizeHint()) + def mouseDoubleClickEvent(self, event): + self.clicked.emit() + super(SliderLabel,self).mouseDoubleClickEvent(event) + +#until there are server side state savings, do it in the client but try and avoid +#simulaneous broadcasting situations +class FilterState(QtCore.QObject): + #DEFAULT_FREQUENCIES=map(float,[25,50,75,100,150,200,300,400,500,800,1e3,1.5e3,3e3,5e3,7e3,10e3,15e3,20e3]) + DEFAULT_FREQUENCIES=[31.75,63.5,125,250,500,1e3,2e3,4e3,8e3,16e3] + readFilter=QtCore.pyqtSignal() + def __init__(self,sink): + super(FilterState,self).__init__() + self.sink_props=dbus.Interface(sink,dbus_interface=prop_iface) + self.sink=dbus.Interface(sink,dbus_interface=eq_iface) + self.sample_rate=self.get_eq_attr('SampleRate') + self.filter_rate=self.get_eq_attr('FilterSampleRate') + self.channels=self.get_eq_attr('NChannels') + self.channel=self.channels + self.set_frequency_values(self.DEFAULT_FREQUENCIES) + self.sync_timer=QtCore.QTimer() + self.sync_timer.setSingleShot(True) + self.sync_timer.timeout.connect(self.save_state) + + def get_eq_attr(self,attr): + return self.sink_props.Get(eq_iface,attr) + def freq_proper(self,xs): + return [0]+xs+[self.sample_rate//2] + def _set_frequency_values(self,freqs): + self.frequencies=freqs + #print 'base',self.frequencies + self.filter_frequencies=map(lambda x: int(round(x)), \ + self.translate_rates(self.filter_rate,self.sample_rate, + self.frequencies) \ + ) + self.coefficients=[0.0]*len(self.frequencies) + self.preamp=1.0 + def set_frequency_values(self,freqs): + self._set_frequency_values(self.freq_proper(freqs)) + @staticmethod + def translate_rates(dst,src,rates): + return list(map(lambda x: x*dst/src,rates)) + def seed(self): + self.sink.SeedFilter(self.channel,self.filter_frequencies,self.coefficients,self.preamp) + self.sync_timer.start(SYNC_TIMEOUT) + def readback(self): + coefs,preamp=self.sink.FilterAtPoints(self.channel,self.filter_frequencies) + self.coefficients=coefs + self.preamp=preamp + self.readFilter.emit() + def set_filter(self,preamp,coefs): + self.sink.SetFilter(self.channel,dbus.Array(coefs),self.preamp) + self.sync_timer.start(SYNC_TIMEOUT) + def save_state(self): + print 'saving state' + self.sink.SaveState() + def load_profile(self,profile): + self.sink.LoadProfile(self.channel,dbus.String(profile)) + self.sync_timer.start(SYNC_TIMEOUT) + def flush_state(self): + if self.sync_timer.isActive(): + self.sync_timer.stop() + self.save_state() + + +def safe_log(k,b): + i=0 + while k//b!=0: + i+=1 + k=k//b + return i +def hz2str(hz): + p=safe_log(hz,10.0) + if p<3: + return '%dHz' %(hz,) + elif hz%1000==0: + return '%dKHz' %(hz/(10.0**3),) + else: + return '%.1fKHz' %(hz/(10.0**3),) + +def subdivide(xs, t_points): + while len(xs)<t_points: + m=[0]*(2*len(xs)-1) + m[0:len(m):2]=xs + for i in range(1,len(m),2): + m[i]=(m[i-1]+m[i+1])//2 + xs=m + p_drop=len(xs)-t_points + p_drop_left=p_drop//2 + p_drop_right=p_drop-p_drop_left + #print 'xs',xs + #print 'dropping %d, %d left, %d right' %(p_drop,p_drop_left,p_drop_right) + c=len(xs)//2 + left=xs[0:p_drop_left*2:2]+xs[p_drop_left*2:c] + right=list(reversed(xs[c:])) + right=right[0:p_drop_right*2:2]+right[p_drop_right*2:] + right=list(reversed(right)) + return left+right + +def main(): + dbus.mainloop.qt.DBusQtMainLoop(set_as_default=True) + app=QtGui.QApplication(sys.argv) + qpaeq_main=QPaeq() + qpaeq_main.show() + sys.exit(app.exec_()) + +if __name__=='__main__': + main() |