Skip to content

Commit 5fc626f

Browse files
committed
Sort the OfflineAudioContext suspend-times for performance
1 parent 8230951 commit 5fc626f

File tree

2 files changed

+31
-24
lines changed

2 files changed

+31
-24
lines changed

src/context/offline.rs

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//! The `OfflineAudioContext` type
2-
use std::collections::hash_map::Entry;
3-
use std::collections::HashMap;
2+
43
use std::sync::atomic::AtomicU64;
54
use std::sync::{Arc, Mutex};
65

@@ -33,10 +32,10 @@ pub struct OfflineAudioContext {
3332
struct OfflineAudioContextRenderer {
3433
/// the rendering 'thread', fully controlled by the offline context
3534
renderer: RenderThread,
36-
/// promises to resolve at certain render quanta (via `suspend`)
37-
suspend_promises: HashMap<usize, oneshot::Sender<()>>,
38-
/// callbacks to run at certain render quanta (via `suspend_sync`)
39-
suspend_callbacks: HashMap<usize, Box<OfflineAudioContextCallback>>,
35+
/// sorted list of promises to resolve at certain render quanta (via `suspend`)
36+
suspend_promises: Vec<(usize, oneshot::Sender<()>)>,
37+
/// sorted list of callbacks to run at certain render quanta (via `suspend_sync`)
38+
suspend_callbacks: Vec<(usize, Box<OfflineAudioContextCallback>)>,
4039
/// channel to listen for `resume` calls on a suspended context
4140
resume_receiver: futures::channel::mpsc::Receiver<()>,
4241
}
@@ -96,8 +95,8 @@ impl OfflineAudioContext {
9695

9796
let renderer = OfflineAudioContextRenderer {
9897
renderer,
99-
suspend_promises: HashMap::new(),
100-
suspend_callbacks: HashMap::new(),
98+
suspend_promises: Vec::new(),
99+
suspend_callbacks: Vec::new(),
101100
resume_receiver,
102101
};
103102

@@ -242,13 +241,16 @@ impl OfflineAudioContext {
242241
}
243242
};
244243

245-
match renderer.suspend_promises.entry(quantum) {
246-
Entry::Occupied(_) => panic!(
244+
match renderer
245+
.suspend_promises
246+
.binary_search_by_key(&quantum, |&(q, _)| q)
247+
{
248+
Ok(_) => panic!(
247249
"InvalidStateError: cannot suspend multiple times at the same render quantum"
248250
),
249-
Entry::Vacant(e) => {
250-
e.insert(sender);
251-
}
251+
Err(position) => renderer
252+
.suspend_promises
253+
.insert(position, (quantum, sender)),
252254
}
253255
} // lock is dropped
254256

@@ -304,13 +306,16 @@ impl OfflineAudioContext {
304306
Some(r) => r,
305307
None => panic!("InvalidStateError: cannot suspend when rendering has already started"),
306308
};
307-
match renderer.suspend_callbacks.entry(quantum) {
308-
Entry::Occupied(_) => panic!(
309+
match renderer
310+
.suspend_callbacks
311+
.binary_search_by_key(&quantum, |(q, _c)| *q)
312+
{
313+
Ok(_) => panic!(
309314
"InvalidStateError: cannot suspend multiple times at the same render quantum"
310315
),
311-
Entry::Vacant(e) => {
312-
e.insert(Box::new(callback));
313-
}
316+
Err(position) => renderer
317+
.suspend_callbacks
318+
.insert(position, (quantum, Box::new(callback))),
314319
}
315320
}
316321

src/render/thread.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::any::Any;
44
use std::cell::Cell;
5-
use std::collections::HashMap;
5+
66
use std::sync::atomic::{AtomicU64, Ordering};
77
use std::sync::Arc;
88
use std::time::{Duration, Instant};
@@ -14,7 +14,7 @@ use futures::stream::StreamExt;
1414

1515
use super::AudioRenderQuantum;
1616
use crate::buffer::{AudioBuffer, AudioBufferOptions};
17-
use crate::context::{AudioNodeId, OfflineAudioContext};
17+
use crate::context::{AudioNodeId, OfflineAudioContext, OfflineAudioContextCallback};
1818
use crate::events::EventDispatch;
1919
use crate::message::ControlMessage;
2020
use crate::node::ChannelInterpretation;
@@ -187,7 +187,7 @@ impl RenderThread {
187187
pub fn render_audiobuffer_sync(
188188
mut self,
189189
length: usize,
190-
mut suspend_callbacks: HashMap<usize, Box<crate::context::OfflineAudioContextCallback>>,
190+
mut suspend_callbacks: Vec<(usize, Box<OfflineAudioContextCallback>)>,
191191
context: &mut OfflineAudioContext,
192192
) -> AudioBuffer {
193193
let options = AudioBufferOptions {
@@ -204,7 +204,8 @@ impl RenderThread {
204204

205205
for quantum in 0..num_frames {
206206
// Suspend at given times and run callbacks
207-
if let Some(callback) = suspend_callbacks.remove(&quantum) {
207+
if suspend_callbacks.get(0).map(|&(q, _)| q) == Some(quantum) {
208+
let callback = suspend_callbacks.remove(0).1;
208209
(callback)(context);
209210

210211
// Handle addition/removal of nodes/edges
@@ -225,7 +226,7 @@ impl RenderThread {
225226
pub async fn render_audiobuffer(
226227
mut self,
227228
length: usize,
228-
mut suspend_callbacks: HashMap<usize, channel::oneshot::Sender<()>>,
229+
mut suspend_callbacks: Vec<(usize, channel::oneshot::Sender<()>)>,
229230
mut resume_receiver: channel::mpsc::Receiver<()>,
230231
) -> AudioBuffer {
231232
let options = AudioBufferOptions {
@@ -242,7 +243,8 @@ impl RenderThread {
242243

243244
for quantum in 0..num_frames {
244245
// Suspend at given times and run callbacks
245-
if let Some(sender) = suspend_callbacks.remove(&quantum) {
246+
if suspend_callbacks.get(0).map(|&(q, _)| q) == Some(quantum) {
247+
let sender = suspend_callbacks.remove(0).1;
246248
sender.send(()).unwrap();
247249
resume_receiver.next().await;
248250

0 commit comments

Comments
 (0)