Fix end-of-track handoff by sending NEXT action
This commit is contained in:
@@ -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);
|
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;
|
||||||
|
}
|
||||||
|
// 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);
|
||||||
|
|||||||
Reference in New Issue
Block a user