Merge "audio: Send A2DP codec to AudioSystem on connection state change"
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 80560f8..860de75 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -487,7 +487,8 @@
 }
 
 static jint
-android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name)
+android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name,
+                                                   jint codec __unused)
 {
     const char *c_address = env->GetStringUTFChars(device_address, NULL);
     const char *c_name = env->GetStringUTFChars(device_name, NULL);
@@ -510,7 +511,8 @@
 }
 
 static jint
-android_media_AudioSystem_handleDeviceConfigChange(JNIEnv *env, jobject thiz, jint device, jstring device_address, jstring device_name)
+android_media_AudioSystem_handleDeviceConfigChange(JNIEnv *env, jobject thiz, jint device, jstring device_address, jstring device_name,
+                                                   jint codec __unused)
 {
     const char *c_address = env->GetStringUTFChars(device_address, NULL);
     const char *c_name = env->GetStringUTFChars(device_name, NULL);
@@ -2142,9 +2144,9 @@
     {"isSourceActive",      "(I)Z",     (void *)android_media_AudioSystem_isSourceActive},
     {"newAudioSessionId",   "()I",      (void *)android_media_AudioSystem_newAudioSessionId},
     {"newAudioPlayerId",    "()I",      (void *)android_media_AudioSystem_newAudioPlayerId},
-    {"setDeviceConnectionState", "(IILjava/lang/String;Ljava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
+    {"setDeviceConnectionState", "(IILjava/lang/String;Ljava/lang/String;I)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
     {"getDeviceConnectionState", "(ILjava/lang/String;)I",  (void *)android_media_AudioSystem_getDeviceConnectionState},
-    {"handleDeviceConfigChange", "(ILjava/lang/String;Ljava/lang/String;)I", (void *)android_media_AudioSystem_handleDeviceConfigChange},
+    {"handleDeviceConfigChange", "(ILjava/lang/String;Ljava/lang/String;I)I", (void *)android_media_AudioSystem_handleDeviceConfigChange},
     {"setPhoneState",       "(I)I",     (void *)android_media_AudioSystem_setPhoneState},
     {"setForceUse",         "(II)I",    (void *)android_media_AudioSystem_setForceUse},
     {"getForceUse",         "(I)I",     (void *)android_media_AudioSystem_getForceUse},
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 6b74479..774023f 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -140,6 +140,30 @@
         }
     }
 
+    /* Formats for A2DP codecs, must match system/audio-base.h audio_format_t */
+    public static final int AUDIO_FORMAT_INVALID        = 0xFFFFFFFF;
+    public static final int AUDIO_FORMAT_DEFAULT        = 0;
+    public static final int AUDIO_FORMAT_AAC            = 0x04000000;
+    public static final int AUDIO_FORMAT_SBC            = 0x1F000000;
+    public static final int AUDIO_FORMAT_APTX           = 0x20000000;
+    public static final int AUDIO_FORMAT_APTX_HD        = 0x21000000;
+    public static final int AUDIO_FORMAT_LDAC           = 0x23000000;
+
+    /** converts audio format enum to string */
+    public static String audioFormatToString(int audioFormat) {
+        switch (audioFormat) {
+            case AUDIO_FORMAT_INVALID: return "AUDIO_FORMAT_INVALID";
+            case AUDIO_FORMAT_DEFAULT: return "AUDIO_FORMAT_DEFAULT";
+            case AUDIO_FORMAT_AAC: return "AUDIO_FORMAT_AAC";
+            case AUDIO_FORMAT_SBC: return "AUDIO_FORMAT_SBC";
+            case AUDIO_FORMAT_APTX: return "AUDIO_FORMAT_APTX";
+            case AUDIO_FORMAT_APTX_HD: return "AUDIO_FORMAT_APTX_HD";
+            case AUDIO_FORMAT_LDAC: return "AUDIO_FORMAT_LDAC";
+            default: return "unknown audio format (" + audioFormat + ")";
+        }
+    }
+
+
     /* Routing bits for the former setRouting/getRouting API */
     /** @deprecated */
     @Deprecated public static final int ROUTE_EARPIECE          = (1 << 0);
@@ -865,12 +889,14 @@
      */
     @UnsupportedAppUsage
     public static native int setDeviceConnectionState(int device, int state,
-                                                      String device_address, String device_name);
+                                                      String device_address, String device_name,
+                                                      int codecFormat);
     @UnsupportedAppUsage
     public static native int getDeviceConnectionState(int device, String device_address);
     public static native int handleDeviceConfigChange(int device,
                                                       String device_address,
-                                                      String device_name);
+                                                      String device_name,
+                                                      int codecFormat);
     @UnsupportedAppUsage
     public static native int setPhoneState(int state);
     @UnsupportedAppUsage
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index d9fcf9e..2625c18 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -38,6 +38,8 @@
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothCodecConfig;
+import android.bluetooth.BluetoothCodecStatus;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothHearingAid;
@@ -480,16 +482,20 @@
         int mDeviceType;
         String mDeviceName;
         String mDeviceAddress;
+        int mDeviceCodecFormat;
 
-        public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
+        DeviceListSpec(int deviceType, String deviceName, String deviceAddress,
+                int deviceCodecFormat) {
             mDeviceType = deviceType;
             mDeviceName = deviceName;
             mDeviceAddress = deviceAddress;
+            mDeviceCodecFormat = deviceCodecFormat;
         }
 
         public String toString() {
             return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
-                    + " address:" + mDeviceAddress + "]";
+                    + " address:" + mDeviceAddress
+                    + " codec: " + Integer.toHexString(mDeviceCodecFormat) + "]";
         }
     }
 
@@ -501,6 +507,52 @@
 
     private final ArrayMap<String, DeviceListSpec> mConnectedDevices = new ArrayMap<>();
 
+    private class BluetoothA2dpDeviceInfo {
+        BluetoothDevice mBtDevice;
+        int mVolume;
+        int mCodec;
+
+        BluetoothA2dpDeviceInfo(BluetoothDevice btDevice) {
+            this(btDevice, -1, AudioSystem.AUDIO_FORMAT_DEFAULT);
+        }
+
+        BluetoothA2dpDeviceInfo(BluetoothDevice btDevice,
+                     int volume, int codec) {
+            mBtDevice = btDevice;
+            mVolume = volume;
+            mCodec = codec;
+        }
+
+        public BluetoothDevice getBtDevice() {
+            return mBtDevice;
+        }
+
+        public int getVolume() {
+            return mVolume;
+        }
+
+        public int getCodec() {
+            return mCodec;
+        }
+    }
+
+    private int mapBluetoothCodecToAudioFormat(int btCodecType) {
+        switch (btCodecType) {
+            case BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC:
+                return AudioSystem.AUDIO_FORMAT_SBC;
+            case BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC:
+                return AudioSystem.AUDIO_FORMAT_AAC;
+            case BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX:
+                return AudioSystem.AUDIO_FORMAT_APTX;
+            case BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD:
+                return AudioSystem.AUDIO_FORMAT_APTX_HD;
+            case BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC:
+                return AudioSystem.AUDIO_FORMAT_LDAC;
+            default:
+                return AudioSystem.AUDIO_FORMAT_DEFAULT;
+        }
+    }
+
     // Forced device usage for communications
     private int mForcedUseForComm;
     private int mForcedUseForCommExt; // External state returned by getters: always consistent
@@ -1020,7 +1072,8 @@
                                                 spec.mDeviceType,
                                                 AudioSystem.DEVICE_STATE_AVAILABLE,
                                                 spec.mDeviceAddress,
-                                                spec.mDeviceName);
+                                                spec.mDeviceName,
+                                                spec.mDeviceCodecFormat);
             }
         }
         // Restore call state
@@ -3906,8 +3959,8 @@
                             queueMsgUnderWakeLock(mAudioHandler,
                                     MSG_SET_A2DP_SINK_CONNECTION_STATE,
                                     state,
-                                    -1,
-                                    btDevice,
+                                    0 /* arg2 unused */,
+                                    new BluetoothA2dpDeviceInfo(btDevice),
                                     delay);
                         }
                     }
@@ -3924,7 +3977,7 @@
                                 MSG_SET_A2DP_SRC_CONNECTION_STATE,
                                 state,
                                 0 /* arg2 unused */,
-                                btDevice,
+                                new BluetoothA2dpDeviceInfo(btDevice),
                                 0 /* delay */);
                     }
                 }
@@ -4689,6 +4742,17 @@
         }
     }
 
+    private int getA2dpCodec(BluetoothDevice device) {
+        synchronized (mA2dpAvrcpLock) {
+            if (mA2dp != null) {
+                BluetoothCodecStatus btCodecStatus = mA2dp.getCodecStatus(device);
+                BluetoothCodecConfig btCodecConfig = btCodecStatus.getCodecConfig();
+                return mapBluetoothCodecToAudioFormat(btCodecConfig.getCodecType());
+            }
+            return AudioSystem.AUDIO_FORMAT_DEFAULT;
+        }
+    }
+
     /*
      * A class just for packaging up a set of connection parameters.
      */
@@ -4753,14 +4817,16 @@
         return delay;
     }
 
-    public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
+    public int setBluetoothA2dpDeviceConnectionState(
+            BluetoothDevice device, int state, int profile)
     {
         return setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
-                device, state, profile, false /* suppressNoisyIntent */, -1 /* a2dpVolume */);
+                device, state, profile, false /* suppressNoisyIntent */,
+                -1 /* a2dpVolume */);
     }
 
     public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice device,
-                int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)
+            int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)
     {
         mDeviceLogger.log((new AudioEventLogger.StringEvent(
                 "setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent state=" + state
@@ -4773,7 +4839,8 @@
             return 0;
         }
         return setBluetoothA2dpDeviceConnectionStateInt(
-                device, state, profile, suppressNoisyIntent, AudioSystem.DEVICE_NONE, a2dpVolume);
+                device, state, profile, suppressNoisyIntent,
+                AudioSystem.DEVICE_NONE, a2dpVolume);
     }
 
     public int setBluetoothA2dpDeviceConnectionStateInt(
@@ -4793,18 +4860,20 @@
                 delay = 0;
             }
 
+            int a2dpCodec = getA2dpCodec(device);
+
             if (DEBUG_DEVICES) {
                 Log.d(TAG, "setBluetoothA2dpDeviceConnectionStateInt device: " + device
-                      + " state: " + state + " delay(ms): " + delay
-                      + " suppressNoisyIntent: " + suppressNoisyIntent);
+                        + " state: " + state + " delay(ms): " + delay + "codec:" + a2dpCodec
+                        + " suppressNoisyIntent: " + suppressNoisyIntent);
             }
 
             queueMsgUnderWakeLock(mAudioHandler,
                     (profile == BluetoothProfile.A2DP ?
                         MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
                     state,
-                    a2dpVolume,
-                    device,
+                    0, /* arg2 unused */
+                    new BluetoothA2dpDeviceInfo(device, a2dpVolume, a2dpCodec),
                     delay);
         }
         return delay;
@@ -4813,11 +4882,12 @@
     public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device)
     {
         synchronized (mConnectedDevices) {
+            int a2dpCodec = getA2dpCodec(device);
             queueMsgUnderWakeLock(mAudioHandler,
                     MSG_A2DP_DEVICE_CONFIG_CHANGE,
                     0 /* arg1 unused */,
-                    0 /* arg1 unused */,
-                    device,
+                    0 /* arg2 unused */,
+                    new BluetoothA2dpDeviceInfo(device, -1, a2dpCodec),
                     0 /* delay */);
         }
     }
@@ -5699,7 +5769,7 @@
                 case MSG_BTA2DP_DOCK_TIMEOUT:
                     // msg.obj  == address of BTA2DP device
                     synchronized (mConnectedDevices) {
-                        makeA2dpDeviceUnavailableNow( (String) msg.obj );
+                        makeA2dpDeviceUnavailableNow((String) msg.obj, msg.arg1);
                     }
                     mAudioEventWakeLock.release();
                     break;
@@ -5724,12 +5794,12 @@
                     break;
 
                 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
-                    onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
+                    onSetA2dpSourceConnectionState((BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
                     mAudioEventWakeLock.release();
                     break;
 
                 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
-                    onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1, msg.arg2);
+                    onSetA2dpSinkConnectionState((BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
                     mAudioEventWakeLock.release();
                     break;
 
@@ -5739,7 +5809,7 @@
                     break;
 
                 case MSG_A2DP_DEVICE_CONFIG_CHANGE:
-                    onBluetoothA2dpDeviceConfigChange((BluetoothDevice)msg.obj);
+                    onBluetoothA2dpDeviceConfigChange((BluetoothA2dpDeviceInfo) msg.obj);
                     mAudioEventWakeLock.release();
                     break;
 
@@ -5913,19 +5983,20 @@
     }
 
     // must be called synchronized on mConnectedDevices
-    private void makeA2dpDeviceAvailable(String address, String name, String eventSource) {
+    private void makeA2dpDeviceAvailable(
+            String address, String name, String eventSource, int a2dpCodec) {
         // enable A2DP before notifying A2DP connection to avoid unnecessary processing in
         // audio policy manager
         VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
         setBluetoothA2dpOnInt(true, eventSource);
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
+                AudioSystem.DEVICE_STATE_AVAILABLE, address, name, a2dpCodec);
         // Reset A2DP suspend state each time a new sink is connected
         AudioSystem.setParameters("A2dpSuspended=false");
         mConnectedDevices.put(
                 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
                 new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
-                                   address));
+                                   address, a2dpCodec));
         sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
                 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, null, 0);
         setCurrentAudioRouteNameIfPossible(name);
@@ -5938,7 +6009,7 @@
     }
 
     // must be called synchronized on mConnectedDevices
-    private void makeA2dpDeviceUnavailableNow(String address) {
+    private void makeA2dpDeviceUnavailableNow(String address, int a2dpCodec) {
         if (address == null) {
             return;
         }
@@ -5946,7 +6017,7 @@
             mAvrcpAbsVolSupported = false;
         }
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
+                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "", a2dpCodec);
         mConnectedDevices.remove(
                 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
         // Remove A2DP routes as well
@@ -5961,32 +6032,38 @@
         // prevent any activity on the A2DP audio output to avoid unwanted
         // reconnection of the sink.
         AudioSystem.setParameters("A2dpSuspended=true");
+        // Retrieve deviceSpec before removing device
+        String deviceKey = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
+        DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
+        int a2dpCodec = deviceSpec != null ? deviceSpec.mDeviceCodecFormat :
+                                AudioSystem.AUDIO_FORMAT_DEFAULT;
         // the device will be made unavailable later, so consider it disconnected right away
-        mConnectedDevices.remove(
-                makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
+        mConnectedDevices.remove(deviceKey);
         // send the delayed message to make the device unavailable later
         queueMsgUnderWakeLock(mAudioHandler,
-            MSG_BTA2DP_DOCK_TIMEOUT,
-            0,
-            0,
-            address,
-            delayMs);
+                MSG_BTA2DP_DOCK_TIMEOUT,
+                a2dpCodec,
+                0,
+                address,
+                delayMs);
     }
 
     // must be called synchronized on mConnectedDevices
     private void makeA2dpSrcAvailable(String address) {
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_AVAILABLE, address, "");
+                AudioSystem.DEVICE_STATE_AVAILABLE, address, "",
+                AudioSystem.AUDIO_FORMAT_DEFAULT);
         mConnectedDevices.put(
                 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
                 new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "",
-                                   address));
+                                   address, AudioSystem.AUDIO_FORMAT_DEFAULT));
     }
 
     // must be called synchronized on mConnectedDevices
     private void makeA2dpSrcUnavailable(String address) {
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
+                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "",
+                AudioSystem.AUDIO_FORMAT_DEFAULT);
         mConnectedDevices.remove(
                 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
     }
@@ -6010,11 +6087,12 @@
         setHearingAidVolume(index, AudioSystem.STREAM_MUSIC);
 
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
-                AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
+                AudioSystem.DEVICE_STATE_AVAILABLE, address, name,
+                AudioSystem.AUDIO_FORMAT_DEFAULT);
         mConnectedDevices.put(
                 makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address),
                 new DeviceListSpec(AudioSystem.DEVICE_OUT_HEARING_AID, name,
-                                   address));
+                                   address, AudioSystem.AUDIO_FORMAT_DEFAULT));
         sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
                 AudioSystem.DEVICE_OUT_HEARING_AID, 0, null, 0);
         sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
@@ -6026,7 +6104,8 @@
     // must be called synchronized on mConnectedDevices
     private void makeHearingAidDeviceUnavailable(String address) {
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
+                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "",
+                AudioSystem.AUDIO_FORMAT_DEFAULT);
         mConnectedDevices.remove(
                 makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address));
         // Remove Hearing Aid routes as well
@@ -6043,15 +6122,23 @@
         return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
     }
 
-    private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state, int a2dpVolume)
+    private void onSetA2dpSinkConnectionState(BluetoothA2dpDeviceInfo btInfo, int state)
     {
-        if (DEBUG_DEVICES) {
-            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice= " + btDevice+" state= " + state
-                + " is dock: "+btDevice.isBluetoothDock());
+        if (btInfo == null) {
+            return;
         }
+
+        BluetoothDevice btDevice = btInfo.getBtDevice();
+        int a2dpVolume = btInfo.getVolume();
+        int a2dpCodec = btInfo.getCodec();
+
         if (btDevice == null) {
             return;
         }
+        if (DEBUG_DEVICES) {
+            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice= " + btDevice + " state= " + state
+                    + " is dock: " + btDevice.isBluetoothDock());
+        }
         String address = btDevice.getAddress();
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             address = "";
@@ -6073,7 +6160,7 @@
                         // the next time isConnected is evaluated, it will be false for the dock
                     }
                 } else {
-                    makeA2dpDeviceUnavailableNow(address);
+                    makeA2dpDeviceUnavailableNow(address, deviceSpec.mDeviceCodecFormat);
                 }
             } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
                 if (btDevice.isBluetoothDock()) {
@@ -6085,7 +6172,8 @@
                     // a dock: cancel the dock timeout, and make the dock unavailable now
                     if (hasScheduledA2dpDockTimeout() && mDockAddress != null) {
                         cancelA2dpDeviceTimeout();
-                        makeA2dpDeviceUnavailableNow(mDockAddress);
+                        makeA2dpDeviceUnavailableNow(mDockAddress,
+                                AudioSystem.AUDIO_FORMAT_DEFAULT);
                     }
                 }
                 if (a2dpVolume != -1) {
@@ -6097,13 +6185,18 @@
                     setDeviceVolume(streamState, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
                 }
                 makeA2dpDeviceAvailable(address, btDevice.getName(),
-                        "onSetA2dpSinkConnectionState");
+                        "onSetA2dpSinkConnectionState", a2dpCodec);
             }
         }
     }
 
-    private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
+    private void onSetA2dpSourceConnectionState(BluetoothA2dpDeviceInfo btInfo, int state)
     {
+        if (btInfo == null) {
+            return;
+        }
+        BluetoothDevice btDevice = btInfo.getBtDevice();
+
         if (DEBUG_VOL) {
             Log.d(TAG, "onSetA2dpSourceConnectionState btDevice=" + btDevice + " state=" + state);
         }
@@ -6178,8 +6271,14 @@
         return false;
     }
 
-    private void onBluetoothA2dpDeviceConfigChange(BluetoothDevice btDevice)
+    private void onBluetoothA2dpDeviceConfigChange(BluetoothA2dpDeviceInfo btInfo)
     {
+        if (btInfo == null) {
+            return;
+        }
+        BluetoothDevice btDevice = btInfo.getBtDevice();
+        int a2dpCodec = btInfo.getCodec();
+
         if (DEBUG_DEVICES) {
             Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
         }
@@ -6202,17 +6301,27 @@
             }
             final String key = makeDeviceListKey(device, address);
             final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
-            if (deviceSpec != null) {
-                // Device is connected
-               int musicDevice = getDeviceForStream(AudioSystem.STREAM_MUSIC);
-               if (AudioSystem.handleDeviceConfigChange(device, address,
-                        btDevice.getName()) != AudioSystem.AUDIO_STATUS_OK) {
-                   // force A2DP device disconnection in case of error so that AudioService state is
-                   // consistent with audio policy manager state
-                   setBluetoothA2dpDeviceConnectionStateInt(
-                           btDevice, BluetoothA2dp.STATE_DISCONNECTED, BluetoothProfile.A2DP,
-                           false /* suppressNoisyIntent */, musicDevice, -1 /* a2dpVolume */);
-               }
+            if (deviceSpec == null) {
+                return;
+            }
+            // Device is connected
+            if (deviceSpec.mDeviceCodecFormat != a2dpCodec) {
+                deviceSpec.mDeviceCodecFormat = a2dpCodec;
+                mConnectedDevices.replace(key, deviceSpec);
+            }
+            if (DEBUG_DEVICES) {
+                Log.d(TAG, "onBluetoothA2dpDeviceConfigChange: codec="
+                        + deviceSpec.mDeviceCodecFormat);
+            }
+            if (AudioSystem.handleDeviceConfigChange(device, address,
+                       btDevice.getName(), deviceSpec.mDeviceCodecFormat)
+                       != AudioSystem.AUDIO_STATUS_OK) {
+                int musicDevice = getDeviceForStream(AudioSystem.STREAM_MUSIC);
+                // force A2DP device disconnection in case of error so that AudioService state is
+                // consistent with audio policy manager state
+                setBluetoothA2dpDeviceConnectionStateInt(
+                        btDevice, BluetoothA2dp.STATE_DISCONNECTED, BluetoothProfile.A2DP,
+                        false /* suppressNoisyIntent */, musicDevice, -1 /* a2dpVolume */);
             }
         }
     }
@@ -6245,19 +6354,22 @@
             }
             if (connect && !isConnected) {
                 final int res = AudioSystem.setDeviceConnectionState(device,
-                        AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
+                        AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName,
+                        AudioSystem.AUDIO_FORMAT_DEFAULT);
                 if (res != AudioSystem.AUDIO_STATUS_OK) {
                     Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) +
                             " due to command error " + res );
                     return false;
                 }
-                mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
+                mConnectedDevices.put(deviceKey, new DeviceListSpec(device,
+                                deviceName, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
                 sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
                         device, 0, null, 0);
                 return true;
             } else if (!connect && isConnected) {
                 AudioSystem.setDeviceConnectionState(device,
-                        AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);
+                        AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName,
+                        AudioSystem.AUDIO_FORMAT_DEFAULT);
                 // always remove even if disconnection failed
                 mConnectedDevices.remove(deviceKey);
                 return true;