2020-09-08 20:56:45 +00:00
|
|
|
use crate::{AudioSource, Decodable};
|
2020-07-16 20:46:51 +00:00
|
|
|
use bevy_asset::{Assets, Handle};
|
|
|
|
use bevy_ecs::Res;
|
2020-08-21 21:55:16 +00:00
|
|
|
use parking_lot::RwLock;
|
2020-09-08 20:56:45 +00:00
|
|
|
use rodio::{Device, Sink};
|
2020-10-08 18:43:01 +00:00
|
|
|
use std::{collections::VecDeque, fmt};
|
2020-07-16 20:46:51 +00:00
|
|
|
|
2020-08-09 23:13:04 +00:00
|
|
|
/// Used to play audio on the current "audio device"
|
2020-09-08 20:56:45 +00:00
|
|
|
pub struct AudioOutput<P = AudioSource>
|
|
|
|
where
|
|
|
|
P: Decodable,
|
|
|
|
{
|
2020-07-16 20:46:51 +00:00
|
|
|
device: Device,
|
2020-09-08 20:56:45 +00:00
|
|
|
queue: RwLock<VecDeque<Handle<P>>>,
|
2020-07-16 20:46:51 +00:00
|
|
|
}
|
|
|
|
|
2020-10-08 18:43:01 +00:00
|
|
|
impl<P> fmt::Debug for AudioOutput<P>
|
|
|
|
where
|
|
|
|
P: Decodable,
|
|
|
|
{
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
f.debug_struct("AudioOutput")
|
|
|
|
.field("queue", &self.queue)
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-08 20:56:45 +00:00
|
|
|
impl<P> Default for AudioOutput<P>
|
|
|
|
where
|
|
|
|
P: Decodable,
|
|
|
|
{
|
2020-07-16 20:46:51 +00:00
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
device: rodio::default_output_device().unwrap(),
|
|
|
|
queue: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-08 20:56:45 +00:00
|
|
|
impl<P> AudioOutput<P>
|
|
|
|
where
|
|
|
|
P: Decodable,
|
|
|
|
<P as Decodable>::Decoder: rodio::Source + Send + Sync,
|
|
|
|
<<P as Decodable>::Decoder as Iterator>::Item: rodio::Sample + Send + Sync,
|
|
|
|
{
|
|
|
|
pub fn play_source(&self, audio_source: &P) {
|
2020-07-16 20:46:51 +00:00
|
|
|
let sink = Sink::new(&self.device);
|
2020-09-08 20:56:45 +00:00
|
|
|
sink.append(audio_source.decoder());
|
2020-07-16 20:46:51 +00:00
|
|
|
sink.detach();
|
|
|
|
}
|
|
|
|
|
2020-09-08 20:56:45 +00:00
|
|
|
pub fn play(&self, audio_source: Handle<P>) {
|
2020-08-21 21:55:16 +00:00
|
|
|
self.queue.write().push_front(audio_source);
|
2020-07-16 20:46:51 +00:00
|
|
|
}
|
|
|
|
|
2020-09-08 20:56:45 +00:00
|
|
|
pub fn try_play_queued(&self, audio_sources: &Assets<P>) {
|
2020-08-21 21:55:16 +00:00
|
|
|
let mut queue = self.queue.write();
|
2020-07-16 20:46:51 +00:00
|
|
|
let len = queue.len();
|
|
|
|
let mut i = 0;
|
|
|
|
while i < len {
|
|
|
|
let audio_source_handle = queue.pop_back().unwrap();
|
|
|
|
if let Some(audio_source) = audio_sources.get(&audio_source_handle) {
|
2020-07-16 21:23:57 +00:00
|
|
|
self.play_source(audio_source);
|
2020-07-16 20:46:51 +00:00
|
|
|
} else {
|
|
|
|
// audio source hasn't loaded yet. add it back to the queue
|
|
|
|
queue.push_front(audio_source_handle);
|
|
|
|
}
|
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-09 23:13:04 +00:00
|
|
|
/// Plays audio currently queued in the [AudioOutput] resource
|
2020-09-08 20:56:45 +00:00
|
|
|
pub fn play_queued_audio_system<P>(audio_sources: Res<Assets<P>>, audio_output: Res<AudioOutput<P>>)
|
|
|
|
where
|
|
|
|
P: Decodable,
|
|
|
|
<P as Decodable>::Decoder: rodio::Source + Send + Sync,
|
|
|
|
<<P as Decodable>::Decoder as Iterator>::Item: rodio::Sample + Send + Sync,
|
|
|
|
{
|
2020-07-16 20:46:51 +00:00
|
|
|
audio_output.try_play_queued(&audio_sources);
|
|
|
|
}
|