summaryrefslogtreecommitdiffstats
path: root/src/modules
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules')
-rw-r--r--src/modules/alsa-util.c84
-rw-r--r--src/modules/alsa-util.h6
-rw-r--r--src/modules/dbus-util.c2
-rw-r--r--src/modules/module-alsa-sink.c268
-rw-r--r--src/modules/module-alsa-source.c260
-rw-r--r--src/modules/module-device-restore.c8
-rw-r--r--src/modules/module-esound-sink.c4
-rw-r--r--src/modules/module-hal-detect.c2
-rw-r--r--src/modules/module-lirc.c6
-rw-r--r--src/modules/module-mmkbd-evdev.c6
-rw-r--r--src/modules/module-native-protocol-fd.c13
-rw-r--r--src/modules/module-protocol-stub.c7
-rw-r--r--src/modules/module-stream-restore.c42
-rw-r--r--src/modules/rtp/module-rtp-send.c23
14 files changed, 438 insertions, 293 deletions
diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c
index 8abf834d..e3e8c85c 100644
--- a/src/modules/alsa-util.c
+++ b/src/modules/alsa-util.c
@@ -56,7 +56,7 @@ struct pa_alsa_fdlist {
void *userdata;
};
-static void io_cb(pa_mainloop_api*a, pa_io_event* e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void *userdata) {
+static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) {
struct pa_alsa_fdlist *fdl = userdata;
int err, i;
@@ -102,7 +102,7 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, PA_GCC_UNUSED int fd, pa_io
snd_mixer_handle_events(fdl->mixer);
}
-static void defer_cb(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event* e, void *userdata) {
+static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) {
struct pa_alsa_fdlist *fdl = userdata;
int num_fds, i, err;
struct pollfd *temp;
@@ -808,7 +808,7 @@ int pa_alsa_calc_mixer_map(snd_mixer_elem_t *elem, const pa_channel_map *channel
if (channel_map->channels > 1 &&
((playback && snd_mixer_selem_has_playback_volume_joined(elem)) ||
(!playback && snd_mixer_selem_has_capture_volume_joined(elem)))) {
- pa_log_info("ALSA device lacks independant volume controls for each channel, falling back to software volume control.");
+ pa_log_info("ALSA device lacks independant volume controls for each channel.");
return -1;
}
@@ -820,7 +820,7 @@ int pa_alsa_calc_mixer_map(snd_mixer_elem_t *elem, const pa_channel_map *channel
id = alsa_channel_ids[channel_map->map[i]];
if (!is_mono && id == SND_MIXER_SCHN_UNKNOWN) {
- pa_log_info("Configured channel map contains channel '%s' that is unknown to the ALSA mixer. Falling back to software volume control.", pa_channel_position_to_string(channel_map->map[i]));
+ pa_log_info("Configured channel map contains channel '%s' that is unknown to the ALSA mixer.", pa_channel_position_to_string(channel_map->map[i]));
return -1;
}
@@ -832,7 +832,7 @@ int pa_alsa_calc_mixer_map(snd_mixer_elem_t *elem, const pa_channel_map *channel
if ((playback && (!snd_mixer_selem_has_playback_channel(elem, id) || (is_mono && !snd_mixer_selem_is_playback_mono(elem)))) ||
(!playback && (!snd_mixer_selem_has_capture_channel(elem, id) || (is_mono && !snd_mixer_selem_is_capture_mono(elem))))) {
- pa_log_info("ALSA device lacks separate volumes control for channel '%s', falling back to software volume control.", pa_channel_position_to_string(channel_map->map[i]));
+ pa_log_info("ALSA device lacks separate volumes control for channel '%s'", pa_channel_position_to_string(channel_map->map[i]));
return -1;
}
@@ -850,56 +850,6 @@ int pa_alsa_calc_mixer_map(snd_mixer_elem_t *elem, const pa_channel_map *channel
return 0;
}
-void pa_alsa_0dB_playback(snd_mixer_elem_t *elem) {
- long min, max, v;
-
- pa_assert(elem);
-
- /* Try to enable 0 dB if possible. If ALSA cannot do dB, then use
- * raw volume levels and fix them to 75% */
-
- if (snd_mixer_selem_set_playback_dB_all(elem, 0, -1) >= 0)
- return;
-
- if (snd_mixer_selem_set_playback_dB_all(elem, 0, 1) >= 0)
- return;
-
- if (snd_mixer_selem_get_playback_volume_range(elem, &min, &max) < 0)
- return;
-
- v = min + ((max - min) * 3) / 4; /* 75% */
-
- if (v <= min)
- v = max;
-
- snd_mixer_selem_set_playback_volume_all(elem, v);
-}
-
-void pa_alsa_0dB_capture(snd_mixer_elem_t *elem) {
- long min, max, v;
-
- pa_assert(elem);
-
- /* Try to enable 0 dB if possible. If ALSA cannot do dB, then use
- * raw volume levels and fix them to 75% */
-
- if (snd_mixer_selem_set_capture_dB_all(elem, 0, -1) >= 0)
- return;
-
- if (snd_mixer_selem_set_capture_dB_all(elem, 0, 1) >= 0)
- return;
-
- if (snd_mixer_selem_get_capture_volume_range(elem, &min, &max) < 0)
- return;
-
- v = min + ((max - min) * 3) / 4; /* 75% */
-
- if (v <= min)
- v = max;
-
- snd_mixer_selem_set_capture_volume_all(elem, v);
-}
-
void pa_alsa_dump(snd_pcm_t *pcm) {
int err;
snd_output_t *out;
@@ -1117,3 +1067,27 @@ pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll) {
return item;
}
+
+pa_cvolume *pa_alsa_volume_divide(pa_cvolume *r, const pa_cvolume *t) {
+ unsigned i;
+
+ pa_assert(r);
+ pa_assert(t);
+ pa_assert(r->channels == t->channels);
+
+ for (i = 0; i < r->channels; i++) {
+ double a, b, c;
+
+ a = pa_sw_volume_to_linear(r->values[i]); /* the hw volume */
+ b = pa_sw_volume_to_linear(t->values[i]); /* the intended volume */
+
+ if (a <= 0)
+ c = 0;
+ else
+ c = b / a;
+
+ r->values[i] = pa_sw_volume_from_linear(c);
+ }
+
+ return r;
+}
diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h
index 4de8bcd2..7991a107 100644
--- a/src/modules/alsa-util.h
+++ b/src/modules/alsa-util.h
@@ -26,6 +26,7 @@
#include <asoundlib.h>
#include <pulse/sample.h>
+#include <pulse/volume.h>
#include <pulse/mainloop-api.h>
#include <pulse/channelmap.h>
#include <pulse/proplist.h>
@@ -79,9 +80,6 @@ snd_pcm_t *pa_alsa_open_by_device_string(
int pa_alsa_calc_mixer_map(snd_mixer_elem_t *elem, const pa_channel_map *channel_map, snd_mixer_selem_channel_id_t mixer_map[], pa_bool_t playback);
-void pa_alsa_0dB_playback(snd_mixer_elem_t *elem);
-void pa_alsa_0dB_capture(snd_mixer_elem_t *elem);
-
void pa_alsa_dump(snd_pcm_t *pcm);
void pa_alsa_dump_status(snd_pcm_t *pcm);
@@ -94,4 +92,6 @@ int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents);
pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll);
+pa_cvolume *pa_alsa_volume_divide(pa_cvolume *r, const pa_cvolume *t);
+
#endif
diff --git a/src/modules/dbus-util.c b/src/modules/dbus-util.c
index 8e0066bc..c9c32a15 100644
--- a/src/modules/dbus-util.c
+++ b/src/modules/dbus-util.c
@@ -90,7 +90,7 @@ static pa_io_event_flags_t get_watch_flags(DBusWatch *watch) {
}
/* pa_io_event_cb_t IO event handler */
-static void handle_io_event(PA_GCC_UNUSED pa_mainloop_api *ea, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
+static void handle_io_event(pa_mainloop_api *ea, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
unsigned int flags = 0;
DBusWatch *watch = userdata;
diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c
index aad6801e..8980ba24 100644
--- a/src/modules/module-alsa-sink.c
+++ b/src/modules/module-alsa-sink.c
@@ -28,6 +28,10 @@
#include <asoundlib.h>
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+#include <valgrind/memcheck.h>
+#endif
+
#include <pulse/xmalloc.h>
#include <pulse/util.h>
#include <pulse/timeval.h>
@@ -68,8 +72,7 @@ PA_MODULE_USAGE(
"mmap=<enable memory mapping?> "
"tsched=<enable system timer based scheduling mode?> "
"tsched_buffer_size=<buffer size when using timer based scheduling> "
- "tsched_buffer_watermark=<lower fill watermark> "
- "mixer_reset=<reset hw volume and mute settings to sane defaults when falling back to software?>");
+ "tsched_buffer_watermark=<lower fill watermark>");
static const char* const valid_modargs[] = {
"sink_name",
@@ -85,7 +88,6 @@ static const char* const valid_modargs[] = {
"tsched",
"tsched_buffer_size",
"tsched_buffer_watermark",
- "mixer_reset",
NULL
};
@@ -112,6 +114,8 @@ struct userdata {
long hw_volume_max, hw_volume_min;
long hw_dB_max, hw_dB_min;
pa_bool_t hw_dB_supported;
+ pa_bool_t mixer_seperate_channels;
+ pa_cvolume hardware_volume;
size_t frame_size, fragment_size, hwbuf_size, tsched_watermark;
unsigned nfragments;
@@ -239,7 +243,7 @@ static size_t check_left_to_play(struct userdata *u, snd_pcm_sframes_t n) {
static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec) {
int work_done = 0;
- pa_usec_t max_sleep_usec, process_usec;
+ pa_usec_t max_sleep_usec = 0, process_usec = 0;
size_t left_to_play;
pa_assert(u);
@@ -354,7 +358,7 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec) {
static int unix_write(struct userdata *u, pa_usec_t *sleep_usec) {
int work_done = 0;
- pa_usec_t max_sleep_usec, process_usec;
+ pa_usec_t max_sleep_usec = 0, process_usec = 0;
size_t left_to_play;
pa_assert(u);
@@ -737,8 +741,8 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) {
return 0;
if (mask & SND_CTL_EVENT_MASK_VALUE) {
- pa_sink_get_volume(u->sink);
- pa_sink_get_mute(u->sink);
+ pa_sink_get_volume(u->sink, TRUE);
+ pa_sink_get_mute(u->sink, TRUE);
}
return 0;
@@ -747,30 +751,68 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) {
static int sink_get_volume_cb(pa_sink *s) {
struct userdata *u = s->userdata;
int err;
- int i;
+ unsigned i;
+ pa_cvolume r;
+ char t[PA_CVOLUME_SNPRINT_MAX];
pa_assert(u);
pa_assert(u->mixer_elem);
- for (i = 0; i < s->sample_spec.channels; i++) {
- long alsa_vol;
+ if (u->mixer_seperate_channels) {
- pa_assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, u->mixer_map[i]));
+ r.channels = s->sample_spec.channels;
- if (u->hw_dB_supported) {
+ for (i = 0; i < s->sample_spec.channels; i++) {
+ long alsa_vol;
- if ((err = snd_mixer_selem_get_playback_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol)) >= 0) {
- s->volume.values[i] = pa_sw_volume_from_dB(alsa_vol / 100.0);
- continue;
- }
+ if (u->hw_dB_supported) {
+
+ if ((err = snd_mixer_selem_get_playback_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+ goto fail;
+
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+ VALGRIND_MAKE_MEM_DEFINED(&alsa_vol, sizeof(alsa_vol));
+#endif
+
+ r.values[i] = pa_sw_volume_from_dB((double) alsa_vol / 100.0);
+ } else {
- u->hw_dB_supported = FALSE;
+ if ((err = snd_mixer_selem_get_playback_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+ goto fail;
+
+ r.values[i] = (pa_volume_t) round(((double) (alsa_vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
+ }
}
- if ((err = snd_mixer_selem_get_playback_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+ } else {
+ long alsa_vol;
+
+ pa_assert(u->hw_dB_supported);
+
+ if ((err = snd_mixer_selem_get_playback_dB(u->mixer_elem, SND_MIXER_SCHN_MONO, &alsa_vol)) < 0)
goto fail;
- s->volume.values[i] = (pa_volume_t) roundf(((float) (alsa_vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+ VALGRIND_MAKE_MEM_DEFINED(&alsa_vol, sizeof(alsa_vol));
+#endif
+
+ pa_cvolume_set(&r, s->sample_spec.channels, pa_sw_volume_from_dB((double) alsa_vol / 100.0));
+ }
+
+ pa_log_debug("Read hardware volume: %s", pa_cvolume_snprint(t, sizeof(t), &r));
+
+ if (!pa_cvolume_equal(&u->hardware_volume, &r)) {
+
+ u->hardware_volume = s->volume = r;
+
+ if (u->hw_dB_supported) {
+ pa_cvolume reset;
+
+ /* Hmm, so the hardware volume changed, let's reset our software volume */
+
+ pa_cvolume_reset(&reset, s->sample_spec.channels);
+ pa_sink_set_soft_volume(s, &reset);
+ }
}
return 0;
@@ -784,45 +826,90 @@ fail:
static int sink_set_volume_cb(pa_sink *s) {
struct userdata *u = s->userdata;
int err;
- int i;
+ unsigned i;
+ pa_cvolume r;
pa_assert(u);
pa_assert(u->mixer_elem);
- for (i = 0; i < s->sample_spec.channels; i++) {
- long alsa_vol;
- pa_volume_t vol;
+ if (u->mixer_seperate_channels) {
- pa_assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, u->mixer_map[i]));
+ r.channels = s->sample_spec.channels;
- vol = PA_MIN(s->volume.values[i], PA_VOLUME_NORM);
+ for (i = 0; i < s->sample_spec.channels; i++) {
+ long alsa_vol;
+ pa_volume_t vol;
- if (u->hw_dB_supported) {
- alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100);
- alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_dB_min, u->hw_dB_max);
+ vol = s->volume.values[i];
- if ((err = snd_mixer_selem_set_playback_dB(u->mixer_elem, u->mixer_map[i], alsa_vol, -1)) >= 0) {
+ if (u->hw_dB_supported) {
- if (snd_mixer_selem_get_playback_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol) >= 0)
- s->volume.values[i] = pa_sw_volume_from_dB(alsa_vol / 100.0);
+ alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100);
+ alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_dB_min, u->hw_dB_max);
- continue;
- }
+ if ((err = snd_mixer_selem_set_playback_dB(u->mixer_elem, u->mixer_map[i], alsa_vol, 1)) < 0)
+ goto fail;
+
+ if ((err = snd_mixer_selem_get_playback_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+ goto fail;
- u->hw_dB_supported = FALSE;
+ r.values[i] = pa_sw_volume_from_dB((double) alsa_vol / 100.0);
+ } else {
+
+ alsa_vol = (long) round(((double) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min;
+ alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_volume_min, u->hw_volume_max);
+
+ if ((err = snd_mixer_selem_set_playback_volume(u->mixer_elem, u->mixer_map[i], alsa_vol)) < 0)
+ goto fail;
+
+ if ((err = snd_mixer_selem_get_playback_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+ goto fail;
+ r.values[i] = (pa_volume_t) round(((double) (alsa_vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
+ }
}
- alsa_vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min;
- alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_volume_min, u->hw_volume_max);
+ } else {
+ pa_volume_t vol;
+ long alsa_vol;
+
+ pa_assert(u->hw_dB_supported);
+
+ vol = pa_cvolume_max(&s->volume);
- if ((err = snd_mixer_selem_set_playback_volume(u->mixer_elem, u->mixer_map[i], alsa_vol)) < 0)
+ alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100);
+ alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_dB_min, u->hw_dB_max);
+
+ if ((err = snd_mixer_selem_set_playback_dB_all(u->mixer_elem, alsa_vol, 1)) < 0)
+ goto fail;
+
+ if ((err = snd_mixer_selem_get_playback_dB(u->mixer_elem, SND_MIXER_SCHN_MONO, &alsa_vol)) < 0)
goto fail;
- if (snd_mixer_selem_get_playback_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol) >= 0)
- s->volume.values[i] = (pa_volume_t) roundf(((float) (alsa_vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
+ pa_cvolume_set(&r, s->volume.channels, pa_sw_volume_from_dB((double) alsa_vol / 100.0));
}
+ u->hardware_volume = r;
+
+ if (u->hw_dB_supported) {
+ char t[PA_CVOLUME_SNPRINT_MAX];
+
+ /* Match exactly what the user requested by software */
+
+ pa_alsa_volume_divide(&r, &s->volume);
+ pa_sink_set_soft_volume(s, &r);
+
+ pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->volume));
+ pa_log_debug("Got hardware volume: %s", pa_cvolume_snprint(t, sizeof(t), &u->hardware_volume));
+ pa_log_debug("Calculated software volume: %s", pa_cvolume_snprint(t, sizeof(t), &r));
+
+ } else
+
+ /* We can't match exactly what the user requested, hence let's
+ * at least tell the user about it */
+
+ s->volume = r;
+
return 0;
fail:
@@ -974,7 +1061,7 @@ static void thread_func(void *userdata) {
/* Render some data and write it to the dsp */
if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) {
int work_done;
- pa_usec_t sleep_usec;
+ pa_usec_t sleep_usec = 0;
if (u->sink->thread_info.rewind_requested)
if (process_rewind(u) < 0)
@@ -1100,7 +1187,7 @@ int pa__init(pa_module*m) {
const char *name;
char *name_buf = NULL;
pa_bool_t namereg_fail;
- pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, mixer_reset = TRUE;
+ pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d;
pa_usec_t usec;
pa_sink_new_data data;
@@ -1157,11 +1244,6 @@ int pa__init(pa_module*m) {
use_tsched = FALSE;
}
- if (pa_modargs_get_value_boolean(ma, "mixer_reset", &mixer_reset) < 0) {
- pa_log("Failed to parse mixer_reset argument.");
- goto fail;
- }
-
u = pa_xnew0(struct userdata, 1);
u->core = m->core;
u->module = m;
@@ -1322,6 +1404,8 @@ int pa__init(pa_module*m) {
u->hw_dB_supported = FALSE;
u->hw_dB_min = u->hw_dB_max = 0;
u->hw_volume_min = u->hw_volume_max = 0;
+ u->mixer_seperate_channels = FALSE;
+ pa_cvolume_mute(&u->hardware_volume, u->sink->sample_spec.channels);
if (use_tsched)
fix_tsched_watermark(u);
@@ -1349,76 +1433,56 @@ int pa__init(pa_module*m) {
if (u->mixer_handle) {
pa_assert(u->mixer_elem);
- if (snd_mixer_selem_has_playback_volume(u->mixer_elem))
-
- if (pa_alsa_calc_mixer_map(u->mixer_elem, &map, u->mixer_map, TRUE) >= 0 &&
- snd_mixer_selem_get_playback_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max) >= 0) {
-
- pa_bool_t suitable = TRUE;
+ if (snd_mixer_selem_has_playback_volume(u->mixer_elem)) {
+ pa_bool_t suitable = TRUE;
+ if (snd_mixer_selem_get_playback_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max) < 0) {
+ pa_log_info("Failed to get volume range. Falling back to software volume control.");
+ suitable = FALSE;
+ } else {
pa_log_info("Volume ranges from %li to %li.", u->hw_volume_min, u->hw_volume_max);
+ pa_assert(u->hw_volume_min < u->hw_volume_max);
+ }
- if (u->hw_volume_min > u->hw_volume_max) {
-
- pa_log_info("Minimal volume %li larger than maximum volume %li. Strange stuff Falling back to software volume control.", u->hw_volume_min, u->hw_volume_max);
- suitable = FALSE;
-
- } else if (u->hw_volume_max - u->hw_volume_min < 3) {
-
- pa_log_info("Device has less than 4 volume levels. Falling back to software volume control.");
- suitable = FALSE;
-
- } else if (snd_mixer_selem_get_playback_dB_range(u->mixer_elem, &u->hw_dB_min, &u->hw_dB_max) >= 0) {
-
- /* u->hw_dB_max = 0; u->hw_dB_min = -3000; Use this to make valgrind shut up */
-
- pa_log_info("Volume ranges from %0.2f dB to %0.2f dB.", u->hw_dB_min/100.0, u->hw_dB_max/100.0);
-
- /* Let's see if this thing actually is useful for muting */
- if (u->hw_dB_min > -6000) {
- pa_log_info("Device cannot attenuate for more than -60 dB (only %0.2f dB supported), falling back to software volume control.", ((double) u->hw_dB_min) / 100);
-
- suitable = FALSE;
- } else if (u->hw_dB_max < 0) {
-
- pa_log_info("Device is still attenuated at maximum volume setting (%0.2f dB is maximum). Strange stuff. Falling back to software volume control.", ((double) u->hw_dB_max) / 100);
- suitable = FALSE;
+ if (snd_mixer_selem_get_playback_dB_range(u->mixer_elem, &u->hw_dB_min, &u->hw_dB_max) < 0)
+ pa_log_info("Mixer doesn't support dB information.");
+ else {
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+ VALGRIND_MAKE_MEM_DEFINED(&u->hw_dB_min, sizeof(u->hw_dB_min));
+ VALGRIND_MAKE_MEM_DEFINED(&u->hw_dB_max, sizeof(u->hw_dB_max));
+#endif
- } else if (u->hw_dB_min >= u->hw_dB_max) {
+ pa_log_info("Volume ranges from %0.2f dB to %0.2f dB.", u->hw_dB_min/100.0, u->hw_dB_max/100.0);
+ pa_assert(u->hw_dB_min < u->hw_dB_max);
+ u->hw_dB_supported = TRUE;
+ }
- pa_log_info("Minimal dB (%0.2f) larger or equal to maximum dB (%0.2f). Strange stuff. Falling back to software volume control.", ((double) u->hw_dB_min) / 100, ((double) u->hw_dB_max) / 100);
- suitable = FALSE;
+ if (suitable &&
+ !u->hw_dB_supported &&
+ u->hw_volume_max - u->hw_volume_min < 3) {
- } else {
+ pa_log_info("Device doesn't do dB volume and has less than 4 volume levels. Falling back to software volume control.");
+ suitable = FALSE;
+ }
- if (u->hw_dB_max > 0) {
- /* dB > 0 means overamplification, and clipping, we don't want that here */
- pa_log_info("Device can do overamplification for %0.2f dB. Limiting to 0 db", ((double) u->hw_dB_max) / 100);
- u->hw_dB_max = 0;
- }
+ if (suitable) {
+ u->mixer_seperate_channels = pa_alsa_calc_mixer_map(u->mixer_elem, &map, u->mixer_map, TRUE) >= 0;
- u->hw_dB_supported = TRUE;
- }
- }
+ u->sink->get_volume = sink_get_volume_cb;
+ u->sink->set_volume = sink_set_volume_cb;
+ u->sink->flags |= PA_SINK_HW_VOLUME_CTRL | (u->hw_dB_supported ? PA_SINK_DECIBEL_VOLUME : 0);
+ pa_log_info("Using hardware volume control. Hardware dB scale %s.", u->hw_dB_supported ? "supported" : "not supported");
- if (suitable) {
- u->sink->get_volume = sink_get_volume_cb;
- u->sink->set_volume = sink_set_volume_cb;
- u->sink->flags |= PA_SINK_HW_VOLUME_CTRL | (u->hw_dB_supported ? PA_SINK_DECIBEL_VOLUME : 0);
- pa_log_info("Using hardware volume control. Hardware dB scale %s.", u->hw_dB_supported ? "supported" : "not supported");
-
- } else if (mixer_reset) {
- pa_log_info("Using software volume control. Trying to reset sound card to 0 dB.");
- pa_alsa_0dB_playback(u->mixer_elem);
- } else
- pa_log_info("Using software volume control. Leaving hw mixer controls untouched.");
- }
+ } else
+ pa_log_info("Using software volume control.");
+ }
if (snd_mixer_selem_has_playback_switch(u->mixer_elem)) {
u->sink->get_mute = sink_get_mute_cb;
u->sink->set_mute = sink_set_mute_cb;
u->sink->flags |= PA_SINK_HW_MUTE_CTRL;
- }
+ } else
+ pa_log_info("Using software mute control.");
u->mixer_fdl = pa_alsa_fdlist_new();
diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c
index 1cc467d9..9cf5aaf6 100644
--- a/src/modules/module-alsa-source.c
+++ b/src/modules/module-alsa-source.c
@@ -28,6 +28,10 @@
#include <asoundlib.h>
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+#include <valgrind/memcheck.h>
+#endif
+
#include <pulse/xmalloc.h>
#include <pulse/util.h>
#include <pulse/timeval.h>
@@ -69,8 +73,7 @@ PA_MODULE_USAGE(
"mmap=<enable memory mapping?> "
"tsched=<enable system timer based scheduling mode?> "
"tsched_buffer_size=<buffer size when using timer based scheduling> "
- "tsched_buffer_watermark=<upper fill watermark> "
- "mixer_reset=<reset hw volume and mute settings to sane defaults when falling back to software?>");
+ "tsched_buffer_watermark=<upper fill watermark>");
static const char* const valid_modargs[] = {
"source_name",
@@ -86,7 +89,6 @@ static const char* const valid_modargs[] = {
"tsched",
"tsched_buffer_size",
"tsched_buffer_watermark",
- "mixer_reset",
NULL
};
@@ -113,6 +115,9 @@ struct userdata {
long hw_volume_max, hw_volume_min;
long hw_dB_max, hw_dB_min;
pa_bool_t hw_dB_supported;
+ pa_bool_t mixer_seperate_channels;
+
+ pa_cvolume hardware_volume;
size_t frame_size, fragment_size, hwbuf_size, tsched_watermark;
unsigned nfragments;
@@ -234,7 +239,7 @@ static size_t check_left_to_record(struct userdata *u, snd_pcm_sframes_t n) {
static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec) {
int work_done = 0;
- pa_usec_t max_sleep_usec, process_usec;
+ pa_usec_t max_sleep_usec = 0, process_usec = 0;
size_t left_to_record;
pa_assert(u);
@@ -331,7 +336,7 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec) {
static int unix_read(struct userdata *u, pa_usec_t *sleep_usec) {
int work_done = 0;
- pa_usec_t max_sleep_usec, process_usec;
+ pa_usec_t max_sleep_usec = 0, process_usec = 0;
size_t left_to_record;
pa_assert(u);
@@ -680,8 +685,8 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) {
return 0;
if (mask & SND_CTL_EVENT_MASK_VALUE) {
- pa_source_get_volume(u->source);
- pa_source_get_mute(u->source);
+ pa_source_get_volume(u->source, TRUE);
+ pa_source_get_mute(u->source, TRUE);
}
return 0;
@@ -690,30 +695,68 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) {
static int source_get_volume_cb(pa_source *s) {
struct userdata *u = s->userdata;
int err;
- int i;
+ unsigned i;
+ pa_cvolume r;
+ char t[PA_CVOLUME_SNPRINT_MAX];
pa_assert(u);
pa_assert(u->mixer_elem);
- for (i = 0; i < s->sample_spec.channels; i++) {
- long alsa_vol;
+ if (u->mixer_seperate_channels) {
- pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, u->mixer_map[i]));
+ r.channels = s->sample_spec.channels;
- if (u->hw_dB_supported) {
+ for (i = 0; i < s->sample_spec.channels; i++) {
+ long alsa_vol;
- if ((err = snd_mixer_selem_get_capture_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol)) >= 0) {
- s->volume.values[i] = pa_sw_volume_from_dB(alsa_vol / 100.0);
- continue;
- }
+ if (u->hw_dB_supported) {
+
+ if ((err = snd_mixer_selem_get_capture_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+ goto fail;
+
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+ VALGRIND_MAKE_MEM_DEFINED(&alsa_vol, sizeof(alsa_vol));
+#endif
- u->hw_dB_supported = FALSE;
+ r.values[i] = pa_sw_volume_from_dB((double) alsa_vol / 100.0);
+ } else {
+
+ if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+ goto fail;
+
+ r.values[i] = (pa_volume_t) round(((double) (alsa_vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
+ }
}
- if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+ } else {
+ long alsa_vol;
+
+ pa_assert(u->hw_dB_supported);
+
+ if ((err = snd_mixer_selem_get_capture_dB(u->mixer_elem, SND_MIXER_SCHN_MONO, &alsa_vol)) < 0)
goto fail;
- s->volume.values[i] = (pa_volume_t) roundf(((float) (alsa_vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+ VALGRIND_MAKE_MEM_DEFINED(&alsa_vol, sizeof(alsa_vol));
+#endif
+
+ pa_cvolume_set(&r, s->sample_spec.channels, pa_sw_volume_from_dB((double) alsa_vol / 100.0));
+ }
+
+ pa_log_debug("Read hardware volume: %s", pa_cvolume_snprint(t, sizeof(t), &r));
+
+ if (!pa_cvolume_equal(&u->hardware_volume, &r)) {
+
+ u->hardware_volume = s->volume = r;
+
+ if (u->hw_dB_supported) {
+ pa_cvolume reset;
+
+ /* Hmm, so the hardware volume changed, let's reset our software volume */
+
+ pa_cvolume_reset(&reset, s->sample_spec.channels);
+ pa_source_set_soft_volume(s, &reset);
+ }
}
return 0;
@@ -727,45 +770,90 @@ fail:
static int source_set_volume_cb(pa_source *s) {
struct userdata *u = s->userdata;
int err;
- int i;
+ unsigned i;
+ pa_cvolume r;
pa_assert(u);
pa_assert(u->mixer_elem);
- for (i = 0; i < s->sample_spec.channels; i++) {
- long alsa_vol;
- pa_volume_t vol;
+ if (u->mixer_seperate_channels) {
- pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, u->mixer_map[i]));
+ r.channels = s->sample_spec.channels;
- vol = PA_MIN(s->volume.values[i], PA_VOLUME_NORM);
+ for (i = 0; i < s->sample_spec.channels; i++) {
+ long alsa_vol;
+ pa_volume_t vol;
- if (u->hw_dB_supported) {
- alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100);
- alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_dB_min, u->hw_dB_max);
+ vol = s->volume.values[i];
+ if (u->hw_dB_supported) {
- if ((err = snd_mixer_selem_set_capture_dB(u->mixer_elem, u->mixer_map[i], alsa_vol, -1)) >= 0) {
+ alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100);
+ alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_dB_min, u->hw_dB_max);
- if (snd_mixer_selem_get_capture_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol) >= 0)
- s->volume.values[i] = pa_sw_volume_from_dB(alsa_vol / 100.0);
+ if ((err = snd_mixer_selem_set_capture_dB(u->mixer_elem, u->mixer_map[i], alsa_vol, 1)) < 0)
+ goto fail;
- continue;
- }
+ if ((err = snd_mixer_selem_get_capture_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+ goto fail;
+
+ r.values[i] = pa_sw_volume_from_dB((double) alsa_vol / 100.0);
+ } else {
+
+ alsa_vol = (long) round(((double) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min;
+ alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_volume_min, u->hw_volume_max);
+
+ if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, u->mixer_map[i], alsa_vol)) < 0)
+ goto fail;
- u->hw_dB_supported = FALSE;
+ if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+ goto fail;
+
+ r.values[i] = (pa_volume_t) round(((double) (alsa_vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
+ }
}
- alsa_vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min;
- alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_volume_min, u->hw_volume_max);
+ } else {
+ pa_volume_t vol;
+ long alsa_vol;
+
+ pa_assert(u->hw_dB_supported);
+
+ vol = pa_cvolume_max(&s->volume);
+
+ alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100);
+ alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_dB_min, u->hw_dB_max);
+
+ if ((err = snd_mixer_selem_set_capture_dB_all(u->mixer_elem, alsa_vol, 1)) < 0)
+ goto fail;
- if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, u->mixer_map[i], alsa_vol)) < 0)
+ if ((err = snd_mixer_selem_get_capture_dB(u->mixer_elem, SND_MIXER_SCHN_MONO, &alsa_vol)) < 0)
goto fail;
- if (snd_mixer_selem_get_capture_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol) >= 0)
- s->volume.values[i] = (pa_volume_t) roundf(((float) (alsa_vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
+ pa_cvolume_set(&r, s->volume.channels, pa_sw_volume_from_dB((double) alsa_vol / 100.0));
}
+ u->hardware_volume = r;
+
+ if (u->hw_dB_supported) {
+ char t[PA_CVOLUME_SNPRINT_MAX];
+
+ /* Match exactly what the user requested by software */
+
+ pa_alsa_volume_divide(&r, &s->volume);
+ pa_source_set_soft_volume(s, &r);
+
+ pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->volume));
+ pa_log_debug("Got hardware volume: %s", pa_cvolume_snprint(t, sizeof(t), &u->hardware_volume));
+ pa_log_debug("Calculated software volume: %s", pa_cvolume_snprint(t, sizeof(t), &r));
+
+ } else
+
+ /* We can't match exactly what the user requested, hence let's
+ * at least tell the user about it */
+
+ s->volume = r;
+
return 0;
fail:
@@ -837,7 +925,7 @@ static void thread_func(void *userdata) {
/* Read some data and pass it to the sources */
if (PA_SOURCE_IS_OPENED(u->source->thread_info.state)) {
int work_done = 0;
- pa_usec_t sleep_usec;
+ pa_usec_t sleep_usec = 0;
if (u->use_mmap)
work_done = mmap_read(u, &sleep_usec);
@@ -932,7 +1020,7 @@ int pa__init(pa_module*m) {
const char *name;
char *name_buf = NULL;
pa_bool_t namereg_fail;
- pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, mixer_reset = TRUE;
+ pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d;
pa_source_new_data data;
snd_pcm_info_alloca(&pcm_info);
@@ -988,11 +1076,6 @@ int pa__init(pa_module*m) {
use_tsched = FALSE;
}
- if (pa_modargs_get_value_boolean(ma, "mixer_reset", &mixer_reset) < 0) {
- pa_log("Failed to parse mixer_reset argument.");
- goto fail;
- }
-
u = pa_xnew0(struct userdata, 1);
u->core = m->core;
u->module = m;
@@ -1146,6 +1229,8 @@ int pa__init(pa_module*m) {
u->hw_dB_supported = FALSE;
u->hw_dB_min = u->hw_dB_max = 0;
u->hw_volume_min = u->hw_volume_max = 0;
+ u->mixer_seperate_channels = FALSE;
+ pa_cvolume_mute(&u->hardware_volume, u->source->sample_spec.channels);
if (use_tsched)
fix_tsched_watermark(u);
@@ -1168,67 +1253,56 @@ int pa__init(pa_module*m) {
if (u->mixer_handle) {
pa_assert(u->mixer_elem);
- if (snd_mixer_selem_has_capture_volume(u->mixer_elem))
- if (pa_alsa_calc_mixer_map(u->mixer_elem, &map, u->mixer_map, FALSE) >= 0 &&
- snd_mixer_selem_get_capture_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max) >= 0) {
-
- pa_bool_t suitable = TRUE;
+ if (snd_mixer_selem_has_capture_volume(u->mixer_elem)) {
+ pa_bool_t suitable = TRUE;
+ if (snd_mixer_selem_get_capture_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max) < 0) {
+ pa_log_info("Failed to get volume range. Falling back to software volume control.");
+ suitable = FALSE;
+ } else {
pa_log_info("Volume ranges from %li to %li.", u->hw_volume_min, u->hw_volume_max);
+ pa_assert(u->hw_volume_min < u->hw_volume_max);
+ }
- if (u->hw_volume_min > u->hw_volume_max) {
-
- pa_log_info("Minimal volume %li larger than maximum volume %li. Strange stuff Falling back to software volume control.", u->hw_volume_min, u->hw_volume_max);
- suitable = FALSE;
-
- } else if (u->hw_volume_max - u->hw_volume_min < 3) {
-
- pa_log_info("Device has less than 4 volume levels. Falling back to software volume control.");
- suitable = FALSE;
-
- } else if (snd_mixer_selem_get_capture_dB_range(u->mixer_elem, &u->hw_dB_min, &u->hw_dB_max) >= 0) {
-
- pa_log_info("Volume ranges from %0.2f dB to %0.2f dB.", u->hw_dB_min/100.0, u->hw_dB_max/100.0);
-
- /* Let's see if this thing actually is useful for muting */
- if (u->hw_dB_min > -6000) {
- pa_log_info("Device cannot attenuate for more than -60 dB (only %0.2f dB supported), falling back to software volume control.", ((double) u->hw_dB_min) / 100);
-
- suitable = FALSE;
- } else if (u->hw_dB_max < 0) {
-
- pa_log_info("Device is still attenuated at maximum volume setting (%0.2f dB is maximum). Strange stuff. Falling back to software volume control.", ((double) u->hw_dB_max) / 100);
- suitable = FALSE;
-
- } else if (u->hw_dB_min >= u->hw_dB_max) {
+ if (snd_mixer_selem_get_capture_dB_range(u->mixer_elem, &u->hw_dB_min, &u->hw_dB_max) < 0)
+ pa_log_info("Mixer doesn't support dB information.");
+ else {
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+ VALGRIND_MAKE_MEM_DEFINED(&u->hw_dB_min, sizeof(u->hw_dB_min));
+ VALGRIND_MAKE_MEM_DEFINED(&u->hw_dB_max, sizeof(u->hw_dB_max));
+#endif
- pa_log_info("Minimal dB (%0.2f) larger or equal to maximum dB (%0.2f). Strange stuff. Falling back to software volume control.", ((double) u->hw_dB_min) / 100, ((double) u->hw_dB_max) / 100);
- suitable = FALSE;
+ pa_log_info("Volume ranges from %0.2f dB to %0.2f dB.", u->hw_dB_min/100.0, u->hw_dB_max/100.0);
+ pa_assert(u->hw_dB_min < u->hw_dB_max);
+ u->hw_dB_supported = TRUE;
+ }
- } else
- u->hw_dB_supported = TRUE;
- }
+ if (suitable &&
+ !u->hw_dB_supported &&
+ u->hw_volume_max - u->hw_volume_min < 3) {
- if (suitable) {
- u->source->get_volume = source_get_volume_cb;
- u->source->set_volume = source_set_volume_cb;
- u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL | (u->hw_dB_supported ? PA_SOURCE_DECIBEL_VOLUME : 0);
- pa_log_info("Using hardware volume control. Hardware dB scale %s.", u->hw_dB_supported ? "supported" : "not supported");
+ pa_log_info("Device has less than 4 volume levels. Falling back to software volume control.");
+ suitable = FALSE;
+ }
- } else if (mixer_reset) {
- pa_log_info("Using software volume control. Trying to reset sound card to 0 dB.");
- pa_alsa_0dB_capture(u->mixer_elem);
- } else
- pa_log_info("Using software volume control. Leaving hw mixer controls untouched.");
- }
+ if (suitable) {
+ u->mixer_seperate_channels = pa_alsa_calc_mixer_map(u->mixer_elem, &map, u->mixer_map, FALSE) >= 0;
+ u->source->get_volume = source_get_volume_cb;
+ u->source->set_volume = source_set_volume_cb;
+ u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL | (u->hw_dB_supported ? PA_SOURCE_DECIBEL_VOLUME : 0);
+ pa_log_info("Using hardware volume control. Hardware dB scale %s.", u->hw_dB_supported ? "supported" : "not supported");
+ } else
+ pa_log_info("Using software volume control.");
+ }
if (snd_mixer_selem_has_capture_switch(u->mixer_elem)) {
u->source->get_mute = source_get_mute_cb;
u->source->set_mute = source_set_mute_cb;
u->source->flags |= PA_SOURCE_HW_MUTE_CTRL;
- }
+ } else
+ pa_log_info("Using software mute control.");
u->mixer_fdl = pa_alsa_fdlist_new();
diff --git a/src/modules/module-device-restore.c b/src/modules/module-device-restore.c
index 3d731f12..f7d82e4d 100644
--- a/src/modules/module-device-restore.c
+++ b/src/modules/module-device-restore.c
@@ -179,8 +179,8 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
name = pa_sprintf_malloc("sink:%s", sink->name);
entry.channel_map = sink->channel_map;
- entry.volume = *pa_sink_get_volume(sink);
- entry.muted = pa_sink_get_mute(sink);
+ entry.volume = *pa_sink_get_volume(sink, FALSE);
+ entry.muted = pa_sink_get_mute(sink, FALSE);
} else {
pa_source *source;
@@ -192,8 +192,8 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
name = pa_sprintf_malloc("source:%s", source->name);
entry.channel_map = source->channel_map;
- entry.volume = *pa_source_get_volume(source);
- entry.muted = pa_source_get_mute(source);
+ entry.volume = *pa_source_get_volume(source, FALSE);
+ entry.muted = pa_source_get_mute(source, FALSE);
}
if ((old = read_entry(u, name))) {
diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c
index f748808e..e0c07d56 100644
--- a/src/modules/module-esound-sink.c
+++ b/src/modules/module-esound-sink.c
@@ -468,7 +468,7 @@ static int do_read(struct userdata *u) {
return 0;
}
-static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) {
+static void io_callback(pa_iochannel *io, void*userdata) {
struct userdata *u = userdata;
pa_assert(u);
@@ -483,7 +483,7 @@ static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) {
}
}
-static void on_connection(PA_GCC_UNUSED pa_socket_client *c, pa_iochannel*io, void *userdata) {
+static void on_connection(pa_socket_client *c, pa_iochannel*io, void *userdata) {
struct userdata *u = userdata;
pa_socket_client_unref(u->client);
diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c
index caa7a1fa..ce766258 100644
--- a/src/modules/module-hal-detect.c
+++ b/src/modules/module-hal-detect.c
@@ -108,7 +108,7 @@ static void hal_device_free(struct device* d) {
pa_xfree(d);
}
-static void hal_device_free_cb(void *d, PA_GCC_UNUSED void *data) {
+static void hal_device_free_cb(void *d, void *data) {
hal_device_free(d);
}
diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c
index f34f7be3..97e97dc7 100644
--- a/src/modules/module-lirc.c
+++ b/src/modules/module-lirc.c
@@ -65,7 +65,7 @@ struct userdata {
static int lirc_in_use = 0;
-static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void*userdata) {
+static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void*userdata) {
struct userdata *u = userdata;
char *name = NULL, *code = NULL;
@@ -122,7 +122,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC
pa_log("Failed to get sink '%s'", u->sink_name);
else {
int i;
- pa_cvolume cv = *pa_sink_get_volume(s);
+ pa_cvolume cv = *pa_sink_get_volume(s, FALSE);
#define DELTA (PA_VOLUME_NORM/20)
@@ -159,7 +159,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC
case MUTE_TOGGLE:
- pa_sink_set_mute(s, !pa_sink_get_mute(s));
+ pa_sink_set_mute(s, !pa_sink_get_mute(s, FALSE));
break;
case INVALID:
diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c
index 7da77c0d..21f176a4 100644
--- a/src/modules/module-mmkbd-evdev.c
+++ b/src/modules/module-mmkbd-evdev.c
@@ -76,7 +76,7 @@ struct userdata {
pa_module *module;
};
-static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void*userdata) {
+static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void*userdata) {
struct userdata *u = userdata;
pa_assert(io);
@@ -113,7 +113,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC
pa_log("Failed to get sink '%s'", u->sink_name);
else {
int i;
- pa_cvolume cv = *pa_sink_get_volume(s);
+ pa_cvolume cv = *pa_sink_get_volume(s, FALSE);
#define DELTA (PA_VOLUME_NORM/20)
@@ -142,7 +142,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC
case MUTE_TOGGLE:
- pa_sink_set_mute(s, !pa_sink_get_mute(s));
+ pa_sink_set_mute(s, !pa_sink_get_mute(s, FALSE));
break;
case INVALID:
diff --git a/src/modules/module-native-protocol-fd.c b/src/modules/module-native-protocol-fd.c
index fa9c0e4f..f17f435a 100644
--- a/src/modules/module-native-protocol-fd.c
+++ b/src/modules/module-native-protocol-fd.c
@@ -48,7 +48,8 @@ static const char* const valid_modargs[] = {
int pa__init(pa_module*m) {
pa_iochannel *io;
pa_modargs *ma;
- int fd, r = -1;
+ int32_t fd;
+ int r = -1;
pa_native_options *options = NULL;
pa_assert(m);
@@ -63,18 +64,16 @@ int pa__init(pa_module*m) {
goto finish;
}
- options = pa_native_options_new();
- options->module = m;
- options->auth_anonymous = TRUE;
+ m->userdata = pa_native_protocol_get(m->core);
io = pa_iochannel_new(m->core->mainloop, fd, fd);
- m->userdata = pa_native_protocol_get(m->core);
+ options = pa_native_options_new();
+ options->module = m;
+ options->auth_anonymous = TRUE;
pa_native_protocol_connect(m->userdata, io, options);
- pa_native_options_unref(options);
-
r = 0;
finish:
diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c
index 8136c6fc..4fe439f9 100644
--- a/src/modules/module-protocol-stub.c
+++ b/src/modules/module-protocol-stub.c
@@ -260,7 +260,7 @@ int pa__init(pa_module*m) {
goto fail;
}
- u = pa_xnew0(struct userdata, 1);
+ m->userdata = u = pa_xnew0(struct userdata, 1);
u->module = m;
#if defined(USE_PROTOCOL_SIMPLE)
@@ -368,8 +368,6 @@ int pa__init(pa_module*m) {
# endif
#endif
- m->userdata = u;
-
if (ma)
pa_modargs_free(ma);
@@ -390,7 +388,8 @@ void pa__done(pa_module*m) {
pa_assert(m);
- u = m->userdata;
+ if (!(u = m->userdata))
+ return;
#if defined(USE_PROTOCOL_SIMPLE)
if (u->simple_protocol) {
diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c
index ec4e7c79..7bbb47d5 100644
--- a/src/modules/module-stream-restore.c
+++ b/src/modules/module-stream-restore.c
@@ -306,8 +306,11 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n
if (u->restore_device &&
(s = pa_namereg_get(c, e->device, PA_NAMEREG_SINK, TRUE))) {
- pa_log_info("Restoring device for stream %s.", name);
- new_data->sink = s;
+ if (!new_data->sink) {
+ pa_log_info("Restoring device for stream %s.", name);
+ new_data->sink = s;
+ } else
+ pa_log_info("Not restore device for stream %s, because already set.", name);
}
pa_xfree(e);
@@ -330,13 +333,20 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu
if ((e = read_entry(u, name))) {
if (u->restore_volume) {
- pa_log_info("Restoring volume for sink input %s.", name);
- pa_sink_input_new_data_set_volume(new_data, pa_cvolume_remap(&e->volume, &e->channel_map, &new_data->channel_map));
+
+ if (!new_data->volume_is_set) {
+ pa_log_info("Restoring volume for sink input %s.", name);
+ pa_sink_input_new_data_set_volume(new_data, pa_cvolume_remap(&e->volume, &e->channel_map, &new_data->channel_map));
+ } else
+ pa_log_debug("Not restoring volume for sink input %s, because already set.", name);
}
if (u->restore_muted) {
- pa_log_info("Restoring mute state for sink input %s.", name);
- pa_sink_input_new_data_set_muted(new_data, e->muted);
+ if (!new_data->muted_is_set) {
+ pa_log_info("Restoring mute state for sink input %s.", name);
+ pa_sink_input_new_data_set_muted(new_data, e->muted);
+ } else
+ pa_log_debug("Not restoring mute state for sink input %s, because already set.", name);
}
pa_xfree(e);
@@ -360,10 +370,14 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou
pa_source *s;
if (u->restore_device &&
+ !new_data->direct_on_input &&
(s = pa_namereg_get(c, e->device, PA_NAMEREG_SOURCE, TRUE))) {
- pa_log_info("Restoring device for stream %s.", name);
- new_data->source = s;
+ if (!new_data->source) {
+ pa_log_info("Restoring device for stream %s.", name);
+ new_data->source = s;
+ } else
+ pa_log_info("Not restroing device for stream %s, because already set", name);
}
pa_xfree(e);
@@ -408,7 +422,7 @@ static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
char *n;
pa_sink *s;
- if (!(n = get_name(si->proplist, "sink_input")))
+ if (!(n = get_name(si->proplist, "sink-input")))
continue;
if (strcmp(name, n)) {
@@ -417,8 +431,9 @@ static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
}
if (u->restore_volume) {
+ pa_cvolume v = e->volume;
pa_log_info("Restoring volume for sink input %s.", name);
- pa_sink_input_set_volume(si, pa_cvolume_remap(&e->volume, &e->channel_map, &si->channel_map));
+ pa_sink_input_set_volume(si, pa_cvolume_remap(&v, &e->channel_map, &si->channel_map));
}
if (u->restore_muted) {
@@ -490,7 +505,7 @@ static void dump_database(struct userdata *u) {
static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
struct userdata *u;
uint32_t command;
- pa_tagstruct *reply;
+ pa_tagstruct *reply = NULL;
pa_assert(p);
pa_assert(m);
@@ -552,7 +567,7 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
case SUBCOMMAND_WRITE: {
uint32_t mode;
- pa_bool_t apply_immediately;
+ pa_bool_t apply_immediately = FALSE;
if (pa_tagstruct_getu32(t, &mode) < 0 ||
pa_tagstruct_get_boolean(t, &apply_immediately) < 0)
@@ -571,6 +586,7 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
pa_bool_t muted;
struct entry entry;
datum key, data;
+ int k;
memset(&entry, 0, sizeof(entry));
@@ -593,7 +609,7 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
data.dptr = (void*) &entry;
data.dsize = sizeof(entry);
- if (gdbm_store(u->gdbm_file, key, data, mode == PA_UPDATE_REPLACE ? GDBM_REPLACE : GDBM_INSERT) == 1)
+ if ((k = gdbm_store(u->gdbm_file, key, data, mode == PA_UPDATE_REPLACE ? GDBM_REPLACE : GDBM_INSERT)) == 0)
if (apply_immediately)
apply_entry(u, name, &entry);
}
diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c
index 5e542253..1423cbc1 100644
--- a/src/modules/rtp/module-rtp-send.c
+++ b/src/modules/rtp/module-rtp-send.c
@@ -67,10 +67,12 @@ PA_MODULE_USAGE(
"destination=<destination IP address> "
"port=<port number> "
"mtu=<maximum transfer unit> "
- "loop=<loopback to local host?>"
+ "loop=<loopback to local host?> "
+ "ttl=<ttl value>"
);
#define DEFAULT_PORT 46000
+#define DEFAULT_TTL 1
#define SAP_PORT 9875
#define DEFAULT_DESTINATION "224.0.0.56"
#define MEMBLOCKQ_MAXLENGTH (1024*170)
@@ -86,6 +88,7 @@ static const char* const valid_modargs[] = {
"port",
"mtu" ,
"loop",
+ "ttl",
NULL
};
@@ -167,6 +170,7 @@ int pa__init(pa_module*m) {
pa_modargs *ma = NULL;
const char *dest;
uint32_t port = DEFAULT_PORT, mtu;
+ uint32_t ttl = DEFAULT_TTL;
int af, fd = -1, sap_fd = -1;
pa_source *s;
pa_sample_spec ss;
@@ -235,6 +239,11 @@ int pa__init(pa_module*m) {
if (port & 1)
pa_log_warn("Port number not even as suggested in RFC3550!");
+ if (pa_modargs_get_value_u32(ma, "ttl", &ttl) < 0 || ttl < 1 || ttl > 0xFF) {
+ pa_log("ttl= expects a numerical argument between 1 and 255.");
+ goto fail;
+ }
+
dest = pa_modargs_get_value(ma, "destination", DEFAULT_DESTINATION);
if (inet_pton(AF_INET6, dest, &sa6.sin6_addr) > 0) {
@@ -279,6 +288,15 @@ int pa__init(pa_module*m) {
goto fail;
}
+ if (ttl != DEFAULT_TTL) {
+ int _ttl = (int) ttl;
+
+ if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &_ttl, sizeof(_ttl)) < 0) {
+ pa_log("IP_MULTICAST_TTL failed: %s", pa_cstrerror(errno));
+ goto fail;
+ }
+ }
+
/* If the socket queue is full, let's drop packets */
pa_make_fd_nonblock(fd);
pa_make_udp_socket_low_delay(fd);
@@ -290,6 +308,7 @@ int pa__init(pa_module*m) {
pa_proplist_sets(data.proplist, "rtp.destination", dest);
pa_proplist_setf(data.proplist, "rtp.mtu", "%lu", (unsigned long) mtu);
pa_proplist_setf(data.proplist, "rtp.port", "%lu", (unsigned long) port);
+ pa_proplist_setf(data.proplist, "rtp.ttl", "%lu", (unsigned long) ttl);
data.driver = __FILE__;
data.module = m;
data.source = s;
@@ -342,7 +361,7 @@ int pa__init(pa_module*m) {
pa_rtp_context_init_send(&u->rtp_context, fd, m->core->cookie, payload, pa_frame_size(&ss));
pa_sap_context_init_send(&u->sap_context, sap_fd, p);
- pa_log_info("RTP stream initialized with mtu %u on %s:%u, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dest, port, u->rtp_context.ssrc, payload, u->rtp_context.sequence);
+ pa_log_info("RTP stream initialized with mtu %u on %s:%u ttl=%u, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dest, port, ttl, u->rtp_context.ssrc, payload, u->rtp_context.sequence);
pa_log_info("SDP-Data:\n%s\nEOF", p);
pa_sap_send(&u->sap_context, 0);