diff options
Diffstat (limited to 'src/modules/module-alsa-sink.c')
-rw-r--r-- | src/modules/module-alsa-sink.c | 125 |
1 files changed, 72 insertions, 53 deletions
diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index cd3ebcc2..70a94ee3 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -74,7 +74,7 @@ PA_MODULE_USAGE( #define DEFAULT_DEVICE "default" #define DEFAULT_TSCHED_BUFFER_USEC (2*PA_USEC_PER_SEC) -#define DEFAULT_TSCHED_WATERMARK_USEC (100*PA_USEC_PER_MSEC) +#define DEFAULT_TSCHED_WATERMARK_USEC (10*PA_USEC_PER_MSEC) struct userdata { pa_core *core; @@ -145,6 +145,8 @@ static int mmap_write(struct userdata *u) { const snd_pcm_channel_area_t *areas; snd_pcm_uframes_t offset, frames; + snd_pcm_hwsync(u->pcm_handle); + /* First we determine how many samples are missing to fill the * buffer up to 100% */ @@ -152,20 +154,20 @@ static int mmap_write(struct userdata *u) { pa_log_debug("snd_pcm_avail_update: %s", snd_strerror(n)); - if (n == -EPIPE) { - pa_log_debug("snd_pcm_avail_update: Buffer underrun!"); - u->first = TRUE; - } - - if ((err = snd_pcm_recover(u->pcm_handle, n, 1)) == 0) - continue; - if (err == -EAGAIN) { pa_log_debug("EAGAIN"); return work_done; } - pa_log("snd_pcm_avail_update: %s", snd_strerror(err)); + if (n == -EPIPE) + pa_log_debug("snd_pcm_avail_update: Buffer underrun!"); + + if ((err = snd_pcm_recover(u->pcm_handle, n, 1)) == 0) { + u->first = TRUE; + continue; + } + + pa_log("snd_pcm_recover: %s", snd_strerror(err)); return -1; } @@ -181,19 +183,19 @@ static int mmap_write(struct userdata *u) { pa_log_debug("snd_pcm_mmap_begin: %s", snd_strerror(err)); - if (err == -EPIPE) { - pa_log_debug("snd_pcm_mmap_begin: Buffer underrun!"); - u->first = TRUE; - } - - if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0) - continue; - if (err == -EAGAIN) { pa_log_debug("EAGAIN"); return work_done; } + if (err == -EPIPE) + pa_log_debug("snd_pcm_mmap_begin: Buffer underrun!"); + + if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0) { + u->first = TRUE; + continue; + } + pa_log("Failed to write data to DSP: %s", snd_strerror(err)); return -1; } @@ -222,19 +224,19 @@ static int mmap_write(struct userdata *u) { pa_log_debug("snd_pcm_mmap_commit: %s", snd_strerror(err)); - if (err == -EPIPE) { - pa_log_debug("snd_pcm_mmap_commit: Buffer underrun!"); - u->first = TRUE; - } - - if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0) - continue; - if (err == -EAGAIN) { pa_log_debug("EAGAIN"); return work_done; } + if (err == -EPIPE) + pa_log_debug("snd_pcm_mmap_commit: Buffer underrun!"); + + if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0) { + u->first = TRUE; + continue; + } + pa_log("Failed to write data to DSP: %s", snd_strerror(err)); return -1; } @@ -264,6 +266,8 @@ static int unix_write(struct userdata *u) { snd_pcm_sframes_t n, frames; int err; + snd_pcm_hwsync(u->pcm_handle); + if (PA_UNLIKELY((err = snd_pcm_status(u->pcm_handle, status)) < 0)) { pa_log("Failed to query DSP status data: %s", snd_strerror(err)); return -1; @@ -300,15 +304,17 @@ static int unix_write(struct userdata *u) { if (PA_UNLIKELY(frames < 0)) { + if (frames == -EAGAIN) { + pa_log_debug("EAGAIN"); + return work_done; + } + if (frames == -EPIPE) pa_log_debug("snd_pcm_avail_update: Buffer underrun!"); - if ((frames = snd_pcm_recover(u->pcm_handle, frames, 1)) == 0) + if ((frames = snd_pcm_recover(u->pcm_handle, frames, 1)) == 0) { + u->first = TRUE; continue; - - if (frames == -EAGAIN) { - pa_log_debug("EAGAIN"); - return work_done; } pa_log("Failed to write data to DSP: %s", snd_strerror(frames)); @@ -332,7 +338,7 @@ static int unix_write(struct userdata *u) { } } -static int update_smoother(struct userdata *u) { +static void update_smoother(struct userdata *u) { snd_pcm_sframes_t delay = 0; int64_t frames; int err; @@ -343,11 +349,12 @@ static int update_smoother(struct userdata *u) { /* Let's update the time smoother */ + snd_pcm_hwsync(u->pcm_handle); snd_pcm_avail_update(u->pcm_handle); if (PA_UNLIKELY((err = snd_pcm_delay(u->pcm_handle, &delay)) < 0)) { - pa_log("Failed to get delay: %s", snd_strerror(err)); - return -1; + pa_log_warn("Failed to get delay: %s", snd_strerror(err)); + return; } frames = u->frame_index - delay; @@ -357,8 +364,6 @@ static int update_smoother(struct userdata *u) { now1 = pa_rtclock_usec(); now2 = pa_bytes_to_usec(frames * u->frame_size, &u->sink->sample_spec); pa_smoother_put(u->smoother, now1, now2); - - return 0; } static pa_usec_t sink_get_latency(struct userdata *u) { @@ -814,6 +819,7 @@ static void thread_func(void *userdata) { frames = u->sink->thread_info.rewind_nbytes / u->frame_size; + snd_pcm_hwsync(u->pcm_handle); if ((unused = snd_pcm_avail_update(u->pcm_handle)) < 0) { pa_log("snd_pcm_avail_update() failed: %s", snd_strerror(unused)); goto fail; @@ -867,12 +873,11 @@ static void thread_func(void *userdata) { pa_smoother_resume(u->smoother, pa_rtclock_usec()); } - if (update_smoother(u) < 0) - goto fail; + update_smoother(u); } if (u->use_tsched) { - pa_usec_t usec, cusec, sleep_usec; + pa_usec_t usec, cusec; /* OK, the playback buffer is now full, let's * calculate when to wake up next */ @@ -887,19 +892,14 @@ static void thread_func(void *userdata) { pa_log_debug("Waking up in %0.2fms (system clock).", (double) cusec / PA_USEC_PER_MSEC); - sleep_usec = PA_MIN(usec, cusec); - - pa_log_debug("Waking up in %0.2fms (smaller value).", (double) sleep_usec / PA_USEC_PER_MSEC); - /* We don't trust the conversion, so we wake up whatever comes first */ - pa_rtpoll_set_timer_relative(u->rtpoll, sleep_usec); + pa_rtpoll_set_timer_relative(u->rtpoll, PA_MIN(usec, cusec)); } - } else if (u->use_tsched) { + } else if (u->use_tsched) /* OK, we're in an invalid state, let's disable our timers */ pa_rtpoll_set_timer_disabled(u->rtpoll); - } /* Hmm, nothing to do. Let's sleep */ if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0) @@ -923,6 +923,7 @@ static void thread_func(void *userdata) { } if (revents & (POLLERR|POLLNVAL|POLLHUP)) { + snd_pcm_state_t state; if (revents & POLLERR) pa_log_warn("Got POLLERR from ALSA"); @@ -931,9 +932,12 @@ static void thread_func(void *userdata) { if (revents & POLLHUP) pa_log_warn("Got POLLHUP from ALSA"); + state = snd_pcm_state(u->pcm_handle); + pa_log_warn("PCM state is %s", snd_pcm_state_name(state)); + /* Try to recover from this error */ - switch (snd_pcm_state(u->pcm_handle)) { + switch (state) { case SND_PCM_STATE_XRUN: if ((err = snd_pcm_recover(u->pcm_handle, -EPIPE, 1)) != 0) { @@ -959,6 +963,8 @@ static void thread_func(void *userdata) { } break; } + + u->first = TRUE; } pa_log_debug("alsa revents = %i", revents); @@ -1132,14 +1138,25 @@ int pa__init(pa_module*m) { if (pa_alsa_prepare_mixer(u->mixer_handle, u->device_name) >= 0) found = TRUE; - else if (dev_id) { - char *md = pa_sprintf_malloc("hw:%s", dev_id); + else { + snd_pcm_info_t *info; + + snd_pcm_info_alloca(&info); + + if (snd_pcm_info(u->pcm_handle, info) >= 0) { + char *md; + int card; - if (strcmp(u->device_name, md)) - if (pa_alsa_prepare_mixer(u->mixer_handle, md) >= 0) - found = TRUE; + if ((card = snd_pcm_info_get_card(info)) >= 0) { - pa_xfree(md); + md = pa_sprintf_malloc("hw:%i", card); + + if (strcmp(u->device_name, md)) + if (pa_alsa_prepare_mixer(u->mixer_handle, md) >= 0) + found = TRUE; + pa_xfree(md); + } + } } if (found) @@ -1304,6 +1321,8 @@ int pa__init(pa_module*m) { } else u->mixer_fdl = NULL; + pa_alsa_dump(u->pcm_handle); + if (!(u->thread = pa_thread_new(thread_func, u))) { pa_log("Failed to create thread."); goto fail; |