Search code examples
rustaudiorodio

rodio panic when trying to play Sink with reverb effect


UPDATED: This issue is officially a bug.

I'm adding a reverb effect following this example, but panic when trying to play the sink.

thread '<unnamed>' panicked at /feelslikehome/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rodio-0.19.0/src/conversions/channels.rs:100:13:
attempt to subtract with overflow
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
fatal runtime error: Rust panics must be rethrown

This is what I did:

        
    fn main() {
        
        // This snippet is from the example
        let (_stream, handle) = rodio::OutputStream::try_default().unwrap();
        let sink = rodio::Sink::try_new(&handle).unwrap();
        let file = std::fs::File::open("assets/music.ogg").unwrap();

        // This is originally a function that returns (Mode, Sink, Stream) tuple
        match Decoder::new(BufReader::new(file)) {
            Ok(decoder) => {
                let mode = get_mode();
                if mode == Mode::Bass {
                    // Duration is just an arbitrary number, I tried 0, milliseconds, etc.
                    let reverb = decoder.buffered().reverb(Duration::from_secs(30), 1.0);
                    sink.append(reverb);
                } else {
                    sink.append(decoder);
                }
                // Try playing it right away, it panicked!
                sink.play();
                Some((mode, sink, stream))
            }
            Err(e) => {
                info!("Failed to create decoder: {:?}", e);
                None
            }
        }
     }

     fn get_mode() -> Mode {
         Mode::Bass
     }

     enum Mode {
        case Bass
     }
     

I suspect calling the buffered() is the problem, but it is needed because the reverb requires a clone-able source. There's no API to unbuffered the decoder. When I tried to play the sink right away, it was also panic.

Any pointers?


Solution

  • This is officially a bug. I posted the solution here to solve the panic. The bug is in the size_hint function of the channels.rs rodio. This line:

    (size + consumed) / self.from as usize * self.to as usize
        - self.next_output_sample_pos as usize
    

    Becomes:

    ((size + consumed) / self.from as usize * self.to as usize).saturating_sub(self.next_output_sample_pos as usize)