Summary
SymphoniaDecoder::new() panics via unreachable!() when symphonia's FormatReader::next_packet() returns Error::SeekError during initialization. This consistently occurs with M4A (AAC in ISO MP4 container) files.
Affected code — src/decoder/symphonia.rs line 40 (master):
Error::SeekError(_) => {
unreachable!("Seek errors should not occur during initialization")
}
Steps to Reproduce
- Obtain an M4A audio file (AAC in ISO MP4 container, e.g. NetEase Cloud Music "exhigh" quality)
- Load the file bytes into memory
- Attempt to decode with any rodio decoder method:
use rodio::Decoder;
use std::io::Cursor;
let audio_bytes: Vec<u8> = std::fs::read("song.m4a").unwrap();
// This panics:
let decoder = Decoder::new(Cursor::new(audio_bytes));
The M4A file has a standard ftyp box header: 00 00 00 1c 66 74 79 70 4d 34 41 20 (ftyp + brand M4A ).
Observed Behavior
The program panics with:
thread 'audio' panicked at 'internal error: entered unreachable code: Seek errors should not occur during initialization'
All decoder methods are affected (Decoder::new, Decoder::new_mp3, Decoder::new_flac, Decoder::new_aac, Decoder::new_wav, Decoder::new_vorbis) — they all go through SymphoniaDecoder::init() which calls format.next_packet(), and symphonia's ISO MP4 format reader returns Error::SeekError for these files.
Expected Behavior
Decoder::new() should return Err(DecoderError::...) instead of panicking. A library should never panic on valid user input.
Root Cause
SymphoniaDecoder::init() reads packets in a loop via format.next_packet(). The error handling at the call site (SymphoniaDecoder::new()) assumes SeekError can never be returned during initialization, but symphonia's ISO MP4 FormatReader can return Error::SeekError from next_packet() for certain M4A files.
Suggested Fix
Replace the unreachable!() with a proper error return:
// Before:
Error::SeekError(_) => {
unreachable!("Seek errors should not occur during initialization")
}
// After:
Error::SeekError(e) => Err(DecoderError::IoError(format!("seek error during init: {}", e))),
This is a one-line fix. A new DecoderError variant (e.g. SeekError) would be even cleaner but would be a breaking change.
Versions
- rodio: 0.20.1 (also verified on master — the
unreachable!() is still present at line 40)
- symphonia: 0.5.5
- OS: Windows 11
- Rust: stable
Summary
SymphoniaDecoder::new()panics viaunreachable!()when symphonia'sFormatReader::next_packet()returnsError::SeekErrorduring initialization. This consistently occurs with M4A (AAC in ISO MP4 container) files.Affected code —
src/decoder/symphonia.rsline 40 (master):Steps to Reproduce
The M4A file has a standard
ftypbox header:00 00 00 1c 66 74 79 70 4d 34 41 20(ftyp+ brandM4A).Observed Behavior
The program panics with:
All decoder methods are affected (
Decoder::new,Decoder::new_mp3,Decoder::new_flac,Decoder::new_aac,Decoder::new_wav,Decoder::new_vorbis) — they all go throughSymphoniaDecoder::init()which callsformat.next_packet(), and symphonia's ISO MP4 format reader returnsError::SeekErrorfor these files.Expected Behavior
Decoder::new()should returnErr(DecoderError::...)instead of panicking. A library should never panic on valid user input.Root Cause
SymphoniaDecoder::init()reads packets in a loop viaformat.next_packet(). The error handling at the call site (SymphoniaDecoder::new()) assumesSeekErrorcan never be returned during initialization, but symphonia's ISO MP4FormatReadercan returnError::SeekErrorfromnext_packet()for certain M4A files.Suggested Fix
Replace the
unreachable!()with a proper error return:This is a one-line fix. A new
DecoderErrorvariant (e.g.SeekError) would be even cleaner but would be a breaking change.Versions
unreachable!()is still present at line 40)