From b280eea4c3fa09472595dd62538e036f2dbcaff5 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Wed, 6 Mar 2019 18:48:18 +0100 Subject: [PATCH] Use ALSA timestamps for marking input data. This reportedly gives much more stable delay, as the timer is sampled when the audio actually arrives in the kernel. Patch by Yann Dubreuil, from the BreizhCamp repository. --- nageru/alsa_input.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/nageru/alsa_input.cpp b/nageru/alsa_input.cpp index a64f810..40fba43 100644 --- a/nageru/alsa_input.cpp +++ b/nageru/alsa_input.cpp @@ -111,6 +111,9 @@ bool ALSAInput::open_device() snd_pcm_sw_params_alloca(&sw_params); RETURN_FALSE_ON_ERROR("snd_pcm_sw_params_current()", snd_pcm_sw_params_current(pcm_handle, sw_params)); RETURN_FALSE_ON_ERROR("snd_pcm_sw_params_set_start_threshold", snd_pcm_sw_params_set_start_threshold(pcm_handle, sw_params, num_periods * period_size / 2)); + RETURN_FALSE_ON_ERROR("snd_pcm_sw_params_set_tstamp_mode", snd_pcm_sw_params_set_tstamp_mode(pcm_handle, sw_params, SND_PCM_TSTAMP_ENABLE)); + RETURN_FALSE_ON_ERROR("snd_pcm_sw_params_set_tstamp_type", snd_pcm_sw_params_set_tstamp_type(pcm_handle, sw_params, SND_PCM_TSTAMP_TYPE_MONOTONIC)); + RETURN_FALSE_ON_ERROR("snd_pcm_sw_params()", snd_pcm_sw_params(pcm_handle, sw_params)); RETURN_FALSE_ON_ERROR("snd_pcm_nonblock()", snd_pcm_nonblock(pcm_handle, 1)); @@ -221,6 +224,8 @@ ALSAInput::CaptureEndReason ALSAInput::do_capture() RETURN_ON_ERROR("snd_pcm_start()", snd_pcm_start(pcm_handle)); parent_pool->set_card_state(internal_dev_index, ALSAPool::Device::State::RUNNING); + snd_pcm_status_t *status; + snd_pcm_status_alloca(&status); while (!should_quit.should_quit()) { int ret = snd_pcm_wait(pcm_handle, /*timeout=*/100); if (ret == 0) continue; // Timeout. @@ -232,7 +237,14 @@ ALSAInput::CaptureEndReason ALSAInput::do_capture() } RETURN_ON_ERROR("snd_pcm_wait()", ret); - snd_pcm_sframes_t frames = snd_pcm_readi(pcm_handle, buffer.get(), buffer_frames); + ret = snd_pcm_status(pcm_handle, status); + RETURN_ON_ERROR("snd_pcm_status()", ret); + + snd_pcm_sframes_t avail = snd_pcm_status_get_avail(status); + snd_htimestamp_t alsa_ts; + snd_pcm_status_get_htstamp(status, &alsa_ts); + + snd_pcm_sframes_t frames = snd_pcm_readi(pcm_handle, buffer.get(), avail); if (frames == -EPIPE) { fprintf(stderr, "[%s] ALSA overrun\n", device.c_str()); snd_pcm_prepare(pcm_handle); @@ -245,11 +257,12 @@ ALSAInput::CaptureEndReason ALSAInput::do_capture() } RETURN_ON_ERROR("snd_pcm_readi()", frames); - const steady_clock::time_point now = steady_clock::now(); + // NOTE: This assumes steady_clock::time_point is the same as clock_gettime(CLOCK_MONOTONIC). + const steady_clock::time_point ts = steady_clock::time_point(seconds(alsa_ts.tv_sec) + nanoseconds(alsa_ts.tv_nsec)); bool success; do { if (should_quit.should_quit()) return CaptureEndReason::REQUESTED_QUIT; - success = audio_callback(buffer.get(), frames, audio_format, now); + success = audio_callback(buffer.get(), frames, audio_format, ts); } while (!success); } return CaptureEndReason::REQUESTED_QUIT; -- 2.39.2