Seek in milliseconds and report the actual new position

This commit is contained in:
Roderick van Domburg 2022-01-04 00:17:30 +01:00
parent f3a66d4b99
commit 01448ccbe8
No known key found for this signature in database
GPG key ID: FE2585E713F9F30A
4 changed files with 108 additions and 107 deletions

View file

@ -55,8 +55,8 @@ impl AudioPacket {
} }
pub trait AudioDecoder { pub trait AudioDecoder {
fn seek(&mut self, absgp: u64) -> Result<u64, DecoderError>; fn seek(&mut self, position_ms: u32) -> Result<u32, DecoderError>;
fn next_packet(&mut self) -> DecoderResult<Option<AudioPacket>>; fn next_packet(&mut self) -> DecoderResult<Option<(u32, AudioPacket)>>;
} }
impl From<symphonia::core::errors::Error> for DecoderError { impl From<symphonia::core::errors::Error> for DecoderError {

View file

@ -9,7 +9,10 @@ use ogg::{OggReadError, Packet, PacketReader, PacketWriteEndInfo, PacketWriter};
use super::{AudioDecoder, AudioPacket, DecoderError, DecoderResult}; use super::{AudioDecoder, AudioPacket, DecoderError, DecoderResult};
use crate::metadata::audio::{AudioFileFormat, AudioFiles}; use crate::{
metadata::audio::{AudioFileFormat, AudioFiles},
MS_PER_PAGE, PAGES_PER_MS,
};
fn get_header<T>(code: u8, rdr: &mut PacketReader<T>) -> DecoderResult<Box<[u8]>> fn get_header<T>(code: u8, rdr: &mut PacketReader<T>) -> DecoderResult<Box<[u8]>>
where where
@ -23,7 +26,7 @@ where
debug!("Vorbis header type {}", &pkt_type); debug!("Vorbis header type {}", &pkt_type);
if pkt_type != code { if pkt_type != code {
return Err(DecoderError::PassthroughDecoder("Invalid Data".to_string())); return Err(DecoderError::PassthroughDecoder("Invalid Data".into()));
} }
Ok(pck.data.into_boxed_slice()) Ok(pck.data.into_boxed_slice())
@ -79,10 +82,16 @@ impl<R: Read + Seek> PassthroughDecoder<R> {
bos: false, bos: false,
}) })
} }
fn position_pcm_to_ms(position_pcm: u64) -> u32 {
(position_pcm as f64 * MS_PER_PAGE) as u32
}
} }
impl<R: Read + Seek> AudioDecoder for PassthroughDecoder<R> { impl<R: Read + Seek> AudioDecoder for PassthroughDecoder<R> {
fn seek(&mut self, absgp: u64) -> Result<u64, DecoderError> { fn seek(&mut self, position_ms: u32) -> Result<u32, DecoderError> {
let absgp = (position_ms as f64 * PAGES_PER_MS) as u64;
// add an eos to previous stream if missing // add an eos to previous stream if missing
if self.bos && !self.eos { if self.bos && !self.eos {
match self.rdr.read_packet() { match self.rdr.read_packet() {
@ -118,18 +127,17 @@ impl<R: Read + Seek> AudioDecoder for PassthroughDecoder<R> {
let new_page = pck.absgp_page(); let new_page = pck.absgp_page();
self.ofsgp_page = new_page; self.ofsgp_page = new_page;
debug!("Seek to offset page {}", new_page); debug!("Seek to offset page {}", new_page);
Ok(new_page) let new_position_ms = Self::position_pcm_to_ms(new_page);
Ok(new_position_ms)
} }
None => Err(DecoderError::PassthroughDecoder( None => Err(DecoderError::PassthroughDecoder("Packet is None".into())),
"Packet is None".to_string(),
)),
} }
} }
Err(e) => Err(DecoderError::PassthroughDecoder(e.to_string())), Err(e) => Err(DecoderError::PassthroughDecoder(e.to_string())),
} }
} }
fn next_packet(&mut self) -> DecoderResult<Option<AudioPacket>> { fn next_packet(&mut self) -> DecoderResult<Option<(u32, AudioPacket)>> {
// write headers if we are (re)starting // write headers if we are (re)starting
if !self.bos { if !self.bos {
self.wtr self.wtr
@ -199,8 +207,9 @@ impl<R: Read + Seek> AudioDecoder for PassthroughDecoder<R> {
let data = self.wtr.inner_mut(); let data = self.wtr.inner_mut();
if !data.is_empty() { if !data.is_empty() {
let position_ms = Self::position_pcm_to_ms(pckgp_page);
let ogg_data = AudioPacket::Raw(std::mem::take(data)); let ogg_data = AudioPacket::Raw(std::mem::take(data));
return Ok(Some(ogg_data)); return Ok(Some((position_ms, ogg_data)));
} }
} }
} }

View file

@ -8,6 +8,7 @@ use symphonia::core::{
io::{MediaSource, MediaSourceStream, MediaSourceStreamOptions}, io::{MediaSource, MediaSourceStream, MediaSourceStreamOptions},
meta::{MetadataOptions, StandardTagKey, Value}, meta::{MetadataOptions, StandardTagKey, Value},
probe::Hint, probe::Hint,
units::Time,
}; };
use super::{AudioDecoder, AudioPacket, DecoderError, DecoderResult}; use super::{AudioDecoder, AudioPacket, DecoderError, DecoderResult};
@ -15,10 +16,10 @@ use super::{AudioDecoder, AudioPacket, DecoderError, DecoderResult};
use crate::{ use crate::{
metadata::audio::{AudioFileFormat, AudioFiles}, metadata::audio::{AudioFileFormat, AudioFiles},
player::NormalisationData, player::NormalisationData,
PAGES_PER_MS,
}; };
pub struct SymphoniaDecoder { pub struct SymphoniaDecoder {
track_id: u32,
decoder: Box<dyn Decoder>, decoder: Box<dyn Decoder>,
format: Box<dyn FormatReader>, format: Box<dyn FormatReader>,
sample_buffer: SampleBuffer<f64>, sample_buffer: SampleBuffer<f64>,
@ -85,7 +86,6 @@ impl SymphoniaDecoder {
let sample_buffer = SampleBuffer::new(max_frames, SignalSpec { rate, channels }); let sample_buffer = SampleBuffer::new(max_frames, SignalSpec { rate, channels });
Ok(Self { Ok(Self {
track_id: track.id,
decoder, decoder,
format, format,
sample_buffer, sample_buffer,
@ -127,22 +127,40 @@ impl SymphoniaDecoder {
} }
} }
} }
fn ts_to_ms(&self, ts: u64) -> u32 {
let time_base = self.decoder.codec_params().time_base;
let seeked_to_ms = match time_base {
Some(time_base) => {
let time = time_base.calc_time(ts);
(time.seconds as f64 + time.frac) * 1000.
}
// Fallback in the unexpected case that the format has no base time set.
None => (ts as f64 * PAGES_PER_MS),
};
seeked_to_ms as u32
}
} }
impl AudioDecoder for SymphoniaDecoder { impl AudioDecoder for SymphoniaDecoder {
// TODO : change to position ms fn seek(&mut self, position_ms: u32) -> Result<u32, DecoderError> {
fn seek(&mut self, absgp: u64) -> Result<u64, DecoderError> { let seconds = position_ms as u64 / 1000;
let seeked_to = self.format.seek( let frac = (position_ms as f64 % 1000.) / 1000.;
let time = Time::new(seconds, frac);
// `track_id: None` implies the default track ID (of the container, not of Spotify).
let seeked_to_ts = self.format.seek(
SeekMode::Accurate, SeekMode::Accurate,
SeekTo::TimeStamp { SeekTo::Time {
ts: absgp, // TODO : move to Duration time,
track_id: self.track_id, track_id: None,
}, },
)?; )?;
Ok(seeked_to.actual_ts)
Ok(self.ts_to_ms(seeked_to_ts.actual_ts))
} }
fn next_packet(&mut self) -> DecoderResult<Option<AudioPacket>> { fn next_packet(&mut self) -> DecoderResult<Option<(u32, AudioPacket)>> {
let packet = match self.format.next_packet() { let packet = match self.format.next_packet() {
Ok(packet) => packet, Ok(packet) => packet,
Err(Error::IoError(err)) => { Err(Error::IoError(err)) => {
@ -159,11 +177,10 @@ impl AudioDecoder for SymphoniaDecoder {
match self.decoder.decode(&packet) { match self.decoder.decode(&packet) {
Ok(audio_buf) => { Ok(audio_buf) => {
// TODO : track current playback position
self.sample_buffer.copy_interleaved_ref(audio_buf); self.sample_buffer.copy_interleaved_ref(audio_buf);
Ok(Some(AudioPacket::Samples( let position_ms = self.ts_to_ms(packet.pts());
self.sample_buffer.samples().to_vec(), let samples = AudioPacket::Samples(self.sample_buffer.samples().to_vec());
))) Ok(Some((position_ms, samples)))
} }
Err(Error::ResetRequired) => { Err(Error::ResetRequired) => {
// This may happen after a seek. // This may happen after a seek.

View file

@ -34,7 +34,7 @@ use crate::{
mixer::AudioFilter, mixer::AudioFilter,
}; };
use crate::{MS_PER_PAGE, NUM_CHANNELS, PAGES_PER_MS, SAMPLES_PER_SECOND}; use crate::SAMPLES_PER_SECOND;
const PRELOAD_NEXT_TRACK_BEFORE_END_DURATION_MS: u32 = 30000; const PRELOAD_NEXT_TRACK_BEFORE_END_DURATION_MS: u32 = 30000;
pub const DB_VOLTAGE_RATIO: f64 = 20.0; pub const DB_VOLTAGE_RATIO: f64 = 20.0;
@ -489,7 +489,7 @@ struct PlayerLoadedTrackData {
stream_loader_controller: StreamLoaderController, stream_loader_controller: StreamLoaderController,
bytes_per_second: usize, bytes_per_second: usize,
duration_ms: u32, duration_ms: u32,
stream_position_pcm: u64, stream_position_ms: u32,
is_explicit: bool, is_explicit: bool,
} }
@ -524,7 +524,7 @@ enum PlayerState {
stream_loader_controller: StreamLoaderController, stream_loader_controller: StreamLoaderController,
bytes_per_second: usize, bytes_per_second: usize,
duration_ms: u32, duration_ms: u32,
stream_position_pcm: u64, stream_position_ms: u32,
suggested_to_preload_next_track: bool, suggested_to_preload_next_track: bool,
is_explicit: bool, is_explicit: bool,
}, },
@ -537,7 +537,7 @@ enum PlayerState {
stream_loader_controller: StreamLoaderController, stream_loader_controller: StreamLoaderController,
bytes_per_second: usize, bytes_per_second: usize,
duration_ms: u32, duration_ms: u32,
stream_position_pcm: u64, stream_position_ms: u32,
reported_nominal_start_time: Option<Instant>, reported_nominal_start_time: Option<Instant>,
suggested_to_preload_next_track: bool, suggested_to_preload_next_track: bool,
is_explicit: bool, is_explicit: bool,
@ -622,7 +622,7 @@ impl PlayerState {
bytes_per_second, bytes_per_second,
normalisation_data, normalisation_data,
stream_loader_controller, stream_loader_controller,
stream_position_pcm, stream_position_ms,
is_explicit, is_explicit,
.. ..
} => { } => {
@ -635,7 +635,7 @@ impl PlayerState {
stream_loader_controller, stream_loader_controller,
bytes_per_second, bytes_per_second,
duration_ms, duration_ms,
stream_position_pcm, stream_position_ms,
is_explicit, is_explicit,
}, },
}; };
@ -663,7 +663,7 @@ impl PlayerState {
stream_loader_controller, stream_loader_controller,
duration_ms, duration_ms,
bytes_per_second, bytes_per_second,
stream_position_pcm, stream_position_ms,
suggested_to_preload_next_track, suggested_to_preload_next_track,
is_explicit, is_explicit,
} => { } => {
@ -676,7 +676,7 @@ impl PlayerState {
stream_loader_controller, stream_loader_controller,
duration_ms, duration_ms,
bytes_per_second, bytes_per_second,
stream_position_pcm, stream_position_ms,
reported_nominal_start_time: None, reported_nominal_start_time: None,
suggested_to_preload_next_track, suggested_to_preload_next_track,
is_explicit, is_explicit,
@ -705,7 +705,7 @@ impl PlayerState {
stream_loader_controller, stream_loader_controller,
duration_ms, duration_ms,
bytes_per_second, bytes_per_second,
stream_position_pcm, stream_position_ms,
reported_nominal_start_time: _, reported_nominal_start_time: _,
suggested_to_preload_next_track, suggested_to_preload_next_track,
is_explicit, is_explicit,
@ -719,7 +719,7 @@ impl PlayerState {
stream_loader_controller, stream_loader_controller,
duration_ms, duration_ms,
bytes_per_second, bytes_per_second,
stream_position_pcm, stream_position_ms,
suggested_to_preload_next_track, suggested_to_preload_next_track,
is_explicit, is_explicit,
}; };
@ -981,13 +981,12 @@ impl PlayerTrackLoader {
// the cursor may have been moved by parsing normalisation data. This may not // the cursor may have been moved by parsing normalisation data. This may not
// matter for playback (but won't hurt either), but may be useful for the // matter for playback (but won't hurt either), but may be useful for the
// passthrough decoder. // passthrough decoder.
let position_pcm = PlayerInternal::position_ms_to_pcm(position_ms); let stream_position_ms = match decoder.seek(position_ms) {
let stream_position_pcm = match decoder.seek(position_pcm) { Ok(_) => position_ms,
Ok(_) => position_pcm,
Err(e) => { Err(e) => {
warn!( warn!(
"PlayerTrackLoader::load_track error seeking to PCM page {}: {}", "PlayerTrackLoader::load_track error seeking to {}: {}",
position_pcm, e position_ms, e
); );
0 0
} }
@ -1005,7 +1004,7 @@ impl PlayerTrackLoader {
stream_loader_controller, stream_loader_controller,
bytes_per_second, bytes_per_second,
duration_ms, duration_ms,
stream_position_pcm, stream_position_ms,
is_explicit, is_explicit,
}); });
} }
@ -1118,23 +1117,18 @@ impl Future for PlayerInternal {
play_request_id, play_request_id,
ref mut decoder, ref mut decoder,
normalisation_factor, normalisation_factor,
ref mut stream_position_pcm, ref mut stream_position_ms,
ref mut reported_nominal_start_time, ref mut reported_nominal_start_time,
duration_ms, duration_ms,
.. ..
} = self.state } = self.state
{ {
match decoder.next_packet() { match decoder.next_packet() {
Ok(packet) => { Ok(result) => {
if !passthrough { if let Some((new_stream_position_ms, ref packet)) = result {
if let Some(ref packet) = packet { if !passthrough {
match packet.samples() { match packet.samples() {
Ok(samples) => { Ok(_) => {
*stream_position_pcm +=
(samples.len() / NUM_CHANNELS as usize) as u64;
let stream_position_millis =
Self::position_pcm_to_ms(*stream_position_pcm);
let notify_about_position = let notify_about_position =
match *reported_nominal_start_time { match *reported_nominal_start_time {
None => true, None => true,
@ -1144,7 +1138,7 @@ impl Future for PlayerInternal {
- reported_nominal_start_time) - reported_nominal_start_time)
.as_millis() .as_millis()
as i64 as i64
- stream_position_millis as i64; - new_stream_position_ms as i64;
lag > Duration::from_secs(1).as_millis() lag > Duration::from_secs(1).as_millis()
as i64 as i64
} }
@ -1153,13 +1147,13 @@ impl Future for PlayerInternal {
*reported_nominal_start_time = Some( *reported_nominal_start_time = Some(
Instant::now() Instant::now()
- Duration::from_millis( - Duration::from_millis(
stream_position_millis as u64, new_stream_position_ms as u64,
), ),
); );
self.send_event(PlayerEvent::Playing { self.send_event(PlayerEvent::Playing {
track_id, track_id,
play_request_id, play_request_id,
position_ms: stream_position_millis as u32, position_ms: new_stream_position_ms as u32,
duration_ms, duration_ms,
}); });
} }
@ -1172,13 +1166,13 @@ impl Future for PlayerInternal {
}) })
} }
} }
} else {
// position, even if irrelevant, must be set so that seek() is called
*stream_position_ms = new_stream_position_ms;
} }
} else {
// position, even if irrelevant, must be set so that seek() is called
*stream_position_pcm = duration_ms.into();
} }
self.handle_packet(packet, normalisation_factor); self.handle_packet(result, normalisation_factor);
} }
Err(e) => { Err(e) => {
error!("Skipping to next track, unable to get next packet for track <{:?}>: {:?}", track_id, e); error!("Skipping to next track, unable to get next packet for track <{:?}>: {:?}", track_id, e);
@ -1198,7 +1192,7 @@ impl Future for PlayerInternal {
track_id, track_id,
play_request_id, play_request_id,
duration_ms, duration_ms,
stream_position_pcm, stream_position_ms,
ref mut stream_loader_controller, ref mut stream_loader_controller,
ref mut suggested_to_preload_next_track, ref mut suggested_to_preload_next_track,
.. ..
@ -1207,14 +1201,14 @@ impl Future for PlayerInternal {
track_id, track_id,
play_request_id, play_request_id,
duration_ms, duration_ms,
stream_position_pcm, stream_position_ms,
ref mut stream_loader_controller, ref mut stream_loader_controller,
ref mut suggested_to_preload_next_track, ref mut suggested_to_preload_next_track,
.. ..
} = self.state } = self.state
{ {
if (!*suggested_to_preload_next_track) if (!*suggested_to_preload_next_track)
&& ((duration_ms as i64 - Self::position_pcm_to_ms(stream_position_pcm) as i64) && ((duration_ms as i64 - stream_position_ms as i64)
< PRELOAD_NEXT_TRACK_BEFORE_END_DURATION_MS as i64) < PRELOAD_NEXT_TRACK_BEFORE_END_DURATION_MS as i64)
&& stream_loader_controller.range_to_end_available() && stream_loader_controller.range_to_end_available()
{ {
@ -1238,14 +1232,6 @@ impl Future for PlayerInternal {
} }
impl PlayerInternal { impl PlayerInternal {
fn position_pcm_to_ms(position_pcm: u64) -> u32 {
(position_pcm as f64 * MS_PER_PAGE) as u32
}
fn position_ms_to_pcm(position_ms: u32) -> u64 {
(position_ms as f64 * PAGES_PER_MS) as u64
}
fn ensure_sink_running(&mut self) { fn ensure_sink_running(&mut self) {
if self.sink_status != SinkStatus::Running { if self.sink_status != SinkStatus::Running {
trace!("== Starting sink =="); trace!("== Starting sink ==");
@ -1336,18 +1322,16 @@ impl PlayerInternal {
if let PlayerState::Paused { if let PlayerState::Paused {
track_id, track_id,
play_request_id, play_request_id,
stream_position_pcm, stream_position_ms,
duration_ms, duration_ms,
.. ..
} = self.state } = self.state
{ {
self.state.paused_to_playing(); self.state.paused_to_playing();
let position_ms = Self::position_pcm_to_ms(stream_position_pcm);
self.send_event(PlayerEvent::Playing { self.send_event(PlayerEvent::Playing {
track_id, track_id,
play_request_id, play_request_id,
position_ms, position_ms: stream_position_ms,
duration_ms, duration_ms,
}); });
self.ensure_sink_running(); self.ensure_sink_running();
@ -1360,7 +1344,7 @@ impl PlayerInternal {
if let PlayerState::Playing { if let PlayerState::Playing {
track_id, track_id,
play_request_id, play_request_id,
stream_position_pcm, stream_position_ms,
duration_ms, duration_ms,
.. ..
} = self.state } = self.state
@ -1368,11 +1352,10 @@ impl PlayerInternal {
self.state.playing_to_paused(); self.state.playing_to_paused();
self.ensure_sink_stopped(false); self.ensure_sink_stopped(false);
let position_ms = Self::position_pcm_to_ms(stream_position_pcm);
self.send_event(PlayerEvent::Paused { self.send_event(PlayerEvent::Paused {
track_id, track_id,
play_request_id, play_request_id,
position_ms, position_ms: stream_position_ms,
duration_ms, duration_ms,
}); });
} else { } else {
@ -1380,9 +1363,9 @@ impl PlayerInternal {
} }
} }
fn handle_packet(&mut self, packet: Option<AudioPacket>, normalisation_factor: f64) { fn handle_packet(&mut self, packet: Option<(u32, AudioPacket)>, normalisation_factor: f64) {
match packet { match packet {
Some(mut packet) => { Some((_, mut packet)) => {
if !packet.is_empty() { if !packet.is_empty() {
if let AudioPacket::Samples(ref mut data) = packet { if let AudioPacket::Samples(ref mut data) = packet {
if self.config.normalisation if self.config.normalisation
@ -1537,7 +1520,7 @@ impl PlayerInternal {
loaded_track: PlayerLoadedTrackData, loaded_track: PlayerLoadedTrackData,
start_playback: bool, start_playback: bool,
) { ) {
let position_ms = Self::position_pcm_to_ms(loaded_track.stream_position_pcm); let position_ms = loaded_track.stream_position_ms;
let mut config = self.config.clone(); let mut config = self.config.clone();
if config.normalisation_type == NormalisationType::Auto { if config.normalisation_type == NormalisationType::Auto {
@ -1569,7 +1552,7 @@ impl PlayerInternal {
stream_loader_controller: loaded_track.stream_loader_controller, stream_loader_controller: loaded_track.stream_loader_controller,
duration_ms: loaded_track.duration_ms, duration_ms: loaded_track.duration_ms,
bytes_per_second: loaded_track.bytes_per_second, bytes_per_second: loaded_track.bytes_per_second,
stream_position_pcm: loaded_track.stream_position_pcm, stream_position_ms: loaded_track.stream_position_ms,
reported_nominal_start_time: Some( reported_nominal_start_time: Some(
Instant::now() - Duration::from_millis(position_ms as u64), Instant::now() - Duration::from_millis(position_ms as u64),
), ),
@ -1588,7 +1571,7 @@ impl PlayerInternal {
stream_loader_controller: loaded_track.stream_loader_controller, stream_loader_controller: loaded_track.stream_loader_controller,
duration_ms: loaded_track.duration_ms, duration_ms: loaded_track.duration_ms,
bytes_per_second: loaded_track.bytes_per_second, bytes_per_second: loaded_track.bytes_per_second,
stream_position_pcm: loaded_track.stream_position_pcm, stream_position_ms: loaded_track.stream_position_ms,
suggested_to_preload_next_track: false, suggested_to_preload_next_track: false,
is_explicit: loaded_track.is_explicit, is_explicit: loaded_track.is_explicit,
}; };
@ -1666,15 +1649,13 @@ impl PlayerInternal {
} }
}; };
let position_pcm = Self::position_ms_to_pcm(position_ms); if position_ms != loaded_track.stream_position_ms {
if position_pcm != loaded_track.stream_position_pcm {
loaded_track loaded_track
.stream_loader_controller .stream_loader_controller
.set_random_access_mode(); .set_random_access_mode();
// This may be blocking. // This may be blocking.
match loaded_track.decoder.seek(position_pcm) { match loaded_track.decoder.seek(position_ms) {
Ok(_) => loaded_track.stream_position_pcm = position_pcm, Ok(_) => loaded_track.stream_position_ms = position_ms,
Err(e) => error!("PlayerInternal handle_command_load: {}", e), Err(e) => error!("PlayerInternal handle_command_load: {}", e),
} }
loaded_track.stream_loader_controller.set_stream_mode(); loaded_track.stream_loader_controller.set_stream_mode();
@ -1692,14 +1673,14 @@ impl PlayerInternal {
// Check if we are already playing the track. If so, just do a seek and update our info. // Check if we are already playing the track. If so, just do a seek and update our info.
if let PlayerState::Playing { if let PlayerState::Playing {
track_id: current_track_id, track_id: current_track_id,
ref mut stream_position_pcm, ref mut stream_position_ms,
ref mut decoder, ref mut decoder,
ref mut stream_loader_controller, ref mut stream_loader_controller,
.. ..
} }
| PlayerState::Paused { | PlayerState::Paused {
track_id: current_track_id, track_id: current_track_id,
ref mut stream_position_pcm, ref mut stream_position_ms,
ref mut decoder, ref mut decoder,
ref mut stream_loader_controller, ref mut stream_loader_controller,
.. ..
@ -1707,13 +1688,11 @@ impl PlayerInternal {
{ {
if current_track_id == track_id { if current_track_id == track_id {
// we can use the current decoder. Ensure it's at the correct position. // we can use the current decoder. Ensure it's at the correct position.
let position_pcm = Self::position_ms_to_pcm(position_ms); if position_ms != *stream_position_ms {
if position_pcm != *stream_position_pcm {
stream_loader_controller.set_random_access_mode(); stream_loader_controller.set_random_access_mode();
// This may be blocking. // This may be blocking.
match decoder.seek(position_pcm) { match decoder.seek(position_ms) {
Ok(_) => *stream_position_pcm = position_pcm, Ok(_) => *stream_position_ms = position_ms,
Err(e) => { Err(e) => {
error!("PlayerInternal::handle_command_load error seeking: {}", e) error!("PlayerInternal::handle_command_load error seeking: {}", e)
} }
@ -1726,7 +1705,7 @@ impl PlayerInternal {
let old_state = mem::replace(&mut self.state, PlayerState::Invalid); let old_state = mem::replace(&mut self.state, PlayerState::Invalid);
if let PlayerState::Playing { if let PlayerState::Playing {
stream_position_pcm, stream_position_ms,
decoder, decoder,
stream_loader_controller, stream_loader_controller,
bytes_per_second, bytes_per_second,
@ -1736,7 +1715,7 @@ impl PlayerInternal {
.. ..
} }
| PlayerState::Paused { | PlayerState::Paused {
stream_position_pcm, stream_position_ms,
decoder, decoder,
stream_loader_controller, stream_loader_controller,
bytes_per_second, bytes_per_second,
@ -1752,7 +1731,7 @@ impl PlayerInternal {
stream_loader_controller, stream_loader_controller,
bytes_per_second, bytes_per_second,
duration_ms, duration_ms,
stream_position_pcm, stream_position_ms,
is_explicit, is_explicit,
}; };
@ -1785,15 +1764,13 @@ impl PlayerInternal {
mut loaded_track, mut loaded_track,
} = preload } = preload
{ {
let position_pcm = Self::position_ms_to_pcm(position_ms); if position_ms != loaded_track.stream_position_ms {
if position_pcm != loaded_track.stream_position_pcm {
loaded_track loaded_track
.stream_loader_controller .stream_loader_controller
.set_random_access_mode(); .set_random_access_mode();
// This may be blocking // This may be blocking
match loaded_track.decoder.seek(position_pcm) { match loaded_track.decoder.seek(position_ms) {
Ok(_) => loaded_track.stream_position_pcm = position_pcm, Ok(_) => loaded_track.stream_position_ms = position_ms,
Err(e) => error!("PlayerInternal handle_command_load: {}", e), Err(e) => error!("PlayerInternal handle_command_load: {}", e),
} }
loaded_track.stream_loader_controller.set_stream_mode(); loaded_track.stream_loader_controller.set_stream_mode();
@ -1908,20 +1885,18 @@ impl PlayerInternal {
stream_loader_controller.set_random_access_mode(); stream_loader_controller.set_random_access_mode();
} }
if let Some(decoder) = self.state.decoder() { if let Some(decoder) = self.state.decoder() {
let position_pcm = Self::position_ms_to_pcm(position_ms); match decoder.seek(position_ms) {
match decoder.seek(position_pcm) {
Ok(_) => { Ok(_) => {
if let PlayerState::Playing { if let PlayerState::Playing {
ref mut stream_position_pcm, ref mut stream_position_ms,
.. ..
} }
| PlayerState::Paused { | PlayerState::Paused {
ref mut stream_position_pcm, ref mut stream_position_ms,
.. ..
} = self.state } = self.state
{ {
*stream_position_pcm = position_pcm; *stream_position_ms = position_ms;
} }
} }
Err(e) => error!("PlayerInternal::handle_command_seek error: {}", e), Err(e) => error!("PlayerInternal::handle_command_seek error: {}", e),