diff --git a/native-bridge/src/audio/engine.rs b/native-bridge/src/audio/engine.rs index ee581ce7..e0bef763 100644 --- a/native-bridge/src/audio/engine.rs +++ b/native-bridge/src/audio/engine.rs @@ -928,13 +928,17 @@ impl AudioEngine { // NO LOGGING IN THIS FUNCTION - logging allocates memory which kills ASIO // Get channel config + // CRITICAL: Default to mono (is_stereo=false) if config cannot be read + // This ensures mono input sounds centered rather than panned left/right let (left_ch, right_ch, is_stereo) = if let Ok(state) = processing_state.try_read() { let left = state.channel_config.left_channel as usize; let right = state.channel_config.right_channel.unwrap_or(1) as usize; let stereo = state.channel_config.channel_count == 2; (left, right, stereo) } else { - (0, 1, true) + // Default to mono mode (channel 0 duplicated to both L/R = centered) + // This is safer than stereo which could cause panning issues + (0, 0, false) }; // Clear and reuse the pre-allocated stereo buffer (no allocation!) diff --git a/native-bridge/src/effects/eq.rs b/native-bridge/src/effects/eq.rs index 3199620f..855accba 100644 --- a/native-bridge/src/effects/eq.rs +++ b/native-bridge/src/effects/eq.rs @@ -47,7 +47,7 @@ impl Eq { let filter_type = match band_settings.band_type { EqBandType::Lowshelf => BiquadType::LowShelf, - EqBandType::Peak => BiquadType::Peak, + EqBandType::Peak | EqBandType::Peaking => BiquadType::Peak, EqBandType::Highshelf => BiquadType::HighShelf, }; diff --git a/native-bridge/src/effects/types.rs b/native-bridge/src/effects/types.rs index d5e75b2f..2b7089c1 100644 --- a/native-bridge/src/effects/types.rs +++ b/native-bridge/src/effects/types.rs @@ -1509,7 +1509,7 @@ pub struct MultibandCompressorSettings { fn default_mb_low() -> f32 { 200.0 } fn default_mb_high() -> f32 { 2000.0 } -#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct CompressorBand { #[serde(default = "default_true")] diff --git a/src/hooks/useNativeBridge.ts b/src/hooks/useNativeBridge.ts index ba9580e4..c31c441e 100644 --- a/src/hooks/useNativeBridge.ts +++ b/src/hooks/useNativeBridge.ts @@ -98,6 +98,9 @@ export function useNativeBridge() { // Use refs to track initialization const initialized = useRef(false); + // Ref to hold startAudio function for auto-start + const startAudioRef = useRef<(() => Promise) | null>(null); + // Single useEffect for setup - runs once on mount useEffect(() => { if (initialized.current) return; @@ -247,6 +250,49 @@ export function useNativeBridge() { }; }, []); // Empty dependency array - run once + // Auto-start native bridge when room is connected and bridge is preferred + // This ensures users don't have to manually start audio after joining a room + useEffect(() => { + // Subscribe to room store for connection changes + const unsubscribeRoom = useRoomStore.subscribe((roomState) => { + const bridgeState = useBridgeAudioStore.getState(); + + // Check if we should auto-start: room connected + bridge connected + bridge preferred + not already running + if ( + roomState.isConnected && + bridgeState.isConnected && + bridgeState.preferNativeBridge && + !bridgeState.isRunning + ) { + console.log('[useNativeBridge] Room connected with bridge preferred, auto-starting audio...'); + // Use a small delay to ensure all other initialization has completed + setTimeout(async () => { + // Re-check conditions in case they changed + const latestBridge = useBridgeAudioStore.getState(); + const latestRoom = useRoomStore.getState(); + if ( + latestRoom.isConnected && + latestBridge.isConnected && + latestBridge.preferNativeBridge && + !latestBridge.isRunning && + startAudioRef.current + ) { + console.log('[useNativeBridge] Executing auto-start via ref...'); + try { + await startAudioRef.current(); + } catch (err) { + console.error('[useNativeBridge] Auto-start failed:', err); + } + } + }, 500); + } + }); + + return () => { + unsubscribeRoom(); + }; + }, []); + // Connect to bridge const connect = useCallback(async () => { console.log('[useNativeBridge] Manual connect requested'); @@ -460,6 +506,7 @@ export function useNativeBridge() { isMuted: track.isMuted, isSolo: track.isSolo, volume: track.volume, + pan: track.pan ?? 0, inputGainDb: track.audioSettings.inputGain || 0, monitoringEnabled: directMonitoring, monitoringVolume: track.audioSettings.monitoringVolume ?? 1, @@ -470,6 +517,11 @@ export function useNativeBridge() { } }, []); + // Update ref whenever startAudio changes (for auto-start feature) + useEffect(() => { + startAudioRef.current = startAudio; + }, [startAudio]); + // Stop audio const stopAudio = useCallback(() => { const state = useBridgeAudioStore.getState(); @@ -591,6 +643,7 @@ export function useNativeBridge() { isMuted: track.isMuted, isSolo: track.isSolo, volume: track.volume, + pan: track.pan ?? 0, inputGainDb: track.audioSettings.inputGain || 0, monitoringEnabled: track.audioSettings.directMonitoring ?? true, monitoringVolume: track.audioSettings.monitoringVolume ?? 1,