use std::{ffi::c_void, io::{self, Read}, ptr, sync::{mpsc::{self, Receiver, Sender}, Arc, Mutex}, thread::{self, Thread}, time::Instant};
use ffmpeg_next::{decoder::decoder, packet::Mut};
use soxr::{format, Soxr};
use crate::ffi::data_callback;
use miniaudio_aurex::{self as miniaudio, ma_device_config_init, ma_device_start, ma_device_stop};
#[allow(unused_imports)] use ffmpeg_next::{
self as av, ffi::AVAudioFifo, frame::Audio as AudioFrame, media, sys
};
pub struct AudioFifo(pub *mut AVAudioFifo);
unsafe impl Send for AudioFifo {}
pub enum PlayerState {
LOADING = 0,
LOADED,
PLAYING,
PAUSED,
EMPTY
}
enum CMD {
Start
}
pub struct AudioEngine {
device: miniaudio::ma_device,
buffer: Arc<Mutex<AudioFifo>>,
channels: i32,
sample_rate: Arc<Mutex<i32>>,
decoder: Arc<Mutex<Option<av::codec::decoder::audio::Audio>>>,
state: PlayerState,
format_ctx: Arc<Mutex<Option<av::format::context::Input>>>,
device_config: miniaudio::ma_device_config,
initialised: bool,
tx: Option<Sender<CMD>>
}
impl AudioEngine {
pub fn new() -> Result<Self, i32> {
let mut device: miniaudio::ma_device = unsafe {
std::mem::zeroed()
};
let buffer_ptr= unsafe {sys::av_audio_fifo_alloc(sys::AVSampleFormat::AV_SAMPLE_FMT_S32, 2, 1)};
let buffer = Arc::new(Mutex::new(AudioFifo(buffer_ptr)));
let mut device_config = unsafe {
ma_device_config_init(miniaudio::ma_device_type_ma_device_type_playback)
};
device_config.playback.format = miniaudio::ma_format_ma_format_s32;
device_config.playback.channels = 0;
device_config.sampleRate = 0;
device_config.dataCallback = Some(data_callback);
device_config.pUserData = buffer.lock().unwrap().0 as *mut c_void;
if cfg!(target_os = "windows") {
println!("Detected Windows");
device_config.wasapi.noAutoConvertSRC = miniaudio::MA_TRUE as u8;
device_config.wasapi.noDefaultQualitySRC = miniaudio::MA_TRUE as u8;
}
let device_result = unsafe { miniaudio::ma_device_init(ptr::null_mut(), &device_config, &mut device) };
if device_result != miniaudio::ma_result_MA_SUCCESS {
println!("Failed to init device.");
}
println!("Detected system configuration: {} channels at {} hz", device.playback.channels, device.sampleRate);
let mut engine = AudioEngine {
device: device,
buffer: buffer,
channels: device.playback.channels as i32,
sample_rate: Arc::new(Mutex::new(device.sampleRate as i32)),
decoder: Arc::new(Mutex::new(None)),
state: PlayerState::EMPTY,
format_ctx: Arc::new(Mutex::new(None)),
device_config: device_config,
initialised: false,
tx: None
};
Ok(engine)
}
pub fn load(&mut self, file: &str) -> Result<(), i32> {
if !self.initialised {
let (tx, rx) = mpsc::channel::<CMD>();
self.tx = Some(tx);
self.reinit_device(); self.spawn_decoder_thread(rx);
self.initialised = true;
}
self.state = PlayerState::LOADING;
let mut format_ctx = av::format::input(&file).expect("Failed to open file.");
let audio_stream_index = format_ctx.streams()
.best(media::Type::Audio)
.expect("No audio stream found.").index();
let codec_params = format_ctx.streams()
.nth(audio_stream_index)
.expect("Stream Disappeared").parameters();
let codec_ctx = av::codec::context::Context::from_parameters(codec_params).expect("Failed to allocate codec context");
let dec = codec_ctx.decoder().audio().expect("Failed to open decoder.");
* self.decoder.lock().unwrap() = Some(dec);
let decoder = self.decoder.lock().unwrap().as_mut().expect("Decoder not Initialised");
* self.format_ctx.lock().unwrap() = Some(format_ctx);
self.state = PlayerState::LOADED;
println!("Loaded {}", &file);
_ = self.tx.as_mut().unwrap().send(CMD::Start);
Ok(())
}
pub fn play(&mut self) -> Result<(), i32> {
if unsafe { miniaudio::ma_device_start(&mut self.device) } != miniaudio::ma_result_MA_SUCCESS {
println!("Failed to start device");
}
Ok(())
}
fn reinit_device(&mut self) -> Result<(), i32> {
unsafe {
std::mem::drop(self.device);
self.device = std::mem::zeroed();
self.device_config.pUserData = Arc::into_raw(self.buffer.clone()) as *mut c_void;
miniaudio::ma_device_init(ptr::null_mut(), &self.device_config, &mut self.device);
}
Ok(())
}
fn spawn_decoder_thread(&mut self, rx: Receiver<CMD>) -> Result<(), i32> {
let decoder_handle = self.decoder.clone();
let sample_rate_handle = self.sample_rate.clone();
let format_ctx_handle = self.format_ctx.clone();
let buffer_handle = self.buffer.clone();
thread::spawn(move || {
for cmd in rx {
match cmd {
CMD::Start => {
let mut decoder_binding = decoder_handle.lock().unwrap();
let decoder = decoder_binding.as_mut().unwrap();
let mut resampler = av::software::resampling::Context::get(
decoder.format(),
decoder.channel_layout(),
decoder.rate(),
av::format::Sample::I32(av::format::sample::Type::Packed), decoder.channel_layout(),
decoder.rate()
).expect("Failed to init resampler");
let mut soxr_resampler = Soxr::<format::Interleaved<i32, 2>>::new(decoder.rate() as f64, *sample_rate_handle.lock().unwrap() as f64).expect("Failed to setup Soxr");
let mut format_ctx_binding = format_ctx_handle.lock().unwrap();
let format_ctx = format_ctx_binding.as_mut().expect("Format Context not initialised");
let audio_stream_index = format_ctx.streams()
.best(media::Type::Audio)
.expect("No audio stream found.").index();
for (stream, packet) in format_ctx.packets() {
if stream.index() != audio_stream_index {
continue;
}
decoder.send_packet(&packet).expect("Failed to send packet to decoder.");
let mut frame = AudioFrame::empty();
while decoder.receive_frame(&mut frame).is_ok() {
let mut resampled_frame = AudioFrame::empty();
_ = resampler.run(&frame, &mut resampled_frame);
let input_samples: &[[i32; 2]] = bytemuck::cast_slice(resampled_frame.data(0));
let mut output_buf = vec![[0i32; 2]; (input_samples.len() as usize * *sample_rate_handle.lock().unwrap() as usize) / decoder.rate() as usize];
let res = soxr_resampler.process(input_samples, &mut output_buf).unwrap();
let mut soxr_frame = AudioFrame::new(
av::format::Sample::I32(av::format::sample::Type::Packed),
res.output_frames,
av::ChannelLayout::STEREO
);
soxr_frame.set_rate(*sample_rate_handle.lock().unwrap() as u32);
let data_plane = soxr_frame.data_mut(0);
let dst_slice: &mut [[i32; 2]] = bytemuck::cast_slice_mut(data_plane);
dst_slice[..res.output_frames].copy_from_slice(&output_buf[..res.output_frames]);
unsafe {
let data_ptr0 = soxr_frame.data_mut(0).as_mut_ptr() as *mut c_void;
let mut data_ptrs: [*mut c_void; 1] = [data_ptr0];
let written = sys::av_audio_fifo_write(
buffer_handle.lock().unwrap().0,
data_ptrs.as_mut_ptr(),
soxr_frame.samples() as i32,
);
if written < 0 {
}
}
}
}
}
}
}
});
Ok(())
}
}