Add fallback instant source to ALSA backend

Here we use `std::time::Instant` as a fallback source for stream
instants in the case that the device produces invalid timestamps via
`get_htstamp`.
This commit is contained in:
mitchmindtree 2020-04-28 16:38:57 +02:00
parent a49297ec2c
commit 45977bf837
1 changed files with 48 additions and 18 deletions

View File

@ -203,6 +203,13 @@ impl Device {
num_descriptors num_descriptors
}; };
// Check to see if we can retrieve valid timestamps from the device.
let ts = handle.status()?.get_htstamp();
let creation_instant = match (ts.tv_sec, ts.tv_nsec) {
(0, 0) => Some(std::time::Instant::now()),
_ => None,
};
handle.start()?; handle.start()?;
let stream_inner = StreamInner { let stream_inner = StreamInner {
@ -213,6 +220,7 @@ impl Device {
buffer_len, buffer_len,
period_len, period_len,
can_pause, can_pause,
creation_instant,
}; };
Ok(stream_inner) Ok(stream_inner)
@ -433,6 +441,16 @@ struct StreamInner {
// Whether or not the hardware supports pausing the stream. // Whether or not the hardware supports pausing the stream.
can_pause: bool, can_pause: bool,
// In the case that the device does not return valid timestamps via `get_htstamp`, this field
// will be `Some` and will contain an `Instant` representing the moment the stream was created.
//
// If this field is `Some`, then the stream will use the duration since this instant as a
// source for timestamps.
//
// If this field is `None` then the elapsed duration between `get_trigger_htstamp` and
// `get_htstamp` is used.
creation_instant: Option<std::time::Instant>,
} }
// Assume that the ALSA library is built with thread safe option. // Assume that the ALSA library is built with thread safe option.
@ -653,7 +671,7 @@ fn process_input(
let delay_duration = frames_to_duration(delay_frames, stream.conf.sample_rate); let delay_duration = frames_to_duration(delay_frames, stream.conf.sample_rate);
let capture = callback let capture = callback
.sub(delay_duration) .sub(delay_duration)
.expect("`capture` occurs before origin of alsa `StreamInstant`"); .expect("`capture` is earlier than representation supported by `StreamInstant`");
let timestamp = crate::InputStreamTimestamp { callback, capture }; let timestamp = crate::InputStreamTimestamp { callback, capture };
let info = crate::InputCallbackInfo { timestamp }; let info = crate::InputCallbackInfo { timestamp };
data_callback(&data, &info); data_callback(&data, &info);
@ -715,10 +733,12 @@ fn process_output(
Ok(()) Ok(())
} }
// Use the duration since the start of the stream. // Use the elapsed duration since the start of the stream.
// //
// This ensures positive values that are compatible with our `StreamInstant` representation. // This ensures positive values that are compatible with our `StreamInstant` representation.
fn stream_timestamp(stream: &StreamInner) -> Result<crate::StreamInstant, BackendSpecificError> { fn stream_timestamp(stream: &StreamInner) -> Result<crate::StreamInstant, BackendSpecificError> {
match stream.creation_instant {
None => {
let status = stream.channel.status()?; let status = stream.channel.status()?;
let trigger_ts = status.get_trigger_htstamp(); let trigger_ts = status.get_trigger_htstamp();
// TODO: This is returning `0` on ALSA where default device forwards to pulse. // TODO: This is returning `0` on ALSA where default device forwards to pulse.
@ -734,6 +754,15 @@ fn stream_timestamp(stream: &StreamInner) -> Result<crate::StreamInstant, Backen
}); });
Ok(crate::StreamInstant::from_nanos(nanos)) Ok(crate::StreamInstant::from_nanos(nanos))
} }
Some(creation) => {
let now = std::time::Instant::now();
let duration = now.duration_since(creation);
let instant = crate::StreamInstant::from_nanos_i128(duration.as_nanos() as i128)
.expect("stream duration has exceeded `StreamInstant` representation");
Ok(instant)
}
}
}
// Adapted from `timestamp2ns` here: // Adapted from `timestamp2ns` here:
// https://fossies.org/linux/alsa-lib/test/audio_time.c // https://fossies.org/linux/alsa-lib/test/audio_time.c
@ -891,8 +920,9 @@ fn set_sw_params_from_format(
}; };
sw_params.set_tstamp_mode(true)?; sw_params.set_tstamp_mode(true)?;
// TODO: `sw_params.set_tstamp_type(CLOCK_MONOTONIC_RAW)` // TODO:
// Pending addressing https://github.com/diwic/alsa-sys/issues/6 // Pending new version of alsa-sys and alsa-rs getting published.
// sw_params.set_tstamp_type(alsa::pcm::TstampType::MonotonicRaw)?;
pcm_handle.sw_params(&sw_params)?; pcm_handle.sw_params(&sw_params)?;