use std::{ffi::c_void, io::{self, Read}, ptr};
use soxr::{format, Soxr};
use crate::ffi::data_callback;
use miniaudio_aurex::{self as miniaudio, ma_device_start, ma_device_stop};
#[allow(unused_imports)] use ffmpeg_next::{
self as av, ffi::AVAudioFifo, frame::Audio as AudioFrame, media, sys
};
pub fn play_audio(filepath: &str) -> i32 {
let mut format_ctx = av::format::input(filepath)
.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 mut decoder = codec_ctx.decoder()
.audio()
.expect("Failed to open decoder.");
let audio_buffer = unsafe {
sys::av_audio_fifo_alloc(
sys::AVSampleFormat::AV_SAMPLE_FMT_S32,
decoder.channels() as i32,
1
)
};
let mut device: miniaudio::ma_device = unsafe { std::mem::zeroed() };
let mut device_config = unsafe { miniaudio::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 = decoder.channels() as u32;
device_config.sampleRate = 0;
device_config.dataCallback = Some(data_callback);
device_config.pUserData = audio_buffer as *mut c_void;
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.");
return -3;
}
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 setup resampler.");
let mut soxr_resampler = Soxr::<format::Interleaved<i32, 2>>::new(
decoder.rate().into(),
device.sampleRate.into()
).expect("Failed to initialize soxr");
for (stream, packet) in format_ctx.packets() {
if stream.index() != audio_stream_index {
continue;
}
decoder.send_packet(&packet)
.expect("failed to send packet");
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 * device.sampleRate 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(device.sampleRate 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(
audio_buffer,
data_ptrs.as_mut_ptr(),
soxr_frame.samples() as i32,
);
if written < 0 {
}
}
}
}
if unsafe { miniaudio::ma_device_start(&mut device) } != miniaudio::ma_result_MA_SUCCESS {
println!("Failed to start playback");
unsafe { miniaudio::ma_device_uninit(&mut device) };
return -4;
}
println!("Playing at {} khz", device.sampleRate);
println!("Press enter to quit, p to pause and resume");
let mut playing = true;
loop {
let mut input = String::new();
_ = io::stdin().read_line(&mut input);
let trimmed = input.trim_end();
if trimmed.is_empty() {break;}
else if trimmed.to_lowercase() == "p" {
if playing {
unsafe {ma_device_stop(&mut device); playing = false;}
} else {
unsafe {ma_device_start(&mut device); playing = true;}
}
}
}
unsafe {
miniaudio::ma_device_uninit(&mut device);
sys::av_audio_fifo_free(audio_buffer);
};
0
}