fix(27): populate backing track Redux state from native client

After opening a backing track file via native client:
1. Call SessionGetAllControlState(true) to get track info
2. Extract backing track data (id, rid, filename, shortFilename)
3. Dispatch to both Redux slices:
   - activeSessionSlice.addBackingTrack (for track sync)
   - mediaSlice.setBackingTracks (for session screen UI)

Also fixes syncTracksToServer calls that incorrectly passed jamClient
object instead of server.clientId.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Nuwan 2026-02-27 01:00:54 +05:30
parent e35163ec84
commit 2ea18d59ea
2 changed files with 63 additions and 17 deletions

View File

@ -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

View File

@ -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);
}