diff --git a/jam-ui/src/hooks/useMediaActions.js b/jam-ui/src/hooks/useMediaActions.js index 91a9634a8..03f4ddc7b 100644 --- a/jam-ui/src/hooks/useMediaActions.js +++ b/jam-ui/src/hooks/useMediaActions.js @@ -5,7 +5,8 @@ import { loadJamTrack as loadJamTrackThunk, closeMedia as closeMediaThunk, clearJamTrackState, - updateJamTrackState + updateJamTrackState, + setBackingTracks } from '../store/features/mediaSlice'; import { setMetronome, @@ -21,7 +22,10 @@ import { setCreatingMixdown, setCreateMixdownErrors } from '../store/features/sessionUISlice'; -import { selectSessionId } from '../store/features/activeSessionSlice'; +import { + selectSessionId, + addBackingTrack as addBackingTrackToActiveSession +} from '../store/features/activeSessionSlice'; import { useJamServerContext } from '../context/JamServerContext'; import { syncTracksToServer } from '../services/trackSyncService'; @@ -32,7 +36,7 @@ import { syncTracksToServer } from '../services/trackSyncService'; const useMediaActions = () => { const dispatch = useDispatch(); const sessionId = useSelector(selectSessionId); - const { jamClient, subscribe, unsubscribe } = useJamServerContext(); + const { jamClient, subscribe, unsubscribe, server } = useJamServerContext(); // Create jamServer object with subscribe/unsubscribe for thunks const jamServer = useMemo(() => ({ @@ -46,7 +50,23 @@ const useMediaActions = () => { */ const openBackingTrack = useCallback(async (file) => { try { - await dispatch(openBackingTrackThunk({ file, jamClient })).unwrap(); + const result = await dispatch(openBackingTrackThunk({ file, jamClient })).unwrap(); + + // Update backing tracks in both Redux slices + // 1. activeSession slice (for syncTracksToServer) + // 2. media slice (for session screen UI) + if (result.backingTracks && result.backingTracks.length > 0) { + console.log('[openBackingTrack] Updating Redux with backing tracks:', result.backingTracks); + + // Add each backing track to activeSession (for track sync) + for (const bt of result.backingTracks) { + dispatch(addBackingTrackToActiveSession(bt)); + } + + // Set backing tracks in media slice (for UI display) + // Format for UI: { shortFilename, filename, mixers (will be added by mixer system) } + dispatch(setBackingTracks(result.backingTracks)); + } // Update media summary dispatch(updateMediaSummary({ @@ -55,15 +75,15 @@ const useMediaActions = () => { })); // Sync tracks to server after opening backing track - if (sessionId && jamClient) { + if (sessionId && server?.clientId) { console.log('[Track Sync] Backing track opened, syncing tracks'); - dispatch(syncTracksToServer(sessionId, jamClient)); + dispatch(syncTracksToServer(sessionId, server.clientId)); } } catch (error) { console.error('Error opening backing track:', error); throw error; } - }, [dispatch, jamClient, sessionId]); + }, [dispatch, jamClient, sessionId, server]); /** * Close all media (backing tracks, jam tracks, recordings, metronome) @@ -108,9 +128,9 @@ const useMediaActions = () => { })); // Sync tracks to server after opening metronome - if (sessionId && jamClient) { + if (sessionId && server?.clientId) { console.log('[Track Sync] Metronome opened, syncing tracks'); - dispatch(syncTracksToServer(sessionId, jamClient)); + dispatch(syncTracksToServer(sessionId, server.clientId)); } return result; @@ -118,7 +138,7 @@ const useMediaActions = () => { console.error('Error opening metronome:', error); throw error; } - }, [dispatch, jamClient, sessionId]); + }, [dispatch, jamClient, sessionId, server]); /** * Close the metronome @@ -134,15 +154,15 @@ const useMediaActions = () => { })); // Sync tracks to server after closing metronome - if (sessionId && jamClient) { + if (sessionId && server?.clientId) { console.log('[Track Sync] Metronome closed, syncing tracks'); - dispatch(syncTracksToServer(sessionId, jamClient)); + dispatch(syncTracksToServer(sessionId, server.clientId)); } } catch (error) { console.error('Error closing metronome:', error); throw error; } - }, [dispatch, jamClient, sessionId]); + }, [dispatch, jamClient, sessionId, server]); /** * Load and play a JamTrack @@ -159,15 +179,15 @@ const useMediaActions = () => { })); // Sync tracks to server after opening jam track - if (sessionId && jamClient) { + if (sessionId && server?.clientId) { console.log('[Track Sync] Jam track opened, syncing tracks'); - dispatch(syncTracksToServer(sessionId, jamClient)); + dispatch(syncTracksToServer(sessionId, server.clientId)); } } catch (error) { console.error('Error loading jam track:', error); throw error; } - }, [dispatch, jamClient, jamServer, sessionId]); + }, [dispatch, jamClient, jamServer, sessionId, server]); /** * Stop and close the currently playing JamTrack diff --git a/jam-ui/src/store/features/mediaSlice.js b/jam-ui/src/store/features/mediaSlice.js index 33c1d9780..6c5405ed7 100644 --- a/jam-ui/src/store/features/mediaSlice.js +++ b/jam-ui/src/store/features/mediaSlice.js @@ -1,13 +1,39 @@ import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; import { enqueueMixdown } from '../../helpers/rest'; +// Channel group IDs for track filtering +const MEDIA_TRACK_GROUP = 8; // ChannelGroupIds.MediaTrackGroup + // Async thunks for media actions export const openBackingTrack = createAsyncThunk( 'media/openBackingTrack', async ({ file, jamClient }, { rejectWithValue }) => { try { + // Open the backing track file via native client await jamClient.SessionOpenBackingTrackFile(file, false); - return { file }; + + // Get track info from native client to populate Redux state + const allTracks = await jamClient.SessionGetAllControlState(true); + + // Extract backing track data (same pattern as useTrackHelpers.getBackingTracks) + const backingTracks = []; + for (const track of allTracks) { + if (track.group_id === MEDIA_TRACK_GROUP && + track.media_type === 'BackingTrack' && + !track.managed) { + backingTracks.push({ + id: track.persisted_track_id, + rid: track.rid, + filename: track.filename, + // Compute shortFilename from full path + shortFilename: track.filename ? track.filename.split('/').pop().split('\\').pop() : 'Audio File' + }); + } + } + + console.log('[openBackingTrack] Got backing tracks from native client:', backingTracks); + + return { file, backingTracks }; } catch (error) { return rejectWithValue(error.message); }