use crate::{
speaker::{Speaker, SONOS_URN},
Error, Result,
};
use futures_util::stream::{FuturesUnordered, Stream, TryStreamExt};
use rupnp::Device;
use std::time::Duration;
pub async fn discover(timeout: Duration) -> Result<impl Stream<Item = Result<Speaker>>> {
let devices = rupnp::discover(&SONOS_URN.into(), timeout)
.await?
.try_filter_map(|dev| async move { Ok(Speaker::from_device(dev)) });
futures_util::pin_mut!(devices);
let mut devices_iter = None;
if let Some(device) = devices.try_next().await? {
let iter = device
._zone_group_state()
.await?
.into_iter()
.flat_map(|(_, speakers)| speakers)
.map(|speaker_info| {
let url = speaker_info.location().parse();
async {
let device = Device::from_url(url?).await?;
let speaker = Speaker::from_device(device);
speaker.ok_or(Error::GetZoneGroupStateReturnedNonSonos)
}
});
devices_iter = Some(iter);
};
Ok(devices_iter
.into_iter()
.flatten()
.collect::<FuturesUnordered<_>>())
}
pub async fn find(roomname: &str, timeout: Duration) -> Result<Option<Speaker>> {
let mut devices = discover(timeout).await?;
while let Some(device) = devices.try_next().await? {
if device.name().await?.eq_ignore_ascii_case(roomname) {
return Ok(Some(device));
}
}
Ok(None)
}