Skip to content

Commit ea024e8

Browse files
committed
AudioNode::disconnect_from now panics when connection does not exist
This means we need to store the connections on the ConcreteBaseAudioContext as well. Fixes #471
1 parent 25f46ed commit ea024e8

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

src/context/concrete_base.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::spatial::AudioListenerParams;
1414
use crate::AudioListener;
1515

1616
use crossbeam_channel::{SendError, Sender};
17+
use std::collections::HashSet;
1718
use std::sync::atomic::{AtomicU64, AtomicU8, Ordering};
1819
use std::sync::{Arc, Mutex, RwLock, RwLockWriteGuard};
1920

@@ -109,6 +110,8 @@ struct ConcreteBaseAudioContextInner {
109110
event_loop: EventLoop,
110111
/// Sender for events that will be handled by the EventLoop
111112
event_send: Sender<EventDispatch>,
113+
/// Current audio graph connections
114+
connections: Mutex<HashSet<(AudioNodeId, usize, AudioNodeId, usize)>>,
112115
}
113116

114117
impl BaseAudioContext for ConcreteBaseAudioContext {
@@ -147,6 +150,7 @@ impl ConcreteBaseAudioContext {
147150
state,
148151
event_loop,
149152
event_send,
153+
connections: Mutex::new(HashSet::new()),
150154
};
151155
let base = Self {
152156
inner: Arc::new(base_inner),
@@ -393,6 +397,11 @@ impl ConcreteBaseAudioContext {
393397

394398
/// Connects the output of the `from` audio node to the input of the `to` audio node
395399
pub(crate) fn connect(&self, from: AudioNodeId, to: AudioNodeId, output: usize, input: usize) {
400+
self.inner
401+
.connections
402+
.lock()
403+
.unwrap()
404+
.insert((from, output, to, input));
396405
let message = ControlMessage::ConnectNode {
397406
from,
398407
to,
@@ -406,6 +415,8 @@ impl ConcreteBaseAudioContext {
406415
///
407416
/// It is not performed immediately as the `AudioNode` is not registered at this point.
408417
pub(super) fn queue_audio_param_connect(&self, param: &AudioParam, audio_node: AudioNodeId) {
418+
// no need to store these type of connections in self.inner.connections
419+
409420
let message = ControlMessage::ConnectNode {
410421
from: param.registration().id(),
411422
to: audio_node,
@@ -416,13 +427,32 @@ impl ConcreteBaseAudioContext {
416427
}
417428

418429
/// Disconnects all outputs of the audio node that go to a specific destination node.
430+
///
431+
/// # Panics
432+
///
433+
/// Panics if this node was not connected to the target node
419434
pub(crate) fn disconnect_from(&self, from: AudioNodeId, to: AudioNodeId) {
435+
// check if the node was connected, otherwise panic
436+
let mut connections = self.inner.connections.lock().unwrap();
437+
let prev_len = connections.len();
438+
connections.retain(|c| c.0 != from || c.2 != to);
439+
let len = connections.len();
440+
drop(connections);
441+
if prev_len == len {
442+
panic!("InvalidAccessError - attempting to disconnect unconnected nodes");
443+
}
444+
420445
let message = ControlMessage::DisconnectNode { from, to };
421446
self.send_control_msg(message);
422447
}
423448

424449
/// Disconnects all outgoing connections from the audio node.
425450
pub(crate) fn disconnect(&self, from: AudioNodeId) {
451+
self.inner
452+
.connections
453+
.lock()
454+
.unwrap()
455+
.retain(|c| c.0 != from);
426456
let message = ControlMessage::DisconnectAll { from };
427457
self.send_control_msg(message);
428458
}
@@ -470,6 +500,7 @@ impl ConcreteBaseAudioContext {
470500
#[cfg(test)]
471501
mod tests {
472502
use super::*;
503+
use crate::context::OfflineAudioContext;
473504

474505
#[test]
475506
fn test_provide_node_id() {
@@ -481,4 +512,29 @@ mod tests {
481512
assert_eq!(provider.get().0, 0); // reused
482513
assert_eq!(provider.get().0, 2); // newly assigned
483514
}
515+
516+
#[test]
517+
fn test_connect_disconnect() {
518+
let context = OfflineAudioContext::new(1, 128, 48000.);
519+
let node1 = context.create_constant_source();
520+
let node2 = context.create_gain();
521+
522+
node1.disconnect(); // never panic for plain disconnect calls
523+
524+
node1.connect(&node2);
525+
node1.disconnect();
526+
527+
node1.connect(&node2);
528+
node1.disconnect_from(&node2);
529+
}
530+
531+
#[test]
532+
#[should_panic]
533+
fn test_disconnect_not_existing() {
534+
let context = OfflineAudioContext::new(1, 128, 48000.);
535+
let node1 = context.create_constant_source();
536+
let node2 = context.create_gain();
537+
538+
node1.disconnect_from(&node2);
539+
}
484540
}

0 commit comments

Comments
 (0)