From 9d9fd86c0463f8a512fea804b400772addafbf14 Mon Sep 17 00:00:00 2001 From: Nuwan Date: Wed, 14 Jan 2026 19:30:42 +0530 Subject: [PATCH] fix(03-03): verify playback state and add loop diagnostics Race condition fix: - After SessionStartPlay, verify actual playback state - Add 100ms delay to let native client update - Check isSessionTrackPlaying() before setting state - Prevents "double click" issue where component thinks it's playing but isn't Loop diagnostics: - Add [LOOP] logging to track loop changes - Add [POLLING] logging when track reaches end - Log whether loop is enabled and native client behavior - Help diagnose why loop not repeating Co-Authored-By: Claude Sonnet 4.5 --- .../client/JKSessionBackingTrackPlayer.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/jam-ui/src/components/client/JKSessionBackingTrackPlayer.js b/jam-ui/src/components/client/JKSessionBackingTrackPlayer.js index 5989aa4c0..3ebdfe6c3 100644 --- a/jam-ui/src/components/client/JKSessionBackingTrackPlayer.js +++ b/jam-ui/src/components/client/JKSessionBackingTrackPlayer.js @@ -181,8 +181,10 @@ const JKSessionBackingTrackPlayer = ({ // Check if track reached the end if (validPosition >= validDuration && validDuration > 0) { + console.log('[POLLING] Track reached end, isLooping:', isLooping); // If loop is enabled, don't interfere - let native client handle loop if (!isLooping) { + console.log('[POLLING] Not looping, stopping and resetting'); // Stop playback and reset to beginning for clean state await jamClient.SessionStopPlay(); setIsPlaying(false); @@ -193,6 +195,7 @@ const JKSessionBackingTrackPlayer = ({ return; } // If looping, just continue polling - native client will loop + console.log('[POLLING] Looping enabled, letting native client handle loop'); } // Only update state if values actually changed (lazy updates) @@ -307,8 +310,14 @@ const JKSessionBackingTrackPlayer = ({ // Play (1 = normal playback mode) console.log('[PLAY] Calling SessionStartPlay'); await jamClient.SessionStartPlay(1); - setIsPlaying(true); - console.log('[PLAY] Playback started successfully'); + + // Verify playback actually started (small delay to let native client update) + await new Promise(resolve => setTimeout(resolve, 100)); + const actuallyPlaying = await jamClient.isSessionTrackPlaying(); + console.log('[PLAY] After SessionStartPlay, actuallyPlaying:', actuallyPlaying); + + setIsPlaying(actuallyPlaying); + console.log('[PLAY] Playback started, state set to:', actuallyPlaying); } } catch (error) { handleError('playback', 'Failed to start playback', error); @@ -408,6 +417,7 @@ const JKSessionBackingTrackPlayer = ({ const handleLoopChange = useCallback(async (e) => { const shouldLoop = e.target.checked; const previousLoop = isLooping; + console.log('[LOOP] Loop change requested:', shouldLoop); setIsLooping(shouldLoop); try { @@ -420,14 +430,18 @@ const JKSessionBackingTrackPlayer = ({ // Set loop state using SessionSetBackingTrackFileLoop // This requires the file path and loop boolean const trackPath = getBackingTrackPath(backingTrack); + console.log('[LOOP] Track path:', trackPath); if (!trackPath) { handleError('playback', 'No backing track available for loop change', null); setIsLooping(previousLoop); // Revert checkbox return; } + console.log('[LOOP] Calling SessionSetBackingTrackFileLoop with path:', trackPath, 'shouldLoop:', shouldLoop); await jamClient.SessionSetBackingTrackFileLoop(trackPath, shouldLoop); + console.log('[LOOP] Loop set successfully'); } catch (error) { + console.error('[LOOP] Failed to set loop:', error); handleError('playback', 'Failed to toggle loop', error); setIsLooping(previousLoop); // Revert checkbox on error }