From f8c5e54962cfc615c50f1310eb4053d5760a9fc7 Mon Sep 17 00:00:00 2001 From: Jamie Pine Date: Mon, 26 Jan 2026 19:39:09 -0800 Subject: [PATCH] Add audio input entitlement and enhance audio sample extraction logic - Added the `com.apple.security.device.audio-input` entitlement to the Entitlements.plist for improved audio capture capabilities. - Refactored the audio sample extraction logic in macOS to handle both interleaved and planar audio formats, improving sample processing and interleaving of channels. - Updated the Assets.car file to reflect changes in the audio capture implementation. --- tauri/src-tauri/Entitlements.plist | 2 + tauri/src-tauri/gen/Assets.car | Bin 3847048 -> 3847048 bytes tauri/src-tauri/src/audio_capture/macos.rs | 56 ++++++++++++++++++--- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/tauri/src-tauri/Entitlements.plist b/tauri/src-tauri/Entitlements.plist index 46f67566..0d041c2c 100644 --- a/tauri/src-tauri/Entitlements.plist +++ b/tauri/src-tauri/Entitlements.plist @@ -8,5 +8,7 @@ com.apple.security.cs.disable-library-validation + com.apple.security.device.audio-input + diff --git a/tauri/src-tauri/gen/Assets.car b/tauri/src-tauri/gen/Assets.car index db1bac230a2c2bcbb656dd283089c4be47d6e1f5..7b81cf777f0b01ca6474699403672548c5e84f92 100644 GIT binary patch delta 864 zcmZwGzfTlF6bJA<&XeOeDj=L7pyKa=nRzp_GZfs-&di3=lG4u3SXx+^SR5_6#7cV- z8xxA9^grMqu(0!Dj6oYM{SuDq*yNL!*L>f;+1dT?KWh8%`D9~dD$BA-n1FGZfoT|n z=F#tslbHkF=$-0L@3~p)eL>}@Z_RS;>(NK^XQXXI5#jFAOXPM6FZA(*hFc%;a^ z)J*4+i1D*WQ&isiQYgFm>g9`r_13$->-Jp@MxYK?paEB5wCcNNYP3_bDTuoO%`DLLd&p0lEGmXRSPt>@f|bjkZ_ z;>AVI>(HF9wWSDoS#WGx7J@0sOJ31kIkieJ6WTB(2~ir zESa)FF&C0$B2w;2hF}Ue6y&)hPv=34-M!r=jKMfez$8q;G|a#(T!ZUy1Lj~J7T_kF zWh_ApZox9Fz-?HCHCTr`a2M{u2Hb}S@DLus<7#jB$-lolp_JYP&zwy;b|S+HgYzbe zR%u~^;lqdHgwlMlQ>%N}c?t|RVGB42kU*e7SBD)_{c2m6VhSZODRB=}t|LBcAZBEW zxT4BMJv`6`a{1tTw7SPzIaqMj@z!?zjabMs{S80D27T$Y*H^WLlt`p%$#hPqh& J{IvaH^gp>2=CA+& delta 864 zcmZwGId2m|7zW_AO^92n8erC2wR>nUx-Wnvv%H=Fkqle60-N>Q{5h(p}y9w%CF=1`e(JvL(V+QIbl&rBCVt(u%t=wMd1p~nThAq zTp2>oKSlH4f@CSkofpra9d50^8M*$*RiFwrxCB#h8K%pTtLIbQz+|9?azd3vU^0q$ zOb}X_m>c0~6!~Ny&SkLUKCN=lt-r19DW?mpzH0?!rB|4-epBd9eTJ&+k3WW0cAgZK5Dj;dD3?BO+PPr3^x8 zJ9*2FnwZ9CTJInA9s_|L=l}%<90W*EDah`ivi;ih72+l4W{nJl1X0Rg8Q8#!pb2<+l&J H@239(2z2H_ diff --git a/tauri/src-tauri/src/audio_capture/macos.rs b/tauri/src-tauri/src/audio_capture/macos.rs index d929e65a..ef5451d0 100644 --- a/tauri/src-tauri/src/audio_capture/macos.rs +++ b/tauri/src-tauri/src/audio_capture/macos.rs @@ -163,25 +163,67 @@ fn extract_audio_samples(sample_buffer: CMSampleBuffer) -> Result, Stri .audio_buffer_list() .ok_or_else(|| "Failed to get audio buffer list".to_string())?; - let mut samples = Vec::new(); + let buffers: Vec<_> = audio_buffer_list.iter().collect(); + let num_buffers = buffers.len(); + + if num_buffers == 0 { + return Ok(Vec::new()); + } - // Iterate through audio buffers - for buffer in audio_buffer_list.iter() { - // Get raw bytes and interpret as f32 samples + // ScreenCaptureKit on macOS provides audio in Float32 format + // The audio can be either: + // - Interleaved (1 buffer with L,R,L,R,... samples) + // - Planar (2 buffers, one for L channel, one for R channel) + + if num_buffers == 1 { + // Interleaved stereo or mono in a single buffer + let buffer = &buffers[0]; let data_bytes = buffer.data(); let num_samples = data_bytes.len() / std::mem::size_of::(); if num_samples > 0 { unsafe { - // Interpret bytes as f32 samples let data_ptr = data_bytes.as_ptr() as *const f32; let data = std::slice::from_raw_parts(data_ptr, num_samples); - samples.extend_from_slice(data); + return Ok(data.to_vec()); } } + } else { + // Planar format - separate buffer for each channel + // We need to interleave them: L0, R0, L1, R1, ... + let mut channel_data: Vec> = Vec::new(); + let mut max_samples = 0; + + for buffer in &buffers { + let data_bytes = buffer.data(); + let num_samples = data_bytes.len() / std::mem::size_of::(); + + if num_samples > 0 { + unsafe { + let data_ptr = data_bytes.as_ptr() as *const f32; + let data = std::slice::from_raw_parts(data_ptr, num_samples); + channel_data.push(data.to_vec()); + max_samples = max_samples.max(num_samples); + } + } + } + + // Interleave the channels + let mut interleaved = Vec::with_capacity(max_samples * num_buffers); + for i in 0..max_samples { + for channel in &channel_data { + if i < channel.len() { + interleaved.push(channel[i]); + } else { + interleaved.push(0.0); // Pad with silence if needed + } + } + } + + return Ok(interleaved); } - Ok(samples) + Ok(Vec::new()) } fn samples_to_wav(samples: &[f32], sample_rate: u32, channels: u16) -> Result, String> {