use flexaudio_core::types::DeviceEvent;
trait DeviceWatchBackend: Send {
fn poll_event(&mut self) -> Option<DeviceEvent>;
fn stop(&mut self);
}
pub struct DeviceWatcher {
inner: Box<dyn DeviceWatchBackend>,
}
impl DeviceWatcher {
pub fn poll_event(&mut self) -> Option<DeviceEvent> {
self.inner.poll_event()
}
pub fn stop(&mut self) {
self.inner.stop();
}
}
impl Drop for DeviceWatcher {
fn drop(&mut self) {
self.stop();
}
}
struct NoopWatcher;
impl DeviceWatchBackend for NoopWatcher {
fn poll_event(&mut self) -> Option<DeviceEvent> {
None
}
fn stop(&mut self) {}
}
#[cfg(target_os = "linux")]
impl DeviceWatchBackend for flexaudio_os_linux::PwDeviceWatcher {
fn poll_event(&mut self) -> Option<DeviceEvent> {
flexaudio_os_linux::PwDeviceWatcher::poll_event(self)
}
fn stop(&mut self) {
flexaudio_os_linux::PwDeviceWatcher::stop(self)
}
}
pub(crate) fn watch_devices() -> flexaudio_core::types::Result<DeviceWatcher> {
#[cfg(target_os = "linux")]
{
let inner: Box<dyn DeviceWatchBackend> = match flexaudio_os_linux::PwDeviceWatcher::start()
{
Ok(w) => Box::new(w),
Err(_) => Box::new(NoopWatcher),
};
Ok(DeviceWatcher { inner })
}
#[cfg(not(target_os = "linux"))]
{
Ok(DeviceWatcher {
inner: Box::new(NoopWatcher),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn watcher_is_send() {
fn assert_send<T: Send>() {}
assert_send::<DeviceWatcher>();
}
#[test]
fn noop_watcher_yields_nothing() {
let mut w = DeviceWatcher {
inner: Box::new(NoopWatcher),
};
assert!(w.poll_event().is_none());
assert!(w.poll_event().is_none());
w.stop();
w.stop();
assert!(w.poll_event().is_none());
}
#[test]
fn watch_devices_is_graceful_without_pipewire() {
let mut w = watch_devices().expect("watch_devices は縮退して常に Ok を返す設計");
let _ = w.poll_event();
w.stop();
}
}