mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 23:35:44 +00:00
diag(#1090/#1072): trace device-changed event into the frontend hang
The Rust reopen path returns cleanly (watcher keeps polling), so the UI hang lives in the frontend after audio:device-changed. Log the emitted payload (resumed null vs f64) and trace the bridge: event received → store state → before/after playTrack. Last surviving line localises the hang. TEMPORARY — revert before the real fix.
This commit is contained in:
@@ -93,6 +93,15 @@ pub(crate) async fn reopen_output_stream(
|
||||
// Falls back gracefully to the frontend path if conditions aren't met.
|
||||
let resumed = try_resume_after_device_change(app, &snapshot).await;
|
||||
|
||||
// [DIAG #1090 — TEMPORARY] What does Rust hand to the frontend? resumed=true
|
||||
// → null payload (frontend does nothing). resumed=false → f64 → frontend
|
||||
// calls playTrack. This tells us which frontend branch the hang follows.
|
||||
crate::app_eprintln!(
|
||||
"[psysonic] DIAG-1090 reopen returning: resumed={resumed} was_playing={} payload={}",
|
||||
snapshot.is_playing,
|
||||
if resumed { "null".to_string() } else { format!("{:?}", snapshot.current_time_secs) }
|
||||
);
|
||||
|
||||
match notify {
|
||||
ReopenNotify::DeviceChanged => {
|
||||
// null → Rust already resumed; frontend skips playTrack
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
import { useEffect } from 'react';
|
||||
import { listen } from '@tauri-apps/api/event';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { usePlayerStore } from '../../store/playerStore';
|
||||
import { useAuthStore } from '../../store/authStore';
|
||||
import { setSeekFallbackVisualTarget } from '../../store/seekFallbackState';
|
||||
|
||||
// [DIAG #1090 — TEMPORARY] Forward a marker to the Rust debug log (only when
|
||||
// Settings → Logging = Debug). Used to find where the UI hangs on device switch.
|
||||
const diag1090 = (message: string) => {
|
||||
void invoke('frontend_debug_log', { scope: 'diag1090', message }).catch(() => {});
|
||||
};
|
||||
|
||||
/** Audio output device lifecycle: device switches (Bluetooth headphones, USB
|
||||
* DAC, …) and pinned-device-unplugged fallbacks emitted by the Rust
|
||||
* device-watcher.
|
||||
@@ -17,11 +24,13 @@ export function useAudioDeviceBridge() {
|
||||
useEffect(() => {
|
||||
let unlisten: (() => void) | undefined;
|
||||
listen('audio:device-changed', (event) => {
|
||||
diag1090(`device-changed received payload=${JSON.stringify(event.payload)}`);
|
||||
// null payload = Rust handled internal replay; nothing to do here.
|
||||
if (event.payload === null) return;
|
||||
|
||||
const resumeAt = typeof event.payload === 'number' ? event.payload : 0;
|
||||
const { currentTrack, isPlaying, playTrack, resetAudioPause } = usePlayerStore.getState();
|
||||
diag1090(`state currentTrack=${!!currentTrack} isPlaying=${isPlaying} resumeAt=${resumeAt}`);
|
||||
if (!currentTrack) return;
|
||||
if (isPlaying) {
|
||||
if (resumeAt > 0.5 && currentTrack.duration > 0) {
|
||||
@@ -31,7 +40,9 @@ export function useAudioDeviceBridge() {
|
||||
setAtMs: Date.now(),
|
||||
});
|
||||
}
|
||||
diag1090('before playTrack');
|
||||
playTrack(currentTrack);
|
||||
diag1090('after playTrack (returned)');
|
||||
} else {
|
||||
// Paused: clear warm-pause flag so the next resume uses the cold path
|
||||
// (audio_play + seek) which creates a new Sink on the new device.
|
||||
|
||||
Reference in New Issue
Block a user