How Meetily Captures System Audio on macOS Using ScreenCaptureKit
Meetily leverages Apple's ScreenCaptureKit (SCK) through the CPAL audio abstraction to capture pristine, digital system-wide audio streams on macOS, automatically falling back to this backend when Core Audio is unavailable.
Meetily implements system-wide audio capture on macOS by integrating Apple's ScreenCaptureKit framework through the CPAL (Cross-Platform Audio Library) abstraction layer. This approach allows the application to access digital audio streams directly from the system output, bypassing the noisy Bluetooth processing pipeline that affects traditional capture methods. The implementation in the Zackriya-Solutions/meetily repository provides a robust backend selection mechanism that prioritizes ScreenCaptureKit for high-quality, low-latency audio recording.
Backend Selection and Configuration
The audio capture architecture in Meetily defines available backends through the AudioCaptureBackend enum. According to the source code in frontend/src-tauri/src/audio/capture/backend_config.rs (lines 11-20), the default backend for macOS is explicitly set to ScreenCaptureKit.
This configuration ensures that when the application initializes audio capture on macOS, it automatically selects the SCK implementation unless overridden by user preferences. The backend selection determines which CPAL host the system uses to enumerate and open audio devices.
// Selecting the backend (macOS default)
let backend = AudioCaptureBackend::ScreenCaptureKit;
println!("Using backend: {}", backend.name());
// → "ScreenCaptureKit" (see capture/backend_config.rs)
Device Enumeration with ScreenCaptureKit
When enumerating output devices, Meetily specifically opens the ScreenCaptureKit host (cpal::HostId::ScreenCaptureKit) to list digital system-audio devices. The implementation in frontend/src-tauri/src/audio/core-old.rs (lines 64-70) demonstrates this approach.
Using the SCK host provides access to the raw digital audio stream rather than the processed analog output that passes through Bluetooth codecs. This distinction is crucial for capturing pristine audio quality without the compression artifacts or latency introduced by wireless audio pathways.
Stream Creation and Initialization
The generic CPAL stream wrapper, implemented in frontend/src-tauri/src/audio/stream.rs (lines 92-105), receives the selected backend name and configures the audio stream accordingly. When "ScreenCaptureKit" is specified, the wrapper initializes a CPAL stream using the SCK host, which delivers system-audio samples directly to the processing pipeline.
The AudioStream::create method handles the platform-specific configuration, ensuring that the stream connects to the system output device with the correct sample format and buffer size for digital capture.
// Creating a system-audio stream with SCK
let sys_device = Arc::new(AudioDevice::new(
"Built‑in Output".to_string(),
DeviceType::Output,
));
let sys_stream = AudioStream::create(
&sys_device,
state.clone(),
DeviceType::Output,
recording_sender.clone(),
).await?; // stream uses CPAL host = ScreenCaptureKit
Fallback Handling in Enhanced Audio Manager
Meetily's newer EnhancedAudioStreamManager implements intelligent backend selection logic. According to frontend/src-tauri/src/audio/system_audio_stream.rs (lines 150-160), the manager first attempts to use the Core Audio capture path for system audio.
If the Core Audio path proves unsuitable—such as on Mac systems that only provide digital output without analog loopback—the manager automatically falls back to the ScreenCaptureKit implementation. This fallback ensures compatibility across different macOS hardware configurations while maintaining optimal audio quality where possible.
// Inside EnhancedAudioStreamManager – fallback to SCK
if should_use_enhanced_system_audio(&sys_device) {
// …use Core Audio
} else {
// Fallback to ScreenCaptureKit
let sys_stream = super::stream::AudioStream::create(
sys_device,
self.state.clone(),
DeviceType::Output,
recording_sender,
).await?;
// (see system_audio_stream.rs lines 150‑160)
}
Audio Processing Pipeline
Once the SCK-backed stream is active, the SystemAudioStreamManager spawns a Tokio asynchronous task to handle sample processing. The implementation in frontend/src-tauri/src/audio/system_audio_stream.rs (lines 41-58) shows how the system pulls samples from the SCK stream, batches them into 1024-frame chunks, and forwards them to the AudioCapture processing stage.
This architecture integrates the system audio stream seamlessly with Meetily's existing audio pipeline, feeding the mixing and Voice Activity Detection (VAD) stages exactly like microphone audio. The batched processing approach optimizes CPU usage while maintaining real-time capture capabilities.
// Processing loop in SystemAudioStreamManager (SCK path)
tokio::spawn(async move {
while let Some(sample) = system_stream.next().await {
buffer.push(sample);
if buffer.len() >= frames_per_chunk {
audio_capture.process_audio_data(&buffer);
buffer.clear();
}
}
// Process any leftovers
if !buffer.is_empty() {
audio_capture.process_audio_data(&buffer);
}
});
User Configuration Options
The application exposes the ScreenCaptureKit backend as a selectable option in the user interface. The configuration entries in frontend/src-tauri/src/audio/recording_preferences.rs (lines 363-382) define the available capture backends for macOS users.
This exposure allows advanced users to explicitly select ScreenCaptureKit when troubleshooting audio issues or when specific capture requirements demand the digital audio pathway. The preference system stores the selection and propagates it to the backend configuration module during audio initialization.
Summary
- Meetily uses ScreenCaptureKit as the default audio capture backend on macOS, configured in
backend_config.rs. - The system enumerates devices via the SCK host in
core-old.rsto access pristine digital audio streams. - CPAL abstraction wraps the platform-specific SCK implementation, providing a consistent cross-platform API while leveraging macOS-specific digital capture capabilities.
- Automatic fallback logic in
system_audio_stream.rsensures capture continuity when Core Audio is unavailable. - Audio samples are processed in 1024-frame batches via Tokio async tasks, integrating seamlessly with VAD and mixing pipelines.
- Users can explicitly select the SCK backend through the preferences UI defined in
recording_preferences.rs.
Frequently Asked Questions
Why does Meetily use ScreenCaptureKit instead of Core Audio for system audio?
Meetily prioritizes ScreenCaptureKit because it provides direct access to the digital audio stream before it passes through Bluetooth processing or analog conversion. This approach eliminates compression artifacts and latency associated with wireless audio pathways, delivering pristine audio quality for recordings.
Can users manually switch between Core Audio and ScreenCaptureKit?
Yes. The application exposes both backends in the recording preferences UI, allowing users to override the automatic selection. However, the system defaults to ScreenCaptureKit on macOS and automatically falls back to it when Core Audio is unavailable for the specific hardware configuration.
How does the SCK implementation handle audio buffer management?
The SystemAudioStreamManager spawns a dedicated Tokio task that pulls samples from the CPAL stream and accumulates them into 1024-frame chunks before processing. This batching approach, implemented in system_audio_stream.rs, optimizes CPU usage while maintaining real-time capture synchronization with the microphone input pipeline.
Is ScreenCaptureKit available on all macOS versions supported by Meetily?
ScreenCaptureKit requires macOS 12.3 (Monterey) or later. Meetily's backend configuration automatically handles version compatibility, falling back to alternative capture methods on older systems where SCK is unavailable, ensuring broad hardware support across different macOS generations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →