Fix end-of-track handoff by sending NEXT action

This commit is contained in:
joren
2026-03-31 20:57:03 +02:00
parent 3a0d6e0240
commit 790eba8792

View File

@@ -367,6 +367,18 @@ fn quality_to_format_id(quality: u32) -> u32 {
} }
} }
/// RNDR_SRVR_RENDERER_ACTION (24): renderer reports a local user action.
/// ActionType: 0=UNKNOWN, 1=PREVIOUS, 2=NEXT, 3=REPEAT_OFF, 4=REPEAT_ONE, 5=REPEAT_ALL,
/// 6=SHUFFLE_OFF, 7=SHUFFLE_ON, 8=SEEK
fn msg_renderer_action(action: u64, seek_position: Option<u32>) -> Vec<u8> {
let mut payload = Vec::new();
if let Some(pos) = seek_position {
payload.extend(encode_field_varint(1, pos as u64)); // field 1: seek_position
}
payload.extend(encode_field_varint(2, action)); // field 2: action
build_qconnect_message(24, &payload)
}
/// RNDR_SRVR_VOLUME_CHANGED (25): renderer reports volume. /// RNDR_SRVR_VOLUME_CHANGED (25): renderer reports volume.
fn msg_volume_changed(volume: u64) -> Vec<u8> { fn msg_volume_changed(volume: u64) -> Vec<u8> {
let payload = encode_field_varint(1, volume); let payload = encode_field_varint(1, volume);
@@ -882,14 +894,19 @@ async fn run_connection(
&& has_seen_position_progress && has_seen_position_progress
&& elapsed_since_play > std::time::Duration::from_secs(3) && elapsed_since_play > std::time::Duration::from_secs(3)
{ {
// Track ended naturally — keep reporting PLAYING with position=duration
// so the server detects end-of-track and sends next track via SET_STATE
if !track_ended { if !track_ended {
info!("[TICK] Track ended naturally, reporting position=duration ({}ms)", current_duration_ms); // Track ended naturally — send final position then request next track
info!("[TICK] Track ended naturally, sending ACTION_TYPE_NEXT");
track_ended = true; track_ended = true;
current_position_ms = current_duration_ms; current_position_ms = current_duration_ms;
send_state!(ws_tx, msg_id);
// Tell server to advance to next track (ACTION_TYPE_NEXT = 2)
let action_msg = msg_renderer_action(2, None);
ws_tx.send(Message::Binary(build_payload_frame(msg_id, &action_msg).into())).await?;
msg_id += 1;
} }
send_state!(ws_tx, msg_id); // Don't spam — wait for server to send new SET_STATE
} else if status.state == PlayerState::Stopped { } else if status.state == PlayerState::Stopped {
debug!("[TICK] Player stopped but grace period (elapsed={:?}, progress={}), ignoring", debug!("[TICK] Player stopped but grace period (elapsed={:?}, progress={}), ignoring",
elapsed_since_play, has_seen_position_progress); elapsed_since_play, has_seen_position_progress);