Skip to content

Commit 520eaf0

Browse files
committed
Ensure all async fns return a Send + Sync Future object
1 parent 5c25551 commit 520eaf0

File tree

2 files changed

+45
-18
lines changed

2 files changed

+45
-18
lines changed

src/context/offline.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,4 +630,15 @@ mod tests {
630630

631631
assert!(complete.load(Ordering::Relaxed));
632632
}
633+
634+
fn require_send_sync<T: Send + Sync>(_: T) {}
635+
636+
#[test]
637+
fn test_all_futures_thread_safe() {
638+
let context = OfflineAudioContext::new(2, 555, 44_100.);
639+
640+
require_send_sync(context.start_rendering());
641+
require_send_sync(context.suspend(1.));
642+
require_send_sync(context.resume());
643+
}
633644
}

src/context/online.rs

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -470,29 +470,30 @@ impl AudioContext {
470470
///
471471
/// * The audio device is not available
472472
/// * For a `BackendSpecificError`
473-
#[allow(clippy::await_holding_lock)] // false positive due to explicit drop
474473
pub async fn resume(&self) {
475-
// Lock the backend manager mutex to avoid concurrent calls
476-
log::debug!("Resume called, locking backend manager");
477-
let backend_manager_guard = self.backend_manager.lock().unwrap();
474+
let (sender, receiver) = oneshot::channel();
478475

479-
if self.state() != AudioContextState::Suspended {
480-
log::debug!("Resume no-op - context is not suspended");
481-
return;
482-
}
476+
{
477+
// Lock the backend manager mutex to avoid concurrent calls
478+
log::debug!("Resume called, locking backend manager");
479+
let backend_manager_guard = self.backend_manager.lock().unwrap();
483480

484-
// Ask the audio host to resume the stream
485-
backend_manager_guard.resume();
481+
if self.state() != AudioContextState::Suspended {
482+
log::debug!("Resume no-op - context is not suspended");
483+
return;
484+
}
486485

487-
// Then, ask to resume rendering via a control message
488-
log::debug!("Resumed audio stream, waking audio graph");
489-
let (sender, receiver) = oneshot::channel();
490-
let notify = OneshotNotify::Async(sender);
491-
self.base
492-
.send_control_msg(ControlMessage::Resume { notify });
486+
// Ask the audio host to resume the stream
487+
backend_manager_guard.resume();
493488

494-
// Drop the Mutex guard so we won't hold it across an await
495-
drop(backend_manager_guard);
489+
// Then, ask to resume rendering via a control message
490+
log::debug!("Resumed audio stream, waking audio graph");
491+
let notify = OneshotNotify::Async(sender);
492+
self.base
493+
.send_control_msg(ControlMessage::Resume { notify });
494+
495+
// Drop the Mutex guard so we won't hold it across an await point
496+
}
496497

497498
// Wait for the render thread to have processed the resume message
498499
// The AudioContextState will be updated by the render thread.
@@ -767,4 +768,19 @@ mod tests {
767768
let time5 = context.current_time();
768769
assert_eq!(time5, time4); // no progression of time
769770
}
771+
772+
fn require_send_sync<T: Send + Sync>(_: T) {}
773+
774+
#[test]
775+
fn test_all_futures_thread_safe() {
776+
let options = AudioContextOptions {
777+
sink_id: "none".into(),
778+
..AudioContextOptions::default()
779+
};
780+
let context = AudioContext::new(options);
781+
782+
require_send_sync(context.suspend());
783+
require_send_sync(context.resume());
784+
require_send_sync(context.close());
785+
}
770786
}

0 commit comments

Comments
 (0)