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.
This commit is contained in:
parent
63f1a9dec8
commit
344a65313f
@ -1,17 +1,28 @@
|
|||||||
use crate::{Audio, AudioSource, Decodable};
|
use crate::{Audio, AudioSource, Decodable};
|
||||||
use bevy_asset::{Asset, Assets};
|
use bevy_asset::{Asset, Assets};
|
||||||
use bevy_ecs::system::{NonSend, Res, ResMut};
|
use bevy_ecs::system::{Res, ResMut, Resource};
|
||||||
use bevy_reflect::TypeUuid;
|
use bevy_reflect::TypeUuid;
|
||||||
use bevy_utils::tracing::warn;
|
use bevy_utils::tracing::warn;
|
||||||
use rodio::{OutputStream, OutputStreamHandle, Sink, Source};
|
use rodio::{OutputStream, OutputStreamHandle, Sink, Source};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// Used internally to play audio on the current "audio device"
|
/// Used internally to play audio on the current "audio device"
|
||||||
|
///
|
||||||
|
/// ## Note
|
||||||
|
///
|
||||||
|
/// Initializing this resource will leak [`rodio::OutputStream`](rodio::OutputStream)
|
||||||
|
/// using [`std::mem::forget`].
|
||||||
|
/// This is done to avoid storing this in the struct (and making this `!Send`)
|
||||||
|
/// while preventing it from dropping (to avoid halting of audio).
|
||||||
|
///
|
||||||
|
/// This is fine when initializing this once (as is default when adding this plugin),
|
||||||
|
/// since the memory cost will be the same.
|
||||||
|
/// However, repeatedly inserting this resource into the app will **leak more memory**.
|
||||||
|
#[derive(Resource)]
|
||||||
pub struct AudioOutput<Source = AudioSource>
|
pub struct AudioOutput<Source = AudioSource>
|
||||||
where
|
where
|
||||||
Source: Decodable,
|
Source: Decodable,
|
||||||
{
|
{
|
||||||
_stream: Option<OutputStream>,
|
|
||||||
stream_handle: Option<OutputStreamHandle>,
|
stream_handle: Option<OutputStreamHandle>,
|
||||||
phantom: PhantomData<Source>,
|
phantom: PhantomData<Source>,
|
||||||
}
|
}
|
||||||
@ -22,15 +33,15 @@ where
|
|||||||
{
|
{
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
if let Ok((stream, stream_handle)) = OutputStream::try_default() {
|
if let Ok((stream, stream_handle)) = OutputStream::try_default() {
|
||||||
|
// We leak `OutputStream` to prevent the audio from stopping.
|
||||||
|
std::mem::forget(stream);
|
||||||
Self {
|
Self {
|
||||||
_stream: Some(stream),
|
|
||||||
stream_handle: Some(stream_handle),
|
stream_handle: Some(stream_handle),
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
warn!("No audio device found.");
|
warn!("No audio device found.");
|
||||||
Self {
|
Self {
|
||||||
_stream: None,
|
|
||||||
stream_handle: None,
|
stream_handle: None,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
@ -84,7 +95,7 @@ where
|
|||||||
|
|
||||||
/// Plays audio currently queued in the [`Audio`] resource through the [`AudioOutput`] resource
|
/// Plays audio currently queued in the [`Audio`] resource through the [`AudioOutput`] resource
|
||||||
pub fn play_queued_audio_system<Source: Asset + Decodable>(
|
pub fn play_queued_audio_system<Source: Asset + Decodable>(
|
||||||
audio_output: NonSend<AudioOutput<Source>>,
|
audio_output: Res<AudioOutput<Source>>,
|
||||||
audio_sources: Option<Res<Assets<Source>>>,
|
audio_sources: Option<Res<Assets<Source>>>,
|
||||||
mut audio: ResMut<Audio<Source>>,
|
mut audio: ResMut<Audio<Source>>,
|
||||||
mut sinks: ResMut<Assets<AudioSink>>,
|
mut sinks: ResMut<Assets<AudioSink>>,
|
||||||
|
|||||||
@ -50,7 +50,7 @@ pub struct AudioPlugin;
|
|||||||
|
|
||||||
impl Plugin for AudioPlugin {
|
impl Plugin for AudioPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.init_non_send_resource::<AudioOutput<AudioSource>>()
|
app.init_resource::<AudioOutput<AudioSource>>()
|
||||||
.add_asset::<AudioSource>()
|
.add_asset::<AudioSource>()
|
||||||
.add_asset::<AudioSink>()
|
.add_asset::<AudioSink>()
|
||||||
.init_resource::<Audio<AudioSource>>()
|
.init_resource::<Audio<AudioSource>>()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user