mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2026-02-05 04:06:34 -05:00
Add tests for various features of the PCM interface. The goal is to maximize coverage of the corresponding kernel code. The tests use a loopback device and require snd-aloop kernel module to be loaded.
454 lines
11 KiB
C
454 lines
11 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <limits.h>
|
|
#include "test.h"
|
|
|
|
#define CARD_NAME "Loopback"
|
|
#define PERIOD_SIZE (16 * 1024)
|
|
#define CHANNELS 2
|
|
#define RATE 48000
|
|
#define FORMAT SND_PCM_FORMAT_S16_LE
|
|
|
|
int card_index;
|
|
static snd_pcm_t *opcm, *ipcm;
|
|
static char opcmdev[10], ipcmdev[10];
|
|
|
|
static int find_card(int *card_index) {
|
|
int index = -1;
|
|
ALSA_CALL(snd_card_next(&index));
|
|
while (index >= 0) {
|
|
char *name;
|
|
ALSA_CALL(snd_card_get_name(index, &name) < 0);
|
|
if (strcmp(name, CARD_NAME) == 0) {
|
|
free(name);
|
|
*card_index = index;
|
|
snprintf(opcmdev, sizeof(opcmdev), "hw:%i,0", index);
|
|
snprintf(ipcmdev, sizeof(ipcmdev), "hw:%i,1", index);
|
|
return 0;
|
|
}
|
|
free(name);
|
|
ALSA_CALL(snd_card_next(&index) < 0);
|
|
}
|
|
|
|
TEST_CHECK_MSG(0, CARD_NAME" card not found");
|
|
return 1;
|
|
}
|
|
|
|
static int setup_params(snd_pcm_t *pcm, int *bufsize) {
|
|
snd_pcm_hw_params_t *hw;
|
|
|
|
*bufsize = snd_pcm_format_size(FORMAT, PERIOD_SIZE) * CHANNELS;
|
|
|
|
snd_pcm_hw_params_alloca(&hw);
|
|
ALSA_CALL(snd_pcm_hw_params_any(pcm, hw));
|
|
ALSA_CALL(snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED));
|
|
ALSA_CALL(snd_pcm_hw_params_set_format(pcm, hw, FORMAT));
|
|
ALSA_CALL(snd_pcm_hw_params_set_channels(pcm, hw, CHANNELS));
|
|
ALSA_CALL(snd_pcm_hw_params_set_rate(pcm, hw, RATE, 0));
|
|
ALSA_CALL(snd_pcm_hw_params_set_period_size(pcm, hw, PERIOD_SIZE, 0));
|
|
ALSA_CALL(snd_pcm_hw_params_set_buffer_size(pcm, hw, *bufsize));
|
|
ALSA_CALL(snd_pcm_hw_params(pcm, hw));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_pass_bad_pointer_to_hw_params(void) {
|
|
ALSA_CALL(snd_pcm_open(&opcm, opcmdev, SND_PCM_STREAM_PLAYBACK, 0));
|
|
ALSA_CALL_FAIL(snd_pcm_hw_params(opcm, (snd_pcm_hw_params_t *) 1));
|
|
ALSA_CALL(snd_pcm_close(opcm));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_set_hw_param_access_to_invalid_value(void) {
|
|
snd_pcm_hw_params_t *hw;
|
|
|
|
ALSA_CALL(snd_pcm_open(&opcm, opcmdev, SND_PCM_STREAM_PLAYBACK, 0));
|
|
snd_pcm_hw_params_alloca(&hw);
|
|
ALSA_CALL_FAIL(snd_pcm_hw_params_set_access(opcm, hw, SND_PCM_ACCESS_LAST + 1));
|
|
ALSA_CALL_FAIL(snd_pcm_hw_params(opcm, hw));
|
|
ALSA_CALL(snd_pcm_close(opcm));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_set_hw_param_format_to_invalid_value(void) {
|
|
snd_pcm_hw_params_t *hw;
|
|
|
|
ALSA_CALL(snd_pcm_open(&opcm, opcmdev, SND_PCM_STREAM_PLAYBACK, 0));
|
|
snd_pcm_hw_params_alloca(&hw);
|
|
ALSA_CALL_FAIL(snd_pcm_hw_params_set_format(opcm, hw, SND_PCM_FORMAT_LAST + 1));
|
|
ALSA_CALL_FAIL(snd_pcm_hw_params(opcm, hw));
|
|
ALSA_CALL(snd_pcm_close(opcm));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_set_hw_params_correctly(void) {
|
|
int bufsize;
|
|
|
|
ALSA_CALL(snd_pcm_open(&opcm, opcmdev, SND_PCM_STREAM_PLAYBACK, 0));
|
|
SUB_CALL(setup_params(opcm, &bufsize));
|
|
ALSA_CALL(snd_pcm_close(opcm));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_free_device_when_it_is_used(void) {
|
|
char *obuf;
|
|
int bufsize;
|
|
|
|
ALSA_CALL(snd_pcm_open(&opcm, opcmdev, SND_PCM_STREAM_PLAYBACK, 0));
|
|
SUB_CALL(setup_params(opcm, &bufsize));
|
|
|
|
obuf = malloc(bufsize);
|
|
ALSA_CALL(snd_pcm_writei(opcm, obuf, PERIOD_SIZE));
|
|
free(obuf);
|
|
|
|
ALSA_CALL_FAIL(snd_pcm_hw_free(opcm));
|
|
|
|
ALSA_CALL(snd_pcm_close(opcm));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_play_sound_and_capture_it(void) {
|
|
char *obuf, *ibuf, val;
|
|
int i, n, bufsize;
|
|
|
|
ALSA_CALL(snd_pcm_open(&opcm, opcmdev, SND_PCM_STREAM_PLAYBACK, 0));
|
|
SUB_CALL(setup_params(opcm, &bufsize));
|
|
|
|
ALSA_CALL(snd_pcm_open(&ipcm, ipcmdev, SND_PCM_STREAM_CAPTURE, 0));
|
|
SUB_CALL(setup_params(ipcm, &bufsize));
|
|
|
|
obuf = malloc(bufsize);
|
|
ibuf = malloc(bufsize);
|
|
|
|
val = rand() % 0x100 - 0x80;
|
|
memset(obuf, val, bufsize);
|
|
for (n = 0; n < 10; n++) {
|
|
ALSA_CALL(snd_pcm_writei(opcm, obuf, PERIOD_SIZE));
|
|
}
|
|
ALSA_CALL(snd_pcm_readi(ipcm, ibuf, PERIOD_SIZE));
|
|
for (i = 0; i < bufsize; i++) {
|
|
TEST_CHECK(ibuf[i] == val);
|
|
if (TEST_FAILED()) {
|
|
break;
|
|
}
|
|
}
|
|
ALSA_CALL(snd_pcm_drain(ipcm));
|
|
ALSA_CALL_FAIL(snd_pcm_readi(ipcm, ibuf, PERIOD_SIZE));
|
|
|
|
free(ibuf);
|
|
free(obuf);
|
|
|
|
ALSA_CALL(snd_pcm_close(ipcm));
|
|
ALSA_CALL(snd_pcm_close(opcm));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_play_drain(void) {
|
|
char *obuf, val;
|
|
int bufsize;
|
|
|
|
ALSA_CALL(snd_pcm_open(&opcm, opcmdev, SND_PCM_STREAM_PLAYBACK, 0));
|
|
SUB_CALL(setup_params(opcm, &bufsize));
|
|
|
|
obuf = malloc(bufsize);
|
|
val = rand() % 0x100 - 0x80;
|
|
memset(obuf, val, bufsize);
|
|
|
|
ALSA_CALL(snd_pcm_writei(opcm, obuf, PERIOD_SIZE));
|
|
ALSA_CALL(snd_pcm_drain(opcm));
|
|
ALSA_CALL_FAIL(snd_pcm_writei(opcm, obuf, PERIOD_SIZE));
|
|
|
|
free(obuf);
|
|
|
|
ALSA_CALL(snd_pcm_close(opcm));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_status(void) {
|
|
char *obuf, val;
|
|
int bufsize;
|
|
snd_pcm_status_t *status;
|
|
snd_pcm_sframes_t delay1, delay2;
|
|
|
|
ALSA_CALL(snd_pcm_open(&opcm, opcmdev, SND_PCM_STREAM_PLAYBACK, 0));
|
|
SUB_CALL(setup_params(opcm, &bufsize));
|
|
|
|
obuf = malloc(bufsize);
|
|
val = rand() % 0x100 - 0x80;
|
|
memset(obuf, val, bufsize);
|
|
ALSA_CALL(snd_pcm_writei(opcm, obuf, PERIOD_SIZE));
|
|
|
|
snd_pcm_status_alloca(&status);
|
|
ALSA_CALL(snd_pcm_status(opcm, status));
|
|
delay1 = snd_pcm_status_get_delay(status);
|
|
ALSA_CALL(snd_pcm_delay(opcm, &delay2));
|
|
TEST_CHECK_MSG(delay1 >= delay2 && (delay1 - delay2) < 100, "Delay values are wrong");
|
|
|
|
ALSA_CALL(snd_pcm_drain(opcm));
|
|
|
|
free(obuf);
|
|
|
|
ALSA_CALL(snd_pcm_close(opcm));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_reset(void) {
|
|
char *obuf, val;
|
|
int bufsize;
|
|
snd_pcm_sframes_t delay;
|
|
|
|
ALSA_CALL(snd_pcm_open(&opcm, opcmdev, SND_PCM_STREAM_PLAYBACK, 0));
|
|
SUB_CALL(setup_params(opcm, &bufsize));
|
|
|
|
obuf = malloc(bufsize);
|
|
val = rand() % 0x100 - 0x80;
|
|
memset(obuf, val, bufsize);
|
|
ALSA_CALL(snd_pcm_writei(opcm, obuf, PERIOD_SIZE));
|
|
|
|
ALSA_CALL(snd_pcm_delay(opcm, &delay));
|
|
TEST_CHECK(delay > 0);
|
|
ALSA_CALL(snd_pcm_reset(opcm));
|
|
ALSA_CALL(snd_pcm_delay(opcm, &delay));
|
|
TEST_CHECK(delay == 0);
|
|
|
|
free(obuf);
|
|
|
|
ALSA_CALL(snd_pcm_close(opcm));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_start(void) {
|
|
snd_pcm_sw_params_t *sw;
|
|
char *obuf, *ibuf, val;
|
|
int i, bufsize;
|
|
|
|
ALSA_CALL(snd_pcm_open(&opcm, opcmdev, SND_PCM_STREAM_PLAYBACK, 0));
|
|
SUB_CALL(setup_params(opcm, &bufsize));
|
|
|
|
ALSA_CALL(snd_pcm_open(&ipcm, ipcmdev, SND_PCM_STREAM_CAPTURE, 0));
|
|
SUB_CALL(setup_params(ipcm, &bufsize));
|
|
|
|
snd_pcm_sw_params_alloca(&sw);
|
|
ALSA_CALL(snd_pcm_sw_params_current(opcm, sw));
|
|
ALSA_CALL(snd_pcm_sw_params_set_start_threshold(opcm, sw, PERIOD_SIZE + 1));
|
|
ALSA_CALL(snd_pcm_sw_params(opcm, sw));
|
|
|
|
obuf = malloc(bufsize);
|
|
ibuf = malloc(bufsize);
|
|
|
|
val = rand() % 0x100 - 0x80;
|
|
memset(obuf, val, bufsize);
|
|
ALSA_CALL(snd_pcm_writei(opcm, obuf, PERIOD_SIZE));
|
|
|
|
ALSA_CALL(snd_pcm_readi(ipcm, ibuf, PERIOD_SIZE));
|
|
for (i = 0; i < bufsize; i++) {
|
|
TEST_CHECK(ibuf[i] == 0);
|
|
if (TEST_FAILED()) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
ALSA_CALL(snd_pcm_start(opcm));
|
|
|
|
ALSA_CALL(snd_pcm_readi(ipcm, ibuf, PERIOD_SIZE));
|
|
for (i = bufsize - 16; i < bufsize; i++) {
|
|
TEST_CHECK(ibuf[i] == val);
|
|
if (TEST_FAILED()) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
free(obuf);
|
|
|
|
ALSA_CALL(snd_pcm_close(ipcm));
|
|
ALSA_CALL(snd_pcm_close(opcm));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_pause(void) {
|
|
char *obuf, *ibuf, val;
|
|
int i, n, bufsize, vals;
|
|
|
|
ALSA_CALL(snd_pcm_open(&opcm, opcmdev, SND_PCM_STREAM_PLAYBACK, 0));
|
|
SUB_CALL(setup_params(opcm, &bufsize));
|
|
|
|
ALSA_CALL(snd_pcm_open(&ipcm, ipcmdev, SND_PCM_STREAM_CAPTURE, 0));
|
|
SUB_CALL(setup_params(ipcm, &bufsize));
|
|
|
|
obuf = malloc(bufsize);
|
|
ibuf = malloc(bufsize);
|
|
|
|
val = rand() % 0x100 - 0x80;
|
|
memset(obuf, val, bufsize);
|
|
ALSA_CALL(snd_pcm_writei(opcm, obuf, PERIOD_SIZE));
|
|
ALSA_CALL(snd_pcm_pause(opcm, 1));
|
|
|
|
ALSA_CALL(snd_pcm_readi(ipcm, ibuf, PERIOD_SIZE));
|
|
for (i = bufsize - 16; i < bufsize; i++) {
|
|
TEST_CHECK(ibuf[i] == 0);
|
|
if (TEST_FAILED()) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
ALSA_CALL(snd_pcm_pause(opcm, 0));
|
|
sleep(1);
|
|
|
|
vals = 0;
|
|
for (n = 0; n < 3; n++) {
|
|
ALSA_CALL(snd_pcm_readi(ipcm, ibuf, PERIOD_SIZE));
|
|
for (i = 0; i < bufsize; i++) {
|
|
if (ibuf[i] == val) {
|
|
vals++;
|
|
}
|
|
}
|
|
}
|
|
TEST_CHECK(vals > 256);
|
|
|
|
free(obuf);
|
|
|
|
ALSA_CALL(snd_pcm_close(ipcm));
|
|
ALSA_CALL(snd_pcm_close(opcm));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_rewind(void) {
|
|
char *obuf, *ibuf;
|
|
int i, bufsize, shift;
|
|
|
|
ALSA_CALL(snd_pcm_open(&opcm, opcmdev, SND_PCM_STREAM_PLAYBACK, 0));
|
|
SUB_CALL(setup_params(opcm, &bufsize));
|
|
|
|
ALSA_CALL(snd_pcm_open(&ipcm, ipcmdev, SND_PCM_STREAM_CAPTURE, 0));
|
|
SUB_CALL(setup_params(ipcm, &bufsize));
|
|
|
|
obuf = malloc(bufsize);
|
|
ibuf = malloc(bufsize);
|
|
|
|
for (i = 0; i < bufsize; i++) {
|
|
obuf[i] = i % 128;
|
|
}
|
|
ALSA_CALL(snd_pcm_writei(opcm, obuf, PERIOD_SIZE));
|
|
|
|
ALSA_CALL(snd_pcm_readi(ipcm, ibuf, PERIOD_SIZE / 2));
|
|
ALSA_CALL(snd_pcm_rewind(ipcm, 16));
|
|
ALSA_CALL(snd_pcm_readi(ipcm, ibuf + (bufsize / 2), PERIOD_SIZE / 2));
|
|
shift = snd_pcm_format_size(FORMAT, 1) * CHANNELS * 16;
|
|
TEST_CHECK(ibuf[bufsize / 2 - 1] - ibuf[bufsize / 2] == shift - 1);
|
|
|
|
free(obuf);
|
|
|
|
ALSA_CALL(snd_pcm_close(ipcm));
|
|
ALSA_CALL(snd_pcm_close(opcm));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_forward(void) {
|
|
char *obuf, *ibuf;
|
|
int i, bufsize, shift;
|
|
|
|
ALSA_CALL(snd_pcm_open(&opcm, opcmdev, SND_PCM_STREAM_PLAYBACK, 0));
|
|
SUB_CALL(setup_params(opcm, &bufsize));
|
|
|
|
ALSA_CALL(snd_pcm_open(&ipcm, ipcmdev, SND_PCM_STREAM_CAPTURE, 0));
|
|
SUB_CALL(setup_params(ipcm, &bufsize));
|
|
|
|
obuf = malloc(bufsize);
|
|
ibuf = malloc(bufsize);
|
|
|
|
for (i = 0; i < bufsize; i++) {
|
|
obuf[i] = i % 128;
|
|
}
|
|
ALSA_CALL(snd_pcm_writei(opcm, obuf, PERIOD_SIZE));
|
|
|
|
ALSA_CALL(snd_pcm_readi(ipcm, ibuf, PERIOD_SIZE / 2));
|
|
ALSA_CALL(snd_pcm_forward(ipcm, 1));
|
|
ALSA_CALL(snd_pcm_readi(ipcm, ibuf + (bufsize / 2), PERIOD_SIZE / 2));
|
|
shift = snd_pcm_format_size(FORMAT, 1) * CHANNELS;
|
|
TEST_CHECK(ibuf[bufsize / 2] == shift);
|
|
for (i = bufsize - shift; i < bufsize; i++) {
|
|
TEST_CHECK(ibuf[i] == 0);
|
|
}
|
|
|
|
free(obuf);
|
|
|
|
ALSA_CALL(snd_pcm_close(ipcm));
|
|
ALSA_CALL(snd_pcm_close(opcm));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_link(void) {
|
|
char *obuf, val;
|
|
int bufsize;
|
|
snd_pcm_status_t *status;
|
|
|
|
ALSA_CALL(snd_pcm_open(&opcm, opcmdev, SND_PCM_STREAM_PLAYBACK, 0));
|
|
SUB_CALL(setup_params(opcm, &bufsize));
|
|
|
|
ALSA_CALL(snd_pcm_open(&ipcm, ipcmdev, SND_PCM_STREAM_CAPTURE, 0));
|
|
SUB_CALL(setup_params(ipcm, &bufsize));
|
|
|
|
ALSA_CALL(snd_pcm_link(ipcm, opcm));
|
|
|
|
obuf = malloc(bufsize);
|
|
|
|
val = rand() % 0x100 - 0x80;
|
|
memset(obuf, val, bufsize);
|
|
ALSA_CALL(snd_pcm_writei(opcm, obuf, PERIOD_SIZE));
|
|
|
|
snd_pcm_status_alloca(&status);
|
|
|
|
ALSA_CALL(snd_pcm_pause(opcm, 1));
|
|
ALSA_CALL(snd_pcm_status(ipcm, status));
|
|
TEST_CHECK(snd_pcm_status_get_state(status) == SND_PCM_STATE_PAUSED);
|
|
|
|
ALSA_CALL(snd_pcm_pause(opcm, 0));
|
|
ALSA_CALL(snd_pcm_status(ipcm, status));
|
|
TEST_CHECK(snd_pcm_status_get_state(status) == SND_PCM_STATE_RUNNING);
|
|
|
|
ALSA_CALL(snd_pcm_unlink(ipcm));
|
|
|
|
ALSA_CALL(snd_pcm_pause(opcm, 1));
|
|
ALSA_CALL(snd_pcm_status(ipcm, status));
|
|
TEST_CHECK(snd_pcm_status_get_state(status) == SND_PCM_STATE_RUNNING);
|
|
|
|
free(obuf);
|
|
|
|
ALSA_CALL(snd_pcm_close(ipcm));
|
|
ALSA_CALL(snd_pcm_close(opcm));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(void) {
|
|
srand(time(0));
|
|
TEST_CALL(find_card(&card_index));
|
|
TEST_CALL(test_pass_bad_pointer_to_hw_params());
|
|
TEST_CALL(test_set_hw_param_access_to_invalid_value());
|
|
TEST_CALL(test_set_hw_param_format_to_invalid_value());
|
|
TEST_CALL(test_set_hw_params_correctly());
|
|
TEST_CALL(test_free_device_when_it_is_used());
|
|
TEST_CALL(test_play_sound_and_capture_it());
|
|
TEST_CALL(test_play_drain());
|
|
TEST_CALL(test_status());
|
|
TEST_CALL(test_reset());
|
|
TEST_CALL(test_start());
|
|
TEST_CALL(test_pause());
|
|
TEST_CALL(test_rewind());
|
|
TEST_CALL(test_forward());
|
|
TEST_CALL(test_link());
|
|
return 0;
|
|
}
|