diff options
Diffstat (limited to 'src/modules/module-alsa-source.c')
-rw-r--r-- | src/modules/module-alsa-source.c | 59 |
1 files changed, 40 insertions, 19 deletions
diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 2827ecfe..b6c6ed1a 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -238,7 +238,7 @@ static size_t check_left_to_record(struct userdata *u, snd_pcm_sframes_t n) { return left_to_record; } -static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec) { +static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled) { int work_done = 0; pa_usec_t max_sleep_usec = 0, process_usec = 0; size_t left_to_record; @@ -255,7 +255,7 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec) { snd_pcm_hwsync(u->pcm_handle); - if (PA_UNLIKELY((n = snd_pcm_avail_update(u->pcm_handle)) < 0)) { + if (PA_UNLIKELY((n = pa_alsa_safe_avail_update(u->pcm_handle, u->hwbuf_size, &u->source->sample_spec)) < 0)) { if ((r = try_recover(u, "snd_pcm_avail_update", (int) n)) == 0) continue; @@ -266,11 +266,20 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec) { left_to_record = check_left_to_record(u, n); if (u->use_tsched) - if (pa_bytes_to_usec(left_to_record, &u->source->sample_spec) > process_usec+max_sleep_usec/2) + if (!polled && + pa_bytes_to_usec(left_to_record, &u->source->sample_spec) > process_usec+max_sleep_usec/2) break; - if (PA_UNLIKELY(n <= 0)) + if (PA_UNLIKELY(n <= 0)) { + + if (polled) + pa_log("ALSA woke us up to read new data from the device, but there was actually nothing to read! " + "Most likely this is an ALSA driver bug. Please report this issue to the PulseAudio device."); + break; + } + + polled = FALSE; for (;;) { int err; @@ -282,7 +291,7 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec) { /* pa_log_debug("%lu frames to read", (unsigned long) frames); */ - if (PA_UNLIKELY((err = snd_pcm_mmap_begin(u->pcm_handle, &areas, &offset, &frames)) < 0)) { + if (PA_UNLIKELY((err = pa_alsa_safe_mmap_begin(u->pcm_handle, &areas, &offset, &frames, u->hwbuf_size, &u->source->sample_spec)) < 0)) { if ((r = try_recover(u, "snd_pcm_mmap_begin", err)) == 0) continue; @@ -336,7 +345,7 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec) { return work_done; } -static int unix_read(struct userdata *u, pa_usec_t *sleep_usec) { +static int unix_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled) { int work_done = 0; pa_usec_t max_sleep_usec = 0, process_usec = 0; size_t left_to_record; @@ -353,7 +362,7 @@ static int unix_read(struct userdata *u, pa_usec_t *sleep_usec) { snd_pcm_hwsync(u->pcm_handle); - if (PA_UNLIKELY((n = snd_pcm_avail_update(u->pcm_handle)) < 0)) { + if (PA_UNLIKELY((n = pa_alsa_safe_avail_update(u->pcm_handle, u->hwbuf_size, &u->source->sample_spec)) < 0)) { if ((r = try_recover(u, "snd_pcm_avail_update", (int) n)) == 0) continue; @@ -364,11 +373,20 @@ static int unix_read(struct userdata *u, pa_usec_t *sleep_usec) { left_to_record = check_left_to_record(u, n); if (u->use_tsched) - if (pa_bytes_to_usec(left_to_record, &u->source->sample_spec) > process_usec+max_sleep_usec/2) + if (!polled && + pa_bytes_to_usec(left_to_record, &u->source->sample_spec) > process_usec+max_sleep_usec/2) break; - if (PA_UNLIKELY(n <= 0)) + if (PA_UNLIKELY(n <= 0)) { + + if (polled) + pa_log("ALSA woke us up to read new data from the device, but there was actually nothing to read! " + "Most likely this is an ALSA driver bug. Please report this issue to the PulseAudio developers."); + return work_done; + } + + polled = FALSE; for (;;) { void *p; @@ -742,7 +760,7 @@ static int source_get_volume_cb(pa_source *s) { VALGRIND_MAKE_MEM_DEFINED(&alsa_vol, sizeof(alsa_vol)); #endif - r.values[i] = pa_sw_volume_from_dB((double) alsa_vol / 100.0); + r.values[i] = pa_sw_volume_from_dB((double) (alsa_vol - u->hw_dB_max) / 100.0); } else { if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0) @@ -764,7 +782,7 @@ static int source_get_volume_cb(pa_source *s) { 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_cvolume_set(&r, s->sample_spec.channels, pa_sw_volume_from_dB((double) (alsa_vol - u->hw_dB_max) / 100.0)); } else { @@ -821,6 +839,7 @@ static int source_set_volume_cb(pa_source *s) { if (u->hw_dB_supported) { alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100); + alsa_vol += u->hw_dB_max; alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_dB_min, u->hw_dB_max); if ((err = snd_mixer_selem_set_capture_dB(u->mixer_elem, u->mixer_map[i], alsa_vol, 1)) < 0) @@ -829,7 +848,7 @@ static int source_set_volume_cb(pa_source *s) { 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); + r.values[i] = pa_sw_volume_from_dB((double) (alsa_vol - u->hw_dB_max) / 100.0); } else { alsa_vol = to_alsa_volume(u, vol); @@ -852,6 +871,7 @@ static int source_set_volume_cb(pa_source *s) { if (u->hw_dB_supported) { alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100); + alsa_vol += u->hw_dB_max; 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) @@ -860,7 +880,7 @@ static int source_set_volume_cb(pa_source *s) { if ((err = snd_mixer_selem_get_capture_dB(u->mixer_elem, SND_MIXER_SCHN_MONO, &alsa_vol)) < 0) goto fail; - pa_cvolume_set(&r, s->volume.channels, pa_sw_volume_from_dB((double) alsa_vol / 100.0)); + pa_cvolume_set(&r, s->volume.channels, pa_sw_volume_from_dB((double) (alsa_vol - u->hw_dB_max) / 100.0)); } else { alsa_vol = to_alsa_volume(u, vol); @@ -948,6 +968,7 @@ static void source_update_requested_latency_cb(pa_source *s) { static void thread_func(void *userdata) { struct userdata *u = userdata; + unsigned short revents = 0; pa_assert(u); @@ -970,9 +991,9 @@ static void thread_func(void *userdata) { pa_usec_t sleep_usec = 0; if (u->use_mmap) - work_done = mmap_read(u, &sleep_usec); + work_done = mmap_read(u, &sleep_usec, revents & POLLIN); else - work_done = unix_read(u, &sleep_usec); + work_done = unix_read(u, &sleep_usec, revents & POLLIN); if (work_done < 0) goto fail; @@ -1014,7 +1035,6 @@ static void thread_func(void *userdata) { /* Tell ALSA about this and process its response */ if (PA_SOURCE_IS_OPENED(u->source->thread_info.state)) { struct pollfd *pollfd; - unsigned short revents = 0; int err; unsigned n; @@ -1025,7 +1045,7 @@ static void thread_func(void *userdata) { goto fail; } - if (revents & (POLLERR|POLLNVAL|POLLHUP|POLLPRI)) { + if (revents & (POLLOUT|POLLERR|POLLNVAL|POLLHUP|POLLPRI)) { if (pa_alsa_recover_from_poll(u->pcm_handle, revents) < 0) goto fail; @@ -1034,7 +1054,8 @@ static void thread_func(void *userdata) { if (revents && u->use_tsched) pa_log_debug("Wakeup from ALSA!%s%s", (revents & POLLIN) ? " INPUT" : "", (revents & POLLOUT) ? " OUTPUT" : ""); - } + } else + revents = 0; } fail: @@ -1215,7 +1236,7 @@ int pa__init(pa_module*m) { } if (found) - if (!(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", "Mic"))) + if (!(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", "Mic", FALSE))) found = FALSE; if (!found) { |