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