View Javadoc
1   /*
2    * Copyright 2018-2022 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.hardware.platform.linux;
6   
7   import java.io.File;
8   import java.util.ArrayList;
9   import java.util.List;
10  import java.util.Map;
11  
12  import org.slf4j.Logger;
13  import org.slf4j.LoggerFactory;
14  
15  import oshi.annotation.concurrent.Immutable;
16  import oshi.hardware.SoundCard;
17  import oshi.hardware.common.AbstractSoundCard;
18  import oshi.util.FileUtil;
19  import oshi.util.platform.linux.ProcPath;
20  
21  /**
22   * Sound card data obtained via /proc/asound directory
23   */
24  @Immutable
25  final class LinuxSoundCard extends AbstractSoundCard {
26  
27      private static final Logger LOG = LoggerFactory.getLogger(LinuxSoundCard.class);
28  
29      private static final String CARD_FOLDER = "card";
30      private static final String CARDS_FILE = "cards";
31      private static final String ID_FILE = "id";
32  
33      /**
34       * Constructor for LinuxSoundCard.
35       *
36       * @param kernelVersion The version
37       * @param name          The name
38       * @param codec         The codec
39       */
40      LinuxSoundCard(String kernelVersion, String name, String codec) {
41          super(kernelVersion, name, codec);
42      }
43  
44      /**
45       * Method to find all the card folders contained in the <b>asound</b> folder denoting the cards currently contained
46       * in our machine.
47       *
48       * @return : A list of files starting with 'card'
49       */
50      private static List<File> getCardFolders() {
51          File cardsDirectory = new File(ProcPath.ASOUND);
52          List<File> cardFolders = new ArrayList<>();
53          File[] allContents = cardsDirectory.listFiles();
54          if (allContents != null) {
55              for (File card : allContents) {
56                  if (card.getName().startsWith(CARD_FOLDER) && card.isDirectory()) {
57                      cardFolders.add(card);
58                  }
59              }
60          } else {
61              LOG.warn("No Audio Cards Found");
62          }
63          return cardFolders;
64      }
65  
66      /**
67       * Reads the 'version' file in the asound folder that contains the complete name of the ALSA driver. Reads all the
68       * lines of the file and retrieves the first line.
69       *
70       * @return The complete name of the ALSA driver currently residing in our machine
71       */
72      private static String getSoundCardVersion() {
73          String driverVersion = FileUtil.getStringFromFile(ProcPath.ASOUND + "version");
74          return driverVersion.isEmpty() ? "not available" : driverVersion;
75      }
76  
77      /**
78       * Retrieves the codec of the sound card contained in the <b>codec</b> file. The name of the codec is always the
79       * first line of that file. <br>
80       * <b>Working</b> <br>
81       * This converts the codec file into key value pairs using the {@link FileUtil} class and then returns the value of
82       * the <b>Codec</b> key.
83       *
84       * @param cardDir The sound card directory
85       * @return The name of the codec
86       */
87      private static String getCardCodec(File cardDir) {
88          String cardCodec = "";
89          File[] cardFiles = cardDir.listFiles();
90          if (cardFiles != null) {
91              for (File file : cardFiles) {
92                  if (file.getName().startsWith("codec")) {
93                      if (!file.isDirectory()) {
94                          cardCodec = FileUtil.getKeyValueMapFromFile(file.getPath(), ":").get("Codec");
95                      } else {
96                          // on various centos environments, this is a subdirectory
97                          // each file is usually named something like
98                          // codec#0-0
99                          // example : ac97#0-0
100                         File[] codecs = file.listFiles();
101                         if (codecs != null) {
102                             for (File codec : codecs) {
103                                 if (!codec.isDirectory() && codec.getName().contains("#")) {
104                                     cardCodec = codec.getName().substring(0, codec.getName().indexOf('#'));
105                                     break;
106                                 }
107                             }
108                         }
109                     }
110                 }
111             }
112         }
113         return cardCodec;
114     }
115 
116     /**
117      * Retrieves the name of the sound card by :
118      * <ol>
119      * <li>Reading the <b>id</b> file and comparing each id with the card id present in the <b>cards</b> file</li>
120      * <li>If the id and the card name matches , then it assigns that name to {@literal cardName}</li>
121      * </ol>
122      *
123      * @param file The sound card File.
124      * @return The name of the sound card.
125      */
126     private static String getCardName(File file) {
127         String cardName = "Not Found..";
128         Map<String, String> cardNamePairs = FileUtil.getKeyValueMapFromFile(ProcPath.ASOUND + "/" + CARDS_FILE, ":");
129         String cardId = FileUtil.getStringFromFile(file.getPath() + "/" + ID_FILE);
130         for (Map.Entry<String, String> entry : cardNamePairs.entrySet()) {
131             if (entry.getKey().contains(cardId)) {
132                 cardName = entry.getValue();
133                 return cardName;
134             }
135         }
136         return cardName;
137     }
138 
139     /**
140      * public method used by {@link oshi.hardware.common.AbstractHardwareAbstractionLayer} to access the sound cards.
141      *
142      * @return List of {@link oshi.hardware.platform.linux.LinuxSoundCard} objects.
143      */
144     public static List<SoundCard> getSoundCards() {
145         List<SoundCard> soundCards = new ArrayList<>();
146         for (File cardFile : getCardFolders()) {
147             soundCards.add(new LinuxSoundCard(getSoundCardVersion(), getCardName(cardFile), getCardCodec(cardFile)));
148         }
149         return soundCards;
150     }
151 }