diff --git a/CHANGELOG.md b/CHANGELOG.md index bf3b3057..c245e6c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [connect] Add `volume_steps` to `ConnectConfig` (breaking) - [connect] Add and enforce rustdoc - [playback] Add `track` field to `PlayerEvent::RepeatChanged` (breaking) +- [playback] Add `PlayerEvent::PositionChanged` event to notify about the current playback position - [core] Add `request_with_options` and `request_with_protobuf_and_options` to `SpClient` - [oauth] Add `OAuthClient` and `OAuthClientBuilder` structs to achieve a more customizable login process diff --git a/playback/src/player.rs b/playback/src/player.rs index 296c26e5..d277fe25 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -85,6 +85,7 @@ struct PlayerInternal { player_id: usize, play_request_id_generator: SeqGenerator, + last_progress_update: Instant, } static PLAYER_COUNTER: AtomicUsize = AtomicUsize::new(0); @@ -195,6 +196,12 @@ pub enum PlayerEvent { track_id: SpotifyId, position_ms: u32, }, + // Will be sent periodically while playing the track to inform about the current playback position + PositionChanged { + play_request_id: u64, + track_id: SpotifyId, + position_ms: u32, + }, Seeked { play_request_id: u64, track_id: SpotifyId, @@ -481,6 +488,7 @@ impl Player { player_id, play_request_id_generator: SeqGenerator::new(0), + last_progress_update: Instant::now(), }; // While PlayerInternal is written as a future, it still contains blocking code. @@ -1340,6 +1348,18 @@ impl Future for PlayerInternal { position_ms: new_stream_position_ms, }); } + + let last_progress_update_since_ms = now + .duration_since(self.last_progress_update) + .as_millis(); + if last_progress_update_since_ms > 250 { + self.last_progress_update = now; + self.send_event(PlayerEvent::PositionChanged { + play_request_id, + track_id, + position_ms: new_stream_position_ms, + }); + } } Err(e) => { error!("Skipping to next track, unable to decode samples for track <{:?}>: {:?}", track_id, e); diff --git a/src/player_event_handler.rs b/src/player_event_handler.rs index 21cfe01c..e1f2ad1b 100644 --- a/src/player_event_handler.rs +++ b/src/player_event_handler.rs @@ -194,6 +194,20 @@ impl EventHandler { env_vars.insert("POSITION_MS", position_ms.to_string()); } }, + PlayerEvent::PositionChanged { + track_id, + position_ms, + .. + } => match track_id.to_base62() { + Err(e) => { + warn!("PlayerEvent::PositionChanged: Invalid track id: {}", e) + } + Ok(id) => { + env_vars.insert("PLAYER_EVENT", "position_changed".to_string()); + env_vars.insert("TRACK_ID", id); + env_vars.insert("POSITION_MS", position_ms.to_string()); + } + }, PlayerEvent::SessionConnected { connection_id, user_name,