fission_shell_winit/
microphone.rs1use fission_core::{
2 MicrophoneAvailability, MicrophoneCapture, MicrophoneCaptureRequest, MicrophoneDevice,
3 MicrophoneError, MicrophonePermission, MicrophonePermissionRequest, CANCEL_MICROPHONE_CAPTURE,
4 CAPTURE_MICROPHONE_AUDIO, GET_MICROPHONE_AVAILABILITY, REQUEST_MICROPHONE_PERMISSION,
5};
6use fission_shell::async_host::AsyncRegistry;
7use std::sync::Arc;
8
9pub trait MicrophoneHost: Send + Sync + 'static {
11 fn availability(&self) -> Result<MicrophoneAvailability, MicrophoneError>;
13 fn request_permission(
15 &self,
16 request: MicrophonePermissionRequest,
17 ) -> Result<MicrophonePermission, MicrophoneError>;
18 fn capture_audio(
20 &self,
21 request: MicrophoneCaptureRequest,
22 ) -> Result<MicrophoneCapture, MicrophoneError>;
23 fn cancel_capture(&self) -> Result<(), MicrophoneError>;
25}
26
27#[derive(Debug, Default)]
28pub struct UnsupportedMicrophoneHost;
29
30impl MicrophoneHost for UnsupportedMicrophoneHost {
31 fn availability(&self) -> Result<MicrophoneAvailability, MicrophoneError> {
32 Ok(MicrophoneAvailability {
33 permission: MicrophonePermission::Denied,
34 devices: Vec::new(),
35 })
36 }
37
38 fn request_permission(
39 &self,
40 _request: MicrophonePermissionRequest,
41 ) -> Result<MicrophonePermission, MicrophoneError> {
42 Err(MicrophoneError::unsupported("request_permission"))
43 }
44
45 fn capture_audio(
46 &self,
47 _request: MicrophoneCaptureRequest,
48 ) -> Result<MicrophoneCapture, MicrophoneError> {
49 Err(MicrophoneError::unsupported("capture_audio"))
50 }
51
52 fn cancel_capture(&self) -> Result<(), MicrophoneError> {
53 Err(MicrophoneError::unsupported("cancel_capture"))
54 }
55}
56
57#[derive(Debug, Clone)]
58pub struct MemoryMicrophoneHost {
59 availability: MicrophoneAvailability,
60 capture: MicrophoneCapture,
61}
62
63impl MemoryMicrophoneHost {
64 pub fn new(availability: MicrophoneAvailability, capture: MicrophoneCapture) -> Self {
65 Self {
66 availability,
67 capture,
68 }
69 }
70}
71
72impl Default for MemoryMicrophoneHost {
73 fn default() -> Self {
74 Self::new(
75 MicrophoneAvailability {
76 permission: MicrophonePermission::Granted,
77 devices: vec![MicrophoneDevice {
78 id: "memory-mic".into(),
79 label: Some("Memory microphone".into()),
80 is_default: true,
81 }],
82 },
83 MicrophoneCapture {
84 bytes: vec![0, 1, 2, 3],
85 content_type: "audio/pcm".into(),
86 sample_rate_hz: 48_000,
87 channels: 1,
88 duration_ms: 1_000,
89 device_id: Some("memory-mic".into()),
90 },
91 )
92 }
93}
94
95impl MicrophoneHost for MemoryMicrophoneHost {
96 fn availability(&self) -> Result<MicrophoneAvailability, MicrophoneError> {
97 Ok(self.availability.clone())
98 }
99
100 fn request_permission(
101 &self,
102 _request: MicrophonePermissionRequest,
103 ) -> Result<MicrophonePermission, MicrophoneError> {
104 Ok(self.availability.permission)
105 }
106
107 fn capture_audio(
108 &self,
109 _request: MicrophoneCaptureRequest,
110 ) -> Result<MicrophoneCapture, MicrophoneError> {
111 Ok(self.capture.clone())
112 }
113
114 fn cancel_capture(&self) -> Result<(), MicrophoneError> {
115 Ok(())
116 }
117}
118
119pub(crate) fn register_microphone_capabilities(
120 async_registry: &mut AsyncRegistry,
121 host: Arc<dyn MicrophoneHost>,
122) {
123 let availability_host = host.clone();
124 async_registry.register_operation_capability(GET_MICROPHONE_AVAILABILITY, move |(), _| {
125 let host = availability_host.clone();
126 async move { host.availability() }
127 });
128
129 let permission_host = host.clone();
130 async_registry.register_operation_capability(
131 REQUEST_MICROPHONE_PERMISSION,
132 move |request, _| {
133 let host = permission_host.clone();
134 async move { host.request_permission(request) }
135 },
136 );
137
138 let capture_host = host.clone();
139 async_registry.register_operation_capability(CAPTURE_MICROPHONE_AUDIO, move |request, _| {
140 let host = capture_host.clone();
141 async move { host.capture_audio(request) }
142 });
143
144 async_registry.register_operation_capability(CANCEL_MICROPHONE_CAPTURE, move |(), _| {
145 let host = host.clone();
146 async move { host.cancel_capture() }
147 });
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153
154 #[test]
155 fn unsupported_host_reports_errors() {
156 let host = UnsupportedMicrophoneHost;
157 assert!(host
158 .capture_audio(MicrophoneCaptureRequest::default())
159 .is_err());
160 }
161
162 #[test]
163 fn memory_host_returns_audio_capture() {
164 let host = MemoryMicrophoneHost::default();
165 let availability = host.availability().unwrap();
166 assert_eq!(availability.permission, MicrophonePermission::Granted);
167
168 let capture = host
169 .capture_audio(MicrophoneCaptureRequest::default())
170 .unwrap();
171 assert_eq!(capture.content_type, "audio/pcm");
172 assert_eq!(capture.sample_rate_hz, 48_000);
173 }
174}