diff options
author | Lennart Poettering <lennart@poettering.net> | 2008-04-07 17:19:51 +0000 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2008-04-07 17:19:51 +0000 |
commit | b3b8a63c507a9f3dec1414510348c92d168813f5 (patch) | |
tree | 1e08b530a95b31645ca50d917d09d8d202f007cd | |
parent | c84a64cf322844b7c4c78dbcc32b1fa1a461af1b (diff) |
call snd_pcm_hwsync() expclicitly before we access any of the status fields, since this seems to be necessary. try to find the right mixer device via the card index
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/glitch-free@2221 fefdeb5f-60dc-0310-8127-8f9354f1896f
-rw-r--r-- | src/modules/module-alsa-sink.c | 125 | ||||
-rw-r--r-- | src/modules/module-alsa-source.c | 110 |
2 files changed, 150 insertions, 85 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; diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 901e3427..a074bc65 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -141,18 +141,26 @@ static int mmap_read(struct userdata *u) { pa_memchunk chunk; void *p; + snd_pcm_hwsync(u->pcm_handle); + if (PA_UNLIKELY((n = snd_pcm_avail_update(u->pcm_handle)) < 0)) { + pa_log_debug("snd_pcm_avail_update: %s", snd_strerror(n)); + + if (err == -EAGAIN) { + pa_log_debug("EAGAIN"); + return work_done; + } + if (n == -EPIPE) pa_log_debug("snd_pcm_avail_update: Buffer underrun!"); - if ((err = snd_pcm_recover(u->pcm_handle, n, 1)) == 0) + if ((err = snd_pcm_recover(u->pcm_handle, n, 1)) == 0) { + snd_pcm_start(u->pcm_handle); continue; + } - if (err == -EAGAIN) - return work_done; - - pa_log("snd_pcm_avail_update: %s", snd_strerror(err)); + pa_log("snd_pcm_recover: %s", snd_strerror(err)); return -1; } @@ -163,14 +171,20 @@ static int mmap_read(struct userdata *u) { if (PA_UNLIKELY((err = snd_pcm_mmap_begin(u->pcm_handle, &areas, &offset, &frames)) < 0)) { + pa_log_debug("snd_pcm_mmap_begin: %s", snd_strerror(err)); + + 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) + if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0) { + snd_pcm_start(u->pcm_handle); continue; - - if (err == -EAGAIN) - return work_done; + } pa_log("Failed to write data to DSP: %s", snd_strerror(err)); return -1; @@ -198,14 +212,20 @@ static int mmap_read(struct userdata *u) { if (PA_UNLIKELY((err = snd_pcm_mmap_commit(u->pcm_handle, offset, frames)) < 0)) { + pa_log_debug("snd_pcm_mmap_commit: %s", snd_strerror(err)); + + 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) + if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0) { + snd_pcm_start(u->pcm_handle); continue; - - if (err == -EAGAIN) - return work_done; + } pa_log("Failed to write data to DSP: %s", snd_strerror(err)); return -1; @@ -215,6 +235,8 @@ static int mmap_read(struct userdata *u) { u->frame_index += frames; + pa_log_debug("read %llu frames", (unsigned long long) frames); + if (PA_LIKELY(frames >= (snd_pcm_uframes_t) n)) return work_done; } @@ -235,6 +257,8 @@ static int unix_read(struct userdata *u) { int err; pa_memchunk chunk; + 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; @@ -264,12 +288,18 @@ static int unix_read(struct userdata *u) { if (PA_UNLIKELY(frames < 0)) { pa_memblock_unref(chunk.memblock); + if (frames == -EAGAIN) { + pa_log_debug("EAGAIN"); + return work_done; + } + + if (frames == -EPIPE) + pa_log_debug("snd_pcm_avail_update: Buffer overrun!"); + if ((frames = snd_pcm_recover(u->pcm_handle, frames, 1)) == 0) + snd_pcm_start(u->pcm_handle); continue; - if (frames == -EAGAIN) - return work_done; - pa_log("Failed to read data from DSP: %s", snd_strerror(frames)); return -1; } @@ -289,7 +319,7 @@ static int unix_read(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; @@ -300,11 +330,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; @@ -312,8 +343,6 @@ static int update_smoother(struct userdata *u) { now1 = pa_rtclock_usec(); now2 = pa_bytes_to_usec(frames * u->frame_size, &u->source->sample_spec); pa_smoother_put(u->smoother, now1, now2); - - return 0; } static pa_usec_t source_get_latency(struct userdata *u) { @@ -728,8 +757,7 @@ static void thread_func(void *userdata) { } if (work_done) - if (update_smoother(u) < 0) - goto fail; + update_smoother(u); if (u->use_tsched) { pa_usec_t usec, cusec; @@ -750,11 +778,10 @@ static void thread_func(void *userdata) { /* We don't trust the conversion, so we wake up whatever comes first */ 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) @@ -778,6 +805,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"); @@ -786,9 +814,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) { @@ -814,6 +845,8 @@ static void thread_func(void *userdata) { } break; } + + snd_pcm_start(u->pcm_handle); } } } @@ -979,14 +1012,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 (strcmp(u->device_name, md)) - if (pa_alsa_prepare_mixer(u->mixer_handle, md) >= 0) - found = TRUE; + if (snd_pcm_info(u->pcm_handle, info) >= 0) { + char *md; + int card; - pa_xfree(md); + if ((card = snd_pcm_info_get_card(info)) >= 0) { + + 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) @@ -1138,6 +1182,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; |