You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
5.8 KiB
221 lines
5.8 KiB
/* |
|
* Copyright (C) 2013 The Android Open Source Project |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless requied by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
* |
|
*/ |
|
|
|
#include <assert.h> |
|
#include <dirent.h> |
|
#include <errno.h> |
|
#include <fcntl.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <gtest/gtest.h> |
|
#include <linux/ioctl.h> |
|
#include <sound/asound.h> |
|
#include <sys/types.h> |
|
#include <tinyalsa/asoundlib.h> |
|
|
|
#define LOG_TAG "pcmtest" |
|
#include <utils/Log.h> |
|
#include <testUtil.h> |
|
|
|
#define PCM_PREFIX "pcm" |
|
#define MIXER_PREFIX "control" |
|
#define TIMER_PREFIX "timer" |
|
|
|
const char kSoundDir[] = "/dev/snd"; |
|
|
|
typedef struct PCM_NODE { |
|
unsigned int card; |
|
unsigned int device; |
|
unsigned int flags; |
|
} pcm_node_t; |
|
|
|
static pcm_node_t *pcmnodes; |
|
|
|
static unsigned int pcms; |
|
static unsigned int cards; |
|
static unsigned int mixers; |
|
static unsigned int timers; |
|
|
|
unsigned int getPcmNodes(void) |
|
{ |
|
DIR *d; |
|
struct dirent *de; |
|
unsigned int pcount = 0; |
|
|
|
d = opendir(kSoundDir); |
|
if (d == 0) |
|
return 0; |
|
while ((de = readdir(d)) != NULL) { |
|
if (de->d_name[0] == '.') |
|
continue; |
|
if (strstr(de->d_name, PCM_PREFIX)) |
|
pcount++; |
|
} |
|
closedir(d); |
|
return pcount; |
|
} |
|
|
|
int getSndDev(unsigned int pcmdevs) |
|
{ |
|
DIR *d; |
|
struct dirent *de; |
|
unsigned int prevcard = -1; |
|
|
|
d = opendir(kSoundDir); |
|
if (d == 0) |
|
return -ENXIO; |
|
pcmnodes = (pcm_node_t *)malloc(pcmdevs * sizeof(pcm_node_t)); |
|
if (!pcmnodes) |
|
return -ENOMEM; |
|
pcms = 0; |
|
while ((de = readdir(d)) != NULL) { |
|
if (de->d_name[0] == '.') |
|
continue; |
|
/* printf("%s\n", de->d_name); */ |
|
if (strstr(de->d_name, PCM_PREFIX)) { |
|
char flags; |
|
|
|
EXPECT_LE(pcms, pcmdevs) << "Too many PCMs"; |
|
if (pcms >= pcmdevs) |
|
continue; |
|
sscanf(de->d_name, PCM_PREFIX "C%uD%u", &(pcmnodes[pcms].card), |
|
&(pcmnodes[pcms].device)); |
|
flags = de->d_name[strlen(de->d_name)-1]; |
|
if (flags == 'c') { |
|
pcmnodes[pcms].flags = PCM_IN; |
|
} else if(flags == 'p') { |
|
pcmnodes[pcms].flags = PCM_OUT; |
|
} else { |
|
pcmnodes[pcms].flags = -1; |
|
testPrintI("Unknown PCM type = %c", flags); |
|
} |
|
if (prevcard != pcmnodes[pcms].card) |
|
cards++; |
|
prevcard = pcmnodes[pcms].card; |
|
pcms++; |
|
continue; |
|
} |
|
if (strstr(de->d_name, MIXER_PREFIX)) { |
|
unsigned int mixer = -1; |
|
sscanf(de->d_name, MIXER_PREFIX "C%u", &mixer); |
|
mixers++; |
|
continue; |
|
} |
|
if (strstr(de->d_name, TIMER_PREFIX)) { |
|
timers++; |
|
continue; |
|
} |
|
} |
|
closedir(d); |
|
return 0; |
|
} |
|
|
|
int getPcmParams(unsigned int i) |
|
{ |
|
struct pcm_params *params; |
|
unsigned int min; |
|
unsigned int max; |
|
|
|
params = pcm_params_get(pcmnodes[i].card, pcmnodes[i].device, |
|
pcmnodes[i].flags); |
|
if (params == NULL) |
|
return -ENODEV; |
|
|
|
min = pcm_params_get_min(params, PCM_PARAM_RATE); |
|
max = pcm_params_get_max(params, PCM_PARAM_RATE); |
|
EXPECT_LE(min, max); |
|
/* printf(" Rate:\tmin=%uHz\tmax=%uHz\n", min, max); */ |
|
min = pcm_params_get_min(params, PCM_PARAM_CHANNELS); |
|
max = pcm_params_get_max(params, PCM_PARAM_CHANNELS); |
|
EXPECT_LE(min, max); |
|
/* printf(" Channels:\tmin=%u\t\tmax=%u\n", min, max); */ |
|
min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS); |
|
max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS); |
|
EXPECT_LE(min, max); |
|
/* printf(" Sample bits:\tmin=%u\t\tmax=%u\n", min, max); */ |
|
min = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE); |
|
max = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE); |
|
EXPECT_LE(min, max); |
|
/* printf(" Period size:\tmin=%u\t\tmax=%u\n", min, max); */ |
|
min = pcm_params_get_min(params, PCM_PARAM_PERIODS); |
|
max = pcm_params_get_max(params, PCM_PARAM_PERIODS); |
|
EXPECT_LE(min, max); |
|
/* printf("Period count:\tmin=%u\t\tmax=%u\n", min, max); */ |
|
|
|
pcm_params_free(params); |
|
return 0; |
|
} |
|
|
|
TEST(pcmtest, CheckAudioDir) { |
|
pcms = getPcmNodes(); |
|
ASSERT_GT(pcms, 0U); |
|
} |
|
|
|
TEST(pcmtest, GetSoundDevs) { |
|
int err = getSndDev(pcms); |
|
testPrintI(" DEVICES = PCMS:%u CARDS:%u MIXERS:%u TIMERS:%u", |
|
pcms, cards, mixers, timers); |
|
ASSERT_EQ(0, err); |
|
} |
|
|
|
TEST(pcmtest, CheckPcmSanity0) { |
|
ASSERT_NE(0U, pcms); |
|
} |
|
|
|
TEST(pcmtest, CheckPcmSanity1) { |
|
EXPECT_NE(1U, pcms % 2); |
|
} |
|
|
|
TEST(pcmtests, CheckMixerSanity) { |
|
ASSERT_NE(0U, mixers); |
|
ASSERT_EQ(mixers, cards); |
|
} |
|
|
|
TEST(pcmtest, CheckTimesSanity0) { |
|
ASSERT_NE(0U, timers); |
|
} |
|
|
|
TEST(pcmtest, CheckTimesSanity1) { |
|
EXPECT_EQ(1U, timers); |
|
} |
|
|
|
TEST(pcmtest, CheckPcmDevices) { |
|
for (unsigned int i = 0; i < pcms; i++) { |
|
EXPECT_EQ(0, getPcmParams(i)); |
|
} |
|
free(pcmnodes); |
|
} |
|
|
|
TEST(pcmtest, CheckMixerDevices) { |
|
struct mixer *mixer; |
|
for (unsigned int i = 0; i < mixers; i++) { |
|
mixer = mixer_open(i); |
|
EXPECT_TRUE(mixer != NULL); |
|
if (mixer) |
|
mixer_close(mixer); |
|
} |
|
} |
|
|
|
TEST(pcmtest, CheckTimer) { |
|
int ver = 0; |
|
int fd = open("/dev/snd/timer", O_RDWR | O_NONBLOCK); |
|
ASSERT_GE(fd, 0); |
|
int ret = ioctl(fd, SNDRV_TIMER_IOCTL_PVERSION, &ver); |
|
EXPECT_EQ(0, ret); |
|
testPrintI(" Timer Version = 0x%x", ver); |
|
close(fd); |
|
}
|
|
|