diff options
author | Paul McLean <pmclean@google.com> | 2015-03-03 10:29:19 -0700 |
---|---|---|
committer | Paul McLean <pmclean@google.com> | 2015-03-10 14:55:30 -0700 |
commit | 394a8e1fa7d2aeeec3d750378c1cb5861a583eeb (patch) | |
tree | 14331da41e51bcac3d33f0de6267b907d250dd1d /services | |
parent | ba4df962972ee271e204d157aa785cb7d0b5d968 (diff) | |
download | frameworks_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.java | 188 | ||||
-rw-r--r-- | services/usb/java/com/android/server/usb/UsbAlsaManager.java | 51 |
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(); |