Home | History | Annotate | Download | only in alsa
      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         public void log(int listIndex) {
     99             Slog.d(TAG, "" + listIndex +
    100                 " [" + mCardNum + " " + mCardName + " : " + mCardDescription +
    101                 " usb:" + mIsUsb);
    102         }
    103     }
    104 
    105     public AlsaCardsParser() {}
    106 
    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 
    144     public ArrayList<AlsaCardRecord> getScanRecords() {
    145         return mCardRecords;
    146     }
    147 
    148     public AlsaCardRecord getCardRecordAt(int index) {
    149         return mCardRecords.get(index);
    150     }
    151 
    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 
    162     public int getNumCardRecords() {
    163         return mCardRecords.size();
    164     }
    165 
    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
    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 
    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 
    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 
    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     //
    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 
    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