Skip to content

Commit f9b51ca

Browse files
committed
Complete inline documentation for bevy_audio (#3510)
# Objective Part of #3492 - Complete inline documentation of `bevy_audio` ## Solution - Added inline documentation to all public parts of `bevy_audio` - Added a few inline examples at important places - Some renaming for clarity (e.g. `AudioLoader` and generics) - added `#![warn(missing_docs)]` and `#![forbid(unsafe_code)]` to `bevy_audio` I also tried adding support for the other vorbis file endings `.oga` and `.spx` to the `AudioLoader` (see `file endings` at https://tools.ietf.org/html/rfc5334#section-10.3), but the `rodio` decoder does not seem to support those.
1 parent 2515140 commit f9b51ca

File tree

5 files changed

+102
-37
lines changed

5 files changed

+102
-37
lines changed

crates/bevy_audio/Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ parking_lot = "0.11.0"
2424
[target.'cfg(target_arch = "wasm32")'.dependencies]
2525
rodio = { version = "0.14", default-features = false, features = ["wasm-bindgen"] }
2626

27+
[dev-dependencies]
28+
# bevy
29+
bevy_internal = { path = "../bevy_internal", version = "0.5.0" }
30+
2731
[features]
2832
mp3 = ["rodio/mp3"]
2933
flac = ["rodio/flac"]

crates/bevy_audio/src/audio.rs

+31-13
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,36 @@ use bevy_asset::{Asset, Handle};
33
use parking_lot::RwLock;
44
use std::{collections::VecDeque, fmt};
55

6-
/// The external struct used to play audio
7-
pub struct Audio<P = AudioSource>
6+
/// Use this resource to play audio
7+
///
8+
/// ```
9+
/// # use bevy_ecs::system::Res;
10+
/// # use bevy_asset::AssetServer;
11+
/// # use bevy_audio::Audio;
12+
/// fn play_audio_system(asset_server: Res<AssetServer>, audio: Res<Audio>) {
13+
/// audio.play(asset_server.load("my_sound.ogg"));
14+
/// }
15+
/// ```
16+
pub struct Audio<Source = AudioSource>
817
where
9-
P: Asset + Decodable,
18+
Source: Asset + Decodable,
1019
{
11-
pub queue: RwLock<VecDeque<Handle<P>>>,
20+
/// Queue for playing audio from asset handles
21+
pub queue: RwLock<VecDeque<Handle<Source>>>,
1222
}
1323

14-
impl<P: Asset> fmt::Debug for Audio<P>
24+
impl<Source: Asset> fmt::Debug for Audio<Source>
1525
where
16-
P: Decodable,
26+
Source: Decodable,
1727
{
1828
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1929
f.debug_struct("Audio").field("queue", &self.queue).finish()
2030
}
2131
}
2232

23-
impl<P> Default for Audio<P>
33+
impl<Source> Default for Audio<Source>
2434
where
25-
P: Asset + Decodable,
35+
Source: Asset + Decodable,
2636
{
2737
fn default() -> Self {
2838
Self {
@@ -31,13 +41,21 @@ where
3141
}
3242
}
3343

34-
impl<P> Audio<P>
44+
impl<Source> Audio<Source>
3545
where
36-
P: Asset + Decodable,
37-
<P as Decodable>::Decoder: rodio::Source + Send + Sync,
38-
<<P as Decodable>::Decoder as Iterator>::Item: rodio::Sample + Send + Sync,
46+
Source: Asset + Decodable,
3947
{
40-
pub fn play(&self, audio_source: Handle<P>) {
48+
/// Play audio from a [`Handle`] to the audio source
49+
///
50+
/// ```
51+
/// # use bevy_ecs::system::Res;
52+
/// # use bevy_asset::AssetServer;
53+
/// # use bevy_audio::Audio;
54+
/// fn play_audio_system(asset_server: Res<AssetServer>, audio: Res<Audio>) {
55+
/// audio.play(asset_server.load("my_sound.ogg"));
56+
/// }
57+
/// ```
58+
pub fn play(&self, audio_source: Handle<Source>) {
4159
self.queue.write().push_front(audio_source);
4260
}
4361
}

crates/bevy_audio/src/audio_output.rs

+14-18
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,18 @@ use rodio::{OutputStream, OutputStreamHandle, Sink};
66
use std::marker::PhantomData;
77

88
/// Used internally to play audio on the current "audio device"
9-
pub struct AudioOutput<P = AudioSource>
9+
pub struct AudioOutput<Source = AudioSource>
1010
where
11-
P: Decodable,
11+
Source: Decodable,
1212
{
1313
_stream: Option<OutputStream>,
1414
stream_handle: Option<OutputStreamHandle>,
15-
phantom: PhantomData<P>,
15+
phantom: PhantomData<Source>,
1616
}
1717

18-
impl<P> Default for AudioOutput<P>
18+
impl<Source> Default for AudioOutput<Source>
1919
where
20-
P: Decodable,
20+
Source: Decodable,
2121
{
2222
fn default() -> Self {
2323
if let Ok((stream, stream_handle)) = OutputStream::try_default() {
@@ -37,21 +37,19 @@ where
3737
}
3838
}
3939

40-
impl<P> AudioOutput<P>
40+
impl<Source> AudioOutput<Source>
4141
where
42-
P: Asset + Decodable,
43-
<P as Decodable>::Decoder: rodio::Source + Send + Sync,
44-
<<P as Decodable>::Decoder as Iterator>::Item: rodio::Sample + Send + Sync,
42+
Source: Asset + Decodable,
4543
{
46-
fn play_source(&self, audio_source: &P) {
44+
fn play_source(&self, audio_source: &Source) {
4745
if let Some(stream_handle) = &self.stream_handle {
4846
let sink = Sink::try_new(stream_handle).unwrap();
4947
sink.append(audio_source.decoder());
5048
sink.detach();
5149
}
5250
}
5351

54-
fn try_play_queued(&self, audio_sources: &Assets<P>, audio: &mut Audio<P>) {
52+
fn try_play_queued(&self, audio_sources: &Assets<Source>, audio: &mut Audio<Source>) {
5553
let mut queue = audio.queue.write();
5654
let len = queue.len();
5755
let mut i = 0;
@@ -69,17 +67,15 @@ where
6967
}
7068

7169
/// Plays audio currently queued in the [`Audio`] resource through the [`AudioOutput`] resource
72-
pub fn play_queued_audio_system<P: Asset>(world: &mut World)
70+
pub fn play_queued_audio_system<Source: Asset>(world: &mut World)
7371
where
74-
P: Decodable,
75-
<P as Decodable>::Decoder: rodio::Source + Send + Sync,
76-
<<P as Decodable>::Decoder as Iterator>::Item: rodio::Sample + Send + Sync,
72+
Source: Decodable,
7773
{
7874
let world = world.cell();
79-
let audio_output = world.get_non_send::<AudioOutput<P>>().unwrap();
80-
let mut audio = world.get_resource_mut::<Audio<P>>().unwrap();
75+
let audio_output = world.get_non_send::<AudioOutput<Source>>().unwrap();
76+
let mut audio = world.get_resource_mut::<Audio<Source>>().unwrap();
8177

82-
if let Some(audio_sources) = world.get_resource::<Assets<P>>() {
78+
if let Some(audio_sources) = world.get_resource::<Assets<Source>>() {
8379
audio_output.try_play_queued(&*audio_sources, &mut *audio);
8480
};
8581
}

crates/bevy_audio/src/audio_source.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::{io::Cursor, sync::Arc};
88
#[derive(Debug, Clone, TypeUuid)]
99
#[uuid = "7a14806a-672b-443b-8d16-4f18afefa463"]
1010
pub struct AudioSource {
11+
/// Raw data of the audio source
1112
pub bytes: Arc<[u8]>,
1213
}
1314

@@ -17,11 +18,18 @@ impl AsRef<[u8]> for AudioSource {
1718
}
1819
}
1920

20-
/// Loads mp3 files as [`AudioSource`] [`Assets`](bevy_asset::Assets)
21+
/// Loads files as [`AudioSource`] [`Assets`](bevy_asset::Assets)
22+
///
23+
/// This asset loader supports different audio formats based on the enable Bevy features.
24+
/// The feature `bevy/vorbis` enables loading from `.ogg` files and is enabled by default.
25+
/// Other file endings can be loaded from with additional features:
26+
/// `.mp3` with `bevy/mp3`
27+
/// `.flac` with `bevy/flac`
28+
/// `.wav` with `bevy/wav`
2129
#[derive(Default)]
22-
pub struct Mp3Loader;
30+
pub struct AudioLoader;
2331

24-
impl AssetLoader for Mp3Loader {
32+
impl AssetLoader for AudioLoader {
2533
fn load(&self, bytes: &[u8], load_context: &mut LoadContext) -> BoxedFuture<Result<()>> {
2634
load_context.set_default_asset(LoadedAsset::new(AudioSource {
2735
bytes: bytes.into(),
@@ -43,14 +51,20 @@ impl AssetLoader for Mp3Loader {
4351
}
4452
}
4553

54+
/// A type implementing this trait can be decoded as a rodio source
4655
pub trait Decodable: Send + Sync + 'static {
47-
type Decoder;
56+
/// The decoder that can decode the implemeting type
57+
type Decoder: rodio::Source + Send + Sync + Iterator<Item = Self::DecoderItem>;
58+
/// A single value given by the decoder
59+
type DecoderItem: rodio::Sample + Send + Sync;
4860

61+
/// Build and return a [`Self::Decoder`] for the implementing type
4962
fn decoder(&self) -> Self::Decoder;
5063
}
5164

5265
impl Decodable for AudioSource {
5366
type Decoder = rodio::Decoder<Cursor<AudioSource>>;
67+
type DecoderItem = <rodio::Decoder<Cursor<AudioSource>> as Iterator>::Item;
5468

5569
fn decoder(&self) -> Self::Decoder {
5670
rodio::Decoder::new(Cursor::new(self.clone())).unwrap()

crates/bevy_audio/src/lib.rs

+35-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,38 @@
1+
//! Audio support for the game engine Bevy
2+
//!
3+
//! ```
4+
//! # use bevy_ecs::{system::Res, event::EventWriter};
5+
//! # use bevy_audio::{Audio, AudioPlugin};
6+
//! # use bevy_asset::{AssetPlugin, AssetServer};
7+
//! # use bevy_app::{App, AppExit};
8+
//! # use bevy_internal::MinimalPlugins;
9+
//! fn main() {
10+
//! App::new()
11+
//! .add_plugins(MinimalPlugins)
12+
//! .add_plugin(AssetPlugin)
13+
//! .add_plugin(AudioPlugin)
14+
//! # .add_system(stop)
15+
//! .add_startup_system(play_background_audio)
16+
//! .run();
17+
//! }
18+
//!
19+
//! fn play_background_audio(asset_server: Res<AssetServer>, audio: Res<Audio>) {
20+
//! audio.play(asset_server.load("background_audio.ogg"));
21+
//! }
22+
//!
23+
//! # fn stop(mut events: EventWriter<AppExit>) {
24+
//! # events.send(AppExit)
25+
//! # }
26+
//! ```
27+
28+
#![forbid(unsafe_code)]
29+
#![warn(missing_docs)]
30+
131
mod audio;
232
mod audio_output;
333
mod audio_source;
434

35+
#[allow(missing_docs)]
536
pub mod prelude {
637
#[doc(hidden)]
738
pub use crate::{Audio, AudioOutput, AudioSource, Decodable};
@@ -15,7 +46,9 @@ use bevy_app::prelude::*;
1546
use bevy_asset::AddAsset;
1647
use bevy_ecs::system::IntoExclusiveSystem;
1748

18-
/// Adds support for audio playback to an App
49+
/// Adds support for audio playback to a Bevy Application
50+
///
51+
/// Use the [`Audio`] resource to play audio.
1952
#[derive(Default)]
2053
pub struct AudioPlugin;
2154

@@ -30,6 +63,6 @@ impl Plugin for AudioPlugin {
3063
);
3164

3265
#[cfg(any(feature = "mp3", feature = "flac", feature = "wav", feature = "vorbis"))]
33-
app.init_asset_loader::<Mp3Loader>();
66+
app.init_asset_loader::<AudioLoader>();
3467
}
3568
}

0 commit comments

Comments
 (0)