web_audio_api/
events.rs

1use crate::context::ConcreteBaseAudioContext;
2use crate::context::{AudioContextState, AudioNodeId};
3use crate::{AudioBuffer, AudioRenderCapacityEvent};
4
5use std::any::Any;
6use std::collections::HashMap;
7use std::hash::Hash;
8use std::ops::ControlFlow;
9use std::sync::{Arc, Mutex};
10
11use crossbeam_channel::Receiver;
12
13/// The Event interface
14#[derive(Debug, Clone)]
15#[non_exhaustive]
16pub struct Event {
17    pub type_: &'static str,
18}
19
20#[derive(Hash, Eq, PartialEq, Debug)]
21pub(crate) enum EventType {
22    Ended(AudioNodeId),
23    SinkChange,
24    StateChange,
25    RenderCapacity,
26    ProcessorError(AudioNodeId),
27    Diagnostics,
28    Message(AudioNodeId),
29    Complete,
30    AudioProcessing(AudioNodeId),
31}
32
33/// The Error Event interface
34#[non_exhaustive]
35#[derive(Debug)]
36pub struct ErrorEvent {
37    /// The error message
38    pub message: String,
39    /// The object with which panic was originally invoked.
40    pub error: Box<dyn Any + Send>,
41    /// Inherits from this base Event
42    pub event: Event,
43}
44
45/// The AudioProcessingEvent interface
46#[non_exhaustive]
47#[derive(Debug)]
48pub struct AudioProcessingEvent {
49    /// The input buffer
50    pub input_buffer: AudioBuffer,
51    /// The output buffer
52    pub output_buffer: AudioBuffer,
53    /// The time when the audio will be played in the same time coordinate system as the
54    /// AudioContext's currentTime.
55    pub playback_time: f64,
56    pub(crate) registration: Option<(ConcreteBaseAudioContext, AudioNodeId)>,
57}
58
59impl Drop for AudioProcessingEvent {
60    fn drop(&mut self) {
61        if let Some((context, id)) = self.registration.take() {
62            let wrapped = crate::message::ControlMessage::NodeMessage {
63                id,
64                msg: llq::Node::new(Box::new(self.output_buffer.clone())),
65            };
66            context.send_control_msg(wrapped);
67        }
68    }
69}
70
71/// The OfflineAudioCompletionEvent Event interface
72#[non_exhaustive]
73#[derive(Debug)]
74pub struct OfflineAudioCompletionEvent {
75    /// The rendered AudioBuffer
76    pub rendered_buffer: AudioBuffer,
77    /// Inherits from this base Event
78    pub event: Event,
79}
80
81#[derive(Debug)]
82pub(crate) enum EventPayload {
83    None,
84    RenderCapacity(AudioRenderCapacityEvent),
85    ProcessorError(ErrorEvent),
86    Diagnostics(Vec<u8>),
87    Message(Box<dyn Any + Send + 'static>),
88    AudioContextState(AudioContextState),
89    Complete(AudioBuffer),
90    AudioProcessing(AudioProcessingEvent),
91}
92
93#[derive(Debug)]
94pub(crate) struct EventDispatch {
95    type_: EventType,
96    payload: EventPayload,
97}
98
99impl EventDispatch {
100    pub fn ended(id: AudioNodeId) -> Self {
101        EventDispatch {
102            type_: EventType::Ended(id),
103            payload: EventPayload::None,
104        }
105    }
106
107    pub fn sink_change() -> Self {
108        EventDispatch {
109            type_: EventType::SinkChange,
110            payload: EventPayload::None,
111        }
112    }
113
114    pub fn state_change(state: AudioContextState) -> Self {
115        EventDispatch {
116            type_: EventType::StateChange,
117            payload: EventPayload::AudioContextState(state),
118        }
119    }
120
121    pub fn render_capacity(value: AudioRenderCapacityEvent) -> Self {
122        EventDispatch {
123            type_: EventType::RenderCapacity,
124            payload: EventPayload::RenderCapacity(value),
125        }
126    }
127
128    pub fn processor_error(id: AudioNodeId, value: ErrorEvent) -> Self {
129        EventDispatch {
130            type_: EventType::ProcessorError(id),
131            payload: EventPayload::ProcessorError(value),
132        }
133    }
134
135    pub fn diagnostics(value: Vec<u8>) -> Self {
136        EventDispatch {
137            type_: EventType::Diagnostics,
138            payload: EventPayload::Diagnostics(value),
139        }
140    }
141
142    pub fn message(id: AudioNodeId, value: Box<dyn Any + Send + 'static>) -> Self {
143        EventDispatch {
144            type_: EventType::Message(id),
145            payload: EventPayload::Message(value),
146        }
147    }
148
149    pub fn complete(buffer: AudioBuffer) -> Self {
150        EventDispatch {
151            type_: EventType::Complete,
152            payload: EventPayload::Complete(buffer),
153        }
154    }
155
156    pub fn audio_processing(id: AudioNodeId, value: AudioProcessingEvent) -> Self {
157        EventDispatch {
158            type_: EventType::AudioProcessing(id),
159            payload: EventPayload::AudioProcessing(value),
160        }
161    }
162}
163
164pub(crate) enum EventHandler {
165    Once(Box<dyn FnOnce(EventPayload) + Send + 'static>),
166    Multiple(Box<dyn FnMut(EventPayload) + Send + 'static>),
167}
168
169#[derive(Clone)]
170pub(crate) struct EventLoop {
171    event_recv: Receiver<EventDispatch>,
172    event_handlers: Arc<Mutex<HashMap<EventType, EventHandler>>>,
173}
174
175impl EventLoop {
176    pub fn new(event_recv: Receiver<EventDispatch>) -> Self {
177        Self {
178            event_recv,
179            event_handlers: Default::default(),
180        }
181    }
182
183    fn handle_event(&self, mut event: EventDispatch) -> ControlFlow<()> {
184        // Terminate the event loop when the audio context is closing
185        let mut result = ControlFlow::Continue(());
186        if matches!(
187            event.payload,
188            EventPayload::AudioContextState(AudioContextState::Closed)
189        ) {
190            event.payload = EventPayload::None; // the statechange handler takes no argument
191            result = ControlFlow::Break(());
192        }
193
194        // In unit tests, we rethrow panics to avoid missing critical node exceptions
195        // https://github.com/orottier/web-audio-api-rs/issues/522
196        #[cfg(test)]
197        if let EventPayload::ProcessorError(e) = event.payload {
198            panic!("Rethrowing exception during tests: {:?}", e);
199        }
200
201        let mut event_handler_lock = self.event_handlers.lock().unwrap();
202        let callback_option = event_handler_lock.remove(&event.type_);
203        drop(event_handler_lock); // release Mutex while running callback
204
205        if let Some(callback) = callback_option {
206            match callback {
207                EventHandler::Once(f) => (f)(event.payload),
208                EventHandler::Multiple(mut f) => {
209                    (f)(event.payload);
210                    self.event_handlers
211                        .lock()
212                        .unwrap()
213                        .insert(event.type_, EventHandler::Multiple(f));
214                }
215            };
216        }
217
218        result
219    }
220
221    #[inline(always)]
222    pub fn handle_pending_events(&self) -> bool {
223        let mut events_were_handled = false;
224        // try_iter will yield all pending events, but does not block
225        for event in self.event_recv.try_iter() {
226            self.handle_event(event);
227            events_were_handled = true;
228        }
229        events_were_handled
230    }
231
232    pub fn run_in_thread(&self) {
233        log::debug!("Entering event thread");
234
235        // split borrows to help compiler
236        let self_clone = self.clone();
237
238        std::thread::spawn(move || {
239            // This thread is dedicated to event handling, so we can block
240            for event in self_clone.event_recv.iter() {
241                let result = self_clone.handle_event(event);
242                if result.is_break() {
243                    break;
244                }
245            }
246
247            log::debug!("Event loop has terminated");
248        });
249    }
250
251    pub fn set_handler(&self, event: EventType, callback: EventHandler) {
252        self.event_handlers.lock().unwrap().insert(event, callback);
253    }
254
255    pub fn clear_handler(&self, event: EventType) {
256        self.event_handlers.lock().unwrap().remove(&event);
257    }
258}