use super::{
AudioOutputFormat,
AudioCommandResult,
AudioSystemCommand,
RateConverter,
AudioSettings,
audio_track::*,
sample::SampleTransform,
play_buffer::*,
};
use cpal::{
Host,
HostId,
HostUnavailable,
Device,
DevicesError,
Devices,
OutputDevices,
traits::{
HostTrait,
DeviceTrait,
EventLoopTrait
},
UnknownTypeOutputBuffer,
StreamData,
StreamId,
EventLoop,
Sample,
Format,
StreamError,
OutputBuffer,
};
use std::{
io,
vec::IntoIter,
iter::Cycle,
path::Path,
thread::{Builder,JoinHandle},
sync::{
Arc,
Mutex,
LockResult,
mpsc::{
Sender,
Receiver,
channel,
TryRecvError
},
},
};
const audio_thread_stack_size:usize=1024;
pub struct Audio{
host:Arc<Host>,
stream:Arc<Mutex<Option<StreamId>>>,
tracks:Arc<Mutex<Vec<Track<i16>>>>,
event_loop:Arc<EventLoop>,
command:Sender<AudioSystemCommand>,
thread:Option<JoinHandle<()>>,
}
impl Audio{
pub fn new( host:Host,
settings:AudioSettings
)->io::Result<Audio>{
let tracks=Arc::new(Mutex::new(Vec::with_capacity(settings.track_array_capacity)));
let stream=Arc::new(Mutex::new(None));
let t=tracks.clone();
let s=stream.clone();
let event_loop=Arc::new(host.event_loop());
let el=event_loop.clone();
let (sender,receiver)=channel::<AudioSystemCommand>();
let owner_host=Arc::new(host);
let host=owner_host.clone();
let thread_result=Builder::new()
.name("CatEngine's audio thread".to_string())
.stack_size(audio_thread_stack_size)
.spawn(move||{
let mut device=host.default_output_device().expect("No available device");
let mut format=device.default_output_format().expect("No available device");
format.channels=settings.output_format.into_channels();
let main_stream=event_loop.build_output_stream(&device,&format).expect("stream");
*stream.lock().unwrap()=Some(main_stream.clone());
event_loop.play_stream(main_stream.clone()).unwrap();
event_loop_handler(
host,
stream,
event_loop,
format,
settings.output_format,
receiver,
tracks,
settings.volume,
)
});
let thread=match thread_result{
Ok(thread)=>thread,
Err(e)=>return Err(e),
};
Ok(Self{
host:owner_host,
stream:s,
tracks:t,
event_loop:el,
command:sender,
thread:Some(thread),
})
}
pub fn add_track<P:AsRef<Path>>(&self,path:P)->AudioCommandResult{
let track=match Track::new(path){
TrackResult::Ok(track)=>track,
_=>return AudioCommandResult::TrackError
};
match self.tracks.lock(){
Ok(mut lock)=>{
lock.push(track);
AudioCommandResult::Ok
},
Err(_)=>AudioCommandResult::ThreadClosed,
}
}
pub fn remove_track(&self,index:usize)->AudioCommandResult{
let mut lock=match self.tracks.lock(){
Ok(lock)=>lock,
Err(_)=>return AudioCommandResult::ThreadClosed,
};
if index<lock.len(){
lock.remove(index);
AudioCommandResult::Ok
}
else{
AudioCommandResult::NoSuchTrack
}
}
pub fn remove_all_tracks(&self)->AudioCommandResult{
self.tracks.lock().unwrap().clear();
AudioCommandResult::Ok
}
pub fn play_track(&self,index:usize,repeats:u32)->AudioCommandResult{
let stream_lock=match self.stream.lock(){
LockResult::Ok(lock)=>lock,
LockResult::Err(_)=>return AudioCommandResult::ThreadClosed
};
let tracks_lock=match self.tracks.lock(){
Ok(lock)=>lock,
Err(_)=>return AudioCommandResult::ThreadClosed,
};
if index>=tracks_lock.len(){
return AudioCommandResult::NoSuchTrack
}
let result=match self.command.send(AudioSystemCommand::Play((index,repeats))){
Ok(())=>AudioCommandResult::Ok,
Err(_)=>return AudioCommandResult::ThreadClosed
};
if let Some(stream)=stream_lock.as_ref(){
self.event_loop.play_stream(stream.clone());
}
result
}
pub fn play(&self)->AudioCommandResult{
let stream_lock=match self.stream.lock(){
LockResult::Ok(stream)=>stream,
LockResult::Err(_)=>return AudioCommandResult::ThreadClosed
};
if let Some(stream)=stream_lock.as_ref(){
self.event_loop.play_stream(stream.clone());
}
AudioCommandResult::Ok
}
pub fn pause(&self)->AudioCommandResult{
let stream_lock=match self.stream.lock(){
LockResult::Ok(stream)=>stream,
LockResult::Err(_)=>return AudioCommandResult::ThreadClosed
};
if let Some(stream)=stream_lock.as_ref(){
self.event_loop.pause_stream(stream.clone());
}
AudioCommandResult::Ok
}
pub fn stop(&self)->AudioCommandResult{
match self.command.send(AudioSystemCommand::Stop){
Ok(())=>AudioCommandResult::Ok,
Err(_)=>AudioCommandResult::ThreadClosed
}
}
pub fn set_volume(&self,volume:f32)->AudioCommandResult{
match self.command.send(AudioSystemCommand::SetVolume(volume)){
Ok(())=>AudioCommandResult::Ok,
Err(_)=>AudioCommandResult::ThreadClosed
}
}
}
fn event_loop_handler( host:Arc<Host>,
main_stream:Arc<Mutex<Option<StreamId>>>,
event_loop:Arc<EventLoop>,
mut format:Format,
mut output_format:AudioOutputFormat,
receiver:Receiver<AudioSystemCommand>,
tracks:Arc<Mutex<Vec<Track<i16>>>>,
mut volume:f32,
)->!{
let mut track=PlayingTrack::new();
let mut rate_converter=RateConverter::new(
track.sample_rate,
format.sample_rate.0,
&mut track,
);
event_loop.clone().run(move|stream,result|{
match receiver.try_recv(){
Ok(command)=>match command{
AudioSystemCommand::Play((i,r))=>{
let lock=tracks.lock().unwrap();
let t:&Track<i16>=lock.get(i).unwrap();
track.set_track_i16(t,r);
rate_converter=RateConverter::new(
track.sample_rate,
format.sample_rate.0,
&mut track,
);
}
AudioSystemCommand::Stop=>{
track.stop()
}
AudioSystemCommand::SetVolume(v)=>{
volume=v;
}
AudioSystemCommand::Close=>{
panic!("Closing CatEngine's audio thread")
},
}
Err(_)=>{
}
}
match result{
Ok(data)=>{
match data{
StreamData::Output{buffer:UnknownTypeOutputBuffer::I16(mut buffer)}
=>output(
&mut track,
&mut rate_converter,
format.channels,
volume,buffer
),
StreamData::Output{buffer:UnknownTypeOutputBuffer::U16(mut buffer)}
=>output(
&mut track,
&mut rate_converter,
format.channels,
volume,buffer
),
StreamData::Output{buffer:UnknownTypeOutputBuffer::F32(mut buffer)}
=>output(
&mut track,
&mut rate_converter,
format.channels,
volume,buffer
),
_=>{}
}
}
Err(error)=>{
match error{
StreamError::DeviceNotAvailable=>{
let new_device=host.default_output_device().expect("No available device");
format=new_device.default_output_format().expect("No available device");
format.channels=output_format.into_channels();
rate_converter=RateConverter::new(
track.sample_rate,
format.sample_rate.0,
&mut track,
);
let new_stream=event_loop.build_output_stream(&new_device,&format).expect("Build a new stream");
*main_stream.lock().unwrap()=Some(new_stream.clone());
event_loop.play_stream(new_stream.clone()).unwrap();
}
StreamError::BackendSpecific{err}=>{
panic!("{}",err)
}
}
}
}
})
}
impl Drop for Audio{
fn drop(&mut self){
let _=self.command.send(AudioSystemCommand::Close);
if let Some(stream)=self.stream.lock().unwrap().as_ref(){
self.event_loop.play_stream(stream.clone());
}
if let Some(thread)=self.thread.take(){
let _=thread.join();
}
}
}
fn output<S:SampleTransform>(
track:&mut PlayingTrack,
converter:&mut RateConverter,
channels:u16,
volume:f32,
mut buffer:OutputBuffer<S>
){
let len=buffer.len()/channels as usize;
let mut c=0;
let mut frame=Vec::with_capacity(channels as usize);
converter.next(track,&mut frame);
for b in buffer.iter_mut(){
if c==channels{
converter.next(track,&mut frame);
c=0;
}
if !frame.is_empty(){
let sample=frame.remove(0);
*b=SampleTransform::from(sample,volume)
}
c+=1;
}
}