summaryrefslogtreecommitdiffstats
path: root/core/java/com
diff options
context:
space:
mode:
authorMike Lockwood <lockwood@google.com>2015-02-27 18:42:11 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-02-27 18:42:13 +0000
commit238cba35934e11c062c5f5da1768fcb474a8715d (patch)
treed356ac475b3cdf15803644a9798a29ed34aa4717 /core/java/com
parent228fd600cebe51e612357489310bc239d6bf24cc (diff)
parent464c655871f4c1dd280474723e4b33f55044baa5 (diff)
downloadframeworks_base-238cba35934e11c062c5f5da1768fcb474a8715d.zip
frameworks_base-238cba35934e11c062c5f5da1768fcb474a8715d.tar.gz
frameworks_base-238cba35934e11c062c5f5da1768fcb474a8715d.tar.bz2
Merge "Move ALSA utilities to com.android.internal.alsa package"
Diffstat (limited to 'core/java/com')
-rw-r--r--core/java/com/android/internal/alsa/AlsaCardsParser.java225
-rw-r--r--core/java/com/android/internal/alsa/AlsaDevicesParser.java288
-rw-r--r--core/java/com/android/internal/alsa/LineTokenizer.java57
3 files changed, 570 insertions, 0 deletions
diff --git a/core/java/com/android/internal/alsa/AlsaCardsParser.java b/core/java/com/android/internal/alsa/AlsaCardsParser.java
new file mode 100644
index 0000000..5c0a888
--- /dev/null
+++ b/core/java/com/android/internal/alsa/AlsaCardsParser.java
@@ -0,0 +1,225 @@
+/*
+ * 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 and
+ * limitations under the License.
+ */
+
+package com.android.internal.alsa;
+
+import android.util.Slog;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+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 final String kCardsFilePath = "/proc/asound/cards";
+
+ 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 = mTokenizer.nextToken(line, tokenIndex);
+ delimIndex = mTokenizer.nextDelimiter(line, tokenIndex);
+
+ try {
+ // mCardNum
+ mCardNum = Integer.parseInt(line.substring(tokenIndex, delimIndex));
+ } catch (NumberFormatException e) {
+ Slog.e(TAG, "Failed to parse line " + lineIndex + " of " + kCardsFilePath
+ + ": " + line.substring(tokenIndex, delimIndex));
+ return false;
+ }
+
+ // mField1
+ tokenIndex = mTokenizer.nextToken(line, delimIndex);
+ delimIndex = mTokenizer.nextDelimiter(line, tokenIndex);
+ mField1 = line.substring(tokenIndex, delimIndex);
+
+ // mCardName
+ tokenIndex = mTokenizer.nextToken(line, delimIndex);
+ mCardName = line.substring(tokenIndex);
+
+ // done
+ } else if (lineIndex == 1) {
+ tokenIndex = mTokenizer.nextToken(line, 0);
+ if (tokenIndex != -1) {
+ int keyIndex = line.indexOf(kUsbCardKeyStr);
+ mIsUsb = keyIndex != -1;
+ if (mIsUsb) {
+ mCardDescription = line.substring(tokenIndex, keyIndex - 1);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public String textFormat() {
+ return mCardName + " : " + mCardDescription;
+ }
+ }
+
+ public AlsaCardsParser() {}
+
+ public void scan() {
+ if (DEBUG) {
+ Slog.i(TAG, "AlsaCardsParser.scan()");
+ }
+ mCardRecords = new ArrayList<AlsaCardRecord>();
+
+ File cardsFile = new File(kCardsFilePath);
+ 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 (line == null) {
+ break;
+ }
+ 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 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/com/android/internal/alsa/AlsaDevicesParser.java b/core/java/com/android/internal/alsa/AlsaDevicesParser.java
new file mode 100644
index 0000000..81b7943
--- /dev/null
+++ b/core/java/com/android/internal/alsa/AlsaDevicesParser.java
@@ -0,0 +1,288 @@
+/*
+ * 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 and
+ * limitations under the License.
+ */
+package com.android.internal.alsa;
+
+import android.util.Slog;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * @hide
+ * Retrieves information from an ALSA "devices" file.
+ */
+public class AlsaDevicesParser {
+ private static final String TAG = "AlsaDevicesParser";
+ protected static final boolean DEBUG = false;
+
+ private static final String kDevicesFilePath = "/proc/asound/devices";
+
+ private static final int kIndex_CardDeviceField = 5;
+ private static final int kStartIndex_CardNum = 6;
+ private static final int kEndIndex_CardNum = 8; // one past
+ private static final int kStartIndex_DeviceNum = 9;
+ private static final int kEndIndex_DeviceNum = 11; // one past
+ private static final int kStartIndex_Type = 14;
+
+ private static LineTokenizer mTokenizer = new LineTokenizer(" :[]-");
+
+ private boolean mHasCaptureDevices = false;
+ private boolean mHasPlaybackDevices = false;
+ private boolean mHasMIDIDevices = false;
+
+ public class AlsaDeviceRecord {
+ public static final int kDeviceType_Unknown = -1;
+ public static final int kDeviceType_Audio = 0;
+ public static final int kDeviceType_Control = 1;
+ public static final int kDeviceType_MIDI = 2;
+
+ public static final int kDeviceDir_Unknown = -1;
+ public static final int kDeviceDir_Capture = 0;
+ public static final int kDeviceDir_Playback = 1;
+
+ int mCardNum = -1;
+ int mDeviceNum = -1;
+ int mDeviceType = kDeviceType_Unknown;
+ int mDeviceDir = kDeviceDir_Unknown;
+
+ public AlsaDeviceRecord() {}
+
+ public boolean parse(String line) {
+ // "0123456789012345678901234567890"
+ // " 2: [ 0-31]: digital audio playback"
+ // " 3: [ 0-30]: digital audio capture"
+ // " 35: [ 1] : control"
+ // " 36: [ 2- 0]: raw midi"
+
+ final int kToken_LineNum = 0;
+ final int kToken_CardNum = 1;
+ final int kToken_DeviceNum = 2;
+ final int kToken_Type0 = 3; // "digital", "control", "raw"
+ final int kToken_Type1 = 4; // "audio", "midi"
+ final int kToken_Type2 = 5; // "capture", "playback"
+
+ int tokenOffset = 0;
+ int delimOffset = 0;
+ int tokenIndex = kToken_LineNum;
+ while (true) {
+ tokenOffset = mTokenizer.nextToken(line, delimOffset);
+ if (tokenOffset == LineTokenizer.kTokenNotFound) {
+ break; // bail
+ }
+ delimOffset = mTokenizer.nextDelimiter(line, tokenOffset);
+ if (delimOffset == LineTokenizer.kTokenNotFound) {
+ delimOffset = line.length();
+ }
+ String token = line.substring(tokenOffset, delimOffset);
+
+ try {
+ switch (tokenIndex) {
+ case kToken_LineNum:
+ // ignore
+ break;
+
+ case kToken_CardNum:
+ mCardNum = Integer.parseInt(token);
+ if (line.charAt(delimOffset) != '-') {
+ tokenIndex++; // no device # in the token stream
+ }
+ break;
+
+ case kToken_DeviceNum:
+ mDeviceNum = Integer.parseInt(token);
+ break;
+
+ case kToken_Type0:
+ if (token.equals("digital")) {
+ // NOP
+ } else if (token.equals("control")) {
+ mDeviceType = kDeviceType_Control;
+ } else if (token.equals("raw")) {
+ // NOP
+ }
+ break;
+
+ case kToken_Type1:
+ if (token.equals("audio")) {
+ mDeviceType = kDeviceType_Audio;
+ } else if (token.equals("midi")) {
+ mDeviceType = kDeviceType_MIDI;
+ mHasMIDIDevices = true;
+ }
+ break;
+
+ case kToken_Type2:
+ if (token.equals("capture")) {
+ mDeviceDir = kDeviceDir_Capture;
+ mHasCaptureDevices = true;
+ } else if (token.equals("playback")) {
+ mDeviceDir = kDeviceDir_Playback;
+ mHasPlaybackDevices = true;
+ }
+ break;
+ } // switch (tokenIndex)
+ } catch (NumberFormatException e) {
+ Slog.e(TAG, "Failed to parse token " + tokenIndex + " of " + kDevicesFilePath
+ + " token: " + token);
+ return false;
+ }
+
+ tokenIndex++;
+ } // while (true)
+
+ return true;
+ } // parse()
+
+ public String textFormat() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[" + mCardNum + ":" + mDeviceNum + "]");
+
+ switch (mDeviceType) {
+ case kDeviceType_Unknown:
+ sb.append(" N/A");
+ break;
+ case kDeviceType_Audio:
+ sb.append(" Audio");
+ break;
+ case kDeviceType_Control:
+ sb.append(" Control");
+ break;
+ case kDeviceType_MIDI:
+ sb.append(" MIDI");
+ break;
+ }
+
+ switch (mDeviceDir) {
+ case kDeviceDir_Unknown:
+ sb.append(" N/A");
+ break;
+ case kDeviceDir_Capture:
+ sb.append(" Capture");
+ break;
+ case kDeviceDir_Playback:
+ sb.append(" Playback");
+ break;
+ }
+
+ return sb.toString();
+ }
+ }
+
+ private ArrayList<AlsaDeviceRecord> mDeviceRecords = new ArrayList<AlsaDeviceRecord>();
+
+ public AlsaDevicesParser() {}
+
+ //
+ // Access
+ //
+ public int getDefaultDeviceNum(int card) {
+ // TODO - This (obviously) isn't sufficient. Revisit.
+ return 0;
+ }
+
+ //
+ // Predicates
+ //
+ public boolean hasPlaybackDevices() {
+ return mHasPlaybackDevices;
+ }
+
+ public boolean hasPlaybackDevices(int card) {
+ for (AlsaDeviceRecord deviceRecord : mDeviceRecords) {
+ if (deviceRecord.mCardNum == card &&
+ deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_Audio &&
+ deviceRecord.mDeviceDir == AlsaDeviceRecord.kDeviceDir_Playback) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean hasCaptureDevices() {
+ return mHasCaptureDevices;
+ }
+
+ public boolean hasCaptureDevices(int card) {
+ for (AlsaDeviceRecord deviceRecord : mDeviceRecords) {
+ if (deviceRecord.mCardNum == card &&
+ deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_Audio &&
+ deviceRecord.mDeviceDir == AlsaDeviceRecord.kDeviceDir_Capture) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean hasMIDIDevices() {
+ return mHasMIDIDevices;
+ }
+
+ public boolean hasMIDIDevices(int card) {
+ for (AlsaDeviceRecord deviceRecord : mDeviceRecords) {
+ if (deviceRecord.mCardNum == card &&
+ deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_MIDI) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ //
+ // Process
+ //
+ private boolean isLineDeviceRecord(String line) {
+ return line.charAt(kIndex_CardDeviceField) == '[';
+ }
+
+ public void scan() {
+ mDeviceRecords.clear();
+
+ File devicesFile = new File(kDevicesFilePath);
+ try {
+ FileReader reader = new FileReader(devicesFile);
+ BufferedReader bufferedReader = new BufferedReader(reader);
+ String line = "";
+ while ((line = bufferedReader.readLine()) != null) {
+ if (isLineDeviceRecord(line)) {
+ AlsaDeviceRecord deviceRecord = new AlsaDeviceRecord();
+ deviceRecord.parse(line);
+ mDeviceRecords.add(deviceRecord);
+ }
+ }
+ reader.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ 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/com/android/internal/alsa/LineTokenizer.java b/core/java/com/android/internal/alsa/LineTokenizer.java
new file mode 100644
index 0000000..43047a9
--- /dev/null
+++ b/core/java/com/android/internal/alsa/LineTokenizer.java
@@ -0,0 +1,57 @@
+/*
+ * 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 and
+ * limitations under the License.
+ */
+package com.android.internal.alsa;
+
+/**
+ * @hide
+ * Breaks lines in an ALSA "cards" or "devices" file into tokens.
+ * TODO(pmclean) Look into replacing this with String.split().
+ */
+public class LineTokenizer {
+ public static final int kTokenNotFound = -1;
+
+ private String mDelimiters = "";
+
+ public LineTokenizer(String delimiters) {
+ mDelimiters = delimiters;
+ }
+
+ int nextToken(String line, int startIndex) {
+ int len = line.length();
+ int offset = startIndex;
+ for (; offset < len; offset++) {
+ if (mDelimiters.indexOf(line.charAt(offset)) == -1) {
+ // past a delimiter
+ break;
+ }
+ }
+
+ return offset < len ? offset : kTokenNotFound;
+ }
+
+ int nextDelimiter(String line, int startIndex) {
+ int len = line.length();
+ int offset = startIndex;
+ for (; offset < len; offset++) {
+ if (mDelimiters.indexOf(line.charAt(offset)) != -1) {
+ // past a delimiter
+ break;
+ }
+ }
+
+ return offset < len ? offset : kTokenNotFound;
+ }
+}