From: Steinar H. Gunderson Date: Wed, 6 Mar 2019 17:48:18 +0000 (+0100) Subject: Use ALSA timestamps for marking input data. X-Git-Tag: 1.8.3~20 X-Git-Url: https://git.sesse.net/?p=nageru;a=commitdiff_plain;h=b280eea4c3fa09472595dd62538e036f2dbcaff5 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. --- 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;