diff options
39 files changed, 438 insertions, 272 deletions
diff --git a/configure.ac b/configure.ac index c28a72cd..11b091bb 100644 --- a/configure.ac +++ b/configure.ac @@ -638,7 +638,7 @@ AC_ARG_ENABLE([alsa], [alsa=auto]) if test "x${alsa}" != xno ; then - PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.17 ], + PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.19 ], [ HAVE_ALSA=1 AC_DEFINE([HAVE_ALSA], 1, [Have ALSA?]) @@ -646,7 +646,7 @@ if test "x${alsa}" != xno ; then [ HAVE_ALSA=0 if test "x$alsa" = xyes ; then - AC_MSG_ERROR([*** Needed alsa >= 1.0.17 support not found]) + AC_MSG_ERROR([*** Needed alsa >= 1.0.19 support not found]) fi ]) else @@ -1220,6 +1220,12 @@ AC_SUBST(PA_SYSTEM_STATE_PATH) # Output # ################################### +AC_ARG_ENABLE([legacy-runtime-dir], + AS_HELP_STRING([--disable-legacy-runtime-dir], [Try to connect on legacy (< 0.9.12) socket paths.])) +if test "x$enable_legacy_runtime_dir" != "xno" ; then + AC_DEFINE(ENABLE_LEGACY_RUNTIME_DIR, [1], [Legacy runtime dir]) +fi + AC_ARG_ENABLE( [static-bins], AS_HELP_STRING([--enable-static-bins],[Statically link executables.]), diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 7d3b89f0..7dfef27f 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -639,7 +639,7 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { if (c->config_file) pa_strbuf_printf(s, _("### Read from configuration file: %s ###\n"), c->config_file); - pa_assert(c->log_level <= PA_LOG_LEVEL_MAX); + pa_assert(c->log_level < PA_LOG_LEVEL_MAX); pa_strbuf_printf(s, "daemonize = %s\n", pa_yes_no(c->daemonize)); pa_strbuf_printf(s, "fail = %s\n", pa_yes_no(c->fail)); diff --git a/src/daemon/main.c b/src/daemon/main.c index 936c214d..5f94ec66 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -348,7 +348,6 @@ int main(int argc, char *argv[]) { pa_time_event *win32_timer; struct timeval win32_tv; #endif - char *lf = NULL; int autospawn_fd = -1; pa_bool_t autospawn_locked = FALSE; @@ -369,8 +368,11 @@ int main(int argc, char *argv[]) { * value of $LD_BIND_NOW on initialization. */ pa_set_env("LD_BIND_NOW", "1"); - pa_assert_se(rp = pa_readlink("/proc/self/exe")); - pa_assert_se(execv(rp, argv) == 0); + + if ((rp = pa_readlink("/proc/self/exe"))) + pa_assert_se(execv(rp, argv) == 0); + else + pa_log_warn("Couldn't read /proc/self/exe, cannot self execute. Running in a chroot()?"); } #endif @@ -997,9 +999,6 @@ finish: pa_autospawn_lock_done(FALSE); } - if (lf) - pa_xfree(lf); - #ifdef OS_IS_WIN32 if (win32_timer) pa_mainloop_get_api(mainloop)->time_free(win32_timer); diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 1474cfee..eeac5e76 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -1227,6 +1227,91 @@ static void set_sink_name(pa_sink_new_data *data, pa_modargs *ma, const char *de pa_xfree(t); } +static int setup_mixer(struct userdata *u, pa_bool_t ignore_dB) { + pa_assert(u); + + if (!u->mixer_handle) + return 0; + + pa_assert(u->mixer_elem); + + if (snd_mixer_selem_has_playback_volume(u->mixer_elem)) { + pa_bool_t suitable = FALSE; + + 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."); + else if (u->hw_volume_min >= u->hw_volume_max) + pa_log_warn("Your kernel driver is broken: it reports a volume range from %li to %li which makes no sense.", u->hw_volume_min, u->hw_volume_max); + else { + pa_log_info("Volume ranges from %li to %li.", u->hw_volume_min, u->hw_volume_max); + suitable = TRUE; + } + + if (suitable) { + if (ignore_dB || 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 or data is ignored."); + 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 + + if (u->hw_dB_min >= u->hw_dB_max) + pa_log_warn("Your kernel driver is broken: it reports a volume range from %0.2f dB to %0.2f dB which makes no sense.", (double) u->hw_dB_min/100.0, (double) u->hw_dB_max/100.0); + else { + pa_log_info("Volume ranges from %0.2f dB to %0.2f dB.", (double) u->hw_dB_min/100.0, (double) u->hw_dB_max/100.0); + u->hw_dB_supported = TRUE; + + if (u->hw_dB_max > 0) { + u->sink->base_volume = pa_sw_volume_from_dB(- (double) u->hw_dB_max/100.0); + pa_log_info("Fixing base volume to %0.2f dB", pa_sw_volume_to_dB(u->sink->base_volume)); + } else + pa_log_info("No particular base volume set, fixing to 0 dB"); + } + } + + if (!u->hw_dB_supported && + u->hw_volume_max - u->hw_volume_min < 3) { + + 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 (suitable) { + u->mixer_seperate_channels = pa_alsa_calc_mixer_map(u->mixer_elem, &u->sink->channel_map, u->mixer_map, TRUE) >= 0; + + 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 (!u->hw_dB_supported) + u->sink->n_volume_steps = u->hw_volume_max - u->hw_volume_min + 1; + } 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(); + + if (pa_alsa_fdlist_set_mixer(u->mixer_fdl, u->mixer_handle, u->core->mainloop) < 0) { + pa_log("Failed to initialize file descriptor monitoring"); + return -1; + } + + snd_mixer_elem_set_callback(u->mixer_elem, mixer_callback); + snd_mixer_elem_set_callback_private(u->mixer_elem, u); + + return 0; +} + pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_card *card, const pa_alsa_profile_info *profile) { struct userdata *u = NULL; @@ -1236,14 +1321,10 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca uint32_t nfrags, hwbuf_size, frag_size, tsched_size, tsched_watermark; snd_pcm_uframes_t period_frames, tsched_frames; size_t frame_size; - snd_pcm_info_t *pcm_info = NULL; - int err; pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE; pa_usec_t usec; pa_sink_new_data data; - snd_pcm_info_alloca(&pcm_info); - pa_assert(m); pa_assert(ma); @@ -1368,7 +1449,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca } if (use_tsched && (!b || !d)) { - pa_log_info("Cannot enabled timer-based scheduling, falling back to sound IRQ scheduling."); + pa_log_info("Cannot enable timer-based scheduling, falling back to sound IRQ scheduling."); u->use_tsched = use_tsched = FALSE; } @@ -1378,11 +1459,6 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca if (u->use_tsched) pa_log_info("Successfully enabled timer-based scheduling mode."); - if ((err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) { - pa_log("Error fetching PCM info: %s", snd_strerror(err)); - goto fail; - } - /* ALSA might tweak the sample spec, so recalculate the frame size */ frame_size = pa_frame_size(&ss); @@ -1396,7 +1472,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca pa_sink_new_data_set_sample_spec(&data, &ss); pa_sink_new_data_set_channel_map(&data, &map); - pa_alsa_init_proplist_pcm(m->core, data.proplist, pcm_info); + pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags)); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size)); @@ -1456,86 +1532,8 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca if (update_sw_params(u) < 0) goto fail; - pa_memchunk_reset(&u->memchunk); - - if (u->mixer_handle) { - pa_assert(u->mixer_elem); - - if (snd_mixer_selem_has_playback_volume(u->mixer_elem)) { - pa_bool_t suitable = FALSE; - - 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."); - else if (u->hw_volume_min >= u->hw_volume_max) - pa_log_warn("Your kernel driver is broken: it reports a volume range from %li to %li which makes no sense.", u->hw_volume_min, u->hw_volume_max); - else { - pa_log_info("Volume ranges from %li to %li.", u->hw_volume_min, u->hw_volume_max); - suitable = TRUE; - } - - if (suitable) { - if (ignore_dB || 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 or data is ignored."); - 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 - - if (u->hw_dB_min >= u->hw_dB_max) - pa_log_warn("Your kernel driver is broken: it reports a volume range from %0.2f dB to %0.2f dB which makes no sense.", (double) u->hw_dB_min/100.0, (double) u->hw_dB_max/100.0); - else { - pa_log_info("Volume ranges from %0.2f dB to %0.2f dB.", (double) u->hw_dB_min/100.0, (double) u->hw_dB_max/100.0); - u->hw_dB_supported = TRUE; - - if (u->hw_dB_max > 0) { - u->sink->base_volume = pa_sw_volume_from_dB(- (double) u->hw_dB_max/100.0); - pa_log_info("Fixing base volume to %0.2f dB", pa_sw_volume_to_dB(u->sink->base_volume)); - } else - pa_log_info("No particular base volume set, fixing to 0 dB"); - } - } - - if (!u->hw_dB_supported && - u->hw_volume_max - u->hw_volume_min < 3) { - - 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 (suitable) { - u->mixer_seperate_channels = pa_alsa_calc_mixer_map(u->mixer_elem, &map, u->mixer_map, TRUE) >= 0; - - 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 (!u->hw_dB_supported) - u->sink->n_volume_steps = u->hw_volume_max - u->hw_volume_min + 1; - } 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(); - - if (pa_alsa_fdlist_set_mixer(u->mixer_fdl, u->mixer_handle, m->core->mainloop) < 0) { - pa_log("Failed to initialize file descriptor monitoring"); - goto fail; - } - - snd_mixer_elem_set_callback(u->mixer_elem, mixer_callback); - snd_mixer_elem_set_callback_private(u->mixer_elem, u); - } else - u->mixer_fdl = NULL; + if (setup_mixer(u, ignore_dB) < 0) + goto fail; pa_alsa_dump(u->pcm_handle); diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 192645d0..81d7c0bb 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -1062,6 +1062,91 @@ static void set_source_name(pa_source_new_data *data, pa_modargs *ma, const char pa_xfree(t); } +static int setup_mixer(struct userdata *u, pa_bool_t ignore_dB) { + pa_assert(u); + + if (!u->mixer_handle) + return 0; + + pa_assert(u->mixer_elem); + + if (snd_mixer_selem_has_capture_volume(u->mixer_elem)) { + pa_bool_t suitable = FALSE; + + 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."); + else if (u->hw_volume_min >= u->hw_volume_max) + pa_log_warn("Your kernel driver is broken: it reports a volume range from %li to %li which makes no sense.", u->hw_volume_min, u->hw_volume_max); + else { + pa_log_info("Volume ranges from %li to %li.", u->hw_volume_min, u->hw_volume_max); + suitable = TRUE; + } + + if (suitable) { + if (ignore_dB || 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 or data is ignored."); + 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 + + if (u->hw_dB_min >= u->hw_dB_max) + pa_log_warn("Your kernel driver is broken: it reports a volume range from %0.2f dB to %0.2f dB which makes no sense.", (double) u->hw_dB_min/100.0, (double) u->hw_dB_max/100.0); + else { + pa_log_info("Volume ranges from %0.2f dB to %0.2f dB.", (double) u->hw_dB_min/100.0, (double) u->hw_dB_max/100.0); + u->hw_dB_supported = TRUE; + + if (u->hw_dB_max > 0) { + u->source->base_volume = pa_sw_volume_from_dB(- (double) u->hw_dB_max/100.0); + pa_log_info("Fixing base volume to %0.2f dB", pa_sw_volume_to_dB(u->source->base_volume)); + } else + pa_log_info("No particular base volume set, fixing to 0 dB"); + } + } + + if (!u->hw_dB_supported && + 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; + } + } + + if (suitable) { + u->mixer_seperate_channels = pa_alsa_calc_mixer_map(u->mixer_elem, &u->source->channel_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"); + + if (!u->hw_dB_supported) + u->source->n_volume_steps = u->hw_volume_max - u->hw_volume_min + 1; + } 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(); + + if (pa_alsa_fdlist_set_mixer(u->mixer_fdl, u->mixer_handle, u->core->mainloop) < 0) { + pa_log("Failed to initialize file descriptor monitoring"); + return -1; + } + + snd_mixer_elem_set_callback(u->mixer_elem, mixer_callback); + snd_mixer_elem_set_callback_private(u->mixer_elem, u); + + return 0; +} + pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, pa_card *card, const pa_alsa_profile_info *profile) { struct userdata *u = NULL; @@ -1071,14 +1156,11 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p uint32_t nfrags, hwbuf_size, frag_size, tsched_size, tsched_watermark; snd_pcm_uframes_t period_frames, tsched_frames; size_t frame_size; - snd_pcm_info_t *pcm_info = NULL; - int err; pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE; pa_source_new_data data; - snd_pcm_info_alloca(&pcm_info); - pa_assert(m); + pa_assert(ma); ss = m->core->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) { @@ -1193,7 +1275,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p } if (use_tsched && (!b || !d)) { - pa_log_info("Cannot enabled timer-based scheduling, falling back to sound IRQ scheduling."); + pa_log_info("Cannot enable timer-based scheduling, falling back to sound IRQ scheduling."); u->use_tsched = use_tsched = FALSE; } @@ -1203,11 +1285,6 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p if (u->use_tsched) pa_log_info("Successfully enabled timer-based scheduling mode."); - if ((err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) { - pa_log("Error fetching PCM info: %s", snd_strerror(err)); - goto fail; - } - /* ALSA might tweak the sample spec, so recalculate the frame size */ frame_size = pa_frame_size(&ss); @@ -1221,7 +1298,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p pa_source_new_data_set_sample_spec(&data, &ss); pa_source_new_data_set_channel_map(&data, &map); - pa_alsa_init_proplist_pcm(m->core, data.proplist, pcm_info); + pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags)); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size)); @@ -1278,85 +1355,8 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p if (update_sw_params(u) < 0) goto fail; - if (u->mixer_handle) { - pa_assert(u->mixer_elem); - - if (snd_mixer_selem_has_capture_volume(u->mixer_elem)) { - pa_bool_t suitable = FALSE; - - 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."); - else if (u->hw_volume_min >= u->hw_volume_max) - pa_log_warn("Your kernel driver is broken: it reports a volume range from %li to %li which makes no sense.", u->hw_volume_min, u->hw_volume_max); - else { - pa_log_info("Volume ranges from %li to %li.", u->hw_volume_min, u->hw_volume_max); - suitable = TRUE; - } - - if (suitable) { - if (ignore_dB || 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 or data is ignored."); - 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 - - if (u->hw_dB_min >= u->hw_dB_max) - pa_log_warn("Your kernel driver is broken: it reports a volume range from %0.2f dB to %0.2f dB which makes no sense.", (double) u->hw_dB_min/100.0, (double) u->hw_dB_max/100.0); - else { - pa_log_info("Volume ranges from %0.2f dB to %0.2f dB.", (double) u->hw_dB_min/100.0, (double) u->hw_dB_max/100.0); - u->hw_dB_supported = TRUE; - - if (u->hw_dB_max > 0) { - u->source->base_volume = pa_sw_volume_from_dB(- (double) u->hw_dB_max/100.0); - pa_log_info("Fixing base volume to %0.2f dB", pa_sw_volume_to_dB(u->source->base_volume)); - } else - pa_log_info("No particular base volume set, fixing to 0 dB"); - - } - } - - if (!u->hw_dB_supported && - 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; - } - } - - 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"); - - if (!u->hw_dB_supported) - u->source->n_volume_steps = u->hw_volume_max - u->hw_volume_min + 1; - } 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(); - - if (pa_alsa_fdlist_set_mixer(u->mixer_fdl, u->mixer_handle, m->core->mainloop) < 0) { - pa_log("Failed to initialize file descriptor monitoring"); - goto fail; - } - - snd_mixer_elem_set_callback(u->mixer_elem, mixer_callback); - snd_mixer_elem_set_callback_private(u->mixer_elem, u); - } else - u->mixer_fdl = NULL; + if (setup_mixer(u, ignore_dB) < 0) + goto fail; pa_alsa_dump(u->pcm_handle); diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index d7caa0f0..a0907c4d 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -1,7 +1,7 @@ /*** This file is part of PulseAudio. - Copyright 2004-2006 Lennart Poettering + Copyright 2004-2009 Lennart Poettering Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB PulseAudio is free software; you can redistribute it and/or modify @@ -37,6 +37,7 @@ #include <pulsecore/macro.h> #include <pulsecore/core-util.h> #include <pulsecore/atomic.h> +#include <pulsecore/core-error.h> #include "alsa-util.h" @@ -112,7 +113,7 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { struct pa_alsa_fdlist *fdl = userdata; unsigned num_fds, i; - int err; + int err, n; struct pollfd *temp; pa_assert(a); @@ -121,7 +122,11 @@ static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { a->defer_enable(fdl->defer, 0); - num_fds = (unsigned) snd_mixer_poll_descriptors_count(fdl->mixer); + if ((n = snd_mixer_poll_descriptors_count(fdl->mixer)) < 0) { + pa_log("snd_mixer_poll_descriptors_count() failed: %s", snd_strerror(n)); + return; + } + num_fds = (unsigned) n; if (num_fds != fdl->num_fds) { if (fdl->fds) @@ -342,7 +347,8 @@ int pa_alsa_set_hw_params( goto finish; if (_use_mmap) { - if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) { + + if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) { /* mmap() didn't work, fall back to interleaved */ @@ -805,8 +811,7 @@ snd_pcm_t *pa_alsa_open_by_device_string( SND_PCM_NO_AUTO_CHANNELS| (reformat ? 0 : SND_PCM_NO_AUTO_FORMAT))) < 0) { pa_log_info("Error opening PCM device %s: %s", d, snd_strerror(err)); - pa_xfree(d); - return NULL; + goto fail; } if ((err = pa_alsa_set_hw_params(pcm_handle, ss, nfrags, period_size, tsched_size, use_mmap, use_tsched, require_exact_channel_number)) < 0) { @@ -834,9 +839,9 @@ snd_pcm_t *pa_alsa_open_by_device_string( } pa_log_info("Failed to set hardware parameters on %s: %s", d, snd_strerror(err)); - pa_xfree(d); snd_pcm_close(pcm_handle); - return NULL; + + goto fail; } if (dev) @@ -849,6 +854,11 @@ snd_pcm_t *pa_alsa_open_by_device_string( return pcm_handle; } + +fail: + pa_xfree(d); + + return NULL; } int pa_alsa_probe_profiles( @@ -1361,7 +1371,7 @@ void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card) { #endif } -void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info) { +void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info) { static const char * const alsa_class_table[SND_PCM_CLASS_LAST+1] = { [SND_PCM_CLASS_GENERIC] = "generic", @@ -1382,7 +1392,7 @@ void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_i snd_pcm_class_t class; snd_pcm_subclass_t subclass; - const char *n, *id, *sdn, *cn; + const char *n, *id, *sdn, *cn = NULL; int card; pa_assert(p); @@ -1427,6 +1437,28 @@ void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_i pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, n); } +void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm) { + snd_pcm_hw_params_t *hwparams; + snd_pcm_info_t *info; + int bits, err; + + snd_pcm_hw_params_alloca(&hwparams); + snd_pcm_info_alloca(&info); + + if ((err = snd_pcm_hw_params_current(pcm, hwparams)) < 0) + pa_log_warn("Error fetching hardware parameter info: %s", snd_strerror(err)); + else { + + if ((bits = snd_pcm_hw_params_get_sbits(hwparams)) >= 0) + pa_proplist_setf(p, "alsa.resolution_bits", "%i", bits); + } + + if ((err = snd_pcm_info(pcm, info)) < 0) + pa_log_warn("Error fetching PCM info: %s", snd_strerror(err)); + else + pa_alsa_init_proplist_pcm_info(c, p, info); +} + int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents) { snd_pcm_state_t state; int err; @@ -1525,8 +1557,8 @@ snd_pcm_sframes_t pa_alsa_safe_avail_update(snd_pcm_t *pcm, size_t hwbuf_size, c if (k >= hwbuf_size * 3 || k >= pa_bytes_per_second(ss)*10) - pa_log("snd_pcm_avail_update() returned a value that is exceptionally large: %lu bytes (%lu ms) " - "Most likely this is an ALSA driver bug. Please report this issue to the PulseAudio developers.", + pa_log("snd_pcm_avail_update() returned a value that is exceptionally large: %lu bytes (%lu ms). " + "Most likely this is an ALSA driver bug. Please report this issue to the ALSA developers.", (unsigned long) k, (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC)); return n; @@ -1557,8 +1589,8 @@ int pa_alsa_safe_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas k >= hwbuf_size * 3 || k >= pa_bytes_per_second(ss)*10) - pa_log("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms) " - "Most likely this is an ALSA driver bug. Please report this issue to the PulseAudio developers.", + pa_log("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms). " + "Most likely this is an ALSA driver bug. Please report this issue to the ALSA developers.", (unsigned long) k, (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC)); return r; diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h index 8b083392..9eab6449 100644 --- a/src/modules/alsa/alsa-util.h +++ b/src/modules/alsa/alsa-util.h @@ -120,8 +120,9 @@ void pa_alsa_dump_status(snd_pcm_t *pcm); void pa_alsa_redirect_errors_inc(void); void pa_alsa_redirect_errors_dec(void); -void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info); +void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info); void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card); +void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm); int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents); diff --git a/src/modules/dbus-util.c b/src/modules/dbus-util.c index f6a986a5..4218bca5 100644 --- a/src/modules/dbus-util.c +++ b/src/modules/dbus-util.c @@ -403,8 +403,7 @@ void pa_dbus_pending_free(pa_dbus_pending *p) { pa_assert(p); if (p->pending) { - dbus_pending_call_cancel(p->pending); - dbus_pending_call_unref(p->pending); + dbus_pending_call_cancel(p->pending); /* p->pending is freed by cancel() */ } if (p->message) diff --git a/src/modules/module-card-restore.c b/src/modules/module-card-restore.c index 909c0957..c7696058 100644 --- a/src/modules/module-card-restore.c +++ b/src/modules/module-card-restore.c @@ -191,7 +191,7 @@ static pa_hook_result_t card_new_hook_callback(pa_core *c, pa_card_new_data *new pa_assert(new_data); - if ((e = read_entry(u, new_data->name)) && e->profile) { + if ((e = read_entry(u, new_data->name)) && e->profile[0]) { if (!new_data->active_profile) { pa_card_new_data_set_profile(new_data, e->profile); diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index e6037381..ce04f367 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -370,6 +370,7 @@ static struct device* hal_device_add(struct userdata *u, const char *udi) { d->originating_udi = NULL; d->module = PA_INVALID_INDEX; d->sink_name = d->source_name = d->card_name = NULL; + r = -1; #ifdef HAVE_ALSA if (pa_streq(u->capability, CAPABILITY_ALSA)) diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index 434dc7a0..d935caf6 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -532,6 +532,7 @@ static void apply_entry(struct userdata *u, const char *name, struct entry *e) { pa_xfree(n); continue; } + pa_xfree(n); if (u->restore_volume) { pa_cvolume v; @@ -581,6 +582,7 @@ static void apply_entry(struct userdata *u, const char *name, struct entry *e) { pa_xfree(n); continue; } + pa_xfree(n); if (u->restore_device && e->device_valid && diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index 063ba725..0d86459e 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -562,7 +562,7 @@ static void sap_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event } else { if (!(s = pa_hashmap_get(u->by_origin, info.origin))) { - if (!(s = session_new(u, &info))) + if (!session_new(u, &info)) pa_sdp_info_destroy(&info); } else { diff --git a/src/modules/rtp/sdp.c b/src/modules/rtp/sdp.c index 643361f2..7c547430 100644 --- a/src/modules/rtp/sdp.c +++ b/src/modules/rtp/sdp.c @@ -44,7 +44,7 @@ char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, uint16_t port, uint8_t payload, const pa_sample_spec *ss) { uint32_t ntp; char buf_src[64], buf_dst[64], un[64]; - const char *u, *f, *a; + const char *u, *f; pa_assert(src); pa_assert(dst); @@ -62,8 +62,8 @@ char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, u ntp = (uint32_t) time(NULL) + 2208988800U; - pa_assert_se(a = inet_ntop(af, src, buf_src, sizeof(buf_src))); - pa_assert_se(a = inet_ntop(af, dst, buf_dst, sizeof(buf_dst))); + pa_assert_se(inet_ntop(af, src, buf_src, sizeof(buf_src))); + pa_assert_se(inet_ntop(af, dst, buf_dst, sizeof(buf_dst))); return pa_sprintf_malloc( PA_SDP_HEADER diff --git a/src/pulse/context.c b/src/pulse/context.c index 8686e0de..9309c6b7 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -335,8 +335,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o pa_assert(p); pa_assert(chunk); - pa_assert(chunk->memblock); - pa_assert(chunk->length); + pa_assert(chunk->length > 0); pa_assert(c); pa_assert(PA_REFCNT_VALUE(c) >= 1); @@ -344,11 +343,11 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o if ((s = pa_dynarray_get(c->record_streams, channel))) { - pa_assert(seek == PA_SEEK_RELATIVE); - pa_assert(offset == 0); - - pa_memblockq_seek(s->record_memblockq, offset, seek); - pa_memblockq_push_align(s->record_memblockq, chunk); + if (chunk->memblock) { + pa_memblockq_seek(s->record_memblockq, offset, seek); + pa_memblockq_push_align(s->record_memblockq, chunk); + } else + pa_memblockq_seek(s->record_memblockq, offset+chunk->length, seek); if (s->read_callback) { size_t l; @@ -555,6 +554,7 @@ static void setup_context(pa_context *c, pa_iochannel *io) { pa_context_unref(c); } +#if ENABLE_LEGACY_RUNTIME_DIR static char *get_old_legacy_runtime_dir(void) { char *p, u[128]; struct stat st; @@ -598,10 +598,12 @@ static char *get_very_old_legacy_runtime_dir(void) { return p; } - +#endif static pa_strlist *prepend_per_user(pa_strlist *l) { char *ufn; + +#if ENABLE_LEGACY_RUNTIME_DIR static char *legacy_dir; /* The very old per-user instance path (< 0.9.11). This is supported only to ease upgrades */ @@ -619,6 +621,7 @@ static pa_strlist *prepend_per_user(pa_strlist *l) { pa_xfree(p); pa_xfree(legacy_dir); } +#endif /* The per-user instance */ if ((ufn = pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET))) { diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c index 1d50939c..04bcd4f5 100644 --- a/src/pulse/introspect.c +++ b/src/pulse/introspect.c @@ -162,6 +162,7 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, u i.n_volume_steps = PA_VOLUME_NORM+1; mute = FALSE; state = PA_SINK_INVALID_STATE; + i.card = PA_INVALID_INDEX; if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || @@ -182,7 +183,8 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, u (o->context->version >= 15 && (pa_tagstruct_get_volume(t, &i.base_volume) < 0 || pa_tagstruct_getu32(t, &state) < 0 || - pa_tagstruct_getu32(t, &i.n_volume_steps) < 0))) { + pa_tagstruct_getu32(t, &i.n_volume_steps) < 0 || + pa_tagstruct_getu32(t, &i.card) < 0))) { pa_context_fail(o->context, PA_ERR_PROTOCOL); pa_proplist_free(i.proplist); @@ -293,6 +295,7 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, i.n_volume_steps = PA_VOLUME_NORM+1; mute = FALSE; state = PA_SOURCE_INVALID_STATE; + i.card = PA_INVALID_INDEX; if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || @@ -313,7 +316,8 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, (o->context->version >= 15 && (pa_tagstruct_get_volume(t, &i.base_volume) < 0 || pa_tagstruct_getu32(t, &state) < 0 || - pa_tagstruct_getu32(t, &i.n_volume_steps) < 0))) { + pa_tagstruct_getu32(t, &i.n_volume_steps) < 0 || + pa_tagstruct_getu32(t, &i.card) < 0))) { pa_context_fail(o->context, PA_ERR_PROTOCOL); pa_proplist_free(i.proplist); @@ -517,7 +521,9 @@ static void context_get_card_info_callback(pa_pdispatch *pd, uint32_t command, u for (j = 0; j < i.n_profiles; j++) { if (pa_tagstruct_gets(t, &i.profiles[j].name) < 0 || - pa_tagstruct_gets(t, &i.profiles[j].description) < 0) { + pa_tagstruct_gets(t, &i.profiles[j].description) < 0 || + pa_tagstruct_getu32(t, &i.profiles[j].n_sinks) < 0 || + pa_tagstruct_getu32(t, &i.profiles[j].n_sources)< 0) { pa_context_fail(o->context, PA_ERR_PROTOCOL); pa_xfree(i.profiles); diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h index badc787e..b873a84a 100644 --- a/src/pulse/introspect.h +++ b/src/pulse/introspect.h @@ -215,6 +215,7 @@ typedef struct pa_sink_info { pa_volume_t base_volume; /**< Some kind of "base" volume that refers to unamplified/unattenuated volume in the context of the output device. \since 0.9.15 */ pa_sink_state_t state; /**< State \since 0.9.15 */ uint32_t n_volume_steps; /**< Number of volume steps for sinks which do not support arbitrary volumes. \since 0.9.15 */ + uint32_t card; /**< Card index, or PA_INVALID_INDEX. \since 0.9.15 */ } pa_sink_info; /** Callback prototype for pa_context_get_sink_info_by_name() and friends */ @@ -273,6 +274,7 @@ typedef struct pa_source_info { pa_volume_t base_volume; /**< Some kind of "base" volume that refers to unamplified/unattenuated volume in the context of the input device. \since 0.9.15 */ pa_source_state_t state; /**< State \since 0.9.15 */ uint32_t n_volume_steps; /**< Number of volume steps for sources which do not support arbitrary volumes. \since 0.9.15 */ + uint32_t card; /**< Card index, or PA_INVALID_INDEX. \since 0.9.15 */ } pa_source_info; /** Callback prototype for pa_context_get_source_info_by_name() and friends */ @@ -396,6 +398,8 @@ pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, pa_context_suc typedef struct pa_card_profile_info { const char *name; /**< Name of this profile */ const char *description; /**< Description of this profile */ + uint32_t n_sinks; /**< Number of sinks this profile would create */ + uint32_t n_sources; /**< Number of sources this profile would create */ } pa_card_profile_info; /** Stores information about cards. Please note that this structure diff --git a/src/pulse/util.c b/src/pulse/util.c index b20ea46a..54a188d5 100644 --- a/src/pulse/util.c +++ b/src/pulse/util.c @@ -54,6 +54,8 @@ #endif #include <pulse/xmalloc.h> +#include <pulse/timeval.h> + #include <pulsecore/winsock.h> #include <pulsecore/core-error.h> #include <pulsecore/log.h> @@ -260,8 +262,8 @@ int pa_msleep(unsigned long t) { #elif defined(HAVE_NANOSLEEP) struct timespec ts; - ts.tv_sec = (time_t) (t/1000UL); - ts.tv_nsec = (long) ((t % 1000UL) * 1000000UL); + ts.tv_sec = (time_t) (t / PA_MSEC_PER_SEC); + ts.tv_nsec = (long) ((t % PA_MSEC_PER_SEC) * PA_NSEC_PER_MSEC); return nanosleep(&ts, NULL); #else diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 1df0bd63..5e45c1aa 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -401,7 +401,6 @@ static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b } static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { - pa_module *m; const char *name; pa_core_assert_ref(c); @@ -414,7 +413,7 @@ static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b return -1; } - if (!(m = pa_module_load(c, name, pa_tokenizer_get(t, 2)))) { + if (!pa_module_load(c, name, pa_tokenizer_get(t, 2))) { pa_strbuf_puts(buf, "Module load failed.\n"); return -1; } diff --git a/src/pulsecore/core-error.c b/src/pulsecore/core-error.c index 3d6c2c3b..d9caa946 100644 --- a/src/pulsecore/core-error.c +++ b/src/pulsecore/core-error.c @@ -47,6 +47,9 @@ const char* pa_cstrerror(int errnum) { char *translated, *t; char errbuf[128]; + if (errnum < 0) + errnum = -errnum; + if ((t = PA_STATIC_TLS_GET(cstrerror))) pa_xfree(t); diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index ad6c6ca9..a184bebd 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -704,7 +704,7 @@ void pa_reset_priority(void) { #endif } -static int match(const char *expr, const char *v) { +int pa_match(const char *expr, const char *v) { int k; regex_t re; int r; @@ -744,12 +744,12 @@ int pa_parse_boolean(const char *v) { /* And then we check language dependant */ if ((expr = nl_langinfo(YESEXPR))) if (expr[0]) - if ((r = match(expr, v)) > 0) + if ((r = pa_match(expr, v)) > 0) return 1; if ((expr = nl_langinfo(NOEXPR))) if (expr[0]) - if ((r = match(expr, v)) > 0) + if ((r = pa_match(expr, v)) > 0) return 0; errno = EINVAL; @@ -1411,6 +1411,7 @@ static int make_random_dir_and_link(mode_t m, const char *k) { return -1; } + pa_xfree(p); return 0; } @@ -1443,6 +1444,7 @@ char *pa_get_runtime_dir(void) { 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; } @@ -2459,7 +2461,7 @@ char *pa_machine_id(void) { pa_strip_nl(ln); - if (ln[0]) + if (r && ln[0]) return pa_xstrdup(ln); } @@ -2604,3 +2606,28 @@ char *pa_unescape(char *p) { return p; } + +char *pa_realpath(const char *path) { + char *r, *t; + pa_assert(path); + + /* We want only abolsute paths */ + if (path[0] != '/') { + errno = EINVAL; + return NULL; + } + +#ifndef __GLIBC__ +#error "It's not clear whether this system supports realpath(..., NULL) like GNU libc does. If it doesn't we need a private version of realpath() here." +#endif + + if (!(r = realpath(path, NULL))) + return NULL; + + /* We copy this here in case our pa_xmalloc() is not implemented + * on top of libc malloc() */ + t = pa_xstrdup(r); + pa_xfree(r); + + return t; +} diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index 442815f1..0ba33f31 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -141,6 +141,8 @@ size_t pa_vsnprintf(char *str, size_t size, const char *format, va_list ap); char *pa_truncate_utf8(char *c, size_t l); +int pa_match(const char *expr, const char *v); + char *pa_getcwd(void); char *pa_make_path_absolute(const char *p); pa_bool_t pa_is_path_absolute(const char *p); @@ -219,4 +221,6 @@ char *pa_replace(const char*s, const char*a, const char *b); char *pa_unescape(char *p); +char *pa_realpath(const char *path); + #endif diff --git a/src/pulsecore/hashmap.c b/src/pulsecore/hashmap.c index 3c6f41ec..57607b69 100644 --- a/src/pulsecore/hashmap.c +++ b/src/pulsecore/hashmap.c @@ -138,7 +138,7 @@ int pa_hashmap_put(pa_hashmap *h, const void *key, void *value) { hash = h->hash_func(key) % NBUCKETS; - if ((e = hash_scan(h, hash, key))) + if (hash_scan(h, hash, key)) return -1; if (!(e = pa_flist_pop(PA_STATIC_FLIST_GET(entries)))) diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c index 1ae43839..89b75da3 100644 --- a/src/pulsecore/log.c +++ b/src/pulsecore/log.c @@ -351,6 +351,7 @@ void pa_log_levelv_meta( } errno = saved_errno; + pa_xfree(bt); } void pa_log_level_meta( diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 1d7f4559..fbf0a470 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -57,7 +57,7 @@ #define PA_MEMEXPORT_SLOTS_MAX 128 -#define PA_MEMIMPORT_SLOTS_MAX 128 +#define PA_MEMIMPORT_SLOTS_MAX 160 #define PA_MEMIMPORT_SEGMENTS_MAX 16 struct pa_memblock { diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index e1643cbb..840f4581 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -924,7 +924,7 @@ static int do_read(connection *c) { c->request = PA_MAYBE_INT32_SWAP(c->swap_byte_order, c->request); - if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { + if (c->request < ESD_PROTO_CONNECT || c->request >= ESD_PROTO_MAX) { pa_log("recieved invalid request."); return -1; } diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index c3032618..a963f78a 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -2560,7 +2560,10 @@ static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uin if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID))) name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME); - CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); + if (!name || !pa_namereg_is_valid_name(name)) { + pa_proplist_free(p); + CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID); + } s = upload_stream_new(c, &ss, &map, name, length, p); pa_proplist_free(p); @@ -2749,6 +2752,7 @@ static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sin pa_log_error("Internal sink state is invalid."); pa_tagstruct_putu32(t, pa_sink_get_state(sink)); pa_tagstruct_putu32(t, sink->n_volume_steps); + pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX); } } @@ -2788,6 +2792,7 @@ static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_s pa_log_error("Internal source state is invalid."); pa_tagstruct_putu32(t, pa_source_get_state(source)); pa_tagstruct_putu32(t, source->n_volume_steps); + pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX); } } @@ -2822,6 +2827,8 @@ static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_car while ((p = pa_hashmap_iterate(card->profiles, &state, NULL))) { pa_tagstruct_puts(t, p->name); pa_tagstruct_puts(t, p->description); + pa_tagstruct_putu32(t, p->n_sinks); + pa_tagstruct_putu32(t, p->n_sources); } } @@ -3007,7 +3014,7 @@ static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, p source_fill_tagstruct(c, reply, source); else if (client) client_fill_tagstruct(c, reply, client); - else if (client) + else if (card) card_fill_tagstruct(c, reply, card); else if (module) module_fill_tagstruct(c, reply, module); @@ -3586,24 +3593,30 @@ static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t } } - CHECK_VALIDITY(c->pstream, mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE, tag, PA_ERR_INVALID); + if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) { + pa_proplist_free(p); + CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID); + } if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) { playback_stream *s; s = pa_idxset_get_by_index(c->output_streams, idx); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); - + if (!s || !playback_stream_isinstance(s)) { + pa_proplist_free(p); + CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY); + } pa_sink_input_update_proplist(s->sink_input, mode, p); } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) { record_stream *s; - s = pa_idxset_get_by_index(c->record_streams, idx); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - + if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { + pa_proplist_free(p); + CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY); + } pa_source_output_update_proplist(s->source_output, mode, p); + } else { pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST); @@ -3611,6 +3624,7 @@ static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t } pa_pstream_send_simple_ack(c->pstream, tag); + pa_proplist_free(p); } static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -4066,7 +4080,7 @@ static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m); - CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION); + CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION); if (cb(c->protocol, m, c, tag, t) < 0) protocol_error(c); @@ -4144,17 +4158,20 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o if (playback_stream_isinstance(stream)) { playback_stream *ps = PLAYBACK_STREAM(stream); - if (seek != PA_SEEK_RELATIVE || offset != 0) - pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset, NULL, NULL); + if (chunk->memblock) { + if (seek != PA_SEEK_RELATIVE || offset != 0) + pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset, NULL, NULL); - pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL); + pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL); + } else + pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset+chunk->length, NULL, NULL); } else { upload_stream *u = UPLOAD_STREAM(stream); size_t l; if (!u->memchunk.memblock) { - if (u->length == chunk->length) { + if (u->length == chunk->length && chunk->memblock) { u->memchunk = *chunk; pa_memblock_ref(u->memchunk.memblock); u->length = 0; @@ -4170,17 +4187,22 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o if (l > chunk->length) l = chunk->length; - if (l > 0) { - void *src, *dst; + void *dst; dst = pa_memblock_acquire(u->memchunk.memblock); - src = pa_memblock_acquire(chunk->memblock); - memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length, - (uint8_t*) src+chunk->index, l); + if (chunk->memblock) { + void *src; + src = pa_memblock_acquire(chunk->memblock); + + memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length, + (uint8_t*) src + chunk->index, l); + + pa_memblock_release(chunk->memblock); + } else + pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec); pa_memblock_release(u->memchunk.memblock); - pa_memblock_release(chunk->memblock); u->memchunk.length += l; u->length -= l; diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index 7ff8edc9..ef1105ba 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -832,8 +832,8 @@ static int do_read(pa_pstream *p) { ntohl(p->read.shm_info[PA_PSTREAM_SHM_INDEX]), ntohl(p->read.shm_info[PA_PSTREAM_SHM_LENGTH])))) { - pa_log_warn("Failed to import memory block."); - return -1; + if (pa_log_ratelimit()) + pa_log_debug("Failed to import memory block."); } if (p->recieve_memblock_callback) { @@ -842,7 +842,7 @@ static int do_read(pa_pstream *p) { chunk.memblock = b; chunk.index = 0; - chunk.length = pa_memblock_get_length(b); + chunk.length = b ? pa_memblock_get_length(b) : ntohl(p->read.shm_info[PA_PSTREAM_SHM_LENGTH]); offset = (int64_t) ( (((uint64_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])) << 32) | @@ -857,7 +857,8 @@ static int do_read(pa_pstream *p) { p->recieve_memblock_callback_userdata); } - pa_memblock_unref(b); + if (b) + pa_memblock_unref(b); } goto frame_done; diff --git a/src/pulsecore/rtclock.c b/src/pulsecore/rtclock.c index 5fc6da2b..dcbd1184 100644 --- a/src/pulsecore/rtclock.c +++ b/src/pulsecore/rtclock.c @@ -141,3 +141,11 @@ struct timeval* pa_rtclock_from_wallclock(struct timeval *tv) { return tv; } + +pa_usec_t pa_timespec_load(const struct timespec *ts) { + pa_assert(ts); + + return + (pa_usec_t) ts->tv_sec * PA_USEC_PER_SEC + + (pa_usec_t) ts->tv_nsec / PA_NSEC_PER_USEC; +} diff --git a/src/pulsecore/rtclock.h b/src/pulsecore/rtclock.h index 281461df..03cc1c72 100644 --- a/src/pulsecore/rtclock.h +++ b/src/pulsecore/rtclock.h @@ -42,4 +42,6 @@ void pa_rtclock_hrtimer_enable(void); struct timeval* pa_rtclock_from_wallclock(struct timeval *tv); +pa_usec_t pa_timespec_load(const struct timespec *ts); + #endif diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 4f39d671..7441e971 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -1846,6 +1846,9 @@ void pa_sink_update_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t m pa_sink_assert_ref(s); + pa_assert(!min_latency || !max_latency || + min_latency <= max_latency); + s->thread_info.min_latency = min_latency; s->thread_info.max_latency = max_latency; diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 0009d85c..c0d6d9ea 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -1120,6 +1120,9 @@ void pa_source_update_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec pa_source_assert_ref(s); + pa_assert(!min_latency || !max_latency || + min_latency <= max_latency); + s->thread_info.min_latency = min_latency; s->thread_info.max_latency = max_latency; diff --git a/src/tests/interpol-test.c b/src/tests/interpol-test.c index 9d930774..d7da660c 100644 --- a/src/tests/interpol-test.c +++ b/src/tests/interpol-test.c @@ -39,10 +39,23 @@ static pa_context *context = NULL; static pa_stream *stream = NULL; static pa_mainloop_api *mainloop_api = NULL; +static pa_bool_t playback = TRUE; static void stream_write_cb(pa_stream *p, size_t nbytes, void *userdata) { /* Just some silence */ - pa_stream_write(p, pa_xmalloc0(nbytes), nbytes, pa_xfree, 0, PA_SEEK_RELATIVE); + pa_assert_se(pa_stream_write(p, pa_xmalloc0(nbytes), nbytes, pa_xfree, 0, PA_SEEK_RELATIVE) == 0); +} + +static void stream_read_cb(pa_stream *p, size_t nbytes, void *userdata) { + /* We don't care, just drop the data */ + + while (pa_stream_readable_size(p) > 0) { + const void *d; + size_t b; + + pa_assert_se(pa_stream_peek(p, &d, &b) == 0); + pa_assert_se(pa_stream_drop(p) == 0); + } } /* This is called whenever the context status changes */ @@ -68,8 +81,13 @@ static void context_state_callback(pa_context *c, void *userdata) { stream = pa_stream_new(c, "interpol-test", &ss, NULL); assert(stream); - pa_stream_connect_playback(stream, NULL, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); - pa_stream_set_write_callback(stream, stream_write_cb, NULL); + if (playback) { + pa_assert_se(pa_stream_connect_playback(stream, NULL, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) == 0); + pa_stream_set_write_callback(stream, stream_write_cb, NULL); + } else { + pa_assert_se(pa_stream_connect_record(stream, NULL, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE) == 0); + pa_stream_set_read_callback(stream, stream_read_cb, NULL); + } break; } @@ -90,6 +108,8 @@ int main(int argc, char *argv[]) { struct timeval start, last_info = { 0, 0 }; pa_usec_t old_t = 0, old_rtc = 0; + playback = argc <= 1 || !pa_streq(argv[1], "-r"); + /* Set up a new main loop */ m = pa_threaded_mainloop_new(); assert(m); @@ -106,7 +126,8 @@ int main(int argc, char *argv[]) { pa_gettimeofday(&start); - pa_threaded_mainloop_start(m); + r = pa_threaded_mainloop_start(m); + assert(r >= 0); for (k = 0; k < 5000; k++) { pa_bool_t success = FALSE, changed = FALSE; @@ -138,7 +159,14 @@ int main(int argc, char *argv[]) { if (success) { rtc = pa_timeval_diff(&now, &start); - printf("%i\t%llu\t%llu\t%llu\t%llu\t%u\t%u\n", k, (unsigned long long) rtc, (unsigned long long) t, (unsigned long long) (rtc-old_rtc), (unsigned long long) (t-old_t), changed, playing); + printf("%i\t%llu\t%llu\t%llu\t%llu\t%u\t%u\n", k, + (unsigned long long) rtc, + (unsigned long long) t, + (unsigned long long) (rtc-old_rtc), + (unsigned long long) (t-old_t), + changed, + playing); + fflush(stdout); old_t = t; old_rtc = rtc; diff --git a/src/tests/ipacl-test.c b/src/tests/ipacl-test.c index 7b7564a4..f89665cd 100644 --- a/src/tests/ipacl-test.c +++ b/src/tests/ipacl-test.c @@ -25,6 +25,7 @@ #endif #include "../pulsecore/winsock.h" +#include "../pulsecore/macro.h" #include <pulsecore/ipacl.h> @@ -96,7 +97,7 @@ int main(int argc, char *argv[]) { memset(&sa6, 0, sizeof(sa6)); sa6.sin6_family = AF_INET6; sa6.sin6_port = htons(22); - inet_pton(AF_INET6, "::1", &sa6.sin6_addr); + pa_assert_se(inet_pton(AF_INET6, "::1", &sa6.sin6_addr) == 1); r = connect(fd, (struct sockaddr*) &sa6, sizeof(sa6)); assert(r >= 0); diff --git a/src/tests/sync-playback.c b/src/tests/sync-playback.c index 42c479a1..f2a15601 100644 --- a/src/tests/sync-playback.c +++ b/src/tests/sync-playback.c @@ -174,11 +174,16 @@ int main(int argc, char *argv[]) { pa_context_set_state_callback(context, context_state_callback, NULL); - pa_context_connect(context, NULL, 0, NULL); + /* Connect the context */ + if (pa_context_connect(context, NULL, 0, NULL) < 0) { + fprintf(stderr, "pa_context_connect() failed.\n"); + goto quit; + } if (pa_mainloop_run(m, &ret) < 0) fprintf(stderr, "pa_mainloop_run() failed.\n"); +quit: pa_context_unref(context); for (i = 0; i < NSTREAMS; i++) diff --git a/src/tests/thread-mainloop-test.c b/src/tests/thread-mainloop-test.c index 263cd57d..3bcf4f16 100644 --- a/src/tests/thread-mainloop-test.c +++ b/src/tests/thread-mainloop-test.c @@ -47,7 +47,7 @@ int main(int argc, char *argv[]) { pa_assert_se(m = pa_threaded_mainloop_new()); pa_assert_se(a = pa_threaded_mainloop_get_api(m)); - pa_threaded_mainloop_start(m); + pa_assert_se(pa_threaded_mainloop_start(m) >= 0); pa_threaded_mainloop_lock(m); diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 10015ce4..2224da9a 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -336,7 +336,6 @@ static void context_drain_complete(pa_context*c, void *userdata) { /* Stream draining complete */ static void stream_drain_complete(pa_stream*s, int success, void *userdata) { - pa_operation *o; if (!success) { fprintf(stderr, _("Failed to drain stream: %s\n"), pa_strerror(pa_context_errno(context))); @@ -350,7 +349,7 @@ static void stream_drain_complete(pa_stream*s, int success, void *userdata) { pa_stream_unref(stream); stream = NULL; - if (!(o = pa_context_drain(context, context_drain_complete, NULL))) + if (!pa_context_drain(context, context_drain_complete, NULL)) pa_context_disconnect(context); else { if (verbose) diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 154e7f9c..d3da90e6 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -649,6 +649,7 @@ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { pa_xfree(d); fprintf(stderr, _("Premature end of file\n")); quit(1); + return; } pa_stream_write(s, d, length, pa_xfree, 0, PA_SEEK_RELATIVE); @@ -1029,7 +1030,10 @@ int main(int argc, char *argv[]) { } pa_context_set_state_callback(context, context_state_callback, NULL); - pa_context_connect(context, server, 0, NULL); + if (pa_context_connect(context, server, 0, NULL) < 0) { + fprintf(stderr, _("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context))); + goto quit; + } if (pa_mainloop_run(m, &ret) < 0) { fprintf(stderr, _("pa_mainloop_run() failed.\n")); diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 046bae45..76e86c8d 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1202,7 +1202,7 @@ fail: static void sink_info_cb(pa_context *context, const pa_sink_info *si, int eol, void *userdata) { fd_info *i = userdata; - if (!si && eol < 0) { + if (!si || eol < 0) { i->operation_success = 0; pa_threaded_mainloop_signal(i->mainloop, 0); return; @@ -1224,7 +1224,7 @@ static void sink_info_cb(pa_context *context, const pa_sink_info *si, int eol, v static void source_info_cb(pa_context *context, const pa_source_info *si, int eol, void *userdata) { fd_info *i = userdata; - if (!si && eol < 0) { + if (!si || eol < 0) { i->operation_success = 0; pa_threaded_mainloop_signal(i->mainloop, 0); return; diff --git a/src/utils/paplay.c b/src/utils/paplay.c index df2edf62..dec80e5c 100644 --- a/src/utils/paplay.c +++ b/src/utils/paplay.c @@ -400,7 +400,10 @@ int main(int argc, char *argv[]) { pa_context_set_state_callback(context, context_state_callback, NULL); /* Connect the context */ - pa_context_connect(context, server, 0, NULL); + if (pa_context_connect(context, server, 0, NULL) < 0) { + fprintf(stderr, _("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context))); + goto quit; + } /* Run the main loop */ if (pa_mainloop_run(m, &ret) < 0) { |