1 /*
2 * Copyright 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "avrcp_service.h"
18
19 #include <base/bind.h>
20 #include <base/logging.h>
21 #include <base/task/cancelable_task_tracker.h>
22 #include <base/threading/thread.h>
23 #include <mutex>
24 #include <sstream>
25
26 #include "bta_closure_api.h"
27 #include "btif_av.h"
28 #include "btif_common.h"
29 #include "device.h"
30
31 namespace bluetooth {
32 namespace avrcp {
33 // Static variables and interface definitions
34 AvrcpService* AvrcpService::instance_ = nullptr;
35 AvrcpService::ServiceInterfaceImpl* AvrcpService::service_interface_ = nullptr;
36
37 std::mutex jni_mutex_;
38 base::MessageLoop* jni_message_loop_ = nullptr;
39 base::CancelableTaskTracker task_tracker_;
40
do_in_avrcp_jni(const base::Closure & task)41 void do_in_avrcp_jni(const base::Closure& task) {
42 std::lock_guard<std::mutex> lock(jni_mutex_);
43
44 if (jni_message_loop_ == nullptr) {
45 LOG(WARNING) << __func__ << ": jni_message_loop_ is null";
46 return;
47 }
48
49 task_tracker_.PostTask(jni_message_loop_->task_runner().get(), FROM_HERE,
50 task);
51 }
52
53 class A2dpInterfaceImpl : public A2dpInterface {
active_peer()54 RawAddress active_peer() override { return btif_av_source_active_peer(); }
55 } a2dp_interface_;
56
57 class AvrcpInterfaceImpl : public AvrcpInterface {
58 public:
AddRecord(uint16_t service_uuid,const char * p_service_name,const char * p_provider_name,uint16_t categories,uint32_t sdp_handle,bool browse_supported,uint16_t profile_version)59 uint16_t AddRecord(uint16_t service_uuid, const char* p_service_name,
60 const char* p_provider_name, uint16_t categories,
61 uint32_t sdp_handle, bool browse_supported,
62 uint16_t profile_version) override {
63 return AVRC_AddRecord(service_uuid, p_service_name, p_provider_name,
64 categories, sdp_handle, browse_supported,
65 profile_version);
66 }
67
FindService(uint16_t service_uuid,const RawAddress & bd_addr,tAVRC_SDP_DB_PARAMS * p_db,tAVRC_FIND_CBACK p_cback)68 uint16_t FindService(uint16_t service_uuid, const RawAddress& bd_addr,
69 tAVRC_SDP_DB_PARAMS* p_db,
70 tAVRC_FIND_CBACK p_cback) override {
71 return AVRC_FindService(service_uuid, bd_addr, p_db, p_cback);
72 }
73
Open(uint8_t * p_handle,tAVRC_CONN_CB * p_ccb,const RawAddress & bd_addr)74 uint16_t Open(uint8_t* p_handle, tAVRC_CONN_CB* p_ccb,
75 const RawAddress& bd_addr) override {
76 return AVRC_Open(p_handle, p_ccb, bd_addr);
77 }
78
OpenBrowse(uint8_t handle,uint8_t conn_role)79 uint16_t OpenBrowse(uint8_t handle, uint8_t conn_role) override {
80 return AVRC_OpenBrowse(handle, conn_role);
81 }
82
GetPeerMtu(uint8_t handle)83 uint16_t GetPeerMtu(uint8_t handle) override {
84 return AVCT_GetPeerMtu(handle);
85 }
86
GetBrowseMtu(uint8_t handle)87 uint16_t GetBrowseMtu(uint8_t handle) override {
88 return AVCT_GetBrowseMtu(handle);
89 }
90
Close(uint8_t handle)91 uint16_t Close(uint8_t handle) override { return AVRC_Close(handle); }
92
CloseBrowse(uint8_t handle)93 uint16_t CloseBrowse(uint8_t handle) override {
94 return AVRC_CloseBrowse(handle);
95 }
96
MsgReq(uint8_t handle,uint8_t label,uint8_t ctype,BT_HDR * p_pkt)97 uint16_t MsgReq(uint8_t handle, uint8_t label, uint8_t ctype,
98 BT_HDR* p_pkt) override {
99 return AVRC_MsgReq(handle, label, ctype, p_pkt);
100 }
101 } avrcp_interface_;
102
103 class SdpInterfaceImpl : public SdpInterface {
104 public:
InitDiscoveryDb(tSDP_DISCOVERY_DB * a,uint32_t b,uint16_t c,const bluetooth::Uuid * d,uint16_t e,uint16_t * f)105 bool InitDiscoveryDb(tSDP_DISCOVERY_DB* a, uint32_t b, uint16_t c,
106 const bluetooth::Uuid* d, uint16_t e,
107 uint16_t* f) override {
108 return SDP_InitDiscoveryDb(a, b, c, d, e, f);
109 }
110
ServiceSearchAttributeRequest(const RawAddress & a,tSDP_DISCOVERY_DB * b,tSDP_DISC_CMPL_CB * c)111 bool ServiceSearchAttributeRequest(const RawAddress& a, tSDP_DISCOVERY_DB* b,
112 tSDP_DISC_CMPL_CB* c) override {
113 return SDP_ServiceSearchAttributeRequest(a, b, c);
114 }
115
FindServiceInDb(tSDP_DISCOVERY_DB * a,uint16_t b,t_sdp_disc_rec * c)116 tSDP_DISC_REC* FindServiceInDb(tSDP_DISCOVERY_DB* a, uint16_t b,
117 t_sdp_disc_rec* c) override {
118 return SDP_FindServiceInDb(a, b, c);
119 }
120
FindAttributeInRec(t_sdp_disc_rec * a,uint16_t b)121 tSDP_DISC_ATTR* FindAttributeInRec(t_sdp_disc_rec* a, uint16_t b) override {
122 return SDP_FindAttributeInRec(a, b);
123 }
124
FindProfileVersionInRec(t_sdp_disc_rec * a,uint16_t b,uint16_t * c)125 bool FindProfileVersionInRec(t_sdp_disc_rec* a, uint16_t b,
126 uint16_t* c) override {
127 return SDP_FindProfileVersionInRec(a, b, c);
128 }
129 } sdp_interface_;
130
131 // A wrapper class for the media callbacks that handles thread
132 // switching/synchronization so the devices don't have to worry about it.
133 class MediaInterfaceWrapper : public MediaInterface {
134 public:
MediaInterfaceWrapper(MediaInterface * cb)135 MediaInterfaceWrapper(MediaInterface* cb) : wrapped_(cb){};
136
SendKeyEvent(uint8_t key,KeyState state)137 void SendKeyEvent(uint8_t key, KeyState state) override {
138 do_in_avrcp_jni(base::Bind(&MediaInterface::SendKeyEvent,
139 base::Unretained(wrapped_), key, state));
140 }
141
GetSongInfo(SongInfoCallback info_cb)142 void GetSongInfo(SongInfoCallback info_cb) override {
143 auto cb_lambda = [](SongInfoCallback cb, SongInfo data) {
144 do_in_bta_thread(FROM_HERE, base::Bind(cb, data));
145 };
146
147 auto bound_cb = base::Bind(cb_lambda, info_cb);
148
149 do_in_avrcp_jni(base::Bind(&MediaInterface::GetSongInfo,
150 base::Unretained(wrapped_), bound_cb));
151 }
152
GetPlayStatus(PlayStatusCallback status_cb)153 void GetPlayStatus(PlayStatusCallback status_cb) override {
154 auto cb_lambda = [](PlayStatusCallback cb, PlayStatus status) {
155 do_in_bta_thread(FROM_HERE, base::Bind(cb, status));
156 };
157
158 auto bound_cb = base::Bind(cb_lambda, status_cb);
159
160 do_in_avrcp_jni(base::Bind(&MediaInterface::GetPlayStatus,
161 base::Unretained(wrapped_), bound_cb));
162 }
163
GetNowPlayingList(NowPlayingCallback now_playing_cb)164 void GetNowPlayingList(NowPlayingCallback now_playing_cb) override {
165 auto cb_lambda = [](NowPlayingCallback cb, std::string curr_media_id,
166 std::vector<SongInfo> song_list) {
167 do_in_bta_thread(FROM_HERE,
168 base::Bind(cb, curr_media_id, std::move(song_list)));
169 };
170
171 auto bound_cb = base::Bind(cb_lambda, now_playing_cb);
172
173 do_in_avrcp_jni(base::Bind(&MediaInterface::GetNowPlayingList,
174 base::Unretained(wrapped_), bound_cb));
175 }
176
GetMediaPlayerList(MediaListCallback list_cb)177 void GetMediaPlayerList(MediaListCallback list_cb) override {
178 auto cb_lambda = [](MediaListCallback cb, uint16_t curr_player,
179 std::vector<MediaPlayerInfo> player_list) {
180 do_in_bta_thread(FROM_HERE,
181 base::Bind(cb, curr_player, std::move(player_list)));
182 };
183
184 auto bound_cb = base::Bind(cb_lambda, list_cb);
185
186 do_in_avrcp_jni(base::Bind(&MediaInterface::GetMediaPlayerList,
187 base::Unretained(wrapped_), bound_cb));
188 }
189
GetFolderItems(uint16_t player_id,std::string media_id,FolderItemsCallback folder_cb)190 void GetFolderItems(uint16_t player_id, std::string media_id,
191 FolderItemsCallback folder_cb) override {
192 auto cb_lambda = [](FolderItemsCallback cb,
193 std::vector<ListItem> item_list) {
194 do_in_bta_thread(FROM_HERE, base::Bind(cb, std::move(item_list)));
195 };
196
197 auto bound_cb = base::Bind(cb_lambda, folder_cb);
198
199 do_in_avrcp_jni(base::Bind(&MediaInterface::GetFolderItems,
200 base::Unretained(wrapped_), player_id, media_id,
201 bound_cb));
202 }
203
SetBrowsedPlayer(uint16_t player_id,SetBrowsedPlayerCallback browse_cb)204 void SetBrowsedPlayer(uint16_t player_id,
205 SetBrowsedPlayerCallback browse_cb) override {
206 auto cb_lambda = [](SetBrowsedPlayerCallback cb, bool success,
207 std::string root_id, uint32_t num_items) {
208 do_in_bta_thread(FROM_HERE, base::Bind(cb, success, root_id, num_items));
209 };
210
211 auto bound_cb = base::Bind(cb_lambda, browse_cb);
212
213 do_in_avrcp_jni(base::Bind(&MediaInterface::SetBrowsedPlayer,
214 base::Unretained(wrapped_), player_id,
215 bound_cb));
216 }
217
PlayItem(uint16_t player_id,bool now_playing,std::string media_id)218 void PlayItem(uint16_t player_id, bool now_playing,
219 std::string media_id) override {
220 do_in_avrcp_jni(base::Bind(&MediaInterface::PlayItem,
221 base::Unretained(wrapped_), player_id,
222 now_playing, media_id));
223 }
224
SetActiveDevice(const RawAddress & address)225 void SetActiveDevice(const RawAddress& address) override {
226 do_in_avrcp_jni(base::Bind(&MediaInterface::SetActiveDevice,
227 base::Unretained(wrapped_), address));
228 }
229
RegisterUpdateCallback(MediaCallbacks * callback)230 void RegisterUpdateCallback(MediaCallbacks* callback) override {
231 wrapped_->RegisterUpdateCallback(callback);
232 }
233
UnregisterUpdateCallback(MediaCallbacks * callback)234 void UnregisterUpdateCallback(MediaCallbacks* callback) override {
235 wrapped_->UnregisterUpdateCallback(callback);
236 }
237
238 private:
239 MediaInterface* wrapped_;
240 };
241
242 // A wrapper class for the media callbacks that handles thread
243 // switching/synchronization so the devices don't have to worry about it.
244 class VolumeInterfaceWrapper : public VolumeInterface {
245 public:
VolumeInterfaceWrapper(VolumeInterface * interface)246 VolumeInterfaceWrapper(VolumeInterface* interface) : wrapped_(interface){};
247
DeviceConnected(const RawAddress & bdaddr)248 void DeviceConnected(const RawAddress& bdaddr) override {
249 do_in_avrcp_jni(
250 base::Bind(static_cast<void (VolumeInterface::*)(const RawAddress&)>(
251 &VolumeInterface::DeviceConnected),
252 base::Unretained(wrapped_), bdaddr));
253 }
254
DeviceConnected(const RawAddress & bdaddr,VolumeChangedCb cb)255 void DeviceConnected(const RawAddress& bdaddr, VolumeChangedCb cb) override {
256 auto cb_lambda = [](VolumeChangedCb cb, int8_t volume) {
257 do_in_bta_thread(FROM_HERE, base::Bind(cb, volume));
258 };
259
260 auto bound_cb = base::Bind(cb_lambda, cb);
261
262 do_in_avrcp_jni(base::Bind(static_cast<void (VolumeInterface::*)(
263 const RawAddress&, VolumeChangedCb)>(
264 &VolumeInterface::DeviceConnected),
265 base::Unretained(wrapped_), bdaddr, bound_cb));
266 }
267
DeviceDisconnected(const RawAddress & bdaddr)268 void DeviceDisconnected(const RawAddress& bdaddr) override {
269 do_in_avrcp_jni(base::Bind(&VolumeInterface::DeviceDisconnected,
270 base::Unretained(wrapped_), bdaddr));
271 }
272
SetVolume(int8_t volume)273 void SetVolume(int8_t volume) override {
274 do_in_avrcp_jni(base::Bind(&VolumeInterface::SetVolume,
275 base::Unretained(wrapped_), volume));
276 }
277
278 private:
279 VolumeInterface* wrapped_;
280 };
281
Init(MediaInterface * media_interface,VolumeInterface * volume_interface)282 void AvrcpService::Init(MediaInterface* media_interface,
283 VolumeInterface* volume_interface) {
284 LOG(INFO) << "AVRCP Target Service started";
285
286 // TODO (apanicke): Add a function that sets up the SDP records once we
287 // remove the AVRCP SDP setup in AVDTP (bta_av_main.cc)
288
289 media_interface_ = new MediaInterfaceWrapper(media_interface);
290 media_interface->RegisterUpdateCallback(instance_);
291
292 VolumeInterfaceWrapper* wrapped_volume_interface = nullptr;
293 if (volume_interface != nullptr) {
294 wrapped_volume_interface = new VolumeInterfaceWrapper(volume_interface);
295 }
296
297 volume_interface_ = wrapped_volume_interface;
298
299 ConnectionHandler::Initialize(
300 base::Bind(&AvrcpService::DeviceCallback, base::Unretained(instance_)),
301 &avrcp_interface_, &sdp_interface_, wrapped_volume_interface);
302 connection_handler_ = ConnectionHandler::Get();
303 }
304
Cleanup()305 void AvrcpService::Cleanup() {
306 LOG(INFO) << "AVRCP Target Service stopped";
307
308 connection_handler_->CleanUp();
309 connection_handler_ = nullptr;
310 if (volume_interface_ != nullptr) {
311 delete volume_interface_;
312 }
313 delete media_interface_;
314 }
315
Get()316 AvrcpService* AvrcpService::Get() {
317 CHECK(instance_);
318 return instance_;
319 }
320
GetServiceInterface()321 ServiceInterface* AvrcpService::GetServiceInterface() {
322 if (service_interface_ == nullptr) {
323 service_interface_ = new ServiceInterfaceImpl();
324 }
325
326 return service_interface_;
327 }
328
ConnectDevice(const RawAddress & bdaddr)329 void AvrcpService::ConnectDevice(const RawAddress& bdaddr) {
330 LOG(INFO) << __PRETTY_FUNCTION__ << ": address=" << bdaddr.ToString();
331
332 connection_handler_->ConnectDevice(bdaddr);
333 }
334
DisconnectDevice(const RawAddress & bdaddr)335 void AvrcpService::DisconnectDevice(const RawAddress& bdaddr) {
336 LOG(INFO) << __PRETTY_FUNCTION__ << ": address=" << bdaddr.ToString();
337 connection_handler_->DisconnectDevice(bdaddr);
338 }
339
SendMediaUpdate(bool track_changed,bool play_state,bool queue)340 void AvrcpService::SendMediaUpdate(bool track_changed, bool play_state,
341 bool queue) {
342 LOG(INFO) << __PRETTY_FUNCTION__ << " track_changed=" << track_changed
343 << " : "
344 << " play_state=" << play_state << " : "
345 << " queue=" << queue;
346
347 // This function may be called on any thread, we need to make sure that the
348 // device update happens on the main thread.
349 for (const auto& device :
350 instance_->connection_handler_->GetListOfDevices()) {
351 do_in_bta_thread(FROM_HERE,
352 base::Bind(&Device::SendMediaUpdate, device.get()->Get(),
353 track_changed, play_state, queue));
354 }
355 }
356
SendFolderUpdate(bool available_players,bool addressed_players,bool uids)357 void AvrcpService::SendFolderUpdate(bool available_players,
358 bool addressed_players, bool uids) {
359 LOG(INFO) << __PRETTY_FUNCTION__ << " available_players=" << available_players
360 << " : "
361 << " addressed_players=" << addressed_players << " : "
362 << " uids=" << uids;
363
364 // Ensure that the update is posted to the correct thread
365 for (const auto& device :
366 instance_->connection_handler_->GetListOfDevices()) {
367 do_in_bta_thread(FROM_HERE,
368 base::Bind(&Device::SendFolderUpdate, device.get()->Get(),
369 available_players, addressed_players, uids));
370 }
371 }
372
373 // Send out the track changed info to update the playback state for each device
SendActiveDeviceChanged(const RawAddress & address)374 void AvrcpService::SendActiveDeviceChanged(const RawAddress& address) {
375 SendMediaUpdate(false, true, false);
376 }
377
DeviceCallback(std::shared_ptr<Device> new_device)378 void AvrcpService::DeviceCallback(std::shared_ptr<Device> new_device) {
379 if (new_device == nullptr) return;
380
381 // TODO (apanicke): Pass the interfaces into the connection handler
382 // so that the devices can be created with any interfaces they need.
383 new_device->RegisterInterfaces(media_interface_, &a2dp_interface_,
384 volume_interface_);
385 }
386
387 // Service Interface
Init(MediaInterface * media_interface,VolumeInterface * volume_interface)388 void AvrcpService::ServiceInterfaceImpl::Init(
389 MediaInterface* media_interface, VolumeInterface* volume_interface) {
390 std::lock_guard<std::mutex> lock(service_interface_lock_);
391
392 // TODO: This function should block until the service is completely up so
393 // that its possible to call Get() on the service immediately after calling
394 // init without issues.
395
396 CHECK(instance_ == nullptr);
397 instance_ = new AvrcpService();
398
399 {
400 std::lock_guard<std::mutex> jni_lock(jni_mutex_);
401 jni_message_loop_ = get_jni_message_loop();
402 }
403
404 do_in_bta_thread(FROM_HERE,
405 base::Bind(&AvrcpService::Init, base::Unretained(instance_),
406 media_interface, volume_interface));
407 }
408
ConnectDevice(const RawAddress & bdaddr)409 bool AvrcpService::ServiceInterfaceImpl::ConnectDevice(
410 const RawAddress& bdaddr) {
411 std::lock_guard<std::mutex> lock(service_interface_lock_);
412 CHECK(instance_ != nullptr);
413 do_in_bta_thread(FROM_HERE, base::Bind(&AvrcpService::ConnectDevice,
414 base::Unretained(instance_), bdaddr));
415 return true;
416 }
417
DisconnectDevice(const RawAddress & bdaddr)418 bool AvrcpService::ServiceInterfaceImpl::DisconnectDevice(
419 const RawAddress& bdaddr) {
420 std::lock_guard<std::mutex> lock(service_interface_lock_);
421 CHECK(instance_ != nullptr);
422 do_in_bta_thread(FROM_HERE, base::Bind(&AvrcpService::DisconnectDevice,
423 base::Unretained(instance_), bdaddr));
424 return true;
425 }
426
Cleanup()427 bool AvrcpService::ServiceInterfaceImpl::Cleanup() {
428 std::lock_guard<std::mutex> lock(service_interface_lock_);
429
430 if (instance_ == nullptr) return false;
431
432 {
433 std::lock_guard<std::mutex> jni_lock(jni_mutex_);
434 task_tracker_.TryCancelAll();
435 jni_message_loop_ = nullptr;
436 }
437
438 do_in_bta_thread(FROM_HERE,
439 base::Bind(&AvrcpService::Cleanup, base::Owned(instance_)));
440
441 // Setting instance to nullptr here is fine since it will be deleted on the
442 // other thread.
443 instance_ = nullptr;
444
445 return true;
446 }
447
DebugDump(int fd)448 void AvrcpService::DebugDump(int fd) {
449 if (instance_ == nullptr) {
450 dprintf(fd, "\nAVRCP Target Service not started\n");
451 return;
452 }
453
454 auto device_list = instance_->connection_handler_->GetListOfDevices();
455 dprintf(fd, "\nAVRCP Target Native Service: %zu devices\n",
456 device_list.size());
457
458 std::stringstream stream;
459 for (auto device : device_list) {
460 stream << *device << std::endl;
461 }
462 dprintf(fd, "%s", stream.str().c_str());
463 }
464
465 } // namespace avrcp
466 } // namespace bluetooth