Skip to main content

cast_sender/
receiver.rs

1use std::collections::HashMap;
2use std::sync::Arc;
3use std::time::Duration;
4
5use async_channel::Sender;
6use smol::lock::Mutex;
7use smol_timeout::TimeoutExt;
8
9use crate::app::AppId;
10use crate::namespace::{
11    connection::*,
12    heartbeat::*,
13    receiver::{self, *},
14    NamespaceUrn,
15};
16use crate::{App, Response, Volume};
17
18use super::{Client, Error, Payload};
19
20#[derive(Debug, Clone)]
21pub struct Receiver {
22    client: Arc<Mutex<Option<Client>>>,
23    platform: App,
24
25    // Ids for request messages which get incremented
26    request_id: Arc<Mutex<u32>>,
27    requests: Arc<Mutex<HashMap<u32, Sender<Response>>>>,
28    receivers: Arc<Mutex<Vec<Sender<Response>>>>,
29}
30
31impl Receiver {
32    pub fn new() -> Self {
33        Self {
34            client: Arc::default(),
35            platform: App::receiver(),
36            request_id: Arc::default(),
37            requests: Arc::default(),
38            receivers: Arc::default(),
39        }
40    }
41
42    pub async fn connect(&self, addr: &str) -> Result<(), Error> {
43        let client = Client::connect(addr).await?;
44        self.client.lock().await.replace(client.clone());
45
46        // Establish virtual connection with cast receiver
47        self.send(&self.platform, Connection::Connect).await?;
48
49        // Ensure we're successfully connected by doing a ping <-> pong sequence
50        self.send(&self.platform, Heartbeat::Ping).await?;
51        client.receive().await?;
52
53        // Spawn own task to receive messages from the receiver
54        let d = self.clone();
55        smol::spawn(async move {
56            loop {
57                if let Some(client) = d.client().await {
58                    match client.receive().await {
59                        Ok(response) => {
60                            if let Err(err) = d.process_response(response).await {
61                                warn!("Unable to process received message: {}", err)
62                            }
63                        }
64                        Err(err) => {
65                            error!("Unable to receive message: {}", err);
66                            d.disconnect().await;
67                            break;
68                        }
69                    }
70                } else {
71                    debug!("No client available, stop receiving.");
72                    break;
73                }
74            }
75        })
76        .detach();
77
78        Ok(())
79    }
80
81    /// Only closes the underlying connection, does not stop any running applications.
82    pub async fn disconnect(&self) {
83        // Try to close the virtual connection, but don't care about the result
84        let _ = self.send(&self.platform, Connection::Close).await;
85
86        let mut client = self.client.lock().await;
87        *client = None;
88
89        // Reset requestId counter
90        *self.request_id.lock().await = 0;
91    }
92
93    pub async fn is_connected(&self) -> bool {
94        self.client().await.is_some()
95    }
96
97    /// Currently running applications
98    pub async fn applications(&self) -> Result<Vec<App>, Error> {
99        Ok(self.status().await?.applications.unwrap_or_default())
100    }
101
102    pub async fn launch_app(&self, app_id: AppId) -> Result<App, Error> {
103        let response = self
104            .send_request(
105                &self.platform,
106                receiver::Receiver::launch_request(app_id.clone()),
107            )
108            .await?;
109
110        if let Payload::Receiver(payload) = response.payload {
111            if let receiver::Receiver::LaunchError(LaunchErrorResponse { reason }) = payload {
112                return Err(Error::LaunchError(reason));
113            }
114
115            if let receiver::Receiver::ReceiverStatus(ReceiverStatusResponse { status }) = payload
116                && let Some(apps) = status.applications {
117                    for app in apps {
118                        if app.app_id == app_id {
119                            // Establish new virtual connection to be able to send/receive app specific payloads
120                            self.send(&app, Connection::Connect).await?;
121                            return Ok(app);
122                        }
123                    }
124                }
125        }
126
127        Err(Error::NoResponse)
128    }
129
130    pub async fn stop_app(&self, app: &App) -> Result<(), Error> {
131        self.send_request(
132            &self.platform,
133            receiver::Receiver::stop_request(app.session_id.clone()),
134        )
135        .await?;
136        Ok(())
137    }
138
139    pub async fn volume(&self) -> Result<Volume, Error> {
140        Ok(self.status().await?.volume)
141    }
142
143    pub async fn set_volume(&self, level: f64, muted: bool) -> Result<(), Error> {
144        self.send_request(
145            &self.platform,
146            receiver::Receiver::set_volume_request(level, muted),
147        )
148        .await?;
149        Ok(())
150    }
151
152    pub async fn status(&self) -> Result<Status, Error> {
153        let response = self
154            .send_request(&self.platform, receiver::Receiver::GetStatus)
155            .await?;
156
157        if let Payload::Receiver(receiver::Receiver::ReceiverStatus(ReceiverStatusResponse {
158            status,
159        })) = response.payload
160        {
161            return Ok(status);
162        }
163
164        Err(Error::NoResponse)
165    }
166
167    pub async fn send<P: Into<Payload>>(&self, app: &App, payload: P) -> Result<(), Error> {
168        let payload: Payload = payload.into();
169        let namespace = payload.namespace();
170        if !app.namespaces.contains(&namespace) && namespace != NamespaceUrn::Connection {
171            debug!(
172                "Unsupported namespace {}, app supports: {:#?}",
173                namespace, app.namespaces
174            );
175            return Err(Error::UnsupportedNamespace);
176        }
177
178        let client = match self.client().await {
179            Some(client) => client,
180            None => {
181                return Err(Error::NoConnection);
182            }
183        };
184
185        client.send(app.transport_id.clone(), payload, None).await?;
186        Ok(())
187    }
188
189    pub async fn send_request<P: Into<Payload>>(
190        &self,
191        app: &App,
192        payload: P,
193    ) -> Result<Response, Error> {
194        let payload: Payload = payload.into();
195        let namespace = payload.namespace();
196        if !app.namespaces.contains(&namespace) && namespace != NamespaceUrn::Connection {
197            dbg!(&payload);
198            debug!(
199                "Unsupported namespace {}, app supports: {:#?}",
200                namespace, app.namespaces
201            );
202            return Err(Error::UnsupportedNamespace);
203        }
204
205        let client = match self.client().await {
206            Some(client) => client,
207            None => {
208                return Err(Error::NoConnection);
209            }
210        };
211
212        let (response_tx, response_rx) = async_channel::bounded(1);
213
214        // Each request message gets a unique requestId
215        let request_id = {
216            let mut id = self.request_id.lock().await;
217            *id += 1;
218            *id
219        };
220
221        // Store request to be able to assign the response in `process_message()`
222        let mut requests = self.requests.lock().await;
223        requests.insert(request_id, response_tx);
224        drop(requests);
225
226        client
227            .send(app.transport_id.clone(), payload, Some(request_id))
228            .await?;
229
230        // Wait up to 10 seconds before giving up the request
231        let res = response_rx.recv().timeout(Duration::from_secs(10)).await;
232        match res {
233            Some(response) => Ok(response?),
234            None => {
235                let mut requests = self.requests.lock().await;
236                requests.remove(&request_id);
237                Err(Error::ResponseTimeout)
238            }
239        }
240    }
241
242    pub async fn receive(&self) -> Result<Response, Error> {
243        let (response_tx, response_rx) = async_channel::bounded(1);
244        let mut receivers = self.receivers.lock().await;
245        receivers.push(response_tx);
246        drop(receivers);
247
248        response_rx.recv().await.map_err(|_| Error::NoResponse)
249    }
250
251    async fn process_response(&self, response: Response) -> Result<(), Error> {
252        // Check if this payload is a response to a sent request
253        if let Some(request_id) = response.request_id
254            && request_id != 0 {
255                match self.requests.lock().await.remove(&request_id) {
256                    Some(sender) => sender.send(response.clone()).await.map_err(Box::new)?,
257                    None => debug!("Ignore payload with unknown requestId"),
258                }
259            }
260
261        if let Payload::Heartbeat(Heartbeat::Ping) = &response.payload {
262            self.send(&self.platform, Heartbeat::Pong).await?;
263        }
264
265        let mut receivers = self.receivers.lock().await;
266        for receiver in receivers.split_off(0) {
267            let _ = receiver.send(response.clone()).await;
268        }
269
270        Ok(())
271    }
272
273    async fn client(&self) -> Option<Client> {
274        self.client.lock().await.clone()
275    }
276}
277
278impl Default for Receiver {
279    fn default() -> Self {
280        Self::new()
281    }
282}