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