fix(qbzd): prevent orchestrator race on play-track + QConnect debug logging
play-track/play-album set skip_auto_advance flag before stop() to prevent the orchestrator from auto-advancing during the download window. This fixes the 'track starts then immediately stops' bug. Added QConnect event type logging to debug why SESSION_STATE never triggers the deferred renderer join. cc
This commit is contained in:
3 files changed
+18
-1
No files matched your search
@@ -48,12 +48,18 @@ pub async fn play_track(
|
||||
|
||||
log::info!("[qbzd/play] Playing track {} (quality: {:?})", req.track_id, quality);
|
||||
|
||||
// Signal orchestrator to not auto-advance during download
|
||||
daemon.skip_auto_advance.store(true, std::sync::atomic::Ordering::Release);
|
||||
|
||||
// Stop current playback
|
||||
let _ = daemon.core.stop();
|
||||
|
||||
// Download audio
|
||||
let audio_data = crate::daemon::download_track(&daemon, req.track_id).await?;
|
||||
|
||||
// Clear the skip flag
|
||||
daemon.skip_auto_advance.store(false, std::sync::atomic::Ordering::Release);
|
||||
|
||||
// Feed to player
|
||||
daemon.core.player()
|
||||
.play_data(audio_data, req.track_id)
|
||||
@@ -122,10 +128,14 @@ pub async fn play_album(
|
||||
_ => qbz_models::Quality::HiRes,
|
||||
};
|
||||
|
||||
// Signal orchestrator to not auto-advance during download
|
||||
daemon.skip_auto_advance.store(true, std::sync::atomic::Ordering::Release);
|
||||
|
||||
// Stop current playback
|
||||
let _ = daemon.core.stop();
|
||||
|
||||
let audio_data = crate::daemon::download_track(&daemon, first_track_id).await?;
|
||||
daemon.skip_auto_advance.store(false, std::sync::atomic::Ordering::Release);
|
||||
daemon.core.player().play_data(audio_data, first_track_id)
|
||||
.map_err(|e| format!("Player error: {}", e))?;
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ pub struct DaemonCore {
|
||||
pub event_bus: broadcast::Sender<DaemonEvent>,
|
||||
/// Per-user state, populated after login + session activation
|
||||
pub user: RwLock<Option<UserSession>>,
|
||||
/// Flag to prevent orchestrator auto-advance during explicit play commands
|
||||
pub skip_auto_advance: std::sync::atomic::AtomicBool,
|
||||
}
|
||||
|
||||
/// Run the daemon main loop.
|
||||
@@ -75,6 +77,7 @@ pub async fn run(mut config: DaemonConfig) -> Result<(), String> {
|
||||
audio_cache,
|
||||
event_bus: event_tx.clone(),
|
||||
user: RwLock::new(None),
|
||||
skip_auto_advance: std::sync::atomic::AtomicBool::new(false),
|
||||
});
|
||||
|
||||
// Try auto-login from saved OAuth token
|
||||
@@ -308,7 +311,7 @@ fn spawn_playback_orchestrator(daemon: Arc<DaemonCore>) {
|
||||
// This handles the case when gapless wasn't available or failed.
|
||||
let track_ended = was_playing && !is_playing && track_id == 0 && last_track_id != 0;
|
||||
|
||||
if track_ended {
|
||||
if track_ended && !daemon.skip_auto_advance.load(std::sync::atomic::Ordering::Acquire) {
|
||||
let queue_state = daemon.core.get_queue_state().await;
|
||||
let repeat_mode = queue_state.repeat;
|
||||
|
||||
|
||||
@@ -204,9 +204,13 @@ async fn run_event_loop(app: &Arc<App>, device_name: &str) {
|
||||
loop {
|
||||
match rx.recv().await {
|
||||
Ok(event) => {
|
||||
// Log event type for debugging
|
||||
log::debug!("[qbzd/qconnect] Transport event: {:?}", std::mem::discriminant(&event));
|
||||
|
||||
// Wait for SESSION_STATE to do deferred renderer join
|
||||
if !renderer_joined {
|
||||
if let qconnect_transport_ws::TransportEvent::InboundQueueServerEvent(ref evt) = event {
|
||||
log::info!("[qbzd/qconnect] Queue server event: {}", evt.message_type());
|
||||
if evt.message_type() == "MESSAGE_TYPE_SRVR_CTRL_SESSION_STATE" {
|
||||
if let Some(session_uuid) = evt.payload.get("session_uuid").and_then(|v| v.as_str()) {
|
||||
renderer_joined = true;
|
||||
|
||||
Reference in new issue
Block a user