1#![warn(missing_docs)]
28
29pub mod backend;
30pub mod chunk_ring;
31pub mod clock;
32pub mod diagnostics;
33pub mod error_context;
34mod errors;
35mod loss;
36pub mod normalizer;
37pub mod process_list;
38pub mod quant;
39pub mod raw_ring;
40pub mod secondary_ring;
41pub mod startup;
42pub mod types;
43mod whisper_error;
44
45pub use backend::{CaptureBackend, RawSink};
47pub use chunk_ring::{chunk_ring, ChunkConsumer, ChunkProducer};
48pub use clock::{monotonic_now_ns, ClockNormalizer};
49pub use normalizer::{InnerProcessor, NormalizedChunk, Normalizer, CHUNK_FRAMES};
50pub use quant::quantize_i16;
51pub use raw_ring::{raw_ring, RawConsumer, RawProducer};
52pub use secondary_ring::{secondary_chunk_ring, SecondaryChunkConsumer, SecondaryChunkProducer};
53pub use types::{
54 AudioChunk, AudioLoss, AudioPath, ChunkFlags, DefaultDeviceKind, DeviceEvent, DeviceInfo,
55 Error, ErrorContext, ErrorGroup, ErrorKind, Event, LossReason, MixLane, NativeStatus,
56 Operation, OutputFormat, OutputTap, Permission, ProcessInfo, Result, SecondaryChunk,
57 ShutdownReport, SourceKind, StreamConfig, CHANNELS, SAMPLE_RATE,
58};
59
60pub use diagnostics::CaptureDiagnostics;
61pub use startup::StartupDropReason;
62pub use whisper_error::WhisperCode;
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub enum ChunkMsOption {
67 SnakeCase,
69 JavaScript,
71}
72pub fn chunk_ms_error(option: ChunkMsOption) -> Error {
74 let name = match option {
75 ChunkMsOption::SnakeCase => "chunk_ms",
76 ChunkMsOption::JavaScript => "chunkMs",
77 };
78 Error::InvalidArg(format!(
79 "capture uses the canonical 20 ms frame contract; set {name} to 20"
80 ))
81}
82pub fn validate_chunk_ms(chunk_ms: u32) -> Result<()> {
84 if chunk_ms == 20 {
85 Ok(())
86 } else {
87 Err(chunk_ms_error(ChunkMsOption::SnakeCase))
88 }
89}
90#[cfg(test)]
91mod chunk_contract_tests {
92 #[test]
93 fn chunk_duration_rejection_explains_contract_and_remedy() {
94 let error = super::validate_chunk_ms(10).expect_err("noncanonical duration must fail");
95 let message = error.to_string();
96 assert!(
97 message.contains("canonical 20 ms frame contract"),
98 "{message}"
99 );
100 assert!(message.contains("set chunk_ms to 20"), "{message}");
101 assert!(super::validate_chunk_ms(20).is_ok());
102 }
103}
104
105#[cfg(test)]
106mod chunk_option_tests {
107 #[test]
108 fn javascript_chunk_duration_uses_its_public_option_spelling() {
109 let error = super::chunk_ms_error(super::ChunkMsOption::JavaScript);
110 let message = error.to_string();
111 assert!(message.contains("set chunkMs to 20"), "{message}");
112 assert!(message.contains("canonical 20 ms frame contract"));
113 }
114}