sbz_switch/soundcore/
event.rs

1use futures::channel::mpsc;
2use futures::sink::SinkExt;
3use futures::{executor, Stream};
4
5use std::clone::Clone;
6use std::mem;
7use std::pin::Pin;
8use std::task::{Context, Poll};
9
10use slog::Logger;
11
12use winapi::shared::winerror::E_ABORT;
13
14use crate::com::event::ComEventIterator;
15use crate::com::ComObject;
16use crate::ctsndcr::{EventInfo, ICallback, IEventNotify, ISoundCore, Param};
17use crate::hresult::{check, Win32Error};
18
19use super::{SoundCoreFeature, SoundCoreParameter};
20
21pub(crate) struct SoundCoreEvents {
22    event_notify: ComObject<IEventNotify>,
23    events: mpsc::UnboundedReceiver<EventInfo>,
24    logger: Logger,
25    core: ComObject<ISoundCore>,
26}
27
28impl SoundCoreEvents {
29    pub fn new(
30        event_notify: ComObject<IEventNotify>,
31        core: ComObject<ISoundCore>,
32        logger: Logger,
33    ) -> Result<Self, Win32Error> {
34        let (mut tx, rx) = mpsc::unbounded();
35
36        unsafe {
37            let callback = ICallback::new(move |e| match executor::block_on(tx.send(*e)) {
38                Ok(()) => Ok(()),
39                Err(_) => Err(Win32Error::new(E_ABORT)),
40            });
41
42            let result = check((*event_notify).RegisterEventCallback(0xff, callback));
43            (*callback).Release();
44            result?;
45        }
46
47        Ok(Self {
48            event_notify,
49            events: rx,
50            core,
51            logger,
52        })
53    }
54}
55
56impl Stream for SoundCoreEvents {
57    type Item = Result<SoundCoreEvent, Win32Error>;
58
59    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
60        match Pin::new(&mut self.events).poll_next(cx) {
61            Poll::Ready(Some(e)) => Poll::Ready(Some(match e.event {
62                2 => unsafe {
63                    let mut feature = mem::zeroed();
64                    let feature = check(self.core.GetFeatureInfo(
65                        0,
66                        e.data_or_feature_id,
67                        &mut feature,
68                    ))
69                    .map(|_| feature);
70                    match feature {
71                        Ok(feature) => {
72                            let feature = SoundCoreFeature::new(
73                                self.core.clone(),
74                                self.logger.clone(),
75                                0,
76                                &feature,
77                            );
78                            let mut param = mem::zeroed();
79                            let param = check(self.core.GetParamInfo(
80                                Param {
81                                    param: e.param_id,
82                                    feature: e.data_or_feature_id,
83                                    context: 0,
84                                },
85                                &mut param,
86                            ))
87                            .map(|_| param);
88                            match param {
89                                Ok(param) => {
90                                    let param = SoundCoreParameter::new(
91                                        self.core.clone(),
92                                        feature.description.clone(),
93                                        self.logger.clone(),
94                                        &param,
95                                    );
96                                    Ok(SoundCoreEvent::ParamChange {
97                                        feature,
98                                        parameter: param,
99                                    })
100                                }
101                                Err(error) => Err(error),
102                            }
103                        }
104                        Err(error) => Err(error),
105                    }
106                },
107                _ => Ok(SoundCoreEvent::Unknown(e)),
108            })),
109            Poll::Ready(None) => Poll::Ready(None),
110            Poll::Pending => Poll::Pending,
111        }
112    }
113}
114
115impl Drop for SoundCoreEvents {
116    fn drop(&mut self) {
117        unsafe {
118            self.event_notify.UnregisterEventCallback();
119        }
120    }
121}
122
123/// Iterates over events produced through the SoundCore API.
124///
125/// This allows a program to be notified of events such as switching
126/// between headphones and speakers.
127///
128/// This iterator will block until the next event is available.
129pub struct SoundCoreEventIterator {
130    inner: ComEventIterator<SoundCoreEvents>,
131}
132
133impl SoundCoreEventIterator {
134    pub(crate) fn new(stream: SoundCoreEvents) -> Self {
135        SoundCoreEventIterator {
136            inner: ComEventIterator::new(stream),
137        }
138    }
139}
140
141impl Iterator for SoundCoreEventIterator {
142    type Item = Result<SoundCoreEvent, Win32Error>;
143
144    fn next(&mut self) -> Option<Result<SoundCoreEvent, Win32Error>> {
145        self.inner.next()
146    }
147}
148
149/// Describes an event produced through the SoundCore API.
150#[derive(Debug)]
151pub enum SoundCoreEvent {
152    /// An event occurred that could not be translated.
153    ///
154    /// The original event information is included unmodified.
155    Unknown(EventInfo),
156    /// A parameter value has changed
157    ParamChange {
158        /// The feature that changed
159        feature: SoundCoreFeature,
160        /// The parameter that changed
161        parameter: SoundCoreParameter,
162    },
163}