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 let proxy_opt = self.inner.read().controller_proxy.clone();
90 match proxy_opt {
91 Some(proxy) => match proxy.get_media_attributes().await? {
92 Ok(media_attribs) => Ok(format!("Media attributes: {:#?}", media_attribs)),
93 Err(e) => fx_err_and_bail!(
94 &with_line!(tag),
95 format!("Error fetching media attributes: {:?}", e)
96 ),
97 },
98 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
99 }
100 }
101
102 pub async fn get_play_status(&self) -> Result<CustomPlayStatus, Error> {
104 let tag = "AvrcpFacade::get_play_status";
105 let proxy_opt = self.inner.read().controller_proxy.clone();
106 match proxy_opt {
107 Some(proxy) => match proxy.get_play_status().await? {
108 Ok(play_status) => Ok(CustomPlayStatus::new(&play_status)),
109 Err(e) => fx_err_and_bail!(
110 &with_line!(tag),
111 format!("Error fetching play status: {:?}", e)
112 ),
113 },
114 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
115 }
116 }
117
118 pub async fn send_command(&self, command: CustomAvcPanelCommand) -> Result<(), Error> {
123 let tag = "AvrcpFacade::send_command";
124 let proxy_opt = self.inner.read().controller_proxy.clone();
125 let result = match proxy_opt {
126 Some(proxy) => proxy.send_command(command.into()).await?,
127 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
128 };
129 match result {
130 Ok(res) => Ok(res),
131 Err(err) => {
132 fx_err_and_bail!(&with_line!(tag), format!("Error sending command:{:?}", err))
133 }
134 }
135 }
136
137 pub async fn set_absolute_volume(&self, absolute_volume: u8) -> Result<u8, Error> {
142 let tag = "AvrcpFacade::set_absolute_volume";
143 let proxy_opt = self.inner.read().controller_proxy.clone();
144
145 let result = match proxy_opt {
146 Some(proxy) => proxy.set_absolute_volume(absolute_volume).await?,
147 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
148 };
149 match result {
150 Ok(res) => Ok(res),
151 Err(err) => {
152 fx_err_and_bail!(&with_line!(tag), format!("Error setting volume:{:?}", err))
153 }
154 }
155 }
156
157 pub async fn get_player_application_settings(
162 &self,
163 attribute_ids: CustomPlayerApplicationSettingsAttributeIds,
164 ) -> Result<CustomPlayerApplicationSettings, Error> {
165 let tag = "AvrcpFacade::get_player_application_settings";
166 let proxy_opt = self.inner.read().controller_proxy.clone();
167 match proxy_opt {
168 Some(proxy) => {
169 match proxy.get_player_application_settings(&attribute_ids.to_vec()).await? {
170 Ok(player_application_settings) => Ok(player_application_settings.into()),
171 Err(e) => fx_err_and_bail!(
172 &with_line!(tag),
173 format!("Error fetching player application settings: {:?}", e)
174 ),
175 }
176 }
177 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
178 }
179 }
180
181 pub async fn set_player_application_settings(
186 &self,
187 settings: CustomPlayerApplicationSettings,
188 ) -> Result<CustomPlayerApplicationSettings, Error> {
189 let tag = "AvrcpFacade::set_player_application_settings";
190 let proxy_opt = self.inner.read().controller_proxy.clone();
191 match proxy_opt {
192 Some(proxy) => match proxy.set_player_application_settings(&settings.into()).await? {
193 Ok(player_application_settings) => Ok(player_application_settings.into()),
194 Err(e) => fx_err_and_bail!(
195 &with_line!(tag),
196 format!("Error fetching player application settings: {:?}", e)
197 ),
198 },
199 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
200 }
201 }
202
203 pub async fn inform_battery_status(
208 &self,
209 battery_status: CustomBatteryStatus,
210 ) -> Result<(), Error> {
211 let tag = "AvrcpFacade::inform_battery_status";
212 let proxy_opt = self.inner.read().controller_proxy.clone();
213 match proxy_opt {
214 Some(proxy) => match proxy.inform_battery_status(battery_status.into()).await? {
215 Ok(()) => Ok(()),
216 Err(e) => fx_err_and_bail!(
217 &with_line!(tag),
218 format!("Error informing battery status: {:?}", e)
219 ),
220 },
221 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
222 }
223 }
224
225 pub async fn set_addressed_player(&self, player_id: u16) -> Result<(), Error> {
230 let tag = "AvrcpFacade::set_addressed_player";
231 let proxy_opt = self.inner.read().controller_proxy.clone();
232 match proxy_opt {
233 Some(proxy) => match proxy.set_addressed_player(player_id).await? {
234 Ok(()) => Ok(()),
235 Err(e) => fx_err_and_bail!(
236 &with_line!(tag),
237 format!("Error setting addressed player: {:?}", e)
238 ),
239 },
240 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
241 }
242 }
243
244 pub async fn set_notification_filter(
251 &self,
252 notifications_filter: u32,
253 position_change_interval: u32,
254 ) -> Result<(), Error> {
255 let tag = "AvrcpFacade::set_notification_filter";
256 let notifications = match Notifications::from_bits(notifications_filter) {
257 Some(notifications) => notifications,
258 _ => fx_err_and_bail!(
259 &with_line!(tag),
260 format!(
261 "Invalid bit flags value for notifications filter: {:?}",
262 notifications_filter
263 )
264 ),
265 };
266
267 let proxy_opt = self.inner.read().controller_proxy.clone();
268 match proxy_opt {
269 Some(proxy) => {
270 match proxy.set_notification_filter(notifications, position_change_interval) {
271 Ok(()) => Ok(()),
272 Err(e) => fx_err_and_bail!(
273 &with_line!(tag),
274 format!("Error setting notification filter: {:?}", e)
275 ),
276 }
277 }
278 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
279 }
280 }
281
282 pub async fn notify_notification_handled(&self) -> Result<(), Error> {
284 let tag = "AvrcpFacade::notify_notification_handled";
285 let proxy_opt = self.inner.read().controller_proxy.clone();
286 match proxy_opt {
287 Some(proxy) => match proxy.notify_notification_handled() {
288 Ok(()) => Ok(()),
289 Err(e) => fx_err_and_bail!(
290 &with_line!(tag),
291 format!("Error setting notification filter: {:?}", e)
292 ),
293 },
294 None => fx_err_and_bail!(&with_line!(tag), "No AVRCP service proxy available"),
295 }
296 }
297
298 fn clear(&self) {
300 self.inner.write().avrcp_service_proxy = None;
301 self.inner.write().controller_proxy = None;
302 }
303
304 pub async fn cleanup(&self) -> Result<(), Error> {
306 self.clear();
307 Ok(())
308 }
309}
310
311#[cfg(test)]
312mod tests {
313
314 use super::super::types::{
315 CustomCustomAttributeValue, CustomCustomPlayerApplicationSetting, CustomEqualizer,
316 CustomRepeatStatusMode, CustomScanMode,
317 };
318 use super::*;
319 use assert_matches::assert_matches;
320 use fidl::endpoints::create_proxy_and_stream;
321 use fidl_fuchsia_bluetooth_avrcp::{BatteryStatus, ControllerRequest, PlayStatus};
322 use fuchsia_async as fasync;
323 use futures::prelude::*;
324 use std::sync::LazyLock;
325
326 static PLAY_STATUS: LazyLock<CustomPlayStatus> = LazyLock::new(|| CustomPlayStatus {
327 song_length: Some(120),
328 song_position: Some(10),
329 playback_status: Some(4),
330 });
331 static PLAYER_APPLICATION_SETTINGS: LazyLock<CustomPlayerApplicationSettings> =
332 LazyLock::new(|| CustomPlayerApplicationSettings {
333 equalizer: Some(CustomEqualizer::Off),
334 repeat_status_mode: Some(CustomRepeatStatusMode::AllTrackRepeat),
335 shuffle_mode: None,
336 scan_mode: Some(CustomScanMode::GroupScan),
337 custom_settings: Some(vec![CustomCustomPlayerApplicationSetting {
338 attribute_id: Some(1),
339 attribute_name: Some("attribute".to_string()),
340 possible_values: Some(vec![CustomCustomAttributeValue {
341 description: "description".to_string(),
342 value: 5,
343 }]),
344 current_value: Some(5),
345 }]),
346 });
347 static PLAYER_APPLICATION_SETTINGS_INPUT: LazyLock<CustomPlayerApplicationSettings> =
348 LazyLock::new(|| CustomPlayerApplicationSettings {
349 equalizer: Some(CustomEqualizer::Off),
350 repeat_status_mode: None,
351 shuffle_mode: None,
352 scan_mode: None,
353 custom_settings: Some(vec![CustomCustomPlayerApplicationSetting {
354 attribute_id: Some(1),
355 attribute_name: Some("attribute".to_string()),
356 possible_values: Some(vec![CustomCustomAttributeValue {
357 description: "description".to_string(),
358 value: 5,
359 }]),
360 current_value: Some(5),
361 }]),
362 });
363 static PLAYER_APPLICATION_SETTINGS_ATTRIBUTE_IDS: LazyLock<
364 CustomPlayerApplicationSettingsAttributeIds,
365 > = LazyLock::new(|| CustomPlayerApplicationSettingsAttributeIds {
366 attribute_ids: Some(vec![1]),
367 });
368 struct MockAvrcpTester {
369 expected_state: Vec<Box<dyn FnOnce(ControllerRequest) + Send + 'static>>,
370 }
371
372 impl MockAvrcpTester {
373 fn new() -> Self {
374 Self { expected_state: vec![] }
375 }
376
377 fn push(mut self, request: impl FnOnce(ControllerRequest) + Send + 'static) -> Self {
378 self.expected_state.push(Box::new(request));
379 self
380 }
381
382 fn build_controller(self) -> (AvrcpFacade, impl Future<Output = ()>) {
383 let (proxy, mut stream) = create_proxy_and_stream::<ControllerMarker>();
384 let fut = async move {
385 for expected in self.expected_state {
386 expected(stream.next().await.unwrap().unwrap());
387 }
388 assert_matches!(stream.next().await, None);
389 };
390 (
391 AvrcpFacade {
392 inner: RwLock::new(AvrcpFacadeInner {
393 controller_proxy: Some(proxy),
394 avrcp_service_proxy: None,
395 }),
396 },
397 fut,
398 )
399 }
400
401 fn expect_get_play_status(self, result: CustomPlayStatus) -> Self {
402 self.push(move |req| match req {
403 ControllerRequest::GetPlayStatus { responder } => {
404 responder.send(Ok(&PlayStatus::from(result))).unwrap();
405 }
406 _ => {}
407 })
408 }
409
410 fn expect_get_player_application_settings(
411 self,
412 result: CustomPlayerApplicationSettings,
413 input: &'static CustomPlayerApplicationSettingsAttributeIds,
414 ) -> Self {
415 self.push(move |req| match req {
416 ControllerRequest::GetPlayerApplicationSettings { attribute_ids, responder } => {
417 assert_eq!(attribute_ids, input.to_vec());
418 responder.send(Ok(&result.into())).unwrap();
419 }
420 _ => {}
421 })
422 }
423
424 fn expect_set_player_application_settings(
425 self,
426 result: CustomPlayerApplicationSettings,
427 input: &'static CustomPlayerApplicationSettings,
428 ) -> Self {
429 self.push(move |req| match req {
430 ControllerRequest::SetPlayerApplicationSettings {
431 requested_settings,
432 responder,
433 } => {
434 let player_application_settings: CustomPlayerApplicationSettings =
435 requested_settings.into();
436 assert_eq!(player_application_settings, *input);
437 responder.send(Ok(&result.into())).unwrap();
438 }
439 _ => {}
440 })
441 }
442
443 fn expect_inform_battery_status(self, input: CustomBatteryStatus) -> Self {
444 self.push(move |req| match req {
445 ControllerRequest::InformBatteryStatus { battery_status, responder } => {
446 let battery_status_expected: BatteryStatus = input.into();
447 assert_eq!(battery_status_expected, battery_status);
448 responder.send(Ok(())).unwrap();
449 }
450 _ => {}
451 })
452 }
453
454 fn expect_set_addressed_player(self, input: u16) -> Self {
455 self.push(move |req| match req {
456 ControllerRequest::SetAddressedPlayer { player_id, responder } => {
457 assert_eq!(input, player_id);
458 responder.send(Ok(())).unwrap();
459 }
460 _ => {}
461 })
462 }
463
464 fn expect_set_notification_filter(
465 self,
466 input_notification_filter: u32,
467 input_position_change_interval: u32,
468 ) -> Self {
469 self.push(move |req| match req {
470 ControllerRequest::SetNotificationFilter {
471 notifications,
472 position_change_interval,
473 ..
474 } => {
475 assert_eq!(
476 Notifications::from_bits(input_notification_filter).unwrap(),
477 notifications
478 );
479 assert_eq!(input_position_change_interval, position_change_interval);
480 }
481 _ => {}
482 })
483 }
484 }
485 #[fasync::run_singlethreaded(test)]
486 async fn test_get_play_status() {
487 let (facade, play_status_fut) =
488 MockAvrcpTester::new().expect_get_play_status(*PLAY_STATUS).build_controller();
489 let facade_fut = async move {
490 let play_status = facade.get_play_status().await.unwrap();
491 assert_eq!(play_status, *PLAY_STATUS);
492 };
493 future::join(facade_fut, play_status_fut).await;
494 }
495
496 #[fasync::run_singlethreaded(test)]
497 async fn test_get_player_application_settings() {
498 let (facade, application_settings_fut) = MockAvrcpTester::new()
499 .expect_get_player_application_settings(
500 PLAYER_APPLICATION_SETTINGS.clone(),
501 &PLAYER_APPLICATION_SETTINGS_ATTRIBUTE_IDS,
502 )
503 .build_controller();
504 let facade_fut = async move {
505 let application_settings = facade
506 .get_player_application_settings(PLAYER_APPLICATION_SETTINGS_ATTRIBUTE_IDS.clone())
507 .await
508 .unwrap();
509 assert_eq!(application_settings, *PLAYER_APPLICATION_SETTINGS);
510 };
511 future::join(facade_fut, application_settings_fut).await;
512 }
513
514 #[fasync::run_singlethreaded(test)]
515 async fn test_set_player_application_settings() {
516 let (facade, application_settings_fut) = MockAvrcpTester::new()
517 .expect_set_player_application_settings(
518 PLAYER_APPLICATION_SETTINGS.clone(),
519 &PLAYER_APPLICATION_SETTINGS_INPUT,
520 )
521 .build_controller();
522 let facade_fut = async move {
523 let application_settings = facade
524 .set_player_application_settings(PLAYER_APPLICATION_SETTINGS_INPUT.clone())
525 .await
526 .unwrap();
527 assert_eq!(application_settings, *PLAYER_APPLICATION_SETTINGS);
528 };
529 future::join(facade_fut, application_settings_fut).await;
530 }
531
532 #[fasync::run_singlethreaded(test)]
533 async fn test_inform_battery_status() {
534 let (facade, battery_status_fut) = MockAvrcpTester::new()
535 .expect_inform_battery_status(CustomBatteryStatus::Normal)
536 .build_controller();
537 let facade_fut = async move {
538 facade.inform_battery_status(CustomBatteryStatus::Normal).await.unwrap();
539 };
540 future::join(facade_fut, battery_status_fut).await;
541 }
542
543 #[fasync::run_singlethreaded(test)]
544 async fn test_set_addressed_player() {
545 let addressed_player = 5;
546 let (facade, addressed_player_fut) =
547 MockAvrcpTester::new().expect_set_addressed_player(addressed_player).build_controller();
548 let facade_fut = async move {
549 facade.set_addressed_player(addressed_player).await.unwrap();
550 };
551 future::join(facade_fut, addressed_player_fut).await;
552 }
553
554 #[fasync::run_singlethreaded(test)]
555 async fn test_set_notification_filter() {
556 let input_notification_filter = 3;
557 let input_position_change_interval = 1;
558 let (facade, notification_filter_fut) = MockAvrcpTester::new()
559 .expect_set_notification_filter(
560 input_notification_filter,
561 input_position_change_interval,
562 )
563 .build_controller();
564 let facade_fut = async move {
565 facade
566 .set_notification_filter(input_notification_filter, input_position_change_interval)
567 .await
568 .unwrap();
569 };
570 future::join(facade_fut, notification_filter_fut).await;
571 }
572}