1use crate::capability::{CapabilityType, OperationCapability};
4use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
7pub enum MicrophonePermission {
8 #[default]
9 Unknown,
10 Granted,
11 Denied,
12 Restricted,
13}
14
15#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
16pub enum AudioSampleFormat {
17 U8,
18 I16,
19 #[default]
20 F32,
21}
22
23#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
24pub struct MicrophoneDevice {
25 pub id: String,
26 pub label: Option<String>,
27 pub is_default: bool,
28}
29
30#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
31pub struct MicrophoneAvailability {
32 pub permission: MicrophonePermission,
33 pub devices: Vec<MicrophoneDevice>,
34}
35
36#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
37pub struct MicrophonePermissionRequest {
38 pub reason: Option<String>,
39}
40
41#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
42pub struct MicrophoneCaptureRequest {
43 pub device_id: Option<String>,
44 pub duration_ms: u64,
45 pub sample_rate_hz: Option<u32>,
46 pub channels: Option<u16>,
47 pub sample_format: AudioSampleFormat,
48}
49
50impl Default for MicrophoneCaptureRequest {
51 fn default() -> Self {
52 Self {
53 device_id: None,
54 duration_ms: 1_000,
55 sample_rate_hz: None,
56 channels: None,
57 sample_format: AudioSampleFormat::F32,
58 }
59 }
60}
61
62#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
63pub struct MicrophoneCapture {
64 pub bytes: Vec<u8>,
65 pub content_type: String,
66 pub sample_rate_hz: u32,
67 pub channels: u16,
68 pub duration_ms: u64,
69 pub device_id: Option<String>,
70}
71
72#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
73pub struct MicrophoneError {
74 pub code: String,
75 pub message: String,
76}
77
78impl MicrophoneError {
79 pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
86 Self {
87 code: code.into(),
88 message: message.into(),
89 }
90 }
91
92 pub fn unsupported(operation: impl Into<String>) -> Self {
98 Self::new(
99 "unsupported",
100 format!(
101 "microphone operation `{}` is not supported by this host",
102 operation.into()
103 ),
104 )
105 }
106}
107
108pub struct GetMicrophoneAvailabilityCapability;
109impl OperationCapability for GetMicrophoneAvailabilityCapability {
110 type Request = ();
111 type Ok = MicrophoneAvailability;
112 type Err = MicrophoneError;
113}
114
115pub struct RequestMicrophonePermissionCapability;
116impl OperationCapability for RequestMicrophonePermissionCapability {
117 type Request = MicrophonePermissionRequest;
118 type Ok = MicrophonePermission;
119 type Err = MicrophoneError;
120}
121
122pub struct CaptureMicrophoneAudioCapability;
123impl OperationCapability for CaptureMicrophoneAudioCapability {
124 type Request = MicrophoneCaptureRequest;
125 type Ok = MicrophoneCapture;
126 type Err = MicrophoneError;
127}
128
129pub struct CancelMicrophoneCaptureCapability;
130impl OperationCapability for CancelMicrophoneCaptureCapability {
131 type Request = ();
132 type Ok = ();
133 type Err = MicrophoneError;
134}
135
136pub const GET_MICROPHONE_AVAILABILITY: CapabilityType<GetMicrophoneAvailabilityCapability> =
137 CapabilityType::new("fission.microphone.get_availability");
138pub const REQUEST_MICROPHONE_PERMISSION: CapabilityType<RequestMicrophonePermissionCapability> =
139 CapabilityType::new("fission.microphone.request_permission");
140pub const CAPTURE_MICROPHONE_AUDIO: CapabilityType<CaptureMicrophoneAudioCapability> =
141 CapabilityType::new("fission.microphone.capture_audio");
142pub const CANCEL_MICROPHONE_CAPTURE: CapabilityType<CancelMicrophoneCaptureCapability> =
143 CapabilityType::new("fission.microphone.cancel_capture");
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148
149 #[test]
150 fn microphone_capture_request_round_trips() {
151 let request = MicrophoneCaptureRequest {
152 device_id: Some("default".into()),
153 duration_ms: 5_000,
154 sample_rate_hz: Some(48_000),
155 channels: Some(2),
156 sample_format: AudioSampleFormat::I16,
157 };
158
159 let bytes = serde_json::to_vec(&request).unwrap();
160 let decoded: MicrophoneCaptureRequest = serde_json::from_slice(&bytes).unwrap();
161
162 assert_eq!(decoded, request);
163 }
164}