From 18375678a6a0c4340f6c52e747e5cb7c164ea207 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 3 Jan 2026 23:37:22 +0000 Subject: [PATCH] fix(effects): Sync channel config properly and fix effects not being applied Channel config fixes: - Use blocking write() instead of try_write() for set_channel_config - Sync channel config from self.config to processing_state at engine start - Add logging for channel config changes Effects fix: - Effects were only sent to native bridge on startup, not when changed - Add effects sync to native bridge in useTrackAudioSync when effects change --- native-bridge/src/audio/engine.rs | 28 ++++++++++++++++++++++++++-- src/hooks/useTrackAudioSync.ts | 6 ++++++ 2 files changed, 32 insertions(+), 2 deletions(-) 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);