blob: f67185f45776f1ec0bbb4c1cd2abc7f3955474d5 [file] [log] [blame]
/* Copyright 2019 HIMSA II K/S - www.himsa.com
* Represented by EHIMA - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "BluetoothLeAudioServiceJni"
#define LOG_NDEBUG 0
#include <hardware/bluetooth.h>
#include <array>
#include <optional>
#include <shared_mutex>
#include "com_android_bluetooth.h"
#include "hardware/bt_le_audio.h"
using bluetooth::le_audio::BroadcastAudioProfile;
using bluetooth::le_audio::BroadcastId;
using bluetooth::le_audio::BroadcastState;
using bluetooth::le_audio::btle_audio_codec_config_t;
using bluetooth::le_audio::btle_audio_codec_index_t;
using bluetooth::le_audio::ConnectionState;
using bluetooth::le_audio::GroupNodeStatus;
using bluetooth::le_audio::GroupStatus;
using bluetooth::le_audio::LeAudioBroadcasterCallbacks;
using bluetooth::le_audio::LeAudioBroadcasterInterface;
using bluetooth::le_audio::LeAudioClientCallbacks;
using bluetooth::le_audio::LeAudioClientInterface;
namespace android {
static jmethodID method_onConnectionStateChanged;
static jmethodID method_onGroupStatus;
static jmethodID method_onGroupNodeStatus;
static jmethodID method_onAudioConf;
static jmethodID method_onSinkAudioLocationAvailable;
static struct {
jclass clazz;
jmethodID constructor;
jmethodID getCodecType;
} android_bluetooth_BluetoothLeAudioCodecConfig;
static LeAudioClientInterface* sLeAudioClientInterface = nullptr;
static std::shared_timed_mutex interface_mutex;
static jobject mCallbacksObj = nullptr;
static std::shared_timed_mutex callbacks_mutex;
class LeAudioClientCallbacksImpl : public LeAudioClientCallbacks {
public:
~LeAudioClientCallbacksImpl() = default;
void OnConnectionState(ConnectionState state,
const RawAddress& bd_addr) override {
LOG(INFO) << __func__ << ", state:" << int(state);
std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
ScopedLocalRef<jbyteArray> addr(
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
if (!addr.get()) {
LOG(ERROR) << "Failed to new jbyteArray bd addr for connection state";
return;
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
(jbyte*)&bd_addr);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged,
(jint)state, addr.get());
}
void OnGroupStatus(int group_id, GroupStatus group_status) override {
LOG(INFO) << __func__;
std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGroupStatus,
(jint)group_id, (jint)group_status);
}
void OnGroupNodeStatus(const RawAddress& bd_addr, int group_id,
GroupNodeStatus node_status) override {
LOG(INFO) << __func__;
std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
ScopedLocalRef<jbyteArray> addr(
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
if (!addr.get()) {
LOG(ERROR) << "Failed to new jbyteArray bd addr for group status";
return;
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
(jbyte*)&bd_addr);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGroupNodeStatus,
addr.get(), (jint)group_id, (jint)node_status);
}
void OnAudioConf(uint8_t direction, int group_id,
uint32_t sink_audio_location, uint32_t source_audio_location,
uint16_t avail_cont) override {
LOG(INFO) << __func__;
std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioConf,
(jint)direction, (jint)group_id,
(jint)sink_audio_location,
(jint)source_audio_location, (jint)avail_cont);
}
void OnSinkAudioLocationAvailable(const RawAddress& bd_addr,
uint32_t sink_audio_location) override {
LOG(INFO) << __func__;
std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
ScopedLocalRef<jbyteArray> addr(
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
if (!addr.get()) {
LOG(ERROR) << "Failed to new jbyteArray bd addr for group status";
return;
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
(jbyte*)&bd_addr);
sCallbackEnv->CallVoidMethod(mCallbacksObj,
method_onSinkAudioLocationAvailable,
addr.get(), (jint)sink_audio_location);
}
};
static LeAudioClientCallbacksImpl sLeAudioClientCallbacks;
static void classInitNative(JNIEnv* env, jclass clazz) {
jclass jniBluetoothLeAudioCodecConfigClass =
env->FindClass("android/bluetooth/BluetoothLeAudioCodecConfig");
android_bluetooth_BluetoothLeAudioCodecConfig.constructor = env->GetMethodID(
jniBluetoothLeAudioCodecConfigClass, "<init>", "(IIIIIIIII)V");
android_bluetooth_BluetoothLeAudioCodecConfig.getCodecType = env->GetMethodID(
jniBluetoothLeAudioCodecConfigClass, "getCodecType", "()I");
method_onGroupStatus = env->GetMethodID(clazz, "onGroupStatus", "(II)V");
method_onGroupNodeStatus =
env->GetMethodID(clazz, "onGroupNodeStatus", "([BII)V");
method_onAudioConf = env->GetMethodID(clazz, "onAudioConf", "(IIIII)V");
method_onSinkAudioLocationAvailable =
env->GetMethodID(clazz, "onSinkAudioLocationAvailable", "([BI)V");
method_onConnectionStateChanged =
env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V");
}
std::vector<btle_audio_codec_config_t> prepareCodecPreferences(
JNIEnv* env, jobject object, jobjectArray codecConfigArray) {
std::vector<btle_audio_codec_config_t> codec_preferences;
int numConfigs = env->GetArrayLength(codecConfigArray);
for (int i = 0; i < numConfigs; i++) {
jobject jcodecConfig = env->GetObjectArrayElement(codecConfigArray, i);
if (jcodecConfig == nullptr) continue;
if (!env->IsInstanceOf(
jcodecConfig,
android_bluetooth_BluetoothLeAudioCodecConfig.clazz)) {
ALOGE("%s: Invalid BluetoothLeAudioCodecConfig instance", __func__);
continue;
}
jint codecType = env->CallIntMethod(
jcodecConfig,
android_bluetooth_BluetoothLeAudioCodecConfig.getCodecType);
btle_audio_codec_config_t codec_config = {
.codec_type = static_cast<btle_audio_codec_index_t>(codecType)};
codec_preferences.push_back(codec_config);
}
return codec_preferences;
}
static void initNative(JNIEnv* env, jobject object,
jobjectArray codecOffloadingArray) {
std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
const bt_interface_t* btInf = getBluetoothInterface();
if (btInf == nullptr) {
LOG(ERROR) << "Bluetooth module is not loaded";
return;
}
if (mCallbacksObj != nullptr) {
LOG(INFO) << "Cleaning up LeAudio callback object";
env->DeleteGlobalRef(mCallbacksObj);
mCallbacksObj = nullptr;
}
if ((mCallbacksObj = env->NewGlobalRef(object)) == nullptr) {
LOG(ERROR) << "Failed to allocate Global Ref for LeAudio Callbacks";
return;
}
android_bluetooth_BluetoothLeAudioCodecConfig.clazz =
(jclass)env->NewGlobalRef(
env->FindClass("android/bluetooth/BluetoothLeAudioCodecConfig"));
if (android_bluetooth_BluetoothLeAudioCodecConfig.clazz == nullptr) {
LOG(ERROR) << "Failed to allocate Global Ref for "
"BluetoothLeAudioCodecConfig class";
return;
}
sLeAudioClientInterface =
(LeAudioClientInterface*)btInf->get_profile_interface(
BT_PROFILE_LE_AUDIO_ID);
if (sLeAudioClientInterface == nullptr) {
LOG(ERROR) << "Failed to get Bluetooth LeAudio Interface";
return;
}
std::vector<btle_audio_codec_config_t> codec_offloading =
prepareCodecPreferences(env, object, codecOffloadingArray);
sLeAudioClientInterface->Initialize(&sLeAudioClientCallbacks,
codec_offloading);
}
static void cleanupNative(JNIEnv* env, jobject object) {
std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
const bt_interface_t* btInf = getBluetoothInterface();
if (btInf == nullptr) {
LOG(ERROR) << "Bluetooth module is not loaded";
return;
}
if (sLeAudioClientInterface != nullptr) {
sLeAudioClientInterface->Cleanup();
sLeAudioClientInterface = nullptr;
}
env->DeleteGlobalRef(android_bluetooth_BluetoothLeAudioCodecConfig.clazz);
android_bluetooth_BluetoothLeAudioCodecConfig.clazz = nullptr;
if (mCallbacksObj != nullptr) {
env->DeleteGlobalRef(mCallbacksObj);
mCallbacksObj = nullptr;
}
}
static jboolean connectLeAudioNative(JNIEnv* env, jobject object,
jbyteArray address) {
LOG(INFO) << __func__;
std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
if (!sLeAudioClientInterface) return JNI_FALSE;
jbyte* addr = env->GetByteArrayElements(address, nullptr);
if (!addr) {
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
RawAddress* tmpraw = (RawAddress*)addr;
sLeAudioClientInterface->Connect(*tmpraw);
env->ReleaseByteArrayElements(address, addr, 0);
return JNI_TRUE;
}
static jboolean disconnectLeAudioNative(JNIEnv* env, jobject object,
jbyteArray address) {
LOG(INFO) << __func__;
std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
if (!sLeAudioClientInterface) return JNI_FALSE;
jbyte* addr = env->GetByteArrayElements(address, nullptr);
if (!addr) {
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
RawAddress* tmpraw = (RawAddress*)addr;
sLeAudioClientInterface->Disconnect(*tmpraw);
env->ReleaseByteArrayElements(address, addr, 0);
return JNI_TRUE;
}
static jboolean groupAddNodeNative(JNIEnv* env, jobject object, jint group_id,
jbyteArray address) {
jbyte* addr = env->GetByteArrayElements(address, nullptr);
if (!sLeAudioClientInterface) {
LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface";
return JNI_FALSE;
}
if (!addr) {
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
RawAddress* tmpraw = (RawAddress*)addr;
sLeAudioClientInterface->GroupAddNode(group_id, *tmpraw);
env->ReleaseByteArrayElements(address, addr, 0);
return JNI_TRUE;
}
static jboolean groupRemoveNodeNative(JNIEnv* env, jobject object,
jint group_id, jbyteArray address) {
if (!sLeAudioClientInterface) {
LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface";
return JNI_FALSE;
}
jbyte* addr = env->GetByteArrayElements(address, nullptr);
if (!addr) {
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
RawAddress* tmpraw = (RawAddress*)addr;
sLeAudioClientInterface->GroupRemoveNode(group_id, *tmpraw);
env->ReleaseByteArrayElements(address, addr, 0);
return JNI_TRUE;
}
static void groupSetActiveNative(JNIEnv* env, jobject object, jint group_id) {
LOG(INFO) << __func__;
if (!sLeAudioClientInterface) {
LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface";
return;
}
sLeAudioClientInterface->GroupSetActive(group_id);
}
static void setCodecConfigPreferenceNative(JNIEnv* env, jobject object,
jint group_id,
jobject inputCodecConfig,
jobject outputCodecConfig) {
if (!env->IsInstanceOf(inputCodecConfig,
android_bluetooth_BluetoothLeAudioCodecConfig.clazz) ||
!env->IsInstanceOf(outputCodecConfig,
android_bluetooth_BluetoothLeAudioCodecConfig.clazz)) {
ALOGE("%s: Invalid BluetoothLeAudioCodecConfig instance", __func__);
return;
}
// TODO Implement
}
static JNINativeMethod sMethods[] = {
{"classInitNative", "()V", (void*)classInitNative},
{"initNative", "([Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V",
(void*)initNative},
{"cleanupNative", "()V", (void*)cleanupNative},
{"connectLeAudioNative", "([B)Z", (void*)connectLeAudioNative},
{"disconnectLeAudioNative", "([B)Z", (void*)disconnectLeAudioNative},
{"groupAddNodeNative", "(I[B)Z", (void*)groupAddNodeNative},
{"groupRemoveNodeNative", "(I[B)Z", (void*)groupRemoveNodeNative},
{"groupSetActiveNative", "(I)V", (void*)groupSetActiveNative},
{"setCodecConfigPreferenceNative",
"(ILandroid/bluetooth/BluetoothLeAudioCodecConfig;Landroid/bluetooth/"
"BluetoothLeAudioCodecConfig;)V",
(void*)setCodecConfigPreferenceNative},
};
/* Le Audio Broadcaster */
static jmethodID method_onBroadcastCreated;
static jmethodID method_onBroadcastDestroyed;
static jmethodID method_onBroadcastStateChanged;
static jmethodID method_onBroadcastId;
static LeAudioBroadcasterInterface* sLeAudioBroadcasterInterface = nullptr;
static std::shared_timed_mutex sBroadcasterInterfaceMutex;
static jobject sBroadcasterCallbacksObj = nullptr;
static std::shared_timed_mutex sBroadcasterCallbacksMutex;
class LeAudioBroadcasterCallbacksImpl : public LeAudioBroadcasterCallbacks {
public:
~LeAudioBroadcasterCallbacksImpl() = default;
void OnBroadcastCreated(uint8_t instance_id, bool success) override {
LOG(INFO) << __func__;
std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return;
sCallbackEnv->CallVoidMethod(sBroadcasterCallbacksObj,
method_onBroadcastCreated, (jint)instance_id,
success ? JNI_TRUE : JNI_FALSE);
}
void OnBroadcastDestroyed(uint8_t instance_id) override {
LOG(INFO) << __func__;
std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return;
sCallbackEnv->CallVoidMethod(sBroadcasterCallbacksObj,
method_onBroadcastDestroyed,
(jint)instance_id);
}
void OnBroadcastStateChanged(uint8_t instance_id,
BroadcastState state) override {
LOG(INFO) << __func__;
std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return;
sCallbackEnv->CallVoidMethod(
sBroadcasterCallbacksObj, method_onBroadcastStateChanged,
(jint)instance_id,
(jint) static_cast<std::underlying_type<BroadcastState>::type>(state));
}
void OnBroadcastId(uint8_t instance_id,
const BroadcastId& broadcast_id) override {
LOG(INFO) << __func__;
std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex);
CallbackEnv sCallbackEnv(__func__);
// broadcast_id
int field_size = broadcast_id.size();
ScopedLocalRef<jbyteArray> serialized_broadcast_id(
sCallbackEnv.get(), sCallbackEnv->NewByteArray(field_size));
if (!serialized_broadcast_id.get()) {
LOG(ERROR) << "Failed to allocate new jbyteArray broadcast_id for the "
"announcement";
return;
}
sCallbackEnv->SetByteArrayRegion(serialized_broadcast_id.get(), 0,
field_size, (jbyte*)broadcast_id.data());
if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return;
sCallbackEnv->CallVoidMethod(sBroadcasterCallbacksObj, method_onBroadcastId,
(jint)instance_id,
serialized_broadcast_id.get());
}
};
static LeAudioBroadcasterCallbacksImpl sLeAudioBroadcasterCallbacks;
static void BroadcasterClassInitNative(JNIEnv* env, jclass clazz) {
method_onBroadcastCreated =
env->GetMethodID(clazz, "onBroadcastCreated", "(IZ)V");
method_onBroadcastDestroyed =
env->GetMethodID(clazz, "onBroadcastDestroyed", "(I)V");
method_onBroadcastStateChanged =
env->GetMethodID(clazz, "onBroadcastStateChanged", "(II)V");
method_onBroadcastId = env->GetMethodID(clazz, "onBroadcastId", "(I[B)V");
}
static void BroadcasterInitNative(JNIEnv* env, jobject object) {
std::unique_lock<std::shared_timed_mutex> interface_lock(
sBroadcasterInterfaceMutex);
std::unique_lock<std::shared_timed_mutex> callbacks_lock(
sBroadcasterCallbacksMutex);
const bt_interface_t* btInf = getBluetoothInterface();
if (btInf == nullptr) {
LOG(ERROR) << "Bluetooth module is not loaded";
return;
}
if (sBroadcasterCallbacksObj != nullptr) {
LOG(INFO) << "Cleaning up LeAudio Broadcaster callback object";
env->DeleteGlobalRef(sBroadcasterCallbacksObj);
sBroadcasterCallbacksObj = nullptr;
}
if ((sBroadcasterCallbacksObj = env->NewGlobalRef(object)) == nullptr) {
LOG(ERROR)
<< "Failed to allocate Global Ref for LeAudio Broadcaster Callbacks";
return;
}
sLeAudioBroadcasterInterface =
(LeAudioBroadcasterInterface*)btInf->get_profile_interface(
BT_PROFILE_LE_AUDIO_BROADCASTER_ID);
if (sLeAudioBroadcasterInterface == nullptr) {
LOG(ERROR) << "Failed to get Bluetooth LeAudio Broadcaster Interface";
return;
}
sLeAudioBroadcasterInterface->Initialize(&sLeAudioBroadcasterCallbacks);
}
static void BroadcasterStopNative(JNIEnv* env, jobject object) {
std::unique_lock<std::shared_timed_mutex> interface_lock(
sBroadcasterInterfaceMutex);
const bt_interface_t* btInf = getBluetoothInterface();
if (btInf == nullptr) {
LOG(ERROR) << "Bluetooth module is not loaded";
return;
}
if (sLeAudioBroadcasterInterface != nullptr)
sLeAudioBroadcasterInterface->Stop();
}
static void BroadcasterCleanupNative(JNIEnv* env, jobject object) {
std::unique_lock<std::shared_timed_mutex> interface_lock(
sBroadcasterInterfaceMutex);
std::unique_lock<std::shared_timed_mutex> callbacks_lock(
sBroadcasterCallbacksMutex);
const bt_interface_t* btInf = getBluetoothInterface();
if (btInf == nullptr) {
LOG(ERROR) << "Bluetooth module is not loaded";
return;
}
if (sLeAudioBroadcasterInterface != nullptr) {
sLeAudioBroadcasterInterface->Cleanup();
sLeAudioBroadcasterInterface = nullptr;
}
if (sBroadcasterCallbacksObj != nullptr) {
env->DeleteGlobalRef(sBroadcasterCallbacksObj);
sBroadcasterCallbacksObj = nullptr;
}
}
static void CreateBroadcastNative(JNIEnv* env, jobject object,
jbyteArray metadata, jint audio_profile,
jbyteArray broadcast_code) {
LOG(INFO) << __func__;
std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
if (!sLeAudioBroadcasterInterface) return;
std::array<uint8_t, 16> code_array;
if (broadcast_code)
env->GetByteArrayRegion(broadcast_code, 0, 16, (jbyte*)code_array.data());
jbyte* meta = env->GetByteArrayElements(metadata, nullptr);
sLeAudioBroadcasterInterface->CreateBroadcast(
std::vector<uint8_t>(meta, meta + env->GetArrayLength(metadata)),
static_cast<BroadcastAudioProfile>(audio_profile),
broadcast_code ? std::optional<std::array<uint8_t, 16>>(code_array)
: std::nullopt);
env->ReleaseByteArrayElements(metadata, meta, 0);
}
static void UpdateMetadataNative(JNIEnv* env, jobject object, jint instance_id,
jbyteArray metadata) {
jbyte* meta = env->GetByteArrayElements(metadata, nullptr);
sLeAudioBroadcasterInterface->UpdateMetadata(
instance_id,
std::vector<uint8_t>(meta, meta + env->GetArrayLength(metadata)));
env->ReleaseByteArrayElements(metadata, meta, 0);
}
static void StartBroadcastNative(JNIEnv* env, jobject object,
jint instance_id) {
LOG(INFO) << __func__;
std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
if (!sLeAudioBroadcasterInterface) return;
sLeAudioBroadcasterInterface->StartBroadcast(instance_id);
}
static void StopBroadcastNative(JNIEnv* env, jobject object, jint instance_id) {
LOG(INFO) << __func__;
std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
if (!sLeAudioBroadcasterInterface) return;
sLeAudioBroadcasterInterface->StopBroadcast(instance_id);
}
static void PauseBroadcastNative(JNIEnv* env, jobject object,
jint instance_id) {
LOG(INFO) << __func__;
std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
if (!sLeAudioBroadcasterInterface) return;
sLeAudioBroadcasterInterface->PauseBroadcast(instance_id);
}
static void DestroyBroadcastNative(JNIEnv* env, jobject object,
jint instance_id) {
LOG(INFO) << __func__;
std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
if (!sLeAudioBroadcasterInterface) return;
sLeAudioBroadcasterInterface->DestroyBroadcast(instance_id);
}
static void GetBroadcastIdNative(JNIEnv* env, jobject object,
jint instance_id) {
LOG(INFO) << __func__;
std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
if (!sLeAudioBroadcasterInterface) return;
sLeAudioBroadcasterInterface->GetBroadcastId(instance_id);
}
static void GetAllBroadcastStatesNative(JNIEnv* env, jobject object) {
LOG(INFO) << __func__;
std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
if (!sLeAudioBroadcasterInterface) return;
sLeAudioBroadcasterInterface->GetAllBroadcastStates();
}
static JNINativeMethod sBroadcasterMethods[] = {
{"classInitNative", "()V", (void*)BroadcasterClassInitNative},
{"initNative", "()V", (void*)BroadcasterInitNative},
{"stopNative", "()V", (void*)BroadcasterStopNative},
{"cleanupNative", "()V", (void*)BroadcasterCleanupNative},
{"createBroadcastNative", "([BI[B)V", (void*)CreateBroadcastNative},
{"updateMetadataNative", "(I[B)V", (void*)UpdateMetadataNative},
{"startBroadcastNative", "(I)V", (void*)StartBroadcastNative},
{"stopBroadcastNative", "(I)V", (void*)StopBroadcastNative},
{"pauseBroadcastNative", "(I)V", (void*)PauseBroadcastNative},
{"destroyBroadcastNative", "(I)V", (void*)DestroyBroadcastNative},
{"getBroadcastIdNative", "(I)V", (void*)GetBroadcastIdNative},
{"getAllBroadcastStatesNative", "()V", (void*)GetAllBroadcastStatesNative},
};
int register_com_android_bluetooth_le_audio(JNIEnv* env) {
int register_success = jniRegisterNativeMethods(
env, "com/android/bluetooth/le_audio/LeAudioNativeInterface", sMethods,
NELEM(sMethods));
return register_success &
jniRegisterNativeMethods(
env,
"com/android/bluetooth/le_audio/LeAudioBroadcasterNativeInterface",
sBroadcasterMethods, NELEM(sBroadcasterMethods));
}
} // namespace android