diff --git a/native-bridge/src/audio/engine.rs b/native-bridge/src/audio/engine.rs index e0bef763..08b67a2c 100644 --- a/native-bridge/src/audio/engine.rs +++ b/native-bridge/src/audio/engine.rs @@ -306,10 +306,22 @@ impl AudioEngine { return Ok(()); } + info!("Setting channel config: {:?}", config); self.config.channel_config = config.clone(); - if let Ok(mut state) = self.processing_state.write() { - state.channel_config = config; + + // CRITICAL: Must update processing_state - this is what the audio callback reads + // Use blocking write to ensure the config is applied + match self.processing_state.write() { + Ok(mut state) => { + state.channel_config = config; + info!("Channel config updated in processing_state"); + } + Err(e) => { + // This should never happen in practice, but log if it does + tracing::error!("Failed to acquire write lock for channel config: {:?}", e); + } } + if self.is_running.load(Ordering::SeqCst) { self.stop()?; self.start()?; @@ -589,6 +601,18 @@ impl AudioEngine { return Ok(()); } + // CRITICAL: Sync channel config from self.config to processing_state before starting + // This ensures the audio callback uses the correct config from the first frame + if let Ok(mut state) = self.processing_state.write() { + if state.channel_config != self.config.channel_config { + info!( + "Syncing channel config at start: {:?} -> {:?}", + state.channel_config, self.config.channel_config + ); + state.channel_config = self.config.channel_config.clone(); + } + } + // Create ring buffers let local_ring = HeapRb::::new(LOCAL_RING_BUFFER_SIZE); let (local_prod, local_cons) = local_ring.split(); diff --git a/src/hooks/useTrackAudioSync.ts b/src/hooks/useTrackAudioSync.ts index e59defaa..7496bef8 100644 --- a/src/hooks/useTrackAudioSync.ts +++ b/src/hooks/useTrackAudioSync.ts @@ -230,6 +230,12 @@ export function useTrackAudioSync(currentUserId: string | undefined) { // Note: Channel config is now handled at the global level via setChannelConfig() // Native bridge uses single-track audio capture; multi-track is handled in browser + + // Sync effects to native bridge when changed + if (currentState.effects && (!lastState || lastState.effects !== currentState.effects)) { + console.log('[useTrackAudioSync] Syncing effects to native bridge for track:', track.id); + nativeBridge.updateEffects(track.id, currentState.effects); + } } lastSyncRef.current.set(track.id, currentState);