-
Notifications
You must be signed in to change notification settings - Fork 247
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
Fix span length issues in queue #684
base: master
Are you sure you want to change the base?
Conversation
I think this fixes #484 can anyone test? |
53ce2c8
to
e798db7
Compare
e798db7
to
6cfec32
Compare
Testing now! |
@dvdsk This is still broken for a 6 channel output device - works fine for a 4 channel and a 2 channel device. It's broken in a different way to before where instead of outputting on channels 5 and 6 it outputs on channels 3 and 4. Screenshots show working 4 channel and broken 6 channel. |
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 think this is the right change, but likely incomplete.
Does Queue verify that input/output channel counts always match (for every source in input queue)? I may have missed it, but there seems to be no checks in this regard (channel count can also change on the next span).
I see that it just always matches the current source.
Maybe problem remains when new input source is added over silence...
There's // TODO: not yet implemented
since 2017 (src/queue.rs:313) :)
src/queue.rs
Outdated
@@ -250,6 +252,11 @@ where | |||
self.signal_after_end = signal_after_end; | |||
Ok(()) | |||
} | |||
|
|||
/// 200 frames of silence | |||
fn silent_span_length(&self) -> usize { |
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.
Inline, maybe.
good point, gotta check that the channels are still in sync then. We should probably check other parts of the library. From a quick glace it seems skippable has the same issue. So there is a wider problem with multi channel audio and span length. For now I would say pad everything with silence. Thats gonna give different issues (silence between sounds) but we can tackle those afterwards. |
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.
This looks good in theory but having reviewed this morning it's flawed due to self.channels()
reporting the channels for the current source which in the case of silence or Empty (which appears to cause the issue with multichannel audio) is 1 and not the number of channels of the remaining sources or the output device.
In my head, the actual fix seems like it could be quite tricky as do we need to know the number of output channels on the Mixer to be able to fix this properly?
I have been able to implement a "fix" in our software for a 6 channel device by using this PR's span length fix and then setting Empty's channels to 6 and where we create silence here using Zero, setting channels to 6 but this is by no means a proper fix or reusable.
Edit: This is actually just a partial "fix" as due to what @dvdsk has said, skippable has the same issue and so when we use sink.clear()
depending on when this is called and the samples are skipped we end up shifting the samples / channel ordering.
|
||
/// 200 frames of silence | ||
fn silent_span_length(&self) -> usize { | ||
200 * self.channels() as usize |
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.
self.channels() will return 1 when we're either playing silence or at the start of the queue with the Empty
source.
we should rename |
@will3942 its worse, I took a deeper look and there are about 5 edge cases not handled by queue. I'll have to rewrite it completely. Gonna be a fun review for you all. |
eek - thanks for your time on this. |
ready for review |
@will3942 does this pass your test (note skip is still broken). If it does not we really need to work on getting an automated integration test for this issue. |
Need to also handle skip & skip_duration.... Since its perfectly fine to end mid frame or before the span ends. So not done yet :( |
I don't have a great test bed for this right now - will test this tomorrow. |
/// The input of the queue. | ||
pub struct SourcesQueueInput<S> { | ||
next_sounds: Mutex<Vec<(Sound<S>, SignalDone)>>, | ||
pub struct QueueControls<S> { |
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.
Maybe just "Queue"? This would be more in line with other control/source struct pairs.
@dvdsk sadly this does not fix the issue. I am using the following code to test it - interestingly if you note the commented out code, when using a SamplesBuffer the code works correctly and outputs on Channels 1 and 2 however using a Decoder results in an output on Channels 5 and 6 - this might help being able to build up an integration test that simulates this as I believe when trying to build tests for this I was only using SamplesBuffer.
|
EDIT: found more edge cases :) Resolving them, ill let you know when testing is needed again I tried to make a test, however it keeps succeeding. I do not have your Could you check if:
For that last setup you will need to do: let stream_handle = rodio::OutputStreamBuilder::open_default_stream()?;
let mixer = stream_handle.mixer();
mixer.add(your source);
sleep a few seconds then exit program |
This was already required by the various parts of rodio but never mentioned anywhere.
The `current_span_length` is in samples not frames. Rodio was using a fixed span_length for all sources regardless of their number of channels. If that span length was not wholly dividable by the number of channels it would create an offset. Credit for finding this goes to: @will3942
…span len edge case
eab95c5
to
bf98f34
Compare
rebase^ |
@dvdsk This is the file if needed for future ref. |
test pass with that file test: #[test]
fn with_queue_in_between() {
let file = fs::File::open("assets/test-bad-seek.mp3").unwrap();
let decoder = Decoder::new(BufReader::new(file)).unwrap();
assert_eq!(decoder.channels(), 2);
let channel_volume = ChannelVolume::new(decoder, vec![1.0, 1.0, 0.0, 0.0, 0.0, 0.0]);
assert_eq!(channel_volume.channels(), 6);
let (controls, queue) = queue::queue(false);
controls.append(channel_volume);
assert_output_only_on_channel_1_and_2(queue);
} It does take quite a lot of time on a release build.... which scares me. But lets first get it working before we refactor and finally optimize. @will3942 could you take the latest version of this pr and run your manual test? I think the test above should match Sink. We are not resampling but that should not matter. |
@dvdsk This latest version works perfectly on my example test! ![]() |
Adjust Source docs: span must be whole frames. This was already required by the various parts of rodio but never mentioned anywhere.
Rodio was using a fixed span_length for all sources regardless of their number of channels. If that span length was not wholly dividable by the number of channels it
would create an offset breaking channel volume.
Edit: credit for finding this goes to @will3942