fix(qbz-slint): cold-start current track on play when no audio is loaded
Local toggle_play always called resume(), which fails with "cannot resume - no audio data available" when the player holds no loaded stream — e.g. a freshly materialized QConnect renderer queue whose cursor sits on a track that was never loaded. Detect the no-loaded-audio case via Player::has_loaded_audio() and load+play the current queue track instead of resuming. A normal pause keeps the stream loaded, so the pause/resume path is unchanged. cc
This commit is contained in:
2 files changed
+46
-10
No files matched your search
@@ -3012,11 +3012,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// renderer/local playback because the gate is `is_peer_renderer_active`.
|
||||
{
|
||||
let runtime = app_runtime.clone();
|
||||
let weak = window.as_weak();
|
||||
let handle = tokio_rt.handle().clone();
|
||||
window
|
||||
.global::<NowPlayingState>()
|
||||
.on_toggle_play(move || {
|
||||
let runtime = runtime.clone();
|
||||
let weak = weak.clone();
|
||||
let handle = handle.clone();
|
||||
handle.clone().spawn(async move {
|
||||
if let Some(svc) = qconnect_service::service() {
|
||||
@@ -3029,7 +3031,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
}
|
||||
}
|
||||
playback::toggle_play_pause(runtime, handle);
|
||||
playback::toggle_play_pause(runtime, weak, handle);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1868,16 +1868,50 @@ pub fn enqueue_local_tracks(
|
||||
}
|
||||
|
||||
/// Toggle play / pause on the live player.
|
||||
pub fn toggle_play_pause(runtime: Runtime, handle: tokio::runtime::Handle) {
|
||||
///
|
||||
/// Resume is only valid when the audio engine actually holds a loaded stream.
|
||||
/// When the player has NO loaded audio but the queue has a current track —
|
||||
/// e.g. a freshly materialized QConnect renderer queue whose cursor sits on a
|
||||
/// track that was never loaded, or a cold cursor after the queue ended — a
|
||||
/// bare `resume()` fails with "cannot resume - no audio data available" and the
|
||||
/// user sees a dead Play button. In that case LOAD and play the current queue
|
||||
/// track instead, so Play works from a cold cursor. A normal pause leaves the
|
||||
/// stream loaded (`has_loaded_audio` stays true), so the pause/resume path is
|
||||
/// unchanged.
|
||||
pub fn toggle_play_pause(
|
||||
runtime: Runtime,
|
||||
weak: slint::Weak<AppWindow>,
|
||||
handle: tokio::runtime::Handle,
|
||||
) {
|
||||
handle.spawn(async move {
|
||||
let playing = runtime.core().get_playback_state().is_playing;
|
||||
let result = if playing {
|
||||
runtime.core().pause()
|
||||
} else {
|
||||
runtime.core().resume()
|
||||
};
|
||||
if let Err(e) = result {
|
||||
log::error!("[qbz-slint] playback: toggle play/pause failed: {e}");
|
||||
if runtime.core().get_playback_state().is_playing {
|
||||
if let Err(e) = runtime.core().pause() {
|
||||
log::error!("[qbz-slint] playback: pause failed: {e}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Not playing: resume an existing stream, or cold-start the current
|
||||
// queue track when nothing is loaded.
|
||||
if runtime.core().player().has_loaded_audio() {
|
||||
if let Err(e) = runtime.core().resume() {
|
||||
log::error!("[qbz-slint] playback: resume failed: {e}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
match runtime.core().current_track().await {
|
||||
Some(track) => {
|
||||
log::info!(
|
||||
"[qbz-slint] playback: play with no loaded audio -> cold-starting current track {}",
|
||||
track.id
|
||||
);
|
||||
after_track_change(&runtime, &weak, track.id).await;
|
||||
refresh_sidebar(true);
|
||||
}
|
||||
None => {
|
||||
log::info!(
|
||||
"[qbz-slint] playback: toggle play ignored (no loaded audio, empty queue)"
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user