• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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 requied 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 
18 #include <assert.h>
19 #include <dirent.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <gtest/gtest.h>
25 #include <linux/ioctl.h>
26 #include <sound/asound.h>
27 #include <sys/types.h>
28 #include <tinyalsa/asoundlib.h>
29 
30 #define LOG_TAG "pcmtest"
31 #include <utils/Log.h>
32 
33 #define PCM_PREFIX	"pcm"
34 #define MIXER_PREFIX	"control"
35 #define TIMER_PREFIX	"timer"
36 
37 #define MAXSTR 200
38 #define testPrintI(...)                 \
39     do {                                \
40         testPrint(stdout, __VA_ARGS__); \
41     } while (0)
42 
43 const char kSoundDir[] = "/dev/snd";
44 
45 typedef struct PCM_NODE {
46     unsigned int card;
47     unsigned int device;
48     unsigned int flags;
49 } pcm_node_t;
50 
51 static pcm_node_t *pcmnodes;
52 
53 static unsigned int pcms;
54 static unsigned int cards;
55 static unsigned int mixers;
56 static unsigned int timers;
57 
testPrint(FILE * stream,const char * fmt,...)58 void testPrint(FILE* stream, const char* fmt, ...) {
59     char line[MAXSTR];
60     va_list args;
61 
62     va_start(args, fmt);
63     vsnprintf(line, sizeof(line), fmt, args);
64     if (stream == stderr) {
65         ALOG(LOG_ERROR, LOG_TAG, "%s", line);
66     } else {
67         ALOG(LOG_INFO, LOG_TAG, "%s", line);
68     }
69     vfprintf(stream, fmt, args);
70     va_end(args);
71     fputc('\n', stream);
72 }
73 
getPcmNodes(void)74 unsigned int getPcmNodes(void)
75 {
76     DIR *d;
77     struct dirent *de;
78     unsigned int pcount = 0;
79 
80     d = opendir(kSoundDir);
81     if (d == 0)
82         return 0;
83     while ((de = readdir(d)) != NULL) {
84         if (de->d_name[0] == '.')
85             continue;
86         if (strstr(de->d_name, PCM_PREFIX))
87             pcount++;
88     }
89     closedir(d);
90     return pcount;
91 }
92 
getSndDev(unsigned int pcmdevs)93 int getSndDev(unsigned int pcmdevs)
94 {
95     DIR *d;
96     struct dirent *de;
97     unsigned int prevcard = -1;
98 
99     d = opendir(kSoundDir);
100     if (d == 0)
101         return -ENXIO;
102     pcmnodes = (pcm_node_t *)malloc(pcmdevs * sizeof(pcm_node_t));
103     if (!pcmnodes)
104         return -ENOMEM;
105     pcms = 0;
106     while ((de = readdir(d)) != NULL) {
107         if (de->d_name[0] == '.')
108             continue;
109         /* printf("%s\n", de->d_name); */
110         if (strstr(de->d_name, PCM_PREFIX)) {
111             char flags;
112 
113             EXPECT_LE(pcms, pcmdevs) << "Too many PCMs";
114             if (pcms >= pcmdevs)
115                 continue;
116             sscanf(de->d_name, PCM_PREFIX "C%uD%u", &(pcmnodes[pcms].card),
117                    &(pcmnodes[pcms].device));
118             flags = de->d_name[strlen(de->d_name)-1];
119             if (flags == 'c') {
120                 pcmnodes[pcms].flags = PCM_IN;
121             } else if(flags == 'p') {
122                 pcmnodes[pcms].flags = PCM_OUT;
123             } else {
124                 pcmnodes[pcms].flags = -1;
125                 testPrintI("Unknown PCM type = %c", flags);
126             }
127             if (prevcard != pcmnodes[pcms].card)
128                 cards++;
129             prevcard = pcmnodes[pcms].card;
130             pcms++;
131             continue;
132         }
133         if (strstr(de->d_name, MIXER_PREFIX)) {
134             unsigned int mixer = -1;
135             sscanf(de->d_name, MIXER_PREFIX "C%u", &mixer);
136             mixers++;
137             continue;
138         }
139         if (strstr(de->d_name, TIMER_PREFIX)) {
140             timers++;
141             continue;
142         }
143     }
144     closedir(d);
145     return 0;
146 }
147 
getPcmParams(unsigned int i)148 int getPcmParams(unsigned int i)
149 {
150     struct pcm_params *params;
151     unsigned int min;
152     unsigned int max;
153 
154     params = pcm_params_get(pcmnodes[i].card, pcmnodes[i].device,
155                             pcmnodes[i].flags);
156     if (params == NULL)
157         return -ENODEV;
158 
159     min = pcm_params_get_min(params, PCM_PARAM_RATE);
160     max = pcm_params_get_max(params, PCM_PARAM_RATE);
161     EXPECT_LE(min, max);
162     /* printf("        Rate:\tmin=%uHz\tmax=%uHz\n", min, max); */
163     min = pcm_params_get_min(params, PCM_PARAM_CHANNELS);
164     max = pcm_params_get_max(params, PCM_PARAM_CHANNELS);
165     EXPECT_LE(min, max);
166     /* printf("    Channels:\tmin=%u\t\tmax=%u\n", min, max); */
167     min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS);
168     max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS);
169     EXPECT_LE(min, max);
170     /* printf(" Sample bits:\tmin=%u\t\tmax=%u\n", min, max); */
171     min = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE);
172     max = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE);
173     EXPECT_LE(min, max);
174     /* printf(" Period size:\tmin=%u\t\tmax=%u\n", min, max); */
175     min = pcm_params_get_min(params, PCM_PARAM_PERIODS);
176     max = pcm_params_get_max(params, PCM_PARAM_PERIODS);
177     EXPECT_LE(min, max);
178     /* printf("Period count:\tmin=%u\t\tmax=%u\n", min, max); */
179 
180     pcm_params_free(params);
181     return 0;
182 }
183 
TEST(pcmtest,CheckAudioDir)184 TEST(pcmtest, CheckAudioDir) {
185     pcms = getPcmNodes();
186     ASSERT_GT(pcms, 0U);
187 }
188 
TEST(pcmtest,GetSoundDevs)189 TEST(pcmtest, GetSoundDevs) {
190     int err = getSndDev(pcms);
191     testPrintI(" DEVICES = PCMS:%u CARDS:%u MIXERS:%u TIMERS:%u",
192                pcms, cards, mixers, timers);
193     ASSERT_EQ(0, err);
194 }
195 
TEST(pcmtest,CheckPcmSanity0)196 TEST(pcmtest, CheckPcmSanity0) {
197     ASSERT_NE(0U, pcms);
198 }
199 
TEST(pcmtest,CheckPcmSanity1)200 TEST(pcmtest, CheckPcmSanity1) {
201     EXPECT_NE(1U, pcms % 2);
202 }
203 
TEST(pcmtests,CheckMixerSanity)204 TEST(pcmtests, CheckMixerSanity) {
205     ASSERT_NE(0U, mixers);
206     ASSERT_EQ(mixers, cards);
207 }
208 
TEST(pcmtest,CheckTimesSanity0)209 TEST(pcmtest, CheckTimesSanity0) {
210     ASSERT_NE(0U, timers);
211 }
212 
TEST(pcmtest,CheckTimesSanity1)213 TEST(pcmtest, CheckTimesSanity1) {
214     EXPECT_EQ(1U, timers);
215 }
216 
TEST(pcmtest,CheckPcmDevices)217 TEST(pcmtest, CheckPcmDevices) {
218     for (unsigned int i = 0; i < pcms; i++) {
219         EXPECT_EQ(0, getPcmParams(i));
220     }
221     free(pcmnodes);
222 }
223 
TEST(pcmtest,CheckMixerDevices)224 TEST(pcmtest, CheckMixerDevices) {
225     struct mixer *mixer;
226     for (unsigned int i = 0; i < mixers; i++) {
227          mixer = mixer_open(i);
228          EXPECT_TRUE(mixer != NULL);
229          if (mixer)
230              mixer_close(mixer);
231     }
232 }
233 
TEST(pcmtest,CheckTimer)234 TEST(pcmtest, CheckTimer) {
235     int ver = 0;
236     int fd = open("/dev/snd/timer", O_RDWR | O_NONBLOCK);
237     ASSERT_GE(fd, 0);
238     int ret = ioctl(fd, SNDRV_TIMER_IOCTL_PVERSION, &ver);
239     EXPECT_EQ(0, ret);
240     testPrintI(" Timer Version = 0x%x", ver);
241     close(fd);
242 }
243