use std::{ffi::CStr, os::raw::c_char};
use crate::{bindings::VBVMR_DEVTYPE, types::ZIndex};
use super::VoicemeeterRemote;
impl VoicemeeterRemote {
pub fn get_total_input_device(&self) -> Result<i32, GetTotalDeviceError> {
let res = unsafe { self.raw.VBVMR_Input_GetDeviceNumber() };
if res < 0 {
Err(GetTotalDeviceError(res))
} else {
Ok(res)
}
}
pub fn get_total_output_device(&self) -> Result<i32, GetTotalDeviceError> {
let res = unsafe { self.raw.VBVMR_Output_GetDeviceNumber() };
if res < 0 {
Err(GetTotalDeviceError(res))
} else {
Ok(res)
}
}
pub fn get_input_device(
&self,
index: impl Into<ZIndex>,
) -> Result<InputDevice, GetDeviceError> {
let mut r#type = -1;
let index = index.into().0;
let mut name = [0 as c_char; 256];
let mut hardware_id = [0 as c_char; 256];
unsafe {
self._get_input_device(
index,
Some(&mut r#type),
Some(&mut name),
Some(&mut hardware_id),
)?;
}
Ok(InputDevice {
r#type: DeviceType::from(r#type),
name: unsafe { CStr::from_ptr(name.as_ptr()) }
.to_string_lossy()
.into_owned(),
hardware_id: unsafe { CStr::from_ptr(hardware_id.as_ptr()) }
.to_string_lossy()
.into_owned(),
})
}
pub(crate) unsafe fn _get_input_device(
&self,
index: i32,
r#type: Option<&mut i32>,
name: Option<&mut [c_char; 256]>,
hardware_id: Option<&mut [c_char; 256]>,
) -> Result<(), GetDeviceError> {
let type_p = crate::opt_or_null(r#type);
let name_p = crate::opt_or_null(name.map(|a| &mut a[0]));
let hardware_id_p = crate::opt_or_null(hardware_id.map(|a| &mut a[0]));
let res = unsafe {
self.raw
.VBVMR_Input_GetDeviceDescA(index, type_p, name_p, hardware_id_p)
};
match res {
0 => Ok(()),
s => Err(GetDeviceError(s)),
}
}
pub fn get_output_device(
&self,
index: impl Into<ZIndex>,
) -> Result<OutputDevice, GetDeviceError> {
let mut r#type = 0;
let index = index.into().0;
let mut name = [0 as c_char; 256];
let mut hardware_id = [0 as c_char; 256];
unsafe {
self._get_output_device(
index,
Some(&mut r#type),
Some(&mut name),
Some(&mut hardware_id),
)?;
}
Ok(OutputDevice {
r#type: DeviceType::from(r#type),
name: unsafe { CStr::from_ptr(name.as_ptr()) }
.to_string_lossy()
.into_owned(),
hardware_id: unsafe { CStr::from_ptr(hardware_id.as_ptr()) }
.to_string_lossy()
.into_owned(),
})
}
pub(crate) unsafe fn _get_output_device(
&self,
index: i32,
r#type: Option<&mut i32>,
name: Option<&mut [c_char; 256]>,
hardware_id: Option<&mut [c_char; 256]>,
) -> Result<(), GetDeviceError> {
let type_p = crate::opt_or_null(r#type);
let name_p = crate::opt_or_null(name.map(|a| &mut a[0]));
let hardware_id_p = crate::opt_or_null(hardware_id.map(|a| &mut a[0]));
let res = unsafe {
self.raw
.VBVMR_Output_GetDeviceDescA(index, type_p, name_p, hardware_id_p)
};
match res {
0 => Ok(()),
s => Err(GetDeviceError(s)),
}
}
}
#[derive(Debug)]
pub struct InputDevice {
pub r#type: DeviceType,
pub name: String,
pub hardware_id: String,
}
#[repr(i32)]
#[derive(Debug)]
pub enum DeviceType {
Mme = VBVMR_DEVTYPE::MME.0,
Wdm = VBVMR_DEVTYPE::WDM.0,
Ks = VBVMR_DEVTYPE::KS.0,
Asio = VBVMR_DEVTYPE::ASIO.0,
Other(VBVMR_DEVTYPE),
}
impl From<i32> for DeviceType {
fn from(value: i32) -> Self {
match VBVMR_DEVTYPE(value) {
VBVMR_DEVTYPE::MME => DeviceType::Mme,
VBVMR_DEVTYPE::WDM => DeviceType::Wdm,
VBVMR_DEVTYPE::KS => DeviceType::Ks,
VBVMR_DEVTYPE::ASIO => DeviceType::Asio,
o => DeviceType::Other(o),
}
}
}
#[derive(Debug)]
pub struct OutputDevice {
pub r#type: DeviceType,
pub name: String,
pub hardware_id: String,
}
#[derive(Debug, thiserror::Error, Clone)]
#[error("unexpected device: error code {0}")]
pub struct GetDeviceError(pub i32);
#[derive(Debug, thiserror::Error, Clone)]
#[error("could not get total device number: error code {0}")]
pub struct GetTotalDeviceError(pub i32);