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 38const char kSoundDir[] = "/dev/snd"; 39 40typedef struct PCM_NODE { 41 unsigned int card; 42 unsigned int device; 43 unsigned int flags; 44} pcm_node_t; 45 46static pcm_node_t *pcmnodes; 47 48static unsigned int pcms; 49static unsigned int cards; 50static unsigned int mixers; 51static unsigned int timers; 52 53unsigned 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 72int 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 127int 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 163TEST(pcmtest, CheckAudioDir) { 164 pcms = getPcmNodes(); 165 ASSERT_GT(pcms, 0U); 166} 167 168TEST(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 175TEST(pcmtest, CheckPcmSanity0) { 176 ASSERT_NE(0U, pcms); 177} 178 179TEST(pcmtest, CheckPcmSanity1) { 180 EXPECT_NE(1U, pcms % 2); 181} 182 183TEST(pcmtests, CheckMixerSanity) { 184 ASSERT_NE(0U, mixers); 185 ASSERT_EQ(mixers, cards); 186} 187 188TEST(pcmtest, CheckTimesSanity0) { 189 ASSERT_NE(0U, timers); 190} 191 192TEST(pcmtest, CheckTimesSanity1) { 193 EXPECT_EQ(1U, timers); 194} 195 196TEST(pcmtest, CheckPcmDevices) { 197 for (unsigned int i = 0; i < pcms; i++) { 198 EXPECT_EQ(0, getPcmParams(i)); 199 } 200 free(pcmnodes); 201} 202 203TEST(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 213TEST(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