summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/usb/java/com/android/server/usb/UsbAlsaDevice.java256
-rw-r--r--services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java3
-rw-r--r--services/usb/java/com/android/server/usb/UsbAlsaManager.java147
3 files changed, 281 insertions, 125 deletions
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
index 337e1f92050c..7fe8582f96de 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
@@ -27,6 +27,8 @@ import android.util.Slog;
import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.server.audio.AudioService;
+import java.util.Arrays;
+
/**
* Represents the ALSA specification, and attributes of an ALSA device.
*/
@@ -36,17 +38,21 @@ public final class UsbAlsaDevice {
private final int mCardNum;
private final int mDeviceNum;
+ private final String mAlsaCardDeviceString;
private final String mDeviceAddress;
- private final boolean mHasOutput;
- private final boolean mHasInput;
- private final boolean mIsInputHeadset;
- private final boolean mIsOutputHeadset;
- private final boolean mIsDock;
+ // The following two constant will be used as index to access arrays.
+ private static final int INPUT = 0;
+ private static final int OUTPUT = 1;
+ private static final int NUM_DIRECTIONS = 2;
+ private static final String[] DIRECTION_STR = {"INPUT", "OUTPUT"};
+ private final boolean[] mHasDevice = new boolean[NUM_DIRECTIONS];
- private boolean mSelected = false;
- private int mOutputState;
- private int mInputState;
+ private final boolean[] mIsHeadset = new boolean[NUM_DIRECTIONS];
+ private final boolean mIsDock;
+ private final int[] mDeviceType = new int[NUM_DIRECTIONS];
+ private boolean[] mIsSelected = new boolean[NUM_DIRECTIONS];
+ private int[] mState = new int[NUM_DIRECTIONS];
private UsbAlsaJackDetector mJackDetector;
private IAudioService mAudioService;
@@ -60,11 +66,13 @@ public final class UsbAlsaDevice {
mCardNum = card;
mDeviceNum = device;
mDeviceAddress = deviceAddress;
- mHasOutput = hasOutput;
- mHasInput = hasInput;
- mIsInputHeadset = isInputHeadset;
- mIsOutputHeadset = isOutputHeadset;
+ mHasDevice[OUTPUT] = hasOutput;
+ mHasDevice[INPUT] = hasInput;
+ mIsHeadset[INPUT] = isInputHeadset;
+ mIsHeadset[OUTPUT] = isOutputHeadset;
mIsDock = isDock;
+ initDeviceType();
+ mAlsaCardDeviceString = getAlsaCardDeviceString();
}
/**
@@ -104,28 +112,28 @@ public final class UsbAlsaDevice {
* @return true if the device supports output.
*/
public boolean hasOutput() {
- return mHasOutput;
+ return mHasDevice[OUTPUT];
}
/**
* @return true if the device supports input (recording).
*/
public boolean hasInput() {
- return mHasInput;
+ return mHasDevice[INPUT];
}
/**
- * @return true if the device is a headset for purposes of input.
+ * @return true if the device is a headset for purposes of output.
*/
- public boolean isInputHeadset() {
- return mIsInputHeadset;
+ public boolean isOutputHeadset() {
+ return mIsHeadset[OUTPUT];
}
/**
- * @return true if the device is a headset for purposes of output.
+ * @return true if the device is a headset for purposes of input.
*/
- public boolean isOutputHeadset() {
- return mIsOutputHeadset;
+ public boolean isInputHeadset() {
+ return mIsHeadset[INPUT];
}
/**
@@ -157,6 +165,9 @@ public final class UsbAlsaDevice {
/** Begins a jack-detection thread. */
private synchronized void startJackDetect() {
+ if (mJackDetector != null) {
+ return;
+ }
// If no jack detect capabilities exist, mJackDetector will be null.
mJackDetector = UsbAlsaJackDetector.startJackDetect(this);
}
@@ -171,75 +182,152 @@ public final class UsbAlsaDevice {
/** Start using this device as the selected USB Audio Device. */
public synchronized void start() {
- mSelected = true;
- mInputState = 0;
- mOutputState = 0;
+ startInput();
+ startOutput();
+ }
+
+ /** Start using this device as the selected USB input device. */
+ public synchronized void startInput() {
+ startDevice(INPUT);
+ }
+
+ /** Start using this device as selected USB output device. */
+ public synchronized void startOutput() {
+ startDevice(OUTPUT);
+ }
+
+ private void startDevice(int direction) {
+ if (mIsSelected[direction]) {
+ return;
+ }
+ mIsSelected[direction] = true;
+ mState[direction] = 0;
startJackDetect();
- updateWiredDeviceConnectionState(true);
+ updateWiredDeviceConnectionState(direction, true /*enable*/);
}
/** Stop using this device as the selected USB Audio Device. */
public synchronized void stop() {
- stopJackDetect();
- updateWiredDeviceConnectionState(false);
- mSelected = false;
+ stopInput();
+ stopOutput();
}
- /** Updates AudioService with the connection state of the alsaDevice.
- * Checks ALSA Jack state for inputs and outputs before reporting.
- */
- public synchronized void updateWiredDeviceConnectionState(boolean enable) {
- if (!mSelected) {
- Slog.e(TAG, "updateWiredDeviceConnectionState on unselected AlsaDevice!");
+ /** Stop using this device as the selected USB input device. */
+ public synchronized void stopInput() {
+ if (!mIsSelected[INPUT]) {
return;
}
- String alsaCardDeviceString = getAlsaCardDeviceString();
- if (alsaCardDeviceString == null) {
+ if (!mIsSelected[OUTPUT]) {
+ // Stop jack detection when both input and output are stopped
+ stopJackDetect();
+ }
+ updateInputWiredDeviceConnectionState(false /*enable*/);
+ mIsSelected[INPUT] = false;
+ }
+
+ /** Stop using this device as the selected USB output device. */
+ public synchronized void stopOutput() {
+ if (!mIsSelected[OUTPUT]) {
return;
}
- try {
- // Output Device
- if (mHasOutput) {
- int device = mIsDock ? AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET
- : (mIsOutputHeadset
- ? AudioSystem.DEVICE_OUT_USB_HEADSET
- : AudioSystem.DEVICE_OUT_USB_DEVICE);
- if (DEBUG) {
- Slog.d(TAG, "pre-call device:0x" + Integer.toHexString(device)
- + " addr:" + alsaCardDeviceString
- + " name:" + mDeviceName);
- }
- boolean connected = isOutputJackConnected();
- Slog.i(TAG, "OUTPUT JACK connected: " + connected);
- int outputState = (enable && connected) ? 1 : 0;
- if (outputState != mOutputState) {
- mOutputState = outputState;
- AudioDeviceAttributes attributes = new AudioDeviceAttributes(device,
- alsaCardDeviceString, mDeviceName);
- mAudioService.setWiredDeviceConnectionState(attributes, outputState, TAG);
- }
- }
+ if (!mIsSelected[INPUT]) {
+ // Stop jack detection when both input and output are stopped
+ stopJackDetect();
+ }
+ updateOutputWiredDeviceConnectionState(false /*enable*/);
+ mIsSelected[OUTPUT] = false;
+ }
+
+ private void initDeviceType() {
+ mDeviceType[INPUT] = mHasDevice[INPUT]
+ ? (mIsHeadset[INPUT] ? AudioSystem.DEVICE_IN_USB_HEADSET
+ : AudioSystem.DEVICE_IN_USB_DEVICE)
+ : AudioSystem.DEVICE_NONE;
+ mDeviceType[OUTPUT] = mHasDevice[OUTPUT]
+ ? (mIsDock ? AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET
+ : (mIsHeadset[OUTPUT] ? AudioSystem.DEVICE_OUT_USB_HEADSET
+ : AudioSystem.DEVICE_OUT_USB_DEVICE))
+ : AudioSystem.DEVICE_NONE;
+ }
- // Input Device
- if (mHasInput) {
- int device = mIsInputHeadset
- ? AudioSystem.DEVICE_IN_USB_HEADSET
- : AudioSystem.DEVICE_IN_USB_DEVICE;
- boolean connected = isInputJackConnected();
- Slog.i(TAG, "INPUT JACK connected: " + connected);
- int inputState = (enable && connected) ? 1 : 0;
- if (inputState != mInputState) {
- mInputState = inputState;
- AudioDeviceAttributes attributes = new AudioDeviceAttributes(device,
- alsaCardDeviceString, mDeviceName);
- mAudioService.setWiredDeviceConnectionState(attributes, inputState, TAG);
- }
+ /**
+ * @return the output device type that will be used to notify AudioService about device
+ * connection. If there is no output on this device, {@link AudioSystem#DEVICE_NONE}
+ * will be returned.
+ */
+ public int getOutputDeviceType() {
+ return mDeviceType[OUTPUT];
+ }
+
+ /**
+ * @return the input device type that will be used to notify AudioService about device
+ * connection. If there is no input on this device, {@link AudioSystem#DEVICE_NONE}
+ * will be returned.
+ */
+ public int getInputDeviceType() {
+ return mDeviceType[INPUT];
+ }
+
+ private boolean updateWiredDeviceConnectionState(int direction, boolean enable) {
+ if (!mIsSelected[direction]) {
+ Slog.e(TAG, "Updating wired device connection state on unselected device");
+ return false;
+ }
+ if (mDeviceType[direction] == AudioSystem.DEVICE_NONE) {
+ Slog.d(TAG,
+ "Unable to set device connection state as " + DIRECTION_STR[direction]
+ + " device type is none");
+ return false;
+ }
+ if (mAlsaCardDeviceString == null) {
+ Slog.w(TAG, "Failed to update " + DIRECTION_STR[direction] + " device connection "
+ + "state failed as alsa card device string is null");
+ return false;
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "pre-call device:0x" + Integer.toHexString(mDeviceType[direction])
+ + " addr:" + mAlsaCardDeviceString
+ + " name:" + mDeviceName);
+ }
+ boolean connected = direction == INPUT ? isInputJackConnected() : isOutputJackConnected();
+ Slog.i(TAG, DIRECTION_STR[direction] + " JACK connected: " + connected);
+ int state = (enable && connected) ? 1 : 0;
+ if (state != mState[direction]) {
+ mState[direction] = state;
+ AudioDeviceAttributes attributes = new AudioDeviceAttributes(
+ mDeviceType[direction], mAlsaCardDeviceString, mDeviceName);
+ try {
+ mAudioService.setWiredDeviceConnectionState(attributes, state, TAG);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException in setWiredDeviceConnectionState for "
+ + DIRECTION_STR[direction]);
+ return false;
}
- } catch (RemoteException e) {
- Slog.e(TAG, "RemoteException in setWiredDeviceConnectionState");
}
+ return true;
}
+ /**
+ * Notify AudioService about the input device connection state.
+ *
+ * @param enable true to notify the device as connected.
+ * @return true only when it successfully notifies AudioService about the device
+ * connection state.
+ */
+ public synchronized boolean updateInputWiredDeviceConnectionState(boolean enable) {
+ return updateWiredDeviceConnectionState(INPUT, enable);
+ }
+
+ /**
+ * Notify AudioService about the output device connection state.
+ *
+ * @param enable true to notify the device as connected.
+ * @return true only when it successfully notifies AudioService about the device
+ * connection state.
+ */
+ public synchronized boolean updateOutputWiredDeviceConnectionState(boolean enable) {
+ return updateWiredDeviceConnectionState(OUTPUT, enable);
+ }
/**
* @Override
@@ -249,8 +337,8 @@ public final class UsbAlsaDevice {
return "UsbAlsaDevice: [card: " + mCardNum
+ ", device: " + mDeviceNum
+ ", name: " + mDeviceName
- + ", hasOutput: " + mHasOutput
- + ", hasInput: " + mHasInput + "]";
+ + ", hasOutput: " + mHasDevice[OUTPUT]
+ + ", hasInput: " + mHasDevice[INPUT] + "]";
}
/**
@@ -262,8 +350,8 @@ public final class UsbAlsaDevice {
dump.write("card", UsbAlsaDeviceProto.CARD, mCardNum);
dump.write("device", UsbAlsaDeviceProto.DEVICE, mDeviceNum);
dump.write("name", UsbAlsaDeviceProto.NAME, mDeviceName);
- dump.write("has_output", UsbAlsaDeviceProto.HAS_PLAYBACK, mHasOutput);
- dump.write("has_input", UsbAlsaDeviceProto.HAS_CAPTURE, mHasInput);
+ dump.write("has_output", UsbAlsaDeviceProto.HAS_PLAYBACK, mHasDevice[OUTPUT]);
+ dump.write("has_input", UsbAlsaDeviceProto.HAS_CAPTURE, mHasDevice[INPUT]);
dump.write("address", UsbAlsaDeviceProto.ADDRESS, mDeviceAddress);
dump.end(token);
@@ -294,10 +382,8 @@ public final class UsbAlsaDevice {
UsbAlsaDevice other = (UsbAlsaDevice) obj;
return (mCardNum == other.mCardNum
&& mDeviceNum == other.mDeviceNum
- && mHasOutput == other.mHasOutput
- && mHasInput == other.mHasInput
- && mIsInputHeadset == other.mIsInputHeadset
- && mIsOutputHeadset == other.mIsOutputHeadset
+ && Arrays.equals(mHasDevice, other.mHasDevice)
+ && Arrays.equals(mIsHeadset, other.mIsHeadset)
&& mIsDock == other.mIsDock);
}
@@ -310,10 +396,10 @@ public final class UsbAlsaDevice {
int result = 1;
result = prime * result + mCardNum;
result = prime * result + mDeviceNum;
- result = prime * result + (mHasOutput ? 0 : 1);
- result = prime * result + (mHasInput ? 0 : 1);
- result = prime * result + (mIsInputHeadset ? 0 : 1);
- result = prime * result + (mIsOutputHeadset ? 0 : 1);
+ result = prime * result + (mHasDevice[OUTPUT] ? 0 : 1);
+ result = prime * result + (mHasDevice[INPUT] ? 0 : 1);
+ result = prime * result + (mIsHeadset[INPUT] ? 0 : 1);
+ result = prime * result + (mIsHeadset[OUTPUT] ? 0 : 1);
result = prime * result + (mIsDock ? 0 : 1);
return result;
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java b/services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java
index c4988478df71..d4f0b59dd7f2 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java
@@ -81,7 +81,8 @@ public final class UsbAlsaJackDetector implements Runnable {
if (mStopJackDetect) {
return false;
}
- mAlsaDevice.updateWiredDeviceConnectionState(true);
+ mAlsaDevice.updateOutputWiredDeviceConnectionState(true);
+ mAlsaDevice.updateInputWiredDeviceConnectionState(true);
}
return true;
}
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index aa1d556d02d3..99881e194b07 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -20,12 +20,14 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.hardware.usb.UsbDevice;
+import android.media.AudioManager;
import android.media.IAudioService;
import android.media.midi.MidiDeviceInfo;
import android.os.Bundle;
import android.os.FileObserver;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.provider.Settings;
import android.service.usb.UsbAlsaManagerProto;
import android.util.Slog;
@@ -42,6 +44,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Stack;
/**
* UsbAlsaManager manages USB audio and MIDI devices.
@@ -51,8 +54,9 @@ public final class UsbAlsaManager {
private static final boolean DEBUG = false;
// Flag to turn on/off multi-peripheral select mode
- // Set to true to have single-device-only mode
- private static final boolean mIsSingleMode = true;
+ // Set to true to have multi-devices mode
+ private static final boolean IS_MULTI_MODE = SystemProperties.getBoolean(
+ "ro.audio.multi_usb_mode", false /*def*/);
private static final String ALSA_DIRECTORY = "/dev/snd/";
@@ -70,7 +74,11 @@ public final class UsbAlsaManager {
// this is needed to map USB devices to ALSA Audio Devices, especially to remove an
// ALSA device when we are notified that its associated USB device has been removed.
private final ArrayList<UsbAlsaDevice> mAlsaDevices = new ArrayList<UsbAlsaDevice>();
- private UsbAlsaDevice mSelectedDevice;
+ // A map from device type to attached devices. Given the audio framework only supports
+ // single device connection per device type, only the last attached device will be
+ // connected to audio framework. Once the last device is removed, previous device can
+ // be connected to audio framework.
+ private HashMap<Integer, Stack<UsbAlsaDevice>> mAttachedDevices = new HashMap<>();
//
// Device Denylist
@@ -162,11 +170,6 @@ public final class UsbAlsaManager {
Slog.d(TAG, "selectAlsaDevice() " + alsaDevice);
}
- // This must be where an existing USB audio device is deselected.... (I think)
- if (mIsSingleMode && mSelectedDevice != null) {
- deselectAlsaDevice();
- }
-
// FIXME Does not yet handle the case where the setting is changed
// after device connection. Ideally we should handle the settings change
// in SettingsObserver. Here we should log that a USB device is connected
@@ -178,21 +181,18 @@ public final class UsbAlsaManager {
return;
}
- mSelectedDevice = alsaDevice;
alsaDevice.start();
+
if (DEBUG) {
Slog.d(TAG, "selectAlsaDevice() - done.");
}
}
- private synchronized void deselectAlsaDevice() {
+ private synchronized void deselectAlsaDevice(UsbAlsaDevice selectedDevice) {
if (DEBUG) {
- Slog.d(TAG, "deselectAlsaDevice() mSelectedDevice " + mSelectedDevice);
- }
- if (mSelectedDevice != null) {
- mSelectedDevice.stop();
- mSelectedDevice = null;
+ Slog.d(TAG, "deselectAlsaDevice() selectedDevice " + selectedDevice);
}
+ selectedDevice.stop();
}
private int getAlsaDeviceListIndexFor(String deviceAddress) {
@@ -204,32 +204,86 @@ public final class UsbAlsaManager {
return -1;
}
- private UsbAlsaDevice removeAlsaDeviceFromList(String deviceAddress) {
+ private void addDeviceToAttachedDevicesMap(int deviceType, UsbAlsaDevice device) {
+ if (deviceType == AudioManager.DEVICE_NONE) {
+ Slog.i(TAG, "Ignore caching device as the type is NONE, device=" + device);
+ return;
+ }
+ Stack<UsbAlsaDevice> devices = mAttachedDevices.get(deviceType);
+ if (devices == null) {
+ mAttachedDevices.put(deviceType, new Stack<>());
+ devices = mAttachedDevices.get(deviceType);
+ }
+ devices.push(device);
+ }
+
+ private void addAlsaDevice(UsbAlsaDevice device) {
+ mAlsaDevices.add(0, device);
+ addDeviceToAttachedDevicesMap(device.getInputDeviceType(), device);
+ addDeviceToAttachedDevicesMap(device.getOutputDeviceType(), device);
+ }
+
+ private void removeDeviceFromAttachedDevicesMap(int deviceType, UsbAlsaDevice device) {
+ Stack<UsbAlsaDevice> devices = mAttachedDevices.get(deviceType);
+ if (devices == null) {
+ return;
+ }
+ devices.remove(device);
+ if (devices.isEmpty()) {
+ mAttachedDevices.remove(deviceType);
+ }
+ }
+
+ private UsbAlsaDevice removeAlsaDevice(String deviceAddress) {
int index = getAlsaDeviceListIndexFor(deviceAddress);
if (index > -1) {
- return mAlsaDevices.remove(index);
+ UsbAlsaDevice device = mAlsaDevices.remove(index);
+ removeDeviceFromAttachedDevicesMap(device.getOutputDeviceType(), device);
+ removeDeviceFromAttachedDevicesMap(device.getInputDeviceType(), device);
+ return device;
} else {
return null;
}
}
- /* package */ UsbAlsaDevice selectDefaultDevice() {
+ private UsbAlsaDevice selectDefaultDevice(int deviceType) {
if (DEBUG) {
- Slog.d(TAG, "selectDefaultDevice()");
+ Slog.d(TAG, "selectDefaultDevice():" + deviceType);
}
- if (mAlsaDevices.size() > 0) {
- UsbAlsaDevice alsaDevice = mAlsaDevices.get(0);
- if (DEBUG) {
- Slog.d(TAG, " alsaDevice:" + alsaDevice);
- }
- if (alsaDevice != null) {
- selectAlsaDevice(alsaDevice);
- }
- return alsaDevice;
- } else {
+ Stack<UsbAlsaDevice> devices = mAttachedDevices.get(deviceType);
+ if (devices == null || devices.isEmpty()) {
return null;
}
+ UsbAlsaDevice alsaDevice = devices.peek();
+ Slog.d(TAG, "select default device:" + alsaDevice);
+ if (AudioManager.isInputDevice(deviceType)) {
+ alsaDevice.startInput();
+ } else {
+ alsaDevice.startOutput();
+ }
+ return alsaDevice;
+ }
+
+ private void deselectCurrentDevice(int deviceType) {
+ if (DEBUG) {
+ Slog.d(TAG, "deselectCurrentDevice():" + deviceType);
+ }
+ if (deviceType == AudioManager.DEVICE_NONE) {
+ return;
+ }
+
+ Stack<UsbAlsaDevice> devices = mAttachedDevices.get(deviceType);
+ if (devices == null || devices.isEmpty()) {
+ return;
+ }
+ UsbAlsaDevice alsaDevice = devices.peek();
+ Slog.d(TAG, "deselect current device:" + alsaDevice);
+ if (AudioManager.isInputDevice(deviceType)) {
+ alsaDevice.stopInput();
+ } else {
+ alsaDevice.stopOutput();
+ }
}
/* package */ void usbDeviceAdded(String deviceAddress, UsbDevice usbDevice,
@@ -246,6 +300,7 @@ public final class UsbAlsaManager {
AlsaCardsParser.AlsaCardRecord cardRec =
mCardsParser.findCardNumFor(deviceAddress);
if (cardRec == null) {
+ Slog.e(TAG, "usbDeviceAdded(): cannot find sound card for " + deviceAddress);
return;
}
@@ -275,12 +330,19 @@ public final class UsbAlsaManager {
new UsbAlsaDevice(mAudioService, cardRec.getCardNum(), 0 /*device*/,
deviceAddress, hasOutput, hasInput,
isInputHeadset, isOutputHeadset, isDock);
- if (alsaDevice != null) {
- alsaDevice.setDeviceNameAndDescription(
- cardRec.getCardName(), cardRec.getCardDescription());
- mAlsaDevices.add(0, alsaDevice);
- selectAlsaDevice(alsaDevice);
+ alsaDevice.setDeviceNameAndDescription(
+ cardRec.getCardName(), cardRec.getCardDescription());
+ if (IS_MULTI_MODE) {
+ deselectCurrentDevice(alsaDevice.getInputDeviceType());
+ deselectCurrentDevice(alsaDevice.getOutputDeviceType());
+ } else {
+ // At single mode, the first device is the selected device.
+ if (!mAlsaDevices.isEmpty()) {
+ deselectAlsaDevice(mAlsaDevices.get(0));
+ }
}
+ addAlsaDevice(alsaDevice);
+ selectAlsaDevice(alsaDevice);
}
addMidiDevice(deviceAddress, usbDevice, parser, cardRec);
@@ -346,12 +408,20 @@ public final class UsbAlsaManager {
}
// Audio
- UsbAlsaDevice alsaDevice = removeAlsaDeviceFromList(deviceAddress);
+ UsbAlsaDevice alsaDevice = removeAlsaDevice(deviceAddress);
Slog.i(TAG, "USB Audio Device Removed: " + alsaDevice);
- if (alsaDevice != null && alsaDevice == mSelectedDevice) {
+ if (alsaDevice != null) {
waitForAlsaDevice(alsaDevice.getCardNum(), false /*isAdded*/);
- deselectAlsaDevice();
- selectDefaultDevice(); // if there any external devices left, select one of them
+ deselectAlsaDevice(alsaDevice);
+ if (IS_MULTI_MODE) {
+ selectDefaultDevice(alsaDevice.getOutputDeviceType());
+ selectDefaultDevice(alsaDevice.getInputDeviceType());
+ } else {
+ // If there are any external devices left, select the latest attached one
+ if (!mAlsaDevices.isEmpty() && mAlsaDevices.get(0) != null) {
+ selectAlsaDevice(mAlsaDevices.get(0));
+ }
+ }
}
// MIDI
@@ -362,7 +432,6 @@ public final class UsbAlsaManager {
}
logDevices("usbDeviceRemoved()");
-
}
/* package */ void setPeripheralMidiState(boolean enabled, int card, int device) {