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