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) {  | 
