Loading android/app/jni/com_android_bluetooth_a2dp.cpp +69 −8 Original line number Diff line number Diff line Loading @@ -30,6 +30,11 @@ static jmethodID method_onConnectionStateChanged; static jmethodID method_onAudioStateChanged; static jmethodID method_onCodecConfigChanged; static struct { jclass clazz; jmethodID constructor; } android_bluetooth_BluetoothCodecConfig; static const btav_source_interface_t* sBluetoothA2dpInterface = NULL; static jobject mCallbacksObj = NULL; Loading Loading @@ -73,19 +78,58 @@ static void bta2dp_audio_state_callback(btav_audio_state_t state, static void bta2dp_audio_config_callback( btav_a2dp_codec_config_t codec_config, std::vector<btav_a2dp_codec_config_t> codec_capabilities) { std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities, std::vector<btav_a2dp_codec_config_t> codecs_selectable_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, jobject codecConfigObj = sCallbackEnv->NewObject( android_bluetooth_BluetoothCodecConfig.clazz, android_bluetooth_BluetoothCodecConfig.constructor, (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); jsize i = 0; jobjectArray local_capabilities_array = sCallbackEnv->NewObjectArray( (jsize)codecs_local_capabilities.size(), android_bluetooth_BluetoothCodecConfig.clazz, NULL); for (auto const& cap : codecs_local_capabilities) { jobject capObj = sCallbackEnv->NewObject( android_bluetooth_BluetoothCodecConfig.clazz, android_bluetooth_BluetoothCodecConfig.constructor, (jint)cap.codec_type, (jint)cap.codec_priority, (jint)cap.sample_rate, (jint)cap.bits_per_sample, (jint)cap.channel_mode, (jlong)cap.codec_specific_1, (jlong)cap.codec_specific_2, (jlong)cap.codec_specific_3, (jlong)cap.codec_specific_4); sCallbackEnv->SetObjectArrayElement(local_capabilities_array, i++, capObj); sCallbackEnv->DeleteLocalRef(capObj); } i = 0; jobjectArray selectable_capabilities_array = sCallbackEnv->NewObjectArray( (jsize)codecs_selectable_capabilities.size(), android_bluetooth_BluetoothCodecConfig.clazz, NULL); for (auto const& cap : codecs_selectable_capabilities) { jobject capObj = sCallbackEnv->NewObject( android_bluetooth_BluetoothCodecConfig.clazz, android_bluetooth_BluetoothCodecConfig.constructor, (jint)cap.codec_type, (jint)cap.codec_priority, (jint)cap.sample_rate, (jint)cap.bits_per_sample, (jint)cap.channel_mode, (jlong)cap.codec_specific_1, (jlong)cap.codec_specific_2, (jlong)cap.codec_specific_3, (jlong)cap.codec_specific_4); sCallbackEnv->SetObjectArrayElement(selectable_capabilities_array, i++, capObj); sCallbackEnv->DeleteLocalRef(capObj); } sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCodecConfigChanged, codecConfigObj, local_capabilities_array, selectable_capabilities_array); } static btav_source_callbacks_t sBluetoothA2dpCallbacks = { Loading @@ -94,14 +138,21 @@ static btav_source_callbacks_t sBluetoothA2dpCallbacks = { }; static void classInitNative(JNIEnv* env, jclass clazz) { jclass jniBluetoothCodecConfigClass = env->FindClass("android/bluetooth/BluetoothCodecConfig"); android_bluetooth_BluetoothCodecConfig.constructor = env->GetMethodID(jniBluetoothCodecConfigClass, "<init>", "(IIIIIJJJJ)V"); method_onConnectionStateChanged = env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V"); method_onAudioStateChanged = env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V"); method_onCodecConfigChanged = env->GetMethodID(clazz, "onCodecConfigChanged", "(IIIIIJJJJ)V"); method_onCodecConfigChanged = env->GetMethodID( clazz, "onCodecConfigChanged", "(Landroid/bluetooth/BluetoothCodecConfig;[Landroid/bluetooth/" "BluetoothCodecConfig;[Landroid/bluetooth/BluetoothCodecConfig;)V"); ALOGI("%s: succeeds", __func__); } Loading Loading @@ -130,6 +181,13 @@ static void initNative(JNIEnv* env, jobject object) { return; } android_bluetooth_BluetoothCodecConfig.clazz = (jclass)env->NewGlobalRef( env->FindClass("android/bluetooth/BluetoothCodecConfig")); if (android_bluetooth_BluetoothCodecConfig.clazz == nullptr) { ALOGE("Failed to allocate Global Ref for BluetoothCodecConfig class"); return; } sBluetoothA2dpInterface = (btav_source_interface_t*)btInf->get_profile_interface( BT_PROFILE_ADVANCED_AUDIO_ID); Loading Loading @@ -158,6 +216,9 @@ static void cleanupNative(JNIEnv* env, jobject object) { sBluetoothA2dpInterface = NULL; } env->DeleteGlobalRef(android_bluetooth_BluetoothCodecConfig.clazz); android_bluetooth_BluetoothCodecConfig.clazz = nullptr; if (mCallbacksObj != NULL) { env->DeleteGlobalRef(mCallbacksObj); mCallbacksObj = NULL; Loading android/app/src/com/android/bluetooth/a2dp/A2dpService.java +6 −5 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.bluetooth.a2dp; import android.bluetooth.BluetoothCodecConfig; import android.bluetooth.BluetoothCodecStatus; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothUuid; Loading Loading @@ -224,10 +225,10 @@ public class A2dpService extends ProfileService { return mStateMachine.isPlaying(device); } public BluetoothCodecConfig getCodecConfig() { public BluetoothCodecStatus getCodecStatus() { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (DBG) Log.d(TAG, "getCodecConfig()"); return mStateMachine.getCodecConfig(); if (DBG) Log.d(TAG, "getCodecStatus()"); return mStateMachine.getCodecStatus(); } public void setCodecConfigPreference(BluetoothCodecConfig codecConfig) { Loading Loading @@ -328,10 +329,10 @@ public class A2dpService extends ProfileService { return service.isA2dpPlaying(device); } public BluetoothCodecConfig getCodecConfig() { public BluetoothCodecStatus getCodecStatus() { A2dpService service = getService(); if (service == null) return null; return service.getCodecConfig(); return service.getCodecStatus(); } public void setCodecConfigPreference(BluetoothCodecConfig codecConfig) { Loading android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java +21 −15 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ package com.android.bluetooth.a2dp; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothCodecConfig; import android.bluetooth.BluetoothCodecStatus; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothUuid; Loading Loading @@ -103,7 +104,7 @@ final class A2dpStateMachine extends StateMachine { private BluetoothDevice mIncomingDevice = null; private BluetoothDevice mPlayingA2dpDevice = null; private BluetoothCodecConfig mCodecConfig = null; private BluetoothCodecStatus mCodecStatus = null; static { classInitNative(); Loading Loading @@ -654,30 +655,35 @@ final class A2dpStateMachine extends StateMachine { return false; } BluetoothCodecConfig getCodecConfig() { BluetoothCodecStatus getCodecStatus() { synchronized (this) { return mCodecConfig; return mCodecStatus; } } 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); private void onCodecConfigChanged(BluetoothCodecConfig newCodecConfig, BluetoothCodecConfig[] codecsLocalCapabilities, BluetoothCodecConfig[] codecsSelectableCapabilities) { BluetoothCodecConfig prevCodecConfig = null; synchronized (this) { prevCodecConfig = mCodecConfig; mCodecConfig = newCodecConfig; if (mCodecStatus != null) { prevCodecConfig = mCodecStatus.getCodecConfig(); } mCodecStatus = new BluetoothCodecStatus( newCodecConfig, codecsLocalCapabilities, codecsSelectableCapabilities); } 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.putExtra(BluetoothCodecStatus.EXTRA_CODEC_STATUS, mCodecStatus); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); log("A2DP Codec Config: " + prevCodecConfig + "->" + newCodecConfig); for (BluetoothCodecConfig codecConfig : codecsLocalCapabilities) { log("A2DP Codec Local Capability: " + codecConfig); } for (BluetoothCodecConfig codecConfig : codecsSelectableCapabilities) { log("A2DP Codec Selectable Capability: " + codecConfig); } // Inform the Audio Service about the codec configuration change, // so the Audio Service can reset accordingly the audio feeding Loading Loading
android/app/jni/com_android_bluetooth_a2dp.cpp +69 −8 Original line number Diff line number Diff line Loading @@ -30,6 +30,11 @@ static jmethodID method_onConnectionStateChanged; static jmethodID method_onAudioStateChanged; static jmethodID method_onCodecConfigChanged; static struct { jclass clazz; jmethodID constructor; } android_bluetooth_BluetoothCodecConfig; static const btav_source_interface_t* sBluetoothA2dpInterface = NULL; static jobject mCallbacksObj = NULL; Loading Loading @@ -73,19 +78,58 @@ static void bta2dp_audio_state_callback(btav_audio_state_t state, static void bta2dp_audio_config_callback( btav_a2dp_codec_config_t codec_config, std::vector<btav_a2dp_codec_config_t> codec_capabilities) { std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities, std::vector<btav_a2dp_codec_config_t> codecs_selectable_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, jobject codecConfigObj = sCallbackEnv->NewObject( android_bluetooth_BluetoothCodecConfig.clazz, android_bluetooth_BluetoothCodecConfig.constructor, (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); jsize i = 0; jobjectArray local_capabilities_array = sCallbackEnv->NewObjectArray( (jsize)codecs_local_capabilities.size(), android_bluetooth_BluetoothCodecConfig.clazz, NULL); for (auto const& cap : codecs_local_capabilities) { jobject capObj = sCallbackEnv->NewObject( android_bluetooth_BluetoothCodecConfig.clazz, android_bluetooth_BluetoothCodecConfig.constructor, (jint)cap.codec_type, (jint)cap.codec_priority, (jint)cap.sample_rate, (jint)cap.bits_per_sample, (jint)cap.channel_mode, (jlong)cap.codec_specific_1, (jlong)cap.codec_specific_2, (jlong)cap.codec_specific_3, (jlong)cap.codec_specific_4); sCallbackEnv->SetObjectArrayElement(local_capabilities_array, i++, capObj); sCallbackEnv->DeleteLocalRef(capObj); } i = 0; jobjectArray selectable_capabilities_array = sCallbackEnv->NewObjectArray( (jsize)codecs_selectable_capabilities.size(), android_bluetooth_BluetoothCodecConfig.clazz, NULL); for (auto const& cap : codecs_selectable_capabilities) { jobject capObj = sCallbackEnv->NewObject( android_bluetooth_BluetoothCodecConfig.clazz, android_bluetooth_BluetoothCodecConfig.constructor, (jint)cap.codec_type, (jint)cap.codec_priority, (jint)cap.sample_rate, (jint)cap.bits_per_sample, (jint)cap.channel_mode, (jlong)cap.codec_specific_1, (jlong)cap.codec_specific_2, (jlong)cap.codec_specific_3, (jlong)cap.codec_specific_4); sCallbackEnv->SetObjectArrayElement(selectable_capabilities_array, i++, capObj); sCallbackEnv->DeleteLocalRef(capObj); } sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCodecConfigChanged, codecConfigObj, local_capabilities_array, selectable_capabilities_array); } static btav_source_callbacks_t sBluetoothA2dpCallbacks = { Loading @@ -94,14 +138,21 @@ static btav_source_callbacks_t sBluetoothA2dpCallbacks = { }; static void classInitNative(JNIEnv* env, jclass clazz) { jclass jniBluetoothCodecConfigClass = env->FindClass("android/bluetooth/BluetoothCodecConfig"); android_bluetooth_BluetoothCodecConfig.constructor = env->GetMethodID(jniBluetoothCodecConfigClass, "<init>", "(IIIIIJJJJ)V"); method_onConnectionStateChanged = env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V"); method_onAudioStateChanged = env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V"); method_onCodecConfigChanged = env->GetMethodID(clazz, "onCodecConfigChanged", "(IIIIIJJJJ)V"); method_onCodecConfigChanged = env->GetMethodID( clazz, "onCodecConfigChanged", "(Landroid/bluetooth/BluetoothCodecConfig;[Landroid/bluetooth/" "BluetoothCodecConfig;[Landroid/bluetooth/BluetoothCodecConfig;)V"); ALOGI("%s: succeeds", __func__); } Loading Loading @@ -130,6 +181,13 @@ static void initNative(JNIEnv* env, jobject object) { return; } android_bluetooth_BluetoothCodecConfig.clazz = (jclass)env->NewGlobalRef( env->FindClass("android/bluetooth/BluetoothCodecConfig")); if (android_bluetooth_BluetoothCodecConfig.clazz == nullptr) { ALOGE("Failed to allocate Global Ref for BluetoothCodecConfig class"); return; } sBluetoothA2dpInterface = (btav_source_interface_t*)btInf->get_profile_interface( BT_PROFILE_ADVANCED_AUDIO_ID); Loading Loading @@ -158,6 +216,9 @@ static void cleanupNative(JNIEnv* env, jobject object) { sBluetoothA2dpInterface = NULL; } env->DeleteGlobalRef(android_bluetooth_BluetoothCodecConfig.clazz); android_bluetooth_BluetoothCodecConfig.clazz = nullptr; if (mCallbacksObj != NULL) { env->DeleteGlobalRef(mCallbacksObj); mCallbacksObj = NULL; Loading
android/app/src/com/android/bluetooth/a2dp/A2dpService.java +6 −5 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.bluetooth.a2dp; import android.bluetooth.BluetoothCodecConfig; import android.bluetooth.BluetoothCodecStatus; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothUuid; Loading Loading @@ -224,10 +225,10 @@ public class A2dpService extends ProfileService { return mStateMachine.isPlaying(device); } public BluetoothCodecConfig getCodecConfig() { public BluetoothCodecStatus getCodecStatus() { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (DBG) Log.d(TAG, "getCodecConfig()"); return mStateMachine.getCodecConfig(); if (DBG) Log.d(TAG, "getCodecStatus()"); return mStateMachine.getCodecStatus(); } public void setCodecConfigPreference(BluetoothCodecConfig codecConfig) { Loading Loading @@ -328,10 +329,10 @@ public class A2dpService extends ProfileService { return service.isA2dpPlaying(device); } public BluetoothCodecConfig getCodecConfig() { public BluetoothCodecStatus getCodecStatus() { A2dpService service = getService(); if (service == null) return null; return service.getCodecConfig(); return service.getCodecStatus(); } public void setCodecConfigPreference(BluetoothCodecConfig codecConfig) { Loading
android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java +21 −15 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ package com.android.bluetooth.a2dp; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothCodecConfig; import android.bluetooth.BluetoothCodecStatus; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothUuid; Loading Loading @@ -103,7 +104,7 @@ final class A2dpStateMachine extends StateMachine { private BluetoothDevice mIncomingDevice = null; private BluetoothDevice mPlayingA2dpDevice = null; private BluetoothCodecConfig mCodecConfig = null; private BluetoothCodecStatus mCodecStatus = null; static { classInitNative(); Loading Loading @@ -654,30 +655,35 @@ final class A2dpStateMachine extends StateMachine { return false; } BluetoothCodecConfig getCodecConfig() { BluetoothCodecStatus getCodecStatus() { synchronized (this) { return mCodecConfig; return mCodecStatus; } } 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); private void onCodecConfigChanged(BluetoothCodecConfig newCodecConfig, BluetoothCodecConfig[] codecsLocalCapabilities, BluetoothCodecConfig[] codecsSelectableCapabilities) { BluetoothCodecConfig prevCodecConfig = null; synchronized (this) { prevCodecConfig = mCodecConfig; mCodecConfig = newCodecConfig; if (mCodecStatus != null) { prevCodecConfig = mCodecStatus.getCodecConfig(); } mCodecStatus = new BluetoothCodecStatus( newCodecConfig, codecsLocalCapabilities, codecsSelectableCapabilities); } 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.putExtra(BluetoothCodecStatus.EXTRA_CODEC_STATUS, mCodecStatus); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); log("A2DP Codec Config: " + prevCodecConfig + "->" + newCodecConfig); for (BluetoothCodecConfig codecConfig : codecsLocalCapabilities) { log("A2DP Codec Local Capability: " + codecConfig); } for (BluetoothCodecConfig codecConfig : codecsSelectableCapabilities) { log("A2DP Codec Selectable Capability: " + codecConfig); } // Inform the Audio Service about the codec configuration change, // so the Audio Service can reset accordingly the audio feeding Loading