diff options
7 files changed, 438 insertions, 605 deletions
diff --git a/core/java/com/android/internal/alsa/AlsaCardsParser.java b/core/java/com/android/internal/alsa/AlsaCardsParser.java index bb75bf6e6fb8..fa8db96781ac 100644 --- a/core/java/com/android/internal/alsa/AlsaCardsParser.java +++ b/core/java/com/android/internal/alsa/AlsaCardsParser.java @@ -31,7 +31,9 @@ public class AlsaCardsParser { private static final String TAG = "AlsaCardsParser"; protected static final boolean DEBUG = false; - private static final String kCardsFilePath = "/proc/asound/cards"; + private static final String kAlsaFolderPath = "/proc/asound"; + private static final String kCardsFilePath = kAlsaFolderPath + "/cards"; + private static final String kDeviceAddressPrefix = "/dev/bus/usb/"; private static LineTokenizer mTokenizer = new LineTokenizer(" :[]"); @@ -47,14 +49,31 @@ public class AlsaCardsParser { private static final String TAG = "AlsaCardRecord"; private static final String kUsbCardKeyStr = "at usb-"; - public int mCardNum = -1; - public String mField1 = ""; - public String mCardName = ""; - public String mCardDescription = ""; - public boolean mIsUsb = false; + int mCardNum = -1; + String mField1 = ""; + String mCardName = ""; + String mCardDescription = ""; + + private String mUsbDeviceAddress = null; public AlsaCardRecord() {} + public int getCardNum() { + return mCardNum; + } + + public String getCardName() { + return mCardName; + } + + public String getCardDescription() { + return mCardDescription; + } + + public void setDeviceAddress(String usbDeviceAddress) { + mUsbDeviceAddress = usbDeviceAddress; + } + private boolean parse(String line, int lineIndex) { int tokenIndex = 0; int delimIndex = 0; @@ -87,8 +106,8 @@ public class AlsaCardsParser { tokenIndex = mTokenizer.nextToken(line, 0); if (tokenIndex != -1) { int keyIndex = line.indexOf(kUsbCardKeyStr); - mIsUsb = keyIndex != -1; - if (mIsUsb) { + boolean isUsb = keyIndex != -1; + if (isUsb) { mCardDescription = line.substring(tokenIndex, keyIndex - 1); } } @@ -97,14 +116,18 @@ public class AlsaCardsParser { return true; } + boolean isUsb() { + return mUsbDeviceAddress != null; + } + public String textFormat() { - return mCardName + " : " + mCardDescription; + return mCardName + " : " + mCardDescription + " [addr:" + mUsbDeviceAddress + "]"; } public void log(int listIndex) { Slog.d(TAG, "" + listIndex + " [" + mCardNum + " " + mCardName + " : " + mCardDescription + - " usb:" + mIsUsb); + " usb:" + isUsb()); } } @@ -112,7 +135,7 @@ public class AlsaCardsParser { public int scan() { if (DEBUG) { - Slog.i(TAG, "AlsaCardsParser.scan()...."); + Slog.d(TAG, "AlsaCardsParser.scan()...."); } mCardRecords = new ArrayList<AlsaCardRecord>(); @@ -125,7 +148,7 @@ public class AlsaCardsParser { while ((line = bufferedReader.readLine()) != null) { AlsaCardRecord cardRecord = new AlsaCardRecord(); if (DEBUG) { - Slog.i(TAG, " " + line); + Slog.d(TAG, " " + line); } cardRecord.parse(line, 0); @@ -134,10 +157,23 @@ public class AlsaCardsParser { break; } if (DEBUG) { - Slog.i(TAG, " " + line); + Slog.d(TAG, " " + line); } cardRecord.parse(line, 1); + // scan "usbbus" file + int cardNum = cardRecord.mCardNum; + String cardFolderPath = kAlsaFolderPath + "/card" + cardNum; + File usbbusFile = new File(cardFolderPath + "/usbbus"); + if (usbbusFile.exists()) { + // read it in + FileReader usbbusReader = new FileReader(usbbusFile); + String deviceAddress = (new BufferedReader(usbbusReader)).readLine(); + if (deviceAddress != null) { + cardRecord.setDeviceAddress(kDeviceAddressPrefix + deviceAddress); + } + usbbusReader.close(); + } mCardRecords.add(cardRecord); } reader.close(); @@ -147,14 +183,12 @@ public class AlsaCardsParser { mScanStatus = SCANSTATUS_EMPTY; } } catch (FileNotFoundException e) { - e.printStackTrace(); mScanStatus = SCANSTATUS_FAIL; } catch (IOException e) { - e.printStackTrace(); mScanStatus = SCANSTATUS_FAIL; } if (DEBUG) { - Slog.i(TAG, " status:" + mScanStatus); + Slog.d(TAG, " status:" + mScanStatus); } return mScanStatus; } @@ -163,142 +197,33 @@ public class AlsaCardsParser { return mScanStatus; } - public ArrayList<AlsaCardRecord> getScanRecords() { - return mCardRecords; - } - - public AlsaCardRecord getCardRecordAt(int index) { - return mCardRecords.get(index); - } - - public AlsaCardRecord getCardRecordFor(int cardNum) { - for (AlsaCardRecord rec : mCardRecords) { - if (rec.mCardNum == cardNum) { - return rec; + public AlsaCardRecord findCardNumFor(String deviceAddress) { + for(AlsaCardRecord cardRec : mCardRecords) { + if (cardRec.isUsb() && cardRec.mUsbDeviceAddress.equals(deviceAddress)) { + return cardRec; } } - return null; } - public int getNumCardRecords() { - return mCardRecords.size(); - } - - public boolean isCardUsb(int cardNum) { - for (AlsaCardRecord rec : mCardRecords) { - if (rec.mCardNum == cardNum) { - return rec.mIsUsb; - } - } - - return false; - } - - // return -1 if none found - public int getDefaultUsbCard() { - // save the current list of devices - ArrayList<AlsaCardsParser.AlsaCardRecord> prevRecs = mCardRecords; - if (DEBUG) { - LogDevices("Previous Devices:", prevRecs); - } - - // get the new list of devices - if (scan() != SCANSTATUS_SUCCESS) { - Slog.e(TAG, "Error scanning Alsa cards file."); - return -1; - } - - if (DEBUG) { - LogDevices("Current Devices:", mCardRecords); - } - - // Calculate the difference between the old and new device list - ArrayList<AlsaCardRecord> newRecs = getNewCardRecords(prevRecs); - if (DEBUG) { - LogDevices("New Devices:", newRecs); - } - - // Choose the most-recently added EXTERNAL card - // Check recently added devices - for (AlsaCardRecord rec : newRecs) { - if (DEBUG) { - Slog.d(TAG, rec.mCardName + " card:" + rec.mCardNum + " usb:" + rec.mIsUsb); - } - if (rec.mIsUsb) { - // Found it - return rec.mCardNum; - } - } - - // or return the first added EXTERNAL card? - for (AlsaCardRecord rec : prevRecs) { - if (DEBUG) { - Slog.d(TAG, rec.mCardName + " card:" + rec.mCardNum + " usb:" + rec.mIsUsb); - } - if (rec.mIsUsb) { - return rec.mCardNum; - } - } - - return -1; - } - - public int getDefaultCard() { - // return an external card if possible - int card = getDefaultUsbCard(); - if (DEBUG) { - Slog.d(TAG, "getDefaultCard() default usb card:" + card); - } - - if (card < 0 && getNumCardRecords() > 0) { - // otherwise return the (internal) card with the highest number - card = getCardRecordAt(getNumCardRecords() - 1).mCardNum; - } - if (DEBUG) { - Slog.d(TAG, " returns card:" + card); - } - return card; - } - - static public boolean hasCardNumber(ArrayList<AlsaCardRecord> recs, int cardNum) { - for (AlsaCardRecord cardRec : recs) { - if (cardRec.mCardNum == cardNum) { - return true; - } - } - return false; - } - - public ArrayList<AlsaCardRecord> getNewCardRecords(ArrayList<AlsaCardRecord> prevScanRecs) { - ArrayList<AlsaCardRecord> newRecs = new ArrayList<AlsaCardRecord>(); - for (AlsaCardRecord rec : mCardRecords) { - // now scan to see if this card number is in the previous scan list - if (!hasCardNumber(prevScanRecs, rec.mCardNum)) { - newRecs.add(rec); - } - } - return newRecs; - } - // // Logging // private void Log(String heading) { if (DEBUG) { - Slog.i(TAG, heading); + Slog.d(TAG, heading); for (AlsaCardRecord cardRec : mCardRecords) { - Slog.i(TAG, cardRec.textFormat()); + Slog.d(TAG, cardRec.textFormat()); } } } - static private void LogDevices(String caption, ArrayList<AlsaCardRecord> deviceList) { - Slog.d(TAG, caption + " ----------------"); - int listIndex = 0; - for (AlsaCardRecord device : deviceList) { - device.log(listIndex++); - } - Slog.d(TAG, "----------------"); - } +// static private void LogDevices(String caption, ArrayList<AlsaCardRecord> deviceList) { +// Slog.d(TAG, caption + " ----------------"); +// int listIndex = 0; +// for (AlsaCardRecord device : deviceList) { +// device.log(listIndex++); +// } +// Slog.d(TAG, caption + "----------------"); +// } } diff --git a/core/java/com/android/internal/alsa/AlsaDevicesParser.java b/core/java/com/android/internal/alsa/AlsaDevicesParser.java index 15261bafd299..8d92d016be24 100644 --- a/core/java/com/android/internal/alsa/AlsaDevicesParser.java +++ b/core/java/com/android/internal/alsa/AlsaDevicesParser.java @@ -27,6 +27,9 @@ import java.util.ArrayList; * @hide * Retrieves information from an ALSA "devices" file. */ +/* + * NOTE: This class is currently not being used, but may be needed in the future. + */ public class AlsaDevicesParser { private static final String TAG = "AlsaDevicesParser"; protected static final boolean DEBUG = false; @@ -207,12 +210,6 @@ public class AlsaDevicesParser { // // Predicates // -/* - public boolean hasPlaybackDevices() { - return mHasPlaybackDevices; - } -*/ - public boolean hasPlaybackDevices(int card) { for (AlsaDeviceRecord deviceRecord : mDeviceRecords) { if (deviceRecord.mCardNum == card && @@ -224,12 +221,6 @@ public class AlsaDevicesParser { return false; } -/* - public boolean hasCaptureDevices() { - return mHasCaptureDevices; - } -*/ - public boolean hasCaptureDevices(int card) { for (AlsaDeviceRecord deviceRecord : mDeviceRecords) { if (deviceRecord.mCardNum == card && @@ -241,12 +232,6 @@ public class AlsaDevicesParser { return false; } -/* - public boolean hasMIDIDevices() { - return mHasMIDIDevices; - } -*/ - public boolean hasMIDIDevices(int card) { for (AlsaDeviceRecord deviceRecord : mDeviceRecords) { if (deviceRecord.mCardNum == card && @@ -280,6 +265,7 @@ public class AlsaDevicesParser { if (isLineDeviceRecord(line)) { AlsaDeviceRecord deviceRecord = new AlsaDeviceRecord(); deviceRecord.parse(line); + Slog.i(TAG, deviceRecord.textFormat()); mDeviceRecords.add(deviceRecord); } } diff --git a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java index 5417d042ca54..74280fff2dfc 100644 --- a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java +++ b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java @@ -17,58 +17,101 @@ package com.android.server.usb; /** - * Represents an instance of an Alsa-supported USB peripheral. + * Represents the ALSA specification, and attributes of an ALSA device. */ public final class UsbAlsaDevice { private static final String TAG = "UsbAlsaDevice"; protected static final boolean DEBUG = false; - public final int mCard; - public final int mDevice; - public final boolean mHasPlayback; - public final boolean mHasCapture; - - // Device "class" flags - static final int AUDIO_DEVICE_CLASS_MASK = 0x00FFFFFF; - static final int AUDIO_DEVICE_CLASS_UNDEFINED = 0x00000000; - static final int AUDIO_DEVICE_CLASS_INTERNAL = 0x00000001; - static final int AUDIO_DEVICE_CLASS_EXTERNAL = 0x00000002; - // Device meta-data flags - static final int AUDIO_DEVICE_META_MASK = 0xFF000000; - static final int AUDIO_DEVICE_META_ALSA = 0x80000000; - // This member is a combination of the above bit-flags - public final int mDeviceClass; + private final int mCardNum; + private final int mDeviceNum; + private final boolean mHasPlayback; + private final boolean mHasCapture; + + private final boolean mIsInputHeadset; + private final boolean mIsOutputHeadset; + + private final String mDeviceAddress; private String mDeviceName = ""; private String mDeviceDescription = ""; - public UsbAlsaDevice(int card, int device, - boolean hasPlayback, boolean hasCapture, int deviceClass) { - mCard = card; - mDevice = device; + public UsbAlsaDevice(int card, int device, String deviceAddress, + boolean hasPlayback, boolean hasCapture, + boolean isInputHeadset, boolean isOutputHeadset) { + mCardNum = card; + mDeviceNum = device; + mDeviceAddress = deviceAddress; mHasPlayback = hasPlayback; mHasCapture = hasCapture; - mDeviceClass = deviceClass; + mIsInputHeadset = isInputHeadset; + mIsOutputHeadset = isOutputHeadset; + } + + /** + * @returns the ALSA card number associated with this peripheral. + */ + public int getCardNum() { + return mCardNum; + } + + /** + * @returns the ALSA device number associated with this peripheral. + */ + public int getDeviceNum() { + return mDeviceNum; + } + + /** + * @returns the USB device device address associated with this peripheral. + */ + public String getDeviceAddress() { + return mDeviceAddress; + } + + /** + * @returns true if the device supports playback. + */ + public boolean hasPlayback() { + return mHasPlayback; + } + + /** + * @returns true if the device supports capture (recording). + */ + public boolean hasCapture() { + return mHasCapture; + } + + /** + * @returns true if the device is a headset for purposes of capture. + */ + public boolean isInputHeadset() { + return mIsInputHeadset; + } + + /** + * @returns true if the device is a headset for purposes of playback. + */ + public boolean isOutputHeadset() { + return mIsOutputHeadset; } /** * @Override - * @return a String representation of the object. + * @returns a string representation of the object. */ public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("UsbAlsaDevice: [card: " + mCard); - sb.append(", device: " + mDevice); - sb.append(", name: " + mDeviceName); - sb.append(", hasPlayback: " + mHasPlayback); - sb.append(", hasCapture: " + mHasCapture); - sb.append(", class: 0x" + Integer.toHexString(mDeviceClass) + "]"); - return sb.toString(); + return "UsbAlsaDevice: [card: " + mCardNum + + ", device: " + mDeviceNum + + ", name: " + mDeviceName + + ", hasPlayback: " + mHasPlayback + + ", hasCapture: " + mHasCapture + "]"; } // called by logDevices String toShortString() { - return "[card:" + mCard + " device:" + mDevice + " " + mDeviceName + "]"; + return "[card:" + mCardNum + " device:" + mDeviceNum + " " + mDeviceName + "]"; } String getDeviceName() { @@ -80,5 +123,38 @@ public final class UsbAlsaDevice { mDeviceDescription = deviceDescription; } + /** + * @Override + * @returns true if the objects are equivalent. + */ + public boolean equals(Object obj) { + if (!(obj instanceof UsbAlsaDevice)) { + return false; + } + UsbAlsaDevice other = (UsbAlsaDevice) obj; + return (mCardNum == other.mCardNum + && mDeviceNum == other.mDeviceNum + && mHasPlayback == other.mHasPlayback + && mHasCapture == other.mHasCapture + && mIsInputHeadset == other.mIsInputHeadset + && mIsOutputHeadset == other.mIsOutputHeadset); + } + + /** + * @Override + * @returns a hash code generated from the object contents. + */ + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + mCardNum; + result = prime * result + mDeviceNum; + result = prime * result + (mHasPlayback ? 0 : 1); + result = prime * result + (mHasCapture ? 0 : 1); + result = prime * result + (mIsInputHeadset ? 0 : 1); + result = prime * result + (mIsOutputHeadset ? 0 : 1); + + return result; + } } diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java index 11517b653838..0a94828e595e 100644 --- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java +++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java @@ -10,7 +10,7 @@ * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions an + * See the License for the specific language governing permissions and * limitations under the License. */ @@ -19,28 +19,24 @@ package com.android.server.usb; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; -import android.hardware.usb.UsbConstants; import android.hardware.usb.UsbDevice; -import android.hardware.usb.UsbInterface; import android.media.AudioSystem; import android.media.IAudioService; import android.media.midi.MidiDeviceInfo; import android.os.Bundle; -import android.os.FileObserver; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.SystemClock; import android.provider.Settings; import android.util.Slog; import com.android.internal.alsa.AlsaCardsParser; -import com.android.internal.alsa.AlsaDevicesParser; import com.android.internal.util.IndentingPrintWriter; import com.android.server.audio.AudioService; +import com.android.server.usb.descriptors.UsbDescriptorParser; import libcore.io.IoUtils; -import java.io.File; +import java.util.ArrayList; import java.util.HashMap; /** @@ -57,107 +53,36 @@ public final class UsbAlsaManager { private final boolean mHasMidiFeature; private final AlsaCardsParser mCardsParser = new AlsaCardsParser(); - private final AlsaDevicesParser mDevicesParser = new AlsaDevicesParser(); // 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 final HashMap<UsbDevice, UsbAlsaDevice> - mAudioDevices = new HashMap<UsbDevice, UsbAlsaDevice>(); - - private boolean mIsInputHeadset; // as reported by UsbDescriptorParser - private boolean mIsOutputHeadset; // as reported by UsbDescriptorParser - - private final HashMap<UsbDevice,UsbMidiDevice> - mMidiDevices = new HashMap<UsbDevice,UsbMidiDevice>(); - - private final HashMap<String,AlsaDevice> - mAlsaDevices = new HashMap<String,AlsaDevice>(); - - private UsbAlsaDevice mAccessoryAudioDevice = null; + /** + * List of connected MIDI devices + */ + private final HashMap<String, UsbMidiDevice> + mMidiDevices = new HashMap<String, UsbMidiDevice>(); // UsbMidiDevice for USB peripheral mode (gadget) device private UsbMidiDevice mPeripheralMidiDevice = null; - private final class AlsaDevice { - public static final int TYPE_UNKNOWN = 0; - public static final int TYPE_PLAYBACK = 1; - public static final int TYPE_CAPTURE = 2; - public static final int TYPE_MIDI = 3; - - public int mCard; - public int mDevice; - public int mType; - - public AlsaDevice(int type, int card, int device) { - mType = type; - mCard = card; - mDevice = device; - } - - public boolean equals(Object obj) { - if (! (obj instanceof AlsaDevice)) { - return false; - } - AlsaDevice other = (AlsaDevice)obj; - return (mType == other.mType && mCard == other.mCard && mDevice == other.mDevice); - } - - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("AlsaDevice: [card: " + mCard); - sb.append(", device: " + mDevice); - sb.append(", type: " + mType); - sb.append("]"); - return sb.toString(); - } - } - - private final FileObserver mAlsaObserver = new FileObserver(ALSA_DIRECTORY, - FileObserver.CREATE | FileObserver.DELETE) { - public void onEvent(int event, String path) { - switch (event) { - case FileObserver.CREATE: - alsaFileAdded(path); - break; - case FileObserver.DELETE: - alsaFileRemoved(path); - break; - } - } - }; - /* package */ UsbAlsaManager(Context context) { mContext = context; mHasMidiFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI); - - // initial scan - if (mCardsParser.scan() != AlsaCardsParser.SCANSTATUS_SUCCESS) { - Slog.e(TAG, "Error scanning ASLA cards file."); - } } public void systemReady() { mAudioService = IAudioService.Stub.asInterface( ServiceManager.getService(Context.AUDIO_SERVICE)); - - mAlsaObserver.startWatching(); - - // add existing alsa devices - File[] files = new File(ALSA_DIRECTORY).listFiles(); - if (files != null) { - for (int i = 0; i < files.length; i++) { - alsaFileAdded(files[i].getName()); - } - } } // Notifies AudioService when a device is added or removed // audioDevice - the AudioDevice that was added or removed // enabled - if true, we're connecting a device (it's arrived), else disconnecting - private void notifyDeviceState(UsbAlsaDevice audioDevice, boolean enabled) { + private void notifyDeviceState(UsbAlsaDevice alsaDevice, boolean enabled) { if (DEBUG) { - Slog.d(TAG, "notifyDeviceState " + enabled + " " + audioDevice); + Slog.d(TAG, "notifyDeviceState " + enabled + " " + alsaDevice); } if (mAudioService == null) { @@ -177,276 +102,151 @@ public final class UsbAlsaManager { } int state = (enabled ? 1 : 0); - int alsaCard = audioDevice.mCard; - int alsaDevice = audioDevice.mDevice; - if (alsaCard < 0 || alsaDevice < 0) { - Slog.e(TAG, "Invalid alsa card or device alsaCard: " + alsaCard + - " alsaDevice: " + alsaDevice); + int cardNum = alsaDevice.getCardNum(); + int deviceNum = alsaDevice.getDeviceNum(); + if (cardNum < 0 || deviceNum < 0) { + Slog.e(TAG, "Invalid alsa card or device alsaCard: " + cardNum + + " alsaDevice: " + deviceNum); return; } - String address = AudioService.makeAlsaAddressString(alsaCard, alsaDevice); + String address = AudioService.makeAlsaAddressString(cardNum, deviceNum); try { // Playback Device - if (audioDevice.mHasPlayback) { - int device; - if (mIsOutputHeadset) { - device = AudioSystem.DEVICE_OUT_USB_HEADSET; - } else { - device = (audioDevice == mAccessoryAudioDevice - ? AudioSystem.DEVICE_OUT_USB_ACCESSORY - : AudioSystem.DEVICE_OUT_USB_DEVICE); - } + if (alsaDevice.hasPlayback()) { + int device = alsaDevice.isOutputHeadset() + ? AudioSystem.DEVICE_OUT_USB_HEADSET + : AudioSystem.DEVICE_OUT_USB_DEVICE; if (DEBUG) { Slog.i(TAG, "pre-call device:0x" + Integer.toHexString(device) + - " addr:" + address + " name:" + audioDevice.getDeviceName()); + " addr:" + address + " name:" + alsaDevice.getDeviceName()); } mAudioService.setWiredDeviceConnectionState( - device, state, address, audioDevice.getDeviceName(), TAG); + device, state, address, alsaDevice.getDeviceName(), TAG); } // Capture Device - if (audioDevice.mHasCapture) { - int device; - if (mIsInputHeadset) { - device = AudioSystem.DEVICE_IN_USB_HEADSET; - } else { - device = (audioDevice == mAccessoryAudioDevice - ? AudioSystem.DEVICE_IN_USB_ACCESSORY - : AudioSystem.DEVICE_IN_USB_DEVICE); - } + if (alsaDevice.hasCapture()) { + int device = alsaDevice.isInputHeadset() + ? AudioSystem.DEVICE_IN_USB_HEADSET + : AudioSystem.DEVICE_IN_USB_DEVICE; mAudioService.setWiredDeviceConnectionState( - device, state, address, audioDevice.getDeviceName(), TAG); + device, state, address, alsaDevice.getDeviceName(), TAG); } } catch (RemoteException e) { Slog.e(TAG, "RemoteException in setWiredDeviceConnectionState"); } } - private AlsaDevice waitForAlsaDevice(int card, int device, int type) { - if (DEBUG) { - Slog.e(TAG, "waitForAlsaDevice(c:" + card + " d:" + device + ")"); - } - - AlsaDevice testDevice = new AlsaDevice(type, card, device); - - // This value was empirically determined. - final int kWaitTimeMs = 2500; - - synchronized(mAlsaDevices) { - long timeoutMs = SystemClock.elapsedRealtime() + kWaitTimeMs; - do { - if (mAlsaDevices.values().contains(testDevice)) { - return testDevice; - } - long waitTimeMs = timeoutMs - SystemClock.elapsedRealtime(); - if (waitTimeMs > 0) { - try { - mAlsaDevices.wait(waitTimeMs); - } catch (InterruptedException e) { - Slog.d(TAG, "usb: InterruptedException while waiting for ALSA file."); - } - } - } while (timeoutMs > SystemClock.elapsedRealtime()); - } - - Slog.e(TAG, "waitForAlsaDevice failed for " + testDevice); - return null; - } - - private void alsaFileAdded(String name) { - Slog.i(TAG, "alsaFileAdded(" + name + ")"); - int type = AlsaDevice.TYPE_UNKNOWN; - int card = -1, device = -1; - - if (name.startsWith("pcmC")) { - if (name.endsWith("p")) { - type = AlsaDevice.TYPE_PLAYBACK; - } else if (name.endsWith("c")) { - type = AlsaDevice.TYPE_CAPTURE; - } - } else if (name.startsWith("midiC")) { - type = AlsaDevice.TYPE_MIDI; - } - - if (type != AlsaDevice.TYPE_UNKNOWN) { - try { - int c_index = name.indexOf('C'); - int d_index = name.indexOf('D'); - int end = name.length(); - if (type == AlsaDevice.TYPE_PLAYBACK || type == AlsaDevice.TYPE_CAPTURE) { - // skip trailing 'p' or 'c' - end--; - } - card = Integer.parseInt(name.substring(c_index + 1, d_index)); - device = Integer.parseInt(name.substring(d_index + 1, end)); - } catch (Exception e) { - Slog.e(TAG, "Could not parse ALSA file name " + name, e); - return; - } - synchronized(mAlsaDevices) { - if (mAlsaDevices.get(name) == null) { - AlsaDevice alsaDevice = new AlsaDevice(type, card, device); - Slog.d(TAG, "Adding ALSA device " + alsaDevice); - mAlsaDevices.put(name, alsaDevice); - mAlsaDevices.notifyAll(); - } - } - } - } - - private void alsaFileRemoved(String path) { - synchronized(mAlsaDevices) { - AlsaDevice device = mAlsaDevices.remove(path); - if (device != null) { - Slog.d(TAG, "ALSA device removed: " + device); + private int getAlsaDeviceListIndexFor(String deviceAddress) { + for (int index = 0; index < mAlsaDevices.size(); index++) { + if (mAlsaDevices.get(index).getDeviceAddress().equals(deviceAddress)) { + return index; } } + return -1; } - /* - * Select the default device of the specified card. - */ - /* package */ UsbAlsaDevice selectAudioCard(int card) { - if (DEBUG) { - Slog.d(TAG, "selectAudioCard() card:" + card - + " isCardUsb(): " + mCardsParser.isCardUsb(card)); - } - if (!mCardsParser.isCardUsb(card)) { - // Don't. AudioPolicyManager has logic for falling back to internal devices. - return null; - } - - if (mDevicesParser.scan() != AlsaDevicesParser.SCANSTATUS_SUCCESS) { - Slog.e(TAG, "Error parsing ALSA devices file."); - return null; - } - - int device = mDevicesParser.getDefaultDeviceNum(card); - - boolean hasPlayback = mDevicesParser.hasPlaybackDevices(card); - boolean hasCapture = mDevicesParser.hasCaptureDevices(card); - if (DEBUG) { - Slog.d(TAG, "usb: hasPlayback:" + hasPlayback + " hasCapture:" + hasCapture); - } - - int deviceClass = - (mCardsParser.isCardUsb(card) - ? UsbAlsaDevice.AUDIO_DEVICE_CLASS_EXTERNAL - : UsbAlsaDevice.AUDIO_DEVICE_CLASS_INTERNAL) - | UsbAlsaDevice.AUDIO_DEVICE_META_ALSA; - - // Playback device file needed/present? - if (hasPlayback && (waitForAlsaDevice(card, device, AlsaDevice.TYPE_PLAYBACK) == null)) { - return null; - } - - // Capture device file needed/present? - if (hasCapture && (waitForAlsaDevice(card, device, AlsaDevice.TYPE_CAPTURE) == null)) { + private UsbAlsaDevice removeAlsaDeviceFromList(String deviceAddress) { + int index = getAlsaDeviceListIndexFor(deviceAddress); + if (index > -1) { + return mAlsaDevices.remove(index); + } else { return null; } - - UsbAlsaDevice audioDevice = - new UsbAlsaDevice(card, device, hasPlayback, hasCapture, deviceClass); - AlsaCardsParser.AlsaCardRecord cardRecord = mCardsParser.getCardRecordFor(card); - audioDevice.setDeviceNameAndDescription(cardRecord.mCardName, cardRecord.mCardDescription); - - notifyDeviceState(audioDevice, true /*enabled*/); - - return audioDevice; } /* package */ UsbAlsaDevice selectDefaultDevice() { if (DEBUG) { Slog.d(TAG, "UsbAudioManager.selectDefaultDevice()"); } - return selectAudioCard(mCardsParser.getDefaultCard()); + + if (mAlsaDevices.size() > 0) { + UsbAlsaDevice alsaDevice = mAlsaDevices.get(0); + if (DEBUG) { + Slog.d(TAG, " alsaDevice:" + alsaDevice); + } + if (alsaDevice != null) { + notifyDeviceState(alsaDevice, true /*enabled*/); + } + return alsaDevice; + } else { + return null; + } } - /* package */ void usbDeviceAdded(UsbDevice usbDevice, - boolean isInputHeadset, boolean isOutputHeadset) { + /* package */ void usbDeviceAdded(String deviceAddress, UsbDevice usbDevice, + UsbDescriptorParser parser) { if (DEBUG) { - Slog.d(TAG, "deviceAdded(): " + usbDevice.getManufacturerName() + Slog.d(TAG, "usbDeviceAdded(): " + usbDevice.getManufacturerName() + " nm:" + usbDevice.getProductName()); } - mIsInputHeadset = isInputHeadset; - mIsOutputHeadset = isOutputHeadset; - - // Is there an audio interface in there? - boolean isAudioDevice = false; + // Scan the Alsa File Space + mCardsParser.scan(); - // FIXME - handle multiple configurations? - int interfaceCount = usbDevice.getInterfaceCount(); - for (int ntrfaceIndex = 0; !isAudioDevice && ntrfaceIndex < interfaceCount; - ntrfaceIndex++) { - UsbInterface ntrface = usbDevice.getInterface(ntrfaceIndex); - if (ntrface.getInterfaceClass() == UsbConstants.USB_CLASS_AUDIO) { - isAudioDevice = true; - } + // Find the ALSA spec for this device address + AlsaCardsParser.AlsaCardRecord cardRec = + mCardsParser.findCardNumFor(deviceAddress); + if (cardRec == null) { + return; } + // Add it to the devices list + boolean hasInput = parser.hasInput(); + boolean hasOutput = parser.hasOutput(); if (DEBUG) { - Slog.d(TAG, " isAudioDevice: " + isAudioDevice); - } - if (!isAudioDevice) { - return; + Slog.d(TAG, "hasInput: " + hasInput + " hasOutput:" + hasOutput); + } + if (hasInput || hasOutput) { + boolean isInputHeadset = parser.isInputHeadset(); + boolean isOutputHeadset = parser.isOutputHeadset(); + UsbAlsaDevice alsaDevice = + new UsbAlsaDevice(cardRec.getCardNum(), 0 /*device*/, deviceAddress, + hasOutput, hasInput, isInputHeadset, isOutputHeadset); + alsaDevice.setDeviceNameAndDescription( + cardRec.getCardName(), cardRec.getCardDescription()); + mAlsaDevices.add(0, alsaDevice); + + // Select it + if (alsaDevice != null) { + notifyDeviceState(alsaDevice, true /*enabled*/); + } } - int addedCard = mCardsParser.getDefaultUsbCard(); - - // If the default isn't a USB device, let the existing "select internal mechanism" - // handle the selection. + // look for MIDI devices + boolean hasMidi = parser.hasMIDIInterface(); if (DEBUG) { - Slog.d(TAG, " mCardsParser.isCardUsb(" + addedCard + ") = " - + mCardsParser.isCardUsb(addedCard)); + Slog.d(TAG, "hasMidi: " + hasMidi + " mHasMidiFeature:" + mHasMidiFeature); } - if (mCardsParser.isCardUsb(addedCard)) { - UsbAlsaDevice audioDevice = selectAudioCard(addedCard); - if (audioDevice != null) { - mAudioDevices.put(usbDevice, audioDevice); - Slog.i(TAG, "USB Audio Device Added: " + audioDevice); + if (hasMidi && mHasMidiFeature) { + int device = 0; + Bundle properties = new Bundle(); + String manufacturer = usbDevice.getManufacturerName(); + String product = usbDevice.getProductName(); + String version = usbDevice.getVersion(); + String name; + if (manufacturer == null || manufacturer.isEmpty()) { + name = product; + } else if (product == null || product.isEmpty()) { + name = manufacturer; + } else { + name = manufacturer + " " + product; } - - // look for MIDI devices - - // Don't need to call mDevicesParser.scan() because selectAudioCard() does this above. - // Uncomment this next line if that behavior changes in the fugure. - // mDevicesParser.scan() - - boolean hasMidi = mDevicesParser.hasMIDIDevices(addedCard); - if (hasMidi && mHasMidiFeature) { - int device = mDevicesParser.getDefaultDeviceNum(addedCard); - AlsaDevice alsaDevice = waitForAlsaDevice(addedCard, device, AlsaDevice.TYPE_MIDI); - if (alsaDevice != null) { - Bundle properties = new Bundle(); - String manufacturer = usbDevice.getManufacturerName(); - String product = usbDevice.getProductName(); - String version = usbDevice.getVersion(); - String name; - if (manufacturer == null || manufacturer.isEmpty()) { - name = product; - } else if (product == null || product.isEmpty()) { - name = manufacturer; - } else { - name = manufacturer + " " + product; - } - properties.putString(MidiDeviceInfo.PROPERTY_NAME, name); - properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, manufacturer); - properties.putString(MidiDeviceInfo.PROPERTY_PRODUCT, product); - properties.putString(MidiDeviceInfo.PROPERTY_VERSION, version); - properties.putString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER, - usbDevice.getSerialNumber()); - properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, alsaDevice.mCard); - properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, alsaDevice.mDevice); - properties.putParcelable(MidiDeviceInfo.PROPERTY_USB_DEVICE, usbDevice); - - UsbMidiDevice usbMidiDevice = UsbMidiDevice.create(mContext, properties, - alsaDevice.mCard, alsaDevice.mDevice); - if (usbMidiDevice != null) { - mMidiDevices.put(usbDevice, usbMidiDevice); - } - } + properties.putString(MidiDeviceInfo.PROPERTY_NAME, name); + properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, manufacturer); + properties.putString(MidiDeviceInfo.PROPERTY_PRODUCT, product); + properties.putString(MidiDeviceInfo.PROPERTY_VERSION, version); + properties.putString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER, + usbDevice.getSerialNumber()); + properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, cardRec.getCardNum()); + properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, 0 /*deviceNum*/); + properties.putParcelable(MidiDeviceInfo.PROPERTY_USB_DEVICE, usbDevice); + + UsbMidiDevice usbMidiDevice = UsbMidiDevice.create(mContext, properties, + cardRec.getCardNum(), 0 /*device*/); + if (usbMidiDevice != null) { + mMidiDevices.put(deviceAddress, usbMidiDevice); } } @@ -455,42 +255,31 @@ public final class UsbAlsaManager { } } - /* package */ void usbDeviceRemoved(UsbDevice usbDevice) { + /* package */ void usbDeviceRemoved(String deviceAddress/*UsbDevice usbDevice*/) { if (DEBUG) { - Slog.d(TAG, "deviceRemoved(): " + usbDevice.getManufacturerName() + - " " + usbDevice.getProductName()); + Slog.d(TAG, "deviceRemoved(" + deviceAddress + ")"); } - UsbAlsaDevice audioDevice = mAudioDevices.remove(usbDevice); - Slog.i(TAG, "USB Audio Device Removed: " + audioDevice); - if (audioDevice != null) { - if (audioDevice.mHasPlayback || audioDevice.mHasCapture) { - notifyDeviceState(audioDevice, false /*enabled*/); + // Audio + UsbAlsaDevice alsaDevice = removeAlsaDeviceFromList(deviceAddress); + Slog.i(TAG, "USB Audio Device Removed: " + alsaDevice); + if (alsaDevice != null) { + if (alsaDevice.hasPlayback() || alsaDevice.hasCapture()) { + notifyDeviceState(alsaDevice, false /*enabled*/); // if there any external devices left, select one of them selectDefaultDevice(); } } - UsbMidiDevice usbMidiDevice = mMidiDevices.remove(usbDevice); + + // MIDI + UsbMidiDevice usbMidiDevice = mMidiDevices.remove(deviceAddress); if (usbMidiDevice != null) { + Slog.i(TAG, "USB MIDI Device Removed: " + usbMidiDevice); IoUtils.closeQuietly(usbMidiDevice); } } - /* package */ void setAccessoryAudioState(boolean enabled, int card, int device) { - if (DEBUG) { - Slog.d(TAG, "setAccessoryAudioState " + enabled + " " + card + " " + device); - } - if (enabled) { - mAccessoryAudioDevice = new UsbAlsaDevice(card, device, true, false, - UsbAlsaDevice.AUDIO_DEVICE_CLASS_EXTERNAL); - notifyDeviceState(mAccessoryAudioDevice, true /*enabled*/); - } else if (mAccessoryAudioDevice != null) { - notifyDeviceState(mAccessoryAudioDevice, false /*enabled*/); - mAccessoryAudioDevice = null; - } - } - /* package */ void setPeripheralMidiState(boolean enabled, int card, int device) { if (!mHasMidiFeature) { return; @@ -515,34 +304,21 @@ public final class UsbAlsaManager { } // - // Devices List - // -/* - //import java.util.ArrayList; - public ArrayList<UsbAlsaDevice> getConnectedDevices() { - ArrayList<UsbAlsaDevice> devices = new ArrayList<UsbAlsaDevice>(mAudioDevices.size()); - for (HashMap.Entry<UsbDevice,UsbAlsaDevice> entry : mAudioDevices.entrySet()) { - devices.add(entry.getValue()); - } - return devices; - } -*/ - - // // Logging // // called by UsbService.dump public void dump(IndentingPrintWriter pw) { pw.println("Parsers Scan Status:"); pw.println(" Cards Parser: " + mCardsParser.getScanStatus()); - pw.println(" Devices Parser: " + mDevicesParser.getScanStatus()); +// pw.println(" Devices Parser: " + mDevicesParser.getScanStatus()); pw.println("USB Audio Devices:"); - for (UsbDevice device : mAudioDevices.keySet()) { - pw.println(" " + device.getDeviceName() + ": " + mAudioDevices.get(device)); + for (UsbAlsaDevice usbAlsaDevice : mAlsaDevices) { + pw.println(" " + usbAlsaDevice.getDeviceAddress() + ": " + usbAlsaDevice); } pw.println("USB MIDI Devices:"); - for (UsbDevice device : mMidiDevices.keySet()) { - pw.println(" " + device.getDeviceName() + ": " + mMidiDevices.get(device)); + for (String deviceAddr : mMidiDevices.keySet()) { + UsbMidiDevice midiDevice = mMidiDevices.get(deviceAddr); + pw.println(" " + deviceAddr + ": " + midiDevice); } } diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 55ffea6f252f..a67e7f37f947 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -726,35 +726,9 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } private void updateUsbFunctions() { - updateAudioSourceFunction(); updateMidiFunction(); } - private void updateAudioSourceFunction() { - boolean enabled = (mCurrentFunctions & UsbManager.FUNCTION_AUDIO_SOURCE) != 0; - if (enabled != mAudioSourceEnabled) { - int card = -1; - int device = -1; - - if (enabled) { - Scanner scanner = null; - try { - scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH)); - card = scanner.nextInt(); - device = scanner.nextInt(); - } catch (FileNotFoundException e) { - Slog.e(TAG, "could not open audio source PCM file", e); - } finally { - if (scanner != null) { - scanner.close(); - } - } - } - mUsbAlsaManager.setAccessoryAudioState(enabled, card, device); - mAudioSourceEnabled = enabled; - } - } - private void updateMidiFunction() { boolean enabled = (mCurrentFunctions & UsbManager.FUNCTION_MIDI) != 0; if (enabled != mMidiEnabled) { diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java index 7a352a4dc69d..58f914773071 100644 --- a/services/usb/java/com/android/server/usb/UsbHostManager.java +++ b/services/usb/java/com/android/server/usb/UsbHostManager.java @@ -44,7 +44,7 @@ import java.util.LinkedList; */ public class UsbHostManager { private static final String TAG = UsbHostManager.class.getSimpleName(); - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; private final Context mContext; @@ -230,6 +230,7 @@ public class UsbHostManager { } private boolean isBlackListed(String deviceAddress) { + Slog.i(TAG, "isBlackListed(" + deviceAddress + ")"); int count = mHostBlacklist.length; for (int i = 0; i < count; i++) { if (deviceAddress.startsWith(mHostBlacklist[i])) { @@ -241,6 +242,7 @@ public class UsbHostManager { /* returns true if the USB device should not be accessible by applications */ private boolean isBlackListed(int clazz, int subClass) { + Slog.i(TAG, "isBlackListed(" + clazz + ", " + subClass + ")"); // blacklist hubs if (clazz == UsbConstants.USB_CLASS_HUB) return true; @@ -312,13 +314,7 @@ public class UsbHostManager { usbDeviceConnectionHandler); } - // Headset? - boolean isInputHeadset = parser.isInputHeadset(); - boolean isOutputHeadset = parser.isOutputHeadset(); - Slog.i(TAG, "---- isHeadset[in: " + isInputHeadset - + " , out: " + isOutputHeadset + "]"); - - mUsbAlsaManager.usbDeviceAdded(newDevice, isInputHeadset, isOutputHeadset); + mUsbAlsaManager.usbDeviceAdded(deviceAddress, newDevice, parser); // Tracking addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT, @@ -343,10 +339,13 @@ public class UsbHostManager { /* Called from JNI in monitorUsbHostBus to report USB device removal */ @SuppressWarnings("unused") private void usbDeviceRemoved(String deviceAddress) { + if (DEBUG) { + Slog.d(TAG, "usbDeviceRemoved(" + deviceAddress + ") - start"); + } synchronized (mLock) { UsbDevice device = mDevices.remove(deviceAddress); if (device != null) { - mUsbAlsaManager.usbDeviceRemoved(device); + mUsbAlsaManager.usbDeviceRemoved(deviceAddress/*device*/); mSettingsManager.usbDeviceRemoved(device); getCurrentUserSettings().usbDeviceRemoved(device); diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java index 7a1e9e2f9896..297a6eab4a78 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java @@ -26,7 +26,7 @@ import java.util.ArrayList; */ public final class UsbDescriptorParser { private static final String TAG = "UsbDescriptorParser"; - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; private final String mDeviceAddr; @@ -358,50 +358,93 @@ public final class UsbDescriptorParser { return list; } + /* + * Attribute predicates + */ /** * @hide */ - public boolean hasHIDDescriptor() { - ArrayList<UsbDescriptor> descriptors = - getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_HID); - return !descriptors.isEmpty(); + public boolean hasInput() { + if (DEBUG) { + Log.d(TAG, "---- hasInput()"); + } + ArrayList<UsbDescriptor> acDescriptors = + getACInterfaceDescriptors(UsbACInterface.ACI_INPUT_TERMINAL, + UsbACInterface.AUDIO_AUDIOCONTROL); + boolean hasInput = false; + for (UsbDescriptor descriptor : acDescriptors) { + if (descriptor instanceof UsbACTerminal) { + UsbACTerminal inDescr = (UsbACTerminal) descriptor; + // Check for input and bi-directional terminal types + int type = inDescr.getTerminalType(); + if (DEBUG) { + Log.d(TAG, " type:0x" + Integer.toHexString(type)); + } + if ((type >= UsbTerminalTypes.TERMINAL_IN_UNDEFINED + && type <= UsbTerminalTypes.TERMINAL_IN_PROC_MIC_ARRAY) + || (type >= UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED + && type <= UsbTerminalTypes.TERMINAL_BIDIR_SKRPHONE_CANCEL) + || (type == UsbTerminalTypes.TERMINAL_USB_STREAMING)) { + hasInput = true; + break; + } + } else { + Log.w(TAG, "Undefined Audio Input terminal l: " + descriptor.getLength() + + " t:0x" + Integer.toHexString(descriptor.getType())); + } + } + + if (DEBUG) { + Log.d(TAG, "hasInput() = " + hasInput); + } + return hasInput; } /** * @hide */ - public boolean hasMIDIInterface() { - ArrayList<UsbDescriptor> descriptors = - getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_AUDIO); - for (UsbDescriptor descriptor : descriptors) { - // enusure that this isn't an unrecognized interface descriptor - if (descriptor instanceof UsbInterfaceDescriptor) { - UsbInterfaceDescriptor interfaceDescr = (UsbInterfaceDescriptor) descriptor; - if (interfaceDescr.getUsbSubclass() == UsbDescriptor.AUDIO_MIDISTREAMING) { - return true; + public boolean hasOutput() { + if (DEBUG) { + Log.d(TAG, "---- hasOutput()"); + } + ArrayList<UsbDescriptor> acDescriptors = + getACInterfaceDescriptors(UsbACInterface.ACI_OUTPUT_TERMINAL, + UsbACInterface.AUDIO_AUDIOCONTROL); + boolean hasOutput = false; + for (UsbDescriptor descriptor : acDescriptors) { + if (descriptor instanceof UsbACTerminal) { + UsbACTerminal outDescr = (UsbACTerminal) descriptor; + // Check for output and bi-directional terminal types + int type = outDescr.getTerminalType(); + if (DEBUG) { + Log.d(TAG, " type:0x" + Integer.toHexString(type)); + } + if ((type >= UsbTerminalTypes.TERMINAL_OUT_UNDEFINED + && type <= UsbTerminalTypes.TERMINAL_OUT_LFSPEAKER) + || (type >= UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED + && type <= UsbTerminalTypes.TERMINAL_BIDIR_SKRPHONE_CANCEL)) { + hasOutput = true; + break; } } else { - Log.w(TAG, "Undefined Audio Class Interface l: " + descriptor.getLength() + Log.w(TAG, "Undefined Audio Input terminal l: " + descriptor.getLength() + " t:0x" + Integer.toHexString(descriptor.getType())); } } - return false; + if (DEBUG) { + Log.d(TAG, "hasOutput() = " + hasOutput); + } + return hasOutput; } /** * @hide */ - public float getInputHeadsetProbability() { - if (hasMIDIInterface()) { - return 0.0f; - } - - float probability = 0.0f; - ArrayList<UsbDescriptor> acDescriptors; - - // Look for a microphone + public boolean hasMic() { boolean hasMic = false; - acDescriptors = getACInterfaceDescriptors(UsbACInterface.ACI_INPUT_TERMINAL, + + ArrayList<UsbDescriptor> acDescriptors = + getACInterfaceDescriptors(UsbACInterface.ACI_INPUT_TERMINAL, UsbACInterface.AUDIO_AUDIOCONTROL); for (UsbDescriptor descriptor : acDescriptors) { if (descriptor instanceof UsbACTerminal) { @@ -418,18 +461,23 @@ public final class UsbDescriptorParser { + " t:0x" + Integer.toHexString(descriptor.getType())); } } + return hasMic; + } - // Look for a "speaker" + /** + * @hide + */ + public boolean hasSpeaker() { boolean hasSpeaker = false; - acDescriptors = + + ArrayList<UsbDescriptor> acDescriptors = getACInterfaceDescriptors(UsbACInterface.ACI_OUTPUT_TERMINAL, UsbACInterface.AUDIO_AUDIOCONTROL); for (UsbDescriptor descriptor : acDescriptors) { if (descriptor instanceof UsbACTerminal) { UsbACTerminal outDescr = (UsbACTerminal) descriptor; if (outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_SPEAKER - || outDescr.getTerminalType() - == UsbTerminalTypes.TERMINAL_OUT_HEADPHONES + || outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_HEADPHONES || outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_HEADSET) { hasSpeaker = true; break; @@ -440,6 +488,55 @@ public final class UsbDescriptorParser { } } + return hasSpeaker; + } + + /** + * @hide + */ + public boolean hasHIDDescriptor() { + ArrayList<UsbDescriptor> descriptors = + getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_HID); + return !descriptors.isEmpty(); + } + + /** + * @hide + */ + public boolean hasMIDIInterface() { + ArrayList<UsbDescriptor> descriptors = + getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_AUDIO); + for (UsbDescriptor descriptor : descriptors) { + // enusure that this isn't an unrecognized interface descriptor + if (descriptor instanceof UsbInterfaceDescriptor) { + UsbInterfaceDescriptor interfaceDescr = (UsbInterfaceDescriptor) descriptor; + if (interfaceDescr.getUsbSubclass() == UsbDescriptor.AUDIO_MIDISTREAMING) { + return true; + } + } else { + Log.w(TAG, "Undefined Audio Class Interface l: " + descriptor.getLength() + + " t:0x" + Integer.toHexString(descriptor.getType())); + } + } + return false; + } + + /** + * @hide + */ + public float getInputHeadsetProbability() { + if (hasMIDIInterface()) { + return 0.0f; + } + + float probability = 0.0f; + + // Look for a microphone + boolean hasMic = hasMic(); + + // Look for a "speaker" + boolean hasSpeaker = hasSpeaker(); + if (hasMic && hasSpeaker) { probability += 0.75f; } |