From 374d5bc0b3fa9ef731ab03ad6c1f1d9bc45eca61 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 16 Oct 2009 09:16:26 -0700 Subject: [PATCH] Bluetooth A2DP suspend-resume improvements. This change will reduce the occurence rate of A2DP sink suspend resume failures observed in issues 2184627, 2181005 and possibly 2189628. More robust suspend/resume logic. Use only the suspend request to audio hardware to avoid having two concurent suspend resume control paths. --- .../android/server/BluetoothA2dpService.java | 93 ++++++------------- 1 file changed, 30 insertions(+), 63 deletions(-) diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java index 9a2d6d94a9348..ec3b2ff7b2c8a 100644 --- a/core/java/android/server/BluetoothA2dpService.java +++ b/core/java/android/server/BluetoothA2dpService.java @@ -72,8 +72,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { private final AudioManager mAudioManager; private final BluetoothService mBluetoothService; private final BluetoothAdapter mAdapter; - private boolean mSuspending; - private boolean mResuming; + private int mTargetA2dpState; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override @@ -151,8 +150,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { if (mBluetoothService.isEnabled()) onBluetoothEnable(); - mSuspending = false; - mResuming = false; + mTargetA2dpState = -1; } @Override @@ -341,10 +339,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { public synchronized boolean suspendSink(BluetoothDevice device) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); - if (DBG) log("suspendSink(" + device + "), mSuspending: "+mSuspending+", mResuming: "+mResuming); - if (mSuspending) { - return true; - } + if (DBG) log("suspendSink(" + device + "), mTargetA2dpState: "+mTargetA2dpState); if (device == null || mAudioDevices == null) { return false; } @@ -353,28 +348,15 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { if (path == null || state == null) { return false; } - switch (state.intValue()) { - case BluetoothA2dp.STATE_CONNECTED: - if (mResuming) { - mSuspending = true; - } - return true; - case BluetoothA2dp.STATE_PLAYING: - mAudioManager.setParameters("A2dpSuspended=true"); - mSuspending = suspendSinkNative(path); - return mSuspending; - default: - return false; - } + + mTargetA2dpState = BluetoothA2dp.STATE_CONNECTED; + return checkSinkSuspendState(state.intValue()); } public synchronized boolean resumeSink(BluetoothDevice device) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); - if (DBG) log("resumeSink(" + device + "), mResuming: "+mResuming+", mSuspending: "+mSuspending); - if (mResuming) { - return true; - } + if (DBG) log("resumeSink(" + device + "), mTargetA2dpState: "+mTargetA2dpState); if (device == null || mAudioDevices == null) { return false; } @@ -383,19 +365,8 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { if (path == null || state == null) { return false; } - switch (state.intValue()) { - case BluetoothA2dp.STATE_PLAYING: - if (mSuspending) { - mResuming = true; - } - return true; - case BluetoothA2dp.STATE_CONNECTED: - mResuming = resumeSinkNative(path); - mAudioManager.setParameters("A2dpSuspended=false"); - return mResuming; - default: - return false; - } + mTargetA2dpState = BluetoothA2dp.STATE_PLAYING; + return checkSinkSuspendState(state.intValue()); } public synchronized BluetoothDevice[] getConnectedSinks() { @@ -458,10 +429,6 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { } private void handleSinkStateChange(BluetoothDevice device, int prevState, int state) { - if (state == BluetoothA2dp.STATE_DISCONNECTED) { - mSuspending = false; - mResuming = false; - } if (state != prevState) { if (state == BluetoothA2dp.STATE_DISCONNECTED || state == BluetoothA2dp.STATE_DISCONNECTING) { @@ -477,28 +444,11 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { } mAudioDevices.put(device, state); - if (state == BluetoothA2dp.STATE_CONNECTED && prevState == BluetoothA2dp.STATE_PLAYING) { - if (DBG) log("handleSinkStateChange() STATE_PLAYING -> STATE_CONNECTED: mSuspending: " - +mSuspending+", mResuming: "+mResuming); - if (mSuspending) { - mSuspending = false; - if (mResuming) { - mResuming = false; - resumeSink(device); - } - } - } - if (state == BluetoothA2dp.STATE_PLAYING && prevState == BluetoothA2dp.STATE_CONNECTED) { - if (DBG) log("handleSinkStateChange() STATE_CONNECTED -> STATE_PLAYING: mSuspending: " - +mSuspending+", mResuming: "+mResuming); + checkSinkSuspendState(state); + mTargetA2dpState = -1; - if (mResuming) { - mResuming = false; - if (mSuspending) { - mSuspending = false; - suspendSink(device); - } - } + if (state == BluetoothA2dp.STATE_CONNECTING) { + mAudioManager.setParameters("A2dpSuspended=false"); } Intent intent = new Intent(BluetoothA2dp.ACTION_SINK_STATE_CHANGED); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); @@ -527,6 +477,23 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { return sinks; } + private boolean checkSinkSuspendState(int state) { + boolean result = true; + + if (state != mTargetA2dpState) { + if (state == BluetoothA2dp.STATE_PLAYING && + mTargetA2dpState == BluetoothA2dp.STATE_CONNECTED) { + mAudioManager.setParameters("A2dpSuspended=true"); + } else if (state == BluetoothA2dp.STATE_CONNECTED && + mTargetA2dpState == BluetoothA2dp.STATE_PLAYING) { + mAudioManager.setParameters("A2dpSuspended=false"); + } else { + result = false; + } + } + return result; + } + @Override protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mAudioDevices.isEmpty()) return;