use std::ffi::OsStr;
use std::mem::MaybeUninit;
use std::os::windows::ffi::OsStrExt;
use std::ptr;
use slog::Logger;
use winapi::shared::guiddef::GUID;
use winapi::um::combaseapi::{CoCreateInstance, CLSCTX_ALL};
use winapi::Interface;
use crate::com::{ComObject, ComScope};
use crate::ctsndcr::{HardwareInfo, IEventNotify, ISoundCore};
use crate::hresult::{check, Win32Error};
use super::event::{SoundCoreEventIterator, SoundCoreEvents};
use super::{SoundCoreError, SoundCoreFeatureIterator};
pub struct SoundCore {
sound_core: ComObject<ISoundCore>,
logger: Logger,
}
impl SoundCore {
pub fn for_device(
clsid: &GUID,
device_id: &str,
logger: Logger,
) -> Result<SoundCore, SoundCoreError> {
let _scope = ComScope::begin();
let mut core = SoundCore::new(clsid, logger)?;
core.bind_hardware(device_id)?;
Ok(core)
}
#[allow(clippy::new_ret_no_self)]
fn new(clsid: &GUID, logger: Logger) -> Result<SoundCore, SoundCoreError> {
unsafe {
let mut sc = MaybeUninit::<*mut ISoundCore>::uninit();
check(CoCreateInstance(
clsid,
ptr::null_mut(),
CLSCTX_ALL,
&ISoundCore::uuidof(),
sc.as_mut_ptr() as *mut _,
))?;
Ok(SoundCore {
sound_core: ComObject::take(sc.assume_init()),
logger,
})
}
}
fn bind_hardware(&mut self, id: &str) -> Result<(), Win32Error> {
trace!(self.logger, "Binding SoundCore to {}...", id);
let mut buffer = [0; 260];
for c in OsStr::new(id).encode_wide().enumerate() {
buffer[c.0] = c.1;
}
let info = HardwareInfo {
info_type: 0,
info: buffer,
};
check(unsafe { self.sound_core.BindHardware(&info) })?;
Ok(())
}
pub fn features(&self, context: u32) -> SoundCoreFeatureIterator {
SoundCoreFeatureIterator::new(self.sound_core.clone(), self.logger.clone(), context)
}
pub fn events(&self) -> Result<SoundCoreEventIterator, Win32Error> {
Ok(SoundCoreEventIterator::new(self.event_stream()?))
}
pub(crate) fn event_stream(&self) -> Result<SoundCoreEvents, Win32Error> {
unsafe {
let mut event_notify = MaybeUninit::<*mut IEventNotify>::uninit();
check(
self.sound_core
.QueryInterface(&IEventNotify::uuidof(), event_notify.as_mut_ptr() as *mut _),
)?;
SoundCoreEvents::new(
ComObject::take(event_notify.assume_init()),
self.sound_core.clone(),
self.logger.clone(),
)
}
}
}