Loading android/app/jni/com_android_bluetooth_a2dp.cpp +71 −18 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ static std::shared_timed_mutex interface_mutex; static jobject mCallbacksObj = nullptr; static std::shared_timed_mutex callbacks_mutex; static void bta2dp_connection_state_callback(RawAddress* bd_addr, static void bta2dp_connection_state_callback(const RawAddress& bd_addr, btav_connection_state_t state) { ALOGI("%s", __func__); Loading @@ -66,13 +66,14 @@ static void bta2dp_connection_state_callback(RawAddress* bd_addr, return; } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)bd_addr); sCallbackEnv->SetByteArrayRegion( addr.get(), 0, sizeof(RawAddress), reinterpret_cast<const jbyte*>(bd_addr.address)); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, addr.get(), (jint)state); } static void bta2dp_audio_state_callback(RawAddress* bd_addr, static void bta2dp_audio_state_callback(const RawAddress& bd_addr, btav_audio_state_t state) { ALOGI("%s", __func__); Loading @@ -87,14 +88,15 @@ static void bta2dp_audio_state_callback(RawAddress* bd_addr, return; } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)bd_addr); sCallbackEnv->SetByteArrayRegion( addr.get(), 0, sizeof(RawAddress), reinterpret_cast<const jbyte*>(bd_addr.address)); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged, addr.get(), (jint)state); } static void bta2dp_audio_config_callback( RawAddress* bd_addr, btav_a2dp_codec_config_t codec_config, const RawAddress& bd_addr, btav_a2dp_codec_config_t codec_config, std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities, std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities) { ALOGI("%s", __func__); Loading Loading @@ -152,8 +154,9 @@ static void bta2dp_audio_config_callback( ALOGE("%s: Fail to new jbyteArray bd addr", __func__); return; } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, RawAddress::kLength, (jbyte*)bd_addr->address); sCallbackEnv->SetByteArrayRegion( addr.get(), 0, RawAddress::kLength, reinterpret_cast<const jbyte*>(bd_addr.address)); sCallbackEnv->CallVoidMethod( mCallbacksObj, method_onCodecConfigChanged, addr.get(), codecConfigObj, Loading Loading @@ -340,7 +343,10 @@ static jboolean connectA2dpNative(JNIEnv* env, jobject object, jbyteArray address) { ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface); std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); if (!sBluetoothA2dpInterface) return JNI_FALSE; if (!sBluetoothA2dpInterface) { ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__); return JNI_FALSE; } jbyte* addr = env->GetByteArrayElements(address, nullptr); if (!addr) { Loading @@ -348,9 +354,11 @@ static jboolean connectA2dpNative(JNIEnv* env, jobject object, return JNI_FALSE; } bt_status_t status = sBluetoothA2dpInterface->connect((RawAddress*)addr); RawAddress bd_addr; bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr)); bt_status_t status = sBluetoothA2dpInterface->connect(bd_addr); if (status != BT_STATUS_SUCCESS) { ALOGE("%s: Failed HF connection, status: %d", __func__, status); ALOGE("%s: Failed A2DP connection, status: %d", __func__, status); } env->ReleaseByteArrayElements(address, addr, 0); return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; Loading @@ -360,7 +368,35 @@ static jboolean disconnectA2dpNative(JNIEnv* env, jobject object, jbyteArray address) { ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface); std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); if (!sBluetoothA2dpInterface) return JNI_FALSE; if (!sBluetoothA2dpInterface) { ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__); return JNI_FALSE; } jbyte* addr = env->GetByteArrayElements(address, nullptr); if (!addr) { jniThrowIOException(env, EINVAL); return JNI_FALSE; } RawAddress bd_addr; bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr)); bt_status_t status = sBluetoothA2dpInterface->disconnect(bd_addr); if (status != BT_STATUS_SUCCESS) { ALOGE("%s: Failed A2DP disconnection, status: %d", __func__, status); } env->ReleaseByteArrayElements(address, addr, 0); return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } static jboolean setActiveDeviceNative(JNIEnv* env, jobject object, jbyteArray address) { ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface); std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); if (!sBluetoothA2dpInterface) { ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__); return JNI_FALSE; } jbyte* addr = env->GetByteArrayElements(address, nullptr); if (!addr) { Loading @@ -368,27 +404,43 @@ static jboolean disconnectA2dpNative(JNIEnv* env, jobject object, return JNI_FALSE; } bt_status_t status = sBluetoothA2dpInterface->disconnect((RawAddress*)addr); RawAddress bd_addr; bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr)); bt_status_t status = sBluetoothA2dpInterface->set_active_device(bd_addr); if (status != BT_STATUS_SUCCESS) { ALOGE("%s: Failed HF disconnection, status: %d", __func__, status); ALOGE("%s: Failed A2DP set_active_device, status: %d", __func__, status); } env->ReleaseByteArrayElements(address, addr, 0); return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } static jboolean setCodecConfigPreferenceNative(JNIEnv* env, jobject object, jbyteArray address, jobjectArray codecConfigArray) { ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface); std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); if (!sBluetoothA2dpInterface) return JNI_FALSE; if (!sBluetoothA2dpInterface) { ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__); return JNI_FALSE; } jbyte* addr = env->GetByteArrayElements(address, nullptr); if (!addr) { jniThrowIOException(env, EINVAL); return JNI_FALSE; } RawAddress bd_addr; bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr)); std::vector<btav_a2dp_codec_config_t> codec_preferences = prepareCodecPreferences(env, object, codecConfigArray); bt_status_t status = sBluetoothA2dpInterface->config_codec(codec_preferences); bt_status_t status = sBluetoothA2dpInterface->config_codec(bd_addr, codec_preferences); if (status != BT_STATUS_SUCCESS) { ALOGE("%s: Failed codec configuration, status: %d", __func__, status); } env->ReleaseByteArrayElements(address, addr, 0); return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } Loading @@ -399,8 +451,9 @@ static JNINativeMethod sMethods[] = { {"cleanupNative", "()V", (void*)cleanupNative}, {"connectA2dpNative", "([B)Z", (void*)connectA2dpNative}, {"disconnectA2dpNative", "([B)Z", (void*)disconnectA2dpNative}, {"setActiveDeviceNative", "([B)Z", (void*)setActiveDeviceNative}, {"setCodecConfigPreferenceNative", "([Landroid/bluetooth/BluetoothCodecConfig;)Z", "([B[Landroid/bluetooth/BluetoothCodecConfig;)Z", (void*)setCodecConfigPreferenceNative}, }; Loading android/app/jni/com_android_bluetooth_a2dp_sink.cpp +12 −8 Original line number Diff line number Diff line Loading @@ -33,7 +33,7 @@ static jmethodID method_onAudioConfigChanged; static const btav_sink_interface_t* sBluetoothA2dpInterface = NULL; static jobject mCallbacksObj = NULL; static void bta2dp_connection_state_callback(RawAddress* bd_addr, static void bta2dp_connection_state_callback(const RawAddress& bd_addr, btav_connection_state_t state) { ALOGI("%s", __func__); CallbackEnv sCallbackEnv(__func__); Loading @@ -47,12 +47,12 @@ static void bta2dp_connection_state_callback(RawAddress* bd_addr, } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)bd_addr); (const jbyte*)bd_addr.address); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, addr.get(), (jint)state); } static void bta2dp_audio_state_callback(RawAddress* bd_addr, static void bta2dp_audio_state_callback(const RawAddress& bd_addr, btav_audio_state_t state) { ALOGI("%s", __func__); CallbackEnv sCallbackEnv(__func__); Loading @@ -66,12 +66,12 @@ static void bta2dp_audio_state_callback(RawAddress* bd_addr, } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)bd_addr); (const jbyte*)bd_addr.address); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged, addr.get(), (jint)state); } static void bta2dp_audio_config_callback(RawAddress* bd_addr, static void bta2dp_audio_config_callback(const RawAddress& bd_addr, uint32_t sample_rate, uint8_t channel_count) { ALOGI("%s", __func__); Loading @@ -86,7 +86,7 @@ static void bta2dp_audio_config_callback(RawAddress* bd_addr, } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)bd_addr); (const jbyte*)bd_addr.address); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioConfigChanged, addr.get(), (jint)sample_rate, (jint)channel_count); Loading Loading @@ -177,7 +177,9 @@ static jboolean connectA2dpNative(JNIEnv* env, jobject object, return JNI_FALSE; } bt_status_t status = sBluetoothA2dpInterface->connect((RawAddress*)addr); RawAddress bd_addr; bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr)); bt_status_t status = sBluetoothA2dpInterface->connect(bd_addr); if (status != BT_STATUS_SUCCESS) { ALOGE("Failed HF connection, status: %d", status); } Loading @@ -195,7 +197,9 @@ static jboolean disconnectA2dpNative(JNIEnv* env, jobject object, return JNI_FALSE; } bt_status_t status = sBluetoothA2dpInterface->disconnect((RawAddress*)addr); RawAddress bd_addr; bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr)); bt_status_t status = sBluetoothA2dpInterface->disconnect(bd_addr); if (status != BT_STATUS_SUCCESS) { ALOGE("Failed HF disconnection, status: %d", status); } Loading android/app/src/com/android/bluetooth/a2dp/A2dpCodecConfig.java 0 → 100644 +190 −0 Original line number Diff line number Diff line /* * Copyright 2018 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.a2dp; import android.bluetooth.BluetoothCodecConfig; import android.bluetooth.BluetoothDevice; import android.content.Context; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; import com.android.bluetooth.R; /* * A2DP Codec Configuration setup. */ class A2dpCodecConfig { private static final boolean DBG = true; private static final String TAG = "A2dpCodecConfig"; private Context mContext; private A2dpNativeInterface mA2dpNativeInterface; private BluetoothCodecConfig[] mCodecConfigPriorities; private int mA2dpSourceCodecPrioritySbc = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; private int mA2dpSourceCodecPriorityAac = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; private int mA2dpSourceCodecPriorityAptx = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; private int mA2dpSourceCodecPriorityAptxHd = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; private int mA2dpSourceCodecPriorityLdac = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; A2dpCodecConfig(Context context, A2dpNativeInterface a2dpNativeInterface) { mContext = context; mA2dpNativeInterface = a2dpNativeInterface; mCodecConfigPriorities = assignCodecConfigPriorities(); } BluetoothCodecConfig[] codecConfigPriorities() { return mCodecConfigPriorities; } void setCodecConfigPreference(BluetoothDevice device, BluetoothCodecConfig codecConfig) { BluetoothCodecConfig[] codecConfigArray = new BluetoothCodecConfig[1]; codecConfigArray[0] = codecConfig; mA2dpNativeInterface.setCodecConfigPreference(device, codecConfigArray); } void enableOptionalCodecs(BluetoothDevice device) { BluetoothCodecConfig[] codecConfigArray = assignCodecConfigPriorities(); if (codecConfigArray == null) { return; } // Set the mandatory codec's priority to default, and remove the rest for (int i = 0; i < codecConfigArray.length; i++) { BluetoothCodecConfig codecConfig = codecConfigArray[i]; if (!codecConfig.isMandatoryCodec()) { codecConfigArray[i] = null; } } mA2dpNativeInterface.setCodecConfigPreference(device, codecConfigArray); } void disableOptionalCodecs(BluetoothDevice device) { BluetoothCodecConfig[] codecConfigArray = assignCodecConfigPriorities(); if (codecConfigArray == null) { return; } // Set the mandatory codec's priority to highest, and remove the rest for (int i = 0; i < codecConfigArray.length; i++) { BluetoothCodecConfig codecConfig = codecConfigArray[i]; if (codecConfig.isMandatoryCodec()) { codecConfig.setCodecPriority(BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST); } else { codecConfigArray[i] = null; } } mA2dpNativeInterface.setCodecConfigPreference(device, codecConfigArray); } // Assign the A2DP Source codec config priorities private BluetoothCodecConfig[] assignCodecConfigPriorities() { Resources resources = mContext.getResources(); if (resources == null) { return null; } int value; try { value = resources.getInteger(R.integer.a2dp_source_codec_priority_sbc); } catch (NotFoundException e) { value = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; } if ((value >= BluetoothCodecConfig.CODEC_PRIORITY_DISABLED) && (value < BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST)) { mA2dpSourceCodecPrioritySbc = value; } try { value = resources.getInteger(R.integer.a2dp_source_codec_priority_aac); } catch (NotFoundException e) { value = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; } if ((value >= BluetoothCodecConfig.CODEC_PRIORITY_DISABLED) && (value < BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST)) { mA2dpSourceCodecPriorityAac = value; } try { value = resources.getInteger(R.integer.a2dp_source_codec_priority_aptx); } catch (NotFoundException e) { value = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; } if ((value >= BluetoothCodecConfig.CODEC_PRIORITY_DISABLED) && (value < BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST)) { mA2dpSourceCodecPriorityAptx = value; } try { value = resources.getInteger(R.integer.a2dp_source_codec_priority_aptx_hd); } catch (NotFoundException e) { value = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; } if ((value >= BluetoothCodecConfig.CODEC_PRIORITY_DISABLED) && (value < BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST)) { mA2dpSourceCodecPriorityAptxHd = value; } try { value = resources.getInteger(R.integer.a2dp_source_codec_priority_ldac); } catch (NotFoundException e) { value = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; } if ((value >= BluetoothCodecConfig.CODEC_PRIORITY_DISABLED) && (value < BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST)) { mA2dpSourceCodecPriorityLdac = value; } BluetoothCodecConfig codecConfig; BluetoothCodecConfig[] codecConfigArray = new BluetoothCodecConfig[BluetoothCodecConfig.SOURCE_CODEC_TYPE_MAX]; codecConfig = new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, mA2dpSourceCodecPrioritySbc, BluetoothCodecConfig.SAMPLE_RATE_NONE, BluetoothCodecConfig.BITS_PER_SAMPLE_NONE, BluetoothCodecConfig .CHANNEL_MODE_NONE, 0 /* codecSpecific1 */, 0 /* codecSpecific2 */, 0 /* codecSpecific3 */, 0 /* codecSpecific4 */); codecConfigArray[0] = codecConfig; codecConfig = new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, mA2dpSourceCodecPriorityAac, BluetoothCodecConfig.SAMPLE_RATE_NONE, BluetoothCodecConfig.BITS_PER_SAMPLE_NONE, BluetoothCodecConfig .CHANNEL_MODE_NONE, 0 /* codecSpecific1 */, 0 /* codecSpecific2 */, 0 /* codecSpecific3 */, 0 /* codecSpecific4 */); codecConfigArray[1] = codecConfig; codecConfig = new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, mA2dpSourceCodecPriorityAptx, BluetoothCodecConfig.SAMPLE_RATE_NONE, BluetoothCodecConfig.BITS_PER_SAMPLE_NONE, BluetoothCodecConfig .CHANNEL_MODE_NONE, 0 /* codecSpecific1 */, 0 /* codecSpecific2 */, 0 /* codecSpecific3 */, 0 /* codecSpecific4 */); codecConfigArray[2] = codecConfig; codecConfig = new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, mA2dpSourceCodecPriorityAptxHd, BluetoothCodecConfig.SAMPLE_RATE_NONE, BluetoothCodecConfig.BITS_PER_SAMPLE_NONE, BluetoothCodecConfig .CHANNEL_MODE_NONE, 0 /* codecSpecific1 */, 0 /* codecSpecific2 */, 0 /* codecSpecific3 */, 0 /* codecSpecific4 */); codecConfigArray[3] = codecConfig; codecConfig = new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, mA2dpSourceCodecPriorityLdac, BluetoothCodecConfig.SAMPLE_RATE_NONE, BluetoothCodecConfig.BITS_PER_SAMPLE_NONE, BluetoothCodecConfig .CHANNEL_MODE_NONE, 0 /* codecSpecific1 */, 0 /* codecSpecific2 */, 0 /* codecSpecific3 */, 0 /* codecSpecific4 */); codecConfigArray[4] = codecConfig; return codecConfigArray; } } android/app/src/com/android/bluetooth/a2dp/A2dpNativeInterface.java +19 −9 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ public class A2dpNativeInterface { private A2dpNativeInterface() { mAdapter = BluetoothAdapter.getDefaultAdapter(); if (mAdapter == null) { Log.wtf(TAG, "No Bluetooth Adapter Available"); Log.wtfStack(TAG, "No Bluetooth Adapter Available"); } } Loading Loading @@ -104,15 +104,28 @@ public class A2dpNativeInterface { return disconnectA2dpNative(getByteAddress(device)); } /** * Sets a connected A2DP remote device as active. * * @param device the remote device * @return true on success, otherwise false. */ public boolean setActiveDevice(BluetoothDevice device) { return setActiveDeviceNative(getByteAddress(device)); } /** * Sets the codec configuration preferences. * * @param device the remote Bluetooth device * @param codecConfigArray an array with the codec configurations to * configure. * @return true on success, otherwise false. */ public boolean setCodecConfigPreference(BluetoothCodecConfig[] codecConfigArray) { return setCodecConfigPreferenceNative(codecConfigArray); public boolean setCodecConfigPreference(BluetoothDevice device, BluetoothCodecConfig[] codecConfigArray) { return setCodecConfigPreferenceNative(getByteAddress(device), codecConfigArray); } private BluetoothDevice getDevice(byte[] address) { Loading Loading @@ -176,14 +189,11 @@ public class A2dpNativeInterface { // Native methods that call into the JNI interface private static native void classInitNative(); private native void initNative(BluetoothCodecConfig[] codecConfigPriorities); private native void cleanupNative(); private native boolean connectA2dpNative(byte[] address); private native boolean disconnectA2dpNative(byte[] address); private native boolean setCodecConfigPreferenceNative(BluetoothCodecConfig[] codecConfigArray); private native boolean setActiveDeviceNative(byte[] address); private native boolean setCodecConfigPreferenceNative(byte[] address, BluetoothCodecConfig[] codecConfigArray); } android/app/src/com/android/bluetooth/a2dp/A2dpService.java +497 −122 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
android/app/jni/com_android_bluetooth_a2dp.cpp +71 −18 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ static std::shared_timed_mutex interface_mutex; static jobject mCallbacksObj = nullptr; static std::shared_timed_mutex callbacks_mutex; static void bta2dp_connection_state_callback(RawAddress* bd_addr, static void bta2dp_connection_state_callback(const RawAddress& bd_addr, btav_connection_state_t state) { ALOGI("%s", __func__); Loading @@ -66,13 +66,14 @@ static void bta2dp_connection_state_callback(RawAddress* bd_addr, return; } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)bd_addr); sCallbackEnv->SetByteArrayRegion( addr.get(), 0, sizeof(RawAddress), reinterpret_cast<const jbyte*>(bd_addr.address)); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, addr.get(), (jint)state); } static void bta2dp_audio_state_callback(RawAddress* bd_addr, static void bta2dp_audio_state_callback(const RawAddress& bd_addr, btav_audio_state_t state) { ALOGI("%s", __func__); Loading @@ -87,14 +88,15 @@ static void bta2dp_audio_state_callback(RawAddress* bd_addr, return; } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)bd_addr); sCallbackEnv->SetByteArrayRegion( addr.get(), 0, sizeof(RawAddress), reinterpret_cast<const jbyte*>(bd_addr.address)); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged, addr.get(), (jint)state); } static void bta2dp_audio_config_callback( RawAddress* bd_addr, btav_a2dp_codec_config_t codec_config, const RawAddress& bd_addr, btav_a2dp_codec_config_t codec_config, std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities, std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities) { ALOGI("%s", __func__); Loading Loading @@ -152,8 +154,9 @@ static void bta2dp_audio_config_callback( ALOGE("%s: Fail to new jbyteArray bd addr", __func__); return; } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, RawAddress::kLength, (jbyte*)bd_addr->address); sCallbackEnv->SetByteArrayRegion( addr.get(), 0, RawAddress::kLength, reinterpret_cast<const jbyte*>(bd_addr.address)); sCallbackEnv->CallVoidMethod( mCallbacksObj, method_onCodecConfigChanged, addr.get(), codecConfigObj, Loading Loading @@ -340,7 +343,10 @@ static jboolean connectA2dpNative(JNIEnv* env, jobject object, jbyteArray address) { ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface); std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); if (!sBluetoothA2dpInterface) return JNI_FALSE; if (!sBluetoothA2dpInterface) { ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__); return JNI_FALSE; } jbyte* addr = env->GetByteArrayElements(address, nullptr); if (!addr) { Loading @@ -348,9 +354,11 @@ static jboolean connectA2dpNative(JNIEnv* env, jobject object, return JNI_FALSE; } bt_status_t status = sBluetoothA2dpInterface->connect((RawAddress*)addr); RawAddress bd_addr; bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr)); bt_status_t status = sBluetoothA2dpInterface->connect(bd_addr); if (status != BT_STATUS_SUCCESS) { ALOGE("%s: Failed HF connection, status: %d", __func__, status); ALOGE("%s: Failed A2DP connection, status: %d", __func__, status); } env->ReleaseByteArrayElements(address, addr, 0); return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; Loading @@ -360,7 +368,35 @@ static jboolean disconnectA2dpNative(JNIEnv* env, jobject object, jbyteArray address) { ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface); std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); if (!sBluetoothA2dpInterface) return JNI_FALSE; if (!sBluetoothA2dpInterface) { ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__); return JNI_FALSE; } jbyte* addr = env->GetByteArrayElements(address, nullptr); if (!addr) { jniThrowIOException(env, EINVAL); return JNI_FALSE; } RawAddress bd_addr; bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr)); bt_status_t status = sBluetoothA2dpInterface->disconnect(bd_addr); if (status != BT_STATUS_SUCCESS) { ALOGE("%s: Failed A2DP disconnection, status: %d", __func__, status); } env->ReleaseByteArrayElements(address, addr, 0); return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } static jboolean setActiveDeviceNative(JNIEnv* env, jobject object, jbyteArray address) { ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface); std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); if (!sBluetoothA2dpInterface) { ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__); return JNI_FALSE; } jbyte* addr = env->GetByteArrayElements(address, nullptr); if (!addr) { Loading @@ -368,27 +404,43 @@ static jboolean disconnectA2dpNative(JNIEnv* env, jobject object, return JNI_FALSE; } bt_status_t status = sBluetoothA2dpInterface->disconnect((RawAddress*)addr); RawAddress bd_addr; bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr)); bt_status_t status = sBluetoothA2dpInterface->set_active_device(bd_addr); if (status != BT_STATUS_SUCCESS) { ALOGE("%s: Failed HF disconnection, status: %d", __func__, status); ALOGE("%s: Failed A2DP set_active_device, status: %d", __func__, status); } env->ReleaseByteArrayElements(address, addr, 0); return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } static jboolean setCodecConfigPreferenceNative(JNIEnv* env, jobject object, jbyteArray address, jobjectArray codecConfigArray) { ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface); std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); if (!sBluetoothA2dpInterface) return JNI_FALSE; if (!sBluetoothA2dpInterface) { ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__); return JNI_FALSE; } jbyte* addr = env->GetByteArrayElements(address, nullptr); if (!addr) { jniThrowIOException(env, EINVAL); return JNI_FALSE; } RawAddress bd_addr; bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr)); std::vector<btav_a2dp_codec_config_t> codec_preferences = prepareCodecPreferences(env, object, codecConfigArray); bt_status_t status = sBluetoothA2dpInterface->config_codec(codec_preferences); bt_status_t status = sBluetoothA2dpInterface->config_codec(bd_addr, codec_preferences); if (status != BT_STATUS_SUCCESS) { ALOGE("%s: Failed codec configuration, status: %d", __func__, status); } env->ReleaseByteArrayElements(address, addr, 0); return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } Loading @@ -399,8 +451,9 @@ static JNINativeMethod sMethods[] = { {"cleanupNative", "()V", (void*)cleanupNative}, {"connectA2dpNative", "([B)Z", (void*)connectA2dpNative}, {"disconnectA2dpNative", "([B)Z", (void*)disconnectA2dpNative}, {"setActiveDeviceNative", "([B)Z", (void*)setActiveDeviceNative}, {"setCodecConfigPreferenceNative", "([Landroid/bluetooth/BluetoothCodecConfig;)Z", "([B[Landroid/bluetooth/BluetoothCodecConfig;)Z", (void*)setCodecConfigPreferenceNative}, }; Loading
android/app/jni/com_android_bluetooth_a2dp_sink.cpp +12 −8 Original line number Diff line number Diff line Loading @@ -33,7 +33,7 @@ static jmethodID method_onAudioConfigChanged; static const btav_sink_interface_t* sBluetoothA2dpInterface = NULL; static jobject mCallbacksObj = NULL; static void bta2dp_connection_state_callback(RawAddress* bd_addr, static void bta2dp_connection_state_callback(const RawAddress& bd_addr, btav_connection_state_t state) { ALOGI("%s", __func__); CallbackEnv sCallbackEnv(__func__); Loading @@ -47,12 +47,12 @@ static void bta2dp_connection_state_callback(RawAddress* bd_addr, } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)bd_addr); (const jbyte*)bd_addr.address); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, addr.get(), (jint)state); } static void bta2dp_audio_state_callback(RawAddress* bd_addr, static void bta2dp_audio_state_callback(const RawAddress& bd_addr, btav_audio_state_t state) { ALOGI("%s", __func__); CallbackEnv sCallbackEnv(__func__); Loading @@ -66,12 +66,12 @@ static void bta2dp_audio_state_callback(RawAddress* bd_addr, } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)bd_addr); (const jbyte*)bd_addr.address); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged, addr.get(), (jint)state); } static void bta2dp_audio_config_callback(RawAddress* bd_addr, static void bta2dp_audio_config_callback(const RawAddress& bd_addr, uint32_t sample_rate, uint8_t channel_count) { ALOGI("%s", __func__); Loading @@ -86,7 +86,7 @@ static void bta2dp_audio_config_callback(RawAddress* bd_addr, } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)bd_addr); (const jbyte*)bd_addr.address); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioConfigChanged, addr.get(), (jint)sample_rate, (jint)channel_count); Loading Loading @@ -177,7 +177,9 @@ static jboolean connectA2dpNative(JNIEnv* env, jobject object, return JNI_FALSE; } bt_status_t status = sBluetoothA2dpInterface->connect((RawAddress*)addr); RawAddress bd_addr; bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr)); bt_status_t status = sBluetoothA2dpInterface->connect(bd_addr); if (status != BT_STATUS_SUCCESS) { ALOGE("Failed HF connection, status: %d", status); } Loading @@ -195,7 +197,9 @@ static jboolean disconnectA2dpNative(JNIEnv* env, jobject object, return JNI_FALSE; } bt_status_t status = sBluetoothA2dpInterface->disconnect((RawAddress*)addr); RawAddress bd_addr; bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr)); bt_status_t status = sBluetoothA2dpInterface->disconnect(bd_addr); if (status != BT_STATUS_SUCCESS) { ALOGE("Failed HF disconnection, status: %d", status); } Loading
android/app/src/com/android/bluetooth/a2dp/A2dpCodecConfig.java 0 → 100644 +190 −0 Original line number Diff line number Diff line /* * Copyright 2018 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.a2dp; import android.bluetooth.BluetoothCodecConfig; import android.bluetooth.BluetoothDevice; import android.content.Context; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; import com.android.bluetooth.R; /* * A2DP Codec Configuration setup. */ class A2dpCodecConfig { private static final boolean DBG = true; private static final String TAG = "A2dpCodecConfig"; private Context mContext; private A2dpNativeInterface mA2dpNativeInterface; private BluetoothCodecConfig[] mCodecConfigPriorities; private int mA2dpSourceCodecPrioritySbc = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; private int mA2dpSourceCodecPriorityAac = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; private int mA2dpSourceCodecPriorityAptx = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; private int mA2dpSourceCodecPriorityAptxHd = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; private int mA2dpSourceCodecPriorityLdac = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; A2dpCodecConfig(Context context, A2dpNativeInterface a2dpNativeInterface) { mContext = context; mA2dpNativeInterface = a2dpNativeInterface; mCodecConfigPriorities = assignCodecConfigPriorities(); } BluetoothCodecConfig[] codecConfigPriorities() { return mCodecConfigPriorities; } void setCodecConfigPreference(BluetoothDevice device, BluetoothCodecConfig codecConfig) { BluetoothCodecConfig[] codecConfigArray = new BluetoothCodecConfig[1]; codecConfigArray[0] = codecConfig; mA2dpNativeInterface.setCodecConfigPreference(device, codecConfigArray); } void enableOptionalCodecs(BluetoothDevice device) { BluetoothCodecConfig[] codecConfigArray = assignCodecConfigPriorities(); if (codecConfigArray == null) { return; } // Set the mandatory codec's priority to default, and remove the rest for (int i = 0; i < codecConfigArray.length; i++) { BluetoothCodecConfig codecConfig = codecConfigArray[i]; if (!codecConfig.isMandatoryCodec()) { codecConfigArray[i] = null; } } mA2dpNativeInterface.setCodecConfigPreference(device, codecConfigArray); } void disableOptionalCodecs(BluetoothDevice device) { BluetoothCodecConfig[] codecConfigArray = assignCodecConfigPriorities(); if (codecConfigArray == null) { return; } // Set the mandatory codec's priority to highest, and remove the rest for (int i = 0; i < codecConfigArray.length; i++) { BluetoothCodecConfig codecConfig = codecConfigArray[i]; if (codecConfig.isMandatoryCodec()) { codecConfig.setCodecPriority(BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST); } else { codecConfigArray[i] = null; } } mA2dpNativeInterface.setCodecConfigPreference(device, codecConfigArray); } // Assign the A2DP Source codec config priorities private BluetoothCodecConfig[] assignCodecConfigPriorities() { Resources resources = mContext.getResources(); if (resources == null) { return null; } int value; try { value = resources.getInteger(R.integer.a2dp_source_codec_priority_sbc); } catch (NotFoundException e) { value = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; } if ((value >= BluetoothCodecConfig.CODEC_PRIORITY_DISABLED) && (value < BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST)) { mA2dpSourceCodecPrioritySbc = value; } try { value = resources.getInteger(R.integer.a2dp_source_codec_priority_aac); } catch (NotFoundException e) { value = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; } if ((value >= BluetoothCodecConfig.CODEC_PRIORITY_DISABLED) && (value < BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST)) { mA2dpSourceCodecPriorityAac = value; } try { value = resources.getInteger(R.integer.a2dp_source_codec_priority_aptx); } catch (NotFoundException e) { value = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; } if ((value >= BluetoothCodecConfig.CODEC_PRIORITY_DISABLED) && (value < BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST)) { mA2dpSourceCodecPriorityAptx = value; } try { value = resources.getInteger(R.integer.a2dp_source_codec_priority_aptx_hd); } catch (NotFoundException e) { value = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; } if ((value >= BluetoothCodecConfig.CODEC_PRIORITY_DISABLED) && (value < BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST)) { mA2dpSourceCodecPriorityAptxHd = value; } try { value = resources.getInteger(R.integer.a2dp_source_codec_priority_ldac); } catch (NotFoundException e) { value = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; } if ((value >= BluetoothCodecConfig.CODEC_PRIORITY_DISABLED) && (value < BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST)) { mA2dpSourceCodecPriorityLdac = value; } BluetoothCodecConfig codecConfig; BluetoothCodecConfig[] codecConfigArray = new BluetoothCodecConfig[BluetoothCodecConfig.SOURCE_CODEC_TYPE_MAX]; codecConfig = new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, mA2dpSourceCodecPrioritySbc, BluetoothCodecConfig.SAMPLE_RATE_NONE, BluetoothCodecConfig.BITS_PER_SAMPLE_NONE, BluetoothCodecConfig .CHANNEL_MODE_NONE, 0 /* codecSpecific1 */, 0 /* codecSpecific2 */, 0 /* codecSpecific3 */, 0 /* codecSpecific4 */); codecConfigArray[0] = codecConfig; codecConfig = new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, mA2dpSourceCodecPriorityAac, BluetoothCodecConfig.SAMPLE_RATE_NONE, BluetoothCodecConfig.BITS_PER_SAMPLE_NONE, BluetoothCodecConfig .CHANNEL_MODE_NONE, 0 /* codecSpecific1 */, 0 /* codecSpecific2 */, 0 /* codecSpecific3 */, 0 /* codecSpecific4 */); codecConfigArray[1] = codecConfig; codecConfig = new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, mA2dpSourceCodecPriorityAptx, BluetoothCodecConfig.SAMPLE_RATE_NONE, BluetoothCodecConfig.BITS_PER_SAMPLE_NONE, BluetoothCodecConfig .CHANNEL_MODE_NONE, 0 /* codecSpecific1 */, 0 /* codecSpecific2 */, 0 /* codecSpecific3 */, 0 /* codecSpecific4 */); codecConfigArray[2] = codecConfig; codecConfig = new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, mA2dpSourceCodecPriorityAptxHd, BluetoothCodecConfig.SAMPLE_RATE_NONE, BluetoothCodecConfig.BITS_PER_SAMPLE_NONE, BluetoothCodecConfig .CHANNEL_MODE_NONE, 0 /* codecSpecific1 */, 0 /* codecSpecific2 */, 0 /* codecSpecific3 */, 0 /* codecSpecific4 */); codecConfigArray[3] = codecConfig; codecConfig = new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, mA2dpSourceCodecPriorityLdac, BluetoothCodecConfig.SAMPLE_RATE_NONE, BluetoothCodecConfig.BITS_PER_SAMPLE_NONE, BluetoothCodecConfig .CHANNEL_MODE_NONE, 0 /* codecSpecific1 */, 0 /* codecSpecific2 */, 0 /* codecSpecific3 */, 0 /* codecSpecific4 */); codecConfigArray[4] = codecConfig; return codecConfigArray; } }
android/app/src/com/android/bluetooth/a2dp/A2dpNativeInterface.java +19 −9 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ public class A2dpNativeInterface { private A2dpNativeInterface() { mAdapter = BluetoothAdapter.getDefaultAdapter(); if (mAdapter == null) { Log.wtf(TAG, "No Bluetooth Adapter Available"); Log.wtfStack(TAG, "No Bluetooth Adapter Available"); } } Loading Loading @@ -104,15 +104,28 @@ public class A2dpNativeInterface { return disconnectA2dpNative(getByteAddress(device)); } /** * Sets a connected A2DP remote device as active. * * @param device the remote device * @return true on success, otherwise false. */ public boolean setActiveDevice(BluetoothDevice device) { return setActiveDeviceNative(getByteAddress(device)); } /** * Sets the codec configuration preferences. * * @param device the remote Bluetooth device * @param codecConfigArray an array with the codec configurations to * configure. * @return true on success, otherwise false. */ public boolean setCodecConfigPreference(BluetoothCodecConfig[] codecConfigArray) { return setCodecConfigPreferenceNative(codecConfigArray); public boolean setCodecConfigPreference(BluetoothDevice device, BluetoothCodecConfig[] codecConfigArray) { return setCodecConfigPreferenceNative(getByteAddress(device), codecConfigArray); } private BluetoothDevice getDevice(byte[] address) { Loading Loading @@ -176,14 +189,11 @@ public class A2dpNativeInterface { // Native methods that call into the JNI interface private static native void classInitNative(); private native void initNative(BluetoothCodecConfig[] codecConfigPriorities); private native void cleanupNative(); private native boolean connectA2dpNative(byte[] address); private native boolean disconnectA2dpNative(byte[] address); private native boolean setCodecConfigPreferenceNative(BluetoothCodecConfig[] codecConfigArray); private native boolean setActiveDeviceNative(byte[] address); private native boolean setCodecConfigPreferenceNative(byte[] address, BluetoothCodecConfig[] codecConfigArray); }
android/app/src/com/android/bluetooth/a2dp/A2dpService.java +497 −122 File changed.Preview size limit exceeded, changes collapsed. Show changes