Skip to content

Commit 557d47b

Browse files
Merge pull request #709 from braedonsaunders/claude/remove-unused-import-KfbWA-U2eAk
fix(audio): Synchronize buffer size and sample rate across all compon…
2 parents 71f7c5f + ca38de6 commit 557d47b

4 files changed

Lines changed: 108 additions & 4 deletions

File tree

native-bridge/src/audio/engine.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl Default for EngineConfig {
5959
fn default() -> Self {
6060
Self {
6161
sample_rate: SampleRate::Hz48000,
62-
buffer_size: BufferSize::Samples128,
62+
buffer_size: BufferSize::Samples256,
6363
input_device_id: None,
6464
output_device_id: None,
6565
channel_config: ChannelConfig::default(),
@@ -598,6 +598,25 @@ impl AudioEngine {
598598
}
599599
}
600600

601+
/// Get current input device ID
602+
pub fn get_input_device_id(&self) -> Option<String> {
603+
self.config.input_device_id.clone()
604+
}
605+
606+
/// Get current output device ID
607+
pub fn get_output_device_id(&self) -> Option<String> {
608+
self.config.output_device_id.clone()
609+
}
610+
611+
/// Get current channel configuration
612+
pub fn get_channel_config(&self) -> ChannelConfig {
613+
if let Ok(state) = self.processing_state.try_read() {
614+
state.channel_config.clone()
615+
} else {
616+
self.config.channel_config.clone()
617+
}
618+
}
619+
601620
/// Get raw audio samples for streaming to browser (for WebRTC broadcast)
602621
/// Returns up to `max_samples` stereo samples, or fewer if buffer has less
603622
pub fn get_browser_stream_audio(&self, max_samples: usize) -> Vec<f32> {

native-bridge/src/protocol/server.rs

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -508,11 +508,32 @@ impl BridgeServer {
508508
256 => crate::audio::BufferSize::Samples256,
509509
512 => crate::audio::BufferSize::Samples512,
510510
1024 => crate::audio::BufferSize::Samples1024,
511-
_ => crate::audio::BufferSize::Samples128,
511+
_ => crate::audio::BufferSize::Samples256,
512512
};
513513

514514
match app.audio_engine.set_buffer_size(buffer_size) {
515-
Ok(_) => None,
515+
Ok(_) => {
516+
// Send updated device info to TUI
517+
let device_info = app.audio_engine.get_device_info();
518+
if let Some(ref tx) = app.tui_tx {
519+
let _ = tx.try_send(AppEvent::DeviceInfo {
520+
input_device: device_info.input_device.clone(),
521+
output_device: device_info.output_device.clone(),
522+
sample_rate: device_info.sample_rate,
523+
buffer_size: device_info.buffer_size,
524+
});
525+
}
526+
// Send DeviceConfig back to browser to confirm
527+
Some(NativeMessage::DeviceConfig {
528+
input_device: app.audio_engine.get_input_devices().ok()
529+
.and_then(|devs| devs.into_iter().find(|d| Some(d.id.clone()) == app.audio_engine.get_input_device_id())),
530+
output_device: app.audio_engine.get_output_devices().ok()
531+
.and_then(|devs| devs.into_iter().find(|d| Some(d.id.clone()) == app.audio_engine.get_output_device_id())),
532+
sample_rate: device_info.sample_rate,
533+
buffer_size: device_info.buffer_size,
534+
channel_config: app.audio_engine.get_channel_config(),
535+
})
536+
}
516537
Err(e) => Some(NativeMessage::Error {
517538
code: "CONFIG_ERROR".to_string(),
518539
message: e.to_string(),
@@ -531,7 +552,28 @@ impl BridgeServer {
531552
};
532553

533554
match app.audio_engine.set_sample_rate(sample_rate) {
534-
Ok(_) => None,
555+
Ok(_) => {
556+
// Send updated device info to TUI
557+
let device_info = app.audio_engine.get_device_info();
558+
if let Some(ref tx) = app.tui_tx {
559+
let _ = tx.try_send(AppEvent::DeviceInfo {
560+
input_device: device_info.input_device.clone(),
561+
output_device: device_info.output_device.clone(),
562+
sample_rate: device_info.sample_rate,
563+
buffer_size: device_info.buffer_size,
564+
});
565+
}
566+
// Send DeviceConfig back to browser to confirm
567+
Some(NativeMessage::DeviceConfig {
568+
input_device: app.audio_engine.get_input_devices().ok()
569+
.and_then(|devs| devs.into_iter().find(|d| Some(d.id.clone()) == app.audio_engine.get_input_device_id())),
570+
output_device: app.audio_engine.get_output_devices().ok()
571+
.and_then(|devs| devs.into_iter().find(|d| Some(d.id.clone()) == app.audio_engine.get_output_device_id())),
572+
sample_rate: device_info.sample_rate,
573+
buffer_size: device_info.buffer_size,
574+
channel_config: app.audio_engine.get_channel_config(),
575+
})
576+
}
535577
Err(e) => Some(NativeMessage::Error {
536578
code: "CONFIG_ERROR".to_string(),
537579
message: e.to_string(),

src/hooks/useNativeBridge.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,21 @@ export function useNativeBridge() {
170170
s.setError(data);
171171
};
172172

173+
// Handle device config confirmation from native bridge - sync actual values back to store
174+
const handleDeviceConfig = (data: {
175+
inputDevice: BridgeDevice | null;
176+
outputDevice: BridgeDevice | null;
177+
sampleRate: number;
178+
bufferSize: number;
179+
channelConfig: { channelCount: 1 | 2; leftChannel: number; rightChannel?: number };
180+
}) => {
181+
console.log('[useNativeBridge] DeviceConfig confirmed:', data.sampleRate, 'Hz,', data.bufferSize, 'samples');
182+
const s = useBridgeAudioStore.getState();
183+
// Update store with actual values from native bridge
184+
s.setSampleRate(data.sampleRate as 44100 | 48000);
185+
s.setBufferSize(data.bufferSize as 32 | 64 | 128 | 256 | 512 | 1024);
186+
};
187+
173188
// Handle audio levels from native bridge - update track levels for waveform display
174189
const handleLevels = (data: {
175190
inputLevel: number;
@@ -211,6 +226,7 @@ export function useNativeBridge() {
211226
nativeBridge.on('disconnected', handleDisconnected);
212227
nativeBridge.on('audioStatus', handleAudioStatus);
213228
nativeBridge.on('devices', handleDevices);
229+
nativeBridge.on('deviceConfig', handleDeviceConfig);
214230
nativeBridge.on('error', handleError);
215231
nativeBridge.on('levels', handleLevels);
216232

@@ -244,6 +260,7 @@ export function useNativeBridge() {
244260
nativeBridge.off('disconnected', handleDisconnected);
245261
nativeBridge.off('audioStatus', handleAudioStatus);
246262
nativeBridge.off('devices', handleDevices);
263+
nativeBridge.off('deviceConfig', handleDeviceConfig);
247264
nativeBridge.off('error', handleError);
248265
nativeBridge.off('levels', handleLevels);
249266
initialized.current = false;

src/lib/audio/native-bridge.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,25 @@ interface BridgeStreamHealth {
5050
msSinceLastRead: number;
5151
}
5252

53+
interface BridgeDeviceConfig {
54+
inputDevice: BridgeDevice | null;
55+
outputDevice: BridgeDevice | null;
56+
sampleRate: number;
57+
bufferSize: number;
58+
channelConfig: {
59+
channelCount: 1 | 2;
60+
leftChannel: number;
61+
rightChannel?: number;
62+
};
63+
}
64+
5365
// Native bridge sends snake_case, we normalize to camelCase
5466
type NativeMessage =
5567
| { type: 'welcome'; version: string; driverType?: string; driver_type?: string }
5668
| { type: 'pong'; timestamp: number; nativeTime: number }
5769
| { type: 'error'; code: string; message: string }
5870
| { type: 'devices'; inputs: BridgeDevice[]; outputs: BridgeDevice[] }
71+
| { type: 'deviceConfig' } & BridgeDeviceConfig
5972
| { type: 'audioStatus' } & BridgeAudioStatus
6073
| { type: 'levels' } & BridgeLevels
6174
| { type: 'streamHealth' } & BridgeStreamHealth
@@ -88,6 +101,7 @@ export type BridgeEventType =
88101
| 'connected'
89102
| 'disconnected'
90103
| 'devices'
104+
| 'deviceConfig'
91105
| 'levels'
92106
| 'audioStatus'
93107
| 'streamHealth'
@@ -99,6 +113,7 @@ type BridgeEventData = {
99113
connected: { version: string; driverType: string };
100114
disconnected: { reason: string };
101115
devices: { inputs: BridgeDevice[]; outputs: BridgeDevice[] };
116+
deviceConfig: BridgeDeviceConfig;
102117
levels: BridgeLevels;
103118
audioStatus: BridgeAudioStatus;
104119
streamHealth: BridgeStreamHealth;
@@ -320,6 +335,17 @@ export class NativeBridge {
320335
this.emit('devices', { inputs: msg.inputs, outputs: msg.outputs });
321336
break;
322337

338+
case 'deviceConfig':
339+
console.log('[NativeBridge] DeviceConfig received:', msg.sampleRate, 'Hz,', msg.bufferSize, 'samples');
340+
this.emit('deviceConfig', {
341+
inputDevice: msg.inputDevice,
342+
outputDevice: msg.outputDevice,
343+
sampleRate: msg.sampleRate,
344+
bufferSize: msg.bufferSize,
345+
channelConfig: msg.channelConfig,
346+
});
347+
break;
348+
323349
case 'levels':
324350
this.emit('levels', {
325351
inputLevel: msg.inputLevel,

0 commit comments

Comments
 (0)