use futures::channel::mpsc;
use futures::sink::SinkExt;
use futures::{executor, Stream};
use std::clone::Clone;
use std::mem;
use std::pin::Pin;
use std::task::{Context, Poll};
use slog::Logger;
use winapi::shared::winerror::E_ABORT;
use crate::com::event::ComEventIterator;
use crate::com::ComObject;
use crate::ctsndcr::{EventInfo, ICallback, IEventNotify, ISoundCore, Param};
use crate::hresult::{check, Win32Error};
use super::{SoundCoreFeature, SoundCoreParameter};
pub(crate) struct SoundCoreEvents {
event_notify: ComObject<IEventNotify>,
events: mpsc::UnboundedReceiver<EventInfo>,
logger: Logger,
core: ComObject<ISoundCore>,
}
impl SoundCoreEvents {
pub fn new(
event_notify: ComObject<IEventNotify>,
core: ComObject<ISoundCore>,
logger: Logger,
) -> Result<Self, Win32Error> {
let (mut tx, rx) = mpsc::unbounded();
unsafe {
let callback = ICallback::new(move |e| match executor::block_on(tx.send(*e)) {
Ok(()) => Ok(()),
Err(_) => Err(Win32Error::new(E_ABORT)),
});
let result = check((*event_notify).RegisterEventCallback(0xff, callback));
(*callback).Release();
result?;
}
Ok(Self {
event_notify,
events: rx,
core,
logger,
})
}
}
impl Stream for SoundCoreEvents {
type Item = Result<SoundCoreEvent, Win32Error>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
match Pin::new(&mut self.events).poll_next(cx) {
Poll::Ready(Some(e)) => Poll::Ready(Some(match e.event {
2 => unsafe {
let mut feature = mem::zeroed();
let feature = check(self.core.GetFeatureInfo(
0,
e.data_or_feature_id,
&mut feature,
))
.map(|_| feature);
match feature {
Ok(feature) => {
let feature = SoundCoreFeature::new(
self.core.clone(),
self.logger.clone(),
0,
&feature,
);
let mut param = mem::zeroed();
let param = check(self.core.GetParamInfo(
Param {
param: e.param_id,
feature: e.data_or_feature_id,
context: 0,
},
&mut param,
))
.map(|_| param);
match param {
Ok(param) => {
let param = SoundCoreParameter::new(
self.core.clone(),
feature.description.clone(),
self.logger.clone(),
¶m,
);
Ok(SoundCoreEvent::ParamChange {
feature,
parameter: param,
})
}
Err(error) => Err(error),
}
}
Err(error) => Err(error),
}
},
_ => Ok(SoundCoreEvent::Unknown(e)),
})),
Poll::Ready(None) => Poll::Ready(None),
Poll::Pending => Poll::Pending,
}
}
}
impl Drop for SoundCoreEvents {
fn drop(&mut self) {
unsafe {
self.event_notify.UnregisterEventCallback();
}
}
}
pub struct SoundCoreEventIterator {
inner: ComEventIterator<SoundCoreEvents>,
}
impl SoundCoreEventIterator {
pub(crate) fn new(stream: SoundCoreEvents) -> Self {
SoundCoreEventIterator {
inner: ComEventIterator::new(stream),
}
}
}
impl Iterator for SoundCoreEventIterator {
type Item = Result<SoundCoreEvent, Win32Error>;
fn next(&mut self) -> Option<Result<SoundCoreEvent, Win32Error>> {
self.inner.next()
}
}
#[derive(Debug)]
pub enum SoundCoreEvent {
Unknown(EventInfo),
ParamChange {
feature: SoundCoreFeature,
parameter: SoundCoreParameter,
},
}