summaryrefslogtreecommitdiffstats
path: root/src/pulsecore
diff options
context:
space:
mode:
Diffstat (limited to 'src/pulsecore')
-rw-r--r--src/pulsecore/asyncq.c5
-rw-r--r--src/pulsecore/card.c2
-rw-r--r--src/pulsecore/cli-command.c8
-rw-r--r--src/pulsecore/cli-text.c20
-rw-r--r--src/pulsecore/core-scache.c1
-rw-r--r--src/pulsecore/core-util.c27
-rw-r--r--src/pulsecore/core.h3
-rw-r--r--src/pulsecore/cpu-arm.c38
-rw-r--r--src/pulsecore/cpu-orc.c34
-rw-r--r--src/pulsecore/cpu-orc.h37
-rw-r--r--src/pulsecore/cpu-x86.c26
-rw-r--r--src/pulsecore/database-simple.c2
-rw-r--r--src/pulsecore/envelope.c989
-rw-r--r--src/pulsecore/envelope.h56
-rw-r--r--src/pulsecore/ipacl.c4
-rw-r--r--src/pulsecore/log.c27
-rw-r--r--src/pulsecore/log.h5
-rw-r--r--src/pulsecore/ltdl-helper.c4
-rw-r--r--src/pulsecore/memblock.c10
-rw-r--r--src/pulsecore/memblockq.c4
-rw-r--r--src/pulsecore/memtrap.c2
-rw-r--r--src/pulsecore/modargs.c2
-rw-r--r--src/pulsecore/module.c2
-rw-r--r--src/pulsecore/play-memblockq.c6
-rw-r--r--src/pulsecore/poll.c4
-rw-r--r--src/pulsecore/poll.h7
-rw-r--r--src/pulsecore/protocol-esound.c3
-rw-r--r--src/pulsecore/protocol-native.c62
-rw-r--r--src/pulsecore/remap.c18
-rw-r--r--src/pulsecore/remap_mmx.c8
-rw-r--r--src/pulsecore/remap_sse.c6
-rw-r--r--src/pulsecore/resampler.c14
-rw-r--r--src/pulsecore/rtpoll.c2
-rw-r--r--src/pulsecore/sample-util.c4
-rw-r--r--src/pulsecore/sconv-s16le.c3
-rw-r--r--src/pulsecore/sconv.c6
-rw-r--r--src/pulsecore/sconv_sse.c33
-rw-r--r--src/pulsecore/semaphore-osx.c3
-rw-r--r--src/pulsecore/semaphore-win32.c3
-rw-r--r--src/pulsecore/shm.c2
-rw-r--r--src/pulsecore/sink-input.c622
-rw-r--r--src/pulsecore/sink-input.h28
-rw-r--r--src/pulsecore/sink.c602
-rw-r--r--src/pulsecore/sink.h6
-rw-r--r--src/pulsecore/sndfile-util.c16
-rw-r--r--src/pulsecore/sound-file-stream.c2
-rw-r--r--src/pulsecore/source-output.c1
-rw-r--r--src/pulsecore/source-output.h4
-rw-r--r--src/pulsecore/source.c35
-rw-r--r--src/pulsecore/source.h3
-rw-r--r--src/pulsecore/strbuf.c2
-rw-r--r--src/pulsecore/strlist.c2
-rw-r--r--src/pulsecore/svolume.orc84
-rw-r--r--src/pulsecore/svolume_arm.c41
-rw-r--r--src/pulsecore/svolume_c.c73
-rw-r--r--src/pulsecore/svolume_mmx.c52
-rw-r--r--src/pulsecore/svolume_orc.c117
-rw-r--r--src/pulsecore/svolume_sse.c46
-rw-r--r--src/pulsecore/time-smoother.c4
-rw-r--r--src/pulsecore/usergroup.c16
-rw-r--r--src/pulsecore/x11prop.c3
61 files changed, 1336 insertions, 1915 deletions
diff --git a/src/pulsecore/asyncq.c b/src/pulsecore/asyncq.c
index e62d0c16..8c2d58a0 100644
--- a/src/pulsecore/asyncq.c
+++ b/src/pulsecore/asyncq.c
@@ -26,6 +26,8 @@
#include <unistd.h>
#include <errno.h>
+#include <pulse/xmalloc.h>
+
#include <pulsecore/atomic.h>
#include <pulsecore/log.h>
#include <pulsecore/thread.h>
@@ -33,10 +35,9 @@
#include <pulsecore/core-util.h>
#include <pulsecore/llist.h>
#include <pulsecore/flist.h>
-#include <pulse/xmalloc.h>
+#include <pulsecore/fdsem.h>
#include "asyncq.h"
-#include "fdsem.h"
#define ASYNCQ_SIZE 256
diff --git a/src/pulsecore/card.c b/src/pulsecore/card.c
index 2f0a3af0..feaa4440 100644
--- a/src/pulsecore/card.c
+++ b/src/pulsecore/card.c
@@ -241,6 +241,8 @@ int pa_card_set_profile(pa_card *c, const char *name, pa_bool_t save) {
c->active_profile = profile;
c->save_profile = save;
+ pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CARD_PROFILE_CHANGED], c);
+
return 0;
}
diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
index a18ebd33..de4995eb 100644
--- a/src/pulsecore/cli-command.c
+++ b/src/pulsecore/cli-command.c
@@ -32,6 +32,7 @@
#include <ltdl.h>
#include <sys/stat.h>
#include <dirent.h>
+#include <time.h>
#include <pulse/xmalloc.h>
#include <pulse/error.h>
@@ -579,11 +580,16 @@ static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strb
return -1;
}
- if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
+ if (!(si = pa_idxset_get_by_index(c->sink_inputs, idx))) {
pa_strbuf_puts(buf, "No sink input found with this index.\n");
return -1;
}
+ if (!pa_sink_input_is_volume_writable(si)) {
+ pa_strbuf_puts(buf, "This sink input's volume can't be changed.\n");
+ return -1;
+ }
+
pa_cvolume_set(&cvolume, 1, volume);
pa_sink_input_set_volume(si, &cvolume, TRUE, TRUE);
return 0;
diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c
index 23a57d37..e6018da2 100644
--- a/src/pulsecore/cli-text.c
+++ b/src/pulsecore/cli-text.c
@@ -553,8 +553,7 @@ char *pa_sink_input_list_to_string(pa_core *c) {
pa_usec_t cl;
const char *cmn;
pa_cvolume v;
-
- pa_sink_input_get_volume(i, &v, TRUE);
+ char *volume_str = NULL;
cmn = pa_channel_map_to_pretty_name(&i->channel_map);
@@ -565,6 +564,15 @@ char *pa_sink_input_list_to_string(pa_core *c) {
pa_assert(i->sink);
+ if (pa_sink_input_is_volume_readable(i)) {
+ pa_sink_input_get_volume(i, &v, TRUE);
+ volume_str = pa_sprintf_malloc("%s\n\t %s\n\t balance %0.2f",
+ pa_cvolume_snprint(cv, sizeof(cv), &v),
+ pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &v),
+ pa_cvolume_get_balance(&v, &i->channel_map));
+ } else
+ volume_str = pa_xstrdup("n/a");
+
pa_strbuf_printf(
s,
" index: %u\n"
@@ -573,8 +581,6 @@ char *pa_sink_input_list_to_string(pa_core *c) {
"\tstate: %s\n"
"\tsink: %u <%s>\n"
"\tvolume: %s\n"
- "\t %s\n"
- "\t balance %0.2f\n"
"\tmuted: %s\n"
"\tcurrent latency: %0.2f ms\n"
"\trequested latency: %s\n"
@@ -596,9 +602,7 @@ char *pa_sink_input_list_to_string(pa_core *c) {
i->flags & PA_SINK_INPUT_KILL_ON_SUSPEND ? "KILL_ON_SUSPEND " : "",
state_table[pa_sink_input_get_state(i)],
i->sink->index, i->sink->name,
- pa_cvolume_snprint(cv, sizeof(cv), &v),
- pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &v),
- pa_cvolume_get_balance(&v, &i->channel_map),
+ volume_str,
pa_yes_no(pa_sink_input_get_mute(i)),
(double) pa_sink_input_get_latency(i, NULL) / PA_USEC_PER_MSEC,
clt,
@@ -608,6 +612,8 @@ char *pa_sink_input_list_to_string(pa_core *c) {
cmn ? cmn : "",
pa_resample_method_to_string(pa_sink_input_get_resample_method(i)));
+ pa_xfree(volume_str);
+
if (i->module)
pa_strbuf_printf(s, "\tmodule: %u\n", i->module->index);
if (i->client)
diff --git a/src/pulsecore/core-scache.c b/src/pulsecore/core-scache.c
index 5ec6159d..1aed9077 100644
--- a/src/pulsecore/core-scache.c
+++ b/src/pulsecore/core-scache.c
@@ -32,6 +32,7 @@
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
+#include <time.h>
#ifdef HAVE_GLOB_H
#include <glob.h>
diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index fd3cc67a..b5043a38 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -222,12 +222,12 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) {
#ifdef OS_IS_WIN32
r = mkdir(dir);
#else
- {
+{
mode_t u;
u = umask((~m) & 0777);
r = mkdir(dir, m);
umask(u);
- }
+}
#endif
if (r < 0 && errno != EEXIST)
@@ -549,7 +549,7 @@ void pa_check_signal_is_blocked(int sig) {
/* The following function is based on an example from the GNU libc
* documentation. This function is similar to GNU's asprintf(). */
char *pa_sprintf_malloc(const char *format, ...) {
- size_t size = 100;
+ size_t size = 100;
char *c = NULL;
pa_assert(format);
@@ -579,7 +579,7 @@ char *pa_sprintf_malloc(const char *format, ...) {
/* Same as the previous function, but use a va_list instead of an
* ellipsis */
char *pa_vsprintf_malloc(const char *format, va_list ap) {
- size_t size = 100;
+ size_t size = 100;
char *c = NULL;
pa_assert(format);
@@ -625,6 +625,7 @@ char *pa_strlcpy(char *b, const char *s, size_t l) {
return b;
}
+#ifdef _POSIX_PRIORITY_SCHEDULING
static int set_scheduler(int rtprio) {
#ifdef HAVE_SCHED_H
struct sched_param sp;
@@ -682,6 +683,7 @@ static int set_scheduler(int rtprio) {
return -1;
}
+#endif
/* Make the current thread a realtime thread, and acquire the highest
* rtprio we can get that is less or equal the specified parameter. If
@@ -718,6 +720,7 @@ int pa_make_realtime(int rtprio) {
return -1;
}
+#ifdef HAVE_SYS_RESOURCE_H
static int set_nice(int nice_level) {
#ifdef HAVE_DBUS
DBusError error;
@@ -762,6 +765,7 @@ static int set_nice(int nice_level) {
return -1;
}
+#endif
/* Raise the priority of the current process as much as possible that
* is <= the specified nice level..*/
@@ -1044,8 +1048,7 @@ static int is_group(gid_t gid, const char *name) {
int r = -1;
errno = 0;
- if (!(group = pa_getgrgid_malloc(gid)))
- {
+ if (!(group = pa_getgrgid_malloc(gid))) {
if (!errno)
errno = ENOENT;
@@ -1111,8 +1114,7 @@ int pa_uid_in_group(uid_t uid, const char *name) {
int r = -1;
errno = 0;
- if (!(group = pa_getgrnam_malloc(name)))
- {
+ if (!(group = pa_getgrnam_malloc(name))) {
if (!errno)
errno = ENOENT;
goto finish;
@@ -1147,8 +1149,7 @@ gid_t pa_get_gid_of_group(const char *name) {
struct group *gr = NULL;
errno = 0;
- if (!(gr = pa_getgrnam_malloc(name)))
- {
+ if (!(gr = pa_getgrnam_malloc(name))) {
if (!errno)
errno = ENOENT;
goto finish;
@@ -1396,7 +1397,7 @@ char *pa_get_state_dir(void) {
/* If PULSE_STATE_PATH and PULSE_RUNTIME_PATH point to the same
* dir then this will break. */
- if (pa_make_secure_dir(d, 0700U, (uid_t) -1, (gid_t) -1) < 0) {
+ if (pa_make_secure_dir(d, 0700U, (uid_t) -1, (gid_t) -1) < 0) {
pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
pa_xfree(d);
return NULL;
@@ -1536,7 +1537,7 @@ char *pa_get_runtime_dir(void) {
if ((d = getenv("PULSE_RUNTIME_PATH"))) {
- if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0) {
+ if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0) {
pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
goto fail;
}
@@ -1547,7 +1548,7 @@ char *pa_get_runtime_dir(void) {
if (!(d = get_pulse_home()))
goto fail;
- if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0) {
+ if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0) {
pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
pa_xfree(d);
goto fail;
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index a1215bb5..358b98d7 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -74,6 +74,7 @@ typedef enum pa_core_hook {
PA_CORE_HOOK_SINK_UNLINK_POST,
PA_CORE_HOOK_SINK_STATE_CHANGED,
PA_CORE_HOOK_SINK_PROPLIST_CHANGED,
+ PA_CORE_HOOK_SINK_PORT_CHANGED,
PA_CORE_HOOK_SOURCE_NEW,
PA_CORE_HOOK_SOURCE_FIXATE,
PA_CORE_HOOK_SOURCE_PUT,
@@ -81,6 +82,7 @@ typedef enum pa_core_hook {
PA_CORE_HOOK_SOURCE_UNLINK_POST,
PA_CORE_HOOK_SOURCE_STATE_CHANGED,
PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED,
+ PA_CORE_HOOK_SOURCE_PORT_CHANGED,
PA_CORE_HOOK_SINK_INPUT_NEW,
PA_CORE_HOOK_SINK_INPUT_FIXATE,
PA_CORE_HOOK_SINK_INPUT_PUT,
@@ -111,6 +113,7 @@ typedef enum pa_core_hook {
PA_CORE_HOOK_CARD_NEW,
PA_CORE_HOOK_CARD_PUT,
PA_CORE_HOOK_CARD_UNLINK,
+ PA_CORE_HOOK_CARD_PROFILE_CHANGED,
PA_CORE_HOOK_MAX
} pa_core_hook_t;
diff --git a/src/pulsecore/cpu-arm.c b/src/pulsecore/cpu-arm.c
index 1d0d7651..0287043e 100644
--- a/src/pulsecore/cpu-arm.c
+++ b/src/pulsecore/cpu-arm.c
@@ -37,24 +37,24 @@
#if defined (__arm__) && defined (__linux__)
-#define MAX_BUFFER 4096
+#define MAX_BUFFER 4096
static char *
-get_cpuinfo_line (char *cpuinfo, const char *tag) {
+get_cpuinfo_line(char *cpuinfo, const char *tag) {
char *line, *end, *colon;
- if (!(line = strstr (cpuinfo, tag)))
+ if (!(line = strstr(cpuinfo, tag)))
return NULL;
- if (!(end = strchr (line, '\n')))
+ if (!(end = strchr(line, '\n')))
return NULL;
- if (!(colon = strchr (line, ':')))
+ if (!(colon = strchr(line, ':')))
return NULL;
if (++colon >= end)
return NULL;
- return pa_xstrndup (colon, end - colon);
+ return pa_xstrndup(colon, end - colon);
}
static char *get_cpuinfo(void) {
@@ -80,7 +80,7 @@ static char *get_cpuinfo(void) {
}
#endif /* defined (__arm__) && defined (__linux__) */
-pa_bool_t pa_cpu_init_arm (pa_cpu_arm_flag_t *flags) {
+pa_bool_t pa_cpu_init_arm(pa_cpu_arm_flag_t *flags) {
#if defined (__arm__)
#if defined (__linux__)
char *cpuinfo, *line;
@@ -88,16 +88,16 @@ pa_bool_t pa_cpu_init_arm (pa_cpu_arm_flag_t *flags) {
/* We need to read the CPU flags from /proc/cpuinfo because there is no user
* space support to get the CPU features. This only works on linux AFAIK. */
- if (!(cpuinfo = get_cpuinfo ())) {
- pa_log ("Can't read cpuinfo");
+ if (!(cpuinfo = get_cpuinfo())) {
+ pa_log("Can't read cpuinfo");
return;
}
*flags = 0;
/* get the CPU architecture */
- if ((line = get_cpuinfo_line (cpuinfo, "CPU architecture"))) {
- arch = strtoul (line, NULL, 0);
+ if ((line = get_cpuinfo_line(cpuinfo, "CPU architecture"))) {
+ arch = strtoul(line, NULL, 0);
if (arch >= 6)
*flags |= PA_CPU_ARM_V6;
if (arch >= 7)
@@ -106,18 +106,18 @@ pa_bool_t pa_cpu_init_arm (pa_cpu_arm_flag_t *flags) {
pa_xfree(line);
}
/* get the CPU features */
- if ((line = get_cpuinfo_line (cpuinfo, "Features"))) {
+ if ((line = get_cpuinfo_line(cpuinfo, "Features"))) {
const char *state = NULL;
char *current;
- while ((current = pa_split_spaces (line, &state))) {
- if (!strcmp (current, "vfp"))
+ while ((current = pa_split_spaces(line, &state))) {
+ if (!strcmp(current, "vfp"))
*flags |= PA_CPU_ARM_VFP;
- else if (!strcmp (current, "edsp"))
+ else if (!strcmp(current, "edsp"))
*flags |= PA_CPU_ARM_EDSP;
- else if (!strcmp (current, "neon"))
+ else if (!strcmp(current, "neon"))
*flags |= PA_CPU_ARM_NEON;
- else if (!strcmp (current, "vfpv3"))
+ else if (!strcmp(current, "vfpv3"))
*flags |= PA_CPU_ARM_VFPV3;
pa_xfree(current);
@@ -125,7 +125,7 @@ pa_bool_t pa_cpu_init_arm (pa_cpu_arm_flag_t *flags) {
}
pa_xfree(cpuinfo);
- pa_log_info ("CPU flags: %s%s%s%s%s%s",
+ pa_log_info("CPU flags: %s%s%s%s%s%s",
(*flags & PA_CPU_ARM_V6) ? "V6 " : "",
(*flags & PA_CPU_ARM_V7) ? "V7 " : "",
(*flags & PA_CPU_ARM_VFP) ? "VFP " : "",
@@ -134,7 +134,7 @@ pa_bool_t pa_cpu_init_arm (pa_cpu_arm_flag_t *flags) {
(*flags & PA_CPU_ARM_VFPV3) ? "VFPV3 " : "");
if (*flags & PA_CPU_ARM_V6)
- pa_volume_func_init_arm (*flags);
+ pa_volume_func_init_arm(*flags);
return TRUE;
diff --git a/src/pulsecore/cpu-orc.c b/src/pulsecore/cpu-orc.c
new file mode 100644
index 00000000..d4a15357
--- /dev/null
+++ b/src/pulsecore/cpu-orc.c
@@ -0,0 +1,34 @@
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2010 Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+ 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.
+***/
+
+#include "cpu-orc.h"
+
+void pa_cpu_init_orc(pa_cpu_info cpu_info)
+{
+#ifndef DISABLE_ORC
+ /* Update these as we test on more architectures */
+ pa_cpu_x86_flag_t x86_want_flags = PA_CPU_X86_MMX | PA_CPU_X86_SSE | PA_CPU_X86_SSE2 | PA_CPU_X86_SSE3 | PA_CPU_X86_SSSE3 | PA_CPU_X86_SSE4_1 | PA_CPU_X86_SSE4_2;
+
+ /* Enable Orc svolume optimizations */
+ if ((cpu_info.cpu_type == PA_CPU_X86) && (cpu_info.flags.x86 & x86_want_flags))
+ pa_volume_func_init_orc();
+#endif
+}
diff --git a/src/pulsecore/cpu-orc.h b/src/pulsecore/cpu-orc.h
new file mode 100644
index 00000000..9924d27b
--- /dev/null
+++ b/src/pulsecore/cpu-orc.h
@@ -0,0 +1,37 @@
+#ifndef foocpuorchfoo
+#define foocpuorchfoo
+
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2010 Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+ 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 <pulsecore/cpu.h>
+
+/* Orc-optimised bits */
+
+void pa_cpu_init_orc(pa_cpu_info cpu_info);
+
+void pa_volume_func_init_orc(void);
+
+#endif /* foocpuorchfoo */
diff --git a/src/pulsecore/cpu-x86.c b/src/pulsecore/cpu-x86.c
index 062a4c1b..05a4b2f0 100644
--- a/src/pulsecore/cpu-x86.c
+++ b/src/pulsecore/cpu-x86.c
@@ -31,9 +31,7 @@
#include "cpu-x86.h"
#if defined (__i386__) || defined (__amd64__)
-static void
-get_cpuid (uint32_t op, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
-{
+static void get_cpuid(uint32_t op, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) {
__asm__ __volatile__ (
" push %%"PA_REG_b" \n\t"
" cpuid \n\t"
@@ -46,7 +44,7 @@ get_cpuid (uint32_t op, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
}
#endif
-pa_bool_t pa_cpu_init_x86 (pa_cpu_x86_flag_t *flags) {
+pa_bool_t pa_cpu_init_x86(pa_cpu_x86_flag_t *flags) {
#if defined (__i386__) || defined (__amd64__)
uint32_t eax, ebx, ecx, edx;
uint32_t level;
@@ -54,9 +52,9 @@ pa_bool_t pa_cpu_init_x86 (pa_cpu_x86_flag_t *flags) {
*flags = 0;
/* get standard level */
- get_cpuid (0x00000000, &level, &ebx, &ecx, &edx);
+ get_cpuid(0x00000000, &level, &ebx, &ecx, &edx);
if (level >= 1) {
- get_cpuid (0x00000001, &eax, &ebx, &ecx, &edx);
+ get_cpuid(0x00000001, &eax, &ebx, &ecx, &edx);
if (edx & (1<<15))
*flags |= PA_CPU_X86_CMOV;
@@ -84,9 +82,9 @@ pa_bool_t pa_cpu_init_x86 (pa_cpu_x86_flag_t *flags) {
}
/* get extended level */
- get_cpuid (0x80000000, &level, &ebx, &ecx, &edx);
+ get_cpuid(0x80000000, &level, &ebx, &ecx, &edx);
if (level >= 0x80000001) {
- get_cpuid (0x80000001, &eax, &ebx, &ecx, &edx);
+ get_cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
if (edx & (1<<22))
*flags |= PA_CPU_X86_MMXEXT;
@@ -101,7 +99,7 @@ pa_bool_t pa_cpu_init_x86 (pa_cpu_x86_flag_t *flags) {
*flags |= PA_CPU_X86_3DNOW;
}
- pa_log_info ("CPU flags: %s%s%s%s%s%s%s%s%s%s%s",
+ pa_log_info("CPU flags: %s%s%s%s%s%s%s%s%s%s%s",
(*flags & PA_CPU_X86_CMOV) ? "CMOV " : "",
(*flags & PA_CPU_X86_MMX) ? "MMX " : "",
(*flags & PA_CPU_X86_SSE) ? "SSE " : "",
@@ -116,14 +114,14 @@ pa_bool_t pa_cpu_init_x86 (pa_cpu_x86_flag_t *flags) {
/* activate various optimisations */
if (*flags & PA_CPU_X86_MMX) {
- pa_volume_func_init_mmx (*flags);
- pa_remap_func_init_mmx (*flags);
+ pa_volume_func_init_mmx(*flags);
+ pa_remap_func_init_mmx(*flags);
}
if (*flags & (PA_CPU_X86_SSE | PA_CPU_X86_SSE2)) {
- pa_volume_func_init_sse (*flags);
- pa_remap_func_init_sse (*flags);
- pa_convert_func_init_sse (*flags);
+ pa_volume_func_init_sse(*flags);
+ pa_remap_func_init_sse(*flags);
+ pa_convert_func_init_sse(*flags);
}
return TRUE;
diff --git a/src/pulsecore/database-simple.c b/src/pulsecore/database-simple.c
index 754930db..237d0bdd 100644
--- a/src/pulsecore/database-simple.c
+++ b/src/pulsecore/database-simple.c
@@ -429,7 +429,7 @@ static int write_uint(FILE *f, const uint32_t num) {
errno = 0;
for (i = 0; i < 4; i++)
- values[i] = (num >> (i*8)) & 0xFF;
+ values[i] = (num >> (i*8)) & 0xFF;
items = fwrite(&values, sizeof(values), sizeof(uint8_t), f);
diff --git a/src/pulsecore/envelope.c b/src/pulsecore/envelope.c
deleted file mode 100644
index 75e189cb..00000000
--- a/src/pulsecore/envelope.c
+++ /dev/null
@@ -1,989 +0,0 @@
-/***
- This file is part of PulseAudio.
-
- Copyright 2007 Lennart Poettering
-
- 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
- Lesser 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 <stdio.h>
-
-#include <pulse/sample.h>
-#include <pulse/xmalloc.h>
-
-#include <pulsecore/endianmacros.h>
-#include <pulsecore/memchunk.h>
-#include <pulsecore/macro.h>
-#include <pulsecore/flist.h>
-#include <pulsecore/semaphore.h>
-#include <pulsecore/g711.h>
-
-#include "envelope.h"
-
-/*
- Envelope subsystem for applying linear interpolated volume
- envelopes on audio data. If multiple enevelopes shall be applied
- at the same time, the "minimum" envelope is determined and
- applied.
-
- Envelopes are defined in a statically allocated constant structure
- pa_envelope_def. It may be activated using pa_envelope_add(). And
- already active envelope may be replaced with pa_envelope_replace()
- and removed with pa_envelope_remove().The combined "minimum"
- envelope can be applied to audio data with pa_envelope_apply().
-
- _apply() on one hand and _add()/_replace()/_remove() on the other
- can be executed in seperate threads, in which case no locking is
- used.
-*/
-
-PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree);
-
-struct pa_envelope_item {
- PA_LLIST_FIELDS(pa_envelope_item);
- const pa_envelope_def *def;
- pa_usec_t start_x;
- union {
- int32_t i;
- float f;
- } start_y;
- unsigned j;
-};
-
-enum envelope_state {
- STATE_VALID0,
- STATE_VALID1,
- STATE_READ0,
- STATE_READ1,
- STATE_WAIT0,
- STATE_WAIT1,
- STATE_WRITE0,
- STATE_WRITE1
-};
-
-struct pa_envelope {
- pa_sample_spec sample_spec;
-
- PA_LLIST_HEAD(pa_envelope_item, items);
-
- pa_atomic_t state;
-
- size_t x;
-
- struct {
- unsigned n_points, n_allocated, n_current;
-
- size_t *x;
- union {
- int32_t *i;
- float *f;
- } y;
-
- size_t cached_dx;
- int32_t cached_dy_i;
- float cached_dy_dx;
- pa_bool_t cached_valid;
- } points[2];
-
- pa_bool_t is_float;
-
- pa_semaphore *semaphore;
-};
-
-pa_envelope *pa_envelope_new(const pa_sample_spec *ss) {
- pa_envelope *e;
- pa_assert(ss);
-
- e = pa_xnew(pa_envelope, 1);
-
- e->sample_spec = *ss;
- PA_LLIST_HEAD_INIT(pa_envelope_item, e->items);
-
- e->x = 0;
-
- e->points[0].n_points = e->points[1].n_points = 0;
- e->points[0].n_allocated = e->points[1].n_allocated = 0;
- e->points[0].n_current = e->points[1].n_current = 0;
- e->points[0].x = e->points[1].x = NULL;
- e->points[0].y.i = e->points[1].y.i = NULL;
- e->points[0].cached_valid = e->points[1].cached_valid = FALSE;
-
- pa_atomic_store(&e->state, STATE_VALID0);
-
- e->is_float =
- ss->format == PA_SAMPLE_FLOAT32LE ||
- ss->format == PA_SAMPLE_FLOAT32BE;
-
- e->semaphore = pa_semaphore_new(0);
-
- return e;
-}
-
-void pa_envelope_free(pa_envelope *e) {
- pa_assert(e);
-
- while (e->items)
- pa_envelope_remove(e, e->items);
-
- pa_xfree(e->points[0].x);
- pa_xfree(e->points[1].x);
- pa_xfree(e->points[0].y.i);
- pa_xfree(e->points[1].y.i);
-
- pa_semaphore_free(e->semaphore);
-
- pa_xfree(e);
-}
-
-static int32_t linear_interpolate_int(pa_usec_t x1, int32_t _y1, pa_usec_t x2, int32_t y2, pa_usec_t x3) {
- return (int32_t) ((double) _y1 + (double) (x3 - x1) * (double) (y2 - _y1) / (double) (x2 - x1));
-}
-
-static float linear_interpolate_float(pa_usec_t x1, float _y1, pa_usec_t x2, float y2, pa_usec_t x3) {
- return _y1 + ((float) x3 - (float) x1) * (y2 - _y1) / ((float) x2 - (float) x1);
-}
-
-static int32_t item_get_int(pa_envelope_item *i, pa_usec_t x) {
- pa_assert(i);
-
- if (x <= i->start_x)
- return i->start_y.i;
-
- x -= i->start_x;
-
- if (x <= i->def->points_x[0])
- return linear_interpolate_int(0, i->start_y.i,
- i->def->points_x[0], i->def->points_y.i[0], x);
-
- if (x >= i->def->points_x[i->def->n_points-1])
- return i->def->points_y.i[i->def->n_points-1];
-
- pa_assert(i->j > 0);
- pa_assert(i->def->points_x[i->j-1] <= x);
- 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);
-}
-
-static float item_get_float(pa_envelope_item *i, pa_usec_t x) {
- pa_assert(i);
-
- if (x <= i->start_x)
- return i->start_y.f;
-
- x -= i->start_x;
-
- if (x <= i->def->points_x[0])
- return linear_interpolate_float(0, i->start_y.f,
- i->def->points_x[0], i->def->points_y.f[0], x);
-
- if (x >= i->def->points_x[i->def->n_points-1])
- return i->def->points_y.f[i->def->n_points-1];
-
- pa_assert(i->j > 0);
- pa_assert(i->def->points_x[i->j-1] <= x);
- 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);
-}
-
-static void envelope_begin_write(pa_envelope *e, int *v) {
- enum envelope_state new_state, old_state;
- pa_bool_t wait_sem;
-
- pa_assert(e);
- pa_assert(v);
-
- for (;;) {
- do {
- wait_sem = FALSE;
- old_state = pa_atomic_load(&e->state);
-
- switch (old_state) {
- case STATE_VALID0:
- *v = 1;
- new_state = STATE_WRITE0;
- break;
- case STATE_VALID1:
- *v = 0;
- new_state = STATE_WRITE1;
- break;
- case STATE_READ0:
- new_state = STATE_WAIT0;
- wait_sem = TRUE;
- break;
- case STATE_READ1:
- new_state = STATE_WAIT1;
- wait_sem = TRUE;
- break;
- default:
- pa_assert_not_reached();
- }
- } while (!pa_atomic_cmpxchg(&e->state, old_state, new_state));
-
- if (!wait_sem)
- break;
-
- pa_semaphore_wait(e->semaphore);
- }
-}
-
-static pa_bool_t envelope_commit_write(pa_envelope *e, int v) {
- enum envelope_state new_state, old_state;
-
- pa_assert(e);
-
- do {
- old_state = pa_atomic_load(&e->state);
-
- switch (old_state) {
- case STATE_WRITE0:
- pa_assert(v == 1);
- new_state = STATE_VALID1;
- break;
- case STATE_WRITE1:
- pa_assert(v == 0);
- new_state = STATE_VALID0;
- break;
- case STATE_VALID0:
- case STATE_VALID1:
- case STATE_READ0:
- case STATE_READ1:
- return FALSE;
- default:
- pa_assert_not_reached();
- }
- } while (!pa_atomic_cmpxchg(&e->state, old_state, new_state));
-
- return TRUE;
-}
-
-static void envelope_begin_read(pa_envelope *e, int *v) {
- enum envelope_state new_state, old_state;
- pa_assert(e);
- pa_assert(v);
-
- do {
- old_state = pa_atomic_load(&e->state);
-
- switch (old_state) {
- case STATE_VALID0:
- case STATE_WRITE0:
- *v = 0;
- new_state = STATE_READ0;
- break;
- case STATE_VALID1:
- case STATE_WRITE1:
- *v = 1;
- new_state = STATE_READ1;
- break;
- default:
- pa_assert_not_reached();
- }
- } while (!pa_atomic_cmpxchg(&e->state, old_state, new_state));
-}
-
-static void envelope_commit_read(pa_envelope *e, int v) {
- enum envelope_state new_state, old_state;
- pa_bool_t post_sem;
-
- pa_assert(e);
-
- do {
- post_sem = FALSE;
- old_state = pa_atomic_load(&e->state);
-
- switch (old_state) {
- case STATE_READ0:
- pa_assert(v == 0);
- new_state = STATE_VALID0;
- break;
- case STATE_READ1:
- pa_assert(v == 1);
- new_state = STATE_VALID1;
- break;
- case STATE_WAIT0:
- pa_assert(v == 0);
- new_state = STATE_VALID0;
- post_sem = TRUE;
- break;
- case STATE_WAIT1:
- pa_assert(v == 1);
- new_state = STATE_VALID1;
- post_sem = TRUE;
- break;
- default:
- pa_assert_not_reached();
- }
- } while (!pa_atomic_cmpxchg(&e->state, old_state, new_state));
-
- if (post_sem)
- pa_semaphore_post(e->semaphore);
-}
-
-static void envelope_merge(pa_envelope *e, int v) {
-
- e->points[v].n_points = 0;
-
- if (e->items) {
- pa_envelope_item *i;
- pa_usec_t x = (pa_usec_t) -1;
-
- for (i = e->items; i; i = i->next)
- i->j = 0;
-
- for (;;) {
- pa_bool_t min_is_set;
- pa_envelope_item *s = NULL;
-
- /* Let's find the next spot on the X axis to analyze */
- for (i = e->items; i; i = i->next) {
-
- for (;;) {
-
- if (i->j >= i->def->n_points)
- break;
-
- if ((x != (pa_usec_t) -1) && i->start_x + i->def->points_x[i->j] <= x) {
- i->j++;
- continue;
- }
-
- if (!s || (i->start_x + i->def->points_x[i->j] < s->start_x + s->def->points_x[s->j]))
- s = i;
-
- break;
- }
- }
-
- if (!s)
- break;
-
- if (e->points[v].n_points >= e->points[v].n_allocated) {
- e->points[v].n_allocated = PA_MAX(e->points[v].n_points*2, PA_ENVELOPE_POINTS_MAX);
-
- e->points[v].x = pa_xrealloc(e->points[v].x, sizeof(size_t) * e->points[v].n_allocated);
- e->points[v].y.i = pa_xrealloc(e->points[v].y.i, sizeof(int32_t) * e->points[v].n_allocated);
- }
-
- x = s->start_x + s->def->points_x[s->j];
- e->points[v].x[e->points[v].n_points] = pa_usec_to_bytes(x, &e->sample_spec);
-
- min_is_set = FALSE;
-
- /* Now let's find the lowest value */
- if (e->is_float) {
- float min_f;
-
- for (i = e->items; i; i = i->next) {
- float f = item_get_float(i, x);
- if (!min_is_set || f < min_f) {
- min_f = f;
- min_is_set = TRUE;
- }
- }
-
- e->points[v].y.f[e->points[v].n_points] = min_f;
- } else {
- int32_t min_k;
-
- for (i = e->items; i; i = i->next) {
- int32_t k = item_get_int(i, x);
- if (!min_is_set || k < min_k) {
- min_k = k;
- min_is_set = TRUE;
- }
- }
-
- e->points[v].y.i[e->points[v].n_points] = min_k;
- }
-
- pa_assert_se(min_is_set);
- e->points[v].n_points++;
- }
- }
-
- e->points[v].n_current = 0;
- e->points[v].cached_valid = FALSE;
-}
-
-pa_envelope_item *pa_envelope_add(pa_envelope *e, const pa_envelope_def *def) {
- pa_envelope_item *i;
- int v;
-
- pa_assert(e);
- pa_assert(def);
- pa_assert(def->n_points > 0);
-
- if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items))))
- i = pa_xnew(pa_envelope_item, 1);
-
- i->def = def;
-
- if (e->is_float)
- i->start_y.f = def->points_y.f[0];
- else
- i->start_y.i = def->points_y.i[0];
-
- PA_LLIST_PREPEND(pa_envelope_item, e->items, i);
-
- envelope_begin_write(e, &v);
-
- do {
-
- i->start_x = pa_bytes_to_usec(e->x, &e->sample_spec);
- envelope_merge(e, v);
-
- } while (!envelope_commit_write(e, v));
-
- return i;
-}
-
-pa_envelope_item *pa_envelope_replace(pa_envelope *e, pa_envelope_item *i, const pa_envelope_def *def) {
- pa_usec_t x;
- int v;
-
- pa_assert(e);
- pa_assert(i);
- pa_assert(def->n_points > 0);
-
- envelope_begin_write(e, &v);
-
- for (;;) {
- float saved_f;
- int32_t saved_i;
- uint64_t saved_start_x;
- const pa_envelope_def *saved_def;
-
- x = pa_bytes_to_usec(e->x, &e->sample_spec);
-
- if (e->is_float) {
- saved_f = i->start_y.f;
- i->start_y.f = item_get_float(i, x);
- } else {
- saved_i = i->start_y.i;
- i->start_y.i = item_get_int(i, x);
- }
-
- saved_start_x = i->start_x;
- saved_def = i->def;
-
- i->start_x = x;
- i->def = def;
-
- envelope_merge(e, v);
-
- if (envelope_commit_write(e, v))
- break;
-
- i->start_x = saved_start_x;
- i->def = saved_def;
-
- if (e->is_float)
- i->start_y.f = saved_f;
- else
- i->start_y.i = saved_i;
- }
-
- return i;
-}
-
-void pa_envelope_remove(pa_envelope *e, pa_envelope_item *i) {
- int v;
-
- pa_assert(e);
- pa_assert(i);
-
- PA_LLIST_REMOVE(pa_envelope_item, e->items, i);
-
- if (pa_flist_push(PA_STATIC_FLIST_GET(items), i) < 0)
- pa_xfree(i);
-
- envelope_begin_write(e, &v);
- do {
- envelope_merge(e, v);
- } while (!envelope_commit_write(e, v));
-}
-
-static int32_t linear_get_int(pa_envelope *e, int v) {
- pa_assert(e);
-
- /* The repeated division could be replaced by Bresenham, as an
- * optimization */
-
- if (e->x < e->points[v].x[0])
- return e->points[v].y.i[0];
-
- for (;;) {
- if (e->points[v].n_current+1 >= e->points[v].n_points)
- return e->points[v].y.i[e->points[v].n_points-1];
-
- if (e->x < e->points[v].x[e->points[v].n_current+1])
- break;
-
- e->points[v].n_current++;
- e->points[v].cached_valid = FALSE;
- }
-
- if (!e->points[v].cached_valid) {
- e->points[v].cached_dx = e->points[v].x[e->points[v].n_current+1] - e->points[v].x[e->points[v].n_current];
- e->points[v].cached_dy_i = e->points[v].y.i[e->points[v].n_current+1] - e->points[v].y.i[e->points[v].n_current];
- e->points[v].cached_valid = TRUE;
- }
-
- 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) {
- pa_assert(e);
-
- if (e->x < e->points[v].x[0])
- return e->points[v].y.f[0];
-
- for (;;) {
- if (e->points[v].n_current+1 >= e->points[v].n_points)
- return e->points[v].y.f[e->points[v].n_points-1];
-
- if (e->x < e->points[v].x[e->points[v].n_current+1])
- break;
-
- e->points[v].n_current++;
- e->points[v].cached_valid = FALSE;
- }
-
- if (!e->points[v].cached_valid) {
- e->points[v].cached_dy_dx =
- (e->points[v].y.f[e->points[v].n_current+1] - e->points[v].y.f[e->points[v].n_current]) /
- ((float) e->points[v].x[e->points[v].n_current+1] - (float) e->points[v].x[e->points[v].n_current]);
- e->points[v].cached_valid = TRUE;
- }
-
- return e->points[v].y.f[e->points[v].n_current] + (float) (e->x - e->points[v].x[e->points[v].n_current]) * e->points[v].cached_dy_dx;
-}
-
-void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) {
- int v;
-
- pa_assert(e);
- pa_assert(chunk);
-
- envelope_begin_read(e, &v);
-
- if (e->points[v].n_points > 0) {
- void *p;
- size_t fs, n;
-
- pa_memchunk_make_writable(chunk, 0);
- p = (uint8_t*) pa_memblock_acquire(chunk->memblock) + chunk->index;
- fs = pa_frame_size(&e->sample_spec);
- n = chunk->length;
-
- pa_log_debug("Envelop position %zu applying factor %d=%f, sample spec is %d, chunk's length is %zu, fs is %zu\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 *d, *s;
- unsigned channel;
- int32_t factor = linear_get_int(e, v);
-
- s = (uint8_t*) p + n;
-
- 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 *d, *s;
- unsigned channel;
- int32_t factor = linear_get_int(e, v);
-
- s = (uint8_t*) p + n;
-
- 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);
- }
- }
-
- break;
- }
-
- case PA_SAMPLE_ALAW: {
- uint8_t *d, *s;
- unsigned channel;
- int32_t factor = linear_get_int(e, v);
-
- s = (uint8_t*) p + n;
-
- 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);
- }
- }
-
- break;
- }
-
- case PA_SAMPLE_S16NE: {
- int16_t *d, *s;
- unsigned channel;
- int32_t factor = linear_get_int(e, v);
-
- s = (int16_t*) p + n/sizeof(int16_t);
-
- 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 *d, *s;
- unsigned channel;
- int32_t factor = linear_get_int(e, v);
-
- s = (int16_t*) p + n/sizeof(int16_t);
-
- 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);
- }
- }
-
- break;
- }
-
- case PA_SAMPLE_S32NE: {
- int32_t *d, *s;
- unsigned channel;
- int32_t factor = linear_get_int(e, v);
-
- s = (int32_t*) p + n/sizeof(int32_t);
-
- 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 *d, *s;
- unsigned channel;
- int32_t factor = linear_get_int(e, v);
-
- s = (int32_t*) p + n/sizeof(int32_t);
-
- 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);
- }
- }
-
- break;
- }
-
- 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) {
- float factor = linear_get_float(e, v);
- unsigned c;
- e->x += fs;
-
- for (c = 0; c < e->sample_spec.channels; c++, t++)
- *t = *t * factor;
- }
-
- break;
- }
-
- 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) {
- float factor = linear_get_float(e, v);
- unsigned c;
- e->x += fs;
-
- for (c = 0; c < e->sample_spec.channels; c++, t++) {
- float r = PA_FLOAT32_SWAP(*t) * factor;
- *t = PA_FLOAT32_SWAP(r);
- }
- }
-
- break;
- }
-
- 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();
-
- case PA_SAMPLE_MAX:
- case PA_SAMPLE_INVALID:
- pa_assert_not_reached();
- }
-
- pa_memblock_release(chunk->memblock);
- } else {
- /* When we have no envelope to apply we reset our origin */
- e->x = 0;
- }
-
- envelope_commit_read(e, v);
-}
-
-void pa_envelope_rewind(pa_envelope *e, size_t n_bytes) {
- int v;
-
- pa_assert(e);
-
- envelope_begin_read(e, &v);
-
- if (e->x - n_bytes <= e->points[v].x[0])
- e->x = e->points[v].x[0];
- else
- 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) {
- int v;
- pa_bool_t finished;
-
- pa_assert(e);
- 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) {
- int v;
- size_t size;
-
- pa_assert(e);
- 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
deleted file mode 100644
index 4fa36579..00000000
--- a/src/pulsecore/envelope.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef foopulseenvelopehfoo
-#define foopulseenvelopehfoo
-
-/***
- This file is part of PulseAudio.
-
- Copyright 2007 Lennart Poettering
-
- 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
- Lesser 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.
-***/
-
-#include <pulsecore/macro.h>
-#include <pulsecore/memchunk.h>
-
-#include <pulse/sample.h>
-
-#define PA_ENVELOPE_POINTS_MAX 4U
-
-typedef struct pa_envelope pa_envelope;
-typedef struct pa_envelope_item pa_envelope_item;
-
-typedef struct pa_envelope_def {
- unsigned n_points;
-
- pa_usec_t points_x[PA_ENVELOPE_POINTS_MAX];
- struct {
- int32_t i[PA_ENVELOPE_POINTS_MAX];
- float f[PA_ENVELOPE_POINTS_MAX];
- } points_y;
-} pa_envelope_def;
-
-pa_envelope *pa_envelope_new(const pa_sample_spec *ss);
-void pa_envelope_free(pa_envelope *e);
-pa_envelope_item *pa_envelope_add(pa_envelope *e, const pa_envelope_def *def);
-pa_envelope_item *pa_envelope_replace(pa_envelope *e, pa_envelope_item *i, const pa_envelope_def *def);
-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/ipacl.c b/src/pulsecore/ipacl.c
index 3930ba61..5455d0e8 100644
--- a/src/pulsecore/ipacl.c
+++ b/src/pulsecore/ipacl.c
@@ -169,7 +169,7 @@ void pa_ip_acl_free(pa_ip_acl *acl) {
int pa_ip_acl_check(pa_ip_acl *acl, int fd) {
struct sockaddr_storage sa;
struct acl_entry *e;
- socklen_t salen;
+ socklen_t salen;
pa_assert(acl);
pa_assert(fd >= 0);
@@ -206,7 +206,7 @@ int pa_ip_acl_check(pa_ip_acl *acl, int fd) {
return 1;
#ifdef HAVE_IPV6
} else if (e->family == AF_INET6) {
- int i, bits ;
+ int i, bits;
struct sockaddr_in6 *sai = (struct sockaddr_in6*) &sa;
if (e->bits == 128)
diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c
index 2c0e267a..b12cbf0c 100644
--- a/src/pulsecore/log.c
+++ b/src/pulsecore/log.c
@@ -70,6 +70,7 @@ static pa_log_level_t maximum_level = PA_LOG_ERROR, maximum_level_override = PA_
static unsigned show_backtrace = 0, show_backtrace_override = 0, skip_backtrace = 0;
static pa_log_flags_t flags = 0, flags_override = 0;
static pa_bool_t no_rate_limit = FALSE;
+static int log_fd = -1;
#ifdef HAVE_SYSLOG_H
static const int level_to_syslog[] = {
@@ -128,6 +129,15 @@ void pa_log_set_flags(pa_log_flags_t _flags, pa_log_merge_t merge) {
flags = _flags;
}
+void pa_log_set_fd(int fd) {
+ if (fd >= 0)
+ log_fd = fd;
+ else if (log_fd >= 0) {
+ pa_close(log_fd);
+ log_fd = -1;
+ }
+}
+
void pa_log_set_show_backtrace(unsigned nlevels) {
show_backtrace = nlevels;
}
@@ -399,6 +409,23 @@ void pa_log_levelv_meta(
}
#endif
+ case PA_LOG_FD: {
+ if (log_fd >= 0) {
+ char metadata[256];
+
+ pa_snprintf(metadata, sizeof(metadata), "\n%c %s %s", level_to_char[level], timestamp, location);
+
+ if ((write(log_fd, metadata, strlen(metadata)) < 0) || (write(log_fd, t, strlen(t)) < 0)) {
+ saved_errno = errno;
+ pa_log_set_fd(-1);
+ fprintf(stderr, "%s\n", "Error writing logs to a file descriptor. Redirect log messages to console.");
+ fprintf(stderr, "%s %s\n", metadata, t);
+ pa_log_set_target(PA_LOG_STDERR);
+ }
+ }
+
+ break;
+ }
case PA_LOG_NULL:
default:
break;
diff --git a/src/pulsecore/log.h b/src/pulsecore/log.h
index 1fd38d44..ad04e7bd 100644
--- a/src/pulsecore/log.h
+++ b/src/pulsecore/log.h
@@ -36,6 +36,7 @@ typedef enum pa_log_target {
PA_LOG_STDERR, /* default */
PA_LOG_SYSLOG,
PA_LOG_NULL, /* to /dev/null */
+ PA_LOG_FD, /* to a file descriptor, e.g. a char device */
PA_LOG_TARGET_MAX
} pa_log_target_t;
@@ -74,6 +75,10 @@ void pa_log_set_level(pa_log_level_t l);
/* Set flags */
void pa_log_set_flags(pa_log_flags_t flags, pa_log_merge_t merge);
+/* Set the file descriptor of the logging device.
+ Daemon conf is in charge of opening this device */
+void pa_log_set_fd(int fd);
+
/* Enable backtrace */
void pa_log_set_show_backtrace(unsigned nlevels);
diff --git a/src/pulsecore/ltdl-helper.c b/src/pulsecore/ltdl-helper.c
index be200ca2..1a0e5558 100644
--- a/src/pulsecore/ltdl-helper.c
+++ b/src/pulsecore/ltdl-helper.c
@@ -42,7 +42,7 @@ pa_void_func_t pa_load_sym(lt_dlhandle handle, const char *module, const char *s
pa_assert(handle);
pa_assert(symbol);
- *(void**) &f = lt_dlsym(handle, symbol);
+ f = (pa_void_func_t) lt_dlsym(handle, symbol);
if (f)
return f;
@@ -59,7 +59,7 @@ pa_void_func_t pa_load_sym(lt_dlhandle handle, const char *module, const char *s
if (!isalnum(*c))
*c = '_';
- *(void**) &f = lt_dlsym(handle, sn);
+ f = (pa_void_func_t) lt_dlsym(handle, sn);
pa_xfree(sn);
return f;
diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c
index 454900d1..bc804577 100644
--- a/src/pulsecore/memblock.c
+++ b/src/pulsecore/memblock.c
@@ -82,7 +82,7 @@ struct pa_memblock {
pa_free_cb_t free_cb;
} user;
- struct {
+ struct {
uint32_t id;
pa_memimport_segment *segment;
} imported;
@@ -531,9 +531,7 @@ static void memblock_free(pa_memblock *b) {
pa_mutex_lock(import->mutex);
- pa_assert_se(pa_hashmap_remove(
- import->blocks,
- PA_UINT32_TO_PTR(b->per_type.imported.id)));
+ pa_assert_se(pa_hashmap_remove(import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id)));
pa_assert(segment->n_blocks >= 1);
if (-- segment->n_blocks <= 0)
@@ -693,9 +691,7 @@ static void memblock_replace_import(pa_memblock *b) {
pa_mutex_lock(import->mutex);
- pa_assert_se(pa_hashmap_remove(
- import->blocks,
- PA_UINT32_TO_PTR(b->per_type.imported.id)));
+ pa_assert_se(pa_hashmap_remove(import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id)));
memblock_make_local(b);
diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c
index 11faedac..c76ca841 100644
--- a/src/pulsecore/memblockq.c
+++ b/src/pulsecore/memblockq.c
@@ -376,8 +376,8 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
size_t d;
pa_assert(bq->write_index + (int64_t)chunk.length > q->index &&
- bq->write_index + (int64_t)chunk.length < q->index + (int64_t)q->chunk.length &&
- bq->write_index < q->index);
+ bq->write_index + (int64_t)chunk.length < q->index + (int64_t)q->chunk.length &&
+ bq->write_index < q->index);
/* The job overwrites the current entry at the end, so let's drop the beginning of this entry */
diff --git a/src/pulsecore/memtrap.c b/src/pulsecore/memtrap.c
index b56d806a..4df1fb71 100644
--- a/src/pulsecore/memtrap.c
+++ b/src/pulsecore/memtrap.c
@@ -67,11 +67,11 @@ pa_bool_t pa_memtrap_is_good(pa_memtrap *m) {
return !pa_atomic_load(&m->bad);
}
+#ifdef HAVE_SIGACTION
static void sigsafe_error(const char *s) {
(void) write(STDERR_FILENO, s, strlen(s));
}
-#ifdef HAVE_SIGACTION
static void signal_handler(int sig, siginfo_t* si, void *data) {
unsigned j;
pa_memtrap *m;
diff --git a/src/pulsecore/modargs.c b/src/pulsecore/modargs.c
index e78cdb9a..3106775f 100644
--- a/src/pulsecore/modargs.c
+++ b/src/pulsecore/modargs.c
@@ -124,7 +124,7 @@ pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) {
key_len++;
break;
- case VALUE_START:
+ case VALUE_START:
if (*p == '\'') {
state = VALUE_TICKS;
value = p+1;
diff --git a/src/pulsecore/module.c b/src/pulsecore/module.c
index 74e94da4..1b1e1126 100644
--- a/src/pulsecore/module.c
+++ b/src/pulsecore/module.c
@@ -110,7 +110,7 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) {
m->unload_requested = FALSE;
if (m->init(m) < 0) {
- pa_log_error("Failed to load module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : "");
+ pa_log_error("Failed to load module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : "");
goto fail;
}
diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c
index 0d6da3ee..f075a5bf 100644
--- a/src/pulsecore/play-memblockq.c
+++ b/src/pulsecore/play-memblockq.c
@@ -135,6 +135,12 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
return -1;
}
+ /* FIXME: u->memblockq doesn't have a silence memchunk set, so
+ * pa_memblockq_peek() will return 0 without returning any memblock if the
+ * read index points to a hole. If the memblockq is rewound beyond index 0,
+ * then there will be a hole. */
+ pa_assert(chunk->memblock);
+
chunk->length = PA_MIN(chunk->length, nbytes);
pa_memblockq_drop(u->memblockq, chunk->length);
diff --git a/src/pulsecore/poll.c b/src/pulsecore/poll.c
index b993c478..df4feb01 100644
--- a/src/pulsecore/poll.c
+++ b/src/pulsecore/poll.c
@@ -105,7 +105,7 @@ int pa_poll (struct pollfd *fds, unsigned long int nfds, int timeout) {
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
- ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset,
+ ready = select((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset,
SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset,
SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv));
@@ -160,7 +160,7 @@ int pa_poll (struct pollfd *fds, unsigned long int nfds, int timeout) {
/* Linux alters the tv struct... but it shouldn't matter here ...
* as we're going to be a little bit out anyway as we've just eaten
* more than a couple of cpu cycles above */
- ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset,
+ ready = select((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset,
SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset,
SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv));
}
diff --git a/src/pulsecore/poll.h b/src/pulsecore/poll.h
index a137d974..dc741e5e 100644
--- a/src/pulsecore/poll.h
+++ b/src/pulsecore/poll.h
@@ -43,12 +43,11 @@
#define POLLNVAL 0x020 /* Invalid polling request. */
/* Data structure describing a polling request. */
-struct pollfd
- {
+struct pollfd {
int fd; /* File descriptor to poll. */
short int events; /* Types of events poller cares about. */
short int revents; /* Types of events that actually occurred. */
- };
+};
/* Poll the file descriptors described by the NFDS structures starting at
@@ -62,5 +61,5 @@ struct pollfd
#if defined(HAVE_POLL_H) && !defined(OS_IS_DARWIN)
#define pa_poll(fds,nfds,timeout) poll((fds),(nfds),(timeout))
#else
-int pa_poll (struct pollfd *fds, unsigned long nfds, int timeout);
+int pa_poll(struct pollfd *fds, unsigned long nfds, int timeout);
#endif
diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c
index 045c5c95..66fd73c8 100644
--- a/src/pulsecore/protocol-esound.c
+++ b/src/pulsecore/protocol-esound.c
@@ -55,8 +55,7 @@
#include <pulsecore/macro.h>
#include <pulsecore/thread-mq.h>
#include <pulsecore/shared.h>
-
-#include "endianmacros.h"
+#include <pulsecore/endianmacros.h>
#include "protocol-esound.h"
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index cc6a6b1d..bb4be726 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -1293,7 +1293,7 @@ static void native_connection_send_memblock(pa_native_connection *c) {
else if (start == c->rrobin_index)
return;
- if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
+ if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
pa_memchunk schunk = chunk;
if (schunk.length > r->buffer_attr.fragsize)
@@ -1387,7 +1387,7 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int
/* If more data is in queue, we rewind later instead. */
if (s->seek_windex != -1)
- windex = PA_MIN(windex, s->seek_windex);
+ windex = PA_MIN(windex, s->seek_windex);
if (pa_atomic_dec(&s->seek_or_post_in_queue) > 1)
s->seek_windex = windex;
else {
@@ -1406,7 +1406,7 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int
pa_sink_input *isync;
void (*func)(pa_memblockq *bq);
- switch (code) {
+ switch (code) {
case SINK_INPUT_MESSAGE_FLUSH:
func = flush_write_no_account;
break;
@@ -1918,7 +1918,7 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u
if (name)
pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
- if (c->version >= 12) {
+ if (c->version >= 12) {
/* Since 0.9.8 the user can ask for a couple of additional flags */
if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
@@ -2009,14 +2009,14 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u
}
flags =
- (corked ? PA_SINK_INPUT_START_CORKED : 0) |
- (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
- (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
- (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
- (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
- (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
- (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
- (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
+ (corked ? PA_SINK_INPUT_START_CORKED : 0) |
+ (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
+ (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
+ (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
+ (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
+ (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
+ (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
+ (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
(dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
(fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0) |
(passthrough ? PA_SINK_INPUT_PASSTHROUGH : 0);
@@ -2185,7 +2185,7 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin
if (name)
pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
- if (c->version >= 12) {
+ if (c->version >= 12) {
/* Since 0.9.8 the user can ask for a couple of additional flags */
if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
@@ -2266,14 +2266,14 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin
}
flags =
- (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
- (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
- (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
- (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
- (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
- (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
- (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
- (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
+ (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
+ (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
+ (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
+ (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
+ (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
+ (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
+ (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
+ (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
(dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
(fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0);
@@ -2902,7 +2902,7 @@ static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sin
PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
PA_TAG_USEC, pa_sink_get_latency(sink),
PA_TAG_STRING, sink->driver,
- PA_TAG_U32, sink->flags,
+ PA_TAG_U32, sink->flags & ~PA_SINK_SHARE_VOLUME_WITH_MASTER,
PA_TAG_INVALID);
if (c->version >= 13) {
@@ -3056,12 +3056,19 @@ static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t,
pa_sample_spec fixed_ss;
pa_usec_t sink_latency;
pa_cvolume v;
+ pa_bool_t has_volume = FALSE;
pa_assert(t);
pa_sink_input_assert_ref(s);
fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
+ has_volume = pa_sink_input_is_volume_readable(s);
+ if (has_volume)
+ pa_sink_input_get_volume(s, &v, TRUE);
+ else
+ pa_cvolume_reset(&v, fixed_ss.channels);
+
pa_tagstruct_putu32(t, s->index);
pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
@@ -3069,7 +3076,7 @@ static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t,
pa_tagstruct_putu32(t, s->sink->index);
pa_tagstruct_put_sample_spec(t, &fixed_ss);
pa_tagstruct_put_channel_map(t, &s->channel_map);
- pa_tagstruct_put_cvolume(t, pa_sink_input_get_volume(s, &v, TRUE));
+ pa_tagstruct_put_cvolume(t, &v);
pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
pa_tagstruct_put_usec(t, sink_latency);
pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
@@ -3080,6 +3087,10 @@ static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t,
pa_tagstruct_put_proplist(t, s->proplist);
if (c->version >= 19)
pa_tagstruct_put_boolean(t, (pa_sink_input_get_state(s) == PA_SINK_INPUT_CORKED));
+ if (c->version >= 20) {
+ pa_tagstruct_put_boolean(t, has_volume);
+ pa_tagstruct_put_boolean(t, has_volume ? !pa_sink_input_is_volume_writable(s) : FALSE);
+ }
}
static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
@@ -3461,6 +3472,7 @@ static void command_set_volume(
pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
pa_source_set_volume(source, &volume, TRUE);
} else if (si) {
+ CHECK_VALIDITY(c->pstream, pa_sink_input_is_volume_writable(si), tag, PA_ERR_INVALID);
CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
pa_log_debug("Client %s changes volume of sink input %s.",
@@ -4927,7 +4939,7 @@ pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
}
pa_client* pa_native_connection_get_client(pa_native_connection *c) {
- pa_native_connection_assert_ref(c);
+ pa_native_connection_assert_ref(c);
- return c->client;
+ return c->client;
}
diff --git a/src/pulsecore/remap.c b/src/pulsecore/remap.c
index a0fc85b9..b831f78c 100644
--- a/src/pulsecore/remap.c
+++ b/src/pulsecore/remap.c
@@ -32,7 +32,7 @@
#include "remap.h"
-static void remap_mono_to_stereo_c (pa_remap_t *m, void *dst, const void *src, unsigned n) {
+static void remap_mono_to_stereo_c(pa_remap_t *m, void *dst, const void *src, unsigned n) {
unsigned i;
switch (*m->format) {
@@ -85,7 +85,7 @@ static void remap_mono_to_stereo_c (pa_remap_t *m, void *dst, const void *src, u
}
}
-static void remap_channels_matrix_c (pa_remap_t *m, void *dst, const void *src, unsigned n) {
+static void remap_channels_matrix_c(pa_remap_t *m, void *dst, const void *src, unsigned n) {
unsigned oc, ic, i;
unsigned n_ic, n_oc;
@@ -97,7 +97,7 @@ static void remap_channels_matrix_c (pa_remap_t *m, void *dst, const void *src,
{
float *d, *s;
- memset(dst, 0, n * sizeof (float) * n_oc);
+ memset(dst, 0, n * sizeof(float) * n_oc);
for (oc = 0; oc < n_oc; oc++) {
@@ -128,7 +128,7 @@ static void remap_channels_matrix_c (pa_remap_t *m, void *dst, const void *src,
{
int16_t *d, *s;
- memset(dst, 0, n * sizeof (int16_t) * n_oc);
+ memset(dst, 0, n * sizeof(int16_t) * n_oc);
for (oc = 0; oc < n_oc; oc++) {
@@ -160,7 +160,7 @@ static void remap_channels_matrix_c (pa_remap_t *m, void *dst, const void *src,
}
/* set the function that will execute the remapping based on the matrices */
-static void init_remap_c (pa_remap_t *m) {
+static void init_remap_c(pa_remap_t *m) {
unsigned n_oc, n_ic;
n_oc = m->o_ss->channels;
@@ -181,17 +181,17 @@ static void init_remap_c (pa_remap_t *m) {
/* default C implementation */
static pa_init_remap_func_t remap_func = init_remap_c;
-void pa_init_remap (pa_remap_t *m) {
- pa_assert (remap_func);
+void pa_init_remap(pa_remap_t *m) {
+ pa_assert(remap_func);
m->do_remap = NULL;
/* call the installed remap init function */
- remap_func (m);
+ remap_func(m);
if (m->do_remap == NULL) {
/* nothing was installed, fallback to C version */
- init_remap_c (m);
+ init_remap_c(m);
}
}
diff --git a/src/pulsecore/remap_mmx.c b/src/pulsecore/remap_mmx.c
index d358a58b..37d72da7 100644
--- a/src/pulsecore/remap_mmx.c
+++ b/src/pulsecore/remap_mmx.c
@@ -103,7 +103,7 @@
" emms \n\t"
#if defined (__i386__) || defined (__amd64__)
-static void remap_mono_to_stereo_mmx (pa_remap_t *m, void *dst, const void *src, unsigned n) {
+static void remap_mono_to_stereo_mmx(pa_remap_t *m, void *dst, const void *src, unsigned n) {
pa_reg_x86 temp, temp2;
switch (*m->format) {
@@ -133,7 +133,7 @@ static void remap_mono_to_stereo_mmx (pa_remap_t *m, void *dst, const void *src,
}
/* set the function that will execute the remapping based on the matrices */
-static void init_remap_mmx (pa_remap_t *m) {
+static void init_remap_mmx(pa_remap_t *m) {
unsigned n_oc, n_ic;
n_oc = m->o_ss->channels;
@@ -148,13 +148,13 @@ static void init_remap_mmx (pa_remap_t *m) {
}
#endif /* defined (__i386__) || defined (__amd64__) */
-void pa_remap_func_init_mmx (pa_cpu_x86_flag_t flags) {
+void pa_remap_func_init_mmx(pa_cpu_x86_flag_t flags) {
#if defined (__i386__) || defined (__amd64__)
if (flags & PA_CPU_X86_MMX) {
pa_log_info("Initialising MMX optimized remappers.");
- pa_set_init_remap_func ((pa_init_remap_func_t) init_remap_mmx);
+ pa_set_init_remap_func((pa_init_remap_func_t) init_remap_mmx);
}
#endif /* defined (__i386__) || defined (__amd64__) */
diff --git a/src/pulsecore/remap_sse.c b/src/pulsecore/remap_sse.c
index 0ccf3161..e1cb161d 100644
--- a/src/pulsecore/remap_sse.c
+++ b/src/pulsecore/remap_sse.c
@@ -102,7 +102,7 @@
"4: \n\t"
#if defined (__i386__) || defined (__amd64__)
-static void remap_mono_to_stereo_sse2 (pa_remap_t *m, void *dst, const void *src, unsigned n) {
+static void remap_mono_to_stereo_sse2(pa_remap_t *m, void *dst, const void *src, unsigned n) {
pa_reg_x86 temp, temp2;
switch (*m->format) {
@@ -132,7 +132,7 @@ static void remap_mono_to_stereo_sse2 (pa_remap_t *m, void *dst, const void *src
}
/* set the function that will execute the remapping based on the matrices */
-static void init_remap_sse2 (pa_remap_t *m) {
+static void init_remap_sse2(pa_remap_t *m) {
unsigned n_oc, n_ic;
n_oc = m->o_ss->channels;
@@ -147,7 +147,7 @@ static void init_remap_sse2 (pa_remap_t *m) {
}
#endif /* defined (__i386__) || defined (__amd64__) */
-void pa_remap_func_init_sse (pa_cpu_x86_flag_t flags) {
+void pa_remap_func_init_sse(pa_cpu_x86_flag_t flags) {
#if defined (__i386__) || defined (__amd64__)
if (flags & PA_CPU_X86_SSE2) {
diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c
index bed5a20d..b5c1611c 100644
--- a/src/pulsecore/resampler.c
+++ b/src/pulsecore/resampler.c
@@ -36,11 +36,11 @@
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include <pulsecore/strbuf.h>
+#include <pulsecore/remap.h>
#include "ffmpeg/avcodec.h"
#include "resampler.h"
-#include "remap.h"
/* Number of samples of extra space we allow the resamplers to return */
#define EXTRA_FRAMES 128
@@ -898,7 +898,7 @@ static void calc_map_table(pa_resampler *r) {
if (!on_center(r->o_cm.map[oc]))
continue;
- for (ic = 0; ic < n_ic; ic++) {
+ for (ic = 0; ic < n_ic; ic++) {
if (ic_connected[ic]) {
m->map_table_f[oc][ic] *= .9f;
@@ -961,7 +961,7 @@ static void calc_map_table(pa_resampler *r) {
if (ncenter[oc] <= 0)
continue;
- for (ic = 0; ic < n_ic; ic++) {
+ for (ic = 0; ic < n_ic; ic++) {
if (ic_connected[ic]) {
m->map_table_f[oc][ic] *= .75f;
@@ -983,7 +983,7 @@ static void calc_map_table(pa_resampler *r) {
/* OK, so there is an unconnected LFE channel. Let's mix
* it into all channels, with factor 0.375 */
- for (ic = 0; ic < n_ic; ic++) {
+ for (ic = 0; ic < n_ic; ic++) {
if (!on_lfe(r->i_cm.map[ic]))
continue;
@@ -1022,7 +1022,7 @@ static void calc_map_table(pa_resampler *r) {
pa_xfree(t);
/* initialize the remapping function */
- pa_init_remap (m);
+ pa_init_remap(m);
}
static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) {
@@ -1096,8 +1096,8 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) {
remap = &r->remap;
- pa_assert (remap->do_remap);
- remap->do_remap (remap, dst, src, n_frames);
+ pa_assert(remap->do_remap);
+ remap->do_remap(remap, dst, src, n_frames);
pa_memblock_release(input->memblock);
pa_memblock_release(r->buf2.memblock);
diff --git a/src/pulsecore/rtpoll.c b/src/pulsecore/rtpoll.c
index 98d7d625..a5e990f6 100644
--- a/src/pulsecore/rtpoll.c
+++ b/src/pulsecore/rtpoll.c
@@ -124,7 +124,7 @@ static void rtpoll_rebuild(pa_rtpoll *p) {
for (i = p->items; i; i = i->next) {
- if (i->n_pollfd > 0) {
+ if (i->n_pollfd > 0) {
size_t l = i->n_pollfd * sizeof(struct pollfd);
if (i->pollfd)
diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c
index 74600dec..62b7c468 100644
--- a/src/pulsecore/sample-util.c
+++ b/src/pulsecore/sample-util.c
@@ -37,9 +37,9 @@
#include <pulsecore/macro.h>
#include <pulsecore/g711.h>
#include <pulsecore/core-util.h>
+#include <pulsecore/endianmacros.h>
#include "sample-util.h"
-#include "endianmacros.h"
#define PA_SILENCE_MAX (PA_PAGE_SIZE*16)
@@ -752,7 +752,7 @@ void pa_volume_memchunk(
return;
}
- do_volume = pa_get_volume_func (spec->format);
+ do_volume = pa_get_volume_func(spec->format);
pa_assert(do_volume);
calc_volume_table[spec->format] ((void *)linear, volume);
diff --git a/src/pulsecore/sconv-s16le.c b/src/pulsecore/sconv-s16le.c
index 0fefdf1c..43587f3e 100644
--- a/src/pulsecore/sconv-s16le.c
+++ b/src/pulsecore/sconv-s16le.c
@@ -31,8 +31,7 @@
#include <pulsecore/sconv.h>
#include <pulsecore/macro.h>
#include <pulsecore/log.h>
-
-#include "endianmacros.h"
+#include <pulsecore/endianmacros.h>
#include "sconv-s16le.h"
diff --git a/src/pulsecore/sconv.c b/src/pulsecore/sconv.c
index 301f08b4..988d4b33 100644
--- a/src/pulsecore/sconv.c
+++ b/src/pulsecore/sconv.c
@@ -29,10 +29,10 @@
#include <pulsecore/g711.h>
#include <pulsecore/macro.h>
+#include <pulsecore/endianmacros.h>
-#include "endianmacros.h"
-#include "sconv-s16le.h"
-#include "sconv-s16be.h"
+#include <pulsecore/sconv-s16le.h>
+#include <pulsecore/sconv-s16be.h>
#include "sconv.h"
diff --git a/src/pulsecore/sconv_sse.c b/src/pulsecore/sconv_sse.c
index 3737af2a..26daa223 100644
--- a/src/pulsecore/sconv_sse.c
+++ b/src/pulsecore/sconv_sse.c
@@ -29,13 +29,12 @@
#include <pulsecore/g711.h>
#include <pulsecore/macro.h>
-
-#include "endianmacros.h"
+#include <pulsecore/endianmacros.h>
#include "cpu-x86.h"
#include "sconv.h"
-#if defined (__i386__) || defined (__amd64__)
+#if !defined(__APPLE__) && defined (__i386__) || defined (__amd64__)
static const PA_DECLARE_ALIGNED (16, float, one[4]) = { 1.0, 1.0, 1.0, 1.0 };
static const PA_DECLARE_ALIGNED (16, float, mone[4]) = { -1.0, -1.0, -1.0, -1.0 };
@@ -170,7 +169,7 @@ static void pa_sconv_s16le_from_f32ne_sse2(unsigned n, const float *a, int16_t *
#define SAMPLES 1019
#define TIMES 1000
-static void run_test (void) {
+static void run_test(void) {
int16_t samples[SAMPLES];
int16_t samples_ref[SAMPLES];
float floats[SAMPLES];
@@ -178,18 +177,18 @@ static void run_test (void) {
pa_usec_t start, stop;
pa_convert_func_t func;
- printf ("checking SSE %zd\n", sizeof (samples));
+ printf("checking SSE %zd\n", sizeof(samples));
- memset (samples_ref, 0, sizeof (samples_ref));
- memset (samples, 0, sizeof (samples));
+ memset(samples_ref, 0, sizeof(samples_ref));
+ memset(samples, 0, sizeof(samples));
for (i = 0; i < SAMPLES; i++) {
floats[i] = (rand()/(RAND_MAX+2.2)) - 1.1;
}
- func = pa_get_convert_from_float32ne_function (PA_SAMPLE_S16LE);
- func (SAMPLES, floats, samples_ref);
- pa_sconv_s16le_from_f32ne_sse2 (SAMPLES, floats, samples);
+ func = pa_get_convert_from_float32ne_function(PA_SAMPLE_S16LE);
+ func(SAMPLES, floats, samples_ref);
+ pa_sconv_s16le_from_f32ne_sse2(SAMPLES, floats, samples);
for (i = 0; i < SAMPLES; i++) {
if (samples[i] != samples_ref[i]) {
@@ -200,14 +199,14 @@ static void run_test (void) {
start = pa_rtclock_now();
for (i = 0; i < TIMES; i++) {
- pa_sconv_s16le_from_f32ne_sse2 (SAMPLES, floats, samples);
+ pa_sconv_s16le_from_f32ne_sse2(SAMPLES, floats, samples);
}
stop = pa_rtclock_now();
pa_log_info("SSE: %llu usec.", (long long unsigned int)(stop - start));
start = pa_rtclock_now();
for (i = 0; i < TIMES; i++) {
- func (SAMPLES, floats, samples_ref);
+ func(SAMPLES, floats, samples_ref);
}
stop = pa_rtclock_now();
pa_log_info("ref: %llu usec.", (long long unsigned int)(stop - start));
@@ -216,19 +215,19 @@ static void run_test (void) {
#endif /* defined (__i386__) || defined (__amd64__) */
-void pa_convert_func_init_sse (pa_cpu_x86_flag_t flags) {
-#if defined (__i386__) || defined (__amd64__)
+void pa_convert_func_init_sse(pa_cpu_x86_flag_t flags) {
+#if !defined(__APPLE__) && defined (__i386__) || defined (__amd64__)
#ifdef RUN_TEST
- run_test ();
+ run_test();
#endif
if (flags & PA_CPU_X86_SSE2) {
pa_log_info("Initialising SSE2 optimized conversions.");
- pa_set_convert_from_float32ne_function (PA_SAMPLE_S16LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_sse2);
+ pa_set_convert_from_float32ne_function(PA_SAMPLE_S16LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_sse2);
} else {
pa_log_info("Initialising SSE optimized conversions.");
- pa_set_convert_from_float32ne_function (PA_SAMPLE_S16LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_sse);
+ pa_set_convert_from_float32ne_function(PA_SAMPLE_S16LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_sse);
}
#endif /* defined (__i386__) || defined (__amd64__) */
diff --git a/src/pulsecore/semaphore-osx.c b/src/pulsecore/semaphore-osx.c
index 73f43559..42afd154 100644
--- a/src/pulsecore/semaphore-osx.c
+++ b/src/pulsecore/semaphore-osx.c
@@ -30,8 +30,7 @@
#include "semaphore.h"
-struct pa_semaphore
-{
+struct pa_semaphore {
MPSemaphoreID sema;
};
diff --git a/src/pulsecore/semaphore-win32.c b/src/pulsecore/semaphore-win32.c
index 9ffbde66..c2e00c63 100644
--- a/src/pulsecore/semaphore-win32.c
+++ b/src/pulsecore/semaphore-win32.c
@@ -30,8 +30,7 @@
#include "semaphore.h"
-struct pa_semaphore
-{
+struct pa_semaphore {
HANDLE sema;
};
diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c
index 5d5d85ab..da8aff70 100644
--- a/src/pulsecore/shm.c
+++ b/src/pulsecore/shm.c
@@ -90,10 +90,12 @@ struct shm_marker {
#define SHM_MARKER_SIZE PA_ALIGN(sizeof(struct shm_marker))
+#ifdef HAVE_SHM_OPEN
static char *segment_name(char *fn, size_t l, unsigned id) {
pa_snprintf(fn, l, "/pulse-shm-%u", id);
return fn;
}
+#endif
int pa_shm_create_rw(pa_shm *m, size_t size, pa_bool_t shared, mode_t mode) {
char fn[32];
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index 065fd2d3..e0e81be4 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -38,7 +38,6 @@
#include <pulsecore/play-memblockq.h>
#include <pulsecore/namereg.h>
#include <pulsecore/core-util.h>
-#include <pulse/timeval.h>
#include "sink-input.h"
@@ -49,11 +48,6 @@ 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);
static int check_passthrough_connection(pa_sink_input_flags_t flags, pa_sink *dest) {
@@ -80,10 +74,10 @@ static int check_passthrough_connection(pa_sink_input_flags_t flags, pa_sink *de
}
} else {
- if (flags & PA_SINK_INPUT_PASSTHROUGH) {
- pa_log_warn("Cannot connect PASSTHROUGH sink input to sink without PASSTHROUGH capabilities");
- return -PA_ERR_INVALID;
- }
+ if (flags & PA_SINK_INPUT_PASSTHROUGH) {
+ pa_log_warn("Cannot connect PASSTHROUGH sink input to sink without PASSTHROUGH capabilities");
+ return -PA_ERR_INVALID;
+ }
}
return PA_OK;
}
@@ -112,8 +106,21 @@ void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const
data->channel_map = *map;
}
+pa_bool_t pa_sink_input_new_data_is_volume_writable(pa_sink_input_new_data *data) {
+ pa_assert(data);
+
+ if (data->flags & PA_SINK_INPUT_PASSTHROUGH)
+ return FALSE;
+
+ if (data->origin_sink && (data->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+ return FALSE;
+
+ return TRUE;
+}
+
void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume) {
pa_assert(data);
+ pa_assert(pa_sink_input_new_data_is_volume_writable(data));
if ((data->volume_is_set = !!volume))
data->volume = *volume;
@@ -205,6 +212,7 @@ int pa_sink_input_new(
if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], data)) < 0)
return r;
+ pa_assert(!data->volume_is_set || pa_sink_input_new_data_is_volume_writable(data));
pa_return_val_if_fail(!data->driver || pa_utf8_valid(data->driver), -PA_ERR_INVALID);
if (!data->sink) {
@@ -321,6 +329,7 @@ int pa_sink_input_new(
i->driver = pa_xstrdup(pa_path_get_filename(data->driver));
i->module = data->module;
i->sink = data->sink;
+ i->origin_sink = data->origin_sink;
i->client = data->client;
i->requested_resample_method = data->resample_method;
@@ -328,7 +337,7 @@ int pa_sink_input_new(
i->sample_spec = data->sample_spec;
i->channel_map = data->channel_map;
- if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !data->volume_is_absolute) {
+ if (!data->volume_is_absolute && pa_sink_flat_volume_enabled(i->sink)) {
pa_cvolume remapped;
/* When the 'absolute' bool is not set then we'll treat the volume
@@ -365,16 +374,6 @@ 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);
@@ -481,7 +480,7 @@ static void sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state)
/* Called from main context */
void pa_sink_input_unlink(pa_sink_input *i) {
pa_bool_t linked;
- pa_source_output *o, *p = NULL;
+ pa_source_output *o, *p = NULL;
pa_assert(i);
pa_assert_ctl_context();
@@ -523,7 +522,7 @@ void pa_sink_input_unlink(pa_sink_input *i) {
if (linked && i->sink) {
/* We might need to update the sink's volume if we are in flat volume mode. */
- if (i->sink->flags & PA_SINK_FLAT_VOLUME)
+ if (pa_sink_flat_volume_enabled(i->sink))
pa_sink_set_volume(i->sink, NULL, FALSE, FALSE);
if (i->sink->asyncmsgq)
@@ -565,12 +564,6 @@ 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);
@@ -610,10 +603,16 @@ void pa_sink_input_put(pa_sink_input *i) {
i->state = state;
/* We might need to update the sink's volume if we are in flat volume mode. */
- if (i->sink->flags & PA_SINK_FLAT_VOLUME)
+ if (pa_sink_flat_volume_enabled(i->sink))
pa_sink_set_volume(i->sink, NULL, FALSE, i->save_volume);
- else
+ else {
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+ pa_assert(pa_cvolume_is_norm(&i->volume));
+ pa_assert(pa_cvolume_is_norm(&i->reference_ratio));
+ }
+
set_real_ratio(i, &i->volume);
+ }
i->thread_info.soft_volume = i->soft_volume;
i->thread_info.muted = i->muted;
@@ -658,7 +657,6 @@ 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;
@@ -703,7 +701,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) || i->thread_info.ramp_info.is_ramping;
+ do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map);
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);
@@ -746,7 +744,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 && !i->thread_info.ramp_info.is_ramping) {
+ if (do_volume_adj_here && !volume_is_norm) {
pa_memchunk_make_writable(&wchunk, 0);
if (i->thread_info.muted) {
@@ -812,23 +810,6 @@ 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 %zu, dead thresholder is %lu\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 >= (int32_t) (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 */
@@ -873,7 +854,6 @@ 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) {
@@ -1010,7 +990,7 @@ pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec)
if (usec != (pa_usec_t) -1) {
pa_usec_t min_latency, max_latency;
pa_sink_get_latency_range(i->sink, &min_latency, &max_latency);
- usec = PA_CLAMP(usec, min_latency, max_latency);
+ usec = PA_CLAMP(usec, min_latency, max_latency);
}
}
@@ -1037,6 +1017,64 @@ pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i) {
}
/* 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));
+ pa_assert(pa_sink_input_is_volume_writable(i));
+
+ 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);
+
+ /* 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);
+}
+
+/* Called from main context */
static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v) {
pa_sink_input_assert_ref(i);
pa_assert_ctl_context();
@@ -1058,14 +1096,25 @@ 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_bool_t pa_sink_input_is_volume_readable(pa_sink_input *i) {
+ pa_sink_input_assert_ref(i);
+ pa_assert_ctl_context();
+
+ return !(i->flags & PA_SINK_INPUT_PASSTHROUGH);
+}
+
+/* Called from main context */
+pa_bool_t pa_sink_input_is_volume_writable(pa_sink_input *i) {
+ pa_sink_input_assert_ref(i);
+ pa_assert_ctl_context();
- /* Do not allow for volume changes for non-audio types */
if (i->flags & PA_SINK_INPUT_PASSTHROUGH)
- return;
+ return FALSE;
+
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+ return FALSE;
- /* 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);
+ return TRUE;
}
/* Called from main context */
@@ -1073,8 +1122,9 @@ pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bo
pa_sink_input_assert_ref(i);
pa_assert_ctl_context();
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
+ pa_assert(pa_sink_input_is_volume_readable(i));
- if (absolute || !(i->sink->flags & PA_SINK_FLAT_VOLUME))
+ if (absolute || !pa_sink_flat_volume_enabled(i->sink))
*volume = i->volume;
else
*volume = i->reference_ratio;
@@ -1084,8 +1134,25 @@ 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) {
- /* 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);
+ 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;
+
+ 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);
}
/* Called from main context */
@@ -1245,7 +1312,7 @@ int pa_sink_input_start_move(pa_sink_input *i) {
if (pa_sink_input_get_state(i) == PA_SINK_INPUT_CORKED)
pa_assert_se(i->sink->n_corked-- >= 1);
- if (i->sink->flags & PA_SINK_FLAT_VOLUME)
+ if (pa_sink_flat_volume_enabled(i->sink))
/* We might need to update the sink's volume if we are in flat
* volume mode. */
pa_sink_set_volume(i->sink, NULL, FALSE, FALSE);
@@ -1261,6 +1328,156 @@ int pa_sink_input_start_move(pa_sink_input *i) {
return 0;
}
+/* Called from main context. If i has an origin sink that uses volume sharing,
+ * then also the origin sink and all streams connected to it need to update
+ * their volume - this function does all that by using recursion. */
+static void update_volume_due_to_moving(pa_sink_input *i, pa_sink *dest) {
+ pa_cvolume old_volume;
+
+ pa_assert(i);
+ pa_assert(dest);
+ pa_assert(i->sink); /* The destination sink should already be set. */
+
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+ pa_sink *root_sink = i->sink;
+ pa_sink_input *origin_sink_input;
+ uint32_t idx;
+
+ while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
+ root_sink = root_sink->input_to_master->sink;
+
+ if (pa_sink_flat_volume_enabled(i->sink)) {
+ /* Ok, so the origin sink uses volume sharing, and flat volume is
+ * enabled. The volume will have to be updated as follows:
+ *
+ * i->volume := i->sink->real_volume
+ * (handled later by pa_sink_set_volume)
+ * i->reference_ratio := i->volume / i->sink->reference_volume
+ * (handled later by pa_sink_set_volume)
+ * i->real_ratio stays unchanged
+ * (streams whose origin sink uses volume sharing should
+ * always have real_ratio of 0 dB)
+ * i->soft_volume stays unchanged
+ * (streams whose origin sink uses volume sharing should
+ * always have volume_factor as soft_volume, so no change
+ * should be needed) */
+
+ pa_assert(pa_cvolume_is_norm(&i->real_ratio));
+ pa_assert(pa_cvolume_equal(&i->soft_volume, &i->volume_factor));
+
+ /* Notifications will be sent by pa_sink_set_volume(). */
+
+ } else {
+ /* Ok, so the origin sink uses volume sharing, and flat volume is
+ * disabled. The volume will have to be updated as follows:
+ *
+ * i->volume := 0 dB
+ * i->reference_ratio := 0 dB
+ * i->real_ratio stays unchanged
+ * (streams whose origin sink uses volume sharing should
+ * always have real_ratio of 0 dB)
+ * i->soft_volume stays unchanged
+ * (streams whose origin sink uses volume sharing should
+ * always have volume_factor as soft_volume, so no change
+ * should be needed) */
+
+ old_volume = i->volume;
+ pa_cvolume_reset(&i->volume, i->volume.channels);
+ pa_cvolume_reset(&i->reference_ratio, i->reference_ratio.channels);
+ pa_assert(pa_cvolume_is_norm(&i->real_ratio));
+ pa_assert(pa_cvolume_equal(&i->soft_volume, &i->volume_factor));
+
+ /* Notify others about the changed sink input volume. */
+ if (!pa_cvolume_equal(&i->volume, &old_volume)) {
+ if (i->volume_changed)
+ i->volume_changed(i);
+
+ pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+ }
+ }
+
+ /* Additionally, the origin sink volume needs updating:
+ *
+ * i->origin_sink->reference_volume := root_sink->reference_volume
+ * i->origin_sink->real_volume := root_sink->real_volume
+ * i->origin_sink->soft_volume stays unchanged
+ * (sinks that use volume sharing should always have
+ * soft_volume of 0 dB) */
+
+ old_volume = i->origin_sink->reference_volume;
+
+ i->origin_sink->reference_volume = root_sink->reference_volume;
+ pa_cvolume_remap(&i->origin_sink->reference_volume, &root_sink->channel_map, &i->origin_sink->channel_map);
+
+ i->origin_sink->real_volume = root_sink->real_volume;
+ pa_cvolume_remap(&i->origin_sink->real_volume, &root_sink->channel_map, &i->origin_sink->channel_map);
+
+ pa_assert(pa_cvolume_is_norm(&i->origin_sink->soft_volume));
+
+ /* Notify others about the changed sink volume. If you wonder whether
+ * i->origin_sink->set_volume() should be called somewhere, that's not
+ * the case, because sinks that use volume sharing shouldn't have any
+ * internal volume that set_volume() would update. If you wonder
+ * whether the thread_info variables should be synced, yes, they
+ * should, and it's done by the PA_SINK_MESSAGE_FINISH_MOVE message
+ * handler. */
+ if (!pa_cvolume_equal(&i->origin_sink->reference_volume, &old_volume))
+ pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, i->origin_sink->index);
+
+ /* Recursively update origin sink inputs. */
+ PA_IDXSET_FOREACH(origin_sink_input, i->origin_sink->inputs, idx)
+ update_volume_due_to_moving(origin_sink_input, dest);
+
+ } else {
+ old_volume = i->volume;
+
+ if (pa_sink_flat_volume_enabled(i->sink)) {
+ /* Ok, so this is a regular stream, and flat volume is enabled. The
+ * volume will have to be updated as follows:
+ *
+ * i->volume := i->reference_ratio * i->sink->reference_volume
+ * i->reference_ratio stays unchanged
+ * i->real_ratio := i->volume / i->sink->real_volume
+ * (handled later by pa_sink_set_volume)
+ * i->soft_volume := i->real_ratio * i->volume_factor
+ * (handled later by pa_sink_set_volume) */
+
+ i->volume = i->sink->reference_volume;
+ pa_cvolume_remap(&i->volume, &i->sink->channel_map, &i->channel_map);
+ pa_sw_cvolume_multiply(&i->volume, &i->volume, &i->reference_ratio);
+
+ } else {
+ /* Ok, so this is a regular stream, and flat volume is disabled.
+ * The volume will have to be updated as follows:
+ *
+ * i->volume := i->reference_ratio
+ * i->reference_ratio stays unchanged
+ * i->real_ratio := i->reference_ratio
+ * i->soft_volume := i->real_ratio * i->volume_factor */
+
+ i->volume = i->reference_ratio;
+ i->real_ratio = i->reference_ratio;
+ pa_sw_cvolume_multiply(&i->soft_volume, &i->real_ratio, &i->volume_factor);
+ }
+
+ /* Notify others about the changed sink input volume. */
+ if (!pa_cvolume_equal(&i->volume, &old_volume)) {
+ /* XXX: In case i->sink has flat volume enabled, then real_ratio
+ * and soft_volume are not updated yet. Let's hope that the
+ * callback implementation doesn't care about those variables... */
+ if (i->volume_changed)
+ i->volume_changed(i);
+
+ pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+ }
+ }
+
+ /* If i->sink == dest, then recursion has finished, and we can finally call
+ * pa_sink_set_volume(), which will do the rest of the updates. */
+ if ((i->sink == dest) && pa_sink_flat_volume_enabled(i->sink))
+ pa_sink_set_volume(i->sink, NULL, FALSE, i->save_volume);
+}
+
/* Called from main context */
int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
pa_resampler *new_resampler;
@@ -1334,17 +1551,7 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
}
pa_sink_update_status(dest);
- if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
- pa_cvolume remapped;
-
- /* Make relative volumes absolute */
- remapped = dest->reference_volume;
- pa_cvolume_remap(&remapped, &dest->channel_map, &i->channel_map);
- pa_sw_cvolume_multiply(&i->volume, &i->reference_ratio, &remapped);
-
- /* We might need to update the sink's volume if we are in flat volume mode. */
- pa_sink_set_volume(i->sink, NULL, FALSE, i->save_volume);
- }
+ update_volume_due_to_moving(i, dest);
pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_FINISH_MOVE, i, 0, NULL) == 0);
@@ -1353,9 +1560,6 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
/* Notify everyone */
pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH], i);
- if (i->volume_changed)
- i->volume_changed(i);
-
pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
return 0;
@@ -1464,23 +1668,15 @@ 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)) {
- if (!pa_atomic_load(&i->before_ramping_v))
- i->thread_info.soft_volume = i->soft_volume;
+ 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) {
- if (!pa_atomic_load(&i->before_ramping_m))
- i->thread_info.muted = i->muted;
+ i->thread_info.muted = i->muted;
pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
}
return 0;
@@ -1528,26 +1724,6 @@ 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;
@@ -1710,237 +1886,3 @@ 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) {
- int32_t envelope_length;
-
- pa_assert(i->thread_info.ramp_info.envelope);
-
- envelope_length = pa_envelope_length(i->thread_info.ramp_info.envelope);
-
- if (i->thread_info.ramp_info.envelope_dying > envelope_length) {
- if ((int32_t) (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 - (ssize_t) 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 f81e2d4b..588005fd 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -35,7 +35,6 @@ 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_input_put() has not been called yet */
@@ -83,7 +82,8 @@ struct pa_sink_input {
pa_module *module; /* may be NULL */
pa_client *client; /* may be NULL */
- pa_sink *sink; /* NULL while we are being moved */
+ pa_sink *sink; /* NULL while we are being moved */
+ pa_sink *origin_sink; /* only set by filter sinks */
/* A sink input may be connected to multiple source outputs
* directly, so that they don't get mixed data of the entire
@@ -234,23 +234,8 @@ 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;
};
@@ -265,7 +250,6 @@ 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
};
@@ -285,6 +269,7 @@ typedef struct pa_sink_input_new_data {
pa_client *client;
pa_sink *sink;
+ pa_sink *origin_sink;
pa_resample_method_t resample_method;
@@ -310,6 +295,7 @@ typedef struct pa_sink_input_new_data {
pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data);
void pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, const pa_sample_spec *spec);
void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const pa_channel_map *map);
+pa_bool_t pa_sink_input_new_data_is_volume_writable(pa_sink_input_new_data *data);
void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume);
void pa_sink_input_new_data_apply_volume_factor(pa_sink_input_new_data *data, const pa_cvolume *volume_factor);
void pa_sink_input_new_data_apply_volume_factor_sink(pa_sink_input_new_data *data, const pa_cvolume *volume_factor);
@@ -354,6 +340,8 @@ void pa_sink_input_kill(pa_sink_input*i);
pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency);
+pa_bool_t pa_sink_input_is_volume_readable(pa_sink_input *i);
+pa_bool_t pa_sink_input_is_volume_writable(pa_sink_input *i);
void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute);
pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bool_t absolute);
@@ -402,8 +390,4 @@ 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 62000e0d..839b7d44 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -226,8 +226,14 @@ pa_sink* pa_sink_new(
pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
- if (!data->volume_is_set)
+ /* FIXME: There should probably be a general function for checking whether
+ * the sink volume is allowed to be set, like there is for sink inputs. */
+ pa_assert(!data->volume_is_set || !(flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
+
+ if (!data->volume_is_set) {
pa_cvolume_reset(&data->volume, data->sample_spec.channels);
+ data->save_volume = FALSE;
+ }
pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
pa_return_null_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec));
@@ -269,6 +275,7 @@ pa_sink* pa_sink_new(
s->inputs = pa_idxset_new(NULL, NULL);
s->n_corked = 0;
+ s->input_to_master = NULL;
s->reference_volume = s->real_volume = data->volume;
pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
@@ -446,6 +453,7 @@ void pa_sink_put(pa_sink* s) {
pa_assert_ctl_context();
pa_assert(s->state == PA_SINK_INIT);
+ pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) || s->input_to_master);
/* The following fields must be initialized properly when calling _put() */
pa_assert(s->asyncmsgq);
@@ -455,22 +463,43 @@ void pa_sink_put(pa_sink* s) {
* special exception we allow volume related flags to be set
* between _new() and _put(). */
- if (!(s->flags & PA_SINK_HW_VOLUME_CTRL))
+ /* XXX: Currently decibel volume is disabled for all sinks that use volume
+ * sharing. When the master sink supports decibel volume, it would be good
+ * to have the flag also in the filter sink, but currently we don't do that
+ * so that the flags of the filter sink never change when it's moved from
+ * a master sink to another. One solution for this problem would be to
+ * remove user-visible volume altogether from filter sinks when volume
+ * sharing is used, but the current approach was easier to implement... */
+ if (!(s->flags & PA_SINK_HW_VOLUME_CTRL) && !(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
s->flags |= PA_SINK_DECIBEL_VOLUME;
if ((s->flags & PA_SINK_DECIBEL_VOLUME) && s->core->flat_volumes)
s->flags |= PA_SINK_FLAT_VOLUME;
- /* We assume that if the sink implementor changed the default
- * volume he did so in real_volume, because that is the usual
- * place where he is supposed to place his changes. */
- s->reference_volume = s->real_volume;
+ if (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) {
+ pa_sink *root_sink = s->input_to_master->sink;
+
+ while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
+ root_sink = root_sink->input_to_master->sink;
+
+ s->reference_volume = root_sink->reference_volume;
+ pa_cvolume_remap(&s->reference_volume, &root_sink->channel_map, &s->channel_map);
+
+ s->real_volume = root_sink->real_volume;
+ pa_cvolume_remap(&s->real_volume, &root_sink->channel_map, &s->channel_map);
+ } else
+ /* We assume that if the sink implementor changed the default
+ * volume he did so in real_volume, because that is the usual
+ * place where he is supposed to place his changes. */
+ s->reference_volume = s->real_volume;
s->thread_info.soft_volume = s->soft_volume;
s->thread_info.soft_muted = s->muted;
pa_sw_cvolume_multiply(&s->thread_info.current_hw_volume, &s->soft_volume, &s->real_volume);
- pa_assert((s->flags & PA_SINK_HW_VOLUME_CTRL) || (s->base_volume == PA_VOLUME_NORM && s->flags & PA_SINK_DECIBEL_VOLUME));
+ pa_assert((s->flags & PA_SINK_HW_VOLUME_CTRL)
+ || (s->base_volume == PA_VOLUME_NORM
+ && ((s->flags & PA_SINK_DECIBEL_VOLUME || (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)))));
pa_assert(!(s->flags & PA_SINK_DECIBEL_VOLUME) || s->n_volume_steps == PA_VOLUME_NORM+1);
pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == (s->thread_info.fixed_latency != 0));
pa_assert(!(s->flags & PA_SINK_LATENCY) == !(s->monitor_source->flags & PA_SOURCE_LATENCY));
@@ -1195,47 +1224,61 @@ pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s) {
return usec;
}
-static pa_cvolume* cvolume_remap_minimal_impact(
- pa_cvolume *v,
- const pa_cvolume *template,
- const pa_channel_map *from,
- const pa_channel_map *to) {
+/* Called from the main thread (and also from the IO thread while the main
+ * thread is waiting).
+ *
+ * When a sink uses volume sharing, it never has the PA_SINK_FLAT_VOLUME flag
+ * set. Instead, flat volume mode is detected by checking whether the root sink
+ * has the flag set. */
+pa_bool_t pa_sink_flat_volume_enabled(pa_sink *s) {
+ pa_sink_assert_ref(s);
- pa_cvolume t;
+ while (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
+ s = s->input_to_master->sink;
- pa_assert(v);
- pa_assert(template);
- pa_assert(from);
- pa_assert(to);
+ return (s->flags & PA_SINK_FLAT_VOLUME);
+}
- pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, from), NULL);
- pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(template, to), NULL);
+/* Called from main context. */
+static void compute_reference_ratio(pa_sink_input *i) {
+ unsigned c = 0;
+ pa_cvolume remapped;
- /* Much like pa_cvolume_remap(), but tries to minimize impact when
- * mapping from sink input to sink volumes:
- *
- * If template is a possible remapping from v it is used instead
- * of remapping anew.
+ pa_assert(i);
+ pa_assert(pa_sink_flat_volume_enabled(i->sink));
+
+ /*
+ * Calculates the reference ratio from the sink's reference
+ * volume. This basically calculates:
*
- * If the channel maps don't match we set an all-channel volume on
- * the sink to ensure that changing a volume on one stream has no
- * effect that cannot be compensated for in another stream that
- * does not have the same channel map as the sink. */
+ * i->reference_ratio = i->volume / i->sink->reference_volume
+ */
- if (pa_channel_map_equal(from, to))
- return v;
+ remapped = i->sink->reference_volume;
+ pa_cvolume_remap(&remapped, &i->sink->channel_map, &i->channel_map);
- t = *template;
- if (pa_cvolume_equal(pa_cvolume_remap(&t, to, from), v)) {
- *v = *template;
- return v;
- }
+ i->reference_ratio.channels = i->sample_spec.channels;
- pa_cvolume_set(v, to->channels, pa_cvolume_max(v));
- return v;
+ for (c = 0; c < i->sample_spec.channels; c++) {
+
+ /* We don't update when the sink volume is 0 anyway */
+ if (remapped.values[c] <= PA_VOLUME_MUTED)
+ continue;
+
+ /* Don't update the reference ratio unless necessary */
+ if (pa_sw_volume_multiply(
+ i->reference_ratio.values[c],
+ remapped.values[c]) == i->volume.values[c])
+ continue;
+
+ i->reference_ratio.values[c] = pa_sw_volume_divide(
+ i->volume.values[c],
+ remapped.values[c]);
+ }
}
-/* Called from main context */
+/* Called from main context. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
static void compute_reference_ratios(pa_sink *s) {
uint32_t idx;
pa_sink_input *i;
@@ -1243,44 +1286,18 @@ static void compute_reference_ratios(pa_sink *s) {
pa_sink_assert_ref(s);
pa_assert_ctl_context();
pa_assert(PA_SINK_IS_LINKED(s->state));
- pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
+ pa_assert(pa_sink_flat_volume_enabled(s));
PA_IDXSET_FOREACH(i, s->inputs, idx) {
- unsigned c;
- pa_cvolume remapped;
-
- /*
- * Calculates the reference volume from the sink's reference
- * volume. This basically calculates:
- *
- * i->reference_ratio = i->volume / s->reference_volume
- */
-
- remapped = s->reference_volume;
- pa_cvolume_remap(&remapped, &s->channel_map, &i->channel_map);
-
- i->reference_ratio.channels = i->sample_spec.channels;
-
- for (c = 0; c < i->sample_spec.channels; c++) {
-
- /* We don't update when the sink volume is 0 anyway */
- if (remapped.values[c] <= PA_VOLUME_MUTED)
- continue;
-
- /* Don't update the reference ratio unless necessary */
- if (pa_sw_volume_multiply(
- i->reference_ratio.values[c],
- remapped.values[c]) == i->volume.values[c])
- continue;
+ compute_reference_ratio(i);
- i->reference_ratio.values[c] = pa_sw_volume_divide(
- i->volume.values[c],
- remapped.values[c]);
- }
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+ compute_reference_ratios(i->origin_sink);
}
}
-/* Called from main context */
+/* Called from main context. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
static void compute_real_ratios(pa_sink *s) {
pa_sink_input *i;
uint32_t idx;
@@ -1288,12 +1305,24 @@ static void compute_real_ratios(pa_sink *s) {
pa_sink_assert_ref(s);
pa_assert_ctl_context();
pa_assert(PA_SINK_IS_LINKED(s->state));
- pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
+ pa_assert(pa_sink_flat_volume_enabled(s));
PA_IDXSET_FOREACH(i, s->inputs, idx) {
unsigned c;
pa_cvolume remapped;
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+ /* The origin sink uses volume sharing, so this input's real ratio
+ * is handled as a special case - the real ratio must be 0 dB, and
+ * as a result i->soft_volume must equal i->volume_factor. */
+ pa_cvolume_reset(&i->real_ratio, i->real_ratio.channels);
+ i->soft_volume = i->volume_factor;
+
+ compute_real_ratios(i->origin_sink);
+
+ continue;
+ }
+
/*
* This basically calculates:
*
@@ -1334,23 +1363,144 @@ static void compute_real_ratios(pa_sink *s) {
}
}
-/* Called from main thread */
-static void compute_real_volume(pa_sink *s) {
+static pa_cvolume *cvolume_remap_minimal_impact(
+ pa_cvolume *v,
+ const pa_cvolume *template,
+ const pa_channel_map *from,
+ const pa_channel_map *to) {
+
+ pa_cvolume t;
+
+ pa_assert(v);
+ pa_assert(template);
+ pa_assert(from);
+ pa_assert(to);
+ pa_assert(pa_cvolume_compatible_with_channel_map(v, from));
+ pa_assert(pa_cvolume_compatible_with_channel_map(template, to));
+
+ /* Much like pa_cvolume_remap(), but tries to minimize impact when
+ * mapping from sink input to sink volumes:
+ *
+ * If template is a possible remapping from v it is used instead
+ * of remapping anew.
+ *
+ * If the channel maps don't match we set an all-channel volume on
+ * the sink to ensure that changing a volume on one stream has no
+ * effect that cannot be compensated for in another stream that
+ * does not have the same channel map as the sink. */
+
+ if (pa_channel_map_equal(from, to))
+ return v;
+
+ t = *template;
+ if (pa_cvolume_equal(pa_cvolume_remap(&t, to, from), v)) {
+ *v = *template;
+ return v;
+ }
+
+ pa_cvolume_set(v, to->channels, pa_cvolume_max(v));
+ return v;
+}
+
+/* Called from main thread. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
+static void get_maximum_input_volume(pa_sink *s, pa_cvolume *max_volume, const pa_channel_map *channel_map) {
+ pa_sink_input *i;
+ uint32_t idx;
+
+ pa_sink_assert_ref(s);
+ pa_assert(max_volume);
+ pa_assert(channel_map);
+ pa_assert(pa_sink_flat_volume_enabled(s));
+
+ PA_IDXSET_FOREACH(i, s->inputs, idx) {
+ pa_cvolume remapped;
+
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+ get_maximum_input_volume(i->origin_sink, max_volume, channel_map);
+
+ /* Ignore this input. The origin sink uses volume sharing, so this
+ * input's volume will be set to be equal to the root sink's real
+ * volume. Obviously this input's current volume must not then
+ * affect what the root sink's real volume will be. */
+ continue;
+ }
+
+ remapped = i->volume;
+ cvolume_remap_minimal_impact(&remapped, max_volume, &i->channel_map, channel_map);
+ pa_cvolume_merge(max_volume, max_volume, &remapped);
+ }
+}
+
+/* Called from main thread. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
+static pa_bool_t has_inputs(pa_sink *s) {
pa_sink_input *i;
uint32_t idx;
pa_sink_assert_ref(s);
+
+ PA_IDXSET_FOREACH(i, s->inputs, idx) {
+ if (!i->origin_sink || !(i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) || has_inputs(i->origin_sink))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Called from main thread. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
+static void update_real_volume(pa_sink *s, const pa_cvolume *new_volume, pa_channel_map *channel_map) {
+ pa_sink_input *i;
+ uint32_t idx;
+
+ pa_sink_assert_ref(s);
+ pa_assert(new_volume);
+ pa_assert(channel_map);
+
+ s->real_volume = *new_volume;
+ pa_cvolume_remap(&s->real_volume, channel_map, &s->channel_map);
+
+ PA_IDXSET_FOREACH(i, s->inputs, idx) {
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+ if (pa_sink_flat_volume_enabled(s)) {
+ pa_cvolume old_volume = i->volume;
+
+ /* Follow the root sink's real volume. */
+ i->volume = *new_volume;
+ pa_cvolume_remap(&i->volume, channel_map, &i->channel_map);
+ compute_reference_ratio(i);
+
+ /* The volume changed, let's tell people so */
+ if (!pa_cvolume_equal(&old_volume, &i->volume)) {
+ if (i->volume_changed)
+ i->volume_changed(i);
+
+ pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+ }
+ }
+
+ update_real_volume(i->origin_sink, new_volume, channel_map);
+ }
+ }
+}
+
+/* Called from main thread. Only called for the root sink in shared volume
+ * cases. */
+static void compute_real_volume(pa_sink *s) {
+ pa_sink_assert_ref(s);
pa_assert_ctl_context();
pa_assert(PA_SINK_IS_LINKED(s->state));
- pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
+ pa_assert(pa_sink_flat_volume_enabled(s));
+ pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
/* This determines the maximum volume of all streams and sets
* s->real_volume accordingly. */
- if (pa_idxset_isempty(s->inputs)) {
- /* In the special case that we have no sink input we leave the
+ if (!has_inputs(s)) {
+ /* In the special case that we have no sink inputs we leave the
* volume unmodified. */
- s->real_volume = s->reference_volume;
+ update_real_volume(s, &s->reference_volume, &s->channel_map);
return;
}
@@ -1358,20 +1508,16 @@ static void compute_real_volume(pa_sink *s) {
/* First let's determine the new maximum volume of all inputs
* connected to this sink */
- PA_IDXSET_FOREACH(i, s->inputs, idx) {
- pa_cvolume remapped;
-
- remapped = i->volume;
- cvolume_remap_minimal_impact(&remapped, &s->real_volume, &i->channel_map, &s->channel_map);
- pa_cvolume_merge(&s->real_volume, &s->real_volume, &remapped);
- }
+ get_maximum_input_volume(s, &s->real_volume, &s->channel_map);
+ update_real_volume(s, &s->real_volume, &s->channel_map);
/* Then, let's update the real ratios/soft volumes of all inputs
* connected to this sink */
compute_real_ratios(s);
}
-/* Called from main thread */
+/* Called from main thread. Only called for the root sink in shared volume
+ * cases, except for internal recursive calls. */
static void propagate_reference_volume(pa_sink *s) {
pa_sink_input *i;
uint32_t idx;
@@ -1379,14 +1525,23 @@ static void propagate_reference_volume(pa_sink *s) {
pa_sink_assert_ref(s);
pa_assert_ctl_context();
pa_assert(PA_SINK_IS_LINKED(s->state));
- pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
+ pa_assert(pa_sink_flat_volume_enabled(s));
/* This is called whenever the sink volume changes that is not
* caused by a sink input volume change. We need to fix up the
* sink input volumes accordingly */
PA_IDXSET_FOREACH(i, s->inputs, idx) {
- pa_cvolume old_volume, remapped;
+ pa_cvolume old_volume;
+
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+ propagate_reference_volume(i->origin_sink);
+
+ /* Since the origin sink uses volume sharing, this input's volume
+ * needs to be updated to match the root sink's real volume, but
+ * that will be done later in update_shared_real_volume(). */
+ continue;
+ }
old_volume = i->volume;
@@ -1394,9 +1549,9 @@ static void propagate_reference_volume(pa_sink *s) {
*
* i->volume := s->reference_volume * i->reference_ratio */
- remapped = s->reference_volume;
- pa_cvolume_remap(&remapped, &s->channel_map, &i->channel_map);
- pa_sw_cvolume_multiply(&i->volume, &remapped, &i->reference_ratio);
+ i->volume = s->reference_volume;
+ pa_cvolume_remap(&i->volume, &s->channel_map, &i->channel_map);
+ pa_sw_cvolume_multiply(&i->volume, &i->volume, &i->reference_ratio);
/* The volume changed, let's tell people so */
if (!pa_cvolume_equal(&old_volume, &i->volume)) {
@@ -1409,6 +1564,54 @@ static void propagate_reference_volume(pa_sink *s) {
}
}
+/* Called from main thread. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. The return value indicates
+ * whether any reference volume actually changed. */
+static pa_bool_t update_reference_volume(pa_sink *s, const pa_cvolume *v, const pa_channel_map *channel_map, pa_bool_t save) {
+ pa_cvolume volume;
+ pa_bool_t reference_volume_changed;
+ pa_sink_input *i;
+ uint32_t idx;
+
+ pa_sink_assert_ref(s);
+ pa_assert(PA_SINK_IS_LINKED(s->state));
+ pa_assert(v);
+ pa_assert(channel_map);
+ pa_assert(pa_cvolume_valid(v));
+
+ volume = *v;
+ pa_cvolume_remap(&volume, channel_map, &s->channel_map);
+
+ reference_volume_changed = !pa_cvolume_equal(&volume, &s->reference_volume);
+ s->reference_volume = volume;
+
+ s->save_volume = (!reference_volume_changed && s->save_volume) || save;
+
+ if (reference_volume_changed)
+ pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+ else if (!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+ /* If the root sink's volume doesn't change, then there can't be any
+ * changes in the other sinks in the sink tree either.
+ *
+ * It's probably theoretically possible that even if the root sink's
+ * volume changes slightly, some filter sink doesn't change its volume
+ * due to rounding errors. If that happens, we still want to propagate
+ * the changed root sink volume to the sinks connected to the
+ * intermediate sink that didn't change its volume. This theoretical
+ * possiblity is the reason why we have that !(s->flags &
+ * PA_SINK_SHARE_VOLUME_WITH_MASTER) condition. Probably nobody would
+ * notice even if we returned here FALSE always if
+ * reference_volume_changed is FALSE. */
+ return FALSE;
+
+ PA_IDXSET_FOREACH(i, s->inputs, idx) {
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+ update_reference_volume(i->origin_sink, v, channel_map, FALSE);
+ }
+
+ return TRUE;
+}
+
/* Called from main thread */
void pa_sink_set_volume(
pa_sink *s,
@@ -1416,14 +1619,14 @@ void pa_sink_set_volume(
pa_bool_t send_msg,
pa_bool_t save) {
- pa_cvolume old_reference_volume;
- pa_bool_t reference_changed;
+ pa_cvolume new_reference_volume;
+ pa_sink *root_sink = s;
pa_sink_assert_ref(s);
pa_assert_ctl_context();
pa_assert(PA_SINK_IS_LINKED(s->state));
pa_assert(!volume || pa_cvolume_valid(volume));
- pa_assert(volume || (s->flags & PA_SINK_FLAT_VOLUME));
+ pa_assert(volume || pa_sink_flat_volume_enabled(s));
pa_assert(!volume || volume->channels == 1 || pa_cvolume_compatible(volume, &s->sample_spec));
/* make sure we don't change the volume when a PASSTHROUGH input is connected */
@@ -1444,76 +1647,80 @@ void pa_sink_set_volume(
}
}
+ /* In case of volume sharing, the volume is set for the root sink first,
+ * from which it's then propagated to the sharing sinks. */
+ while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
+ root_sink = root_sink->input_to_master->sink;
+
/* As a special exception we accept mono volumes on all sinks --
* even on those with more complex channel maps */
+ if (volume) {
+ if (pa_cvolume_compatible(volume, &s->sample_spec))
+ new_reference_volume = *volume;
+ else {
+ new_reference_volume = s->reference_volume;
+ pa_cvolume_scale(&new_reference_volume, pa_cvolume_max(volume));
+ }
+
+ pa_cvolume_remap(&new_reference_volume, &s->channel_map, &root_sink->channel_map);
+ }
+
/* If volume is NULL we synchronize the sink's real and reference
* volumes with the stream volumes. If it is not NULL we update
* the reference_volume with it. */
- old_reference_volume = s->reference_volume;
-
if (volume) {
-
- if (pa_cvolume_compatible(volume, &s->sample_spec))
- s->reference_volume = *volume;
- else
- pa_cvolume_scale(&s->reference_volume, pa_cvolume_max(volume));
-
- if (s->flags & PA_SINK_FLAT_VOLUME) {
- /* OK, propagate this volume change back to the inputs */
- propagate_reference_volume(s);
-
- /* And now recalculate the real volume */
- compute_real_volume(s);
- } else
- s->real_volume = s->reference_volume;
+ if (update_reference_volume(root_sink, &new_reference_volume, &root_sink->channel_map, save)) {
+ if (pa_sink_flat_volume_enabled(root_sink)) {
+ /* OK, propagate this volume change back to the inputs */
+ propagate_reference_volume(root_sink);
+
+ /* And now recalculate the real volume */
+ compute_real_volume(root_sink);
+ } else
+ update_real_volume(root_sink, &root_sink->reference_volume, &root_sink->channel_map);
+ }
} else {
- pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
+ pa_assert(pa_sink_flat_volume_enabled(root_sink));
/* Ok, let's determine the new real volume */
- compute_real_volume(s);
+ compute_real_volume(root_sink);
/* Let's 'push' the reference volume if necessary */
- pa_cvolume_merge(&s->reference_volume, &s->reference_volume, &s->real_volume);
+ pa_cvolume_merge(&new_reference_volume, &s->reference_volume, &root_sink->real_volume);
+ update_reference_volume(root_sink, &new_reference_volume, &root_sink->channel_map, save);
- /* We need to fix the reference ratios of all streams now that
- * we changed the reference volume */
- compute_reference_ratios(s);
+ /* Now that the reference volume is updated, we can update the streams'
+ * reference ratios. */
+ compute_reference_ratios(root_sink);
}
- reference_changed = !pa_cvolume_equal(&old_reference_volume, &s->reference_volume);
- s->save_volume = (!reference_changed && s->save_volume) || save;
-
- if (s->set_volume) {
+ if (root_sink->set_volume) {
/* If we have a function set_volume(), then we do not apply a
* soft volume by default. However, set_volume() is free to
- * apply one to s->soft_volume */
+ * apply one to root_sink->soft_volume */
- pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
- if (!(s->flags & PA_SINK_SYNC_VOLUME))
- s->set_volume(s);
- else
- send_msg = TRUE;
+ pa_cvolume_reset(&root_sink->soft_volume, root_sink->sample_spec.channels);
+ if (!(root_sink->flags & PA_SINK_SYNC_VOLUME))
+ root_sink->set_volume(root_sink);
} else
/* If we have no function set_volume(), then the soft volume
- * becomes the virtual volume */
- s->soft_volume = s->real_volume;
+ * becomes the real volume */
+ root_sink->soft_volume = root_sink->real_volume;
- /* This tells the sink that soft and/or virtual volume changed */
+ /* This tells the sink that soft volume and/or real volume changed */
if (send_msg)
- pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL) == 0);
-
- if (reference_changed)
- pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+ pa_assert_se(pa_asyncmsgq_send(root_sink->asyncmsgq, PA_MSGOBJECT(root_sink), PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL) == 0);
}
/* Called from the io thread if sync volume is used, otherwise from the main thread.
* Only to be called by sink implementor */
void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
pa_sink_assert_ref(s);
+ pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
if (s->flags & PA_SINK_SYNC_VOLUME)
pa_sink_assert_io_context(s);
else
@@ -1530,12 +1737,14 @@ void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
s->thread_info.soft_volume = s->soft_volume;
}
+/* Called from the main thread. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume) {
pa_sink_input *i;
uint32_t idx;
- pa_cvolume old_reference_volume;
pa_sink_assert_ref(s);
+ pa_assert(old_real_volume);
pa_assert_ctl_context();
pa_assert(PA_SINK_IS_LINKED(s->state));
@@ -1544,20 +1753,18 @@ static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume)
* reference volume and then rebuild the stream volumes based on
* i->real_ratio which should stay fixed. */
- if (old_real_volume && pa_cvolume_equal(old_real_volume, &s->real_volume))
- return;
-
- old_reference_volume = s->reference_volume;
+ if (!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+ if (pa_cvolume_equal(old_real_volume, &s->real_volume))
+ return;
- /* 1. Make the real volume the reference volume */
- s->reference_volume = s->real_volume;
+ /* 1. Make the real volume the reference volume */
+ update_reference_volume(s, &s->real_volume, &s->channel_map, TRUE);
+ }
- if (s->flags & PA_SINK_FLAT_VOLUME) {
+ if (pa_sink_flat_volume_enabled(s)) {
PA_IDXSET_FOREACH(i, s->inputs, idx) {
- pa_cvolume old_volume, remapped;
-
- old_volume = i->volume;
+ pa_cvolume old_volume = i->volume;
/* 2. Since the sink's reference and real volumes are equal
* now our ratios should be too. */
@@ -1571,9 +1778,9 @@ static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume)
* i->volume = s->reference_volume * i->reference_ratio
*
* This is identical to propagate_reference_volume() */
- remapped = s->reference_volume;
- pa_cvolume_remap(&remapped, &s->channel_map, &i->channel_map);
- pa_sw_cvolume_multiply(&i->volume, &remapped, &i->reference_ratio);
+ i->volume = s->reference_volume;
+ pa_cvolume_remap(&i->volume, &s->channel_map, &i->channel_map);
+ pa_sw_cvolume_multiply(&i->volume, &i->volume, &i->reference_ratio);
/* Notify if something changed */
if (!pa_cvolume_equal(&old_volume, &i->volume)) {
@@ -1583,16 +1790,17 @@ static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume)
pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
}
+
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+ propagate_real_volume(i->origin_sink, old_real_volume);
}
}
/* Something got changed in the hardware. It probably makes sense
* to save changed hw settings given that hw volume changes not
* triggered by PA are almost certainly done by the user. */
- s->save_volume = TRUE;
-
- if (!pa_cvolume_equal(&old_reference_volume, &s->reference_volume))
- pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+ if (!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+ s->save_volume = TRUE;
}
/* Called from io thread */
@@ -1612,6 +1820,8 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
if (s->refresh_volume || force_refresh) {
struct pa_cvolume old_real_volume;
+ pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
+
old_real_volume = s->real_volume;
if (!(s->flags & PA_SINK_SYNC_VOLUME) && s->get_volume)
@@ -1619,25 +1829,27 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
+ update_real_volume(s, &s->real_volume, &s->channel_map);
propagate_real_volume(s, &old_real_volume);
}
return &s->reference_volume;
}
-/* Called from main thread */
+/* Called from main thread. In volume sharing cases, only the root sink may
+ * call this. */
void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_real_volume) {
pa_cvolume old_real_volume;
pa_sink_assert_ref(s);
pa_assert_ctl_context();
pa_assert(PA_SINK_IS_LINKED(s->state));
+ pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
/* The sink implementor may call this if the volume changed to make sure everyone is notified */
old_real_volume = s->real_volume;
- s->real_volume = *new_real_volume;
-
+ update_real_volume(s, new_real_volume, &s->channel_map);
propagate_real_volume(s, &old_real_volume);
}
@@ -1844,18 +2056,30 @@ 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;
- if (!pa_atomic_load(&i->before_ramping_v))
- i->thread_info.soft_volume = i->soft_volume;
+ i->thread_info.soft_volume = i->soft_volume;
pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
}
}
+/* Called from the IO thread. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
+static void set_shared_volume_within_thread(pa_sink *s) {
+ pa_sink_input *i = NULL;
+ void *state = NULL;
+
+ pa_sink_assert_ref(s);
+
+ PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL);
+
+ PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+ set_shared_volume_within_thread(i->origin_sink);
+ }
+}
+
/* Called from IO thread, except when it is not */
int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
pa_sink *s = PA_SINK(o);
@@ -1912,7 +2136,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
/* In flat volume mode we need to update the volume as
* well */
- return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL);
+ return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
}
case PA_SINK_MESSAGE_REMOVE_INPUT: {
@@ -1955,7 +2179,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
/* In flat volume mode we need to update the volume as
* well */
- return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL);
+ return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
}
case PA_SINK_MESSAGE_START_MOVE: {
@@ -2000,7 +2224,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
/* In flat volume mode we need to update the volume as
* well */
- return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL);
+ return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
}
case PA_SINK_MESSAGE_FINISH_MOVE: {
@@ -2041,9 +2265,17 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
pa_sink_request_rewind(s, nbytes);
}
- /* In flat volume mode we need to update the volume as
- * well */
- return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL);
+ return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
+ }
+
+ case PA_SINK_MESSAGE_SET_SHARED_VOLUME: {
+ pa_sink *root_sink = s;
+
+ while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
+ root_sink = root_sink->input_to_master->sink;
+
+ set_shared_volume_within_thread(root_sink);
+ return 0;
}
case PA_SINK_MESSAGE_SET_VOLUME_SYNCED:
@@ -2061,9 +2293,6 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
pa_sink_request_rewind(s, (size_t) -1);
}
- if (!(s->flags & PA_SINK_FLAT_VOLUME))
- return 0;
-
/* Fall through ... */
case PA_SINK_MESSAGE_SYNC_VOLUMES:
@@ -2503,22 +2732,22 @@ void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_
/* Called from main thread */
void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
- pa_sink_assert_ref(s);
- pa_assert_ctl_context();
- pa_assert(min_latency);
- pa_assert(max_latency);
+ pa_sink_assert_ref(s);
+ pa_assert_ctl_context();
+ pa_assert(min_latency);
+ pa_assert(max_latency);
- if (PA_SINK_IS_LINKED(s->state)) {
- pa_usec_t r[2] = { 0, 0 };
+ if (PA_SINK_IS_LINKED(s->state)) {
+ pa_usec_t r[2] = { 0, 0 };
- pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
- *min_latency = r[0];
- *max_latency = r[1];
- } else {
- *min_latency = s->thread_info.min_latency;
- *max_latency = s->thread_info.max_latency;
- }
+ *min_latency = r[0];
+ *max_latency = r[1];
+ } else {
+ *min_latency = s->thread_info.min_latency;
+ *max_latency = s->thread_info.max_latency;
+ }
}
/* Called from IO thread */
@@ -2699,6 +2928,8 @@ int pa_sink_set_port(pa_sink *s, const char *name, pa_bool_t save) {
s->active_port = port;
s->save_port = save;
+ pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED], s);
+
return 0;
}
@@ -2942,11 +3173,11 @@ void pa_sink_volume_change_push(pa_sink *s) {
PA_LLIST_INSERT_AFTER(pa_sink_volume_change, s->thread_info.volume_changes, c, nc);
}
- pa_log_debug("Volume going %s to %d at %llu", direction, pa_cvolume_avg(&nc->hw_volume), nc->at);
+ pa_log_debug("Volume going %s to %d at %llu", direction, pa_cvolume_avg(&nc->hw_volume), (long long unsigned) nc->at);
/* We can ignore volume events that came earlier but should happen later than this. */
PA_LLIST_FOREACH(c, nc->next) {
- pa_log_debug("Volume change to %d at %llu was dropped", pa_cvolume_avg(&c->hw_volume), c->at);
+ pa_log_debug("Volume change to %d at %llu was dropped", pa_cvolume_avg(&c->hw_volume), (long long unsigned) c->at);
pa_sink_volume_change_free(c);
}
nc->next = NULL;
@@ -2977,7 +3208,8 @@ pa_bool_t pa_sink_volume_change_apply(pa_sink *s, pa_usec_t *usec_to_next) {
while (s->thread_info.volume_changes && now >= s->thread_info.volume_changes->at) {
pa_sink_volume_change *c = s->thread_info.volume_changes;
PA_LLIST_REMOVE(pa_sink_volume_change, s->thread_info.volume_changes, c);
- pa_log_debug("Volume change to %d at %llu was written %llu usec late", pa_cvolume_avg(&c->hw_volume), c->at, now - c->at);
+ pa_log_debug("Volume change to %d at %llu was written %llu usec late",
+ pa_cvolume_avg(&c->hw_volume), (long long unsigned) c->at, (long long unsigned) (now - c->at));
ret = TRUE;
s->thread_info.current_hw_volume = c->hw_volume;
pa_sink_volume_change_free(c);
@@ -2990,7 +3222,7 @@ pa_bool_t pa_sink_volume_change_apply(pa_sink *s, pa_usec_t *usec_to_next) {
if (usec_to_next)
*usec_to_next = s->thread_info.volume_changes->at - now;
if (pa_log_ratelimit(PA_LOG_DEBUG))
- pa_log_debug("Next volume change in %lld usec", s->thread_info.volume_changes->at - now);
+ pa_log_debug("Next volume change in %lld usec", (long long) (s->thread_info.volume_changes->at - now));
}
else {
if (usec_to_next)
@@ -3008,7 +3240,7 @@ static void pa_sink_volume_change_rewind(pa_sink *s, size_t nbytes) {
pa_usec_t rewound = pa_bytes_to_usec(nbytes, &s->sample_spec);
pa_usec_t limit = pa_sink_get_latency_within_thread(s);
- pa_log_debug("latency = %lld", limit);
+ pa_log_debug("latency = %lld", (long long) limit);
limit += pa_rtclock_now() + s->thread_info.volume_change_extra_delay;
PA_LLIST_FOREACH(c, s->thread_info.volume_changes) {
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index 4d569ddc..ef698813 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -44,6 +44,7 @@ typedef struct pa_sink_volume_change pa_sink_volume_change;
#include <pulsecore/card.h>
#include <pulsecore/queue.h>
#include <pulsecore/thread-mq.h>
+#include <pulsecore/sink-input.h>
#define PA_MAX_INPUTS_PER_SINK 32
@@ -86,6 +87,7 @@ struct pa_sink {
pa_idxset *inputs;
unsigned n_corked;
pa_source *monitor_source;
+ pa_sink_input *input_to_master; /* non-NULL only for filter sinks */
pa_volume_t base_volume; /* shall be constant */
unsigned n_volume_steps; /* shall be constant */
@@ -262,6 +264,7 @@ typedef enum pa_sink_message {
PA_SINK_MESSAGE_ADD_INPUT,
PA_SINK_MESSAGE_REMOVE_INPUT,
PA_SINK_MESSAGE_GET_VOLUME,
+ PA_SINK_MESSAGE_SET_SHARED_VOLUME,
PA_SINK_MESSAGE_SET_VOLUME_SYNCED,
PA_SINK_MESSAGE_SET_VOLUME,
PA_SINK_MESSAGE_SYNC_VOLUMES,
@@ -372,6 +375,9 @@ int pa_sink_update_status(pa_sink*s);
int pa_sink_suspend(pa_sink *s, pa_bool_t suspend, pa_suspend_cause_t cause);
int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause);
+/* Use this instead of checking s->flags & PA_SINK_FLAT_VOLUME directly. */
+pa_bool_t pa_sink_flat_volume_enabled(pa_sink *s);
+
void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume, pa_bool_t sendmsg, pa_bool_t save);
const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_bool_t force_refresh);
diff --git a/src/pulsecore/sndfile-util.c b/src/pulsecore/sndfile-util.c
index 9d15a868..292eb6e8 100644
--- a/src/pulsecore/sndfile-util.c
+++ b/src/pulsecore/sndfile-util.c
@@ -51,6 +51,9 @@ int pa_sndfile_read_sample_spec(SNDFILE *sf, pa_sample_spec *ss) {
break;
case SF_FORMAT_PCM_24:
+ ss->format = PA_SAMPLE_S24NE;
+ break;
+
case SF_FORMAT_PCM_32:
ss->format = PA_SAMPLE_S32NE;
break;
@@ -106,10 +109,14 @@ int pa_sndfile_write_sample_spec(SF_INFO *sfi, pa_sample_spec *ss) {
case PA_SAMPLE_S24LE:
case PA_SAMPLE_S24BE:
+ ss->format = PA_SAMPLE_S24NE;
+ sfi->format |= SF_FORMAT_PCM_24;
+ break;
+
case PA_SAMPLE_S24_32LE:
case PA_SAMPLE_S24_32BE:
- ss->format = PA_SAMPLE_S32NE;
- sfi->format |= SF_FORMAT_PCM_24;
+ ss->format = PA_SAMPLE_S24_32NE;
+ sfi->format |= SF_FORMAT_PCM_32;
break;
case PA_SAMPLE_S32LE:
@@ -297,8 +304,7 @@ int pa_sndfile_write_channel_map(SNDFILE *sf, pa_channel_map *cm) {
channels[c] = table[cm->map[c]];
}
- if (!sf_command(sf, SFC_SET_CHANNEL_MAP_INFO,
- channels, sizeof(channels[0]) * cm->channels)) {
+ if (!sf_command(sf, SFC_SET_CHANNEL_MAP_INFO, channels, sizeof(channels[0]) * cm->channels)) {
pa_xfree(channels);
return -1;
}
@@ -362,6 +368,7 @@ pa_sndfile_readf_t pa_sndfile_readf_function(const pa_sample_spec *ss) {
return (pa_sndfile_readf_t) sf_readf_short;
case PA_SAMPLE_S32NE:
+ case PA_SAMPLE_S24_32NE:
return (pa_sndfile_readf_t) sf_readf_int;
case PA_SAMPLE_FLOAT32NE:
@@ -384,6 +391,7 @@ pa_sndfile_writef_t pa_sndfile_writef_function(const pa_sample_spec *ss) {
return (pa_sndfile_writef_t) sf_writef_short;
case PA_SAMPLE_S32NE:
+ case PA_SAMPLE_S24_32NE:
return (pa_sndfile_writef_t) sf_writef_int;
case PA_SAMPLE_FLOAT32NE:
diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c
index 4037dca8..1ec19425 100644
--- a/src/pulsecore/sound-file-stream.c
+++ b/src/pulsecore/sound-file-stream.c
@@ -200,7 +200,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk
}
return -1;
- }
+}
static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
file_stream *u;
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 88731e76..0bb8899c 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -208,6 +208,7 @@ int pa_source_output_new(
o->driver = pa_xstrdup(pa_path_get_filename(data->driver));
o->module = data->module;
o->source = data->source;
+ o->destination_source = data->destination_source;
o->client = data->client;
o->actual_resample_method = resampler ? pa_resampler_get_method(resampler) : PA_RESAMPLER_INVALID;
diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
index 273b78fc..f16f9520 100644
--- a/src/pulsecore/source-output.h
+++ b/src/pulsecore/source-output.h
@@ -74,7 +74,8 @@ struct pa_source_output {
pa_module *module; /* may be NULL */
pa_client *client; /* may be NULL */
- pa_source *source; /* NULL while being moved */
+ pa_source *source; /* NULL while being moved */
+ pa_source *destination_source; /* only set by filter sources */
/* A source output can monitor just a single input of a sink, in which case we find it here */
pa_sink_input *direct_on_input; /* may be NULL */
@@ -211,6 +212,7 @@ typedef struct pa_source_output_new_data {
pa_client *client;
pa_source *source;
+ pa_source *destination_source;
pa_resample_method_t resample_method;
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index 412a3db9..92fb80e0 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -221,6 +221,7 @@ pa_source* pa_source_new(
s->outputs = pa_idxset_new(NULL, NULL);
s->n_corked = 0;
s->monitor_of = NULL;
+ s->output_from_master = NULL;
s->volume = data->volume;
pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
@@ -1401,22 +1402,22 @@ void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t
/* Called from main thread */
void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
- pa_source_assert_ref(s);
- pa_assert_ctl_context();
- pa_assert(min_latency);
- pa_assert(max_latency);
-
- if (PA_SOURCE_IS_LINKED(s->state)) {
- pa_usec_t r[2] = { 0, 0 };
-
- pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
-
- *min_latency = r[0];
- *max_latency = r[1];
- } else {
- *min_latency = s->thread_info.min_latency;
- *max_latency = s->thread_info.max_latency;
- }
+ pa_source_assert_ref(s);
+ pa_assert_ctl_context();
+ pa_assert(min_latency);
+ pa_assert(max_latency);
+
+ if (PA_SOURCE_IS_LINKED(s->state)) {
+ pa_usec_t r[2] = { 0, 0 };
+
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
+
+ *min_latency = r[0];
+ *max_latency = r[1];
+ } else {
+ *min_latency = s->thread_info.min_latency;
+ *max_latency = s->thread_info.max_latency;
+ }
}
/* Called from IO thread, and from main thread before pa_source_put() is called */
@@ -1570,5 +1571,7 @@ int pa_source_set_port(pa_source *s, const char *name, pa_bool_t save) {
s->active_port = port;
s->save_port = save;
+ pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PORT_CHANGED], s);
+
return 0;
}
diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
index e3e56bc4..9e8e2ada 100644
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -75,6 +75,7 @@ struct pa_source {
pa_idxset *outputs;
unsigned n_corked;
pa_sink *monitor_of; /* may be NULL */
+ pa_source_output *output_from_master; /* non-NULL only for filter sources */
pa_volume_t base_volume; /* shall be constant */
unsigned n_volume_steps; /* shall be constant */
@@ -155,7 +156,7 @@ struct pa_source {
pa_usec_t max_latency; /* An upper limit for the latencies */
pa_usec_t fixed_latency; /* for sources with PA_SOURCE_DYNAMIC_LATENCY this is 0 */
- } thread_info;
+} thread_info;
void *userdata;
};
diff --git a/src/pulsecore/strbuf.c b/src/pulsecore/strbuf.c
index 4fc82ded..f131d5cd 100644
--- a/src/pulsecore/strbuf.c
+++ b/src/pulsecore/strbuf.c
@@ -146,7 +146,7 @@ void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t l) {
pa_assert(t);
if (!l)
- return;
+ return;
c = pa_xmalloc(PA_ALIGN(sizeof(struct chunk)) + l);
c->length = l;
diff --git a/src/pulsecore/strlist.c b/src/pulsecore/strlist.c
index 0f4ca867..b2ba12ba 100644
--- a/src/pulsecore/strlist.c
+++ b/src/pulsecore/strlist.c
@@ -49,7 +49,7 @@ pa_strlist* pa_strlist_prepend(pa_strlist *l, const char *s) {
memcpy(ITEM_TO_TEXT(n), s, size + 1);
n->next = l;
- return n;
+ return n;
}
char *pa_strlist_tostring(pa_strlist *l) {
diff --git a/src/pulsecore/svolume.orc b/src/pulsecore/svolume.orc
new file mode 100644
index 00000000..3411161c
--- /dev/null
+++ b/src/pulsecore/svolume.orc
@@ -0,0 +1,84 @@
+# This file is part of PulseAudio.
+#
+# Copyright 2010 Lennart Poettering
+# Copyright 2010 Wim Taymans <wim.taymans@collabora.co.uk>
+# Copyright 2010 Arun Raghavan <arun.raghavan@collabora.co.uk>
+#
+# 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.
+
+# S16NE 1- and 2-channel volume scaling work as follows:
+#
+# params: samples s (signed 16-bit), volume v (signed 32-bit < 2^31)
+#
+# 32 16 0 (type of operation)
+# sample = | sample | (signed)
+# s = | 0 | sample | (unsigned)
+#
+# if (sample < 0)
+# signc = | 0 | 0xffff | (unsigned)
+# else
+# signc = | 0 | 0 | (unsgined)
+#
+# if (sample < 0)
+# ml = | 0 | -((s*vl) >> 16) | (unsgined)
+# else
+# ml = | 0 | (s*vl) >> 16 | (unsgined)
+#
+# vh = | v >> 16 | (signed, but value is always signed
+# since PA_VOLUME_MAX is 0x0fffffff)
+# mh = | (s * vh) >> 16 | (signed)
+# ml = | ml + mh | (signed)
+# sample = | (ml >> 16) | (signed, saturated)
+
+.function pa_volume_s16ne_orc_1ch
+.dest 2 samples int16_t
+.param 4 v int32_t
+.temp 2 vh
+.temp 4 s
+.temp 4 mh
+.temp 4 ml
+.temp 4 signc
+
+convuwl s, samples
+x2 cmpgtsw signc, 0, s
+x2 andw signc, signc, v
+x2 mulhuw ml, s, v
+subl ml, ml, signc
+convhlw vh, v
+mulswl mh, samples, vh
+addl ml, ml, mh
+convssslw samples, ml
+
+.function pa_volume_s16ne_orc_2ch
+.dest 4 samples int16_t
+.longparam 8 vols
+.temp 8 v
+.temp 4 vh
+.temp 8 s
+.temp 8 mh
+.temp 8 ml
+.temp 8 signc
+
+loadpq v, vols
+x2 convuwl s, samples
+x4 cmpgtsw signc, 0, s
+x4 andw signc, signc, v
+x4 mulhuw ml, s, v
+x2 subl ml, ml, signc
+x2 convhlw vh, v
+x2 mulswl mh, samples, vh
+x2 addl ml, ml, mh
+x2 convssslw samples, ml
diff --git a/src/pulsecore/svolume_arm.c b/src/pulsecore/svolume_arm.c
index 3973e518..42e8cbf9 100644
--- a/src/pulsecore/svolume_arm.c
+++ b/src/pulsecore/svolume_arm.c
@@ -29,22 +29,21 @@
#include <pulsecore/macro.h>
#include <pulsecore/g711.h>
#include <pulsecore/core-util.h>
+#include <pulsecore/endianmacros.h>
#include "cpu-arm.h"
#include "sample-util.h"
-#include "endianmacros.h"
#if defined (__arm__) && defined (HAVE_ARMV6)
#define MOD_INC() \
" subs r0, r6, %2 \n\t" \
+ " itt cs \n\t" \
" addcs r0, %1 \n\t" \
" movcs r6, r0 \n\t"
-static void
-pa_volume_s16ne_arm (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s16ne_arm(int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
int32_t *ve;
/* Channels must be at least 4, and always a multiple of the original number.
@@ -129,11 +128,11 @@ pa_volume_s16ne_arm (int16_t *samples, int32_t *volumes, unsigned channels, unsi
#ifdef RUN_TEST
#define CHANNELS 2
-#define SAMPLES 1023
+#define SAMPLES 1022
#define TIMES 1000
#define PADDING 16
-static void run_test (void) {
+static void run_test(void) {
int16_t samples[SAMPLES];
int16_t samples_ref[SAMPLES];
int16_t samples_orig[SAMPLES];
@@ -142,21 +141,21 @@ static void run_test (void) {
pa_do_volume_func_t func;
pa_usec_t start, stop;
- func = pa_get_volume_func (PA_SAMPLE_S16NE);
+ func = pa_get_volume_func(PA_SAMPLE_S16NE);
- printf ("checking ARM %zd\n", sizeof (samples));
+ printf("checking ARM %zd\n", sizeof(samples));
- pa_random (samples, sizeof (samples));
- memcpy (samples_ref, samples, sizeof (samples));
- memcpy (samples_orig, samples, sizeof (samples));
+ pa_random(samples, sizeof(samples));
+ memcpy(samples_ref, samples, sizeof(samples));
+ memcpy(samples_orig, samples, sizeof(samples));
for (i = 0; i < CHANNELS; i++)
- volumes[i] = rand() >> 1;
+ volumes[i] = PA_CLAMP_VOLUME(rand() >> 1);
for (padding = 0; padding < PADDING; padding++, i++)
volumes[i] = volumes[padding];
- func (samples_ref, volumes, CHANNELS, sizeof (samples));
- pa_volume_s16ne_arm (samples, volumes, CHANNELS, sizeof (samples));
+ func(samples_ref, volumes, CHANNELS, sizeof(samples));
+ pa_volume_s16ne_arm(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],
@@ -166,16 +165,16 @@ static void run_test (void) {
start = pa_rtclock_now();
for (j = 0; j < TIMES; j++) {
- memcpy (samples, samples_orig, sizeof (samples));
- pa_volume_s16ne_arm (samples, volumes, CHANNELS, sizeof (samples));
+ memcpy(samples, samples_orig, sizeof(samples));
+ pa_volume_s16ne_arm(samples, volumes, CHANNELS, sizeof(samples));
}
stop = pa_rtclock_now();
pa_log_info("ARM: %llu usec.", (long long unsigned int) (stop - start));
start = pa_rtclock_now();
for (j = 0; j < TIMES; j++) {
- memcpy (samples_ref, samples_orig, sizeof (samples));
- func (samples_ref, volumes, CHANNELS, sizeof (samples));
+ memcpy(samples_ref, samples_orig, sizeof(samples));
+ func(samples_ref, volumes, CHANNELS, sizeof(samples));
}
stop = pa_rtclock_now();
pa_log_info("ref: %llu usec.", (long long unsigned int) (stop - start));
@@ -185,14 +184,14 @@ static void run_test (void) {
#endif /* defined (__arm__) && defined (HAVE_ARMV6) */
-void pa_volume_func_init_arm (pa_cpu_arm_flag_t flags) {
+void pa_volume_func_init_arm(pa_cpu_arm_flag_t flags) {
#if defined (__arm__) && defined (HAVE_ARMV6)
pa_log_info("Initialising ARM optimized functions.");
#ifdef RUN_TEST
- run_test ();
+ run_test();
#endif
- pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_arm);
+ pa_set_volume_func(PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_arm);
#endif /* defined (__arm__) && defined (HAVE_ARMV6) */
}
diff --git a/src/pulsecore/svolume_c.c b/src/pulsecore/svolume_c.c
index 5fc052b8..e55d0d7b 100644
--- a/src/pulsecore/svolume_c.c
+++ b/src/pulsecore/svolume_c.c
@@ -28,13 +28,11 @@
#include <pulsecore/macro.h>
#include <pulsecore/g711.h>
#include <pulsecore/core-util.h>
+#include <pulsecore/endianmacros.h>
#include "sample-util.h"
-#include "endianmacros.h"
-static void
-pa_volume_u8_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_u8_c(uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
for (channel = 0; length; length--) {
@@ -53,9 +51,7 @@ pa_volume_u8_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned
}
}
-static void
-pa_volume_alaw_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_alaw_c(uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
for (channel = 0; length; length--) {
@@ -74,9 +70,7 @@ pa_volume_alaw_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigne
}
}
-static void
-pa_volume_ulaw_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_ulaw_c(uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
for (channel = 0; length; length--) {
@@ -95,12 +89,10 @@ pa_volume_ulaw_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigne
}
}
-static void
-pa_volume_s16ne_c (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s16ne_c(int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
- length /= sizeof (int16_t);
+ length /= sizeof(int16_t);
for (channel = 0; length; length--) {
int32_t t, hi, lo;
@@ -124,12 +116,10 @@ pa_volume_s16ne_c (int16_t *samples, int32_t *volumes, unsigned channels, unsign
}
}
-static void
-pa_volume_s16re_c (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s16re_c(int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
- length /= sizeof (int16_t);
+ length /= sizeof(int16_t);
for (channel = 0; length; length--) {
int32_t t, hi, lo;
@@ -147,12 +137,10 @@ pa_volume_s16re_c (int16_t *samples, int32_t *volumes, unsigned channels, unsign
}
}
-static void
-pa_volume_float32ne_c (float *samples, float *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_float32ne_c(float *samples, float *volumes, unsigned channels, unsigned length) {
unsigned channel;
- length /= sizeof (float);
+ length /= sizeof(float);
for (channel = 0; length; length--) {
*samples++ *= volumes[channel];
@@ -162,12 +150,10 @@ pa_volume_float32ne_c (float *samples, float *volumes, unsigned channels, unsign
}
}
-static void
-pa_volume_float32re_c (float *samples, float *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_float32re_c(float *samples, float *volumes, unsigned channels, unsigned length) {
unsigned channel;
- length /= sizeof (float);
+ length /= sizeof(float);
for (channel = 0; length; length--) {
float t;
@@ -181,12 +167,10 @@ pa_volume_float32re_c (float *samples, float *volumes, unsigned channels, unsign
}
}
-static void
-pa_volume_s32ne_c (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s32ne_c(int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
- length /= sizeof (int32_t);
+ length /= sizeof(int32_t);
for (channel = 0; length; length--) {
int64_t t;
@@ -201,12 +185,10 @@ pa_volume_s32ne_c (int32_t *samples, int32_t *volumes, unsigned channels, unsign
}
}
-static void
-pa_volume_s32re_c (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s32re_c(int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
- length /= sizeof (int32_t);
+ length /= sizeof(int32_t);
for (channel = 0; length; length--) {
int64_t t;
@@ -221,9 +203,7 @@ pa_volume_s32re_c (int32_t *samples, int32_t *volumes, unsigned channels, unsign
}
}
-static void
-pa_volume_s24ne_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s24ne_c(uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
uint8_t *e;
@@ -242,9 +222,7 @@ pa_volume_s24ne_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsign
}
}
-static void
-pa_volume_s24re_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s24re_c(uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
uint8_t *e;
@@ -263,12 +241,10 @@ pa_volume_s24re_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsign
}
}
-static void
-pa_volume_s24_32ne_c (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s24_32ne_c(uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
- length /= sizeof (uint32_t);
+ length /= sizeof(uint32_t);
for (channel = 0; length; length--) {
int64_t t;
@@ -283,12 +259,10 @@ pa_volume_s24_32ne_c (uint32_t *samples, int32_t *volumes, unsigned channels, un
}
}
-static void
-pa_volume_s24_32re_c (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s24_32re_c(uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
- length /= sizeof (uint32_t);
+ length /= sizeof(uint32_t);
for (channel = 0; length; length--) {
int64_t t;
@@ -303,8 +277,7 @@ pa_volume_s24_32re_c (uint32_t *samples, int32_t *volumes, unsigned channels, un
}
}
-static pa_do_volume_func_t do_volume_table[] =
-{
+static pa_do_volume_func_t do_volume_table[] = {
[PA_SAMPLE_U8] = (pa_do_volume_func_t) pa_volume_u8_c,
[PA_SAMPLE_ALAW] = (pa_do_volume_func_t) pa_volume_alaw_c,
[PA_SAMPLE_ULAW] = (pa_do_volume_func_t) pa_volume_ulaw_c,
diff --git a/src/pulsecore/svolume_mmx.c b/src/pulsecore/svolume_mmx.c
index 3e2992a2..421156ea 100644
--- a/src/pulsecore/svolume_mmx.c
+++ b/src/pulsecore/svolume_mmx.c
@@ -31,11 +31,11 @@
#include <pulsecore/macro.h>
#include <pulsecore/g711.h>
#include <pulsecore/core-util.h>
+#include <pulsecore/endianmacros.h>
#include "cpu-x86.h"
#include "sample-util.h"
-#include "endianmacros.h"
#if defined (__i386__) || defined (__amd64__)
/* in s: 2 int16_t samples
@@ -95,9 +95,7 @@
" por %%mm4, "#s1" \n\t" /* .. | l h | */ \
" por %%mm5, "#s2" \n\t"
-static void
-pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s16ne_mmx(int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
pa_reg_x86 channel, temp;
/* Channels must be at least 4, and always a multiple of the original number.
@@ -156,15 +154,13 @@ pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi
"6: \n\t"
" emms \n\t"
- : "+r" (samples), "+r" (volumes), "+r" (length), "=D" ((pa_reg_x86)channel), "=&r" (temp)
+ : "+r" (samples), "+r" (volumes), "+r" (length), "=D" (channel), "=&r" (temp)
: "rm" ((pa_reg_x86)channels)
: "cc"
);
}
-static void
-pa_volume_s16re_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s16re_mmx(int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
pa_reg_x86 channel, temp;
/* Channels must be at least 4, and always a multiple of the original number.
@@ -233,7 +229,7 @@ pa_volume_s16re_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi
"6: \n\t"
" emms \n\t"
- : "+r" (samples), "+r" (volumes), "+r" (length), "=D" ((pa_reg_x86)channel), "=&r" (temp)
+ : "+r" (samples), "+r" (volumes), "+r" (length), "=D" (channel), "=&r" (temp)
: "rm" ((pa_reg_x86)channels)
: "cc"
);
@@ -243,11 +239,11 @@ pa_volume_s16re_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi
#ifdef RUN_TEST
#define CHANNELS 2
-#define SAMPLES 1021
+#define SAMPLES 1022
#define TIMES 1000
#define PADDING 16
-static void run_test (void) {
+static void run_test(void) {
int16_t samples[SAMPLES];
int16_t samples_ref[SAMPLES];
int16_t samples_orig[SAMPLES];
@@ -256,43 +252,43 @@ static void run_test (void) {
pa_do_volume_func_t func;
pa_usec_t start, stop;
- func = pa_get_volume_func (PA_SAMPLE_S16NE);
+ func = pa_get_volume_func(PA_SAMPLE_S16NE);
- printf ("checking MMX %zd\n", sizeof (samples));
+ printf("checking MMX %zd\n", sizeof(samples));
- pa_random (samples, 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));
+ memcpy(samples_ref, samples, sizeof(samples));
+ memcpy(samples_orig, samples, sizeof(samples));
for (i = 0; i < CHANNELS; i++)
- volumes[i] = rand() >> 1;
+ volumes[i] = PA_CLAMP_VOLUME(rand() >> 1);
/* volumes[i] = 0x0000ffff; */
for (padding = 0; padding < PADDING; padding++, i++)
volumes[i] = volumes[padding];
- func (samples_ref, volumes, CHANNELS, sizeof (samples));
- pa_volume_s16ne_mmx (samples, volumes, CHANNELS, sizeof (samples));
+ func(samples_ref, volumes, CHANNELS, sizeof(samples));
+ 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 * %08x)\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]);
}
}
start = pa_rtclock_now();
for (j = 0; j < TIMES; j++) {
- memcpy (samples, samples_orig, sizeof (samples));
- pa_volume_s16ne_mmx (samples, volumes, CHANNELS, sizeof (samples));
+ memcpy(samples, samples_orig, sizeof(samples));
+ pa_volume_s16ne_mmx(samples, volumes, CHANNELS, sizeof(samples));
}
stop = pa_rtclock_now();
pa_log_info("MMX: %llu usec.", (long long unsigned int)(stop - start));
start = pa_rtclock_now();
for (j = 0; j < TIMES; j++) {
- memcpy (samples_ref, samples_orig, sizeof (samples));
- func (samples_ref, volumes, CHANNELS, sizeof (samples));
+ memcpy(samples_ref, samples_orig, sizeof(samples));
+ func(samples_ref, volumes, CHANNELS, sizeof(samples));
}
stop = pa_rtclock_now();
pa_log_info("ref: %llu usec.", (long long unsigned int)(stop - start));
@@ -304,18 +300,18 @@ static void run_test (void) {
#endif /* defined (__i386__) || defined (__amd64__) */
-void pa_volume_func_init_mmx (pa_cpu_x86_flag_t flags) {
+void pa_volume_func_init_mmx(pa_cpu_x86_flag_t flags) {
#if defined (__i386__) || defined (__amd64__)
#ifdef RUN_TEST
- run_test ();
+ run_test();
#endif
if ((flags & PA_CPU_X86_MMX) && (flags & PA_CPU_X86_CMOV)) {
pa_log_info("Initialising MMX optimized functions.");
- pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_mmx);
- pa_set_volume_func (PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_mmx);
+ pa_set_volume_func(PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_mmx);
+ pa_set_volume_func(PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_mmx);
}
#endif /* defined (__i386__) || defined (__amd64__) */
}
diff --git a/src/pulsecore/svolume_orc.c b/src/pulsecore/svolume_orc.c
new file mode 100644
index 00000000..db07ba61
--- /dev/null
+++ b/src/pulsecore/svolume_orc.c
@@ -0,0 +1,117 @@
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2004-2006 Lennart Poettering
+ Copyright 2009 Wim Taymans <wim.taymans@collabora.co.uk>
+ Copyright 2010 Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+ 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 "cpu-orc.h"
+#include <pulse/xmalloc.h>
+#include <pulse/rtclock.h>
+#include <pulsecore/sample-util.h>
+#include <pulsecore/random.h>
+#include <pulsecore/svolume-orc-gen.h>
+
+pa_do_volume_func_t fallback;
+
+static void
+pa_volume_s16ne_orc(int16_t *samples, int32_t *volumes, unsigned channels, unsigned length)
+{
+ if (channels == 2) {
+ int64_t v = (int64_t)volumes[1] << 32 | volumes[0];
+ pa_volume_s16ne_orc_2ch (samples, v, ((length / (sizeof(int16_t))) / 2));
+ } else if (channels == 1)
+ pa_volume_s16ne_orc_1ch (samples, volumes[0], length / (sizeof(int16_t)));
+ else
+ fallback(samples, volumes, channels, length);
+}
+
+#undef RUN_TEST
+
+#ifdef RUN_TEST
+#define CHANNELS 2
+#define SAMPLES 1022
+#define TIMES 1000
+#define PADDING 16
+
+static void run_test (void) {
+ int16_t samples[SAMPLES];
+ int16_t samples_ref[SAMPLES];
+ int16_t samples_orig[SAMPLES];
+ int32_t volumes[CHANNELS + PADDING];
+ int i, j, padding;
+ pa_do_volume_func_t func;
+ pa_usec_t start, stop;
+
+ func = pa_get_volume_func (PA_SAMPLE_S16NE);
+
+ printf ("checking ORC %zd\n", sizeof (samples));
+
+ pa_random (samples, sizeof (samples));
+ memcpy (samples_ref, samples, sizeof (samples));
+ memcpy (samples_orig, samples, sizeof (samples));
+
+ for (i = 0; i < CHANNELS; i++)
+ volumes[i] = PA_CLAMP_VOLUME(rand() >> 1);
+ for (padding = 0; padding < PADDING; padding++, i++)
+ volumes[i] = volumes[padding];
+
+ func (samples_ref, volumes, CHANNELS, sizeof (samples));
+ pa_volume_s16ne_orc (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],
+ samples_orig[i], volumes[i % CHANNELS]);
+ }
+ }
+
+ start = pa_rtclock_now();
+ for (j = 0; j < TIMES; j++) {
+ memcpy (samples, samples_orig, sizeof (samples));
+ pa_volume_s16ne_orc (samples, volumes, CHANNELS, sizeof (samples));
+ }
+ stop = pa_rtclock_now();
+ pa_log_info("ORC: %llu usec.", (long long unsigned int)(stop - start));
+
+ start = pa_rtclock_now();
+ for (j = 0; j < TIMES; j++) {
+ memcpy (samples_ref, samples_orig, sizeof (samples));
+ func (samples_ref, volumes, CHANNELS, sizeof (samples));
+ }
+ 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
+
+void pa_volume_func_init_orc(void) {
+ pa_log_info("Initialising ORC optimized functions.");
+
+#ifdef RUN_TEST
+ run_test();
+#endif
+
+ fallback = pa_get_volume_func(PA_SAMPLE_S16NE);
+ pa_set_volume_func(PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_orc);
+}
diff --git a/src/pulsecore/svolume_sse.c b/src/pulsecore/svolume_sse.c
index 200482ec..ef07a243 100644
--- a/src/pulsecore/svolume_sse.c
+++ b/src/pulsecore/svolume_sse.c
@@ -31,11 +31,11 @@
#include <pulsecore/macro.h>
#include <pulsecore/g711.h>
#include <pulsecore/core-util.h>
+#include <pulsecore/endianmacros.h>
#include "cpu-x86.h"
#include "sample-util.h"
-#include "endianmacros.h"
#if defined (__i386__) || defined (__amd64__)
@@ -79,9 +79,7 @@
static int channel_overread_table[8] = {8,8,8,12,8,10,12,14};
-static void
-pa_volume_s16ne_sse2 (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s16ne_sse2(int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
pa_reg_x86 channel, temp;
/* Channels must be at least 8 and always a multiple of the original number.
@@ -161,9 +159,7 @@ pa_volume_s16ne_sse2 (int16_t *samples, int32_t *volumes, unsigned channels, uns
);
}
-static void
-pa_volume_s16re_sse2 (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s16re_sse2(int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
pa_reg_x86 channel, temp;
/* Channels must be at least 8 and always a multiple of the original number.
@@ -255,11 +251,11 @@ pa_volume_s16re_sse2 (int16_t *samples, int32_t *volumes, unsigned channels, uns
#ifdef RUN_TEST
#define CHANNELS 2
-#define SAMPLES 1021
+#define SAMPLES 1022
#define TIMES 1000
#define PADDING 16
-static void run_test (void) {
+static void run_test(void) {
int16_t samples[SAMPLES];
int16_t samples_ref[SAMPLES];
int16_t samples_orig[SAMPLES];
@@ -268,21 +264,21 @@ static void run_test (void) {
pa_do_volume_func_t func;
pa_usec_t start, stop;
- func = pa_get_volume_func (PA_SAMPLE_S16NE);
+ func = pa_get_volume_func(PA_SAMPLE_S16NE);
- printf ("checking SSE2 %zd\n", sizeof (samples));
+ printf("checking SSE2 %zd\n", sizeof(samples));
- pa_random (samples, sizeof (samples));
- memcpy (samples_ref, samples, sizeof (samples));
- memcpy (samples_orig, samples, sizeof (samples));
+ pa_random(samples, sizeof(samples));
+ memcpy(samples_ref, samples, sizeof(samples));
+ memcpy(samples_orig, samples, sizeof(samples));
for (i = 0; i < CHANNELS; i++)
- volumes[i] = rand() >> 1;
+ volumes[i] = PA_CLAMP_VOLUME(rand() >> 1);
for (padding = 0; padding < PADDING; padding++, i++)
volumes[i] = volumes[padding];
- func (samples_ref, volumes, CHANNELS, sizeof (samples));
- pa_volume_s16ne_sse2 (samples, volumes, CHANNELS, sizeof (samples));
+ func(samples_ref, 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],
@@ -292,16 +288,16 @@ static void run_test (void) {
start = pa_rtclock_now();
for (j = 0; j < TIMES; j++) {
- memcpy (samples, samples_orig, sizeof (samples));
- pa_volume_s16ne_sse2 (samples, volumes, CHANNELS, sizeof (samples));
+ memcpy(samples, samples_orig, 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));
start = pa_rtclock_now();
for (j = 0; j < TIMES; j++) {
- memcpy (samples_ref, samples_orig, sizeof (samples));
- func (samples_ref, volumes, CHANNELS, sizeof (samples));
+ memcpy(samples_ref, samples_orig, sizeof(samples));
+ func(samples_ref, volumes, CHANNELS, sizeof (samples));
}
stop = pa_rtclock_now();
pa_log_info("ref: %llu usec.", (long long unsigned int)(stop - start));
@@ -311,18 +307,18 @@ static void run_test (void) {
#endif
#endif /* defined (__i386__) || defined (__amd64__) */
-void pa_volume_func_init_sse (pa_cpu_x86_flag_t flags) {
+void pa_volume_func_init_sse(pa_cpu_x86_flag_t flags) {
#if defined (__i386__) || defined (__amd64__)
#ifdef RUN_TEST
- run_test ();
+ run_test();
#endif
if (flags & PA_CPU_X86_SSE2) {
pa_log_info("Initialising SSE2 optimized functions.");
- pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_sse2);
- pa_set_volume_func (PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_sse2);
+ pa_set_volume_func(PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_sse2);
+ pa_set_volume_func(PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_sse2);
}
#endif /* defined (__i386__) || defined (__amd64__) */
}
diff --git a/src/pulsecore/time-smoother.c b/src/pulsecore/time-smoother.c
index 0696cabc..a8dd333f 100644
--- a/src/pulsecore/time-smoother.c
+++ b/src/pulsecore/time-smoother.c
@@ -385,7 +385,7 @@ void pa_smoother_put(pa_smoother *s, pa_usec_t x, pa_usec_t y) {
s->abc_valid = FALSE;
#ifdef DEBUG_DATA
- pa_log_debug("%p, put(%llu | %llu) = %llu", s, (unsigned long long) (x + s->time_offset), (unsigned long long) x, (unsigned long long) y);
+ pa_log_debug("%p, put(%llu | %llu) = %llu", s, (unsigned long long) (x + s->time_offset), (unsigned long long) x, (unsigned long long) y);
#endif
}
@@ -441,7 +441,7 @@ void pa_smoother_pause(pa_smoother *s, pa_usec_t x) {
return;
#ifdef DEBUG_DATA
- pa_log_debug("pause(%llu)", (unsigned long long) x);
+ pa_log_debug("pause(%llu)", (unsigned long long) x);
#endif
s->paused = TRUE;
diff --git a/src/pulsecore/usergroup.c b/src/pulsecore/usergroup.c
index 71b13bca..c244865e 100644
--- a/src/pulsecore/usergroup.c
+++ b/src/pulsecore/usergroup.c
@@ -142,9 +142,7 @@ struct group *pa_getgrgid_malloc(gid_t gid) {
getgr_buflen = buflen - sizeof(struct group);
getgr_buf = (char *)buf + sizeof(struct group);
- while ((err = getgrgid_r(gid, (struct group *)buf, getgr_buf,
- getgr_buflen, &result)) == ERANGE)
- {
+ while ((err = getgrgid_r(gid, (struct group *)buf, getgr_buf, getgr_buflen, &result)) == ERANGE) {
if (expand_buffer_trashcontents(&buf, &buflen))
break;
@@ -203,9 +201,7 @@ struct group *pa_getgrnam_malloc(const char *name) {
getgr_buflen = buflen - sizeof(struct group);
getgr_buf = (char *)buf + sizeof(struct group);
- while ((err = getgrnam_r(name, (struct group *)buf, getgr_buf,
- getgr_buflen, &result)) == ERANGE)
- {
+ while ((err = getgrnam_r(name, (struct group *)buf, getgr_buf, getgr_buflen, &result)) == ERANGE) {
if (expand_buffer_trashcontents(&buf, &buflen))
break;
@@ -268,9 +264,7 @@ struct passwd *pa_getpwnam_malloc(const char *name) {
getpw_buflen = buflen - sizeof(struct passwd);
getpw_buf = (char *)buf + sizeof(struct passwd);
- while ((err = getpwnam_r(name, (struct passwd *)buf, getpw_buf,
- getpw_buflen, &result)) == ERANGE)
- {
+ while ((err = getpwnam_r(name, (struct passwd *)buf, getpw_buf, getpw_buflen, &result)) == ERANGE) {
if (expand_buffer_trashcontents(&buf, &buflen))
break;
@@ -329,9 +323,7 @@ struct passwd *pa_getpwuid_malloc(uid_t uid) {
getpw_buflen = buflen - sizeof(struct passwd);
getpw_buf = (char *)buf + sizeof(struct passwd);
- while ((err = getpwuid_r(uid, (struct passwd *)buf, getpw_buf,
- getpw_buflen, &result)) == ERANGE)
- {
+ while ((err = getpwuid_r(uid, (struct passwd *)buf, getpw_buf, getpw_buflen, &result)) == ERANGE) {
if (expand_buffer_trashcontents(&buf, &buflen))
break;
diff --git a/src/pulsecore/x11prop.c b/src/pulsecore/x11prop.c
index 4cb21daa..8df32788 100644
--- a/src/pulsecore/x11prop.c
+++ b/src/pulsecore/x11prop.c
@@ -34,8 +34,7 @@
#define PA_XCB_FORMAT 8
-static xcb_screen_t *screen_of_display(xcb_connection_t *xcb, int screen)
-{
+static xcb_screen_t *screen_of_display(xcb_connection_t *xcb, int screen) {
const xcb_setup_t *s;
xcb_screen_iterator_t iter;