1 //! Media service facade
2
3 use bt_topshim::btif::{BluetoothInterface, RawAddress};
4 use bt_topshim::profiles::a2dp::{
5 A2dp, A2dpCallbacksDispatcher, A2dpSink, A2dpSinkCallbacksDispatcher,
6 };
7 use bt_topshim::profiles::avrcp::{Avrcp, AvrcpCallbacksDispatcher};
8 use bt_topshim_facade_protobuf::facade::{
9 A2dpSourceConnectRequest, A2dpSourceConnectResponse, StartA2dpRequest, StartA2dpResponse,
10 };
11 use bt_topshim_facade_protobuf::facade_grpc::{create_media_service, MediaService};
12
13 use grpcio::*;
14
15 use std::sync::{Arc, Mutex};
16 use tokio::runtime::Runtime;
17
get_a2dp_dispatcher() -> A2dpCallbacksDispatcher18 fn get_a2dp_dispatcher() -> A2dpCallbacksDispatcher {
19 A2dpCallbacksDispatcher { dispatch: Box::new(move |_cb| {}) }
20 }
21
get_a2dp_sink_dispatcher() -> A2dpSinkCallbacksDispatcher22 fn get_a2dp_sink_dispatcher() -> A2dpSinkCallbacksDispatcher {
23 A2dpSinkCallbacksDispatcher { dispatch: Box::new(move |_cb| {}) }
24 }
25
get_avrcp_dispatcher() -> AvrcpCallbacksDispatcher26 fn get_avrcp_dispatcher() -> AvrcpCallbacksDispatcher {
27 AvrcpCallbacksDispatcher { dispatch: Box::new(move |_cb| {}) }
28 }
29
30 /// Main object for Media facade service
31 #[derive(Clone)]
32 pub struct MediaServiceImpl {
33 #[allow(dead_code)]
34 rt: Arc<Runtime>,
35 pub btif_a2dp: Arc<Mutex<A2dp>>,
36 btif_a2dp_sink: Arc<Mutex<A2dpSink>>,
37 pub btif_avrcp: Arc<Mutex<Avrcp>>,
38 }
39
40 impl MediaServiceImpl {
41 /// Create a new instance of the root facade service
create(rt: Arc<Runtime>, btif_intf: Arc<Mutex<BluetoothInterface>>) -> grpcio::Service42 pub fn create(rt: Arc<Runtime>, btif_intf: Arc<Mutex<BluetoothInterface>>) -> grpcio::Service {
43 let mut btif_a2dp = A2dp::new(&btif_intf.lock().unwrap());
44 let btif_a2dp_sink = A2dpSink::new(&btif_intf.lock().unwrap());
45 let mut btif_avrcp = Avrcp::new(&btif_intf.lock().unwrap());
46 btif_a2dp.initialize(get_a2dp_dispatcher());
47 btif_avrcp.initialize(get_avrcp_dispatcher());
48
49 create_media_service(Self {
50 rt,
51 btif_a2dp: Arc::new(Mutex::new(btif_a2dp)),
52 btif_a2dp_sink: Arc::new(Mutex::new(btif_a2dp_sink)),
53 btif_avrcp: Arc::new(Mutex::new(btif_avrcp)),
54 })
55 }
56 }
57
58 impl MediaService for MediaServiceImpl {
start_a2dp( &mut self, ctx: RpcContext<'_>, req: StartA2dpRequest, sink: UnarySink<StartA2dpResponse>, )59 fn start_a2dp(
60 &mut self,
61 ctx: RpcContext<'_>,
62 req: StartA2dpRequest,
63 sink: UnarySink<StartA2dpResponse>,
64 ) {
65 if req.start_a2dp_source {
66 ctx.spawn(async move {
67 sink.success(StartA2dpResponse::default()).await.unwrap();
68 })
69 } else if req.start_a2dp_sink {
70 self.btif_a2dp_sink.lock().unwrap().initialize(get_a2dp_sink_dispatcher());
71 ctx.spawn(async move {
72 sink.success(StartA2dpResponse::default()).await.unwrap();
73 })
74 }
75 }
76
a2dp_source_connect( &mut self, ctx: RpcContext<'_>, req: A2dpSourceConnectRequest, sink: UnarySink<A2dpSourceConnectResponse>, )77 fn a2dp_source_connect(
78 &mut self,
79 ctx: RpcContext<'_>,
80 req: A2dpSourceConnectRequest,
81 sink: UnarySink<A2dpSourceConnectResponse>,
82 ) {
83 let a2dp = self.btif_a2dp.clone();
84 ctx.spawn(async move {
85 if let Some(addr) = RawAddress::from_string(req.address.clone()) {
86 a2dp.lock().unwrap().connect(addr);
87 a2dp.lock().unwrap().set_active_device(addr);
88 sink.success(A2dpSourceConnectResponse::default()).await.unwrap();
89 } else {
90 sink.fail(RpcStatus::with_message(
91 RpcStatusCode::INVALID_ARGUMENT,
92 format!("Invalid Request Address: {}", req.address),
93 ))
94 .await
95 .unwrap();
96 }
97 })
98 }
99 }
100