1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use crate::{
speaker::{Speaker, SONOS_URN},
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?;
futures_util::pin_mut!(devices);
let mut devices_iter = None;
if let Some(device) = devices.try_next().await? {
let iter = Speaker::from_device(device)
.expect("searched for sonos urn but got something else")
._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);
Ok(speaker.expect("sonos action 'GetZoneGroupState' return non-sonos devices"))
}
});
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)
}