diff --git a/CHANGELOG.md b/CHANGELOG.md index bbe4628946f67..988232d13f9e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,9 @@ - New methods `Color::rgb_linear` and `Color::rgba_linear` will accept colors already in linear sRGB (the old behavior) - Individual color-components must now be accessed through setters and getters: `.r`, `.g`, `.b`, `.a`, `.set_r`, `.set_g`, `.set_b`, `.set_a`, and the corresponding methods with the `*_linear` suffix. - Despawning an entity multiple times causes a debug-level log message to be emitted instead of a panic [649] [651] +- Breaking Change: Migrated to rodio 0.12, this means: + - Playing an mp3 no longer sometimes panics in debug mode + - New method of playing audio can be found in the audio example (an intermediary `Audio` struct is used instead of `AudioOutput` directly) [696]: https://github.com/bevyengine/bevy/pull/696 [689]: https://github.com/bevyengine/bevy/pull/689 diff --git a/crates/bevy_audio/Cargo.toml b/crates/bevy_audio/Cargo.toml index c8a9e480b31a0..bd6481c61511d 100644 --- a/crates/bevy_audio/Cargo.toml +++ b/crates/bevy_audio/Cargo.toml @@ -22,7 +22,7 @@ bevy_utils = { path = "../bevy_utils", version = "0.2.1" } # other anyhow = "1.0" -rodio = { version = "0.11", default-features = false } +rodio = { version = "0.12", default-features = false } parking_lot = "0.11.0" [features] diff --git a/crates/bevy_audio/src/audio.rs b/crates/bevy_audio/src/audio.rs new file mode 100644 index 0000000000000..0c6d0ef80e6be --- /dev/null +++ b/crates/bevy_audio/src/audio.rs @@ -0,0 +1,43 @@ +use crate::{AudioSource, Decodable}; +use bevy_asset::Handle; +use parking_lot::RwLock; +use std::{collections::VecDeque, fmt}; + +/// The external struct used to play audio +pub struct Audio

+where + P: Decodable, +{ + pub queue: RwLock>>, +} + +impl

fmt::Debug for Audio

+where + P: Decodable, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Audio").field("queue", &self.queue).finish() + } +} + +impl

Default for Audio

+where + P: Decodable, +{ + fn default() -> Self { + Self { + queue: Default::default(), + } + } +} + +impl

Audio

+where + P: Decodable, +

::Decoder: rodio::Source + Send + Sync, + <

::Decoder as Iterator>::Item: rodio::Sample + Send + Sync, +{ + pub fn play(&self, audio_source: Handle

) { + self.queue.write().push_front(audio_source); + } +} diff --git a/crates/bevy_audio/src/audio_output.rs b/crates/bevy_audio/src/audio_output.rs index 50c29a9670b6a..2571b0c72b9a4 100644 --- a/crates/bevy_audio/src/audio_output.rs +++ b/crates/bevy_audio/src/audio_output.rs @@ -1,28 +1,17 @@ -use crate::{AudioSource, Decodable}; -use bevy_asset::{Asset, Assets, Handle}; -use bevy_ecs::Res; -use parking_lot::RwLock; -use rodio::{Device, Sink}; -use std::{collections::VecDeque, fmt}; +use crate::{Audio, AudioSource, Decodable}; +use bevy_asset::{Asset, Assets}; +use bevy_ecs::{Resources, World}; +use rodio::{OutputStream, OutputStreamHandle, Sink}; +use std::marker::PhantomData; -/// Used to play audio on the current "audio device" +/// Used internally to play audio on the current "audio device" pub struct AudioOutput

where P: Decodable, { - device: Device, - queue: RwLock>>, -} - -impl

fmt::Debug for AudioOutput

-where - P: Decodable, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("AudioOutput") - .field("queue", &self.queue) - .finish() - } + _stream: OutputStream, + stream_handle: OutputStreamHandle, + phantom: PhantomData

, } impl

Default for AudioOutput

@@ -30,9 +19,12 @@ where P: Decodable, { fn default() -> Self { + let (stream, stream_handle) = OutputStream::try_default().unwrap(); + Self { - device: rodio::default_output_device().unwrap(), - queue: Default::default(), + _stream: stream, + stream_handle, + phantom: PhantomData, } } } @@ -43,18 +35,14 @@ where

::Decoder: rodio::Source + Send + Sync, <

::Decoder as Iterator>::Item: rodio::Sample + Send + Sync, { - pub fn play_source(&self, audio_source: &P) { - let sink = Sink::new(&self.device); + fn play_source(&self, audio_source: &P) { + let sink = Sink::try_new(&self.stream_handle).unwrap(); sink.append(audio_source.decoder()); sink.detach(); } - pub fn play(&self, audio_source: Handle

) { - self.queue.write().push_front(audio_source); - } - - pub fn try_play_queued(&self, audio_sources: &Assets

) { - let mut queue = self.queue.write(); + fn try_play_queued(&self, audio_sources: &Assets

, audio: &mut Audio

) { + let mut queue = audio.queue.write(); let len = queue.len(); let mut i = 0; while i < len { @@ -70,14 +58,17 @@ where } } -/// Plays audio currently queued in the [AudioOutput] resource -pub fn play_queued_audio_system( - audio_sources: Res>, - audio_output: Res>, -) where +/// Plays audio currently queued in the [Audio] resource through the [AudioOutput] resource +pub fn play_queued_audio_system(_world: &mut World, resources: &mut Resources) +where P: Decodable,

::Decoder: rodio::Source + Send + Sync, <

::Decoder as Iterator>::Item: rodio::Sample + Send + Sync, { - audio_output.try_play_queued(&audio_sources); + let audio_output = resources.get_thread_local::>().unwrap(); + let mut audio = resources.get_mut::>().unwrap(); + + if let Some(audio_sources) = resources.get::>() { + audio_output.try_play_queued(&*audio_sources, &mut *audio); + } } diff --git a/crates/bevy_audio/src/lib.rs b/crates/bevy_audio/src/lib.rs index 7c1d422a6c566..dfe792ef5afaf 100644 --- a/crates/bevy_audio/src/lib.rs +++ b/crates/bevy_audio/src/lib.rs @@ -1,16 +1,18 @@ +mod audio; mod audio_output; mod audio_source; +pub use audio::*; pub use audio_output::*; pub use audio_source::*; pub mod prelude { - pub use crate::{AudioOutput, AudioSource, Decodable}; + pub use crate::{Audio, AudioOutput, AudioSource, Decodable}; } use bevy_app::prelude::*; use bevy_asset::AddAsset; -use bevy_ecs::IntoQuerySystem; +use bevy_ecs::IntoThreadLocalSystem; /// Adds support for audio playback to an App #[derive(Default)] @@ -18,12 +20,13 @@ pub struct AudioPlugin; impl Plugin for AudioPlugin { fn build(&self, app: &mut AppBuilder) { - app.init_resource::>() + app.init_thread_local_resource::>() .add_asset::() .init_asset_loader::() + .init_resource::>() .add_system_to_stage( stage::POST_UPDATE, - play_queued_audio_system::.system(), + play_queued_audio_system::.thread_local_system(), ); } } diff --git a/crates/bevy_utils/Cargo.toml b/crates/bevy_utils/Cargo.toml index 64288f8c7426a..494db5fe870e3 100644 --- a/crates/bevy_utils/Cargo.toml +++ b/crates/bevy_utils/Cargo.toml @@ -13,4 +13,4 @@ license = "MIT" keywords = ["bevy"] [dependencies] -ahash = "0.4.5" +ahash = "0.5.3" diff --git a/examples/audio/audio.rs b/examples/audio/audio.rs index d560010ae29ff..238900b166de0 100644 --- a/examples/audio/audio.rs +++ b/examples/audio/audio.rs @@ -8,7 +8,7 @@ fn main() { .run(); } -fn setup(asset_server: Res, audio_output: Res) { +fn setup(asset_server: Res, audio: Res