Skip to content

Commit 6cfcae6

Browse files
committed
Refactor out AudioNodeId issuer for readability
1 parent 0a3a27f commit 6cfcae6

File tree

1 file changed

+55
-14
lines changed

1 file changed

+55
-14
lines changed

src/context/concrete_base.rs

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,34 @@ use crossbeam_channel::{Receiver, SendError, Sender};
1717
use std::sync::atomic::{AtomicU64, AtomicU8, Ordering};
1818
use std::sync::{Arc, Mutex, RwLock, RwLockWriteGuard};
1919

20+
/// This struct assigns new [`AudioNodeId`]s for [`AudioNode`]s
21+
///
22+
/// It reuses the ids of decommissioned nodes to prevent unbounded growth of the audio graphs node
23+
/// list (which is stored in a Vec indexed by the AudioNodeId).
24+
struct AudioNodeIdIssuer {
25+
/// incrementing id
26+
id_inc: AtomicU64,
27+
/// receiver for decommissioned AudioNodeIds, which can be reused
28+
id_consumer: Mutex<llq::Consumer<AudioNodeId>>,
29+
}
30+
31+
impl AudioNodeIdIssuer {
32+
fn new(id_consumer: llq::Consumer<AudioNodeId>) -> Self {
33+
Self {
34+
id_inc: AtomicU64::new(0),
35+
id_consumer: Mutex::new(id_consumer),
36+
}
37+
}
38+
39+
fn issue(&self) -> AudioNodeId {
40+
if let Some(available_id) = self.id_consumer.lock().unwrap().pop() {
41+
llq::Node::into_inner(available_id)
42+
} else {
43+
AudioNodeId(self.id_inc.fetch_add(1, Ordering::Relaxed))
44+
}
45+
}
46+
}
47+
2048
/// The struct that corresponds to the Javascript `BaseAudioContext` object.
2149
///
2250
/// This object is returned from the `base()` method on
@@ -47,10 +75,8 @@ struct ConcreteBaseAudioContextInner {
4775
sample_rate: f32,
4876
/// max number of speaker output channels
4977
max_channel_count: usize,
50-
/// incrementing id to assign to audio nodes
51-
node_id_inc: AtomicU64,
52-
/// receiver for decommissioned AudioNodeIds, which can be reused
53-
node_id_consumer: Mutex<llq::Consumer<AudioNodeId>>,
78+
/// issuer for new AudioNodeIds
79+
audio_node_id_issuer: AudioNodeIdIssuer,
5480
/// destination node's current channel count
5581
destination_channel_config: ChannelConfig,
5682
/// message channel from control to render thread
@@ -85,13 +111,8 @@ impl BaseAudioContext for ConcreteBaseAudioContext {
85111
&self,
86112
f: F,
87113
) -> T {
88-
// create unique identifier for this node
89-
let id = if let Some(available_id) = self.inner.node_id_consumer.lock().unwrap().pop() {
90-
llq::Node::into_inner(available_id)
91-
} else {
92-
AudioNodeId(self.inner.node_id_inc.fetch_add(1, Ordering::Relaxed))
93-
};
94-
114+
// create a unique id for this node
115+
let id = self.inner.audio_node_id_issuer.issue();
95116
let registration = AudioContextRegistration {
96117
id,
97118
context: self.clone(),
@@ -141,13 +162,14 @@ impl ConcreteBaseAudioContext {
141162
Some((send, recv)) => (Some(send), Some(recv)),
142163
};
143164

165+
let audio_node_id_issuer = AudioNodeIdIssuer::new(node_id_consumer);
166+
144167
let base_inner = ConcreteBaseAudioContextInner {
145168
sample_rate,
146169
max_channel_count,
147170
render_channel: RwLock::new(render_channel),
148171
queued_messages: Mutex::new(Vec::new()),
149-
node_id_inc: AtomicU64::new(0),
150-
node_id_consumer: Mutex::new(node_id_consumer),
172+
audio_node_id_issuer,
151173
destination_channel_config: ChannelConfigOptions::default().into(),
152174
frames_played,
153175
queued_audio_listener_msgs: Mutex::new(Vec::new()),
@@ -211,7 +233,10 @@ impl ConcreteBaseAudioContext {
211233

212234
// Validate if the hardcoded node IDs line up
213235
debug_assert_eq!(
214-
base.inner.node_id_inc.load(Ordering::Relaxed),
236+
base.inner
237+
.audio_node_id_issuer
238+
.id_inc
239+
.load(Ordering::Relaxed),
215240
LISTENER_PARAM_IDS.end,
216241
);
217242

@@ -429,3 +454,19 @@ impl ConcreteBaseAudioContext {
429454
self.inner.event_loop.clear_handler(event);
430455
}
431456
}
457+
458+
#[cfg(test)]
459+
mod tests {
460+
use super::*;
461+
462+
#[test]
463+
fn test_issue_node_id() {
464+
let (mut id_producer, id_consumer) = llq::Queue::new().split();
465+
let issuer = AudioNodeIdIssuer::new(id_consumer);
466+
assert_eq!(issuer.issue().0, 0); // newly assigned
467+
assert_eq!(issuer.issue().0, 1); // newly assigned
468+
id_producer.push(llq::Node::new(AudioNodeId(0)));
469+
assert_eq!(issuer.issue().0, 0); // reused
470+
assert_eq!(issuer.issue().0, 2); // newly assigned
471+
}
472+
}

0 commit comments

Comments
 (0)