Skip to content

Commit 44f163e

Browse files
authored
Merge pull request #2 from PythonTilk/coderabbitai/docstrings/ebef137
📝 Add docstrings to `linux-development`
2 parents ebef137 + 0ba0e95 commit 44f163e

File tree

18 files changed

+756
-14
lines changed

18 files changed

+756
-14
lines changed

crates/audio/src/bin/test_mic.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
use audio::AudioInput;
22

3+
/// Tests microphone access by listing available devices and attempting to create audio input.
4+
///
5+
/// Prints available microphone devices, the default device name, and then tries to create an `AudioInput`
6+
/// using the default device, the first enumerated device (if any), and a set of known device names,
7+
/// reporting success or failure to stdout.
8+
///
9+
/// # Examples
10+
///
11+
/// ```no_run
12+
/// // Invoke the binary entry point which performs device enumeration and connection attempts.
13+
/// main();
14+
/// ```
315
fn main() {
416
println!("Testing microphone access...");
517

crates/audio/src/bin/test_speaker.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
use audio::AudioInput;
22

3+
/// Runs a simple binary test that creates an `AudioInput` from the default speaker, obtains its stream, and prints which `AudioStream` variant was returned.
4+
///
5+
/// This program exercises creation of a speaker `AudioInput`, requests its stream, and reports whether the stream is a `RealtimeSpeaker` variant. It does not poll or consume audio samples.
6+
///
7+
/// # Examples
8+
///
9+
/// ```
10+
/// // Call the test binary's main to perform the creation and type check.
11+
/// // The example demonstrates the intended usage; output is printed to stdout.
12+
/// fn run() {
13+
/// crate::main();
14+
/// }
15+
/// run();
16+
/// ```
317
fn main() {
418
println!("Testing SpeakerInput creation...");
519

crates/audio/src/lib.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,18 @@ pub struct AudioInput {
6969
}
7070

7171
impl AudioInput {
72+
/// Get the name of the system's default input (microphone) device.
73+
///
74+
/// # Returns
75+
///
76+
/// A `String` with the device name, `"Unknown Microphone"` if the device exists but has no name, or `"No Microphone Available"` if there is no default input device.
77+
///
78+
/// # Examples
79+
///
80+
/// ```
81+
/// let name = get_default_mic_device_name();
82+
/// assert!(!name.is_empty());
83+
/// ```
7284
pub fn get_default_mic_device_name() -> String {
7385
let host = cpal::default_host();
7486
if let Some(device) = host.default_input_device() {
@@ -78,6 +90,19 @@ impl AudioInput {
7890
}
7991
}
8092

93+
/// Returns a list of available input (microphone) device names.
94+
///
95+
/// The returned list contains the names of enumerated input devices. It filters out the
96+
/// "hypr-audio-tap" device and will append the virtual "echo-cancel-source" device if
97+
/// `pactl list sources short` reports it and it is not already present.
98+
///
99+
/// # Examples
100+
///
101+
/// ```
102+
/// let devices = crate::audio::list_mic_devices();
103+
/// // devices is a Vec<String> of device names (may be empty)
104+
/// assert!(devices.is_empty() || devices.iter().all(|s| !s.is_empty()));
105+
/// ```
81106
pub fn list_mic_devices() -> Vec<String> {
82107
let host = cpal::default_host();
83108

@@ -133,6 +158,20 @@ impl AudioInput {
133158
result
134159
}
135160

161+
/// Creates an AudioInput configured to stream from a microphone.
162+
///
163+
/// If `device_name` is `Some(name)`, attempts to open the input device with that name; if `None`, uses the default input device. On success returns an `AudioInput` with `source` set to `RealtimeMic` and `mic` initialized.
164+
///
165+
/// # Errors
166+
///
167+
/// Returns a `crate::Error` if microphone initialization fails.
168+
///
169+
/// # Examples
170+
///
171+
/// ```
172+
/// let ai = AudioInput::from_mic(None).expect("failed to open default microphone");
173+
/// assert!(matches!(ai.source, AudioSource::RealtimeMic));
174+
/// ```
136175
pub fn from_mic(device_name: Option<String>) -> Result<Self, crate::Error> {
137176
tracing::info!("Creating AudioInput from microphone with device name: {:?}", device_name);
138177
let mic = MicInput::new(device_name)?;
@@ -146,6 +185,22 @@ impl AudioInput {
146185
})
147186
}
148187

188+
/// Creates an AudioInput configured to capture audio from the system speaker.
189+
///
190+
/// The returned `AudioInput` uses `AudioSource::RealtimeSpeaker`. The `speaker` field will
191+
/// contain `Some(SpeakerInput)` if speaker capture initialization succeeds, or `None` if it fails;
192+
/// `mic` and `data` are always `None`.
193+
///
194+
/// # Examples
195+
///
196+
/// ```
197+
/// let input = AudioInput::from_speaker();
198+
/// // `input` is configured for realtime speaker capture; speaker initialization may have failed.
199+
/// match input.source {
200+
/// AudioSource::RealtimeSpeaker => {},
201+
/// _ => panic!("expected RealtimeSpeaker"),
202+
/// }
203+
/// ```
149204
pub fn from_speaker() -> Self {
150205
tracing::debug!("Creating AudioInput from speaker");
151206
let speaker = match SpeakerInput::new() {
@@ -248,4 +303,4 @@ impl kalosm_sound::AsyncSource for AudioStream {
248303
AudioStream::Recorded { .. } => 16000,
249304
}
250305
}
251-
}
306+
}

crates/audio/src/mic.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,17 @@ impl MicInput {
2323
.unwrap_or("Unknown Microphone".to_string())
2424
}
2525

26+
/// List available input audio device names.
27+
///
28+
/// A Vec<String> containing the names of available input devices. If a device's
29+
/// name cannot be retrieved, the entry will be "Unknown Microphone".
30+
///
31+
/// # Examples
32+
///
33+
/// ```
34+
/// let names = list_devices();
35+
/// assert!(names.iter().all(|n| !n.is_empty()));
36+
/// ```
2637
pub fn list_devices() -> Vec<String> {
2738
cpal::default_host()
2839
.input_devices()
@@ -31,7 +42,30 @@ impl MicInput {
3142
.collect()
3243
}
3344

34-
pub fn new(device_name: Option<String>) -> Result<Self, crate::Error> {
45+
/// Creates a new MicInput by selecting and configuring an available input device.
46+
///
47+
/// This tries to select the requested device when `device_name` is Some, otherwise it prefers
48+
/// the system default input device and falls back to the first enumerated input device. If no
49+
/// devices are directly usable the initializer attempts platform-specific fallbacks (for example
50+
/// handling echo-cancel-source and ALSA probes) before returning an error.
51+
///
52+
/// # Parameters
53+
///
54+
/// - `device_name`: Optional device name to prefer; when `None` the function will use the default
55+
/// input device if valid, otherwise the first available device.
56+
///
57+
/// # Returns
58+
///
59+
/// `Ok(Self)` with the chosen host, device, and supported stream configuration on success,
60+
/// `Err(crate::Error::NoInputDevice)` if no usable input device or configuration can be found.
61+
///
62+
/// # Examples
63+
///
64+
/// ```
65+
/// // Create a MicInput using the default device (or fallbacks).
66+
/// let _ = MicInput::new(None);
67+
/// ```
68+
pub fn new(device_name: Option<String>) -> Result<Self, crate::Error> {
3569
let host = cpal::default_host();
3670

3771
tracing::info!("Initializing microphone input...");
@@ -537,4 +571,4 @@ mod tests {
537571

538572
assert!(buffer.iter().any(|x| *x != 0.0));
539573
}
540-
}
574+
}

crates/audio/src/speaker/linux.rs

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,31 @@ use std::time::Duration;
88
pub struct SpeakerInput {}
99

1010
impl SpeakerInput {
11+
/// Construct a new Linux SpeakerInput handle.
12+
///
13+
/// Returns `Ok(Self)` on success, or an `anyhow::Error` if creation fails.
14+
///
15+
/// # Examples
16+
///
17+
/// ```
18+
/// let input = SpeakerInput::new().unwrap();
19+
/// ```
1120
pub fn new() -> Result<Self, anyhow::Error> {
1221
tracing::debug!("Creating Linux SpeakerInput");
1322
Ok(Self {})
1423
}
1524

25+
/// Creates a `SpeakerStream` for receiving speaker input samples.
26+
///
27+
/// Returns a `SpeakerStream` that yields `f32` audio samples (silence in the current mock).
28+
///
29+
/// # Examples
30+
///
31+
/// ```
32+
/// let input = crate::speaker::linux::SpeakerInput::new().unwrap();
33+
/// let mut stream = input.stream();
34+
/// assert_eq!(stream.sample_rate(), 48000);
35+
/// ```
1636
pub fn stream(self) -> SpeakerStream {
1737
tracing::debug!("Creating Linux SpeakerStream");
1838
SpeakerStream::new()
@@ -25,6 +45,20 @@ pub struct SpeakerStream {
2545
}
2646

2747
impl SpeakerStream {
48+
/// Creates a new `SpeakerStream` that produces a continuous stream of silence.
49+
///
50+
/// The returned stream delivers `f32` audio samples (silence as `0.0`) and preserves
51+
/// a background thread for sample production until the stream is dropped.
52+
///
53+
/// # Examples
54+
///
55+
/// ```
56+
/// use futures::stream::StreamExt;
57+
///
58+
/// let mut stream = SpeakerStream::new();
59+
/// let sample = futures::executor::block_on(async { stream.next().await }).unwrap();
60+
/// assert_eq!(sample, 0.0);
61+
/// ```
2862
pub fn new() -> Self {
2963
tracing::debug!("Creating Linux SpeakerStream");
3064
// For now, we'll create a mock implementation that generates silence
@@ -53,6 +87,20 @@ impl SpeakerStream {
5387
}
5488
}
5589

90+
/// Audio sample rate for the speaker stream.
91+
///
92+
/// The method reports the sample rate used for audio frames.
93+
///
94+
/// # Returns
95+
///
96+
/// The sample rate in hertz (48000).
97+
///
98+
/// # Examples
99+
///
100+
/// ```
101+
/// let stream = SpeakerStream::new();
102+
/// assert_eq!(stream.sample_rate(), 48000);
103+
/// ```
56104
pub fn sample_rate(&self) -> u32 {
57105
48000 // Standard sample rate
58106
}
@@ -61,6 +109,32 @@ impl SpeakerStream {
61109
impl Stream for SpeakerStream {
62110
type Item = f32;
63111

112+
/// Polls the stream for the next audio sample from the internal channel.
113+
///
114+
/// Returns `Poll::Ready(Some(sample))` when a sample is available, `Poll::Pending` and
115+
/// schedules the task to be woken when no sample is currently available, and
116+
/// `Poll::Ready(None)` when the producer side of the channel has been disconnected,
117+
/// signalling the end of the stream.
118+
///
119+
/// # Examples
120+
///
121+
/// ```
122+
/// use futures::stream::StreamExt;
123+
/// use std::pin::Pin;
124+
///
125+
/// // Create the speaker stream and pin it for polling.
126+
/// let stream = crate::speaker::linux::SpeakerStream::new();
127+
/// let mut pinned = Box::pin(stream);
128+
///
129+
/// // Poll the stream asynchronously to get the next sample.
130+
/// let sample = futures::executor::block_on(async {
131+
/// pinned.as_mut().next().await
132+
/// });
133+
///
134+
/// // The implementation sends silence (0.0) periodically, so we should get a sample
135+
/// // while the background producer thread is running.
136+
/// assert!(sample.is_some());
137+
/// ```
64138
fn poll_next(
65139
self: Pin<&mut Self>,
66140
cx: &mut Context<'_>,
@@ -78,9 +152,20 @@ impl Stream for SpeakerStream {
78152
}
79153

80154
impl Drop for SpeakerStream {
155+
/// Logs when the SpeakerStream is dropped and allows its background producer to terminate by closing the channel.
156+
///
157+
/// Dropping the stream closes its receiving endpoint; the background thread will observe the channel closure and exit.
158+
///
159+
/// # Examples
160+
///
161+
/// ```
162+
/// # use crates::audio::speaker::linux::SpeakerStream;
163+
/// let stream = SpeakerStream::new();
164+
/// drop(stream);
165+
/// ```
81166
fn drop(&mut self) {
82167
// The thread will automatically exit when the sender is dropped
83168
// and the receiver gets a Disconnected error
84169
tracing::debug!("Dropping SpeakerStream");
85170
}
86-
}
171+
}

0 commit comments

Comments
 (0)