1#[cfg(feature = "diagnostics")]
2use crate::context::AudioContextDiagnostics;
3use crate::context::ConcreteBaseAudioContext;
4use crate::context::{AudioContextState, AudioNodeId};
5use crate::{AudioBuffer, AudioRenderCapacityEvent};
6
7use std::any::Any;
8use std::collections::HashMap;
9use std::hash::Hash;
10use std::ops::ControlFlow;
11use std::sync::{Arc, Mutex};
12
13use crossbeam_channel::Receiver;
14
15#[derive(Debug, Clone)]
17#[non_exhaustive]
18pub struct Event {
19 pub type_: &'static str,
20}
21
22#[derive(Hash, Eq, PartialEq, Debug)]
23pub(crate) enum EventType {
24 Ended(AudioNodeId),
25 SinkChange,
26 StateChange,
27 RenderCapacity,
28 ProcessorError(AudioNodeId),
29 #[cfg(feature = "diagnostics")]
30 Diagnostics,
31 Message(AudioNodeId),
32 Complete,
33 AudioProcessing(AudioNodeId),
34}
35
36#[non_exhaustive]
38#[derive(Debug)]
39pub struct ErrorEvent {
40 pub message: String,
42 pub error: Box<dyn Any + Send>,
44 pub event: Event,
46}
47
48#[non_exhaustive]
50#[derive(Debug)]
51pub struct AudioProcessingEvent {
52 pub input_buffer: AudioBuffer,
54 pub output_buffer: AudioBuffer,
56 pub playback_time: f64,
59 pub(crate) registration: Option<(ConcreteBaseAudioContext, AudioNodeId)>,
60}
61
62impl Drop for AudioProcessingEvent {
63 fn drop(&mut self) {
64 if let Some((context, id)) = self.registration.take() {
65 let wrapped = crate::message::ControlMessage::NodeMessage {
66 id,
67 msg: llq::Node::new(Box::new(self.output_buffer.clone())),
68 };
69 context.send_control_msg(wrapped);
70 }
71 }
72}
73
74#[non_exhaustive]
76#[derive(Debug)]
77pub struct OfflineAudioCompletionEvent {
78 pub rendered_buffer: AudioBuffer,
80 pub event: Event,
82}
83
84#[derive(Debug)]
85pub(crate) enum EventPayload {
86 None,
87 RenderCapacity(AudioRenderCapacityEvent),
88 ProcessorError(ErrorEvent),
89 #[cfg(feature = "diagnostics")]
90 Diagnostics(AudioContextDiagnostics),
91 Message(Box<dyn Any + Send + 'static>),
92 AudioContextState(AudioContextState),
93 Complete(AudioBuffer),
94 AudioProcessing(AudioProcessingEvent),
95}
96
97#[derive(Debug)]
98pub(crate) struct EventDispatch {
99 type_: EventType,
100 payload: EventPayload,
101}
102
103impl EventDispatch {
104 pub fn ended(id: AudioNodeId) -> Self {
105 EventDispatch {
106 type_: EventType::Ended(id),
107 payload: EventPayload::None,
108 }
109 }
110
111 pub fn sink_change() -> Self {
112 EventDispatch {
113 type_: EventType::SinkChange,
114 payload: EventPayload::None,
115 }
116 }
117
118 pub fn state_change(state: AudioContextState) -> Self {
119 EventDispatch {
120 type_: EventType::StateChange,
121 payload: EventPayload::AudioContextState(state),
122 }
123 }
124
125 pub fn render_capacity(value: AudioRenderCapacityEvent) -> Self {
126 EventDispatch {
127 type_: EventType::RenderCapacity,
128 payload: EventPayload::RenderCapacity(value),
129 }
130 }
131
132 pub fn processor_error(id: AudioNodeId, value: ErrorEvent) -> Self {
133 EventDispatch {
134 type_: EventType::ProcessorError(id),
135 payload: EventPayload::ProcessorError(value),
136 }
137 }
138
139 #[cfg(feature = "diagnostics")]
140 pub fn diagnostics(value: AudioContextDiagnostics) -> Self {
141 EventDispatch {
142 type_: EventType::Diagnostics,
143 payload: EventPayload::Diagnostics(value),
144 }
145 }
146
147 pub fn message(id: AudioNodeId, value: Box<dyn Any + Send + 'static>) -> Self {
148 EventDispatch {
149 type_: EventType::Message(id),
150 payload: EventPayload::Message(value),
151 }
152 }
153
154 pub fn complete(buffer: AudioBuffer) -> Self {
155 EventDispatch {
156 type_: EventType::Complete,
157 payload: EventPayload::Complete(buffer),
158 }
159 }
160
161 pub fn audio_processing(id: AudioNodeId, value: AudioProcessingEvent) -> Self {
162 EventDispatch {
163 type_: EventType::AudioProcessing(id),
164 payload: EventPayload::AudioProcessing(value),
165 }
166 }
167}
168
169pub(crate) enum EventHandler {
170 Once(Box<dyn FnOnce(EventPayload) + Send + 'static>),
171 Multiple(Box<dyn FnMut(EventPayload) + Send + 'static>),
172}
173
174#[derive(Clone)]
175pub(crate) struct EventLoop {
176 event_recv: Receiver<EventDispatch>,
177 event_handlers: Arc<Mutex<HashMap<EventType, EventHandler>>>,
178}
179
180impl EventLoop {
181 pub fn new(event_recv: Receiver<EventDispatch>) -> Self {
182 Self {
183 event_recv,
184 event_handlers: Default::default(),
185 }
186 }
187
188 fn handle_event(&self, mut event: EventDispatch) -> ControlFlow<()> {
189 let mut result = ControlFlow::Continue(());
191 if matches!(
192 event.payload,
193 EventPayload::AudioContextState(AudioContextState::Closed)
194 ) {
195 event.payload = EventPayload::None; result = ControlFlow::Break(());
197 }
198
199 #[cfg(test)]
202 if let EventPayload::ProcessorError(e) = event.payload {
203 panic!("Rethrowing exception during tests: {:?}", e);
204 }
205
206 let mut event_handler_lock = self.event_handlers.lock().unwrap();
207 let callback_option = event_handler_lock.remove(&event.type_);
208 drop(event_handler_lock); if let Some(callback) = callback_option {
211 match callback {
212 EventHandler::Once(f) => (f)(event.payload),
213 EventHandler::Multiple(mut f) => {
214 (f)(event.payload);
215 self.event_handlers
216 .lock()
217 .unwrap()
218 .insert(event.type_, EventHandler::Multiple(f));
219 }
220 };
221 }
222
223 result
224 }
225
226 #[inline(always)]
227 pub fn handle_pending_events(&self) -> bool {
228 let mut events_were_handled = false;
229 for event in self.event_recv.try_iter() {
231 let _ = self.handle_event(event);
233 events_were_handled = true;
234 }
235 events_were_handled
236 }
237
238 pub fn run_in_thread(&self) {
239 log::debug!("Entering event thread");
240
241 let self_clone = self.clone();
243
244 std::thread::spawn(move || {
245 for event in self_clone.event_recv.iter() {
247 let result = self_clone.handle_event(event);
248 if result.is_break() {
249 break;
250 }
251 }
252
253 log::debug!("Event loop has terminated");
254 });
255 }
256
257 pub fn set_handler(&self, event: EventType, callback: EventHandler) {
258 self.event_handlers.lock().unwrap().insert(event, callback);
259 }
260
261 pub fn clear_handler(&self, event: EventType) {
262 self.event_handlers.lock().unwrap().remove(&event);
263 }
264}