music_player_playback/decoder/
symphonia_decoder.rs

1use 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        // Create the media source stream using the boxed media source from above.
43        let mss = MediaSourceStream::new(Box::new(input), Default::default());
44
45        // Use the default options for format readers other than for gapless playback.
46        let format_opts = FormatOptions {
47            enable_gapless: false,
48            ..Default::default()
49        };
50
51        // Use the default options for metadata readers.
52        let metadata_opts: MetadataOptions = Default::default();
53
54        let track: Option<usize> = None;
55
56        // Probe the media source stream for metadata and get the format reader.
57        match symphonia::default::get_probe().format(&hint, mss, &format_opts, &metadata_opts) {
58            Ok(probed) => {
59                // Playback mode.
60                // print_format(song, &mut probed);
61
62                // Set the decoder options.
63                let decode_opts = DecoderOptions {
64                    verify: false,
65                    ..Default::default()
66                };
67
68                // Play it!
69                // play(probed.format, track, seek_time, &decode_opts, no_progress);
70
71                // If the user provided a track number, select that track if it exists, otherwise, select the
72                // first track with a known codec.
73                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                // Get the selected track using the track ID.
91                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                // Create a decoder for the track.
106                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                // The input was not supported by any format reader.
116                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            // Fallback in the unexpected case that the format has no base time set.
132            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        // `track_id: None` implies the default track ID (of the container, not of Spotify).
145        let seeked_to_ts = self.format.seek(
146            SeekMode::Accurate,
147            SeekTo::Time {
148                time,
149                track_id: None,
150            },
151        )?;
152
153        // Seeking is a `FormatReader` operation, so the decoder cannot reliably
154        // know when a seek took place. Reset it to avoid audio glitches.
155        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                    // The packet failed to decode due to corrupted or invalid data, get a new
209                    // packet and try again.
210                    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}