use std::{any::Any, ops::Range};
mod base;
pub use base::*;
mod concrete_base;
pub use concrete_base::*;
mod offline;
pub use offline::*;
mod online;
pub use online::*;
pub(crate) const DESTINATION_NODE_ID: AudioNodeId = AudioNodeId(0);
const LISTENER_NODE_ID: AudioNodeId = AudioNodeId(1);
const LISTENER_PARAM_IDS: Range<u64> = 2..11;
pub(crate) const LISTENER_AUDIO_PARAM_IDS: [AudioParamId; 9] = [
AudioParamId(2),
AudioParamId(3),
AudioParamId(4),
AudioParamId(5),
AudioParamId(6),
AudioParamId(7),
AudioParamId(8),
AudioParamId(9),
AudioParamId(10),
];
#[derive(Hash, PartialEq, Eq, Clone, Copy)]
pub(crate) struct AudioNodeId(pub u64);
impl std::fmt::Debug for AudioNodeId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "AudioNodeId({})", self.0)
}
}
#[derive(Debug)]
pub struct AudioParamId(u64);
impl From<&AudioParamId> for AudioNodeId {
fn from(i: &AudioParamId) -> Self {
Self(i.0)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum AudioContextState {
Suspended,
Running,
Closed,
}
impl From<u8> for AudioContextState {
fn from(value: u8) -> Self {
match value {
0 => Self::Suspended,
1 => Self::Running,
2 => Self::Closed,
_ => unreachable!(),
}
}
}
pub struct AudioContextRegistration {
context: ConcreteBaseAudioContext,
id: AudioNodeId,
}
impl std::fmt::Debug for AudioContextRegistration {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AudioContextRegistration")
.field("id", &self.id)
.field(
"context",
&format!("BaseAudioContext@{}", self.context.address()),
)
.finish()
}
}
impl AudioContextRegistration {
#[must_use]
pub(crate) fn id(&self) -> AudioNodeId {
self.id
}
#[must_use]
pub(crate) fn context(&self) -> &ConcreteBaseAudioContext {
&self.context
}
pub(crate) fn post_message<M: Any + Send + 'static>(&self, msg: M) {
let wrapped = crate::message::ControlMessage::NodeMessage {
id: self.id,
msg: llq::Node::new(Box::new(msg)),
};
self.context.send_control_msg(wrapped);
}
}
impl Drop for AudioContextRegistration {
fn drop(&mut self) {
self.context.mark_node_dropped(self.id);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::node::AudioNode;
fn require_send_sync_static<T: Send + Sync + 'static>(_: T) {}
#[test]
fn test_audio_context_registration_traits() {
let context = OfflineAudioContext::new(1, 1, 44100.);
let registration = context.mock_registration();
require_send_sync_static(registration);
}
#[test]
fn test_offline_audio_context_send_sync() {
let context = OfflineAudioContext::new(1, 1, 44100.);
require_send_sync_static(context);
}
#[test]
fn test_online_audio_context_send_sync() {
let options = AudioContextOptions {
sink_id: "none".into(),
..AudioContextOptions::default()
};
let context = AudioContext::new(options);
require_send_sync_static(context);
}
#[test]
fn test_context_equals() {
let context = OfflineAudioContext::new(1, 48000, 96000.);
let dest = context.destination();
assert!(dest.context() == context.base());
}
}