Skip to content

Commit d12e1b8

Browse files
authored
Send playback position as player event (#1495)
* Send play progress as PlayerEvent::PositionChanged * Replaced PlayerEvent::PositionChanged with set_progress_callback() method * Revert "Replaced PlayerEvent::PositionChanged with set_progress_callback() method" This reverts commit f26e3de. * Added opt-in config in PlayerConfig for progress event * Added doc comments and set default position interval to 1sec for standalone * Remove handling of PositionChanged in standalone binary * Fixed wrong event handling
1 parent 6bdc0eb commit d12e1b8

5 files changed

Lines changed: 34 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2626
- [connect] Add `volume_steps` to `ConnectConfig` (breaking)
2727
- [connect] Add and enforce rustdoc
2828
- [playback] Add `track` field to `PlayerEvent::RepeatChanged` (breaking)
29+
- [playback] Add `PlayerEvent::PositionChanged` event to notify about the current playback position
2930
- [core] Add `request_with_options` and `request_with_protobuf_and_options` to `SpClient`
3031
- [oauth] Add `OAuthClient` and `OAuthClientBuilder` structs to achieve a more customizable login process
3132

playback/src/config.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ pub struct PlayerConfig {
139139
// pass function pointers so they can be lazily instantiated *after* spawning a thread
140140
// (thereby circumventing Send bounds that they might not satisfy)
141141
pub ditherer: Option<DithererBuilder>,
142+
/// Setting this will enable periodically sending events during playback informing about the playback position
143+
/// To consume the PlayerEvent::PositionChanged event, listen to events via `Player::get_player_event_channel()``
144+
pub position_update_interval: Option<Duration>,
142145
}
143146

144147
impl Default for PlayerConfig {
@@ -156,6 +159,7 @@ impl Default for PlayerConfig {
156159
normalisation_knee_db: 5.0,
157160
passthrough: false,
158161
ditherer: Some(mk_ditherer::<TriangularDitherer>),
162+
position_update_interval: None,
159163
}
160164
}
161165
}

playback/src/player.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ struct PlayerInternal {
8585

8686
player_id: usize,
8787
play_request_id_generator: SeqGenerator<u64>,
88+
last_progress_update: Instant,
8889
}
8990

9091
static PLAYER_COUNTER: AtomicUsize = AtomicUsize::new(0);
@@ -195,6 +196,14 @@ pub enum PlayerEvent {
195196
track_id: SpotifyId,
196197
position_ms: u32,
197198
},
199+
/// Requires `PlayerConfig::position_update_interval` to be set to Some.
200+
/// Once set this event will be sent periodically while playing the track to inform about the
201+
/// current playback position
202+
PositionChanged {
203+
play_request_id: u64,
204+
track_id: SpotifyId,
205+
position_ms: u32,
206+
},
198207
Seeked {
199208
play_request_id: u64,
200209
track_id: SpotifyId,
@@ -481,6 +490,7 @@ impl Player {
481490

482491
player_id,
483492
play_request_id_generator: SeqGenerator::new(0),
493+
last_progress_update: Instant::now(),
484494
};
485495

486496
// While PlayerInternal is written as a future, it still contains blocking code.
@@ -1340,6 +1350,22 @@ impl Future for PlayerInternal {
13401350
position_ms: new_stream_position_ms,
13411351
});
13421352
}
1353+
1354+
if let Some(interval) =
1355+
self.config.position_update_interval
1356+
{
1357+
let last_progress_update_since_ms =
1358+
now.duration_since(self.last_progress_update);
1359+
1360+
if last_progress_update_since_ms > interval {
1361+
self.last_progress_update = now;
1362+
self.send_event(PlayerEvent::PositionChanged {
1363+
play_request_id,
1364+
track_id,
1365+
position_ms: new_stream_position_ms,
1366+
});
1367+
}
1368+
}
13431369
}
13441370
Err(e) => {
13451371
error!("Skipping to next track, unable to decode samples for track <{:?}>: {:?}", track_id, e);

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1818,6 +1818,7 @@ fn get_setup() -> Setup {
18181818
normalisation_release_cf,
18191819
normalisation_knee_db,
18201820
ditherer,
1821+
position_update_interval: None,
18211822
}
18221823
};
18231824

src/player_event_handler.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,8 @@ impl EventHandler {
243243
);
244244
env_vars.insert("FILTER", filter.to_string());
245245
}
246+
// Ignore event irrelevant for standalone binary like PositionChanged
247+
_ => {}
246248
}
247249

248250
if !env_vars.is_empty() {

0 commit comments

Comments
 (0)