Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl SamplesBuffer {
impl Source for SamplesBuffer {
#[inline]
fn current_span_len(&self) -> Option<usize> {
None
Some(self.data.len() - self.pos)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The contract is that current_span_len returns the length of the span / buffer regardless of its current position. That's for size_hint to do.

}

#[inline]
Expand Down Expand Up @@ -126,7 +126,7 @@ impl Iterator for SamplesBuffer {

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.data.len(), Some(self.data.len()))
(self.data.len() - self.pos, Some(self.data.len() - self.pos))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SamplesBuffer could therefore also implement ExactSizeIterator. I know that's not directly related to this change, but see it also doesn't implement it currently.

}
}

Expand Down
29 changes: 25 additions & 4 deletions src/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ pub struct SourcesQueueOutput {
}

const THRESHOLD: usize = 512;
const SILENCE_SAMPLE_RATE: SampleRate = nz!(44100);
const SILENCE_CHANNELS: ChannelCount = nz!(1);

impl Source for SourcesQueueOutput {
#[inline]
Expand Down Expand Up @@ -154,12 +156,28 @@ impl Source for SourcesQueueOutput {

#[inline]
fn channels(&self) -> ChannelCount {
self.current.channels()
// current_span_len() should never return 0 unless the source is empty, so this is a cheeky hint
if self.current.current_span_len() != Some(0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the cheekiness 😄

How much sense do you think it would make to add an is_empty helper method to Source?

self.current.channels()
} else if let Some((next, _)) = self.input.next_sounds.lock().unwrap().first() {
next.channels()
} else {
// If keep_alive_if_empty is true, then it'll be mono 44.1khz silence -- otherwise it doesn't matter what it is
SILENCE_CHANNELS
}
}

#[inline]
fn sample_rate(&self) -> SampleRate {
self.current.sample_rate()
// current_span_len() should never return 0 unless the source is empty, so this is a cheeky hint
if self.current.current_span_len() != Some(0) {
self.current.sample_rate()
} else if let Some((next, _)) = self.input.next_sounds.lock().unwrap().first() {
next.sample_rate()
} else {
// If keep_alive_if_empty is true, then it'll be mono 44.1khz silence -- otherwise it doesn't matter what it is
SILENCE_SAMPLE_RATE
}
}

#[inline]
Expand Down Expand Up @@ -221,7 +239,11 @@ impl SourcesQueueOutput {
let mut next = self.input.next_sounds.lock().unwrap();

if next.is_empty() {
let silence = Box::new(Zero::new_samples(nz!(1), nz!(44100), THRESHOLD)) as Box<_>;
let silence = Box::new(Zero::new_samples(
SILENCE_CHANNELS,
SILENCE_SAMPLE_RATE,
THRESHOLD,
)) as Box<_>;
if self.input.keep_alive_if_empty.load(Ordering::Acquire) {
// Play a short silence in order to avoid spinlocking.
(silence, None)
Expand All @@ -247,7 +269,6 @@ mod tests {
use crate::source::Source;

#[test]
#[ignore] // FIXME: samples rate and channel not updated immediately after transition
fn basic() {
let (tx, mut rx) = queue::queue(false);

Expand Down
16 changes: 10 additions & 6 deletions src/source/skip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,22 @@ where
return;
}

let ns_per_sample: u128 =
NS_PER_SECOND / input.sample_rate().get() as u128 / input.channels().get() as u128;
let sample_rate = input.sample_rate().get() as u128;
let channels = input.channels().get() as u128;

let samples_per_channel = duration.as_nanos() * sample_rate / NS_PER_SECOND;
let samples_to_skip: u128 = samples_per_channel * channels;

// Check if we need to skip only part of the current span.
if span_len as u128 * ns_per_sample > duration.as_nanos() {
skip_samples(input, (duration.as_nanos() / ns_per_sample) as usize);
if span_len as u128 > samples_to_skip {
skip_samples(input, samples_to_skip as usize);
return;
}

duration -= Duration::from_nanos(
(NS_PER_SECOND * span_len as u128 / channels / sample_rate) as u64,
);
skip_samples(input, span_len);

duration -= Duration::from_nanos((span_len * ns_per_sample as usize) as u64);
}
}

Expand Down