summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorPaul McLean <pmclean@google.com>2015-03-03 10:29:19 -0700
committerPaul McLean <pmclean@google.com>2015-03-10 14:55:30 -0700
commit394a8e1fa7d2aeeec3d750378c1cb5861a583eeb (patch)
tree14331da41e51bcac3d33f0de6267b907d250dd1d /services
parentba4df962972ee271e204d157aa785cb7d0b5d968 (diff)
downloadframeworks_base-394a8e1fa7d2aeeec3d750378c1cb5861a583eeb.zip
frameworks_base-394a8e1fa7d2aeeec3d750378c1cb5861a583eeb.tar.gz
frameworks_base-394a8e1fa7d2aeeec3d750378c1cb5861a583eeb.tar.bz2
Handle simultaneous connect of devices with the same "type" (as in USB)
Change-Id: I163bf8e33ccf5aacc7ba21775916727430327f18 Bug: 19563570
Diffstat (limited to 'services')
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java188
-rw-r--r--services/usb/java/com/android/server/usb/UsbAlsaManager.java51
2 files changed, 141 insertions, 98 deletions
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 61a7263..fc949e0 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -141,6 +141,9 @@ public class AudioService extends IAudioService.Stub {
/** debug calls to media session apis */
private static final boolean DEBUG_SESSIONS = Log.isLoggable(TAG + ".SESSIONS", Log.DEBUG);
+ /** debug calls to devices APIs */
+ protected static final boolean DEBUG_DEVICES = Log.isLoggable(TAG + ".DEVICES", Log.DEBUG);
+
/** Allow volume changes to set ringer mode to silent? */
private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
@@ -376,7 +379,32 @@ public class AudioService extends IAudioService.Stub {
private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
// Devices currently connected
- private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
+ // Use makeDeviceListKey() to make a unique key for this list.
+ private class DeviceListSpec {
+ int mDeviceType;
+ String mDeviceName;
+ String mDeviceAddress;
+
+ public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
+ mDeviceType = deviceType;
+ mDeviceName = deviceName;
+ mDeviceAddress = deviceAddress;
+ }
+
+ public String toString() {
+ return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
+ + " address:" + mDeviceAddress + "]";
+ }
+ }
+
+ // Generate a unique key for the mConnectedDevices List by composing the device "type"
+ // and the "address" associated with a specific instance of that device type
+ private String makeDeviceListKey(int device, String deviceAddress) {
+ return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
+ }
+
+ private final HashMap<String, DeviceListSpec> mConnectedDevices =
+ new HashMap<String, DeviceListSpec>();
// Forced device usage for communications
private int mForcedUseForComm;
@@ -520,6 +548,8 @@ public class AudioService extends IAudioService.Stub {
return "card=" + card + ";device=" + device + ";";
}
+ private final String DEVICE_NAME_A2DP = "a2dp-device";
+
///////////////////////////////////////////////////////////////////////////
// Construction
///////////////////////////////////////////////////////////////////////////
@@ -2767,14 +2797,17 @@ public class AudioService extends IAudioService.Stub {
}
}
public void onServiceDisconnected(int profile) {
- switch(profile) {
+ switch (profile) {
case BluetoothProfile.A2DP:
synchronized (mConnectedDevices) {
synchronized (mA2dpAvrcpLock) {
- mA2dp = null;
- if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
- makeA2dpDeviceUnavailableNow(
- mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
+ // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
+ for(Map.Entry<String, DeviceListSpec> entry
+ : mConnectedDevices.entrySet()) {
+ DeviceListSpec deviceSpec = entry.getValue();
+ if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
+ makeA2dpDeviceUnavailableNow(deviceSpec.mDeviceAddress);
+ }
}
}
}
@@ -2782,9 +2815,13 @@ public class AudioService extends IAudioService.Stub {
case BluetoothProfile.A2DP_SINK:
synchronized (mConnectedDevices) {
- if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
- makeA2dpSrcUnavailable(
- mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
+ // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
+ for(Map.Entry<String, DeviceListSpec> entry
+ : mConnectedDevices.entrySet()) {
+ DeviceListSpec deviceSpec = entry.getValue();
+ if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
+ makeA2dpSrcUnavailable(deviceSpec.mDeviceAddress);
+ }
}
}
break;
@@ -3272,6 +3309,10 @@ public class AudioService extends IAudioService.Stub {
public void setWiredDeviceConnectionState(int type, int state, String address,
String name) {
synchronized (mConnectedDevices) {
+ if (DEBUG_DEVICES) {
+ Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
+ + address + ")");
+ }
int delay = checkSendBecomingNoisyIntent(type, state);
queueMsgUnderWakeLock(mAudioHandler,
MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
@@ -4236,13 +4277,13 @@ public class AudioService extends IAudioService.Stub {
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
setBluetoothA2dpOnInt(true);
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- AudioSystem.DEVICE_STATE_AVAILABLE,
- address,
- "a2dp-device");
+ AudioSystem.DEVICE_STATE_AVAILABLE, address, DEVICE_NAME_A2DP);
// Reset A2DP suspend state each time a new sink is connected
AudioSystem.setParameters("A2dpSuspended=false");
- mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
- address);
+ mConnectedDevices.put(
+ makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
+ new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, DEVICE_NAME_A2DP,
+ address));
}
private void onSendBecomingNoisyIntent() {
@@ -4255,10 +4296,9 @@ public class AudioService extends IAudioService.Stub {
mAvrcpAbsVolSupported = false;
}
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- AudioSystem.DEVICE_STATE_UNAVAILABLE,
- address,
- "a2dp-device");
- mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+ AudioSystem.DEVICE_STATE_UNAVAILABLE, address, DEVICE_NAME_A2DP);
+ mConnectedDevices.remove(
+ makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
synchronized (mCurAudioRoutes) {
// Remove A2DP routes as well
if (mCurAudioRoutes.bluetoothName != null) {
@@ -4275,7 +4315,8 @@ public class AudioService extends IAudioService.Stub {
// reconnection of the sink.
AudioSystem.setParameters("A2dpSuspended=true");
// the device will be made unavailable later, so consider it disconnected right away
- mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+ mConnectedDevices.remove(
+ makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
// send the delayed message to make the device unavailable later
Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
@@ -4285,20 +4326,19 @@ public class AudioService extends IAudioService.Stub {
// must be called synchronized on mConnectedDevices
private void makeA2dpSrcAvailable(String address) {
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
- AudioSystem.DEVICE_STATE_AVAILABLE,
- address,
- "a2dp-device");
- mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
- address);
+ AudioSystem.DEVICE_STATE_AVAILABLE, address, DEVICE_NAME_A2DP);
+ mConnectedDevices.put(
+ makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
+ new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, DEVICE_NAME_A2DP,
+ address));
}
// must be called synchronized on mConnectedDevices
private void makeA2dpSrcUnavailable(String address) {
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
- AudioSystem.DEVICE_STATE_UNAVAILABLE,
- address,
- "a2dp-device");
- mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
+ AudioSystem.DEVICE_STATE_UNAVAILABLE, address, DEVICE_NAME_A2DP);
+ mConnectedDevices.remove(
+ makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
}
// must be called synchronized on mConnectedDevices
@@ -4325,9 +4365,10 @@ public class AudioService extends IAudioService.Stub {
}
synchronized (mConnectedDevices) {
- boolean isConnected =
- (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
- mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
+ String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+ btDevice.getAddress());
+ DeviceListSpec deviceSpec = mConnectedDevices.get(key);
+ boolean isConnected = deviceSpec != null;
if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
if (btDevice.isBluetoothDock()) {
@@ -4388,9 +4429,9 @@ public class AudioService extends IAudioService.Stub {
}
synchronized (mConnectedDevices) {
- boolean isConnected =
- (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
- mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
+ String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
+ DeviceListSpec deviceSpec = mConnectedDevices.get(key);
+ boolean isConnected = deviceSpec != null;
if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
makeA2dpSrcUnavailable(address);
@@ -4413,27 +4454,32 @@ public class AudioService extends IAudioService.Stub {
}
}
- private boolean handleDeviceConnection(boolean connect, int device, String address, String deviceName) {
- Slog.i(TAG, "handleDeviceConnection(" + connect +
- " dev:" + Integer.toHexString(device) +
- " address:" + address +
- " name:" + deviceName + ")");
+ private boolean handleDeviceConnection(boolean connect, int device, String address,
+ String deviceName) {
+ if (DEBUG_DEVICES) {
+ Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device)
+ + " address:" + address + " name:" + deviceName + ")");
+ }
synchronized (mConnectedDevices) {
- boolean isConnected = (mConnectedDevices.containsKey(device) &&
- (address.isEmpty() || mConnectedDevices.get(device).equals(address)));
-
- if (isConnected && !connect) {
- AudioSystem.setDeviceConnectionState(device,
- AudioSystem.DEVICE_STATE_UNAVAILABLE,
- address, deviceName);
- mConnectedDevices.remove(device);
- return true;
- } else if (!isConnected && connect) {
- AudioSystem.setDeviceConnectionState(device,
- AudioSystem.DEVICE_STATE_AVAILABLE,
- address, deviceName);
- mConnectedDevices.put(new Integer(device), address);
- return true;
+ String deviceKey = makeDeviceListKey(device, address);
+ if (DEBUG_DEVICES) {
+ Slog.i(TAG, "deviceKey:" + deviceKey);
+ }
+ DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
+ boolean isConnected = deviceSpec != null;
+ if (DEBUG_DEVICES) {
+ Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
+ }
+ if (connect && !isConnected) {
+ AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE,
+ address, deviceName);
+ mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
+ return true;
+ } else if (!connect && isConnected) {
+ AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ address, deviceName);
+ mConnectedDevices.remove(deviceKey);
+ return true;
}
}
return false;
@@ -4454,10 +4500,11 @@ public class AudioService extends IAudioService.Stub {
int delay = 0;
if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
int devices = 0;
- for (int dev : mConnectedDevices.keySet()) {
- if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) &&
- ((dev & mBecomingNoisyIntentDevices) != 0)) {
- devices |= dev;
+ for (String key : mConnectedDevices.keySet()) {
+ int dev = mConnectedDevices.get(key).mDeviceType;
+ if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
+ && ((dev & mBecomingNoisyIntentDevices) != 0)) {
+ devices |= dev;
}
}
if (devices == device) {
@@ -4485,12 +4532,13 @@ public class AudioService extends IAudioService.Stub {
return delay;
}
- private void sendDeviceConnectionIntent(int device, int state, String address, String deviceName)
- {
- Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
- " state:0x" + Integer.toHexString(state) +
- " address:" + address +
- " name:" + deviceName + ");");
+ private void sendDeviceConnectionIntent(int device, int state, String address,
+ String deviceName) {
+ if (DEBUG_DEVICES) {
+ Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
+ " state:0x" + Integer.toHexString(state) + " address:" + address +
+ " name:" + deviceName + ");");
+ }
Intent intent = new Intent();
intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
@@ -4544,12 +4592,12 @@ public class AudioService extends IAudioService.Stub {
}
private void onSetWiredDeviceConnectionState(int device, int state, String address,
- String deviceName)
- {
- Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
- + " state:" + Integer.toHexString(state)
- + " address:" + address
- + " deviceName:" + deviceName + ");");
+ String deviceName) {
+ if (DEBUG_DEVICES) {
+ Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device) +
+ " state:" + Integer.toHexString(state) + " address:" + address +
+ " deviceName:" + deviceName + ");");
+ }
synchronized (mConnectedDevices) {
if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 3f180e7..b0e30b5 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -73,8 +73,6 @@ public final class UsbAlsaManager {
private UsbAudioDevice mAccessoryAudioDevice = null;
- private UsbAudioDevice mSelectedAudioDevice = null;
-
// UsbMidiDevice for USB peripheral mode (gadget) device
private UsbMidiDevice mPeripheralMidiDevice = null;
@@ -186,6 +184,10 @@ public final class UsbAlsaManager {
int device = (audioDevice == mAccessoryAudioDevice ?
AudioSystem.DEVICE_OUT_USB_ACCESSORY :
AudioSystem.DEVICE_OUT_USB_DEVICE);
+ if (DEBUG) {
+ Slog.i(TAG, "pre-call device:0x" + Integer.toHexString(device) +
+ " addr:" + address + " name:" + audioDevice.mDeviceName);
+ }
mAudioService.setWiredDeviceConnectionState(
device, state, address, audioDevice.mDeviceName);
}
@@ -282,23 +284,13 @@ public final class UsbAlsaManager {
/*
* Select the default device of the specified card.
*/
- /* package */ boolean selectAudioCard(int card) {
+ /* package */ UsbAudioDevice selectAudioCard(int card) {
if (DEBUG) {
Slog.d(TAG, "selectAudioCard() card:" + card);
}
if (!mCardsParser.isCardUsb(card)) {
// Don't. AudioPolicyManager has logic for falling back to internal devices.
- return false;
- }
-
- if (mSelectedAudioDevice != null) {
- if (mSelectedAudioDevice.mCard == card) {
- // Nothing to do here.
- return false;
- }
- // "disconnect" the AudioPolicyManager from the previously selected device.
- notifyDeviceState(mSelectedAudioDevice, false);
- mSelectedAudioDevice = null;
+ return null;
}
mDevicesParser.scan();
@@ -314,30 +306,30 @@ public final class UsbAlsaManager {
// Playback device file needed/present?
if (hasPlayback && (waitForAlsaDevice(card, device, AlsaDevice.TYPE_PLAYBACK) == null)) {
- return false;
+ return null;
}
// Capture device file needed/present?
if (hasCapture && (waitForAlsaDevice(card, device, AlsaDevice.TYPE_CAPTURE) == null)) {
- return false;
+ return null;
}
if (DEBUG) {
Slog.d(TAG, "usb: hasPlayback:" + hasPlayback + " hasCapture:" + hasCapture);
}
- mSelectedAudioDevice =
+ UsbAudioDevice audioDevice =
new UsbAudioDevice(card, device, hasPlayback, hasCapture, deviceClass);
- mSelectedAudioDevice.mDeviceName = mCardsParser.getCardRecordFor(card).mCardName;
- mSelectedAudioDevice.mDeviceDescription =
- mCardsParser.getCardRecordFor(card).mCardDescription;
+ AlsaCardsParser.AlsaCardRecord cardRecord = mCardsParser.getCardRecordFor(card);
+ audioDevice.mDeviceName = cardRecord.mCardName;
+ audioDevice.mDeviceDescription = cardRecord.mCardDescription;
- notifyDeviceState(mSelectedAudioDevice, true);
+ notifyDeviceState(audioDevice, true);
- return true;
+ return audioDevice;
}
- /* package */ boolean selectDefaultDevice() {
+ /* package */ UsbAudioDevice selectDefaultDevice() {
if (DEBUG) {
Slog.d(TAG, "UsbAudioManager.selectDefaultDevice()");
}
@@ -347,7 +339,8 @@ public final class UsbAlsaManager {
/* package */ void usbDeviceAdded(UsbDevice usbDevice) {
if (DEBUG) {
- Slog.d(TAG, "usbDeviceAdded(): " + usbDevice);
+ Slog.d(TAG, "deviceAdded(): " + usbDevice.getManufacturerName() +
+ "nm:" + usbDevice.getProductName());
}
// Is there an audio interface in there?
@@ -384,8 +377,10 @@ public final class UsbAlsaManager {
// If the default isn't a USB device, let the existing "select internal mechanism"
// handle the selection.
if (mCardsParser.isCardUsb(addedCard)) {
- selectAudioCard(addedCard);
- mAudioDevices.put(usbDevice, mSelectedAudioDevice);
+ UsbAudioDevice audioDevice = selectAudioCard(addedCard);
+ if (audioDevice != null) {
+ mAudioDevices.put(usbDevice, audioDevice);
+ }
// look for MIDI devices
@@ -420,14 +415,14 @@ public final class UsbAlsaManager {
/* package */ void usbDeviceRemoved(UsbDevice usbDevice) {
if (DEBUG) {
- Slog.d(TAG, "deviceRemoved(): " + usbDevice);
+ Slog.d(TAG, "deviceRemoved(): " + usbDevice.getManufacturerName() +
+ " " + usbDevice.getProductName());
}
UsbAudioDevice audioDevice = mAudioDevices.remove(usbDevice);
if (audioDevice != null) {
if (audioDevice.mHasPlayback || audioDevice.mHasPlayback) {
notifyDeviceState(audioDevice, false);
- mSelectedAudioDevice = null;
// if there any external devices left, select one of them
selectDefaultDevice();