fix(05-01): fix loadJamTrack fqId bug and extend mediaSlice state
- Fix critical bug: JamTrackPlay now uses fqId instead of jamTrack.id - Move fqId construction outside conditional for consistent availability - Extend jamTrackState with 7 fields (isPlaying, isPaused, position, duration, etc) - Replace downloadingJamTrack with full downloadState (8 fields, 6-state machine) - Add 3 new reducers: setJamTrackState, setDownloadState, clearDownloadState - Update clearJamTrackState and clearAllMedia to reset to proper structures - Update loadJamTrack extraReducers to use downloadState - Update selectors: remove selectDownloadingJamTrack, add selectDownloadState Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
cc32abcaba
commit
bb74c50462
|
|
@ -17,16 +17,18 @@ export const loadJamTrack = createAsyncThunk(
|
|||
'media/loadJamTrack',
|
||||
async ({ jamTrack, jamClient }, { rejectWithValue }) => {
|
||||
try {
|
||||
// Build fqId for all JamTrack calls (format: {jamTrackId}-{sampleRate})
|
||||
const sampleRate = await jamClient.GetSampleRate();
|
||||
const sampleRateForFilename = sampleRate === 48 ? '48' : '44';
|
||||
const fqId = `${jamTrack.id}-${sampleRateForFilename}`;
|
||||
|
||||
// Load JMep data if available (matches MediaContext:163-170 logic)
|
||||
if (jamTrack.jmep) {
|
||||
const sampleRate = await jamClient.GetSampleRate();
|
||||
const sampleRateForFilename = sampleRate === 48 ? '48' : '44';
|
||||
const fqId = `${jamTrack.id}-${sampleRateForFilename}`;
|
||||
await jamClient.JamTrackLoadJmep(fqId, jamTrack.jmep);
|
||||
}
|
||||
|
||||
// Play/load the jamtrack
|
||||
const result = await jamClient.JamTrackPlay(jamTrack.id);
|
||||
const result = await jamClient.JamTrackPlay(fqId);
|
||||
|
||||
if (!result) {
|
||||
throw new Error('Unable to open JamTrack');
|
||||
|
|
@ -59,8 +61,27 @@ const initialState = {
|
|||
recordedTracks: [], // [{ recordingName, isOpener, userName, instrumentIcon, track, mixers }]
|
||||
|
||||
// JamTrack state (real-time playback state from native client)
|
||||
jamTrackState: {}, // Real-time jamTrack playback state from WebSocket JAM_TRACK_CHANGES
|
||||
downloadingJamTrack: false,
|
||||
jamTrackState: {
|
||||
isPlaying: false,
|
||||
isPaused: false,
|
||||
currentPositionMs: 0,
|
||||
durationMs: 0,
|
||||
selectedMixdownId: null,
|
||||
playbackMode: null, // 'master' | 'custom-mix' | 'stem'
|
||||
lastUpdate: null
|
||||
},
|
||||
|
||||
// Download/sync state machine
|
||||
downloadState: {
|
||||
jamTrackId: null,
|
||||
mixdownId: null,
|
||||
fqId: null,
|
||||
state: 'idle', // 'idle' | 'checking' | 'downloading' | 'keying' | 'synchronized' | 'error'
|
||||
progress: 0,
|
||||
currentStep: 0,
|
||||
totalSteps: 0,
|
||||
error: null
|
||||
},
|
||||
|
||||
// Loading states for async operations
|
||||
loading: {
|
||||
|
|
@ -94,8 +115,38 @@ export const mediaSlice = createSlice({
|
|||
state.jamTrackState = { ...state.jamTrackState, ...action.payload };
|
||||
},
|
||||
|
||||
setJamTrackState: (state, action) => {
|
||||
state.jamTrackState = action.payload;
|
||||
},
|
||||
|
||||
clearJamTrackState: (state) => {
|
||||
state.jamTrackState = {};
|
||||
state.jamTrackState = {
|
||||
isPlaying: false,
|
||||
isPaused: false,
|
||||
currentPositionMs: 0,
|
||||
durationMs: 0,
|
||||
selectedMixdownId: null,
|
||||
playbackMode: null,
|
||||
lastUpdate: null
|
||||
};
|
||||
},
|
||||
|
||||
// Download state management
|
||||
setDownloadState: (state, action) => {
|
||||
state.downloadState = { ...state.downloadState, ...action.payload };
|
||||
},
|
||||
|
||||
clearDownloadState: (state) => {
|
||||
state.downloadState = {
|
||||
jamTrackId: null,
|
||||
mixdownId: null,
|
||||
fqId: null,
|
||||
state: 'idle',
|
||||
progress: 0,
|
||||
currentStep: 0,
|
||||
totalSteps: 0,
|
||||
error: null
|
||||
};
|
||||
},
|
||||
|
||||
// Clear all media (called on session end or media close)
|
||||
|
|
@ -103,8 +154,25 @@ export const mediaSlice = createSlice({
|
|||
state.backingTracks = [];
|
||||
state.jamTracks = [];
|
||||
state.recordedTracks = [];
|
||||
state.jamTrackState = {};
|
||||
state.downloadingJamTrack = false;
|
||||
state.jamTrackState = {
|
||||
isPlaying: false,
|
||||
isPaused: false,
|
||||
currentPositionMs: 0,
|
||||
durationMs: 0,
|
||||
selectedMixdownId: null,
|
||||
playbackMode: null,
|
||||
lastUpdate: null
|
||||
};
|
||||
state.downloadState = {
|
||||
jamTrackId: null,
|
||||
mixdownId: null,
|
||||
fqId: null,
|
||||
state: 'idle',
|
||||
progress: 0,
|
||||
currentStep: 0,
|
||||
totalSteps: 0,
|
||||
error: null
|
||||
};
|
||||
state.error = null;
|
||||
}
|
||||
},
|
||||
|
|
@ -129,17 +197,18 @@ export const mediaSlice = createSlice({
|
|||
// Load jam track
|
||||
.addCase(loadJamTrack.pending, (state) => {
|
||||
state.loading.jamTrack = true;
|
||||
state.downloadingJamTrack = true;
|
||||
state.downloadState.state = 'checking';
|
||||
state.error = null;
|
||||
})
|
||||
.addCase(loadJamTrack.fulfilled, (state) => {
|
||||
state.loading.jamTrack = false;
|
||||
state.downloadingJamTrack = false;
|
||||
state.downloadState.state = 'synchronized';
|
||||
// Note: jamTracks array updated by MIXER_CHANGES WebSocket message
|
||||
})
|
||||
.addCase(loadJamTrack.rejected, (state, action) => {
|
||||
state.loading.jamTrack = false;
|
||||
state.downloadingJamTrack = false;
|
||||
state.downloadState.state = 'error';
|
||||
state.downloadState.error = { message: action.payload };
|
||||
state.error = action.payload;
|
||||
})
|
||||
|
||||
|
|
@ -153,7 +222,25 @@ export const mediaSlice = createSlice({
|
|||
state.backingTracks = [];
|
||||
state.jamTracks = [];
|
||||
state.recordedTracks = [];
|
||||
state.jamTrackState = {};
|
||||
state.jamTrackState = {
|
||||
isPlaying: false,
|
||||
isPaused: false,
|
||||
currentPositionMs: 0,
|
||||
durationMs: 0,
|
||||
selectedMixdownId: null,
|
||||
playbackMode: null,
|
||||
lastUpdate: null
|
||||
};
|
||||
state.downloadState = {
|
||||
jamTrackId: null,
|
||||
mixdownId: null,
|
||||
fqId: null,
|
||||
state: 'idle',
|
||||
progress: 0,
|
||||
currentStep: 0,
|
||||
totalSteps: 0,
|
||||
error: null
|
||||
};
|
||||
})
|
||||
.addCase(closeMedia.rejected, (state, action) => {
|
||||
state.loading.closing = false;
|
||||
|
|
@ -167,7 +254,10 @@ export const {
|
|||
setJamTracks,
|
||||
setRecordedTracks,
|
||||
updateJamTrackState,
|
||||
setJamTrackState,
|
||||
clearJamTrackState,
|
||||
setDownloadState,
|
||||
clearDownloadState,
|
||||
clearAllMedia
|
||||
} = mediaSlice.actions;
|
||||
|
||||
|
|
@ -178,6 +268,6 @@ export const selectBackingTracks = (state) => state.media.backingTracks;
|
|||
export const selectJamTracks = (state) => state.media.jamTracks;
|
||||
export const selectRecordedTracks = (state) => state.media.recordedTracks;
|
||||
export const selectJamTrackState = (state) => state.media.jamTrackState;
|
||||
export const selectDownloadingJamTrack = (state) => state.media.downloadingJamTrack;
|
||||
export const selectDownloadState = (state) => state.media.downloadState;
|
||||
export const selectMediaLoading = (state) => state.media.loading;
|
||||
export const selectMediaError = (state) => state.media.error;
|
||||
|
|
|
|||
Loading…
Reference in New Issue