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

Commit 500b5985 authored by Patty's avatar Patty
Browse files

Parse audio config codec capability for LE devices

1. Update btif_le_audio.Initialize() to include the codec capability
   vector which obtain from audio config file
2. While init LE Audio Service, call Audio manager function to get
   codec capability
3. Update JNI interface to pass the codec information to BT stack

Tag: #feature
Bug: 203535499
Bug: 150670922
Test: atest BluetoothInstrumentationTests
Change-Id: Ic9b4ffb7fb001a2ea22284bc72ecb93ed65d3147
Merged-In: Ic9b4ffb7fb001a2ea22284bc72ecb93ed65d3147
parent f5028672
Loading
Loading
Loading
Loading
+62 −3
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@
#include "com_android_bluetooth.h"
#include "hardware/bt_le_audio.h"

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;
@@ -39,6 +41,12 @@ static jmethodID method_onGroupStatus;
static jmethodID method_onGroupNodeStatus;
static jmethodID method_onAudioConf;

static struct {
  jclass clazz;
  jmethodID constructor;
  jmethodID getCodecType;
} android_bluetooth_BluetoothLeAudioCodecConfig;

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

@@ -121,6 +129,13 @@ class LeAudioClientCallbacksImpl : public LeAudioClientCallbacks {
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>", "(I)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");
@@ -129,7 +144,34 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
      env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V");
}

static void initNative(JNIEnv* env, jobject object) {
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);

@@ -150,6 +192,15 @@ static void initNative(JNIEnv* env, jobject object) {
    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);
@@ -158,7 +209,11 @@ static void initNative(JNIEnv* env, jobject object) {
    return;
  }

  sLeAudioClientInterface->Initialize(&sLeAudioClientCallbacks);
  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) {
@@ -176,6 +231,9 @@ static void cleanupNative(JNIEnv* env, jobject object) {
    sLeAudioClientInterface = nullptr;
  }

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

  if (mCallbacksObj != nullptr) {
    env->DeleteGlobalRef(mCallbacksObj);
    mCallbacksObj = nullptr;
@@ -272,7 +330,8 @@ static void groupSetActiveNative(JNIEnv* env, jobject object, jint group_id) {

static JNINativeMethod sMethods[] = {
    {"classInitNative", "()V", (void*)classInitNative},
    {"initNative", "()V", (void*)initNative},
    {"initNative", "([Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V",
     (void*)initNative},
    {"cleanupNative", "()V", (void*)cleanupNative},
    {"connectLeAudioNative", "([B)Z", (void*)connectLeAudioNative},
    {"disconnectLeAudioNative", "([B)Z", (void*)disconnectLeAudioNative},
+2 −1
Original line number Diff line number Diff line
@@ -64,7 +64,8 @@ class A2dpCodecConfig {
          Log.w(TAG, "Can't obtain the codec offloading prefernece from null AudioManager");
          return;
        }
        mCodecConfigOffloading = audioManager.getHwOffloadEncodingFormatsSupportedForA2DP()
        mCodecConfigOffloading = audioManager.getHwOffloadFormatsSupportedForBluetoothMedia(
                                                    AudioManager.DEVICE_OUT_BLUETOOTH_A2DP)
                                             .toArray(mCodecConfigOffloading);
    }

+62 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * 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.
 */

package com.android.bluetooth.le_audio;

import android.bluetooth.BluetoothLeAudioCodecConfig;
import android.content.Context;
import android.media.AudioManager;
import android.util.Log;
/*
 * LeAudio Codec Configuration setup.
 */
class LeAudioCodecConfig {
    private static final boolean DBG = true;
    private static final String TAG = "LeAudioCodecConfig";

    private Context mContext;
    private BluetoothLeAudioCodecConfig[] mCodecConfigOffloading =
            new BluetoothLeAudioCodecConfig[0];

    LeAudioCodecConfig(Context context) {
        Log.i(TAG, "LeAudioCodecConfig init");
        mContext = context;

        AudioManager audioManager = mContext.getSystemService(AudioManager.class);
        if (audioManager == null) {
            Log.w(TAG, "Can't obtain the codec offloading prefernece from null AudioManager");
            return;
        }

        mCodecConfigOffloading = audioManager.getHwOffloadFormatsSupportedForBluetoothMedia(
                                                    AudioManager.DEVICE_OUT_BLE_HEADSET)
                                             .toArray(mCodecConfigOffloading);

        if (DBG) {
            Log.i(TAG, "mCodecConfigOffloading size for le -> " + mCodecConfigOffloading.length);

            for (int idx = 0; idx < mCodecConfigOffloading.length; idx++) {
                Log.i(TAG, String.format("mCodecConfigOffloading[%d] -> %s",
                        idx, mCodecConfigOffloading[idx].toString()));
            }
        }
    }

    BluetoothLeAudioCodecConfig[] codecConfigOffloading() {
        return mCodecConfigOffloading;
    }
}
+4 −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.BluetoothLeAudioCodecConfig;
import android.util.Log;

import com.android.bluetooth.Utils;
@@ -145,8 +146,8 @@ public class LeAudioNativeInterface {
     *
     * priorities to configure.
     */
    public void init() {
        initNative();
    public void init(BluetoothLeAudioCodecConfig[] codecConfigOffloading) {
        initNative(codecConfigOffloading);
    }

    /**
@@ -204,7 +205,7 @@ public class LeAudioNativeInterface {

    // Native methods that call into the JNI interface
    private static native void classInitNative();
    private native void initNative();
    private native void initNative(BluetoothLeAudioCodecConfig[] codecConfigOffloading);
    private native void cleanupNative();
    private native boolean connectLeAudioNative(byte[] address);
    private native boolean disconnectLeAudioNative(byte[] address);
+5 −1
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ public class LeAudioService extends ProfileService {
    private HandlerThread mStateMachinesThread;
    private BluetoothDevice mActiveAudioOutDevice;
    private BluetoothDevice mActiveAudioInDevice;
    private LeAudioCodecConfig mLeAudioCodecConfig;
    ServiceFactory mServiceFactory = new ServiceFactory();

    LeAudioNativeInterface mLeAudioNativeInterface;
@@ -215,7 +216,10 @@ public class LeAudioService extends ProfileService {
        // Mark service as started
        setLeAudioService(this);

        mLeAudioNativeInterface.init();
        // Setup codec config
        mLeAudioCodecConfig = new LeAudioCodecConfig(this);

        mLeAudioNativeInterface.init(mLeAudioCodecConfig.codecConfigOffloading());

        return true;
    }
Loading