diff options
-rw-r--r-- | core/java/android/alsa/AlsaCardsParser.java | 186 | ||||
-rw-r--r-- | core/java/android/alsa/AlsaDevicesParser.java | 72 | ||||
-rw-r--r-- | core/java/android/hardware/usb/UsbDevice.java | 1 | ||||
-rw-r--r-- | media/java/android/media/AudioService.java | 8 | ||||
-rw-r--r-- | services/usb/java/com/android/server/usb/UsbAlsaManager.java | 240 | ||||
-rw-r--r-- | services/usb/java/com/android/server/usb/UsbAudioDevice.java | 70 |
6 files changed, 416 insertions, 161 deletions
diff --git a/core/java/android/alsa/AlsaCardsParser.java b/core/java/android/alsa/AlsaCardsParser.java index 8b44881..8f9c56c 100644 --- a/core/java/android/alsa/AlsaCardsParser.java +++ b/core/java/android/alsa/AlsaCardsParser.java @@ -22,46 +22,58 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; -import java.util.Vector; +import java.util.ArrayList; /** * @hide Retrieves information from an ALSA "cards" file. */ public class AlsaCardsParser { private static final String TAG = "AlsaCardsParser"; + protected static final boolean DEBUG = true; - private static LineTokenizer tokenizer_ = new LineTokenizer(" :[]"); + private static LineTokenizer mTokenizer = new LineTokenizer(" :[]"); + + private ArrayList<AlsaCardRecord> mCardRecords = new ArrayList<AlsaCardRecord>(); public class AlsaCardRecord { + 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; public AlsaCardRecord() {} public boolean parse(String line, int lineIndex) { int tokenIndex = 0; int delimIndex = 0; + if (lineIndex == 0) { // line # (skip) - tokenIndex = tokenizer_.nextToken(line, tokenIndex); - delimIndex = tokenizer_.nextDelimiter(line, tokenIndex); + tokenIndex = mTokenizer.nextToken(line, tokenIndex); + delimIndex = mTokenizer.nextDelimiter(line, tokenIndex); + + // mCardNum + mCardNum = Integer.parseInt(line.substring(tokenIndex, delimIndex)); // mField1 - tokenIndex = tokenizer_.nextToken(line, delimIndex); - delimIndex = tokenizer_.nextDelimiter(line, tokenIndex); + tokenIndex = mTokenizer.nextToken(line, delimIndex); + delimIndex = mTokenizer.nextDelimiter(line, tokenIndex); mField1 = line.substring(tokenIndex, delimIndex); // mCardName - tokenIndex = tokenizer_.nextToken(line, delimIndex); - // delimIndex = tokenizer_.nextDelimiter(line, tokenIndex); + tokenIndex = mTokenizer.nextToken(line, delimIndex); mCardName = line.substring(tokenIndex); + // done } else if (lineIndex == 1) { - tokenIndex = tokenizer_.nextToken(line, 0); + tokenIndex = mTokenizer.nextToken(line, 0); if (tokenIndex != -1) { mCardDescription = line.substring(tokenIndex); + mIsUsb = mCardDescription.contains(kUsbCardKeyStr); } } @@ -73,44 +85,128 @@ public class AlsaCardsParser { } } - private Vector<AlsaCardRecord> cardRecords_ = new Vector<AlsaCardRecord>(); + public AlsaCardsParser() {} public void scan() { - cardRecords_.clear(); - final String cardsFilePath = "/proc/asound/cards"; - File cardsFile = new File(cardsFilePath); - try { - FileReader reader = new FileReader(cardsFile); - BufferedReader bufferedReader = new BufferedReader(reader); - String line = ""; - while ((line = bufferedReader.readLine()) != null) { - AlsaCardRecord cardRecord = new AlsaCardRecord(); - cardRecord.parse(line, 0); - cardRecord.parse(line = bufferedReader.readLine(), 1); - cardRecords_.add(cardRecord); - } - reader.close(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public AlsaCardRecord getCardRecordAt(int index) { - return cardRecords_.get(index); - } - - public int getNumCardRecords() { - return cardRecords_.size(); - } - - public void Log() { - int numCardRecs = getNumCardRecords(); - for (int index = 0; index < numCardRecs; ++index) { - Slog.w(TAG, "usb:" + getCardRecordAt(index).textFormat()); - } + if (DEBUG) { + Slog.i(TAG, "AlsaCardsParser.scan()"); + } + mCardRecords = new ArrayList<AlsaCardRecord>(); + + final String cardsFilePath = "/proc/asound/cards"; + File cardsFile = new File(cardsFilePath); + try { + FileReader reader = new FileReader(cardsFile); + BufferedReader bufferedReader = new BufferedReader(reader); + String line = ""; + while ((line = bufferedReader.readLine()) != null) { + AlsaCardRecord cardRecord = new AlsaCardRecord(); + if (DEBUG) { + Slog.i(TAG, " " + line); + } + cardRecord.parse(line, 0); + + line = bufferedReader.readLine(); + if (DEBUG) { + Slog.i(TAG, " " + line); + } + cardRecord.parse(line, 1); + + mCardRecords.add(cardRecord); + } + reader.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } } - public AlsaCardsParser() {} + 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; + } + } + + 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() { + // Choose the most-recently added EXTERNAL card + // or return the first added EXTERNAL card? + for (AlsaCardRecord rec : mCardRecords) { + if (rec.mIsUsb) { + return rec.mCardNum; + } + } + + return -1; + } + + public int getDefaultCard() { + // return an external card if possible + int card = getDefaultUsbCard(); + + if (card < 0 && getNumCardRecords() > 0) { + // otherwise return the (internal) card with the highest number + card = getCardRecordAt(getNumCardRecords() - 1).mCardNum; + } + 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 + // + public void Log(String heading) { + if (DEBUG) { + Slog.i(TAG, heading); + for (AlsaCardRecord cardRec : mCardRecords) { + Slog.i(TAG, cardRec.textFormat()); + } + } + } } diff --git a/core/java/android/alsa/AlsaDevicesParser.java b/core/java/android/alsa/AlsaDevicesParser.java index 82cc1ae..3581cb6 100644 --- a/core/java/android/alsa/AlsaDevicesParser.java +++ b/core/java/android/alsa/AlsaDevicesParser.java @@ -21,7 +21,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; -import java.util.Vector; +import java.util.ArrayList; /** * @hide @@ -29,6 +29,7 @@ import java.util.Vector; */ public class AlsaDevicesParser { private static final String TAG = "AlsaDevicesParser"; + protected static final boolean DEBUG = false; private static final int kIndex_CardDeviceField = 5; private static final int kStartIndex_CardNum = 6; @@ -58,8 +59,7 @@ public class AlsaDevicesParser { int mDeviceType = kDeviceType_Unknown; int mDeviceDir = kDeviceDir_Unknown; - public AlsaDeviceRecord() { - } + public AlsaDeviceRecord() {} public boolean parse(String line) { // "0123456789012345678901234567890" @@ -176,38 +176,27 @@ public class AlsaDevicesParser { } } - private Vector<AlsaDeviceRecord> - deviceRecords_ = new Vector<AlsaDeviceRecord>(); - - private boolean isLineDeviceRecord(String line) { - return line.charAt(kIndex_CardDeviceField) == '['; - } - - public AlsaDevicesParser() { - } + private ArrayList<AlsaDeviceRecord> mDeviceRecords = new ArrayList<AlsaDeviceRecord>(); - public int getNumDeviceRecords() { - return deviceRecords_.size(); - } + public AlsaDevicesParser() {} - public AlsaDeviceRecord getDeviceRecordAt(int index) { - return deviceRecords_.get(index); + // + // Access + // + public int getDefaultDeviceNum(int card) { + // TODO - This (obviously) isn't sufficient. Revisit. + return 0; } - public void Log() { - int numDevRecs = getNumDeviceRecords(); - for (int index = 0; index < numDevRecs; ++index) { - Slog.w(TAG, "usb:" + getDeviceRecordAt(index).textFormat()); - } - } - - public boolean hasPlaybackDevices() { + // + // Predicates + // + public boolean hasPlaybackDevices() { return mHasPlaybackDevices; } public boolean hasPlaybackDevices(int card) { - for (int index = 0; index < deviceRecords_.size(); index++) { - AlsaDeviceRecord deviceRecord = deviceRecords_.get(index); + for (AlsaDeviceRecord deviceRecord : mDeviceRecords) { if (deviceRecord.mCardNum == card && deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_Audio && deviceRecord.mDeviceDir == AlsaDeviceRecord.kDeviceDir_Playback) { @@ -222,8 +211,7 @@ public class AlsaDevicesParser { } public boolean hasCaptureDevices(int card) { - for (int index = 0; index < deviceRecords_.size(); index++) { - AlsaDeviceRecord deviceRecord = deviceRecords_.get(index); + for (AlsaDeviceRecord deviceRecord : mDeviceRecords) { if (deviceRecord.mCardNum == card && deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_Audio && deviceRecord.mDeviceDir == AlsaDeviceRecord.kDeviceDir_Capture) { @@ -238,8 +226,7 @@ public class AlsaDevicesParser { } public boolean hasMIDIDevices(int card) { - for (int index = 0; index < deviceRecords_.size(); index++) { - AlsaDeviceRecord deviceRecord = deviceRecords_.get(index); + for (AlsaDeviceRecord deviceRecord : mDeviceRecords) { if (deviceRecord.mCardNum == card && deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_MIDI) { return true; @@ -248,8 +235,15 @@ public class AlsaDevicesParser { return false; } + // + // Process + // + private boolean isLineDeviceRecord(String line) { + return line.charAt(kIndex_CardDeviceField) == '['; + } + public void scan() { - deviceRecords_.clear(); + mDeviceRecords.clear(); final String devicesFilePath = "/proc/asound/devices"; File devicesFile = new File(devicesFilePath); @@ -261,7 +255,7 @@ public class AlsaDevicesParser { if (isLineDeviceRecord(line)) { AlsaDeviceRecord deviceRecord = new AlsaDeviceRecord(); deviceRecord.parse(line); - deviceRecords_.add(deviceRecord); + mDeviceRecords.add(deviceRecord); } } reader.close(); @@ -271,5 +265,17 @@ public class AlsaDevicesParser { e.printStackTrace(); } } + + // + // Loging + // + public void Log(String heading) { + if (DEBUG) { + Slog.i(TAG, heading); + for (AlsaDeviceRecord deviceRecord : mDeviceRecords) { + Slog.i(TAG, deviceRecord.textFormat()); + } + } + } } // class AlsaDevicesParser diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java index d90e06e..1a42319 100644 --- a/core/java/android/hardware/usb/UsbDevice.java +++ b/core/java/android/hardware/usb/UsbDevice.java @@ -40,6 +40,7 @@ import android.os.Parcelable; public class UsbDevice implements Parcelable { private static final String TAG = "UsbDevice"; + private static final boolean DEBUG = false; private final String mName; private final String mManufacturerName; diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 430ead5..a7965b4 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -4979,9 +4979,13 @@ public class AudioService extends IAudioService.Stub { boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false); boolean hasCapture = intent.getBooleanExtra("hasCapture", false); boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false); + int deviceClass = intent.getIntExtra("class", 0); - String params = (alsaCard == -1 && alsaDevice == -1 ? "" - : "card=" + alsaCard + ";device=" + alsaDevice); + String params = (alsaCard == -1 && alsaDevice == -1 + ? "" + : "card=" + alsaCard + + ";device=" + alsaDevice + + ";class=" + Integer.toHexString(deviceClass)); // Playback Device if (hasPlayback) { diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java index 6cc8ff5..32ca723 100644 --- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java +++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java @@ -37,46 +37,33 @@ import java.io.File; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.HashMap; +import java.util.ArrayList; /** * UsbAlsaManager manages USB audio and MIDI devices. */ public class UsbAlsaManager { private static final String TAG = UsbAlsaManager.class.getSimpleName(); - private static final boolean DEBUG = false; + private static final boolean DEBUG = true; private static final String ALSA_DIRECTORY = "/dev/snd/"; private final Context mContext; private IMidiManager mMidiManager; - private final class AudioDevice { - public int mCard; - public int mDevice; - public boolean mHasPlayback; - public boolean mHasCapture; - public boolean mHasMIDI; + private final AlsaCardsParser mCardsParser = new AlsaCardsParser(); + private final AlsaDevicesParser mDevicesParser = new AlsaDevicesParser(); - public AudioDevice(int card, int device, - boolean hasPlayback, boolean hasCapture, boolean hasMidi) { - mCard = card; - mDevice = device; - mHasPlayback = hasPlayback; - mHasCapture = hasCapture; - mHasMIDI = hasMidi; - } + // 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. - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("AudioDevice: [card: " + mCard); - sb.append(", device: " + mDevice); - sb.append(", hasPlayback: " + mHasPlayback); - sb.append(", hasCapture: " + mHasCapture); - sb.append(", hasMidi: " + mHasMIDI); - sb.append("]"); - return sb.toString(); - } - } + private final HashMap<UsbDevice,UsbAudioDevice> + mAudioDevices = new HashMap<UsbDevice,UsbAudioDevice>(); + + private final HashMap<String,AlsaDevice> + mAlsaDevices = new HashMap<String,AlsaDevice>(); + + private UsbAudioDevice mSelectedAudioDevice = null; private final class AlsaDevice { public static final int TYPE_UNKNOWN = 0; @@ -112,12 +99,6 @@ public class UsbAlsaManager { } } - private final HashMap<UsbDevice,AudioDevice> mAudioDevices - = new HashMap<UsbDevice,AudioDevice>(); - - private final HashMap<String,AlsaDevice> mAlsaDevices - = new HashMap<String,AlsaDevice>(); - private final FileObserver mAlsaObserver = new FileObserver(ALSA_DIRECTORY, FileObserver.CREATE | FileObserver.DELETE) { public void onEvent(int event, String path) { @@ -134,6 +115,9 @@ public class UsbAlsaManager { /* package */ UsbAlsaManager(Context context) { mContext = context; + + // initial scan + mCardsParser.scan(); } public void systemReady() { @@ -149,9 +133,15 @@ public class UsbAlsaManager { } // Broadcasts the arrival/departure of a USB audio interface - // audioDevice - the AudioDevice that was added or removed + // audioDevice - the UsbAudioDevice that was added or removed // enabled - if true, we're connecting a device (it's arrived), else disconnecting - private void sendDeviceNotification(AudioDevice audioDevice, boolean enabled) { + private void sendDeviceNotification(UsbAudioDevice audioDevice, boolean enabled) { + if (DEBUG) { + Slog.d(TAG, "sendDeviceNotification(enabled:" + enabled + + " c:" + audioDevice.mCard + + " d:" + audioDevice.mDevice + ")"); + } + // send a sticky broadcast containing current USB state Intent intent = new Intent(AudioManager.ACTION_USB_AUDIO_DEVICE_PLUG); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); @@ -162,6 +152,7 @@ public class UsbAlsaManager { intent.putExtra("hasPlayback", audioDevice.mHasPlayback); intent.putExtra("hasCapture", audioDevice.mHasCapture); intent.putExtra("hasMIDI", audioDevice.mHasMIDI); + intent.putExtra("class", audioDevice.mDeviceClass); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } @@ -241,6 +232,81 @@ public class UsbAlsaManager { } } + /* + * Select the default device of the specified card. + */ + /* package */ boolean selectCard(int card) { + if (DEBUG) { + Slog.d(TAG, "selectCard() card:" + card); + } + if (!mCardsParser.isCardUsb(card)) { + // Don't. AudioPolicyManager has logic for falling back to internal devices. + return false; + } + + if (mSelectedAudioDevice != null) { + if (mSelectedAudioDevice.mCard == card) { + // Nothing to do here. + return false; + } + // "disconnect" the AudioPolicyManager from the previously selected device. + sendDeviceNotification(mSelectedAudioDevice, false); + mSelectedAudioDevice = null; + } + + mDevicesParser.scan(); + int device = mDevicesParser.getDefaultDeviceNum(card); + + boolean hasPlayback = mDevicesParser.hasPlaybackDevices(card); + boolean hasCapture = mDevicesParser.hasCaptureDevices(card); + boolean hasMidi = mDevicesParser.hasMIDIDevices(card); + int deviceClass = + (mCardsParser.isCardUsb(card) + ? UsbAudioDevice.kAudioDeviceClass_External + : UsbAudioDevice.kAudioDeviceClass_Internal) | + UsbAudioDevice.kAudioDeviceMeta_Alsa; + + // Playback device file needed/present? + if (hasPlayback && (waitForAlsaDevice(card, device, AlsaDevice.TYPE_PLAYBACK) == null)) { + return false; + } + + // Capture device file needed/present? + if (hasCapture && (waitForAlsaDevice(card, device, AlsaDevice.TYPE_CAPTURE) == null)) { + return false; + } + //TODO - seems to me that we need to decouple the above tests for audio + // from the one below for MIDI. + + // MIDI device file needed/present? + AlsaDevice midiDevice = null; + if (hasMidi) { + midiDevice = waitForAlsaDevice(card, device, AlsaDevice.TYPE_MIDI); + } + + if (DEBUG) { + Slog.d(TAG, "usb: hasPlayback:" + hasPlayback + " hasCapture:" + hasCapture); + } + + mSelectedAudioDevice = + new UsbAudioDevice(card, device, hasPlayback, hasCapture, hasMidi, deviceClass); + mSelectedAudioDevice.mDeviceName = mCardsParser.getCardRecordFor(card).mCardName; + mSelectedAudioDevice.mDeviceDescription = + mCardsParser.getCardRecordFor(card).mCardDescription; + + sendDeviceNotification(mSelectedAudioDevice, true); + + return true; + } + + /* package */ boolean selectDefaultDevice() { + if (DEBUG) { + Slog.d(TAG, "UsbAudioManager.selectDefaultDevice()"); + } + mCardsParser.scan(); + return selectCard(mCardsParser.getDefaultCard()); + } + /* package */ void deviceAdded(UsbDevice usbDevice) { if (DEBUG) { Slog.d(TAG, "deviceAdded(): " + usbDevice); @@ -263,56 +329,28 @@ public class UsbAlsaManager { return; } - //TODO(pmclean) The "Parser" objects inspect files in "/proc/asound" which we presume is - // present, unlike the waitForAlsaDevice() which waits on a file in /dev/snd. It is not - // clear why this works, or that it can be relied on going forward. Needs further - // research. - AlsaCardsParser cardsParser = new AlsaCardsParser(); - cardsParser.scan(); - // cardsParser.Log(); - - // But we need to parse the device to determine its capabilities. - AlsaDevicesParser devicesParser = new AlsaDevicesParser(); - devicesParser.scan(); - // devicesParser.Log(); - - // The protocol for now will be to select the last-connected (highest-numbered) - // Alsa Card. - int card = cardsParser.getNumCardRecords() - 1; - int device = 0; - - boolean hasPlayback = devicesParser.hasPlaybackDevices(card); - boolean hasCapture = devicesParser.hasCaptureDevices(card); - boolean hasMidi = devicesParser.hasMIDIDevices(card); - - // Playback device file needed/present? - if (hasPlayback && - waitForAlsaDevice(card, device, AlsaDevice.TYPE_PLAYBACK) == null) { - return; - } - - // Capture device file needed/present? - if (hasCapture && - waitForAlsaDevice(card, device, AlsaDevice.TYPE_CAPTURE) == null) { - return; + ArrayList<AlsaCardsParser.AlsaCardRecord> prevScanRecs = mCardsParser.getScanRecords(); + mCardsParser.scan(); + + int addedCard = -1; + ArrayList<AlsaCardsParser.AlsaCardRecord> + newScanRecs = mCardsParser.getNewCardRecords(prevScanRecs); + if (newScanRecs.size() > 0) { + // This is where we select the just connected device + // NOTE - to switch to prefering the first-connected device, just always + // take the else clause below. + addedCard = newScanRecs.get(0).mCardNum; + } else { + addedCard = mCardsParser.getDefaultUsbCard(); } - // MIDI device file needed/present? - if (hasMidi) { - midiDevice = waitForAlsaDevice(card, device, AlsaDevice.TYPE_MIDI); + // If the default isn't a USB device, let the existing "select internal mechanism" + // handle the selection. + if (mCardsParser.isCardUsb(addedCard)) { + selectCard(addedCard); + mAudioDevices.put(usbDevice, mSelectedAudioDevice); } - if (DEBUG) { - Slog.d(TAG, - "usb: hasPlayback:" + hasPlayback + - " hasCapture:" + hasCapture + - " hasMidi:" + hasMidi); - } - - AudioDevice audioDevice = new AudioDevice(card, device, hasPlayback, hasCapture, hasMidi); - mAudioDevices.put(usbDevice, audioDevice); - sendDeviceNotification(audioDevice, true); - if (midiDevice != null && mMidiManager != null) { try { mMidiManager.alsaDeviceAdded(midiDevice.mCard, midiDevice.mDevice, usbDevice); @@ -327,7 +365,7 @@ public class UsbAlsaManager { Slog.d(TAG, "deviceRemoved(): " + device); } - AudioDevice audioDevice = mAudioDevices.remove(device); + UsbAudioDevice audioDevice = mAudioDevices.remove(device); if (audioDevice != null) { if (audioDevice.mHasPlayback || audioDevice.mHasPlayback) { sendDeviceNotification(audioDevice, false); @@ -340,12 +378,52 @@ public class UsbAlsaManager { } } } + + mSelectedAudioDevice = null; + + // if there any external devices left, select one of them + selectDefaultDevice(); } + // + // Devices List + // + public ArrayList<UsbAudioDevice> getConnectedDevices() { + ArrayList<UsbAudioDevice> devices = new ArrayList<UsbAudioDevice>(mAudioDevices.size()); + for (HashMap.Entry<UsbDevice,UsbAudioDevice> entry : mAudioDevices.entrySet()) { + devices.add(entry.getValue()); + } + return devices; + } + + // + // Logging + // public void dump(FileDescriptor fd, PrintWriter pw) { pw.println(" USB AudioDevices:"); for (UsbDevice device : mAudioDevices.keySet()) { pw.println(" " + device.getDeviceName() + ": " + mAudioDevices.get(device)); } } + + public void logDevicesList(String title) { + if (DEBUG) { + for (HashMap.Entry<UsbDevice,UsbAudioDevice> entry : mAudioDevices.entrySet()) { + Slog.i(TAG, "UsbDevice-------------------"); + Slog.i(TAG, "" + (entry != null ? entry.getKey() : "[none]")); + Slog.i(TAG, "UsbAudioDevice--------------"); + Slog.i(TAG, "" + entry.getValue()); + } + } + } + + // This logs a more terse (and more readable) version of the devices list + public void logDevices(String title) { + if (DEBUG) { + Slog.i(TAG, title); + for (HashMap.Entry<UsbDevice,UsbAudioDevice> entry : mAudioDevices.entrySet()) { + Slog.i(TAG, entry.getValue().toShortString()); + } + } + } } diff --git a/services/usb/java/com/android/server/usb/UsbAudioDevice.java b/services/usb/java/com/android/server/usb/UsbAudioDevice.java new file mode 100644 index 0000000..b7b9563 --- /dev/null +++ b/services/usb/java/com/android/server/usb/UsbAudioDevice.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 + * limitations under the License. + */ + +package com.android.server.usb; + +public final class UsbAudioDevice { + private static final String TAG = "UsbAudioDevice"; + protected static final boolean DEBUG = false; + + public int mCard; + public int mDevice; + public boolean mHasPlayback; + public boolean mHasCapture; + public boolean mHasMIDI; + + // Device "class" flags + public static final int kAudioDeviceClassMask = 0x00FFFFFF; + public static final int kAudioDeviceClass_Undefined = 0x00000000; + public static final int kAudioDeviceClass_Internal = 0x00000001; + public static final int kAudioDeviceClass_External = 0x00000002; + // Device meta-data flags + public static final int kAudioDeviceMetaMask = 0xFF000000; + public static final int kAudioDeviceMeta_Alsa = 0x80000000; + // This member is a combination of the above bit-flags + public int mDeviceClass; + + public String mDeviceName = ""; + public String mDeviceDescription = ""; + + public UsbAudioDevice(int card, int device, + boolean hasPlayback, boolean hasCapture, boolean hasMidi, int deviceClass) { + mCard = card; + mDevice = device; + mHasPlayback = hasPlayback; + mHasCapture = hasCapture; + mHasMIDI = hasMidi; + mDeviceClass = deviceClass; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("UsbAudioDevice: [card: " + mCard); + sb.append(", device: " + mDevice); + sb.append(", name: " + mDeviceName); + sb.append(", description: " + mDeviceDescription); + sb.append(", hasPlayback: " + mHasPlayback); + sb.append(", hasCapture: " + mHasCapture); + sb.append(", hasMidi: " + mHasMIDI); + sb.append(", class: 0x" + Integer.toHexString(mDeviceClass) + "]"); + return sb.toString(); + } + + public String toShortString() { + return "[card:" + mCard + " device:" + mDevice + " " + mDeviceName + "]"; + } +} + |