use std::{
io::Cursor,
sync::{atomic::AtomicBool, Arc},
};
use rodio::{Decoder, SpatialSink};
use smallvec::SmallVec;
use amethyst_core::ecs::{prelude::Component, storage::BTreeStorage};
use crate::{source::Source, DecoderError};
#[allow(missing_debug_implementations)]
#[derive(Default)]
pub struct AudioEmitter {
pub(crate) sinks: SmallVec<[(SpatialSink, Arc<AtomicBool>); 4]>,
pub(crate) sound_queue: SmallVec<[Decoder<Cursor<Source>>; 4]>,
pub(crate) picker: Option<Box<dyn FnMut(&mut AudioEmitter) -> bool + Send + Sync>>,
}
impl AudioEmitter {
pub fn new() -> AudioEmitter {
Default::default()
}
pub fn play(&mut self, source: &Source) -> Result<(), DecoderError> {
self.sound_queue
.push(Decoder::new(Cursor::new(source.clone())).map_err(|_| DecoderError)?);
Ok(())
}
pub fn set_picker(&mut self, picker: Box<dyn FnMut(&mut AudioEmitter) -> bool + Send + Sync>) {
self.picker = Some(picker);
}
pub fn clear_picker(&mut self) {
self.picker = None;
}
}
impl Component for AudioEmitter {
type Storage = BTreeStorage<Self>;
}
#[cfg(test)]
mod tests {
use std::{fs::File, io::Read, vec::Vec};
use amethyst_utils::app_root_dir::application_root_dir;
use crate::{AudioEmitter, Source};
fn test_play(file_name: &str, should_pass: bool) {
let app_root = application_root_dir().unwrap();
let audio_path = app_root.join(file_name);
let mut f = File::open(audio_path).unwrap();
let mut buffer = Vec::new();
f.read_to_end(&mut buffer).unwrap();
let src = Source { bytes: buffer };
let mut emitter = AudioEmitter::default();
match emitter.play(&src) {
Ok(_pass) => assert!(
should_pass,
"Expected `play` result to be Err(..), but was Ok(..)"
),
Err(fail) => assert!(
!should_pass,
"Expected `play` result to be `Ok(..)`, but was {:?}",
fail
),
};
}
#[test]
fn test_play_wav() {
test_play("tests/sound_test.wav", true);
}
#[test]
fn test_play_mp3() {
test_play("tests/sound_test.mp3", true);
}
#[test]
fn test_play_flac() {
test_play("tests/sound_test.flac", true);
}
#[test]
fn test_play_ogg() {
test_play("tests/sound_test.ogg", true);
}
#[test]
fn test_play_fake() {
test_play("tests/sound_test.fake", false);
}
#[test]
fn test_picker() {
let mut emitter_main = AudioEmitter::default();
let box_picker: Box<dyn FnMut(&mut AudioEmitter) -> bool + Send + Sync> =
Box::new(use_audio_emitter);
emitter_main.set_picker(box_picker);
assert!(emitter_main.picker.is_some());
emitter_main.clear_picker();
assert!(emitter_main.picker.is_none());
}
fn use_audio_emitter(_emitter: &mut AudioEmitter) -> bool {
true
}
}