selene_core/symphonia_helpers/
raw_decoder.rs1use std::fs;
2
3use symphonia::{
4 core::{
5 audio::{GenericAudioBuffer, GenericAudioBufferRef},
6 codecs::audio::{AudioDecoder, AudioDecoderOptions},
7 errors::Error as SymphoniaError,
8 formats::{FormatOptions, FormatReader, TrackType},
9 io::{MediaSourceStream, MediaSourceStreamOptions},
10 },
11 default::formats::{FlacReader, MpaReader, OggReader, WavReader},
12};
13
14use thiserror::Error;
15
16use crate::{
17 errors::ContainerError,
18 media_container::{ContainerFormat, MediaContainer, Stream},
19};
20
21#[derive(Debug, Error)]
22pub enum DecodingError {
23 #[error("{0}")]
24 Io(#[from] std::io::Error),
25
26 #[error("{0}")]
27 Symphonia(#[from] SymphoniaError),
28
29 #[error("{0}")]
30 Container(#[from] ContainerError),
31
32 #[error("Player attempted to play an unsupported container: '{0:?}'")]
33 UnsupportedContainer(ContainerFormat),
34}
35
36pub struct RawDecoder {
37 pub stream: Stream,
38 pub format_reader: Box<dyn FormatReader>,
39 pub decoder: Box<dyn AudioDecoder>,
40}
41
42impl RawDecoder {
43 pub fn from_container(
44 container: &MediaContainer,
45 buffer_len: usize,
46 ) -> Result<Self, DecodingError> {
47 let file = fs::File::open(container.path())?;
48
49 let options = MediaSourceStreamOptions { buffer_len };
50 let mss = MediaSourceStream::new(Box::new(file), options);
51
52 let fmt_opts = FormatOptions::default();
53 let format_reader: Box<dyn FormatReader> = match container.format() {
54 ContainerFormat::Flac => Box::new(FlacReader::try_new(mss, fmt_opts)?),
55 ContainerFormat::Mpa => Box::new(MpaReader::try_new(mss, fmt_opts)?),
56 ContainerFormat::Ogg => Box::new(OggReader::try_new(mss, fmt_opts)?),
57 ContainerFormat::Wav => Box::new(WavReader::try_new(mss, fmt_opts)?),
58 other => return Err(DecodingError::UnsupportedContainer(*other)),
59 };
60
61 let track = format_reader
62 .default_track(TrackType::Audio)
63 .expect("Playable file does not have any supported codecs");
64
65 let dec_opts: AudioDecoderOptions = Default::default();
66
67 let params = track
68 .codec_params
69 .as_ref()
70 .expect("Track is not playable")
71 .audio()
72 .unwrap();
73 let decoder = symphonia::default::get_codecs().make_audio_decoder(params, &dec_opts)?;
74
75 Ok(Self {
76 stream: Stream::try_from(track)?,
77 format_reader,
78 decoder,
79 })
80 }
81
82 pub fn decode_next_packet(&mut self) -> Result<Option<GenericAudioBuffer>, 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 Ok(None) => return Ok(None),
91 Err(err) => return Err(DecodingError::Symphonia(err)),
92 };
93
94 while !self.format_reader.metadata().is_latest() {
95 self.format_reader.metadata().pop();
96 }
97
98 if packet.track_id() != self.stream.id {
99 continue;
100 }
101
102 let decoded = match self.decoder.decode(&packet) {
103 Ok(decoded) => decoded,
104 Err(SymphoniaError::DecodeError(_)) => continue,
105 Err(SymphoniaError::IoError(_)) => continue,
106 Err(err) => return Err(DecodingError::Symphonia(err)),
107 };
108
109 let audio_buf = match decoded {
110 GenericAudioBufferRef::U8(audio_buffer) => {
111 GenericAudioBuffer::U8(audio_buffer.clone())
112 }
113 GenericAudioBufferRef::U16(audio_buffer) => {
114 GenericAudioBuffer::U16(audio_buffer.clone())
115 }
116 GenericAudioBufferRef::U24(audio_buffer) => {
117 GenericAudioBuffer::U24(audio_buffer.clone())
118 }
119 GenericAudioBufferRef::U32(audio_buffer) => {
120 GenericAudioBuffer::U32(audio_buffer.clone())
121 }
122 GenericAudioBufferRef::S8(audio_buffer) => {
123 GenericAudioBuffer::S8(audio_buffer.clone())
124 }
125 GenericAudioBufferRef::S16(audio_buffer) => {
126 GenericAudioBuffer::S16(audio_buffer.clone())
127 }
128 GenericAudioBufferRef::S24(audio_buffer) => {
129 GenericAudioBuffer::S24(audio_buffer.clone())
130 }
131 GenericAudioBufferRef::S32(audio_buffer) => {
132 GenericAudioBuffer::S32(audio_buffer.clone())
133 }
134 GenericAudioBufferRef::F32(audio_buffer) => {
135 GenericAudioBuffer::F32(audio_buffer.clone())
136 }
137 GenericAudioBufferRef::F64(audio_buffer) => {
138 GenericAudioBuffer::F64(audio_buffer.clone())
139 }
140 };
141
142 return Ok(Some(audio_buf));
143 }
144 }
145}