Merge "Multiple USB support." into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
739b95b7c5
@@ -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;
|
||||
// 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 final boolean[] mIsHeadset = new boolean[NUM_DIRECTIONS];
|
||||
private final boolean mIsDock;
|
||||
|
||||
private boolean mSelected = false;
|
||||
private int mOutputState;
|
||||
private int mInputState;
|
||||
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 true if the device is a headset for purposes of input.
|
||||
*/
|
||||
public boolean isInputHeadset() {
|
||||
return mIsInputHeadset;
|
||||
return mHasDevice[INPUT];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the device is a headset for purposes of output.
|
||||
*/
|
||||
public boolean isOutputHeadset() {
|
||||
return mIsOutputHeadset;
|
||||
return mIsHeadset[OUTPUT];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the device is a headset for purposes of input.
|
||||
*/
|
||||
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.
|
||||
/** Stop using this device as the selected USB input device. */
|
||||
public synchronized void stopInput() {
|
||||
if (!mIsSelected[INPUT]) {
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 synchronized void updateWiredDeviceConnectionState(boolean enable) {
|
||||
if (!mSelected) {
|
||||
Slog.e(TAG, "updateWiredDeviceConnectionState on unselected AlsaDevice!");
|
||||
return;
|
||||
}
|
||||
String alsaCardDeviceString = getAlsaCardDeviceString();
|
||||
if (alsaCardDeviceString == null) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "RemoteException in setWiredDeviceConnectionState");
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user