1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.alsa; 18 19 import android.util.Slog; 20 import java.io.BufferedReader; 21 import java.io.File; 22 import java.io.FileNotFoundException; 23 import java.io.FileReader; 24 import java.io.IOException; 25 import java.util.ArrayList; 26 27 /** 28 * @hide Retrieves information from an ALSA "cards" file. 29 */ 30 public class AlsaCardsParser { 31 private static final String TAG = "AlsaCardsParser"; 32 protected static final boolean DEBUG = false; 33 34 private static final String kCardsFilePath = "/proc/asound/cards"; 35 36 private static LineTokenizer mTokenizer = new LineTokenizer(" :[]"); 37 38 private ArrayList<AlsaCardRecord> mCardRecords = new ArrayList<AlsaCardRecord>(); 39 40 public class AlsaCardRecord { 41 private static final String TAG = "AlsaCardRecord"; 42 private static final String kUsbCardKeyStr = "at usb-"; 43 44 public int mCardNum = -1; 45 public String mField1 = ""; 46 public String mCardName = ""; 47 public String mCardDescription = ""; 48 public boolean mIsUsb = false; 49 50 public AlsaCardRecord() {} 51 52 public boolean parse(String line, int lineIndex) { 53 int tokenIndex = 0; 54 int delimIndex = 0; 55 56 if (lineIndex == 0) { 57 // line # (skip) 58 tokenIndex = mTokenizer.nextToken(line, tokenIndex); 59 delimIndex = mTokenizer.nextDelimiter(line, tokenIndex); 60 61 try { 62 // mCardNum 63 mCardNum = Integer.parseInt(line.substring(tokenIndex, delimIndex)); 64 } catch (NumberFormatException e) { 65 Slog.e(TAG, "Failed to parse line " + lineIndex + " of " + kCardsFilePath 66 + ": " + line.substring(tokenIndex, delimIndex)); 67 return false; 68 } 69 70 // mField1 71 tokenIndex = mTokenizer.nextToken(line, delimIndex); 72 delimIndex = mTokenizer.nextDelimiter(line, tokenIndex); 73 mField1 = line.substring(tokenIndex, delimIndex); 74 75 // mCardName 76 tokenIndex = mTokenizer.nextToken(line, delimIndex); 77 mCardName = line.substring(tokenIndex); 78 79 // done 80 } else if (lineIndex == 1) { 81 tokenIndex = mTokenizer.nextToken(line, 0); 82 if (tokenIndex != -1) { 83 int keyIndex = line.indexOf(kUsbCardKeyStr); 84 mIsUsb = keyIndex != -1; 85 if (mIsUsb) { 86 mCardDescription = line.substring(tokenIndex, keyIndex - 1); 87 } 88 } 89 } 90 91 return true; 92 } 93 94 public String textFormat() { 95 return mCardName + " : " + mCardDescription; 96 } 97 } 98 99 public AlsaCardsParser() {} 100 101 public void scan() { 102 if (DEBUG) { 103 Slog.i(TAG, "AlsaCardsParser.scan()"); 104 } 105 mCardRecords = new ArrayList<AlsaCardRecord>(); 106 107 File cardsFile = new File(kCardsFilePath); 108 try { 109 FileReader reader = new FileReader(cardsFile); 110 BufferedReader bufferedReader = new BufferedReader(reader); 111 String line = ""; 112 while ((line = bufferedReader.readLine()) != null) { 113 AlsaCardRecord cardRecord = new AlsaCardRecord(); 114 if (DEBUG) { 115 Slog.i(TAG, " " + line); 116 } 117 cardRecord.parse(line, 0); 118 119 line = bufferedReader.readLine(); 120 if (line == null) { 121 break; 122 } 123 if (DEBUG) { 124 Slog.i(TAG, " " + line); 125 } 126 cardRecord.parse(line, 1); 127 128 mCardRecords.add(cardRecord); 129 } 130 reader.close(); 131 } catch (FileNotFoundException e) { 132 e.printStackTrace(); 133 } catch (IOException e) { 134 e.printStackTrace(); 135 } 136 } 137 138 public ArrayList<AlsaCardRecord> getScanRecords() { 139 return mCardRecords; 140 } 141 142 public AlsaCardRecord getCardRecordAt(int index) { 143 return mCardRecords.get(index); 144 } 145 146 public AlsaCardRecord getCardRecordFor(int cardNum) { 147 for (AlsaCardRecord rec : mCardRecords) { 148 if (rec.mCardNum == cardNum) { 149 return rec; 150 } 151 } 152 153 return null; 154 } 155 156 public int getNumCardRecords() { 157 return mCardRecords.size(); 158 } 159 160 public boolean isCardUsb(int cardNum) { 161 for (AlsaCardRecord rec : mCardRecords) { 162 if (rec.mCardNum == cardNum) { 163 return rec.mIsUsb; 164 } 165 } 166 167 return false; 168 } 169 170 // return -1 if none found 171 public int getDefaultUsbCard() { 172 // Choose the most-recently added EXTERNAL card 173 // or return the first added EXTERNAL card? 174 for (AlsaCardRecord rec : mCardRecords) { 175 if (rec.mIsUsb) { 176 return rec.mCardNum; 177 } 178 } 179 180 return -1; 181 } 182 183 public int getDefaultCard() { 184 // return an external card if possible 185 int card = getDefaultUsbCard(); 186 187 if (card < 0 && getNumCardRecords() > 0) { 188 // otherwise return the (internal) card with the highest number 189 card = getCardRecordAt(getNumCardRecords() - 1).mCardNum; 190 } 191 return card; 192 } 193 194 static public boolean hasCardNumber(ArrayList<AlsaCardRecord> recs, int cardNum) { 195 for (AlsaCardRecord cardRec : recs) { 196 if (cardRec.mCardNum == cardNum) { 197 return true; 198 } 199 } 200 return false; 201 } 202 203 public ArrayList<AlsaCardRecord> getNewCardRecords(ArrayList<AlsaCardRecord> prevScanRecs) { 204 ArrayList<AlsaCardRecord> newRecs = new ArrayList<AlsaCardRecord>(); 205 for (AlsaCardRecord rec : mCardRecords) { 206 // now scan to see if this card number is in the previous scan list 207 if (!hasCardNumber(prevScanRecs, rec.mCardNum)) { 208 newRecs.add(rec); 209 } 210 } 211 return newRecs; 212 } 213 214 // 215 // Logging 216 // 217 public void Log(String heading) { 218 if (DEBUG) { 219 Slog.i(TAG, heading); 220 for (AlsaCardRecord cardRec : mCardRecords) { 221 Slog.i(TAG, cardRec.textFormat()); 222 } 223 } 224 } 225 } 226