selene_core/symphonia_helpers/
raw_decoder.rs1use std::fs;
2
3use symphonia::{
4 core::{
5 audio::GenericAudioBufferRef,
6 codecs::audio::{AudioDecoder, AudioDecoderOptions},
7 errors::Error as SymphoniaError,
8 formats::{FormatOptions, FormatReader, TrackType},
9 io::{MediaSourceStream, MediaSourceStreamOptions},
10 },
11 default::formats::{AiffReader, FlacReader, MpaReader, OggReader, WavReader},
12};
13
14use thiserror::Error;
15
16use crate::media_container::{ContainerError, ContainerFormat, MediaContainer, Stream};
17
18#[derive(Debug, Error)]
19pub enum DecodingError {
20 #[error("{0}")]
21 Io(#[from] std::io::Error),
22
23 #[error("{0}")]
24 Symphonia(#[from] SymphoniaError),
25
26 #[error("{0}")]
27 Container(#[from] ContainerError),
28
29 #[error("Player attempted to play an unsupported container: '{0:?}'")]
30 UnsupportedContainer(ContainerFormat),
31}
32
33pub struct RawDecoder {
34 pub stream: Stream,
35 pub format_reader: Box<dyn FormatReader>,
36 pub decoder: Box<dyn AudioDecoder>,
37}
38
39impl RawDecoder {
40 pub fn from_container(
41 container: &MediaContainer,
42 buffer_len: usize,
43 ) -> Result<Self, DecodingError> {
44 let file = fs::File::open(container.path())?;
45
46 let options = MediaSourceStreamOptions { buffer_len };
47 let mss = MediaSourceStream::new(Box::new(file), options);
48
49 let fmt_opts = FormatOptions::default();
50 let format_reader: Box<dyn FormatReader> = match container.format() {
51 ContainerFormat::Flac => Box::new(FlacReader::try_new(mss, fmt_opts)?),
52 ContainerFormat::Mpa => Box::new(MpaReader::try_new(mss, fmt_opts)?),
53 ContainerFormat::Ogg => Box::new(OggReader::try_new(mss, fmt_opts)?),
54 ContainerFormat::Wav => Box::new(WavReader::try_new(mss, fmt_opts)?),
55 ContainerFormat::Aiff => Box::new(AiffReader::try_new(mss, fmt_opts)?),
56 other => return Err(DecodingError::UnsupportedContainer(*other)),
57 };
58
59 let track = format_reader
60 .default_track(TrackType::Audio)
61 .expect("Playable file does not have any supported codecs");
62
63 let dec_opts: AudioDecoderOptions = Default::default();
64
65 let params = track
66 .codec_params
67 .as_ref()
68 .expect("Track is not playable")
69 .audio()
70 .unwrap();
71 let decoder = symphonia::default::get_codecs().make_audio_decoder(params, &dec_opts)?;
72
73 Ok(Self {
74 stream: Stream::try_from(track)?,
75 format_reader,
76 decoder,
77 })
78 }
79
80 pub fn decode_next_packet(
81 &mut self,
82 ) -> Result<Option<GenericAudioBufferRef<'_>>, DecodingError> {
83 loop {
84 let packet = match self.format_reader.next_packet() {
85 Ok(Some(packet)) => packet,
86 Err(SymphoniaError::ResetRequired) => {
87 self.decoder.reset();
88 continue;
89 }
90 Err(SymphoniaError::IoError(err))
91 if matches!(err.kind(), std::io::ErrorKind::UnexpectedEof) =>
92 {
93 return Ok(None);
94 }
95 Ok(None) => return Ok(None),
96 Err(err) => return Err(DecodingError::Symphonia(err)),
97 };
98
99 while !self.format_reader.metadata().is_latest() {
100 self.format_reader.metadata().pop();
101 }
102
103 if packet.track_id() == self.stream.id {
104 return match self.decoder.decode(&packet) {
105 Ok(decoded) => Ok(Some(decoded)),
106 Err(SymphoniaError::DecodeError(_)) => Ok(None),
107 Err(SymphoniaError::IoError(_)) => Ok(None),
108 Err(err) => Err(DecodingError::Symphonia(err)),
109 };
110 }
111 }
112 }
113}