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 package android.alsa;
     17 
     18 import android.util.Slog;
     19 import java.io.BufferedReader;
     20 import java.io.File;
     21 import java.io.FileNotFoundException;
     22 import java.io.FileReader;
     23 import java.io.IOException;
     24 import java.util.Vector;
     25 
     26 /**
     27  * @hide
     28  * Retrieves information from an ALSA "devices" file.
     29  */
     30 public class AlsaDevicesParser {
     31     private static final String TAG = "AlsaDevicesParser";
     32 
     33     private static final int kIndex_CardDeviceField = 5;
     34     private static final int kStartIndex_CardNum = 6;
     35     private static final int kEndIndex_CardNum = 8; // one past
     36     private static final int kStartIndex_DeviceNum = 9;
     37     private static final int kEndIndex_DeviceNum = 11; // one past
     38     private static final int kStartIndex_Type = 14;
     39 
     40     private static LineTokenizer mTokenizer = new LineTokenizer(" :[]-");
     41 
     42     private boolean mHasCaptureDevices = false;
     43     private boolean mHasPlaybackDevices = false;
     44     private boolean mHasMIDIDevices = false;
     45 
     46     public class AlsaDeviceRecord {
     47         public static final int kDeviceType_Unknown = -1;
     48         public static final int kDeviceType_Audio = 0;
     49         public static final int kDeviceType_Control = 1;
     50         public static final int kDeviceType_MIDI = 2;
     51 
     52         public static final int kDeviceDir_Unknown = -1;
     53         public static final int kDeviceDir_Capture = 0;
     54         public static final int kDeviceDir_Playback = 1;
     55 
     56         int mCardNum = -1;
     57         int mDeviceNum = -1;
     58         int mDeviceType = kDeviceType_Unknown;
     59         int mDeviceDir = kDeviceDir_Unknown;
     60 
     61         public AlsaDeviceRecord() {
     62         }
     63 
     64         public boolean parse(String line) {
     65             // "0123456789012345678901234567890"
     66             // "  2: [ 0-31]: digital audio playback"
     67             // "  3: [ 0-30]: digital audio capture"
     68             // " 35: [ 1]   : control"
     69             // " 36: [ 2- 0]: raw midi"
     70 
     71             final int kToken_LineNum = 0;
     72             final int kToken_CardNum = 1;
     73             final int kToken_DeviceNum = 2;
     74             final int kToken_Type0 = 3; // "digital", "control", "raw"
     75             final int kToken_Type1 = 4; // "audio", "midi"
     76             final int kToken_Type2 = 5; // "capture", "playback"
     77 
     78             int tokenOffset = 0;
     79             int delimOffset = 0;
     80             int tokenIndex = kToken_LineNum;
     81             while (true) {
     82                 tokenOffset = mTokenizer.nextToken(line, delimOffset);
     83                 if (tokenOffset == LineTokenizer.kTokenNotFound) {
     84                     break; // bail
     85                 }
     86                 delimOffset = mTokenizer.nextDelimiter(line, tokenOffset);
     87                 if (delimOffset == LineTokenizer.kTokenNotFound) {
     88                     delimOffset = line.length();
     89                 }
     90                 String token = line.substring(tokenOffset, delimOffset);
     91 
     92                 switch (tokenIndex) {
     93                 case kToken_LineNum:
     94                     // ignore
     95                     break;
     96 
     97                 case kToken_CardNum:
     98                     mCardNum = Integer.parseInt(token);
     99                     if (line.charAt(delimOffset) != '-') {
    100                         tokenIndex++; // no device # in the token stream
    101                     }
    102                     break;
    103 
    104                 case kToken_DeviceNum:
    105                     mDeviceNum = Integer.parseInt(token);
    106                     break;
    107 
    108                 case kToken_Type0:
    109                     if (token.equals("digital")) {
    110                         // NOP
    111                     } else if (token.equals("control")) {
    112                         mDeviceType = kDeviceType_Control;
    113                     } else if (token.equals("raw")) {
    114                         // NOP
    115                     }
    116                     break;
    117 
    118                 case kToken_Type1:
    119                     if (token.equals("audio")) {
    120                         mDeviceType = kDeviceType_Audio;
    121                     } else if (token.equals("midi")) {
    122                         mDeviceType = kDeviceType_MIDI;
    123                         mHasMIDIDevices = true;
    124                     }
    125                     break;
    126 
    127                 case kToken_Type2:
    128                     if (token.equals("capture")) {
    129                         mDeviceDir = kDeviceDir_Capture;
    130                         mHasCaptureDevices = true;
    131                     } else if (token.equals("playback")) {
    132                         mDeviceDir = kDeviceDir_Playback;
    133                         mHasPlaybackDevices = true;
    134                     }
    135                     break;
    136                 } // switch (tokenIndex)
    137 
    138                 tokenIndex++;
    139             } // while (true)
    140 
    141             return true;
    142         } // parse()
    143 
    144         public String textFormat() {
    145             StringBuilder sb = new StringBuilder();
    146             sb.append("[" + mCardNum + ":" + mDeviceNum + "]");
    147 
    148             switch (mDeviceType) {
    149             case kDeviceType_Unknown:
    150                 sb.append(" N/A");
    151                 break;
    152             case kDeviceType_Audio:
    153                 sb.append(" Audio");
    154                 break;
    155             case kDeviceType_Control:
    156                 sb.append(" Control");
    157                 break;
    158             case kDeviceType_MIDI:
    159                 sb.append(" MIDI");
    160                 break;
    161             }
    162 
    163             switch (mDeviceDir) {
    164             case kDeviceDir_Unknown:
    165                 sb.append(" N/A");
    166                 break;
    167             case kDeviceDir_Capture:
    168                 sb.append(" Capture");
    169                 break;
    170             case kDeviceDir_Playback:
    171                 sb.append(" Playback");
    172                 break;
    173             }
    174 
    175             return sb.toString();
    176         }
    177     }
    178 
    179     private Vector<AlsaDeviceRecord>
    180             deviceRecords_ = new Vector<AlsaDeviceRecord>();
    181 
    182     private boolean isLineDeviceRecord(String line) {
    183         return line.charAt(kIndex_CardDeviceField) == '[';
    184     }
    185 
    186     public AlsaDevicesParser() {
    187     }
    188 
    189     public int getNumDeviceRecords() {
    190         return deviceRecords_.size();
    191     }
    192 
    193     public AlsaDeviceRecord getDeviceRecordAt(int index) {
    194         return deviceRecords_.get(index);
    195     }
    196 
    197     public void Log() {
    198         int numDevRecs = getNumDeviceRecords();
    199         for (int index = 0; index < numDevRecs; ++index) {
    200             Slog.w(TAG, "usb:" + getDeviceRecordAt(index).textFormat());
    201         }
    202     }
    203 
    204     public boolean hasPlaybackDevices() {
    205         return mHasPlaybackDevices;
    206     }
    207 
    208     public boolean hasPlaybackDevices(int card) {
    209         for (int index = 0; index < deviceRecords_.size(); index++) {
    210             AlsaDeviceRecord deviceRecord = deviceRecords_.get(index);
    211             if (deviceRecord.mCardNum == card &&
    212                 deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_Audio &&
    213                 deviceRecord.mDeviceDir == AlsaDeviceRecord.kDeviceDir_Playback) {
    214                 return true;
    215             }
    216         }
    217         return false;
    218     }
    219 
    220     public boolean hasCaptureDevices() {
    221         return mHasCaptureDevices;
    222     }
    223 
    224     public boolean hasCaptureDevices(int card) {
    225         for (int index = 0; index < deviceRecords_.size(); index++) {
    226             AlsaDeviceRecord deviceRecord = deviceRecords_.get(index);
    227             if (deviceRecord.mCardNum == card &&
    228                 deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_Audio &&
    229                 deviceRecord.mDeviceDir == AlsaDeviceRecord.kDeviceDir_Capture) {
    230                 return true;
    231             }
    232         }
    233         return false;
    234     }
    235 
    236     public boolean hasMIDIDevices() {
    237         return mHasMIDIDevices;
    238     }
    239 
    240     public boolean hasMIDIDevices(int card) {
    241         for (int index = 0; index < deviceRecords_.size(); index++) {
    242             AlsaDeviceRecord deviceRecord = deviceRecords_.get(index);
    243             if (deviceRecord.mCardNum == card &&
    244                 deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_MIDI) {
    245                 return true;
    246             }
    247         }
    248         return false;
    249     }
    250 
    251     public void scan() {
    252         deviceRecords_.clear();
    253 
    254         final String devicesFilePath = "/proc/asound/devices";
    255         File devicesFile = new File(devicesFilePath);
    256         try {
    257             FileReader reader = new FileReader(devicesFile);
    258             BufferedReader bufferedReader = new BufferedReader(reader);
    259             String line = "";
    260             while ((line = bufferedReader.readLine()) != null) {
    261                 if (isLineDeviceRecord(line)) {
    262                     AlsaDeviceRecord deviceRecord = new AlsaDeviceRecord();
    263                     deviceRecord.parse(line);
    264                     deviceRecords_.add(deviceRecord);
    265                 }
    266             }
    267             reader.close();
    268         } catch (FileNotFoundException e) {
    269             e.printStackTrace();
    270         } catch (IOException e) {
    271             e.printStackTrace();
    272         }
    273     }
    274 } // class AlsaDevicesParser
    275 
    276