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 AlsaCardRecord()50 public AlsaCardRecord() {} 51 parse(String line, int lineIndex)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 textFormat()94 public String textFormat() { 95 return mCardName + " : " + mCardDescription; 96 } 97 log(int listIndex)98 public void log(int listIndex) { 99 Slog.d(TAG, "" + listIndex + 100 " [" + mCardNum + " " + mCardName + " : " + mCardDescription + 101 " usb:" + mIsUsb); 102 } 103 } 104 AlsaCardsParser()105 public AlsaCardsParser() {} 106 scan()107 public void scan() { 108 if (DEBUG) { 109 Slog.i(TAG, "AlsaCardsParser.scan()"); 110 } 111 mCardRecords = new ArrayList<AlsaCardRecord>(); 112 113 File cardsFile = new File(kCardsFilePath); 114 try { 115 FileReader reader = new FileReader(cardsFile); 116 BufferedReader bufferedReader = new BufferedReader(reader); 117 String line = ""; 118 while ((line = bufferedReader.readLine()) != null) { 119 AlsaCardRecord cardRecord = new AlsaCardRecord(); 120 if (DEBUG) { 121 Slog.i(TAG, " " + line); 122 } 123 cardRecord.parse(line, 0); 124 125 line = bufferedReader.readLine(); 126 if (line == null) { 127 break; 128 } 129 if (DEBUG) { 130 Slog.i(TAG, " " + line); 131 } 132 cardRecord.parse(line, 1); 133 134 mCardRecords.add(cardRecord); 135 } 136 reader.close(); 137 } catch (FileNotFoundException e) { 138 e.printStackTrace(); 139 } catch (IOException e) { 140 e.printStackTrace(); 141 } 142 } 143 getScanRecords()144 public ArrayList<AlsaCardRecord> getScanRecords() { 145 return mCardRecords; 146 } 147 getCardRecordAt(int index)148 public AlsaCardRecord getCardRecordAt(int index) { 149 return mCardRecords.get(index); 150 } 151 getCardRecordFor(int cardNum)152 public AlsaCardRecord getCardRecordFor(int cardNum) { 153 for (AlsaCardRecord rec : mCardRecords) { 154 if (rec.mCardNum == cardNum) { 155 return rec; 156 } 157 } 158 159 return null; 160 } 161 getNumCardRecords()162 public int getNumCardRecords() { 163 return mCardRecords.size(); 164 } 165 isCardUsb(int cardNum)166 public boolean isCardUsb(int cardNum) { 167 for (AlsaCardRecord rec : mCardRecords) { 168 if (rec.mCardNum == cardNum) { 169 return rec.mIsUsb; 170 } 171 } 172 173 return false; 174 } 175 176 // return -1 if none found getDefaultUsbCard()177 public int getDefaultUsbCard() { 178 // save the current list of devices 179 ArrayList<AlsaCardsParser.AlsaCardRecord> prevRecs = mCardRecords; 180 if (DEBUG) { 181 LogDevices("Previous Devices:", prevRecs); 182 } 183 184 // get the new list of devices 185 scan(); 186 if (DEBUG) { 187 LogDevices("Current Devices:", mCardRecords); 188 } 189 190 // Calculate the difference between the old and new device list 191 ArrayList<AlsaCardRecord> newRecs = getNewCardRecords(prevRecs); 192 if (DEBUG) { 193 LogDevices("New Devices:", newRecs); 194 } 195 196 // Choose the most-recently added EXTERNAL card 197 // Check recently added devices 198 for (AlsaCardRecord rec : newRecs) { 199 if (DEBUG) { 200 Slog.d(TAG, rec.mCardName + " card:" + rec.mCardNum + " usb:" + rec.mIsUsb); 201 } 202 if (rec.mIsUsb) { 203 // Found it 204 return rec.mCardNum; 205 } 206 } 207 208 // or return the first added EXTERNAL card? 209 for (AlsaCardRecord rec : prevRecs) { 210 if (DEBUG) { 211 Slog.d(TAG, rec.mCardName + " card:" + rec.mCardNum + " usb:" + rec.mIsUsb); 212 } 213 if (rec.mIsUsb) { 214 return rec.mCardNum; 215 } 216 } 217 218 return -1; 219 } 220 getDefaultCard()221 public int getDefaultCard() { 222 // return an external card if possible 223 int card = getDefaultUsbCard(); 224 if (DEBUG) { 225 Slog.d(TAG, "getDefaultCard() default usb card:" + card); 226 } 227 228 if (card < 0 && getNumCardRecords() > 0) { 229 // otherwise return the (internal) card with the highest number 230 card = getCardRecordAt(getNumCardRecords() - 1).mCardNum; 231 } 232 if (DEBUG) { 233 Slog.d(TAG, " returns card:" + card); 234 } 235 return card; 236 } 237 hasCardNumber(ArrayList<AlsaCardRecord> recs, int cardNum)238 static public boolean hasCardNumber(ArrayList<AlsaCardRecord> recs, int cardNum) { 239 for (AlsaCardRecord cardRec : recs) { 240 if (cardRec.mCardNum == cardNum) { 241 return true; 242 } 243 } 244 return false; 245 } 246 getNewCardRecords(ArrayList<AlsaCardRecord> prevScanRecs)247 public ArrayList<AlsaCardRecord> getNewCardRecords(ArrayList<AlsaCardRecord> prevScanRecs) { 248 ArrayList<AlsaCardRecord> newRecs = new ArrayList<AlsaCardRecord>(); 249 for (AlsaCardRecord rec : mCardRecords) { 250 // now scan to see if this card number is in the previous scan list 251 if (!hasCardNumber(prevScanRecs, rec.mCardNum)) { 252 newRecs.add(rec); 253 } 254 } 255 return newRecs; 256 } 257 258 // 259 // Logging 260 // Log(String heading)261 public void Log(String heading) { 262 if (DEBUG) { 263 Slog.i(TAG, heading); 264 for (AlsaCardRecord cardRec : mCardRecords) { 265 Slog.i(TAG, cardRec.textFormat()); 266 } 267 } 268 } 269 LogDevices(String caption, ArrayList<AlsaCardRecord> deviceList)270 static public void LogDevices(String caption, ArrayList<AlsaCardRecord> deviceList) { 271 Slog.d(TAG, caption + " ----------------"); 272 int listIndex = 0; 273 for (AlsaCardRecord device : deviceList) { 274 device.log(listIndex++); 275 } 276 Slog.d(TAG, "----------------"); 277 } 278 } 279