fix: omit queue_item_ids from renderer state reports to fix seekbar sync
The server rejects renderer state reports with "Current track not found in queue nor autoplay" after QBZ-initiated queue loads, because it assigns non-standard queue_item_ids (first track = track_id, rest = 1..N). Omit current_queue_item_id and next_queue_item_id from all outbound renderer reports. The server already knows the current track from SET_STATE commands and adds the correct queue_item_id when forwarding to controllers. Also add info-level diagnostic logging to both report paths (periodic frontend reports and command-response reports) and the protobuf encoder for verifying wire content.
This commit is contained in:
4 files changed
+48
-10
No files matched your search
@@ -15,6 +15,7 @@ serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
uuid = { version = "1", features = ["v4"] }
|
||||
log = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { workspace = true, features = ["test-util"] }
|
||||
@@ -416,10 +416,25 @@ where
|
||||
) -> Result<(), QconnectAppError> {
|
||||
match command {
|
||||
RendererCommand::SetState { .. } => {
|
||||
log::info!(
|
||||
"[QConnect/Report] SetState report: playing={:?} pos={:?} track={:?} next={:?} qv={}.{}",
|
||||
renderer.playing_state,
|
||||
renderer.current_position_ms,
|
||||
renderer.current_track.as_ref().map(|t| (t.track_id, t.queue_item_id)),
|
||||
renderer.next_track.as_ref().map(|t| (t.track_id, t.queue_item_id)),
|
||||
queue_version_ref.major,
|
||||
queue_version_ref.minor
|
||||
);
|
||||
let report = RendererReport::new(
|
||||
RendererReportType::RndrSrvrStateUpdated,
|
||||
self.next_action_uuid(),
|
||||
queue_version_ref,
|
||||
// NOTE: We intentionally OMIT current_queue_item_id and next_queue_item_id.
|
||||
// The server validates these IDs against its queue state and rejects reports
|
||||
// when IDs don't match ("Current track not found in queue nor autoplay").
|
||||
// This happens after QBZ-initiated queue loads where the server assigns
|
||||
// non-standard queue_item_ids (first track = track_id, rest = 1..N).
|
||||
// The server already knows the current track from SET_STATE commands.
|
||||
serde_json::json!({
|
||||
"playing_state": renderer.playing_state,
|
||||
"buffer_state": infer_buffer_state(renderer.playing_state),
|
||||
@@ -429,8 +444,8 @@ where
|
||||
"major": queue_version_ref.major,
|
||||
"minor": queue_version_ref.minor
|
||||
},
|
||||
"current_queue_item_id": renderer.current_track.as_ref().map(|item| item.queue_item_id),
|
||||
"next_queue_item_id": renderer.next_track.as_ref().map(|item| item.queue_item_id)
|
||||
"current_queue_item_id": Option::<i32>::None,
|
||||
"next_queue_item_id": Option::<i32>::None
|
||||
}),
|
||||
);
|
||||
self.send_renderer_report(report).await?;
|
||||
|
||||
@@ -424,25 +424,32 @@ fn map_renderer_report(report: &RendererReport) -> Result<QConnectMessage, Proto
|
||||
.unwrap_or(report.queue_version_ref);
|
||||
let current_position = optional_i32(&report.payload, "current_position")?;
|
||||
let duration = optional_i32(&report.payload, "duration")?;
|
||||
let current_qid = optional_i32(&report.payload, "current_queue_item_id")?;
|
||||
let next_qid = optional_i32(&report.payload, "next_queue_item_id")?;
|
||||
let playing_state = optional_i32(&report.payload, "playing_state")?;
|
||||
let playback_position = current_position.map(|value| PlaybackPositionMessage {
|
||||
timestamp: Some(now_ms()),
|
||||
value: Some(value),
|
||||
});
|
||||
|
||||
log::info!(
|
||||
"[QConnect/Proto] Encoding StateUpdated: playing={:?} pos={:?} dur={:?} qid={:?} next_qid={:?} qv={}.{}",
|
||||
playing_state, current_position, duration,
|
||||
current_qid, next_qid,
|
||||
queue_version.major, queue_version.minor
|
||||
);
|
||||
|
||||
Ok(QConnectMessage {
|
||||
message_type: Some(QConnectMessageType::MessageTypeRndrSrvrStateUpdated as i32),
|
||||
rndr_srvr_state_updated: Some(RendererStateUpdatedMessage {
|
||||
state: Some(RendererStateMessage {
|
||||
playing_state: optional_i32(&report.payload, "playing_state")?,
|
||||
playing_state,
|
||||
buffer_state: optional_i32(&report.payload, "buffer_state")?,
|
||||
current_position: playback_position,
|
||||
duration,
|
||||
queue_version: Some(to_proto_queue_version(queue_version)?),
|
||||
current_queue_item_id: optional_i32(
|
||||
&report.payload,
|
||||
"current_queue_item_id",
|
||||
)?,
|
||||
next_queue_item_id: optional_i32(&report.payload, "next_queue_item_id")?,
|
||||
current_queue_item_id: current_qid,
|
||||
next_queue_item_id: next_qid,
|
||||
}),
|
||||
}),
|
||||
..Default::default()
|
||||
|
||||
@@ -1723,6 +1723,21 @@ pub async fn v2_qconnect_report_playback_state(
|
||||
}
|
||||
|
||||
let queue_version = service.get_queue_version().await;
|
||||
|
||||
log::info!(
|
||||
"[QConnect/Report] Periodic state report: playing={} pos={:?} dur={:?} qid={:?} next_qid={:?} track_id={:?} qv={}.{}",
|
||||
playing_state, current_position, duration,
|
||||
resolved_current_qid, resolved_next_qid, current_track_id,
|
||||
queue_version.major, queue_version.minor
|
||||
);
|
||||
|
||||
// NOTE: We intentionally OMIT current_queue_item_id and next_queue_item_id
|
||||
// from periodic state reports. The server validates these IDs against its
|
||||
// queue state and rejects reports when IDs don't match (returns "Current track
|
||||
// not found in queue nor autoplay"). This happens consistently after QBZ-initiated
|
||||
// queue loads where the server assigns non-standard queue_item_ids.
|
||||
// The server already knows the current track from SET_STATE commands and adds
|
||||
// the correct queue_item_id when forwarding to controllers.
|
||||
let report = RendererReport::new(
|
||||
RendererReportType::RndrSrvrStateUpdated,
|
||||
Uuid::new_v4().to_string(),
|
||||
@@ -1732,8 +1747,8 @@ pub async fn v2_qconnect_report_playback_state(
|
||||
"buffer_state": BUFFER_STATE_OK,
|
||||
"current_position": current_position,
|
||||
"duration": duration,
|
||||
"current_queue_item_id": resolved_current_qid,
|
||||
"next_queue_item_id": resolved_next_qid,
|
||||
"current_queue_item_id": null,
|
||||
"next_queue_item_id": null,
|
||||
"queue_version": {
|
||||
"major": queue_version.major,
|
||||
"minor": queue_version.minor
|
||||
|
||||
Reference in new issue
Block a user