Skip to main content

selene_core/
decoding.rs

1use std::{fs, sync::LazyLock};
2
3use symphonia::{
4    core::{
5        audio::{SampleBuffer, SignalSpec},
6        codecs::{CODEC_TYPE_NULL, CodecRegistry, Decoder, DecoderOptions},
7        errors::Error as SymphoniaError,
8        formats::{FormatOptions, FormatReader},
9        io::{MediaSourceStream, MediaSourceStreamOptions},
10        probe::Probe,
11    },
12    default::{
13        codecs::{FlacDecoder, MpaDecoder, PcmDecoder, VorbisDecoder},
14        formats::{FlacReader, MpaReader, OggReader, WavReader},
15    },
16};
17use thiserror::Error;
18
19use crate::media_container::{ContainerFormat, MediaContainer};
20
21/// Symphonia codec registry for all supported codecs
22pub static SYMPHONIA_CODEC_REGISTRY: LazyLock<CodecRegistry> = LazyLock::new(|| {
23    let mut codecs = CodecRegistry::new();
24    codecs.register_all::<FlacDecoder>();
25    codecs.register_all::<MpaDecoder>();
26    codecs.register_all::<VorbisDecoder>();
27    codecs.register_all::<PcmDecoder>();
28    codecs
29});
30
31pub static SYMPHONIA_PROBE: LazyLock<Probe> = LazyLock::new(|| {
32    let mut probe = Probe::default();
33    probe.register_all::<FlacReader>();
34    probe.register_all::<OggReader>();
35    probe.register_all::<MpaReader>();
36    probe.register_all::<WavReader>();
37    probe
38});
39
40#[derive(Debug, Error)]
41pub enum DecodingError {
42    #[error("{0}")]
43    Io(#[from] std::io::Error),
44
45    #[error("{0}")]
46    Symphonia(#[from] SymphoniaError),
47
48    #[error("Player attempted to play an unsupported container: '{0:?}'")]
49    UnsupportedContainer(ContainerFormat),
50}
51
52pub struct RawDecoder {
53    pub stream: symphonia::core::formats::Track,
54    pub format_reader: Box<dyn FormatReader>,
55    pub decoder: Box<dyn Decoder>,
56}
57
58pub struct DecodedPacket {
59    pub sample_buf: SampleBuffer<f32>,
60    pub frame_count: usize,
61    pub spec: SignalSpec,
62}
63
64impl RawDecoder {
65    pub fn from_container(
66        container: &MediaContainer,
67        buffer_len: usize,
68    ) -> Result<Self, DecodingError> {
69        let file = fs::File::open(container.path())?;
70
71        let options = MediaSourceStreamOptions { buffer_len };
72        let mss = MediaSourceStream::new(Box::new(file), options);
73
74        let fmt_opts = FormatOptions {
75            enable_gapless: true,
76            ..Default::default()
77        };
78
79        let format_reader: Box<dyn FormatReader> = match container.container() {
80            ContainerFormat::Flac => Box::new(FlacReader::try_new(mss, &fmt_opts)?),
81            ContainerFormat::Mpa => Box::new(MpaReader::try_new(mss, &fmt_opts)?),
82            ContainerFormat::Ogg => Box::new(OggReader::try_new(mss, &fmt_opts)?),
83            ContainerFormat::Wav => Box::new(WavReader::try_new(mss, &fmt_opts)?),
84            other => return Err(DecodingError::UnsupportedContainer(*other)),
85        };
86
87        let track = format_reader
88            .tracks()
89            .iter()
90            .find(|t| t.codec_params.codec != CODEC_TYPE_NULL)
91            .expect("Playable file does not have any supported codecs");
92        let dec_opts: DecoderOptions = Default::default();
93
94        let decoder = SYMPHONIA_CODEC_REGISTRY.make(&track.codec_params, &dec_opts)?;
95
96        Ok(Self {
97            stream: track.clone(),
98            format_reader,
99            decoder,
100        })
101    }
102
103    pub fn decode_next_packet(&mut self) -> Result<Option<DecodedPacket>, DecodingError> {
104        loop {
105            let packet = match self.format_reader.next_packet() {
106                Ok(packet) => packet,
107                Err(SymphoniaError::ResetRequired) => {
108                    self.decoder.reset();
109                    continue;
110                }
111                Err(SymphoniaError::IoError(err))
112                    if matches!(err.kind(), std::io::ErrorKind::UnexpectedEof) =>
113                {
114                    return Ok(None);
115                }
116                Err(err) => return Err(DecodingError::Symphonia(err)),
117            };
118
119            while !self.format_reader.metadata().is_latest() {
120                self.format_reader.metadata().pop();
121            }
122
123            if packet.track_id() != self.stream.id {
124                continue;
125            }
126
127            let decoded = match self.decoder.decode(&packet) {
128                Ok(decoded) => decoded,
129                Err(SymphoniaError::DecodeError(_)) => continue,
130                Err(SymphoniaError::IoError(_)) => continue,
131                Err(err) => return Err(DecodingError::Symphonia(err)),
132            };
133
134            let frame_count = decoded.frames();
135            let spec = *decoded.spec();
136
137            let mut sample_buf = SampleBuffer::<f32>::new(frame_count as u64, spec);
138            sample_buf.copy_interleaved_ref(decoded);
139
140            return Ok(Some(DecodedPacket {
141                sample_buf,
142                frame_count,
143                spec,
144            }));
145        }
146    }
147}