-
Notifications
You must be signed in to change notification settings - Fork 284
SourcesQueueOutput can peek metadata from next source #812
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
channels and sample_rate currently return the old metadata on source boundaries, which is problematic for UniformSourceIterator, which checks metadata on span boundaries. This commit takes advantage of current_span_len's behavior to use it as a cheap "peek" to hopefully find out if we're done with the current source or not.
do_skip_duration's math was prone to rounding errors -- this commit shuffles the math around a bit so that the sample skip and the duration subtraction are each holding onto as much precision as possible.
The queue will now change samples and sample rate immediately on source boundaries that correctly report their current_span_len, so this test passes
unrelated to the rest of the PR, but since I'm fixing current_span_len, might as well do this too thanks @max-m
roderickvd
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for tackling this one! Sorry for the late response. Here are a few points and questions for further improvement.
| #[inline] | ||
| fn current_span_len(&self) -> Option<usize> { | ||
| None | ||
| Some(self.data.len() - self.pos) |
There was a problem hiding this comment.
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] | ||
| 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)) |
There was a problem hiding this comment.
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.
| 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) { |
There was a problem hiding this comment.
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?
Fixes #811
SourcesQueueOutput currently violates the span interface by returning incorrect values for sample_rate and channels while the iterator is positioned on a source boundary (i.e. at the end of one source, before the next source has started.).
This PR adjusts its sample_rate and channels implementations so that they use current_span_len == 0 as an admissible heuristic to check if the current source is empty. This means that it can obey the span interface contract as long as the sources are returning Some current_span_len values. (If they aren't, there's probably no way we can possibly obey that contract.)
In order to actually uncomment the
basictest for the queue, I also had to adjust theSamplesBufferimplementation to return a Some current_span_len value. This showed some unrelated rounding errors inSkipDuration, so I made unrelated adjustments to theSkipDurationmath to reduce rounding errors, just to keep tests passing.