Fix seek handling and playback position sync

This commit is contained in:
joren
2026-03-31 21:04:34 +02:00
parent 790eba8792
commit 122d64e9f4
2 changed files with 147 additions and 25 deletions

View File

@@ -263,7 +263,6 @@ fn build_device_info(device_uuid: &str, device_name: &str) -> Vec<u8> {
out.extend(encode_field_string(4, "Linux")); // model
out.extend(encode_field_string(5, device_uuid)); // serial_number
out.extend(encode_field_varint(6, 5)); // type = COMPUTER(5)
// capabilities: field 1=min_audio_quality(MP3=1), field 2=max_audio_quality(HIRES_LEVEL3=5), field 3=volume_remote_control(ALLOWED=2)
let mut caps = encode_field_varint(1, 1);
caps.extend(encode_field_varint(2, 5));
caps.extend(encode_field_varint(3, 2));
@@ -936,12 +935,44 @@ async fn run_connection(
position_ms,
current_track,
next_track,
..
queue_version_major,
} => {
info!("[STATE] SET_STATE: playing_state={:?} current_track={:?} next_track={:?} pos={}",
playing_state, current_track.as_ref().map(|t| t.track_id),
next_track.as_ref().map(|t| t.track_id), position_ms);
let seek_only_state = playing_state.is_none()
&& current_track.is_none()
&& next_track.is_none()
&& *queue_version_major == 0
&& *position_ms > 0;
if seek_only_state {
let target_pos = *position_ms as u64;
let status = player.status();
let current_player_pos = status.position_ms;
let should_seek = status.state != PlayerState::Stopped
&& target_pos.abs_diff(current_player_pos) > 800;
if should_seek {
info!(
"[STATE] Applying seek to {}ms (local={}ms)",
target_pos, current_player_pos
);
player.send(PlayerCommand::Seek(target_pos));
track_ended = false;
// ACTION_TYPE_SEEK = 8
let action_msg = msg_renderer_action(8, Some(*position_ms));
ws_tx.send(Message::Binary(build_payload_frame(msg_id, &action_msg).into())).await?;
msg_id += 1;
}
current_position_ms = target_pos;
send_state!(ws_tx, msg_id);
continue;
}
// 1. Store next_track metadata
if let Some(nt) = next_track {
current_next_queue_item_id = nt.queue_item_id;
@@ -978,6 +1009,7 @@ async fn run_connection(
track_id: track.track_id,
queue_item_id: track.queue_item_id,
duration_ms,
start_position_ms: *position_ms as u64,
});
current_buffer_state = 2; // OK
}
@@ -1034,7 +1066,19 @@ async fn run_connection(
// 4. Apply seek position if provided and not loading new track
let is_pause = matches!(playing_state, Some(3));
if !loaded_new_track && *position_ms > 0 && !is_pause {
current_position_ms = *position_ms as u64;
let requested = *position_ms as u64;
let status = player.status();
let local = status.position_ms;
if status.state != PlayerState::Stopped && requested.abs_diff(local) > 1500 {
info!("[STATE] Position jump detected, seeking to {}ms (local={}ms)", requested, local);
player.send(PlayerCommand::Seek(requested));
track_ended = false;
// ACTION_TYPE_SEEK = 8
let action_msg = msg_renderer_action(8, Some(*position_ms));
ws_tx.send(Message::Binary(build_payload_frame(msg_id, &action_msg).into())).await?;
msg_id += 1;
}
current_position_ms = requested;
}
// 5. Always send state update (like reference implementation)
@@ -1118,6 +1162,7 @@ async fn run_connection(
track_id: current_track_id,
queue_item_id: current_queue_item_id,
duration_ms,
start_position_ms: 0,
});
current_buffer_state = 2; // OK(2)
info!("Restarted at format_id={}", format_id);