Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 15a8e39b authored by Jack He's avatar Jack He Committed by Automerger Merge Worker
Browse files

Merge changes If47a6350,Ib795d8d8 am: 2d58918e am: eb38a571 am: ada957e4

parents 50da0abc ada957e4
Loading
Loading
Loading
Loading
+477 −3
Original line number Diff line number Diff line
@@ -53,6 +53,42 @@ static struct {
  jmethodID getCodecType;
} android_bluetooth_BluetoothLeAudioCodecConfig;

static struct {
  jclass clazz;
  jmethodID constructor;
} android_bluetooth_BluetoothLeAudioCodecConfigMetadata;

static struct {
  jclass clazz;
  jmethodID constructor;
  jmethodID add;
} java_util_ArrayList;

static struct {
  jclass clazz;
  jmethodID constructor;
} android_bluetooth_BluetoothLeBroadcastChannel;

static struct {
  jclass clazz;
  jmethodID constructor;
} android_bluetooth_BluetoothLeBroadcastSubgroup;

static struct {
  jclass clazz;
  jmethodID constructor;
} android_bluetooth_BluetoothLeAudioContentMetadata;

static struct {
  jclass clazz;
  jmethodID constructor;
} android_bluetooth_BluetoothLeBroadcastMetadata;

static struct {
  jclass clazz;
  jmethodID constructor;
} android_bluetooth_BluetoothDevice;

static LeAudioClientInterface* sLeAudioClientInterface = nullptr;
static std::shared_timed_mutex interface_mutex;

@@ -496,6 +532,7 @@ static JNINativeMethod sMethods[] = {
static jmethodID method_onBroadcastCreated;
static jmethodID method_onBroadcastDestroyed;
static jmethodID method_onBroadcastStateChanged;
static jmethodID method_onBroadcastMetadataChanged;

static LeAudioBroadcasterInterface* sLeAudioBroadcasterInterface = nullptr;
static std::shared_timed_mutex sBroadcasterInterfaceMutex;
@@ -503,6 +540,297 @@ static std::shared_timed_mutex sBroadcasterInterfaceMutex;
static jobject sBroadcasterCallbacksObj = nullptr;
static std::shared_timed_mutex sBroadcasterCallbacksMutex;

#define VEC_UINT8_TO_UINT32(vec)                                          \
  ((vec.data()[3] << 24) + (vec.data()[2] << 16) + (vec.data()[1] << 8) + \
   vec.data()[0])

size_t RawPacketSize(const std::map<uint8_t, std::vector<uint8_t>>& values) {
  size_t bytes = 0;
  for (auto const& value : values) {
    bytes += (/* ltv_len + ltv_type */ 2 + value.second.size());
  }
  return bytes;
}

jbyteArray prepareRawLtvArray(
    JNIEnv* env, const std::map<uint8_t, std::vector<uint8_t>>& metadata) {
  auto raw_meta_size = RawPacketSize(metadata);

  jbyteArray raw_metadata = env->NewByteArray(raw_meta_size);
  if (!raw_metadata) {
    LOG(ERROR) << "Failed to create new jbyteArray for raw LTV";
    return nullptr;
  }

  jsize offset = 0;
  for (auto const& kv_pair : metadata) {
    // Length
    const jbyte ltv_sz = kv_pair.second.size() + 1;
    env->SetByteArrayRegion(raw_metadata, offset, 1, &ltv_sz);
    offset += 1;
    // Type
    env->SetByteArrayRegion(raw_metadata, offset, 1,
                            (const jbyte*)&kv_pair.first);
    offset += 1;
    // Value
    env->SetByteArrayRegion(raw_metadata, offset, 1,
                            (const jbyte*)kv_pair.second.data());
    offset += kv_pair.second.size();
  }

  return raw_metadata;
}

static jlong getAudioLocationOrDefault(
    const std::map<uint8_t, std::vector<uint8_t>>& metadata,
    jlong default_location) {
  if (metadata.count(
          bluetooth::le_audio::kLeAudioCodecLC3TypeAudioChannelAllocation) == 0)
    return default_location;

  auto& vec = metadata.at(
      bluetooth::le_audio::kLeAudioCodecLC3TypeAudioChannelAllocation);
  return VEC_UINT8_TO_UINT32(vec);
}

jobject prepareLeAudioCodecConfigMetadataObject(
    JNIEnv* env, const std::map<uint8_t, std::vector<uint8_t>>& metadata) {
  jlong audio_location = getAudioLocationOrDefault(metadata, -1);
  ScopedLocalRef<jbyteArray> raw_metadata(env,
                                          prepareRawLtvArray(env, metadata));
  if (!raw_metadata.get()) {
    LOG(ERROR) << "Failed to create raw metadata jbyteArray";
    return nullptr;
  }

  jobject obj = env->NewObject(
      android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz,
      android_bluetooth_BluetoothLeAudioCodecConfigMetadata.constructor,
      audio_location, raw_metadata.get());

  return obj;
}

jobject prepareLeBroadcastChannelObject(
    JNIEnv* env,
    const bluetooth::le_audio::BasicAudioAnnouncementBisConfig& bis_config) {
  ScopedLocalRef<jobject> meta_object(
      env, prepareLeAudioCodecConfigMetadataObject(
               env, bis_config.codec_specific_params));
  if (!meta_object.get()) {
    LOG(ERROR) << "Failed to create new metadata object for bis config";
    return nullptr;
  }

  jobject obj =
      env->NewObject(android_bluetooth_BluetoothLeBroadcastChannel.clazz,
                     android_bluetooth_BluetoothLeBroadcastChannel.constructor,
                     false, bis_config.bis_index, meta_object.get());

  return obj;
}

jobject prepareLeAudioContentMetadataObject(
    JNIEnv* env, const std::map<uint8_t, std::vector<uint8_t>>& metadata) {
  jstring program_info_str = nullptr;
  if (metadata.count(bluetooth::le_audio::kLeAudioMetadataTypeProgramInfo)) {
    program_info_str = env->NewStringUTF(
        (const char*)(metadata
                          .at(bluetooth::le_audio::
                                  kLeAudioMetadataTypeProgramInfo)
                          .data()));
    if (!program_info_str) {
      LOG(ERROR) << "Failed to create new preset name String for preset name";
      return nullptr;
    }
  }

  jstring language_str = nullptr;
  if (metadata.count(bluetooth::le_audio::kLeAudioMetadataTypeLanguage)) {
    language_str = env->NewStringUTF(
        (const char*)(metadata
                          .at(bluetooth::le_audio::kLeAudioMetadataTypeLanguage)
                          .data()));
    if (!language_str) {
      LOG(ERROR) << "Failed to create new preset name String for language";
      return nullptr;
    }
  }

  // This can be nullptr
  ScopedLocalRef<jbyteArray> raw_metadata(env,
                                          prepareRawLtvArray(env, metadata));
  if (!raw_metadata.get()) {
    LOG(ERROR) << "Failed to create raw_metadata jbyteArray";
    return nullptr;
  }

  jobject obj = env->NewObject(
      android_bluetooth_BluetoothLeAudioContentMetadata.clazz,
      android_bluetooth_BluetoothLeAudioContentMetadata.constructor,
      program_info_str, language_str, raw_metadata.get());

  if (program_info_str) {
    env->DeleteLocalRef(program_info_str);
  }

  if (language_str) {
    env->DeleteLocalRef(language_str);
  }

  return obj;
}

jobject prepareLeBroadcastChannelListObject(
    JNIEnv* env,
    const std::vector<bluetooth::le_audio::BasicAudioAnnouncementBisConfig>&
        bis_configs) {
  jobject array = env->NewObject(java_util_ArrayList.clazz,
                                 java_util_ArrayList.constructor);
  if (!array) {
    LOG(ERROR) << "Failed to create array for subgroups";
    return nullptr;
  }

  for (const auto& el : bis_configs) {
    ScopedLocalRef<jobject> channel_obj(
        env, prepareLeBroadcastChannelObject(env, el));
    if (!channel_obj.get()) {
      LOG(ERROR) << "Failed to create new channel object";
      return nullptr;
    }

    env->CallBooleanMethod(array, java_util_ArrayList.add, channel_obj.get());
  }
  return array;
}

jobject prepareLeBroadcastSubgroupObject(
    JNIEnv* env,
    const bluetooth::le_audio::BasicAudioAnnouncementSubgroup& subgroup) {
  // Serialize codec ID
  jlong jlong_codec_id =
      subgroup.codec_config.codec_id |
      ((jlong)subgroup.codec_config.vendor_company_id << 16) |
      ((jlong)subgroup.codec_config.vendor_codec_id << 32);

  ScopedLocalRef<jobject> codec_config_meta_obj(
      env, prepareLeAudioCodecConfigMetadataObject(
               env, subgroup.codec_config.codec_specific_params));
  if (!codec_config_meta_obj.get()) {
    LOG(ERROR) << "Failed to create new codec config metadata";
    return nullptr;
  }

  ScopedLocalRef<jobject> content_meta_obj(
      env, prepareLeAudioContentMetadataObject(env, subgroup.metadata));
  if (!content_meta_obj.get()) {
    LOG(ERROR) << "Failed to create new codec config metadata";
    return nullptr;
  }

  ScopedLocalRef<jobject> channel_list_obj(
      env, prepareLeBroadcastChannelListObject(env, subgroup.bis_configs));
  if (!channel_list_obj.get()) {
    LOG(ERROR) << "Failed to create new codec config metadata";
    return nullptr;
  }

  // Create the subgroup
  return env->NewObject(
      android_bluetooth_BluetoothLeBroadcastSubgroup.clazz,
      android_bluetooth_BluetoothLeBroadcastSubgroup.constructor,
      jlong_codec_id, codec_config_meta_obj.get(), content_meta_obj.get(),
      channel_list_obj.get());
}

jobject prepareLeBroadcastSubgroupListObject(
    JNIEnv* env,
    const std::vector<bluetooth::le_audio::BasicAudioAnnouncementSubgroup>&
        subgroup_configs) {
  jobject array = env->NewObject(java_util_ArrayList.clazz,
                                 java_util_ArrayList.constructor);
  if (!array) {
    LOG(ERROR) << "Failed to create array for subgroups";
    return nullptr;
  }

  for (const auto& el : subgroup_configs) {
    ScopedLocalRef<jobject> subgroup_obj(
        env, prepareLeBroadcastSubgroupObject(env, el));
    if (!subgroup_obj.get()) {
      LOG(ERROR) << "Failed to create new subgroup object";
      return nullptr;
    }

    env->CallBooleanMethod(array, java_util_ArrayList.add, subgroup_obj.get());
  }
  return array;
}

jobject prepareBluetoothDeviceObject(JNIEnv* env, const RawAddress& addr,
                                     int addr_type) {
  // The address string has to be uppercase or the BluetoothDevice constructor
  // will treat it as invalid.
  auto addr_str = addr.ToString();
  std::transform(addr_str.begin(), addr_str.end(), addr_str.begin(),
                 [](unsigned char c) { return std::toupper(c); });

  ScopedLocalRef<jstring> addr_jstr(env, env->NewStringUTF(addr_str.c_str()));
  if (!addr_jstr.get()) {
    LOG(ERROR) << "Failed to create new preset name String for preset name";
    return nullptr;
  }

  return env->NewObject(android_bluetooth_BluetoothDevice.clazz,
                        android_bluetooth_BluetoothDevice.constructor,
                        addr_jstr.get(), (jint)addr_type);
}

jobject prepareBluetoothLeBroadcastMetadataObject(
    JNIEnv* env,
    const bluetooth::le_audio::BroadcastMetadata& broadcast_metadata) {
  ScopedLocalRef<jobject> device_obj(
      env, prepareBluetoothDeviceObject(env, broadcast_metadata.addr,
                                        broadcast_metadata.addr_type));
  if (!device_obj.get()) {
    LOG(ERROR) << "Failed to create new BluetoothDevice";
    return nullptr;
  }

  ScopedLocalRef<jobject> subgroup_list_obj(
      env,
      prepareLeBroadcastSubgroupListObject(
          env, broadcast_metadata.basic_audio_announcement.subgroup_configs));
  if (!subgroup_list_obj.get()) {
    LOG(ERROR) << "Failed to create new Subgroup array";
    return nullptr;
  }

  ScopedLocalRef<jbyteArray> code(env, env->NewByteArray(sizeof(RawAddress)));
  if (!code.get()) {
    LOG(ERROR) << "Failed to create new jbyteArray for the broadcast code";
    return nullptr;
  }

  if (broadcast_metadata.broadcast_code) {
    env->SetByteArrayRegion(
        code.get(), 0, sizeof(RawAddress),
        (jbyte*)broadcast_metadata.broadcast_code.value().data());
  }

  return env->NewObject(
      android_bluetooth_BluetoothLeBroadcastMetadata.clazz,
      android_bluetooth_BluetoothLeBroadcastMetadata.constructor,
      (jint)broadcast_metadata.addr_type, device_obj.get(),
      (jint)broadcast_metadata.adv_sid, (jint)broadcast_metadata.broadcast_id,
      (jint)broadcast_metadata.pa_interval,
      broadcast_metadata.broadcast_code ? true : false,
      broadcast_metadata.broadcast_code ? code.get() : nullptr,
      (jint)broadcast_metadata.basic_audio_announcement.presentation_delay,
      subgroup_list_obj.get());
}

class LeAudioBroadcasterCallbacksImpl : public LeAudioBroadcasterCallbacks {
 public:
  ~LeAudioBroadcasterCallbacksImpl() = default;
@@ -544,6 +872,24 @@ class LeAudioBroadcasterCallbacksImpl : public LeAudioBroadcasterCallbacks {
        (jint)broadcast_id,
        (jint) static_cast<std::underlying_type<BroadcastState>::type>(state));
  }

  void OnBroadcastMetadataChanged(uint32_t broadcast_id,
                                  const bluetooth::le_audio::BroadcastMetadata&
                                      broadcast_metadata) override {
    LOG(INFO) << __func__;

    std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex);
    CallbackEnv sCallbackEnv(__func__);

    ScopedLocalRef<jobject> metadata_obj(
        sCallbackEnv.get(), prepareBluetoothLeBroadcastMetadataObject(
                                sCallbackEnv.get(), broadcast_metadata));

    if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return;
    sCallbackEnv->CallVoidMethod(sBroadcasterCallbacksObj,
                                 method_onBroadcastMetadataChanged,
                                 (jint)broadcast_id, metadata_obj.get());
  }
};

static LeAudioBroadcasterCallbacksImpl sLeAudioBroadcasterCallbacks;
@@ -555,6 +901,52 @@ static void BroadcasterClassInitNative(JNIEnv* env, jclass clazz) {
      env->GetMethodID(clazz, "onBroadcastDestroyed", "(I)V");
  method_onBroadcastStateChanged =
      env->GetMethodID(clazz, "onBroadcastStateChanged", "(II)V");
  method_onBroadcastMetadataChanged =
      env->GetMethodID(clazz, "onBroadcastMetadataChanged",
                       "(ILandroid/bluetooth/BluetoothLeBroadcastMetadata;)V");

  jclass jniArrayListClass = env->FindClass("java/util/ArrayList");
  java_util_ArrayList.constructor =
      env->GetMethodID(jniArrayListClass, "<init>", "()V");
  java_util_ArrayList.add =
      env->GetMethodID(jniArrayListClass, "add", "(Ljava/lang/Object;)Z");

  jclass jniBluetoothLeAudioCodecConfigMetadataClass =
      env->FindClass("android/bluetooth/BluetoothLeAudioCodecConfigMetadata");
  android_bluetooth_BluetoothLeAudioCodecConfigMetadata.constructor =
      env->GetMethodID(jniBluetoothLeAudioCodecConfigMetadataClass, "<init>",
                       "(J[B)V");

  jclass jniBluetoothLeAudioContentMetadataClass =
      env->FindClass("android/bluetooth/BluetoothLeAudioContentMetadata");
  android_bluetooth_BluetoothLeAudioContentMetadata.constructor =
      env->GetMethodID(jniBluetoothLeAudioContentMetadataClass, "<init>",
                       "(Ljava/lang/String;Ljava/lang/String;[B)V");

  jclass jniBluetoothLeBroadcastChannelClass =
      env->FindClass("android/bluetooth/BluetoothLeBroadcastChannel");
  android_bluetooth_BluetoothLeBroadcastChannel.constructor = env->GetMethodID(
      jniBluetoothLeBroadcastChannelClass, "<init>",
      "(ZILandroid/bluetooth/BluetoothLeAudioCodecConfigMetadata;)V");

  jclass jniBluetoothLeBroadcastSubgroupClass =
      env->FindClass("android/bluetooth/BluetoothLeBroadcastSubgroup");
  android_bluetooth_BluetoothLeBroadcastSubgroup.constructor = env->GetMethodID(
      jniBluetoothLeBroadcastSubgroupClass, "<init>",
      "(JLandroid/bluetooth/BluetoothLeAudioCodecConfigMetadata;"
      "Landroid/bluetooth/BluetoothLeAudioContentMetadata;"
      "Ljava/util/List;)V");

  jclass jniBluetoothDeviceClass =
      env->FindClass("android/bluetooth/BluetoothDevice");
  android_bluetooth_BluetoothDevice.constructor = env->GetMethodID(
      jniBluetoothDeviceClass, "<init>", "(Ljava/lang/String;I)V");

  jclass jniBluetoothLeBroadcastMetadataClass =
      env->FindClass("android/bluetooth/BluetoothLeBroadcastMetadata");
  android_bluetooth_BluetoothLeBroadcastMetadata.constructor = env->GetMethodID(
      jniBluetoothLeBroadcastMetadataClass, "<init>",
      "(ILandroid/bluetooth/BluetoothDevice;IIIZ[BILjava/util/List;)V");
}

static void BroadcasterInitNative(JNIEnv* env, jobject object) {
@@ -569,6 +961,65 @@ static void BroadcasterInitNative(JNIEnv* env, jobject object) {
    return;
  }

  android_bluetooth_BluetoothDevice.clazz = (jclass)env->NewGlobalRef(
      env->FindClass("android/bluetooth/BluetoothDevice"));
  if (android_bluetooth_BluetoothDevice.clazz == nullptr) {
    LOG(ERROR) << "Failed to allocate Global Ref for BluetoothDevice class";
    return;
  }

  java_util_ArrayList.clazz =
      (jclass)env->NewGlobalRef(env->FindClass("java/util/ArrayList"));
  if (java_util_ArrayList.clazz == nullptr) {
    LOG(ERROR) << "Failed to allocate Global Ref for ArrayList class";
    return;
  }

  android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz =
      (jclass)env->NewGlobalRef(env->FindClass(
          "android/bluetooth/BluetoothLeAudioCodecConfigMetadata"));
  if (android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz == nullptr) {
    LOG(ERROR) << "Failed to allocate Global Ref for "
                  "BluetoothLeAudioCodecConfigMetadata class";
    return;
  }

  android_bluetooth_BluetoothLeAudioContentMetadata.clazz =
      (jclass)env->NewGlobalRef(
          env->FindClass("android/bluetooth/BluetoothLeAudioContentMetadata"));
  if (android_bluetooth_BluetoothLeAudioContentMetadata.clazz == nullptr) {
    LOG(ERROR) << "Failed to allocate Global Ref for "
                  "BluetoothLeAudioContentMetadata class";
    return;
  }

  android_bluetooth_BluetoothLeBroadcastSubgroup.clazz =
      (jclass)env->NewGlobalRef(
          env->FindClass("android/bluetooth/BluetoothLeBroadcastSubgroup"));
  if (android_bluetooth_BluetoothLeBroadcastSubgroup.clazz == nullptr) {
    LOG(ERROR) << "Failed to allocate Global Ref for "
                  "BluetoothLeBroadcastSubgroup class";
    return;
  }

  android_bluetooth_BluetoothLeBroadcastChannel.clazz =
      (jclass)env->NewGlobalRef(
          env->FindClass("android/bluetooth/BluetoothLeBroadcastChannel"));
  if (android_bluetooth_BluetoothLeBroadcastChannel.clazz == nullptr) {
    LOG(ERROR) << "Failed to allocate Global Ref for "
                  "BluetoothLeBroadcastChannel class";
    return;
  }

  android_bluetooth_BluetoothLeBroadcastMetadata.clazz =
      (jclass)env->NewGlobalRef(
          env->FindClass("android/bluetooth/BluetoothLeBroadcastMetadata"));
  if (android_bluetooth_BluetoothLeBroadcastMetadata.clazz == nullptr) {
    LOG(ERROR) << "Failed to allocate Global Ref for "
                  "BluetoothLeBroadcastMetadata class";
    return;
  }

  if (sBroadcasterCallbacksObj != nullptr) {
    LOG(INFO) << "Cleaning up LeAudio Broadcaster callback object";
    env->DeleteGlobalRef(sBroadcasterCallbacksObj);
@@ -618,6 +1069,28 @@ static void BroadcasterCleanupNative(JNIEnv* env, jobject object) {
    return;
  }

  env->DeleteGlobalRef(java_util_ArrayList.clazz);
  java_util_ArrayList.clazz = nullptr;

  env->DeleteGlobalRef(android_bluetooth_BluetoothDevice.clazz);
  android_bluetooth_BluetoothDevice.clazz = nullptr;

  env->DeleteGlobalRef(
      android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz);
  android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz = nullptr;

  env->DeleteGlobalRef(android_bluetooth_BluetoothLeAudioContentMetadata.clazz);
  android_bluetooth_BluetoothLeAudioContentMetadata.clazz = nullptr;

  env->DeleteGlobalRef(android_bluetooth_BluetoothLeBroadcastSubgroup.clazz);
  android_bluetooth_BluetoothLeBroadcastSubgroup.clazz = nullptr;

  env->DeleteGlobalRef(android_bluetooth_BluetoothLeBroadcastChannel.clazz);
  android_bluetooth_BluetoothLeBroadcastChannel.clazz = nullptr;

  env->DeleteGlobalRef(android_bluetooth_BluetoothLeBroadcastMetadata.clazz);
  android_bluetooth_BluetoothLeBroadcastMetadata.clazz = nullptr;

  if (sLeAudioBroadcasterInterface != nullptr) {
    sLeAudioBroadcasterInterface->Cleanup();
    sLeAudioBroadcasterInterface = nullptr;
@@ -690,11 +1163,12 @@ static void DestroyBroadcastNative(JNIEnv* env, jobject object,
  sLeAudioBroadcasterInterface->DestroyBroadcast(broadcast_id);
}

static void GetAllBroadcastStatesNative(JNIEnv* env, jobject object) {
static void getBroadcastMetadataNative(JNIEnv* env, jobject object,
                                       jint broadcast_id) {
  LOG(INFO) << __func__;
  std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
  if (!sLeAudioBroadcasterInterface) return;
  sLeAudioBroadcasterInterface->GetAllBroadcastStates();
  sLeAudioBroadcasterInterface->GetBroadcastMetadata(broadcast_id);
}

static JNINativeMethod sBroadcasterMethods[] = {
@@ -708,7 +1182,7 @@ static JNINativeMethod sBroadcasterMethods[] = {
    {"stopBroadcastNative", "(I)V", (void*)StopBroadcastNative},
    {"pauseBroadcastNative", "(I)V", (void*)PauseBroadcastNative},
    {"destroyBroadcastNative", "(I)V", (void*)DestroyBroadcastNative},
    {"getAllBroadcastStatesNative", "()V", (void*)GetAllBroadcastStatesNative},
    {"getBroadcastMetadataNative", "(I)V", (void*)getBroadcastMetadataNative},
};

int register_com_android_bluetooth_le_audio(JNIEnv* env) {
+17 −3
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ package com.android.bluetooth.le_audio;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.util.Log;

import com.android.bluetooth.Utils;
@@ -125,6 +126,19 @@ public class LeAudioBroadcasterNativeInterface {
        sendMessageToService(event);
    }

    @VisibleForTesting
    public void onBroadcastMetadataChanged(int broadcastId, BluetoothLeBroadcastMetadata metadata) {
        if (DBG) {
            Log.d(TAG, "onBroadcastMetadataChanged: broadcastId=" + broadcastId);
        }
        LeAudioStackEvent event =
                new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_METADATA_CHANGED);

        event.valueInt1 = broadcastId;
        event.broadcastMetadata = metadata;
        sendMessageToService(event);
    }

    /**
     * Initializes the native interface.
     *
@@ -218,8 +232,8 @@ public class LeAudioBroadcasterNativeInterface {
     * Get all LeAudio Broadcast instance states.
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public void getAllBroadcastStates() {
        getAllBroadcastStatesNative();
    public void getBroadcastMetadata(int broadcastId) {
        getBroadcastMetadataNative(broadcastId);
    }

    // Native methods that call into the JNI interface
@@ -233,5 +247,5 @@ public class LeAudioBroadcasterNativeInterface {
    private native void stopBroadcastNative(int broadcastId);
    private native void pauseBroadcastNative(int broadcastId);
    private native void destroyBroadcastNative(int broadcastId);
    private native void getAllBroadcastStatesNative();
    private native void getBroadcastMetadataNative(int broadcastId);
}
+17 −4
Original line number Diff line number Diff line
@@ -175,7 +175,8 @@ public class LeAudioService extends ProfileService {

    private final Map<Integer, Integer> mBroadcastStateMap = new HashMap<>();
    private final Map<Integer, Boolean> mBroadcastsPlaybackMap = new HashMap<>();
    private final List<BluetoothLeBroadcastMetadata> mBroadcastMetadataList = new ArrayList<>();
    private final Map<Integer, BluetoothLeBroadcastMetadata> mBroadcastMetadataList =
            new HashMap<>();

    @Override
    protected IProfileServiceBinder initBinder() {
@@ -674,7 +675,7 @@ public class LeAudioService extends ProfileService {
     * @return list of all know Broadcast metadata
     */
    public List<BluetoothLeBroadcastMetadata> getAllBroadcastMetadata() {
        return mBroadcastMetadataList;
        return new ArrayList<BluetoothLeBroadcastMetadata>(mBroadcastMetadataList.values());
    }

    /**
@@ -1151,11 +1152,16 @@ public class LeAudioService extends ProfileService {

            mBroadcastsPlaybackMap.remove(broadcastId);
            mBroadcastStateMap.remove(broadcastId);
            mBroadcastMetadataList.removeIf(m -> broadcastId == m.getBroadcastId());
            mBroadcastMetadataList.remove(broadcastId);

        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_BROADCAST_STATE) {
            int broadcastId = stackEvent.valueInt1;
            int state = stackEvent.valueInt2;

            /* Request broadcast details if not known yet */
            if (!mBroadcastStateMap.containsKey(broadcastId)) {
                mLeAudioBroadcasterNativeInterface.getBroadcastMetadata(broadcastId);
            }
            mBroadcastStateMap.put(broadcastId, state);

            if (state == LeAudioStackEvent.BROADCAST_STATE_STOPPED) {
@@ -1216,8 +1222,15 @@ public class LeAudioService extends ProfileService {
                    }
                }
            }
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_BROADCAST_METADATA_CHANGED) {
            int broadcastId = stackEvent.valueInt1;
            if (stackEvent.broadcastMetadata == null) {
                Log.e(TAG, "Missing Broadcast metadata for broadcastId: " + broadcastId);
            } else {
                mBroadcastMetadataList.put(broadcastId, stackEvent.broadcastMetadata);
                notifyBroadcastMetadataChanged(broadcastId, stackEvent.broadcastMetadata);
            }
        }
        // TODO: Support Broadcast metadata updates

        if (intent != null) {
            sendBroadcast(intent, BLUETOOTH_CONNECT);
+18 −2

File changed.

Preview size limit exceeded, changes collapsed.

+114 −1

File changed.

Preview size limit exceeded, changes collapsed.

Loading