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

Commit 3c979455 authored by Łukasz Rymanowski's avatar Łukasz Rymanowski Committed by Jack He
Browse files

BluetoothLeAudio: Fix API for codec preferences

This patch adjust codec preferences for the Le Audio usage.
API is using group id now and allows to choose configuration for output
and input.
Note: Input and Output shall use same codec type (for now) but different
codec parameters might be used.

Bug: 219875113
Test: atest BluetoothInstrumentationTests
Merged-In: Iee7a0c6d42dd029f9c24a27ec892eb7ef261263b
Change-Id: Iee7a0c6d42dd029f9c24a27ec892eb7ef261263b
parent cc894359
Loading
Loading
Loading
Loading
+20 −1
Original line number Diff line number Diff line
@@ -160,7 +160,7 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
  jclass jniBluetoothLeAudioCodecConfigClass =
      env->FindClass("android/bluetooth/BluetoothLeAudioCodecConfig");
  android_bluetooth_BluetoothLeAudioCodecConfig.constructor = env->GetMethodID(
      jniBluetoothLeAudioCodecConfigClass, "<init>", "(IIIIIII)V");
      jniBluetoothLeAudioCodecConfigClass, "<init>", "(IIIIIIIII)V");
  android_bluetooth_BluetoothLeAudioCodecConfig.getCodecType = env->GetMethodID(
      jniBluetoothLeAudioCodecConfigClass, "getCodecType", "()I");

@@ -357,6 +357,21 @@ static void groupSetActiveNative(JNIEnv* env, jobject object, jint group_id) {
  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",
@@ -367,6 +382,10 @@ static JNINativeMethod sMethods[] = {
    {"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 */
+15 −0
Original line number Diff line number Diff line
@@ -215,6 +215,18 @@ public class LeAudioNativeInterface {
        groupSetActiveNative(groupId);
    }

    /**
     * Set codec config preference.
     * @param groupId group ID for the preference
     * @param inputCodecConfig input codec configuration
     * @param outputCodecConfig output codec configuration
     */
    public void setCodecConfigPreference(int groupId,
            BluetoothLeAudioCodecConfig inputCodecConfig,
            BluetoothLeAudioCodecConfig outputCodecConfig) {
        setCodecConfigPreferenceNative(groupId, inputCodecConfig, outputCodecConfig);
    }

    // Native methods that call into the JNI interface
    private static native void classInitNative();
    private native void initNative(BluetoothLeAudioCodecConfig[] codecConfigOffloading);
@@ -224,4 +236,7 @@ public class LeAudioNativeInterface {
    private native boolean groupAddNodeNative(int groupId, byte[] address);
    private native boolean groupRemoveNodeNative(int groupId, byte[] address);
    private native void groupSetActiveNative(int groupId);
    private native void setCodecConfigPreferenceNative(int groupId,
            BluetoothLeAudioCodecConfig inputCodecConfig,
            BluetoothLeAudioCodecConfig outputCodecConfig);
}
+43 −21
Original line number Diff line number Diff line
@@ -132,11 +132,13 @@ public class LeAudioService extends ProfileService {
            mIsConnected = false;
            mIsActive = false;
            mActiveContexts = ACTIVE_CONTEXTS_NONE;
            mCodecStatus = null;
        }

        public Boolean mIsConnected;
        public Boolean mIsActive;
        public Integer mActiveContexts;
        public BluetoothLeAudioCodecStatus mCodecStatus;
    }

    private final Map<Integer, LeAudioGroupDescriptor> mGroupDescriptors = new LinkedHashMap<>();
@@ -1726,46 +1728,64 @@ public class LeAudioService extends ProfileService {
    /**
     * Gets the current codec status (configuration and capability).
     *
     * @param device the remote Bluetooth device.
     * @param groupId the group id
     * @return the current codec status
     * @hide
     */
    public BluetoothLeAudioCodecStatus getCodecStatus(BluetoothDevice device) {
    public BluetoothLeAudioCodecStatus getCodecStatus(int groupId) {
        if (DBG) {
            Log.d(TAG, "getCodecStatus(" + device + ")");
            Log.d(TAG, "getCodecStatus(" + groupId + ")");
        }
        LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(groupId);
        if (descriptor != null) {
            return descriptor.mCodecStatus;
        }

        return null;
    }

    /**
     * Sets the codec configuration preference.
     *
     * @param device the remote Bluetooth device.
     * @param codecConfig the codec configuration preference
     * @param groupId the group id
     * @param inputCodecConfig the input codec configuration preference
     * @param outputCodecConfig the output codec configuration preference
     * @hide
     */
    public void setCodecConfigPreference(BluetoothDevice device,
                                         BluetoothLeAudioCodecConfig codecConfig) {
    public void setCodecConfigPreference(int groupId,
                                         BluetoothLeAudioCodecConfig inputCodecConfig,
                                         BluetoothLeAudioCodecConfig outputCodecConfig) {
        if (DBG) {
            Log.d(TAG, "setCodecConfigPreference(" + device + "): "
                    + Objects.toString(codecConfig));
            Log.d(TAG, "setCodecConfigPreference(" + groupId + "): "
                    + Objects.toString(inputCodecConfig)
                    + Objects.toString(outputCodecConfig));
        }
        if (device == null) {
            Log.e(TAG, "setCodecConfigPreference: Invalid device");
        LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(groupId);
        if (descriptor == null) {
            Log.e(TAG, "setCodecConfigPreference: Invalid groupId, " + groupId);
            return;
        }
        if (codecConfig == null) {

        if (inputCodecConfig == null || outputCodecConfig == null) {
            Log.e(TAG, "setCodecConfigPreference: Codec config can't be null");
            return;
        }
        BluetoothLeAudioCodecStatus codecStatus = getCodecStatus(device);
        if (codecStatus == null) {

        /* We support different configuration for input and output but codec type
         * shall be same */
        if (inputCodecConfig.getCodecType() != outputCodecConfig.getCodecType()) {
            Log.e(TAG, "setCodecConfigPreference: Input codec type: "
                    + inputCodecConfig.getCodecType()
                    + "does not match output codec type: " + outputCodecConfig.getCodecType());
            return;
        }

        if (descriptor.mCodecStatus == null) {
            Log.e(TAG, "setCodecConfigPreference: Codec status is null");
            return;
        }

        // TODO: pass the information to bt stack
        mLeAudioNativeInterface.setCodecConfigPreference(groupId,
                                inputCodecConfig, outputCodecConfig);
    }


@@ -2185,14 +2205,14 @@ public class LeAudioService extends ProfileService {
        }

        @Override
        public void getCodecStatus(BluetoothDevice device,
        public void getCodecStatus(int groupId,
                AttributionSource source, SynchronousResultReceiver receiver) {
            try {
                LeAudioService service = getService(source);
                BluetoothLeAudioCodecStatus codecStatus = null;
                if (service != null) {
                    enforceBluetoothPrivilegedPermission(service);
                    codecStatus = service.getCodecStatus(device);
                    codecStatus = service.getCodecStatus(groupId);
                }
                receiver.send(codecStatus);
            } catch (RuntimeException e) {
@@ -2201,15 +2221,17 @@ public class LeAudioService extends ProfileService {
        }

        @Override
        public void setCodecConfigPreference(BluetoothDevice device,
                BluetoothLeAudioCodecConfig codecConfig, AttributionSource source) {
        public void setCodecConfigPreference(int groupId,
                BluetoothLeAudioCodecConfig inputCodecConfig,
                BluetoothLeAudioCodecConfig outputCodecConfig,
                AttributionSource source) {
            LeAudioService service = getService(source);
            if (service == null) {
                return;
            }

            enforceBluetoothPrivilegedPermission(service);
            service.setCodecConfigPreference(device, codecConfig);
            service.setCodecConfigPreference(groupId, inputCodecConfig, outputCodecConfig);
        }
    }

+24 −16
Original line number Diff line number Diff line
@@ -925,21 +925,23 @@ package android.bluetooth {
  public final class BluetoothLeAudioCodecConfig implements android.os.Parcelable {
    method public int describeContents();
    method public int getBitsPerSample();
    method public int getChannelMode();
    method public int getChannelCount();
    method @NonNull public String getCodecName();
    method public int getCodecPriority();
    method public int getCodecType();
    method public int getFrameDuration();
    method public int getMaxOctetsPerFrame();
    method public int getMinOctetsPerFrame();
    method public int getOctetsPerFrame();
    method public int getSampleRate();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field public static final int BITS_PER_SAMPLE_16 = 1; // 0x1
    field public static final int BITS_PER_SAMPLE_24 = 2; // 0x2
    field public static final int BITS_PER_SAMPLE_32 = 3; // 0x3
    field public static final int BITS_PER_SAMPLE_32 = 8; // 0x8
    field public static final int BITS_PER_SAMPLE_NONE = 0; // 0x0
    field public static final int CHANNEL_MODE_MONO = 1; // 0x1
    field public static final int CHANNEL_MODE_NONE = 0; // 0x0
    field public static final int CHANNEL_MODE_STEREO = 2; // 0x2
    field public static final int CHANNEL_COUNT_1 = 1; // 0x1
    field public static final int CHANNEL_COUNT_2 = 2; // 0x2
    field public static final int CHANNEL_COUNT_NONE = 0; // 0x0
    field public static final int CODEC_PRIORITY_DEFAULT = 0; // 0x0
    field public static final int CODEC_PRIORITY_DISABLED = -1; // 0xffffffff
    field public static final int CODEC_PRIORITY_HIGHEST = 1000000; // 0xf4240
@@ -947,11 +949,11 @@ package android.bluetooth {
    field public static final int FRAME_DURATION_10000 = 2; // 0x2
    field public static final int FRAME_DURATION_7500 = 1; // 0x1
    field public static final int FRAME_DURATION_NONE = 0; // 0x0
    field public static final int SAMPLE_RATE_16000 = 2; // 0x2
    field public static final int SAMPLE_RATE_24000 = 3; // 0x3
    field public static final int SAMPLE_RATE_32000 = 4; // 0x4
    field public static final int SAMPLE_RATE_44100 = 5; // 0x5
    field public static final int SAMPLE_RATE_48000 = 6; // 0x6
    field public static final int SAMPLE_RATE_16000 = 4; // 0x4
    field public static final int SAMPLE_RATE_24000 = 16; // 0x10
    field public static final int SAMPLE_RATE_32000 = 32; // 0x20
    field public static final int SAMPLE_RATE_44100 = 64; // 0x40
    field public static final int SAMPLE_RATE_48000 = 128; // 0x80
    field public static final int SAMPLE_RATE_8000 = 1; // 0x1
    field public static final int SAMPLE_RATE_NONE = 0; // 0x0
    field public static final int SOURCE_CODEC_TYPE_INVALID = 1000000; // 0xf4240
@@ -963,21 +965,27 @@ package android.bluetooth {
    ctor public BluetoothLeAudioCodecConfig.Builder(@NonNull android.bluetooth.BluetoothLeAudioCodecConfig);
    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig build();
    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setBitsPerSample(int);
    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setChannelMode(int);
    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setChannelCount(int);
    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setCodecPriority(int);
    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setCodecType(int);
    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setFrameDuration(int);
    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setMaxOctetsPerFrame(int);
    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setMinOctetsPerFrame(int);
    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setOctetsPerFrame(int);
    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setSampleRate(int);
  }

  public final class BluetoothLeAudioCodecStatus implements android.os.Parcelable {
    ctor public BluetoothLeAudioCodecStatus(@Nullable android.bluetooth.BluetoothLeAudioCodecConfig, @NonNull java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig>, @NonNull java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig>);
    ctor public BluetoothLeAudioCodecStatus(@Nullable android.bluetooth.BluetoothLeAudioCodecConfig, @Nullable android.bluetooth.BluetoothLeAudioCodecConfig, @NonNull java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig>, @NonNull java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig>, @NonNull java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig>, @NonNull java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig>);
    method public int describeContents();
    method @Nullable public android.bluetooth.BluetoothLeAudioCodecConfig getCodecConfig();
    method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig> getCodecLocalCapabilities();
    method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig> getCodecSelectableCapabilities();
    method public boolean isCodecConfigSelectable(@Nullable android.bluetooth.BluetoothLeAudioCodecConfig);
    method @Nullable public android.bluetooth.BluetoothLeAudioCodecConfig getInputCodecConfig();
    method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig> getInputCodecLocalCapabilities();
    method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig> getInputCodecSelectableCapabilities();
    method @Nullable public android.bluetooth.BluetoothLeAudioCodecConfig getOutputCodecConfig();
    method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig> getOutputCodecLocalCapabilities();
    method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig> getOutputCodecSelectableCapabilities();
    method public boolean isInputCodecConfigSelectable(@Nullable android.bluetooth.BluetoothLeAudioCodecConfig);
    method public boolean isOutputCodecConfigSelectable(@Nullable android.bluetooth.BluetoothLeAudioCodecConfig);
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothLeAudioCodecStatus> CREATOR;
    field public static final String EXTRA_LE_AUDIO_CODEC_STATUS = "android.bluetooth.extra.LE_AUDIO_CODEC_STATUS";
+2 −2
Original line number Diff line number Diff line
@@ -330,10 +330,10 @@ package android.bluetooth {

  public final class BluetoothLeAudio implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getAudioLocation(@NonNull android.bluetooth.BluetoothDevice);
    method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public android.bluetooth.BluetoothLeAudioCodecStatus getCodecStatus(@NonNull android.bluetooth.BluetoothDevice);
    method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public android.bluetooth.BluetoothLeAudioCodecStatus getCodecStatus(int);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothLeAudio.Callback);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void setCodecConfigPreference(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothLeAudioCodecConfig);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void setCodecConfigPreference(int, @NonNull android.bluetooth.BluetoothLeAudioCodecConfig, @NonNull android.bluetooth.BluetoothLeAudioCodecConfig);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void setVolume(int);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void unregisterCallback(@NonNull android.bluetooth.BluetoothLeAudio.Callback);
Loading