Skip to content

Commit 9a9daa7

Browse files
authored
Merge pull request #370 from orottier/bugfix/369
Fix #369 - AudioListener would have a connection to a dropped PannerNode
2 parents 95b13bd + 12a3955 commit 9a9daa7

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed

src/render/graph.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -453,12 +453,16 @@ impl Graph {
453453
// Nodes are only dropped when they do not have incoming connections.
454454
// But they may have AudioParams feeding into them, these can de dropped too.
455455
nodes.retain(|id, n| {
456-
id.0 < 2 // never drop Listener and Destination node
457-
|| !n
458-
.borrow()
459-
.outgoing_edges
460-
.iter()
461-
.any(|e| e.other_id == *index)
456+
// Check if this node was connected to the dropped node. In that case, it is
457+
// either an AudioParam (which can be dropped), or the AudioListener that feeds
458+
// into a PannerNode (which can be disconnected).
459+
let outgoing_edges = &mut n.borrow_mut().outgoing_edges;
460+
let prev_len = outgoing_edges.len();
461+
outgoing_edges.retain(|e| e.other_id != *index);
462+
let was_connected = outgoing_edges.len() != prev_len;
463+
464+
let special = id.0 < 2; // never drop Listener and Destination node
465+
special || !was_connected
462466
});
463467
}
464468
});

tests/online.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,30 @@ fn test_channels() {
121121
context.destination().set_channel_count(5);
122122
assert_eq!(context.destination().channel_count(), 5);
123123
}
124+
125+
#[test]
126+
fn test_panner_node_drop_panic() {
127+
// https://github.com/orottier/web-audio-api-rs/issues/369
128+
let options = AudioContextOptions {
129+
sink_id: "none".into(),
130+
..AudioContextOptions::default()
131+
};
132+
let context = AudioContext::new(options);
133+
134+
// create a new panner and drop it
135+
let panner = context.create_panner();
136+
drop(panner);
137+
138+
// allow the audio render thread to boot and handle adding and dropping the panner
139+
std::thread::sleep(std::time::Duration::from_millis(200));
140+
141+
// creating a new panner node should not crash the render thread
142+
let mut _panner = context.create_panner();
143+
144+
// A crashed thread will not fail the test (only if the main thread panics).
145+
// Instead inspect if there is progression of time in the audio context.
146+
147+
let time = context.current_time();
148+
std::thread::sleep(std::time::Duration::from_millis(200));
149+
assert!(context.current_time() >= time + 0.15);
150+
}

0 commit comments

Comments
 (0)