Skip to content

Commit

Permalink
Merge pull request #370 from orottier/bugfix/369
Browse files Browse the repository at this point in the history
Fix #369 - AudioListener would have a connection to a dropped PannerNode
  • Loading branch information
orottier authored Oct 12, 2023
2 parents 95b13bd + 12a3955 commit 9a9daa7
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 6 deletions.
16 changes: 10 additions & 6 deletions src/render/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,12 +453,16 @@ impl Graph {
// Nodes are only dropped when they do not have incoming connections.
// But they may have AudioParams feeding into them, these can de dropped too.
nodes.retain(|id, n| {
id.0 < 2 // never drop Listener and Destination node
|| !n
.borrow()
.outgoing_edges
.iter()
.any(|e| e.other_id == *index)
// Check if this node was connected to the dropped node. In that case, it is
// either an AudioParam (which can be dropped), or the AudioListener that feeds
// into a PannerNode (which can be disconnected).
let outgoing_edges = &mut n.borrow_mut().outgoing_edges;
let prev_len = outgoing_edges.len();
outgoing_edges.retain(|e| e.other_id != *index);
let was_connected = outgoing_edges.len() != prev_len;

let special = id.0 < 2; // never drop Listener and Destination node
special || !was_connected
});
}
});
Expand Down
27 changes: 27 additions & 0 deletions tests/online.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,30 @@ fn test_channels() {
context.destination().set_channel_count(5);
assert_eq!(context.destination().channel_count(), 5);
}

#[test]
fn test_panner_node_drop_panic() {
// https://github.com/orottier/web-audio-api-rs/issues/369
let options = AudioContextOptions {
sink_id: "none".into(),
..AudioContextOptions::default()
};
let context = AudioContext::new(options);

// create a new panner and drop it
let panner = context.create_panner();
drop(panner);

// allow the audio render thread to boot and handle adding and dropping the panner
std::thread::sleep(std::time::Duration::from_millis(200));

// creating a new panner node should not crash the render thread
let mut _panner = context.create_panner();

// A crashed thread will not fail the test (only if the main thread panics).
// Instead inspect if there is progression of time in the audio context.

let time = context.current_time();
std::thread::sleep(std::time::Duration::from_millis(200));
assert!(context.current_time() >= time + 0.15);
}

0 comments on commit 9a9daa7

Please sign in to comment.