music_player_playback/decoder/
symphonia_decoder.rs1use std::io;
2
3use log::warn;
4use symphonia::core::{
5 audio::SampleBuffer,
6 codecs::{Decoder, DecoderOptions, CODEC_TYPE_NULL},
7 errors::Error,
8 formats::{FormatOptions, FormatReader, SeekMode, SeekTo, Track},
9 io::{MediaSource, MediaSourceStream},
10 meta::{MetadataOptions, Visual},
11 probe::{Hint, ProbeResult},
12 units::{Time, TimeBase},
13};
14
15use super::{AudioDecoder, AudioPacket, AudioPacketPosition, DecoderError, DecoderResult};
16
17use crate::PAGES_PER_MS;
18
19#[derive(Copy, Clone)]
20struct PlayTrackOptions {
21 track_id: u32,
22 seek_ts: u64,
23}
24
25fn first_supported_track(tracks: &[Track]) -> Option<&Track> {
26 tracks
27 .iter()
28 .find(|t| t.codec_params.codec != CODEC_TYPE_NULL)
29}
30
31pub struct SymphoniaDecoder {
32 format: Box<dyn FormatReader>,
33 decoder: Box<dyn Decoder>,
34 sample_buffer: Option<SampleBuffer<f64>>,
35}
36
37impl SymphoniaDecoder {
38 pub fn new<R>(input: R, hint: Hint) -> DecoderResult<Self>
39 where
40 R: MediaSource + 'static,
41 {
42 let mss = MediaSourceStream::new(Box::new(input), Default::default());
44
45 let format_opts = FormatOptions {
47 enable_gapless: false,
48 ..Default::default()
49 };
50
51 let metadata_opts: MetadataOptions = Default::default();
53
54 let track: Option<usize> = None;
55
56 match symphonia::default::get_probe().format(&hint, mss, &format_opts, &metadata_opts) {
58 Ok(probed) => {
59 let decode_opts = DecoderOptions {
64 verify: false,
65 ..Default::default()
66 };
67
68 let track = track
74 .and_then(|t| probed.format.tracks().get(t))
75 .or_else(|| first_supported_track(probed.format.tracks()));
76
77 let track_id = match track {
78 Some(track) => track.id,
79 _ => {
80 return Err(DecoderError::SymphoniaDecoder(
81 "No supported tracks found".to_string(),
82 ))
83 }
84 };
85
86 let seek_ts = 0;
87
88 let track_info = PlayTrackOptions { track_id, seek_ts };
89
90 let track = match probed
92 .format
93 .tracks()
94 .iter()
95 .find(|track| track.id == track_info.track_id)
96 {
97 Some(track) => track,
98 _ => {
99 return Err(DecoderError::SymphoniaDecoder(
100 "No supported tracks found".to_string(),
101 ))
102 }
103 };
104
105 let decoder =
107 symphonia::default::get_codecs().make(&track.codec_params, &decode_opts)?;
108 return Ok(SymphoniaDecoder {
109 format: probed.format,
110 decoder,
111 sample_buffer: None,
112 });
113 }
114 Err(err) => {
115 return Err(DecoderError::SymphoniaDecoder(format!(
117 "file not supported. reason? {}",
118 err
119 )));
120 }
121 }
122 }
123
124 fn ts_to_ms(&self, ts: u64) -> u32 {
125 let time_base = self.decoder.codec_params().time_base;
126 let seeked_to_ms = match time_base {
127 Some(time_base) => {
128 let time = time_base.calc_time(ts);
129 (time.seconds as f64 + time.frac) * 1000.
130 }
131 None => ts as f64 * PAGES_PER_MS,
133 };
134 seeked_to_ms as u32
135 }
136}
137
138impl AudioDecoder for SymphoniaDecoder {
139 fn seek(&mut self, position_ms: u32) -> Result<u32, DecoderError> {
140 let seconds = position_ms as u64 / 1000;
141 let frac = (position_ms as f64 % 1000.) / 1000.;
142 let time = Time::new(seconds, frac);
143
144 let seeked_to_ts = self.format.seek(
146 SeekMode::Accurate,
147 SeekTo::Time {
148 time,
149 track_id: None,
150 },
151 )?;
152
153 self.decoder.reset();
156
157 Ok(self.ts_to_ms(seeked_to_ts.actual_ts))
158 }
159
160 fn next_packet(
161 &mut self,
162 ) -> DecoderResult<Option<(AudioPacketPosition, AudioPacket, u16, u32)>> {
163 let mut skipped = false;
164
165 loop {
166 let packet = match self.format.next_packet() {
167 Ok(packet) => packet,
168 Err(Error::IoError(err)) => {
169 if err.kind() == io::ErrorKind::UnexpectedEof {
170 return Ok(None);
171 } else {
172 return Err(DecoderError::SymphoniaDecoder(err.to_string()));
173 }
174 }
175 Err(err) => {
176 return Err(err.into());
177 }
178 };
179
180 let position_ms = self.ts_to_ms(packet.ts());
181 let packet_position = AudioPacketPosition {
182 position_ms,
183 skipped,
184 };
185
186 match self.decoder.decode(&packet) {
187 Ok(decoded) => {
188 let spec = *decoded.spec();
189 let sample_buffer = match self.sample_buffer.as_mut() {
190 Some(buffer) => buffer,
191 None => {
192 let duration = decoded.capacity() as u64;
193 self.sample_buffer.insert(SampleBuffer::new(duration, spec))
194 }
195 };
196
197 sample_buffer.copy_interleaved_ref(decoded);
198 let samples = AudioPacket::Samples(sample_buffer.samples().to_vec());
199
200 return Ok(Some((
201 packet_position,
202 samples,
203 spec.channels.count() as u16,
204 spec.rate,
205 )));
206 }
207 Err(Error::DecodeError(_)) => {
208 warn!("Skipping malformed audio packet at {} ms", position_ms);
211 skipped = true;
212 continue;
213 }
214 Err(err) => return Err(err.into()),
215 }
216 }
217 }
218}