Skip to content

Commit 344a653

Browse files
committed
Make AudioOutput a Resource (#6436)
# Objective - Make `AudioOutput` a `Resource`. ## Solution - Do not store `OutputStream` in the struct. - `mem::forget` `OutputStream`. --- ## Changelog ### Added - `AudioOutput` is now a `Resource`. ## Migration Guide - Use `Res<AudioOutput<Source>>` instead of `NonSend<AudioOutput<Source>>`. Same for `Mut` variants.
1 parent 63f1a9d commit 344a653

File tree

2 files changed

+17
-6
lines changed

2 files changed

+17
-6
lines changed

crates/bevy_audio/src/audio_output.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,28 @@
11
use crate::{Audio, AudioSource, Decodable};
22
use bevy_asset::{Asset, Assets};
3-
use bevy_ecs::system::{NonSend, Res, ResMut};
3+
use bevy_ecs::system::{Res, ResMut, Resource};
44
use bevy_reflect::TypeUuid;
55
use bevy_utils::tracing::warn;
66
use rodio::{OutputStream, OutputStreamHandle, Sink, Source};
77
use std::marker::PhantomData;
88

99
/// Used internally to play audio on the current "audio device"
10+
///
11+
/// ## Note
12+
///
13+
/// Initializing this resource will leak [`rodio::OutputStream`](rodio::OutputStream)
14+
/// using [`std::mem::forget`].
15+
/// This is done to avoid storing this in the struct (and making this `!Send`)
16+
/// while preventing it from dropping (to avoid halting of audio).
17+
///
18+
/// This is fine when initializing this once (as is default when adding this plugin),
19+
/// since the memory cost will be the same.
20+
/// However, repeatedly inserting this resource into the app will **leak more memory**.
21+
#[derive(Resource)]
1022
pub struct AudioOutput<Source = AudioSource>
1123
where
1224
Source: Decodable,
1325
{
14-
_stream: Option<OutputStream>,
1526
stream_handle: Option<OutputStreamHandle>,
1627
phantom: PhantomData<Source>,
1728
}
@@ -22,15 +33,15 @@ where
2233
{
2334
fn default() -> Self {
2435
if let Ok((stream, stream_handle)) = OutputStream::try_default() {
36+
// We leak `OutputStream` to prevent the audio from stopping.
37+
std::mem::forget(stream);
2538
Self {
26-
_stream: Some(stream),
2739
stream_handle: Some(stream_handle),
2840
phantom: PhantomData,
2941
}
3042
} else {
3143
warn!("No audio device found.");
3244
Self {
33-
_stream: None,
3445
stream_handle: None,
3546
phantom: PhantomData,
3647
}
@@ -84,7 +95,7 @@ where
8495

8596
/// Plays audio currently queued in the [`Audio`] resource through the [`AudioOutput`] resource
8697
pub fn play_queued_audio_system<Source: Asset + Decodable>(
87-
audio_output: NonSend<AudioOutput<Source>>,
98+
audio_output: Res<AudioOutput<Source>>,
8899
audio_sources: Option<Res<Assets<Source>>>,
89100
mut audio: ResMut<Audio<Source>>,
90101
mut sinks: ResMut<Assets<AudioSink>>,

crates/bevy_audio/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ pub struct AudioPlugin;
5050

5151
impl Plugin for AudioPlugin {
5252
fn build(&self, app: &mut App) {
53-
app.init_non_send_resource::<AudioOutput<AudioSource>>()
53+
app.init_resource::<AudioOutput<AudioSource>>()
5454
.add_asset::<AudioSource>()
5555
.add_asset::<AudioSink>()
5656
.init_resource::<Audio<AudioSource>>()

0 commit comments

Comments
 (0)