diff --git a/audio/src/fetch/mod.rs b/audio/src/fetch/mod.rs index f3229574..9185e14e 100644 --- a/audio/src/fetch/mod.rs +++ b/audio/src/fetch/mod.rs @@ -65,10 +65,7 @@ pub const MINIMUM_DOWNLOAD_SIZE: usize = 1024 * 128; /// Note: if the file is opened to play from the beginning, the amount of data to /// read ahead is requested in addition to this amount. If the file is opened to seek to /// another position, then only this amount is requested on the first request. -pub const INITIAL_DOWNLOAD_SIZE: usize = 1024 * 128; - -/// The ping time that is used for calculations before a ping time was actually measured. -pub const INITIAL_PING_TIME_ESTIMATE: Duration = Duration::from_millis(500); +pub const INITIAL_DOWNLOAD_SIZE: usize = 1024 * 8; /// If the measured ping time to the Spotify server is larger than this value, it is capped /// to avoid run-away block sizes and pre-fetching. @@ -321,7 +318,6 @@ impl AudioFile { session: &Session, file_id: FileId, bytes_per_second: usize, - play_from_beginning: bool, ) -> Result { if let Some(file) = session.cache().and_then(|cache| cache.file(file_id)) { debug!("File {} already in cache", file_id); @@ -332,13 +328,8 @@ impl AudioFile { let (complete_tx, complete_rx) = oneshot::channel(); - let streaming = AudioFileStreaming::open( - session.clone(), - file_id, - complete_tx, - bytes_per_second, - play_from_beginning, - ); + let streaming = + AudioFileStreaming::open(session.clone(), file_id, complete_tx, bytes_per_second); let session_ = session.clone(); session.spawn(complete_rx.map_ok(move |mut file| { @@ -386,38 +377,26 @@ impl AudioFileStreaming { file_id: FileId, complete_tx: oneshot::Sender, bytes_per_second: usize, - play_from_beginning: bool, ) -> Result { - // When the audio file is really small, this `download_size` may turn out to be - // larger than the audio file we're going to stream later on. This is OK; requesting - // `Content-Range` > `Content-Length` will return the complete file with status code - // 206 Partial Content. - let download_size = if play_from_beginning { - INITIAL_DOWNLOAD_SIZE - + max( - (READ_AHEAD_DURING_PLAYBACK.as_secs_f32() * bytes_per_second as f32) as usize, - (INITIAL_PING_TIME_ESTIMATE.as_secs_f32() - * READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS - * bytes_per_second as f32) as usize, - ) - } else { - INITIAL_DOWNLOAD_SIZE - }; - let cdn_url = CdnUrl::new(file_id).resolve_audio(&session).await?; if let Ok(url) = cdn_url.try_get_url() { trace!("Streaming from {}", url); } - let mut streamer = session - .spclient() - .stream_from_cdn(&cdn_url, 0, download_size)?; - let request_time = Instant::now(); + // When the audio file is really small, this `download_size` may turn out to be + // larger than the audio file we're going to stream later on. This is OK; requesting + // `Content-Range` > `Content-Length` will return the complete file with status code + // 206 Partial Content. + let mut streamer = + session + .spclient() + .stream_from_cdn(&cdn_url, 0, INITIAL_DOWNLOAD_SIZE)?; // Get the first chunk with the headers to get the file size. // The remainder of that chunk with possibly also a response body is then // further processed in `audio_file_fetch`. + let request_time = Instant::now(); let response = streamer.next().await.ok_or(AudioFileError::NoData)??; let header_value = response @@ -425,14 +404,16 @@ impl AudioFileStreaming { .get(CONTENT_RANGE) .ok_or(AudioFileError::Header)?; let str_value = header_value.to_str()?; - let file_size_str = str_value.split('/').last().unwrap_or_default(); - let file_size = file_size_str.parse()?; + let hyphen_index = str_value.find('-').unwrap_or_default(); + let slash_index = str_value.find('/').unwrap_or_default(); + let upper_bound: usize = str_value[hyphen_index + 1..slash_index].parse()?; + let file_size = str_value[slash_index + 1..].parse()?; let initial_request = StreamingRequest { streamer, initial_response: Some(response), offset: 0, - length: download_size, + length: upper_bound + 1, request_time, }; diff --git a/playback/src/decoder/symphonia_decoder.rs b/playback/src/decoder/symphonia_decoder.rs index eba819ee..3b585007 100644 --- a/playback/src/decoder/symphonia_decoder.rs +++ b/playback/src/decoder/symphonia_decoder.rs @@ -1,14 +1,19 @@ use std::io; -use symphonia::core::{ - audio::SampleBuffer, - codecs::{Decoder, DecoderOptions}, - errors::Error, - formats::{FormatReader, SeekMode, SeekTo}, - io::{MediaSource, MediaSourceStream, MediaSourceStreamOptions}, - meta::{MetadataOptions, StandardTagKey, Value}, - probe::Hint, - units::Time, +use symphonia::{ + core::{ + audio::SampleBuffer, + codecs::{Decoder, DecoderOptions}, + errors::Error, + formats::{FormatReader, SeekMode, SeekTo}, + io::{MediaSource, MediaSourceStream, MediaSourceStreamOptions}, + meta::{StandardTagKey, Value}, + units::Time, + }, + default::{ + codecs::{Mp3Decoder, VorbisDecoder}, + formats::{Mp3Reader, OggReader}, + }, }; use super::{AudioDecoder, AudioPacket, DecoderError, DecoderResult}; @@ -20,13 +25,13 @@ use crate::{ }; pub struct SymphoniaDecoder { - decoder: Box, format: Box, + decoder: Box, sample_buffer: Option>, } impl SymphoniaDecoder { - pub fn new(input: R, format: AudioFileFormat) -> DecoderResult + pub fn new(input: R, file_format: AudioFileFormat) -> DecoderResult where R: MediaSource + 'static, { @@ -35,41 +40,37 @@ impl SymphoniaDecoder { }; let mss = MediaSourceStream::new(Box::new(input), mss_opts); - // Not necessary, but speeds up loading. - let mut hint = Hint::new(); - if AudioFiles::is_ogg_vorbis(format) { - hint.with_extension("ogg"); - hint.mime_type("audio/ogg"); - } else if AudioFiles::is_mp3(format) { - hint.with_extension("mp3"); - hint.mime_type("audio/mp3"); - } else if AudioFiles::is_flac(format) { - hint.with_extension("flac"); - hint.mime_type("audio/flac"); - } - let format_opts = Default::default(); - let metadata_opts: MetadataOptions = Default::default(); - let decoder_opts: DecoderOptions = Default::default(); - - let probed = - symphonia::default::get_probe().format(&hint, mss, &format_opts, &metadata_opts)?; - let format = probed.format; + let format: Box = if AudioFiles::is_ogg_vorbis(file_format) { + Box::new(OggReader::try_new(mss, &format_opts)?) + } else if AudioFiles::is_mp3(file_format) { + Box::new(Mp3Reader::try_new(mss, &format_opts)?) + } else { + return Err(DecoderError::SymphoniaDecoder(format!( + "Unsupported format: {:?}", + file_format + ))); + }; let track = format.default_track().ok_or_else(|| { DecoderError::SymphoniaDecoder("Could not retrieve default track".into()) })?; - let decoder = symphonia::default::get_codecs().make(&track.codec_params, &decoder_opts)?; + let decoder_opts: DecoderOptions = Default::default(); + let decoder: Box = if AudioFiles::is_ogg_vorbis(file_format) { + Box::new(VorbisDecoder::try_new(&track.codec_params, &decoder_opts)?) + } else if AudioFiles::is_mp3(file_format) { + Box::new(Mp3Decoder::try_new(&track.codec_params, &decoder_opts)?) + } else { + return Err(DecoderError::SymphoniaDecoder(format!( + "Unsupported decoder: {:?}", + file_format + ))); + }; - let codec_params = decoder.codec_params(); - let rate = codec_params.sample_rate.ok_or_else(|| { + let rate = decoder.codec_params().sample_rate.ok_or_else(|| { DecoderError::SymphoniaDecoder("Could not retrieve sample rate".into()) })?; - let channels = codec_params.channels.ok_or_else(|| { - DecoderError::SymphoniaDecoder("Could not retrieve channel configuration".into()) - })?; - if rate != SAMPLE_RATE { return Err(DecoderError::SymphoniaDecoder(format!( "Unsupported sample rate: {}", @@ -77,6 +78,9 @@ impl SymphoniaDecoder { ))); } + let channels = decoder.codec_params().channels.ok_or_else(|| { + DecoderError::SymphoniaDecoder("Could not retrieve channel configuration".into()) + })?; if channels.count() != NUM_CHANNELS as usize { return Err(DecoderError::SymphoniaDecoder(format!( "Unsupported number of channels: {}", @@ -85,8 +89,8 @@ impl SymphoniaDecoder { } Ok(Self { - decoder, format, + decoder, // We set the sample buffer when decoding the first full packet, // whose duration is also the ideal sample buffer size. diff --git a/playback/src/player.rs b/playback/src/player.rs index 9ebd455c..d5d4b269 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -875,17 +875,11 @@ impl PlayerTrackLoader { }; let bytes_per_second = self.stream_data_rate(format); - let play_from_beginning = position_ms == 0; // This is only a loop to be able to reload the file if an error occured // while opening a cached file. loop { - let encrypted_file = AudioFile::open( - &self.session, - file_id, - bytes_per_second, - play_from_beginning, - ); + let encrypted_file = AudioFile::open(&self.session, file_id, bytes_per_second); let encrypted_file = match encrypted_file.await { Ok(encrypted_file) => encrypted_file,