1use super::types::{
6 CustomAvcPanelCommand, CustomBatteryStatus, CustomPlayStatus, CustomPlayerApplicationSettings,
7 CustomPlayerApplicationSettingsAttributeIds,
8};
9use crate::common_utils::common::macros::{fx_err_and_bail, with_line};
10use anyhow::Error;
11use fidl::endpoints::create_endpoints;
12use fidl_fuchsia_bluetooth::PeerId;
13use fidl_fuchsia_bluetooth_avrcp::{
14 ControllerMarker, ControllerProxy, Notifications, PeerManagerMarker, PeerManagerProxy,
15};
16use fuchsia_component::client;
17use fuchsia_sync::RwLock;
18use log::info;
19#[derive(Debug)]
21struct AvrcpFacadeInner {
22 avrcp_service_proxy: Option<PeerManagerProxy>,
24 controller_proxy: Option<ControllerProxy>,
26}
27
28#[derive(Debug)]
29pub struct AvrcpFacade {
30 inner: RwLock<AvrcpFacadeInner>,
31}
32
33impl AvrcpFacade {
34 pub fn new() -> AvrcpFacade {
35 AvrcpFacade {
36 inner: RwLock::new(AvrcpFacadeInner {
37 avrcp_service_proxy: None,
38 controller_proxy: None,
39 }),
40 }
41 }
42
43 async fn create_avrcp_service_proxy(&self) -> Result<PeerManagerProxy, Error> {
45 let tag = "AvrcpFacade::create_avrcp_service_proxy";
46 match self.inner.read().avrcp_service_proxy.clone() {
47 Some(avrcp_service_proxy) => {
48 info!(
49 tag = &with_line!(tag);
50 "Current AVRCP service proxy: {:?}", avrcp_service_proxy
51 );
52 Ok(avrcp_service_proxy)
53 }
54 None => {
55 let avrcp_service_proxy = client::connect_to_protocol::<PeerManagerMarker>();
56 if let Err(err) = avrcp_service_proxy {
57 fx_err_and_bail!(
58 &with_line!(tag),
59 format_err!("Failed to create AVRCP service proxy: {}", err)
60 );
61 }
62 avrcp_service_proxy
63 }
64 }
65 }
66
67 pub async fn init_avrcp(&self, id: u64) -> Result<(), Error> {
72 let tag = "AvrcpFacade::init_avrcp";
73 self.inner.write().avrcp_service_proxy = Some(self.create_avrcp_service_proxy().await?);
74 let avrcp_service_proxy = match &self.inner.read().avrcp_service_proxy {
75 Some(p) => p.clone(),
76 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy created"),
77 };
78 let (cont_client, cont_server) = create_endpoints::<ControllerMarker>();
79 let _status = avrcp_service_proxy
80 .get_controller_for_target(&PeerId { value: id }, cont_server)
81 .await?;
82 self.inner.write().controller_proxy = Some(cont_client.into_proxy());
83 Ok(())
84 }
85
86 pub async fn get_media_attributes(&self) -> Result<String, Error> {
88 let tag = "AvrcpFacade::get_media_attributes";
89 match self.inner.read().controller_proxy.clone() {
90 Some(proxy) => match proxy.get_media_attributes().await? {
91 Ok(media_attribs) => Ok(format!("Media attributes: {:#?}", media_attribs)),
92 Err(e) => fx_err_and_bail!(
93 &with_line!(tag),
94 format!("Error fetching media attributes: {:?}", e)
95 ),
96 },
97 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
98 }
99 }
100
101 pub async fn get_play_status(&self) -> Result<CustomPlayStatus, Error> {
103 let tag = "AvrcpFacade::get_play_status";
104 match self.inner.read().controller_proxy.clone() {
105 Some(proxy) => match proxy.get_play_status().await? {
106 Ok(play_status) => Ok(CustomPlayStatus::new(&play_status)),
107 Err(e) => fx_err_and_bail!(
108 &with_line!(tag),
109 format!("Error fetching play status: {:?}", e)
110 ),
111 },
112 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
113 }
114 }
115
116 pub async fn send_command(&self, command: CustomAvcPanelCommand) -> Result<(), Error> {
121 let tag = "AvrcpFacade::send_command";
122 let result = match self.inner.read().controller_proxy.clone() {
123 Some(proxy) => proxy.send_command(command.into()).await?,
124 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
125 };
126 match result {
127 Ok(res) => Ok(res),
128 Err(err) => {
129 fx_err_and_bail!(&with_line!(tag), format!("Error sending command:{:?}", err))
130 }
131 }
132 }
133
134 pub async fn set_absolute_volume(&self, absolute_volume: u8) -> Result<u8, Error> {
139 let tag = "AvrcpFacade::set_absolute_volume";
140 let result = match self.inner.read().controller_proxy.clone() {
141 Some(proxy) => proxy.set_absolute_volume(absolute_volume).await?,
142 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
143 };
144 match result {
145 Ok(res) => Ok(res),
146 Err(err) => {
147 fx_err_and_bail!(&with_line!(tag), format!("Error setting volume:{:?}", err))
148 }
149 }
150 }
151
152 pub async fn get_player_application_settings(
157 &self,
158 attribute_ids: CustomPlayerApplicationSettingsAttributeIds,
159 ) -> Result<CustomPlayerApplicationSettings, Error> {
160 let tag = "AvrcpFacade::get_player_application_settings";
161 match self.inner.read().controller_proxy.clone() {
162 Some(proxy) => {
163 match proxy.get_player_application_settings(&attribute_ids.to_vec()).await? {
164 Ok(player_application_settings) => Ok(player_application_settings.into()),
165 Err(e) => fx_err_and_bail!(
166 &with_line!(tag),
167 format!("Error fetching player application settings: {:?}", e)
168 ),
169 }
170 }
171 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
172 }
173 }
174
175 pub async fn set_player_application_settings(
180 &self,
181 settings: CustomPlayerApplicationSettings,
182 ) -> Result<CustomPlayerApplicationSettings, Error> {
183 let tag = "AvrcpFacade::set_player_application_settings";
184 match self.inner.read().controller_proxy.clone() {
185 Some(proxy) => match proxy.set_player_application_settings(&settings.into()).await? {
186 Ok(player_application_settings) => Ok(player_application_settings.into()),
187 Err(e) => fx_err_and_bail!(
188 &with_line!(tag),
189 format!("Error fetching player application settings: {:?}", e)
190 ),
191 },
192 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
193 }
194 }
195
196 pub async fn inform_battery_status(
201 &self,
202 battery_status: CustomBatteryStatus,
203 ) -> Result<(), Error> {
204 let tag = "AvrcpFacade::inform_battery_status";
205 match self.inner.read().controller_proxy.clone() {
206 Some(proxy) => match proxy.inform_battery_status(battery_status.into()).await? {
207 Ok(()) => Ok(()),
208 Err(e) => fx_err_and_bail!(
209 &with_line!(tag),
210 format!("Error informing battery status: {:?}", e)
211 ),
212 },
213 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
214 }
215 }
216
217 pub async fn set_addressed_player(&self, player_id: u16) -> Result<(), Error> {
222 let tag = "AvrcpFacade::set_addressed_player";
223 match self.inner.read().controller_proxy.clone() {
224 Some(proxy) => match proxy.set_addressed_player(player_id).await? {
225 Ok(()) => Ok(()),
226 Err(e) => fx_err_and_bail!(
227 &with_line!(tag),
228 format!("Error setting addressed player: {:?}", e)
229 ),
230 },
231 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
232 }
233 }
234
235 pub async fn set_notification_filter(
242 &self,
243 notifications_filter: u32,
244 position_change_interval: u32,
245 ) -> Result<(), Error> {
246 let tag = "AvrcpFacade::set_notification_filter";
247 let notifications = match Notifications::from_bits(notifications_filter) {
248 Some(notifications) => notifications,
249 _ => fx_err_and_bail!(
250 &with_line!(tag),
251 format!(
252 "Invalid bit flags value for notifications filter: {:?}",
253 notifications_filter
254 )
255 ),
256 };
257 match self.inner.read().controller_proxy.clone() {
258 Some(proxy) => {
259 match proxy.set_notification_filter(notifications, position_change_interval) {
260 Ok(()) => Ok(()),
261 Err(e) => fx_err_and_bail!(
262 &with_line!(tag),
263 format!("Error setting notification filter: {:?}", e)
264 ),
265 }
266 }
267 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
268 }
269 }
270
271 pub async fn notify_notification_handled(&self) -> Result<(), Error> {
273 let tag = "AvrcpFacade::notify_notification_handled";
274 match self.inner.read().controller_proxy.clone() {
275 Some(proxy) => match proxy.notify_notification_handled() {
276 Ok(()) => Ok(()),
277 Err(e) => fx_err_and_bail!(
278 &with_line!(tag),
279 format!("Error setting notification filter: {:?}", e)
280 ),
281 },
282 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
283 }
284 }
285
286 fn clear(&self) {
288 self.inner.write().avrcp_service_proxy = None;
289 self.inner.write().controller_proxy = None;
290 }
291
292 pub async fn cleanup(&self) -> Result<(), Error> {
294 self.clear();
295 Ok(())
296 }
297}
298
299#[cfg(test)]
300mod tests {
301
302 use super::super::types::{
303 CustomCustomAttributeValue, CustomCustomPlayerApplicationSetting, CustomEqualizer,
304 CustomRepeatStatusMode, CustomScanMode,
305 };
306 use super::*;
307 use assert_matches::assert_matches;
308 use fidl::endpoints::create_proxy_and_stream;
309 use fidl_fuchsia_bluetooth_avrcp::{BatteryStatus, ControllerRequest, PlayStatus};
310 use fuchsia_async as fasync;
311 use futures::prelude::*;
312 use std::sync::LazyLock;
313
314 static PLAY_STATUS: LazyLock<CustomPlayStatus> = LazyLock::new(|| CustomPlayStatus {
315 song_length: Some(120),
316 song_position: Some(10),
317 playback_status: Some(4),
318 });
319 static PLAYER_APPLICATION_SETTINGS: LazyLock<CustomPlayerApplicationSettings> =
320 LazyLock::new(|| CustomPlayerApplicationSettings {
321 equalizer: Some(CustomEqualizer::Off),
322 repeat_status_mode: Some(CustomRepeatStatusMode::AllTrackRepeat),
323 shuffle_mode: None,
324 scan_mode: Some(CustomScanMode::GroupScan),
325 custom_settings: Some(vec![CustomCustomPlayerApplicationSetting {
326 attribute_id: Some(1),
327 attribute_name: Some("attribute".to_string()),
328 possible_values: Some(vec![CustomCustomAttributeValue {
329 description: "description".to_string(),
330 value: 5,
331 }]),
332 current_value: Some(5),
333 }]),
334 });
335 static PLAYER_APPLICATION_SETTINGS_INPUT: LazyLock<CustomPlayerApplicationSettings> =
336 LazyLock::new(|| CustomPlayerApplicationSettings {
337 equalizer: Some(CustomEqualizer::Off),
338 repeat_status_mode: None,
339 shuffle_mode: None,
340 scan_mode: None,
341 custom_settings: Some(vec![CustomCustomPlayerApplicationSetting {
342 attribute_id: Some(1),
343 attribute_name: Some("attribute".to_string()),
344 possible_values: Some(vec![CustomCustomAttributeValue {
345 description: "description".to_string(),
346 value: 5,
347 }]),
348 current_value: Some(5),
349 }]),
350 });
351 static PLAYER_APPLICATION_SETTINGS_ATTRIBUTE_IDS: LazyLock<
352 CustomPlayerApplicationSettingsAttributeIds,
353 > = LazyLock::new(|| CustomPlayerApplicationSettingsAttributeIds {
354 attribute_ids: Some(vec![1]),
355 });
356 struct MockAvrcpTester {
357 expected_state: Vec<Box<dyn FnOnce(ControllerRequest) + Send + 'static>>,
358 }
359
360 impl MockAvrcpTester {
361 fn new() -> Self {
362 Self { expected_state: vec![] }
363 }
364
365 fn push(mut self, request: impl FnOnce(ControllerRequest) + Send + 'static) -> Self {
366 self.expected_state.push(Box::new(request));
367 self
368 }
369
370 fn build_controller(self) -> (AvrcpFacade, impl Future<Output = ()>) {
371 let (proxy, mut stream) = create_proxy_and_stream::<ControllerMarker>();
372 let fut = async move {
373 for expected in self.expected_state {
374 expected(stream.next().await.unwrap().unwrap());
375 }
376 assert_matches!(stream.next().await, None);
377 };
378 (
379 AvrcpFacade {
380 inner: RwLock::new(AvrcpFacadeInner {
381 controller_proxy: Some(proxy),
382 avrcp_service_proxy: None,
383 }),
384 },
385 fut,
386 )
387 }
388
389 fn expect_get_play_status(self, result: CustomPlayStatus) -> Self {
390 self.push(move |req| match req {
391 ControllerRequest::GetPlayStatus { responder } => {
392 responder.send(Ok(&PlayStatus::from(result))).unwrap();
393 }
394 _ => {}
395 })
396 }
397
398 fn expect_get_player_application_settings(
399 self,
400 result: CustomPlayerApplicationSettings,
401 input: &'static CustomPlayerApplicationSettingsAttributeIds,
402 ) -> Self {
403 self.push(move |req| match req {
404 ControllerRequest::GetPlayerApplicationSettings { attribute_ids, responder } => {
405 assert_eq!(attribute_ids, input.to_vec());
406 responder.send(Ok(&result.into())).unwrap();
407 }
408 _ => {}
409 })
410 }
411
412 fn expect_set_player_application_settings(
413 self,
414 result: CustomPlayerApplicationSettings,
415 input: &'static CustomPlayerApplicationSettings,
416 ) -> Self {
417 self.push(move |req| match req {
418 ControllerRequest::SetPlayerApplicationSettings {
419 requested_settings,
420 responder,
421 } => {
422 let player_application_settings: CustomPlayerApplicationSettings =
423 requested_settings.into();
424 assert_eq!(player_application_settings, *input);
425 responder.send(Ok(&result.into())).unwrap();
426 }
427 _ => {}
428 })
429 }
430
431 fn expect_inform_battery_status(self, input: CustomBatteryStatus) -> Self {
432 self.push(move |req| match req {
433 ControllerRequest::InformBatteryStatus { battery_status, responder } => {
434 let battery_status_expected: BatteryStatus = input.into();
435 assert_eq!(battery_status_expected, battery_status);
436 responder.send(Ok(())).unwrap();
437 }
438 _ => {}
439 })
440 }
441
442 fn expect_set_addressed_player(self, input: u16) -> Self {
443 self.push(move |req| match req {
444 ControllerRequest::SetAddressedPlayer { player_id, responder } => {
445 assert_eq!(input, player_id);
446 responder.send(Ok(())).unwrap();
447 }
448 _ => {}
449 })
450 }
451
452 fn expect_set_notification_filter(
453 self,
454 input_notification_filter: u32,
455 input_position_change_interval: u32,
456 ) -> Self {
457 self.push(move |req| match req {
458 ControllerRequest::SetNotificationFilter {
459 notifications,
460 position_change_interval,
461 ..
462 } => {
463 assert_eq!(
464 Notifications::from_bits(input_notification_filter).unwrap(),
465 notifications
466 );
467 assert_eq!(input_position_change_interval, position_change_interval);
468 }
469 _ => {}
470 })
471 }
472 }
473 #[fasync::run_singlethreaded(test)]
474 async fn test_get_play_status() {
475 let (facade, play_status_fut) =
476 MockAvrcpTester::new().expect_get_play_status(*PLAY_STATUS).build_controller();
477 let facade_fut = async move {
478 let play_status = facade.get_play_status().await.unwrap();
479 assert_eq!(play_status, *PLAY_STATUS);
480 };
481 future::join(facade_fut, play_status_fut).await;
482 }
483
484 #[fasync::run_singlethreaded(test)]
485 async fn test_get_player_application_settings() {
486 let (facade, application_settings_fut) = MockAvrcpTester::new()
487 .expect_get_player_application_settings(
488 PLAYER_APPLICATION_SETTINGS.clone(),
489 &PLAYER_APPLICATION_SETTINGS_ATTRIBUTE_IDS,
490 )
491 .build_controller();
492 let facade_fut = async move {
493 let application_settings = facade
494 .get_player_application_settings(PLAYER_APPLICATION_SETTINGS_ATTRIBUTE_IDS.clone())
495 .await
496 .unwrap();
497 assert_eq!(application_settings, *PLAYER_APPLICATION_SETTINGS);
498 };
499 future::join(facade_fut, application_settings_fut).await;
500 }
501
502 #[fasync::run_singlethreaded(test)]
503 async fn test_set_player_application_settings() {
504 let (facade, application_settings_fut) = MockAvrcpTester::new()
505 .expect_set_player_application_settings(
506 PLAYER_APPLICATION_SETTINGS.clone(),
507 &PLAYER_APPLICATION_SETTINGS_INPUT,
508 )
509 .build_controller();
510 let facade_fut = async move {
511 let application_settings = facade
512 .set_player_application_settings(PLAYER_APPLICATION_SETTINGS_INPUT.clone())
513 .await
514 .unwrap();
515 assert_eq!(application_settings, *PLAYER_APPLICATION_SETTINGS);
516 };
517 future::join(facade_fut, application_settings_fut).await;
518 }
519
520 #[fasync::run_singlethreaded(test)]
521 async fn test_inform_battery_status() {
522 let (facade, battery_status_fut) = MockAvrcpTester::new()
523 .expect_inform_battery_status(CustomBatteryStatus::Normal)
524 .build_controller();
525 let facade_fut = async move {
526 facade.inform_battery_status(CustomBatteryStatus::Normal).await.unwrap();
527 };
528 future::join(facade_fut, battery_status_fut).await;
529 }
530
531 #[fasync::run_singlethreaded(test)]
532 async fn test_set_addressed_player() {
533 let addressed_player = 5;
534 let (facade, addressed_player_fut) =
535 MockAvrcpTester::new().expect_set_addressed_player(addressed_player).build_controller();
536 let facade_fut = async move {
537 facade.set_addressed_player(addressed_player).await.unwrap();
538 };
539 future::join(facade_fut, addressed_player_fut).await;
540 }
541
542 #[fasync::run_singlethreaded(test)]
543 async fn test_set_notification_filter() {
544 let input_notification_filter = 3;
545 let input_position_change_interval = 1;
546 let (facade, notification_filter_fut) = MockAvrcpTester::new()
547 .expect_set_notification_filter(
548 input_notification_filter,
549 input_position_change_interval,
550 )
551 .build_controller();
552 let facade_fut = async move {
553 facade
554 .set_notification_filter(input_notification_filter, input_position_change_interval)
555 .await
556 .unwrap();
557 };
558 future::join(facade_fut, notification_filter_fut).await;
559 }
560}