diff --git a/examples/wgpu_room/src/sine_track.rs b/examples/wgpu_room/src/sine_track.rs index 21eab97..de581c0 100644 --- a/examples/wgpu_room/src/sine_track.rs +++ b/examples/wgpu_room/src/sine_track.rs @@ -12,6 +12,7 @@ struct FrameData { pub sample_rate: u32, pub freq: f64, pub amplitude: f64, + pub phase: u64, } impl Default for FrameData { @@ -20,6 +21,7 @@ impl Default for FrameData { sample_rate: 48000, freq: 440.0, amplitude: 1.0, + phase: 0, } } } @@ -98,7 +100,7 @@ impl SineTrack { loop { interval.tick().await; - let data = frame_options.lock(); + let mut data = frame_options.lock(); let samples_count_10ms = (data.sample_rate / 100) as usize; if samples_10ms.capacity() != samples_count_10ms { @@ -108,10 +110,13 @@ impl SineTrack { for i in 0..samples_count_10ms { let val = data.amplitude * f64::sin( - std::f64::consts::PI * 2.0 * data.freq * i as f64 - / samples_count_10ms as f64, + std::f64::consts::PI + * 2.0 + * data.freq + * (data.phase as f64 / data.sample_rate as f64), ); + data.phase += 1; // WebRTC uses 16-bit signed PCM samples_10ms[i] = (val * 32768.0) as i16; } diff --git a/livekit-webrtc/src/native/audio_source.rs b/livekit-webrtc/src/native/audio_source.rs index 195078f..7a85caf 100644 --- a/livekit-webrtc/src/native/audio_source.rs +++ b/livekit-webrtc/src/native/audio_source.rs @@ -1,16 +1,27 @@ use crate::audio_frame::AudioFrame; use cxx::SharedPtr; +use std::sync::{Arc, Mutex}; use webrtc_sys::media_stream as sys_ms; #[derive(Clone)] pub struct NativeAudioSource { sys_handle: SharedPtr, + inner: Arc>, +} + +#[derive(Default)] +struct AudioSourceInner { + buf: Vec, + offset: usize, + sample_rate: u32, + num_channels: u32, } impl Default for NativeAudioSource { fn default() -> Self { Self { sys_handle: sys_ms::ffi::new_audio_track_source(), + inner: Default::default(), } } } @@ -21,14 +32,51 @@ impl NativeAudioSource { } pub fn capture_frame(&self, frame: &AudioFrame) { - // TODO(theomonnom): Should we check for 10ms worth of data here? - unsafe { - self.sys_handle.on_captured_frame( - frame.data.as_ptr(), - frame.sample_rate as i32, - frame.num_channels as usize, - frame.samples_per_channel as usize, - ) + let mut inner = self.inner.lock().unwrap(); + let samples_10ms = (frame.sample_rate / 100 * frame.num_channels) as usize; + if inner.sample_rate != frame.sample_rate || inner.num_channels != frame.num_channels { + inner.buf.resize(samples_10ms as usize, 0); + inner.offset = 0; + } + + // Split the frame into 10ms chunks + let mut i = 0; + loop { + let buf_offset = inner.offset; + let remaining_data = frame.data.len() - i; // Remaining data to read inside the frame + let needed_data = samples_10ms - buf_offset; // Needed data of "frame.data" to make a complete 10ms from inner.buf + if remaining_data < needed_data { + if remaining_data > 0 { + // Not enough data to make a complete 10ms frame, store the remaining data inside inner.buf + // It'll be used on the next capture. + inner.buf[buf_offset..buf_offset + remaining_data] + .copy_from_slice(&frame.data[i..]); + inner.offset += remaining_data; + } + + break; + } + + let data = if inner.offset != 0 { + // Use the data from the previous capture + let data = &mut inner.buf[buf_offset..]; + data.copy_from_slice(&frame.data[i..i + needed_data]); + inner.offset = 0; + &inner.buf + } else { + &frame.data[i..i + samples_10ms] + }; + + unsafe { + self.sys_handle.on_captured_frame( + data.as_ptr(), + frame.sample_rate as i32, + frame.num_channels as usize, + samples_10ms, + ) + } + + i += needed_data; } } }