screencapturekit/stream/configuration/audio.rs
1//! Audio capture configuration
2//!
3//! Methods for configuring audio capture, sample rate, and channel count.
4//!
5//! ## Supported Values
6//!
7//! `ScreenCaptureKit` supports specific sample rates and channel counts:
8//!
9//! | Sample Rate | Description |
10//! |-------------|-------------|
11//! | 8000 Hz | Low quality, telephony |
12//! | 16000 Hz | Speech quality |
13//! | 24000 Hz | Medium quality |
14//! | 48000 Hz | Professional audio (default) |
15//!
16//! | Channel Count | Description |
17//! |---------------|-------------|
18//! | 1 | Mono |
19//! | 2 | Stereo (default) |
20
21use crate::utils::ffi_string::{ffi_string_from_buffer, SMALL_BUFFER_SIZE};
22
23use super::internal::SCStreamConfiguration;
24
25/// Audio sample rate for capture
26///
27/// `ScreenCaptureKit` supports a fixed set of sample rates. Using values outside
28/// this set will result in the system defaulting to 48000 Hz.
29///
30/// # Examples
31///
32/// ```
33/// use screencapturekit::stream::configuration::audio::AudioSampleRate;
34///
35/// // Get the Hz value
36/// assert_eq!(AudioSampleRate::Rate48000.as_hz(), 48000);
37///
38/// // Use default (48000 Hz)
39/// let rate = AudioSampleRate::default();
40/// assert_eq!(rate, AudioSampleRate::Rate48000);
41/// ```
42#[repr(i32)]
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
44pub enum AudioSampleRate {
45 /// 8000 Hz - Low quality, suitable for telephony
46 Rate8000 = 8000,
47 /// 16000 Hz - Speech quality
48 Rate16000 = 16000,
49 /// 24000 Hz - Medium quality
50 Rate24000 = 24000,
51 /// 48000 Hz - Professional audio quality (default)
52 #[default]
53 Rate48000 = 48000,
54}
55
56impl AudioSampleRate {
57 /// Get the sample rate in Hz
58 #[must_use]
59 pub const fn as_hz(self) -> i32 {
60 self as i32
61 }
62
63 /// Create from Hz value, returning None if unsupported
64 ///
65 /// # Examples
66 ///
67 /// ```
68 /// use screencapturekit::stream::configuration::audio::AudioSampleRate;
69 ///
70 /// assert_eq!(AudioSampleRate::from_hz(48000), Some(AudioSampleRate::Rate48000));
71 /// assert_eq!(AudioSampleRate::from_hz(44100), None); // Not supported
72 /// ```
73 #[must_use]
74 pub const fn from_hz(hz: i32) -> Option<Self> {
75 match hz {
76 8000 => Some(Self::Rate8000),
77 16000 => Some(Self::Rate16000),
78 24000 => Some(Self::Rate24000),
79 48000 => Some(Self::Rate48000),
80 _ => None,
81 }
82 }
83}
84
85impl std::fmt::Display for AudioSampleRate {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 write!(f, "{} Hz", self.as_hz())
88 }
89}
90
91impl From<AudioSampleRate> for i32 {
92 fn from(rate: AudioSampleRate) -> Self {
93 rate.as_hz()
94 }
95}
96
97/// Audio channel configuration for capture
98///
99/// `ScreenCaptureKit` supports mono (1 channel) or stereo (2 channels) audio.
100/// Using other values will result in the system defaulting to stereo.
101///
102/// # Examples
103///
104/// ```
105/// use screencapturekit::stream::configuration::audio::AudioChannelCount;
106///
107/// // Get the channel count
108/// assert_eq!(AudioChannelCount::Stereo.as_count(), 2);
109///
110/// // Use default (stereo)
111/// let channels = AudioChannelCount::default();
112/// assert_eq!(channels, AudioChannelCount::Stereo);
113/// ```
114#[repr(i32)]
115#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
116pub enum AudioChannelCount {
117 /// Mono - single channel audio
118 Mono = 1,
119 /// Stereo - two channel audio (default)
120 #[default]
121 Stereo = 2,
122}
123
124impl AudioChannelCount {
125 /// Get the channel count as an integer
126 #[must_use]
127 pub const fn as_count(self) -> i32 {
128 self as i32
129 }
130
131 /// Create from channel count, returning None if unsupported
132 ///
133 /// # Examples
134 ///
135 /// ```
136 /// use screencapturekit::stream::configuration::audio::AudioChannelCount;
137 ///
138 /// assert_eq!(AudioChannelCount::from_count(2), Some(AudioChannelCount::Stereo));
139 /// assert_eq!(AudioChannelCount::from_count(6), None); // Not supported
140 /// ```
141 #[must_use]
142 pub const fn from_count(count: i32) -> Option<Self> {
143 match count {
144 1 => Some(Self::Mono),
145 2 => Some(Self::Stereo),
146 _ => None,
147 }
148 }
149}
150
151impl std::fmt::Display for AudioChannelCount {
152 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153 match self {
154 Self::Mono => write!(f, "Mono (1 channel)"),
155 Self::Stereo => write!(f, "Stereo (2 channels)"),
156 }
157 }
158}
159
160impl From<AudioChannelCount> for i32 {
161 fn from(count: AudioChannelCount) -> Self {
162 count.as_count()
163 }
164}
165
166impl SCStreamConfiguration {
167 /// Enable or disable audio capture
168 ///
169 /// # Examples
170 ///
171 /// ```
172 /// use screencapturekit::prelude::*;
173 ///
174 /// let mut config = SCStreamConfiguration::default();
175 /// config.set_captures_audio(true);
176 /// assert!(config.captures_audio());
177 /// ```
178 pub fn set_captures_audio(&mut self, captures_audio: bool) -> &mut Self {
179 unsafe {
180 crate::ffi::sc_stream_configuration_set_captures_audio(self.as_ptr(), captures_audio);
181 }
182 self
183 }
184
185 /// Enable or disable audio capture (builder pattern)
186 #[must_use]
187 pub fn with_captures_audio(mut self, captures_audio: bool) -> Self {
188 self.set_captures_audio(captures_audio);
189 self
190 }
191
192 /// Check if audio capture is enabled
193 pub fn captures_audio(&self) -> bool {
194 unsafe { crate::ffi::sc_stream_configuration_get_captures_audio(self.as_ptr()) }
195 }
196
197 /// Set the audio sample rate
198 ///
199 /// Accepts either an [`AudioSampleRate`] enum or a raw `i32` Hz value.
200 ///
201 /// # Supported Values
202 ///
203 /// `ScreenCaptureKit` supports: 8000, 16000, 24000, 48000 Hz.
204 /// Other values will default to 48000 Hz.
205 ///
206 /// # Examples
207 ///
208 /// ```
209 /// use screencapturekit::prelude::*;
210 /// use screencapturekit::stream::configuration::audio::AudioSampleRate;
211 ///
212 /// // Using the enum (recommended)
213 /// let config = SCStreamConfiguration::new()
214 /// .with_sample_rate(AudioSampleRate::Rate48000);
215 ///
216 /// // Using raw value (still works)
217 /// let config = SCStreamConfiguration::new()
218 /// .with_sample_rate(48000);
219 /// ```
220 pub fn set_sample_rate(&mut self, sample_rate: impl Into<i32>) -> &mut Self {
221 unsafe {
222 crate::ffi::sc_stream_configuration_set_sample_rate(
223 self.as_ptr(),
224 sample_rate.into() as isize,
225 );
226 }
227 self
228 }
229
230 /// Set the audio sample rate (builder pattern)
231 #[must_use]
232 pub fn with_sample_rate(mut self, sample_rate: impl Into<i32>) -> Self {
233 self.set_sample_rate(sample_rate);
234 self
235 }
236
237 /// Get the configured audio sample rate in Hz
238 pub fn sample_rate(&self) -> i32 {
239 // FFI returns isize but sample rate fits in i32 (typical values: 44100, 48000)
240 #[allow(clippy::cast_possible_truncation)]
241 unsafe {
242 crate::ffi::sc_stream_configuration_get_sample_rate(self.as_ptr()) as i32
243 }
244 }
245
246 /// Get the configured audio sample rate as an enum
247 ///
248 /// Returns `None` if the current sample rate is not a supported value.
249 pub fn audio_sample_rate(&self) -> Option<AudioSampleRate> {
250 AudioSampleRate::from_hz(self.sample_rate())
251 }
252
253 /// Set the number of audio channels
254 ///
255 /// Accepts either an [`AudioChannelCount`] enum or a raw `i32` value.
256 ///
257 /// # Supported Values
258 ///
259 /// `ScreenCaptureKit` supports: 1 (mono), 2 (stereo).
260 /// Other values will default to stereo.
261 ///
262 /// # Examples
263 ///
264 /// ```
265 /// use screencapturekit::prelude::*;
266 /// use screencapturekit::stream::configuration::audio::AudioChannelCount;
267 ///
268 /// // Using the enum (recommended)
269 /// let config = SCStreamConfiguration::new()
270 /// .with_channel_count(AudioChannelCount::Stereo);
271 ///
272 /// // Using raw value (still works)
273 /// let config = SCStreamConfiguration::new()
274 /// .with_channel_count(2);
275 /// ```
276 pub fn set_channel_count(&mut self, channel_count: impl Into<i32>) -> &mut Self {
277 unsafe {
278 crate::ffi::sc_stream_configuration_set_channel_count(
279 self.as_ptr(),
280 channel_count.into() as isize,
281 );
282 }
283 self
284 }
285
286 /// Set the number of audio channels (builder pattern)
287 #[must_use]
288 pub fn with_channel_count(mut self, channel_count: impl Into<i32>) -> Self {
289 self.set_channel_count(channel_count);
290 self
291 }
292
293 /// Get the configured channel count
294 pub fn channel_count(&self) -> i32 {
295 // FFI returns isize but channel count fits in i32 (typical values: 1-8)
296 #[allow(clippy::cast_possible_truncation)]
297 unsafe {
298 crate::ffi::sc_stream_configuration_get_channel_count(self.as_ptr()) as i32
299 }
300 }
301
302 /// Get the configured channel count as an enum
303 ///
304 /// Returns `None` if the current channel count is not a supported value.
305 pub fn audio_channel_count(&self) -> Option<AudioChannelCount> {
306 AudioChannelCount::from_count(self.channel_count())
307 }
308
309 /// Enable microphone capture (macOS 15.0+)
310 ///
311 /// When set to `true`, the stream will capture audio from the microphone
312 /// in addition to system/application audio (if `captures_audio` is also enabled).
313 ///
314 /// **Note**: Requires `NSMicrophoneUsageDescription` in your app's Info.plist
315 /// for microphone access permission.
316 ///
317 /// # Availability
318 /// macOS 15.0+. On earlier versions, this setting has no effect.
319 ///
320 /// # Example
321 /// ```rust,no_run
322 /// use screencapturekit::prelude::*;
323 ///
324 /// let config = SCStreamConfiguration::new()
325 /// .with_captures_audio(true) // System audio
326 /// .with_captures_microphone(true) // Microphone audio (macOS 15.0+)
327 /// .with_sample_rate(48000)
328 /// .with_channel_count(2);
329 /// ```
330 pub fn set_captures_microphone(&mut self, captures_microphone: bool) -> &mut Self {
331 unsafe {
332 crate::ffi::sc_stream_configuration_set_captures_microphone(
333 self.as_ptr(),
334 captures_microphone,
335 );
336 }
337 self
338 }
339
340 /// Enable microphone capture (builder pattern)
341 #[must_use]
342 pub fn with_captures_microphone(mut self, captures_microphone: bool) -> Self {
343 self.set_captures_microphone(captures_microphone);
344 self
345 }
346
347 /// Get whether microphone capture is enabled (macOS 15.0+).
348 pub fn captures_microphone(&self) -> bool {
349 unsafe { crate::ffi::sc_stream_configuration_get_captures_microphone(self.as_ptr()) }
350 }
351
352 /// Exclude current process audio from capture.
353 ///
354 /// When set to `true`, the stream will not capture audio from the current
355 /// process, preventing feedback loops in recording applications.
356 ///
357 /// # Example
358 /// ```rust,no_run
359 /// use screencapturekit::prelude::*;
360 ///
361 /// let config = SCStreamConfiguration::new()
362 /// .with_captures_audio(true)
363 /// .with_excludes_current_process_audio(true); // Prevent feedback
364 /// ```
365 pub fn set_excludes_current_process_audio(&mut self, excludes: bool) -> &mut Self {
366 unsafe {
367 crate::ffi::sc_stream_configuration_set_excludes_current_process_audio(
368 self.as_ptr(),
369 excludes,
370 );
371 }
372 self
373 }
374
375 /// Exclude current process audio (builder pattern)
376 #[must_use]
377 pub fn with_excludes_current_process_audio(mut self, excludes: bool) -> Self {
378 self.set_excludes_current_process_audio(excludes);
379 self
380 }
381
382 /// Get whether current process audio is excluded from capture.
383 pub fn excludes_current_process_audio(&self) -> bool {
384 unsafe {
385 crate::ffi::sc_stream_configuration_get_excludes_current_process_audio(self.as_ptr())
386 }
387 }
388
389 /// Set microphone capture device ID (macOS 15.0+).
390 ///
391 /// Specifies which microphone device to capture from.
392 ///
393 /// # Availability
394 /// macOS 15.0+. On earlier versions, this setting has no effect.
395 ///
396 /// # Example
397 /// ```rust,no_run
398 /// use screencapturekit::prelude::*;
399 ///
400 /// let mut config = SCStreamConfiguration::new()
401 /// .with_captures_microphone(true);
402 /// config.set_microphone_capture_device_id("AppleHDAEngineInput:1B,0,1,0:1");
403 /// ```
404 pub fn set_microphone_capture_device_id(&mut self, device_id: &str) -> &mut Self {
405 unsafe {
406 if let Ok(c_id) = std::ffi::CString::new(device_id) {
407 crate::ffi::sc_stream_configuration_set_microphone_capture_device_id(
408 self.as_ptr(),
409 c_id.as_ptr(),
410 );
411 }
412 }
413 self
414 }
415
416 /// Set microphone capture device ID (builder pattern)
417 #[must_use]
418 pub fn with_microphone_capture_device_id(mut self, device_id: &str) -> Self {
419 self.set_microphone_capture_device_id(device_id);
420 self
421 }
422
423 /// Clear microphone capture device ID, reverting to default system microphone
424 pub fn clear_microphone_capture_device_id(&mut self) -> &mut Self {
425 unsafe {
426 crate::ffi::sc_stream_configuration_set_microphone_capture_device_id(
427 self.as_ptr(),
428 std::ptr::null(),
429 );
430 }
431 self
432 }
433
434 /// Get microphone capture device ID (macOS 15.0+).
435 pub fn microphone_capture_device_id(&self) -> Option<String> {
436 unsafe {
437 ffi_string_from_buffer(SMALL_BUFFER_SIZE, |buf, len| {
438 crate::ffi::sc_stream_configuration_get_microphone_capture_device_id(
439 self.as_ptr(),
440 buf,
441 len,
442 )
443 })
444 }
445 }
446}