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

Commit d8aecc6d authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Add a mechanism for configuring the A2DP Source codecs"

parents d17ac215 a0810686
Loading
Loading
Loading
Loading
+57 −5
Original line number Diff line number Diff line
@@ -28,8 +28,9 @@
namespace android {
static jmethodID method_onConnectionStateChanged;
static jmethodID method_onAudioStateChanged;
static jmethodID method_onCodecConfigChanged;

static const btav_interface_t* sBluetoothA2dpInterface = NULL;
static const btav_source_interface_t* sBluetoothA2dpInterface = NULL;
static jobject mCallbacksObj = NULL;

static void bta2dp_connection_state_callback(btav_connection_state_t state,
@@ -70,9 +71,26 @@ static void bta2dp_audio_state_callback(btav_audio_state_t state,
  sCallbackEnv->DeleteLocalRef(addr);
}

static btav_callbacks_t sBluetoothA2dpCallbacks = {
static void bta2dp_audio_config_callback(
    btav_a2dp_codec_config_t codec_config,
    std::vector<btav_a2dp_codec_config_t> codec_capabilities) {
  ALOGI("%s", __func__);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  sCallbackEnv->CallVoidMethod(
      mCallbacksObj, method_onCodecConfigChanged, (jint)codec_config.codec_type,
      (jint)codec_config.codec_priority, (jint)codec_config.sample_rate,
      (jint)codec_config.bits_per_sample, (jint)codec_config.channel_mode,
      (jlong)codec_config.codec_specific_1,
      (jlong)codec_config.codec_specific_2,
      (jlong)codec_config.codec_specific_3,
      (jlong)codec_config.codec_specific_4);
}

static btav_source_callbacks_t sBluetoothA2dpCallbacks = {
    sizeof(sBluetoothA2dpCallbacks), bta2dp_connection_state_callback,
    bta2dp_audio_state_callback, NULL, /* audio_config_cb */
    bta2dp_audio_state_callback, bta2dp_audio_config_callback,
};

static void classInitNative(JNIEnv* env, jclass clazz) {
@@ -82,6 +100,9 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
  method_onAudioStateChanged =
      env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V");

  method_onCodecConfigChanged =
      env->GetMethodID(clazz, "onCodecConfigChanged", "(IIIIIJJJJ)V");

  ALOGI("%s: succeeds", __func__);
}

@@ -109,7 +130,8 @@ static void initNative(JNIEnv* env, jobject object) {
    return;
  }

  sBluetoothA2dpInterface = (btav_interface_t*)btInf->get_profile_interface(
  sBluetoothA2dpInterface =
      (btav_source_interface_t*)btInf->get_profile_interface(
          BT_PROFILE_ADVANCED_AUDIO_ID);
  if (sBluetoothA2dpInterface == NULL) {
    ALOGE("Failed to get Bluetooth A2DP Interface");
@@ -179,12 +201,42 @@ static jboolean disconnectA2dpNative(JNIEnv* env, jobject object,
  return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

static jboolean setCodecConfigPreferenceNative(
    JNIEnv* env, jobject object, jint codecType, jint codecPriority,
    jint sampleRate, jint bitsPerSample, jint channelMode, jlong codecSpecific1,
    jlong codecSpecific2, jlong codecSpecific3, jlong codecSpecific4) {
  if (!sBluetoothA2dpInterface) return JNI_FALSE;

  btav_a2dp_codec_config_t codec_config = {
      .codec_type = static_cast<btav_a2dp_codec_index_t>(codecType),
      .codec_priority = static_cast<btav_a2dp_codec_priority_t>(codecPriority),
      .sample_rate = static_cast<btav_a2dp_codec_sample_rate_t>(sampleRate),
      .bits_per_sample =
          static_cast<btav_a2dp_codec_bits_per_sample_t>(bitsPerSample),
      .channel_mode = static_cast<btav_a2dp_codec_channel_mode_t>(channelMode),
      .codec_specific_1 = codecSpecific1,
      .codec_specific_2 = codecSpecific2,
      .codec_specific_3 = codecSpecific3,
      .codec_specific_4 = codecSpecific4};

  std::vector<btav_a2dp_codec_config_t> codec_preferences;
  codec_preferences.push_back(codec_config);

  bt_status_t status = sBluetoothA2dpInterface->config_codec(codec_preferences);
  if (status != BT_STATUS_SUCCESS) {
    ALOGE("Failed codec configuration, status: %d", status);
  }
  return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

static JNINativeMethod sMethods[] = {
    {"classInitNative", "()V", (void*)classInitNative},
    {"initNative", "()V", (void*)initNative},
    {"cleanupNative", "()V", (void*)cleanupNative},
    {"connectA2dpNative", "([B)Z", (void*)connectA2dpNative},
    {"disconnectA2dpNative", "([B)Z", (void*)disconnectA2dpNative},
    {"setCodecConfigPreferenceNative", "(IIIIIJJJJ)Z",
     (void*)setCodecConfigPreferenceNative},
};

int register_com_android_bluetooth_a2dp(JNIEnv* env) {
+5 −4
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@ static jmethodID method_onConnectionStateChanged;
static jmethodID method_onAudioStateChanged;
static jmethodID method_onAudioConfigChanged;

static const btav_interface_t* sBluetoothA2dpInterface = NULL;
static const btav_sink_interface_t* sBluetoothA2dpInterface = NULL;
static jobject mCallbacksObj = NULL;

static void bta2dp_connection_state_callback(btav_connection_state_t state,
@@ -91,7 +91,7 @@ static void bta2dp_audio_config_callback(bt_bdaddr_t* bd_addr,
  sCallbackEnv->DeleteLocalRef(addr);
}

static btav_callbacks_t sBluetoothA2dpCallbacks = {
static btav_sink_callbacks_t sBluetoothA2dpCallbacks = {
    sizeof(sBluetoothA2dpCallbacks), bta2dp_connection_state_callback,
    bta2dp_audio_state_callback, bta2dp_audio_config_callback,
};
@@ -128,7 +128,8 @@ static void initNative(JNIEnv* env, jobject object) {
    mCallbacksObj = NULL;
  }

  sBluetoothA2dpInterface = (btav_interface_t*)btInf->get_profile_interface(
  sBluetoothA2dpInterface =
      (btav_sink_interface_t*)btInf->get_profile_interface(
          BT_PROFILE_ADVANCED_AUDIO_SINK_ID);
  if (sBluetoothA2dpInterface == NULL) {
    ALOGE("Failed to get Bluetooth A2DP Sink Interface");
+26 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.bluetooth.a2dp;

import android.bluetooth.BluetoothCodecConfig;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
@@ -28,6 +29,7 @@ import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.Utils;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * Provides Bluetooth A2DP profile, as a service in the Bluetooth application.
@@ -222,6 +224,18 @@ public class A2dpService extends ProfileService {
        return mStateMachine.isPlaying(device);
    }

    public BluetoothCodecConfig getCodecConfig() {
        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
        if (DBG) Log.d(TAG, "getCodecConfig()");
        return mStateMachine.getCodecConfig();
    }

    public void setCodecConfigPreference(BluetoothCodecConfig codecConfig) {
        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
        if (DBG) Log.d(TAG, "setCodecConfigPreference(): " + Objects.toString(codecConfig));
        mStateMachine.setCodecConfigPreference(codecConfig);
    }

    //Binder object: Must be static class or memory leak may occur 
    private static class BluetoothA2dpBinder extends IBluetoothA2dp.Stub 
        implements IProfileServiceBinder {
@@ -313,6 +327,18 @@ public class A2dpService extends ProfileService {
            if (service == null) return false;
            return service.isA2dpPlaying(device);
        }

        public BluetoothCodecConfig getCodecConfig() {
            A2dpService service = getService();
            if (service == null) return null;
            return service.getCodecConfig();
        }

        public void setCodecConfigPreference(BluetoothCodecConfig codecConfig) {
            A2dpService service = getService();
            if (service == null) return;
            service.setCodecConfigPreference(codecConfig);
        }
    };

    @Override
+52 −2
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ package com.android.bluetooth.a2dp;

import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothCodecConfig;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
@@ -102,6 +103,7 @@ final class A2dpStateMachine extends StateMachine {
    private BluetoothDevice mIncomingDevice = null;
    private BluetoothDevice mPlayingA2dpDevice = null;

    private BluetoothCodecConfig mCodecConfig = null;

    static {
        classInitNative();
@@ -664,6 +666,51 @@ final class A2dpStateMachine extends StateMachine {
        return false;
    }

    BluetoothCodecConfig getCodecConfig() {
        synchronized (this) {
            return mCodecConfig;
        }
    }

    private void onCodecConfigChanged(int codecType, int codecPriority, int sampleRate,
            int bitsPerSample, int channelMode, long codecSpecific1, long codecSpecific2,
            long codecSpecific3, long codecSpecific4) {
        BluetoothCodecConfig prevCodecConfig;
        BluetoothCodecConfig newCodecConfig = new BluetoothCodecConfig(codecType, codecPriority,
                sampleRate, bitsPerSample, channelMode, codecSpecific1, codecSpecific2,
                codecSpecific3, codecSpecific4);
        synchronized (this) {
            prevCodecConfig = mCodecConfig;
            mCodecConfig = newCodecConfig;
        }

        Intent intent = new Intent(BluetoothA2dp.ACTION_CODEC_CONFIG_CHANGED);
        intent.putExtra(BluetoothCodecConfig.EXTRA_CODEC_CONFIG, newCodecConfig);
        intent.putExtra(BluetoothCodecConfig.EXTRA_PREVIOUS_CODEC_CONFIG, prevCodecConfig);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);

        log("A2DP Codec Config : " + prevCodecConfig + "->" + newCodecConfig);

        // Inform the Audio Service about the codec configuration change,
        // so the Audio Service can reset accordingly the audio feeding
        // parameters in the Audio HAL to the Bluetooth stack.
        if (!newCodecConfig.sameAudioFeedingParameters(prevCodecConfig) && (mCurrentDevice != null)
                && (getCurrentState() == mConnected)) {
            // Add the device only if it is currently connected
            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mCurrentDevice);
            mAudioManager.handleBluetoothA2dpDeviceConfigChange(mCurrentDevice);
        }
        mContext.sendBroadcast(intent, A2dpService.BLUETOOTH_PERM);
    }

    void setCodecConfigPreference(BluetoothCodecConfig codecConfig) {
        setCodecConfigPreferenceNative(codecConfig.getCodecType(), codecConfig.getCodecPriority(),
                codecConfig.getSampleRate(), codecConfig.getBitsPerSample(),
                codecConfig.getChannelMode(), codecConfig.getCodecSpecific1(),
                codecConfig.getCodecSpecific2(), codecConfig.getCodecSpecific3(),
                codecConfig.getCodecSpecific4());
    }

    boolean okToConnect(BluetoothDevice device) {
        AdapterService adapterService = AdapterService.getAdapterService();
        int priority = mService.getPriority(device);
@@ -818,4 +865,7 @@ final class A2dpStateMachine extends StateMachine {
    private native void cleanupNative();
    private native boolean connectA2dpNative(byte[] address);
    private native boolean disconnectA2dpNative(byte[] address);
    private native boolean setCodecConfigPreferenceNative(int codecType, int codecPriority,
            int sampleRate, int bitsPerSample, int channelMode, long codecSpecific1,
            long codecSpecific2, long codecSpecific3, long codecSpecific4);
}
+2 −1
Original line number Diff line number Diff line
@@ -53,7 +53,8 @@ final public class AbstractionLayer {
    static final int BT_DEVICE_TYPE_DUAL = 0x03;

    static final int BT_BOND_STATE_NONE = 0x00;
    static final int BT_BOND_STATE_BONDED = 0x01;
    static final int BT_BOND_STATE_BONDING = 0x01;
    static final int BT_BOND_STATE_BONDED = 0x02;

    static final int BT_SSP_VARIANT_PASSKEY_CONFIRMATION = 0x00;
    static final int BT_SSP_VARIANT_PASSKEY_ENTRY = 0x01;