1 /*
2 * Copyright (C) 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 #define LOG_TAG "AvrcpTargetJni"
18
19 #include <base/functional/bind.h>
20 #include <base/functional/callback.h>
21
22 #include <map>
23 #include <mutex>
24 #include <shared_mutex>
25 #include <vector>
26
27 #include "avrcp.h"
28 #include "com_android_bluetooth.h"
29
30 using namespace bluetooth::avrcp;
31
32 namespace android {
33
34 // Static Variables
35 static MediaCallbacks* mServiceCallbacks;
36 static ServiceInterface* sServiceInterface;
37 static jobject mJavaInterface;
38 static std::shared_timed_mutex interface_mutex;
39 static std::shared_timed_mutex callbacks_mutex;
40
41 // Forward Declarations
42 static void sendMediaKeyEvent(int, KeyState);
43 static std::string getCurrentMediaId();
44 static SongInfo getSongInfo();
45 static PlayStatus getCurrentPlayStatus();
46 static std::vector<SongInfo> getNowPlayingList();
47 static uint16_t getCurrentPlayerId();
48 static std::vector<MediaPlayerInfo> getMediaPlayerList();
49 using SetBrowsedPlayerCb = MediaInterface::SetBrowsedPlayerCallback;
50 static void setBrowsedPlayer(uint16_t player_id, SetBrowsedPlayerCb);
51 using GetFolderItemsCb = MediaInterface::FolderItemsCallback;
52 static void getFolderItems(uint16_t player_id, std::string media_id,
53 GetFolderItemsCb cb);
54 static void playItem(uint16_t player_id, bool now_playing,
55 std::string media_id);
56 static void setActiveDevice(const RawAddress& address);
57
58 static void volumeDeviceConnected(const RawAddress& address);
59 static void volumeDeviceConnected(
60 const RawAddress& address,
61 ::bluetooth::avrcp::VolumeInterface::VolumeChangedCb cb);
62 static void volumeDeviceDisconnected(const RawAddress& address);
63 static void setVolume(int8_t volume);
64
65 using ListPlayerSettingsCb =
66 PlayerSettingsInterface::ListPlayerSettingsCallback;
67 static void listPlayerSettings(ListPlayerSettingsCb cb);
68 ListPlayerSettingsCb list_player_settings_cb;
69 using ListPlayerSettingValuesCb =
70 PlayerSettingsInterface::ListPlayerSettingValuesCallback;
71 static void listPlayerSettingValues(PlayerAttribute setting,
72 ListPlayerSettingValuesCb cb);
73 ListPlayerSettingValuesCb list_player_setting_values_cb;
74 using GetCurrentPlayerSettingValueCb =
75 PlayerSettingsInterface::GetCurrentPlayerSettingValueCallback;
76 static void getPlayerSettings(std::vector<PlayerAttribute> attributes,
77 GetCurrentPlayerSettingValueCb cb);
78 GetCurrentPlayerSettingValueCb get_current_player_setting_value_cb;
79 using SetPlayerSettingValueCb =
80 PlayerSettingsInterface::SetPlayerSettingValueCallback;
81 static void setPlayerSettings(std::vector<PlayerAttribute> attributes,
82 std::vector<uint8_t> values,
83 SetPlayerSettingValueCb cb);
84 SetPlayerSettingValueCb set_player_setting_value_cb;
85
86 // Local Variables
87 // TODO (apanicke): Use a map here to store the callback in order to
88 // support multi-browsing
89 SetBrowsedPlayerCb set_browsed_player_cb;
90 using map_entry = std::pair<std::string, GetFolderItemsCb>;
91 std::map<std::string, GetFolderItemsCb> get_folder_items_cb_map;
92 std::map<RawAddress, ::bluetooth::avrcp::VolumeInterface::VolumeChangedCb>
93 volumeCallbackMap;
94
95 template <typename T>
copyJavaArraytoCppVector(JNIEnv * env,const jbyteArray & jArray,std::vector<T> & cVec)96 void copyJavaArraytoCppVector(JNIEnv* env, const jbyteArray& jArray,
97 std::vector<T>& cVec) {
98 size_t len = (size_t)env->GetArrayLength(jArray);
99 if (len == 0) return;
100 jbyte* elements = env->GetByteArrayElements(jArray, nullptr);
101 T* array = reinterpret_cast<T*>(elements);
102 cVec.reserve(len);
103 std::copy(array, array + len, std::back_inserter(cVec));
104 env->ReleaseByteArrayElements(jArray, elements, 0);
105 }
106
107 // TODO (apanicke): In the future, this interface should guarantee that
108 // all calls happen on the JNI Thread. Right now this is very difficult
109 // as it is hard to get a handle on the JNI thread from here.
110 class AvrcpMediaInterfaceImpl : public MediaInterface {
111 public:
SendKeyEvent(uint8_t key,KeyState state)112 void SendKeyEvent(uint8_t key, KeyState state) {
113 sendMediaKeyEvent(key, state);
114 }
115
GetSongInfo(SongInfoCallback cb)116 void GetSongInfo(SongInfoCallback cb) override {
117 auto info = getSongInfo();
118 cb.Run(info);
119 }
120
GetPlayStatus(PlayStatusCallback cb)121 void GetPlayStatus(PlayStatusCallback cb) override {
122 auto status = getCurrentPlayStatus();
123 cb.Run(status);
124 }
125
GetNowPlayingList(NowPlayingCallback cb)126 void GetNowPlayingList(NowPlayingCallback cb) override {
127 auto curr_song_id = getCurrentMediaId();
128 auto now_playing_list = getNowPlayingList();
129 cb.Run(curr_song_id, std::move(now_playing_list));
130 }
131
GetMediaPlayerList(MediaListCallback cb)132 void GetMediaPlayerList(MediaListCallback cb) override {
133 uint16_t current_player = getCurrentPlayerId();
134 auto player_list = getMediaPlayerList();
135 cb.Run(current_player, std::move(player_list));
136 }
137
GetFolderItems(uint16_t player_id,std::string media_id,FolderItemsCallback folder_cb)138 void GetFolderItems(uint16_t player_id, std::string media_id,
139 FolderItemsCallback folder_cb) override {
140 getFolderItems(player_id, media_id, folder_cb);
141 }
142
SetBrowsedPlayer(uint16_t player_id,SetBrowsedPlayerCallback browse_cb)143 void SetBrowsedPlayer(uint16_t player_id,
144 SetBrowsedPlayerCallback browse_cb) override {
145 setBrowsedPlayer(player_id, browse_cb);
146 }
147
RegisterUpdateCallback(MediaCallbacks * callback)148 void RegisterUpdateCallback(MediaCallbacks* callback) override {
149 // TODO (apanicke): Allow multiple registrations in the future
150 mServiceCallbacks = callback;
151 }
152
UnregisterUpdateCallback(MediaCallbacks *)153 void UnregisterUpdateCallback(MediaCallbacks* /* callback */) override {
154 mServiceCallbacks = nullptr;
155 }
156
PlayItem(uint16_t player_id,bool now_playing,std::string media_id)157 void PlayItem(uint16_t player_id, bool now_playing,
158 std::string media_id) override {
159 playItem(player_id, now_playing, media_id);
160 }
161
SetActiveDevice(const RawAddress & address)162 void SetActiveDevice(const RawAddress& address) override {
163 setActiveDevice(address);
164 }
165 };
166 static AvrcpMediaInterfaceImpl mAvrcpInterface;
167
168 class VolumeInterfaceImpl : public VolumeInterface {
169 public:
DeviceConnected(const RawAddress & bdaddr)170 void DeviceConnected(const RawAddress& bdaddr) override {
171 volumeDeviceConnected(bdaddr);
172 }
173
DeviceConnected(const RawAddress & bdaddr,VolumeChangedCb cb)174 void DeviceConnected(const RawAddress& bdaddr, VolumeChangedCb cb) override {
175 volumeDeviceConnected(bdaddr, cb);
176 }
177
DeviceDisconnected(const RawAddress & bdaddr)178 void DeviceDisconnected(const RawAddress& bdaddr) override {
179 volumeDeviceDisconnected(bdaddr);
180 }
181
SetVolume(int8_t volume)182 void SetVolume(int8_t volume) override { setVolume(volume); }
183 };
184 static VolumeInterfaceImpl mVolumeInterface;
185
186 class PlayerSettingsInterfaceImpl : public PlayerSettingsInterface {
187 public:
ListPlayerSettings(ListPlayerSettingsCallback cb)188 void ListPlayerSettings(ListPlayerSettingsCallback cb) {
189 listPlayerSettings(cb);
190 }
191
ListPlayerSettingValues(PlayerAttribute setting,ListPlayerSettingValuesCallback cb)192 void ListPlayerSettingValues(PlayerAttribute setting,
193 ListPlayerSettingValuesCallback cb) {
194 listPlayerSettingValues(setting, cb);
195 }
196
GetCurrentPlayerSettingValue(std::vector<PlayerAttribute> attributes,GetCurrentPlayerSettingValueCallback cb)197 void GetCurrentPlayerSettingValue(std::vector<PlayerAttribute> attributes,
198 GetCurrentPlayerSettingValueCallback cb) {
199 getPlayerSettings(attributes, cb);
200 }
201
SetPlayerSettings(std::vector<PlayerAttribute> attributes,std::vector<uint8_t> values,SetPlayerSettingValueCallback cb)202 void SetPlayerSettings(std::vector<PlayerAttribute> attributes,
203 std::vector<uint8_t> values,
204 SetPlayerSettingValueCallback cb) {
205 setPlayerSettings(attributes, values, cb);
206 }
207 };
208 static PlayerSettingsInterfaceImpl mPlayerSettingsInterface;
209
210 static jmethodID method_getCurrentSongInfo;
211 static jmethodID method_getPlaybackStatus;
212 static jmethodID method_sendMediaKeyEvent;
213
214 static jmethodID method_getCurrentMediaId;
215 static jmethodID method_getNowPlayingList;
216
217 static jmethodID method_setBrowsedPlayer;
218 static jmethodID method_getCurrentPlayerId;
219 static jmethodID method_getMediaPlayerList;
220 static jmethodID method_getFolderItemsRequest;
221 static jmethodID method_playItem;
222
223 static jmethodID method_setActiveDevice;
224
225 static jmethodID method_volumeDeviceConnected;
226 static jmethodID method_volumeDeviceDisconnected;
227
228 static jmethodID method_setVolume;
229
230 static jmethodID method_listPlayerSettings;
231 static jmethodID method_listPlayerSettingValues;
232 static jmethodID method_getPlayerSettings;
233 static jmethodID method_setPlayerSettings;
234
initNative(JNIEnv * env,jobject object)235 static void initNative(JNIEnv* env, jobject object) {
236 log::debug("");
237 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
238 std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
239 mJavaInterface = env->NewGlobalRef(object);
240
241 sServiceInterface = getBluetoothInterface()->get_avrcp_service();
242 sServiceInterface->Init(&mAvrcpInterface, &mVolumeInterface,
243 &mPlayerSettingsInterface);
244 }
245
registerBipServerNative(JNIEnv *,jobject,jint l2cap_psm)246 static void registerBipServerNative(JNIEnv* /* env */, jobject /* object */,
247 jint l2cap_psm) {
248 log::debug("l2cap_psm={}", (int)l2cap_psm);
249 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
250 if (sServiceInterface == nullptr) {
251 log::warn("Service not loaded.");
252 return;
253 }
254 sServiceInterface->RegisterBipServer((int)l2cap_psm);
255 }
256
unregisterBipServerNative(JNIEnv *,jobject)257 static void unregisterBipServerNative(JNIEnv* /* env */, jobject /* object */) {
258 log::debug("");
259 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
260 if (sServiceInterface == nullptr) {
261 log::warn("Service not loaded.");
262 return;
263 }
264 sServiceInterface->UnregisterBipServer();
265 }
266
sendMediaUpdateNative(JNIEnv *,jobject,jboolean metadata,jboolean state,jboolean queue)267 static void sendMediaUpdateNative(JNIEnv* /* env */, jobject /* object */,
268 jboolean metadata, jboolean state,
269 jboolean queue) {
270 log::debug("");
271 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
272 if (mServiceCallbacks == nullptr) {
273 log::warn("Service not loaded.");
274 return;
275 }
276
277 mServiceCallbacks->SendMediaUpdate(metadata == JNI_TRUE, state == JNI_TRUE,
278 queue == JNI_TRUE);
279 }
280
sendFolderUpdateNative(JNIEnv *,jobject,jboolean available_players,jboolean addressed_player,jboolean uids)281 static void sendFolderUpdateNative(JNIEnv* /* env */, jobject /* object */,
282 jboolean available_players,
283 jboolean addressed_player, jboolean uids) {
284 log::debug("");
285 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
286 if (mServiceCallbacks == nullptr) {
287 log::warn("Service not loaded.");
288 return;
289 }
290
291 mServiceCallbacks->SendFolderUpdate(available_players == JNI_TRUE,
292 addressed_player == JNI_TRUE,
293 uids == JNI_TRUE);
294 }
295
cleanupNative(JNIEnv * env,jobject)296 static void cleanupNative(JNIEnv* env, jobject /* object */) {
297 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
298 std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
299
300 get_folder_items_cb_map.clear();
301 volumeCallbackMap.clear();
302
303 sServiceInterface->Cleanup();
304 env->DeleteGlobalRef(mJavaInterface);
305 mJavaInterface = nullptr;
306 mServiceCallbacks = nullptr;
307 sServiceInterface = nullptr;
308 }
309
connectDeviceNative(JNIEnv * env,jobject,jstring address)310 jboolean connectDeviceNative(JNIEnv* env, jobject /* object */,
311 jstring address) {
312 log::debug("");
313 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
314 if (mServiceCallbacks == nullptr) {
315 log::warn("Service not loaded.");
316 return JNI_FALSE;
317 }
318
319 const char* tmp_addr = env->GetStringUTFChars(address, 0);
320 RawAddress bdaddr;
321 bool success = RawAddress::FromString(tmp_addr, bdaddr);
322 env->ReleaseStringUTFChars(address, tmp_addr);
323
324 if (!success) return JNI_FALSE;
325
326 return sServiceInterface->ConnectDevice(bdaddr) == true ? JNI_TRUE
327 : JNI_FALSE;
328 }
329
disconnectDeviceNative(JNIEnv * env,jobject,jstring address)330 jboolean disconnectDeviceNative(JNIEnv* env, jobject /* object */,
331 jstring address) {
332 log::debug("");
333 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
334 if (mServiceCallbacks == nullptr) {
335 log::warn("Service not loaded.");
336 return JNI_FALSE;
337 }
338
339 const char* tmp_addr = env->GetStringUTFChars(address, 0);
340 RawAddress bdaddr;
341 bool success = RawAddress::FromString(tmp_addr, bdaddr);
342 env->ReleaseStringUTFChars(address, tmp_addr);
343
344 if (!success) return JNI_FALSE;
345
346 return sServiceInterface->DisconnectDevice(bdaddr) == true ? JNI_TRUE
347 : JNI_FALSE;
348 }
349
sendMediaKeyEvent(int key,KeyState state)350 static void sendMediaKeyEvent(int key, KeyState state) {
351 log::debug("");
352 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
353 CallbackEnv sCallbackEnv(__func__);
354 if (!sCallbackEnv.valid() || !mJavaInterface) return;
355 sCallbackEnv->CallVoidMethod(
356 mJavaInterface, method_sendMediaKeyEvent, key,
357 state == KeyState::PUSHED ? JNI_TRUE : JNI_FALSE);
358 }
359
getImageHandleFromJavaObj(JNIEnv * env,jobject image)360 static std::string getImageHandleFromJavaObj(JNIEnv* env, jobject image) {
361 std::string handle;
362
363 if (image == nullptr) return handle;
364
365 jclass class_image = env->GetObjectClass(image);
366 jmethodID method_getImageHandle =
367 env->GetMethodID(class_image, "getImageHandle", "()Ljava/lang/String;");
368 jstring imageHandle = (jstring) env->CallObjectMethod(
369 image, method_getImageHandle);
370 if (imageHandle == nullptr) {
371 return handle;
372 }
373
374 const char* value = env->GetStringUTFChars(imageHandle, nullptr);
375 handle = std::string(value);
376 env->ReleaseStringUTFChars(imageHandle, value);
377 env->DeleteLocalRef(imageHandle);
378 return handle;
379 }
380
getSongInfoFromJavaObj(JNIEnv * env,jobject metadata)381 static SongInfo getSongInfoFromJavaObj(JNIEnv* env, jobject metadata) {
382 SongInfo info;
383
384 if (metadata == nullptr) return info;
385
386 jclass class_metadata = env->GetObjectClass(metadata);
387 jfieldID field_mediaId =
388 env->GetFieldID(class_metadata, "mediaId", "Ljava/lang/String;");
389 jfieldID field_title =
390 env->GetFieldID(class_metadata, "title", "Ljava/lang/String;");
391 jfieldID field_artist =
392 env->GetFieldID(class_metadata, "artist", "Ljava/lang/String;");
393 jfieldID field_album =
394 env->GetFieldID(class_metadata, "album", "Ljava/lang/String;");
395 jfieldID field_trackNum =
396 env->GetFieldID(class_metadata, "trackNum", "Ljava/lang/String;");
397 jfieldID field_numTracks =
398 env->GetFieldID(class_metadata, "numTracks", "Ljava/lang/String;");
399 jfieldID field_genre =
400 env->GetFieldID(class_metadata, "genre", "Ljava/lang/String;");
401 jfieldID field_playingTime =
402 env->GetFieldID(class_metadata, "duration", "Ljava/lang/String;");
403 jfieldID field_image =
404 env->GetFieldID(class_metadata, "image", "Lcom/android/bluetooth/audio_util/Image;");
405
406 jstring jstr = (jstring)env->GetObjectField(metadata, field_mediaId);
407 if (jstr != nullptr) {
408 const char* value = env->GetStringUTFChars(jstr, nullptr);
409 info.media_id = std::string(value);
410 env->ReleaseStringUTFChars(jstr, value);
411 env->DeleteLocalRef(jstr);
412 }
413
414 jstr = (jstring)env->GetObjectField(metadata, field_title);
415 if (jstr != nullptr) {
416 const char* value = env->GetStringUTFChars(jstr, nullptr);
417 info.attributes.insert(
418 AttributeEntry(Attribute::TITLE, std::string(value)));
419 env->ReleaseStringUTFChars(jstr, value);
420 env->DeleteLocalRef(jstr);
421 }
422
423 jstr = (jstring)env->GetObjectField(metadata, field_artist);
424 if (jstr != nullptr) {
425 const char* value = env->GetStringUTFChars(jstr, nullptr);
426 info.attributes.insert(
427 AttributeEntry(Attribute::ARTIST_NAME, std::string(value)));
428 env->ReleaseStringUTFChars(jstr, value);
429 env->DeleteLocalRef(jstr);
430 }
431
432 jstr = (jstring)env->GetObjectField(metadata, field_album);
433 if (jstr != nullptr) {
434 const char* value = env->GetStringUTFChars(jstr, nullptr);
435 info.attributes.insert(
436 AttributeEntry(Attribute::ALBUM_NAME, std::string(value)));
437 env->ReleaseStringUTFChars(jstr, value);
438 env->DeleteLocalRef(jstr);
439 }
440
441 jstr = (jstring)env->GetObjectField(metadata, field_trackNum);
442 if (jstr != nullptr) {
443 const char* value = env->GetStringUTFChars(jstr, nullptr);
444 info.attributes.insert(
445 AttributeEntry(Attribute::TRACK_NUMBER, std::string(value)));
446 env->ReleaseStringUTFChars(jstr, value);
447 env->DeleteLocalRef(jstr);
448 }
449
450 jstr = (jstring)env->GetObjectField(metadata, field_numTracks);
451 if (jstr != nullptr) {
452 const char* value = env->GetStringUTFChars(jstr, nullptr);
453 info.attributes.insert(
454 AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, std::string(value)));
455 env->ReleaseStringUTFChars(jstr, value);
456 env->DeleteLocalRef(jstr);
457 }
458
459 jstr = (jstring)env->GetObjectField(metadata, field_genre);
460 if (jstr != nullptr) {
461 const char* value = env->GetStringUTFChars(jstr, nullptr);
462 info.attributes.insert(
463 AttributeEntry(Attribute::GENRE, std::string(value)));
464 env->ReleaseStringUTFChars(jstr, value);
465 env->DeleteLocalRef(jstr);
466 }
467
468 jstr = (jstring)env->GetObjectField(metadata, field_playingTime);
469 if (jstr != nullptr) {
470 const char* value = env->GetStringUTFChars(jstr, nullptr);
471 info.attributes.insert(
472 AttributeEntry(Attribute::PLAYING_TIME, std::string(value)));
473 env->ReleaseStringUTFChars(jstr, value);
474 env->DeleteLocalRef(jstr);
475 }
476
477 jobject object_image = env->GetObjectField(metadata, field_image);
478 if (object_image != nullptr) {
479 std::string imageHandle = getImageHandleFromJavaObj(env, object_image);
480 if (!imageHandle.empty()) {
481 info.attributes.insert(
482 AttributeEntry(Attribute::DEFAULT_COVER_ART, imageHandle));
483 }
484 env->DeleteLocalRef(object_image);
485 }
486
487 return info;
488 }
489
getFolderInfoFromJavaObj(JNIEnv * env,jobject folder)490 static FolderInfo getFolderInfoFromJavaObj(JNIEnv* env, jobject folder) {
491 FolderInfo info;
492
493 jclass class_folder = env->GetObjectClass(folder);
494 jfieldID field_mediaId =
495 env->GetFieldID(class_folder, "mediaId", "Ljava/lang/String;");
496 jfieldID field_isPlayable = env->GetFieldID(class_folder, "isPlayable", "Z");
497 jfieldID field_name =
498 env->GetFieldID(class_folder, "title", "Ljava/lang/String;");
499
500 jstring jstr = (jstring)env->GetObjectField(folder, field_mediaId);
501 if (jstr != nullptr) {
502 const char* value = env->GetStringUTFChars(jstr, nullptr);
503 info.media_id = std::string(value);
504 env->ReleaseStringUTFChars(jstr, value);
505 env->DeleteLocalRef(jstr);
506 }
507
508 info.is_playable = env->GetBooleanField(folder, field_isPlayable) == JNI_TRUE;
509
510 jstr = (jstring)env->GetObjectField(folder, field_name);
511 if (jstr != nullptr) {
512 const char* value = env->GetStringUTFChars(jstr, nullptr);
513 info.name = std::string(value);
514 env->ReleaseStringUTFChars(jstr, value);
515 env->DeleteLocalRef(jstr);
516 }
517
518 return info;
519 }
520
getSongInfo()521 static SongInfo getSongInfo() {
522 log::debug("");
523 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
524 CallbackEnv sCallbackEnv(__func__);
525 if (!sCallbackEnv.valid() || !mJavaInterface) return SongInfo();
526
527 jobject metadata =
528 sCallbackEnv->CallObjectMethod(mJavaInterface, method_getCurrentSongInfo);
529 SongInfo info = getSongInfoFromJavaObj(sCallbackEnv.get(), metadata);
530 sCallbackEnv->DeleteLocalRef(metadata);
531 return info;
532 }
533
getCurrentPlayStatus()534 static PlayStatus getCurrentPlayStatus() {
535 log::debug("");
536 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
537 CallbackEnv sCallbackEnv(__func__);
538 if (!sCallbackEnv.valid() || !mJavaInterface) return PlayStatus();
539
540 PlayStatus status;
541 jobject playStatus =
542 sCallbackEnv->CallObjectMethod(mJavaInterface, method_getPlaybackStatus);
543
544 if (playStatus == nullptr) {
545 log::error("Got a null play status");
546 return status;
547 }
548
549 jclass class_playStatus = sCallbackEnv->GetObjectClass(playStatus);
550 jfieldID field_position =
551 sCallbackEnv->GetFieldID(class_playStatus, "position", "J");
552 jfieldID field_duration =
553 sCallbackEnv->GetFieldID(class_playStatus, "duration", "J");
554 jfieldID field_state =
555 sCallbackEnv->GetFieldID(class_playStatus, "state", "B");
556
557 status.position = sCallbackEnv->GetLongField(playStatus, field_position);
558 status.duration = sCallbackEnv->GetLongField(playStatus, field_duration);
559 status.state = (PlayState)sCallbackEnv->GetByteField(playStatus, field_state);
560
561 sCallbackEnv->DeleteLocalRef(playStatus);
562
563 return status;
564 }
565
getCurrentMediaId()566 static std::string getCurrentMediaId() {
567 log::debug("");
568 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
569 CallbackEnv sCallbackEnv(__func__);
570 if (!sCallbackEnv.valid() || !mJavaInterface) return "";
571
572 jstring media_id = (jstring)sCallbackEnv->CallObjectMethod(
573 mJavaInterface, method_getCurrentMediaId);
574 if (media_id == nullptr) {
575 log::error("Got a null media ID");
576 return "";
577 }
578
579 const char* value = sCallbackEnv->GetStringUTFChars(media_id, nullptr);
580 std::string ret(value);
581 sCallbackEnv->ReleaseStringUTFChars(media_id, value);
582 sCallbackEnv->DeleteLocalRef(media_id);
583 return ret;
584 }
585
getNowPlayingList()586 static std::vector<SongInfo> getNowPlayingList() {
587 log::debug("");
588 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
589 CallbackEnv sCallbackEnv(__func__);
590 if (!sCallbackEnv.valid() || !mJavaInterface) return std::vector<SongInfo>();
591
592 jobject song_list =
593 sCallbackEnv->CallObjectMethod(mJavaInterface, method_getNowPlayingList);
594 if (song_list == nullptr) {
595 log::error("Got a null now playing list");
596 return std::vector<SongInfo>();
597 }
598
599 jclass class_list = sCallbackEnv->GetObjectClass(song_list);
600 jmethodID method_get =
601 sCallbackEnv->GetMethodID(class_list, "get", "(I)Ljava/lang/Object;");
602 jmethodID method_size = sCallbackEnv->GetMethodID(class_list, "size", "()I");
603
604 auto size = sCallbackEnv->CallIntMethod(song_list, method_size);
605 if (size == 0) {
606 sCallbackEnv->DeleteLocalRef(song_list);
607 return std::vector<SongInfo>();
608 }
609 std::vector<SongInfo> ret;
610 for (int i = 0; i < size; i++) {
611 jobject song = sCallbackEnv->CallObjectMethod(song_list, method_get, i);
612 ret.push_back(getSongInfoFromJavaObj(sCallbackEnv.get(), song));
613 sCallbackEnv->DeleteLocalRef(song);
614 }
615
616 sCallbackEnv->DeleteLocalRef(song_list);
617
618 return ret;
619 }
620
getCurrentPlayerId()621 static uint16_t getCurrentPlayerId() {
622 log::debug("");
623 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
624 CallbackEnv sCallbackEnv(__func__);
625 if (!sCallbackEnv.valid() || !mJavaInterface) return 0u;
626
627 jint id =
628 sCallbackEnv->CallIntMethod(mJavaInterface, method_getCurrentPlayerId);
629
630 return (static_cast<int>(id) & 0xFFFF);
631 }
632
getMediaPlayerList()633 static std::vector<MediaPlayerInfo> getMediaPlayerList() {
634 log::debug("");
635 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
636 CallbackEnv sCallbackEnv(__func__);
637 if (!sCallbackEnv.valid() || !mJavaInterface)
638 return std::vector<MediaPlayerInfo>();
639
640 jobject player_list = (jobject)sCallbackEnv->CallObjectMethod(
641 mJavaInterface, method_getMediaPlayerList);
642
643 if (player_list == nullptr) {
644 log::error("Got a null media player list");
645 return std::vector<MediaPlayerInfo>();
646 }
647
648 jclass class_list = sCallbackEnv->GetObjectClass(player_list);
649 jmethodID method_get =
650 sCallbackEnv->GetMethodID(class_list, "get", "(I)Ljava/lang/Object;");
651 jmethodID method_size = sCallbackEnv->GetMethodID(class_list, "size", "()I");
652
653 jint list_size = sCallbackEnv->CallIntMethod(player_list, method_size);
654 if (list_size == 0) {
655 sCallbackEnv->DeleteLocalRef(player_list);
656 return std::vector<MediaPlayerInfo>();
657 }
658
659 jobject player_info =
660 sCallbackEnv->CallObjectMethod(player_list, method_get, 0);
661 jclass class_playerInfo = sCallbackEnv->GetObjectClass(player_info);
662 jfieldID field_playerId =
663 sCallbackEnv->GetFieldID(class_playerInfo, "id", "I");
664 jfieldID field_name =
665 sCallbackEnv->GetFieldID(class_playerInfo, "name", "Ljava/lang/String;");
666 jfieldID field_browsable =
667 sCallbackEnv->GetFieldID(class_playerInfo, "browsable", "Z");
668
669 std::vector<MediaPlayerInfo> ret_list;
670 for (jsize i = 0; i < list_size; i++) {
671 jobject player = sCallbackEnv->CallObjectMethod(player_list, method_get, i);
672
673 MediaPlayerInfo temp;
674 temp.id = sCallbackEnv->GetIntField(player, field_playerId);
675
676 jstring jstr = (jstring)sCallbackEnv->GetObjectField(player, field_name);
677 if (jstr != nullptr) {
678 const char* value = sCallbackEnv->GetStringUTFChars(jstr, nullptr);
679 temp.name = std::string(value);
680 sCallbackEnv->ReleaseStringUTFChars(jstr, value);
681 sCallbackEnv->DeleteLocalRef(jstr);
682 }
683
684 temp.browsing_supported =
685 sCallbackEnv->GetBooleanField(player, field_browsable) == JNI_TRUE
686 ? true
687 : false;
688
689 ret_list.push_back(std::move(temp));
690 sCallbackEnv->DeleteLocalRef(player);
691 }
692
693 sCallbackEnv->DeleteLocalRef(player_info);
694 sCallbackEnv->DeleteLocalRef(player_list);
695
696 return ret_list;
697 }
698
setBrowsedPlayer(uint16_t player_id,SetBrowsedPlayerCb cb)699 static void setBrowsedPlayer(uint16_t player_id, SetBrowsedPlayerCb cb) {
700 log::debug("");
701 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
702 CallbackEnv sCallbackEnv(__func__);
703 if (!sCallbackEnv.valid() || !mJavaInterface) return;
704
705 set_browsed_player_cb = cb;
706 sCallbackEnv->CallVoidMethod(mJavaInterface, method_setBrowsedPlayer,
707 player_id);
708 }
709
setBrowsedPlayerResponseNative(JNIEnv * env,jobject,jint,jboolean success,jstring root_id,jint num_items)710 static void setBrowsedPlayerResponseNative(JNIEnv* env, jobject /* object */,
711 jint /* player_id */,
712 jboolean success, jstring root_id,
713 jint num_items) {
714 log::debug("");
715
716 std::string root;
717 if (root_id != nullptr) {
718 const char* value = env->GetStringUTFChars(root_id, nullptr);
719 root = std::string(value);
720 env->ReleaseStringUTFChars(root_id, value);
721 }
722
723 set_browsed_player_cb.Run(success == JNI_TRUE, root, num_items);
724 }
725
getFolderItemsResponseNative(JNIEnv * env,jobject,jstring parent_id,jobject list)726 static void getFolderItemsResponseNative(JNIEnv* env, jobject /* object */,
727 jstring parent_id, jobject list) {
728 log::debug("");
729
730 std::string id;
731 if (parent_id != nullptr) {
732 const char* value = env->GetStringUTFChars(parent_id, nullptr);
733 id = std::string(value);
734 env->ReleaseStringUTFChars(parent_id, value);
735 }
736
737 // TODO (apanicke): Right now browsing will fail on a second device if two
738 // devices browse the same folder. Use a MultiMap to fix this behavior so
739 // that both callbacks can be handled with one lookup if a request comes
740 // for a folder that is already trying to be looked at.
741 if (get_folder_items_cb_map.find(id) == get_folder_items_cb_map.end()) {
742 log::error("Could not find response callback for the request of \"{}\"",
743 id);
744 return;
745 }
746
747 auto callback = get_folder_items_cb_map.find(id)->second;
748 get_folder_items_cb_map.erase(id);
749
750 if (list == nullptr) {
751 log::error("Got a null get folder items response list");
752 callback.Run(std::vector<ListItem>());
753 return;
754 }
755
756 jclass class_list = env->GetObjectClass(list);
757 jmethodID method_get =
758 env->GetMethodID(class_list, "get", "(I)Ljava/lang/Object;");
759 jmethodID method_size = env->GetMethodID(class_list, "size", "()I");
760
761 jint list_size = env->CallIntMethod(list, method_size);
762 if (list_size == 0) {
763 callback.Run(std::vector<ListItem>());
764 return;
765 }
766
767 jobject list_item = env->CallObjectMethod(list, method_get, 0);
768 jclass class_listItem = env->GetObjectClass(list_item);
769 jfieldID field_isFolder = env->GetFieldID(class_listItem, "isFolder", "Z");
770 jfieldID field_folder = env->GetFieldID(
771 class_listItem, "folder", "Lcom/android/bluetooth/audio_util/Folder;");
772 jfieldID field_song = env->GetFieldID(
773 class_listItem, "song", "Lcom/android/bluetooth/audio_util/Metadata;");
774
775 std::vector<ListItem> ret_list;
776 for (jsize i = 0; i < list_size; i++) {
777 jobject item = env->CallObjectMethod(list, method_get, i);
778
779 bool is_folder = env->GetBooleanField(item, field_isFolder) == JNI_TRUE;
780
781 if (is_folder) {
782 jobject folder = env->GetObjectField(item, field_folder);
783 ListItem temp = {ListItem::FOLDER,
784 getFolderInfoFromJavaObj(env, folder),
785 SongInfo()};
786 ret_list.push_back(temp);
787 env->DeleteLocalRef(folder);
788 } else {
789 jobject song = env->GetObjectField(item, field_song);
790 ListItem temp = {ListItem::SONG, FolderInfo(),
791 getSongInfoFromJavaObj(env, song)};
792 ret_list.push_back(temp);
793 env->DeleteLocalRef(song);
794 }
795 env->DeleteLocalRef(item);
796 }
797
798 env->DeleteLocalRef(list_item);
799
800 callback.Run(std::move(ret_list));
801 }
802
getFolderItems(uint16_t player_id,std::string media_id,GetFolderItemsCb cb)803 static void getFolderItems(uint16_t player_id, std::string media_id,
804 GetFolderItemsCb cb) {
805 log::debug("");
806 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
807 CallbackEnv sCallbackEnv(__func__);
808 if (!sCallbackEnv.valid() || !mJavaInterface) return;
809
810 // TODO (apanicke): Fix a potential media_id collision if two media players
811 // use the same media_id scheme or two devices browse the same content.
812 get_folder_items_cb_map.insert(map_entry(media_id, cb));
813
814 jstring j_media_id = sCallbackEnv->NewStringUTF(media_id.c_str());
815 sCallbackEnv->CallVoidMethod(mJavaInterface, method_getFolderItemsRequest,
816 player_id, j_media_id);
817 }
818
playItem(uint16_t player_id,bool now_playing,std::string media_id)819 static void playItem(uint16_t player_id, bool now_playing,
820 std::string media_id) {
821 log::debug("");
822 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
823 CallbackEnv sCallbackEnv(__func__);
824 if (!sCallbackEnv.valid() || !mJavaInterface) return;
825
826 jstring j_media_id = sCallbackEnv->NewStringUTF(media_id.c_str());
827 sCallbackEnv->CallVoidMethod(mJavaInterface, method_playItem, player_id,
828 now_playing ? JNI_TRUE : JNI_FALSE, j_media_id);
829 }
830
setActiveDevice(const RawAddress & address)831 static void setActiveDevice(const RawAddress& address) {
832 log::debug("");
833 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
834 CallbackEnv sCallbackEnv(__func__);
835 if (!sCallbackEnv.valid() || !mJavaInterface) return;
836
837 jstring j_bdaddr = sCallbackEnv->NewStringUTF(address.ToString().c_str());
838 sCallbackEnv->CallVoidMethod(mJavaInterface, method_setActiveDevice,
839 j_bdaddr);
840 }
841
volumeDeviceConnected(const RawAddress & address)842 static void volumeDeviceConnected(const RawAddress& address) {
843 log::debug("");
844 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
845 CallbackEnv sCallbackEnv(__func__);
846 if (!sCallbackEnv.valid() || !mJavaInterface) return;
847
848 jstring j_bdaddr = sCallbackEnv->NewStringUTF(address.ToString().c_str());
849 sCallbackEnv->CallVoidMethod(mJavaInterface, method_volumeDeviceConnected,
850 j_bdaddr, JNI_FALSE);
851 }
852
volumeDeviceConnected(const RawAddress & address,::bluetooth::avrcp::VolumeInterface::VolumeChangedCb cb)853 static void volumeDeviceConnected(
854 const RawAddress& address,
855 ::bluetooth::avrcp::VolumeInterface::VolumeChangedCb cb) {
856 log::debug("");
857 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
858 CallbackEnv sCallbackEnv(__func__);
859 if (!sCallbackEnv.valid() || !mJavaInterface) return;
860
861 volumeCallbackMap.emplace(address, cb);
862
863 jstring j_bdaddr = sCallbackEnv->NewStringUTF(address.ToString().c_str());
864 sCallbackEnv->CallVoidMethod(mJavaInterface, method_volumeDeviceConnected,
865 j_bdaddr, JNI_TRUE);
866 }
867
volumeDeviceDisconnected(const RawAddress & address)868 static void volumeDeviceDisconnected(const RawAddress& address) {
869 log::debug("");
870 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
871 CallbackEnv sCallbackEnv(__func__);
872 if (!sCallbackEnv.valid() || !mJavaInterface) return;
873
874 volumeCallbackMap.erase(address);
875
876 jstring j_bdaddr = sCallbackEnv->NewStringUTF(address.ToString().c_str());
877 sCallbackEnv->CallVoidMethod(mJavaInterface, method_volumeDeviceDisconnected,
878 j_bdaddr);
879 }
880
sendVolumeChangedNative(JNIEnv * env,jobject,jstring address,jint volume)881 static void sendVolumeChangedNative(JNIEnv* env, jobject /* object */,
882 jstring address, jint volume) {
883 const char* tmp_addr = env->GetStringUTFChars(address, 0);
884 RawAddress bdaddr;
885 bool success = RawAddress::FromString(tmp_addr, bdaddr);
886 env->ReleaseStringUTFChars(address, tmp_addr);
887
888 if (!success) return;
889
890 log::debug("");
891 if (volumeCallbackMap.find(bdaddr) != volumeCallbackMap.end()) {
892 volumeCallbackMap.find(bdaddr)->second.Run(volume & 0x7F);
893 }
894 }
895
setVolume(int8_t volume)896 static void setVolume(int8_t volume) {
897 log::debug("");
898 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
899 CallbackEnv sCallbackEnv(__func__);
900 if (!sCallbackEnv.valid() || !mJavaInterface) return;
901
902 sCallbackEnv->CallVoidMethod(mJavaInterface, method_setVolume, volume);
903 }
904
setBipClientStatusNative(JNIEnv * env,jobject,jstring address,jboolean connected)905 static void setBipClientStatusNative(JNIEnv* env, jobject /* object */,
906 jstring address, jboolean connected) {
907 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
908 if (mServiceCallbacks == nullptr) {
909 log::warn("Service not loaded.");
910 return;
911 }
912
913 const char* tmp_addr = env->GetStringUTFChars(address, 0);
914 RawAddress bdaddr;
915 bool success = RawAddress::FromString(tmp_addr, bdaddr);
916 env->ReleaseStringUTFChars(address, tmp_addr);
917
918 if (!success) return;
919
920 bool status = (connected == JNI_TRUE);
921 sServiceInterface->SetBipClientStatus(bdaddr, status);
922 }
923
924 // Called from native to list available player settings
listPlayerSettings(ListPlayerSettingsCb cb)925 static void listPlayerSettings(ListPlayerSettingsCb cb) {
926 log::debug("");
927 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
928 CallbackEnv sCallbackEnv(__func__);
929 if (!sCallbackEnv.valid() || !mJavaInterface) return;
930
931 list_player_settings_cb = std::move(cb);
932 sCallbackEnv->CallVoidMethod(mJavaInterface, method_listPlayerSettings);
933 }
934
listPlayerSettingsResponseNative(JNIEnv * env,jobject,jbyteArray attributes)935 static void listPlayerSettingsResponseNative(JNIEnv* env, jobject /* object */,
936 jbyteArray attributes) {
937 log::debug("");
938
939 std::vector<PlayerAttribute> attributes_vector;
940 copyJavaArraytoCppVector(env, attributes, attributes_vector);
941
942 list_player_settings_cb.Run(std::move(attributes_vector));
943 }
944
945 // Called from native to list available values for player setting
listPlayerSettingValues(PlayerAttribute attribute,ListPlayerSettingValuesCb cb)946 static void listPlayerSettingValues(PlayerAttribute attribute,
947 ListPlayerSettingValuesCb cb) {
948 log::debug("");
949 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
950 CallbackEnv sCallbackEnv(__func__);
951 if (!sCallbackEnv.valid() || !mJavaInterface) return;
952
953 list_player_setting_values_cb = std::move(cb);
954 sCallbackEnv->CallVoidMethod(mJavaInterface, method_listPlayerSettingValues,
955 (jbyte)attribute);
956 }
957
listPlayerSettingValuesResponseNative(JNIEnv * env,jobject,jbyte attribute,jbyteArray values)958 static void listPlayerSettingValuesResponseNative(JNIEnv* env,
959 jobject /* object */,
960 jbyte attribute,
961 jbyteArray values) {
962 log::debug("");
963 PlayerAttribute player_attribute = static_cast<PlayerAttribute>(attribute);
964 std::vector<uint8_t> values_vector;
965 copyJavaArraytoCppVector(env, values, values_vector);
966 list_player_setting_values_cb.Run(player_attribute, std::move(values_vector));
967 }
968
969 // Called from native to get current player settings
getPlayerSettings(std::vector<PlayerAttribute> attributes,GetCurrentPlayerSettingValueCb cb)970 static void getPlayerSettings(std::vector<PlayerAttribute> attributes,
971 GetCurrentPlayerSettingValueCb cb) {
972 log::debug("");
973 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
974 CallbackEnv sCallbackEnv(__func__);
975 if (!sCallbackEnv.valid() || !mJavaInterface) return;
976
977 jbyteArray attributes_array = sCallbackEnv->NewByteArray(attributes.size());
978 sCallbackEnv->SetByteArrayRegion(
979 attributes_array, 0, attributes.size(),
980 reinterpret_cast<const jbyte*>(attributes.data()));
981
982 get_current_player_setting_value_cb = std::move(cb);
983 sCallbackEnv->CallVoidMethod(mJavaInterface, method_getPlayerSettings,
984 attributes_array);
985 }
986
getPlayerSettingsResponseNative(JNIEnv * env,jobject,jbyteArray attributes,jbyteArray values)987 static void getPlayerSettingsResponseNative(JNIEnv* env, jobject /* object */,
988 jbyteArray attributes,
989 jbyteArray values) {
990 log::debug("");
991 std::vector<PlayerAttribute> attributes_vector;
992 std::vector<uint8_t> values_vector;
993 copyJavaArraytoCppVector(env, attributes, attributes_vector);
994 copyJavaArraytoCppVector(env, values, values_vector);
995 get_current_player_setting_value_cb.Run(std::move(attributes_vector),
996 std::move(values_vector));
997 }
998
999 // Called from native to set current player settings
setPlayerSettings(std::vector<PlayerAttribute> attributes,std::vector<uint8_t> values,SetPlayerSettingValueCb cb)1000 static void setPlayerSettings(std::vector<PlayerAttribute> attributes,
1001 std::vector<uint8_t> values,
1002 SetPlayerSettingValueCb cb) {
1003 log::debug("");
1004 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
1005 CallbackEnv sCallbackEnv(__func__);
1006 if (!sCallbackEnv.valid() || !mJavaInterface) return;
1007
1008 jbyteArray attributes_array = sCallbackEnv->NewByteArray(attributes.size());
1009 sCallbackEnv->SetByteArrayRegion(
1010 attributes_array, 0, attributes.size(),
1011 reinterpret_cast<const jbyte*>(attributes.data()));
1012
1013 jbyteArray values_array = sCallbackEnv->NewByteArray(values.size());
1014 sCallbackEnv->SetByteArrayRegion(
1015 values_array, 0, values.size(),
1016 reinterpret_cast<const jbyte*>(values.data()));
1017
1018 set_player_setting_value_cb = std::move(cb);
1019
1020 sCallbackEnv->CallVoidMethod(mJavaInterface, method_setPlayerSettings,
1021 attributes_array, values_array);
1022 }
1023
setPlayerSettingsResponseNative(JNIEnv *,jobject,jboolean success)1024 static void setPlayerSettingsResponseNative(JNIEnv* /* env */,
1025 jobject /* object */,
1026 jboolean success) {
1027 log::debug("");
1028 set_player_setting_value_cb.Run(success);
1029 }
1030
sendPlayerSettingsNative(JNIEnv * env,jobject,jbyteArray attributes,jbyteArray values)1031 static void sendPlayerSettingsNative(JNIEnv* env, jobject /* object */,
1032 jbyteArray attributes, jbyteArray values) {
1033 log::debug("");
1034 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
1035 if (mServiceCallbacks == nullptr) {
1036 log::warn("Service not loaded.");
1037 return;
1038 }
1039 std::vector<PlayerAttribute> attributes_vector;
1040 std::vector<uint8_t> values_vector;
1041 copyJavaArraytoCppVector(env, attributes, attributes_vector);
1042 copyJavaArraytoCppVector(env, values, values_vector);
1043 mServiceCallbacks->SendPlayerSettingsChanged(attributes_vector,
1044 values_vector);
1045 }
1046
register_com_android_bluetooth_avrcp_target(JNIEnv * env)1047 int register_com_android_bluetooth_avrcp_target(JNIEnv* env) {
1048 const JNINativeMethod methods[] = {
1049 {"initNative", "()V", (void*)initNative},
1050 {"registerBipServerNative", "(I)V", (void*)registerBipServerNative},
1051 {"unregisterBipServerNative", "()V", (void*)unregisterBipServerNative},
1052 {"sendMediaUpdateNative", "(ZZZ)V", (void*)sendMediaUpdateNative},
1053 {"sendFolderUpdateNative", "(ZZZ)V", (void*)sendFolderUpdateNative},
1054 {"setBrowsedPlayerResponseNative", "(IZLjava/lang/String;I)V",
1055 (void*)setBrowsedPlayerResponseNative},
1056 {"getFolderItemsResponseNative", "(Ljava/lang/String;Ljava/util/List;)V",
1057 (void*)getFolderItemsResponseNative},
1058 {"cleanupNative", "()V", (void*)cleanupNative},
1059 {"connectDeviceNative", "(Ljava/lang/String;)Z",
1060 (void*)connectDeviceNative},
1061 {"disconnectDeviceNative", "(Ljava/lang/String;)Z",
1062 (void*)disconnectDeviceNative},
1063 {"sendVolumeChangedNative", "(Ljava/lang/String;I)V",
1064 (void*)sendVolumeChangedNative},
1065 {"setBipClientStatusNative", "(Ljava/lang/String;Z)V",
1066 (void*)setBipClientStatusNative},
1067 {"listPlayerSettingsResponseNative", "([B)V",
1068 (void*)listPlayerSettingsResponseNative},
1069 {"listPlayerSettingValuesResponseNative", "(B[B)V",
1070 (void*)listPlayerSettingValuesResponseNative},
1071 {"getPlayerSettingsResponseNative", "([B[B)V",
1072 (void*)getPlayerSettingsResponseNative},
1073 {"setPlayerSettingsResponseNative", "(Z)V",
1074 (void*)setPlayerSettingsResponseNative},
1075 {"sendPlayerSettingsNative", "([B[B)V", (void*)sendPlayerSettingsNative},
1076 };
1077 const int result = REGISTER_NATIVE_METHODS(
1078 env, "com/android/bluetooth/avrcp/AvrcpNativeInterface", methods);
1079 if (result != 0) {
1080 return result;
1081 }
1082
1083 const JNIJavaMethod javaMethods[] = {
1084 {"getCurrentSongInfo", "()Lcom/android/bluetooth/audio_util/Metadata;",
1085 &method_getCurrentSongInfo},
1086 {"getPlayStatus", "()Lcom/android/bluetooth/audio_util/PlayStatus;",
1087 &method_getPlaybackStatus},
1088 {"sendMediaKeyEvent", "(IZ)V", &method_sendMediaKeyEvent},
1089 {"getCurrentMediaId", "()Ljava/lang/String;", &method_getCurrentMediaId},
1090 {"getNowPlayingList", "()Ljava/util/List;", &method_getNowPlayingList},
1091 {"getCurrentPlayerId", "()I", &method_getCurrentPlayerId},
1092 {"getMediaPlayerList", "()Ljava/util/List;", &method_getMediaPlayerList},
1093 {"setBrowsedPlayer", "(I)V", &method_setBrowsedPlayer},
1094 {"getFolderItemsRequest", "(ILjava/lang/String;)V",
1095 &method_getFolderItemsRequest},
1096 {"playItem", "(IZLjava/lang/String;)V", &method_playItem},
1097 {"setActiveDevice", "(Ljava/lang/String;)V", &method_setActiveDevice},
1098 {"deviceConnected", "(Ljava/lang/String;Z)V",
1099 &method_volumeDeviceConnected},
1100 {"deviceDisconnected", "(Ljava/lang/String;)V",
1101 &method_volumeDeviceDisconnected},
1102 {"setVolume", "(I)V", &method_setVolume},
1103 {"listPlayerSettingsRequest", "()V", &method_listPlayerSettings},
1104 {"listPlayerSettingValuesRequest", "(B)V",
1105 &method_listPlayerSettingValues},
1106 {"getCurrentPlayerSettingValuesRequest", "([B)V",
1107 &method_getPlayerSettings},
1108 {"setPlayerSettingsRequest", "([B[B)V", &method_setPlayerSettings},
1109 };
1110 GET_JAVA_METHODS(env, "com/android/bluetooth/avrcp/AvrcpNativeInterface",
1111 javaMethods);
1112
1113 return 0;
1114 }
1115
1116 } // namespace android
1117