use bevy_ecs::prelude::*;
use rodio::{OutputStream, OutputStreamHandle, Sink};
use std::collections::HashMap;
use log::{info, error};
struct AudioEngineInner {
_stream: OutputStream,
stream_handle: OutputStreamHandle,
sinks: HashMap<Entity, Sink>,
}
unsafe impl Send for AudioEngineInner {}
unsafe impl Sync for AudioEngineInner {}
#[derive(Resource)]
pub struct AudioEngine {
inner: AudioEngineInner,
}
impl AudioEngine {
pub fn new() -> Option<Self> {
match OutputStream::try_default() {
Ok((stream, handle)) => {
info!("音频引擎初始化成功");
Some(Self {
inner: AudioEngineInner {
_stream: stream,
stream_handle: handle,
sinks: HashMap::new(),
},
})
}
Err(e) => {
error!("音频引擎初始化失败: {}", e);
None
}
}
}
pub fn get_or_create_sink(&mut self, entity: Entity) -> Result<&Sink, String> {
if !self.inner.sinks.contains_key(&entity) {
let sink = Sink::try_new(&self.inner.stream_handle)
.map_err(|e| format!("创建音频 sink 失败: {}", e))?;
self.inner.sinks.insert(entity, sink);
}
Ok(self.inner.sinks.get(&entity).unwrap())
}
pub fn pause(&self, entity: Entity) {
if let Some(sink) = self.inner.sinks.get(&entity) {
sink.pause();
}
}
pub fn resume(&self, entity: Entity) {
if let Some(sink) = self.inner.sinks.get(&entity) {
sink.play();
}
}
pub fn stop(&mut self, entity: Entity) {
if let Some(sink) = self.inner.sinks.remove(&entity) {
sink.stop();
}
}
pub fn set_volume(&self, entity: Entity, volume: f32) {
if let Some(sink) = self.inner.sinks.get(&entity) {
sink.set_volume(volume);
}
}
pub fn cleanup_finished(&mut self) {
self.inner.sinks.retain(|_, sink| !sink.empty());
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_engine_creation() {
let engine = AudioEngine::new();
drop(engine);
}
#[test]
fn test_engine_is_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<AudioEngine>();
}
#[test]
fn test_operations_without_sink() {
if let Some(engine) = AudioEngine::new() {
let entity = Entity::from_raw(0);
engine.pause(entity);
engine.resume(entity);
engine.set_volume(entity, 0.5);
}
}
#[test]
fn test_sink_creation_result() {
if let Some(mut engine) = AudioEngine::new() {
let entity = Entity::from_raw(42);
let result = engine.get_or_create_sink(entity);
assert!(result.is_ok());
engine.stop(entity);
}
}
}