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:
parent
a49297ec2c
commit
45977bf837
|
@ -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)?;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue