mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-12-23 00:36:31 +01:00
speaker-test: Add support for channel mapping API
The surround channel map follows the given channel map from the driver if available. Also, the channels can be specified manually via -m option. Pass the channel map like "FL,FR,FC,LFE". Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
b9deb6d9f3
commit
951cb2c297
1 changed files with 124 additions and 15 deletions
|
@ -60,6 +60,10 @@
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SND_CHMAP_API_VERSION
|
||||||
|
#define CONFIG_SUPPORT_CHMAP 1
|
||||||
|
#endif
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
TEST_PINK_NOISE = 1,
|
TEST_PINK_NOISE = 1,
|
||||||
TEST_SINE,
|
TEST_SINE,
|
||||||
|
@ -100,6 +104,11 @@ static const char *given_test_wav_file = NULL;
|
||||||
static char *wav_file_dir = SOUNDSDIR;
|
static char *wav_file_dir = SOUNDSDIR;
|
||||||
static int debug = 0;
|
static int debug = 0;
|
||||||
|
|
||||||
|
#ifdef CONFIG_SUPPORT_CHMAP
|
||||||
|
static snd_pcm_chmap_t *channel_map;
|
||||||
|
static int channel_map_set;
|
||||||
|
#endif
|
||||||
|
|
||||||
static const char *const channel_name[MAX_CHANNELS] = {
|
static const char *const channel_name[MAX_CHANNELS] = {
|
||||||
/* 0 */ N_("Front Left"),
|
/* 0 */ N_("Front Left"),
|
||||||
/* 1 */ N_("Front Right"),
|
/* 1 */ N_("Front Right"),
|
||||||
|
@ -143,6 +152,65 @@ static const int channels8[] = {
|
||||||
6, /* Side Left */
|
6, /* Side Left */
|
||||||
5, /* LFE */
|
5, /* LFE */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int get_mapped_channel(int chn)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_SUPPORT_CHMAP
|
||||||
|
static const int maps[MAX_CHANNELS] = {
|
||||||
|
SND_CHMAP_FL,
|
||||||
|
SND_CHMAP_FR,
|
||||||
|
SND_CHMAP_RL,
|
||||||
|
SND_CHMAP_RR,
|
||||||
|
SND_CHMAP_FC,
|
||||||
|
SND_CHMAP_LFE,
|
||||||
|
SND_CHMAP_SL,
|
||||||
|
SND_CHMAP_SR,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (channel_map && maps[chn]) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < channel_map->channels; i++) {
|
||||||
|
if (channel_map->pos[i] == maps[chn])
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return chn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_speaker_channel(int chn)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_SUPPORT_CHMAP
|
||||||
|
if (channel_map_set)
|
||||||
|
return chn;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (channels) {
|
||||||
|
case 4:
|
||||||
|
chn = channels4[chn];
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
chn = channels6[chn];
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
chn = channels8[chn];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return get_mapped_channel(chn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *get_channel_name(int chn)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_SUPPORT_CHMAP
|
||||||
|
if (channel_map_set && chn < channel_map->channels) {
|
||||||
|
const char *name = snd_pcm_chmap_long_name(channel_map->pos[chn]);
|
||||||
|
return name ? name : "Unknown";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return gettext(channel_name[chn]);
|
||||||
|
}
|
||||||
|
|
||||||
static const int supported_formats[] = {
|
static const int supported_formats[] = {
|
||||||
SND_PCM_FORMAT_S8,
|
SND_PCM_FORMAT_S8,
|
||||||
SND_PCM_FORMAT_S16_LE,
|
SND_PCM_FORMAT_S16_LE,
|
||||||
|
@ -519,6 +587,31 @@ static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SUPPORT_CHMAP
|
||||||
|
static int config_chmap(snd_pcm_t *handle, const char *mapstr)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (mapstr) {
|
||||||
|
channel_map = snd_pcm_chmap_parse_string(mapstr);
|
||||||
|
if (!channel_map) {
|
||||||
|
fprintf(stderr, _("Unable to parse channel map string: %s\n"), mapstr);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
err = snd_pcm_set_chmap(handle, channel_map);
|
||||||
|
if (err < 0) {
|
||||||
|
fprintf(stderr, _("Unable to set channel map: %s\n"), mapstr);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
channel_map_set = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
channel_map = snd_pcm_get_chmap(handle);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Underrun and suspend recovery
|
* Underrun and suspend recovery
|
||||||
*/
|
*/
|
||||||
|
@ -815,6 +908,7 @@ static void help(void)
|
||||||
"-s,--speaker single speaker test. Values 1=Left, 2=right, etc\n"
|
"-s,--speaker single speaker test. Values 1=Left, 2=right, etc\n"
|
||||||
"-w,--wavfile Use the given WAV file as a test sound\n"
|
"-w,--wavfile Use the given WAV file as a test sound\n"
|
||||||
"-W,--wavdir Specify the directory containing WAV files\n"
|
"-W,--wavdir Specify the directory containing WAV files\n"
|
||||||
|
"-m,--chmap Specify the channel map to override\n"
|
||||||
"\n"));
|
"\n"));
|
||||||
printf(_("Recognized sample formats are:"));
|
printf(_("Recognized sample formats are:"));
|
||||||
for (fmt = supported_formats; *fmt >= 0; fmt++) {
|
for (fmt = supported_formats; *fmt >= 0; fmt++) {
|
||||||
|
@ -837,6 +931,9 @@ int main(int argc, char *argv[]) {
|
||||||
double time1,time2,time3;
|
double time1,time2,time3;
|
||||||
unsigned int n, nloops;
|
unsigned int n, nloops;
|
||||||
struct timeval tv1,tv2;
|
struct timeval tv1,tv2;
|
||||||
|
#ifdef CONFIG_SUPPORT_CHMAP
|
||||||
|
const char *chmap = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
static const struct option long_option[] = {
|
static const struct option long_option[] = {
|
||||||
{"help", 0, NULL, 'h'},
|
{"help", 0, NULL, 'h'},
|
||||||
|
@ -854,6 +951,9 @@ int main(int argc, char *argv[]) {
|
||||||
{"wavfile", 1, NULL, 'w'},
|
{"wavfile", 1, NULL, 'w'},
|
||||||
{"wavdir", 1, NULL, 'W'},
|
{"wavdir", 1, NULL, 'W'},
|
||||||
{"debug", 0, NULL, 'd'},
|
{"debug", 0, NULL, 'd'},
|
||||||
|
#ifdef CONFIG_SUPPORT_CHMAP
|
||||||
|
{"chmap", 1, NULL, 'm'},
|
||||||
|
#endif
|
||||||
{NULL, 0, NULL, 0 },
|
{NULL, 0, NULL, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -872,7 +972,11 @@ int main(int argc, char *argv[]) {
|
||||||
while (1) {
|
while (1) {
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
if ((c = getopt_long(argc, argv, "hD:r:c:f:F:b:p:P:t:l:s:w:W:d", long_option, NULL)) < 0)
|
if ((c = getopt_long(argc, argv, "hD:r:c:f:F:b:p:P:t:l:s:w:W:d"
|
||||||
|
#ifdef CONFIG_SUPPORT_CHMAP
|
||||||
|
"m:"
|
||||||
|
#endif
|
||||||
|
, long_option, NULL)) < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
@ -963,6 +1067,11 @@ int main(int argc, char *argv[]) {
|
||||||
case 'd':
|
case 'd':
|
||||||
debug = 1;
|
debug = 1;
|
||||||
break;
|
break;
|
||||||
|
#ifdef CONFIG_SUPPORT_CHMAP
|
||||||
|
case 'm':
|
||||||
|
chmap = optarg;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, _("Unknown option '%c'\n"), c);
|
fprintf(stderr, _("Unknown option '%c'\n"), c);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
@ -1008,6 +1117,13 @@ int main(int argc, char *argv[]) {
|
||||||
snd_pcm_close(handle);
|
snd_pcm_close(handle);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SUPPORT_CHMAP
|
||||||
|
err = config_chmap(handle, chmap);
|
||||||
|
if (err < 0)
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
snd_output_t *log;
|
snd_output_t *log;
|
||||||
err = snd_output_stdio_attach(&log, stderr, 0);
|
err = snd_output_stdio_attach(&log, stderr, 0);
|
||||||
|
@ -1038,17 +1154,8 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
gettimeofday(&tv1, NULL);
|
gettimeofday(&tv1, NULL);
|
||||||
for(chn = 0; chn < channels; chn++) {
|
for(chn = 0; chn < channels; chn++) {
|
||||||
int channel=chn;
|
int channel = get_speaker_channel(chn);
|
||||||
if (channels == 4) {
|
printf(" %d - %s\n", channel, get_channel_name(channel));
|
||||||
channel=channels4[chn];
|
|
||||||
}
|
|
||||||
if (channels == 6) {
|
|
||||||
channel=channels6[chn];
|
|
||||||
}
|
|
||||||
if (channels == 8) {
|
|
||||||
channel=channels8[chn];
|
|
||||||
}
|
|
||||||
printf(" %d - %s\n", channel, gettext(channel_name[channel]));
|
|
||||||
|
|
||||||
err = write_loop(handle, channel, ((rate*3)/period_size), frames);
|
err = write_loop(handle, channel, ((rate*3)/period_size), frames);
|
||||||
|
|
||||||
|
@ -1066,13 +1173,15 @@ int main(int argc, char *argv[]) {
|
||||||
printf(_("Time per period = %lf\n"), time3 );
|
printf(_("Time per period = %lf\n"), time3 );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
chn = get_speaker_channel(speaker - 1);
|
||||||
|
|
||||||
if (test_type == TEST_WAV) {
|
if (test_type == TEST_WAV) {
|
||||||
if (setup_wav_file(speaker - 1) < 0)
|
if (setup_wav_file(chn) < 0)
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(" - %s\n", gettext(channel_name[speaker-1]));
|
printf(" - %s\n", get_channel_name(chn));
|
||||||
err = write_loop(handle, speaker-1, ((rate*5)/period_size), frames);
|
err = write_loop(handle, chn, ((rate*5)/period_size), frames);
|
||||||
|
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
fprintf(stderr, _("Transfer failed: %s\n"), snd_strerror(err));
|
fprintf(stderr, _("Transfer failed: %s\n"), snd_strerror(err));
|
||||||
|
|
Loading…
Reference in a new issue