add support for testing audio devices. the usage of audiocfg changes:
audiocfg list audiocfg default [index] audiocfg test [index] 'list' shows the available audio devices, 'default' sets the default audio device, and 'test' will play a tone for 2 seconds on each channel. example: $ ./audiocfg list 0: [*] audio0: ICH2 AC97 (2 playback channels) 1: [ ] audio1: Pseudo Audio (2 playback channels) $ ./audiocfg test 0 testing channel 0... testing channel 1... $
This commit is contained in:
parent
bd524aa578
commit
e405ac8d24
|
@ -1,9 +1,11 @@
|
|||
# $NetBSD: Makefile,v 1.3 2010/09/01 09:04:16 jmcneill Exp $
|
||||
|
||||
PROG= audiocfg
|
||||
SRCS= audiodev.c drvctl.c
|
||||
SRCS= audiodev.c drvctl.c dtmf.c
|
||||
SRCS+= main.c
|
||||
WARNS= 3
|
||||
|
||||
LDADD+= -lprop
|
||||
DPADD+= $(LIBPROP)
|
||||
LDADD+= -lprop -lm
|
||||
DPADD+= $(LIBPROP) $(LIBM)
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: audiodev.c,v 1.1.1.1 2010/08/30 02:19:47 mrg Exp $ */
|
||||
/* $NetBSD: audiodev.c,v 1.2 2010/09/01 09:04:16 jmcneill Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Jared D. McNeill <jmcneill@invisible.ca>
|
||||
|
@ -40,10 +40,42 @@
|
|||
|
||||
#include "audiodev.h"
|
||||
#include "drvctl.h"
|
||||
#include "dtmf.h"
|
||||
|
||||
static TAILQ_HEAD(audiodevhead, audiodev) audiodevlist =
|
||||
TAILQ_HEAD_INITIALIZER(audiodevlist);
|
||||
|
||||
#define AUDIODEV_SAMPLE_RATE 44100
|
||||
|
||||
static unsigned int
|
||||
audiodev_probe_pchans(struct audiodev *adev)
|
||||
{
|
||||
audio_info_t info;
|
||||
unsigned int nchans = 0, n;
|
||||
int error;
|
||||
|
||||
AUDIO_INITINFO(&info);
|
||||
info.play.sample_rate = AUDIODEV_SAMPLE_RATE;
|
||||
info.play.precision = 16;
|
||||
info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
|
||||
info.play.channels = 1;
|
||||
info.mode = AUMODE_PLAY;
|
||||
error = ioctl(adev->fd, AUDIO_SETINFO, &info);
|
||||
if (error == -1)
|
||||
return 0;
|
||||
nchans = 1;
|
||||
|
||||
for (n = 2; n <= 16; n += 2) {
|
||||
info.play.channels = n;
|
||||
error = ioctl(adev->fd, AUDIO_SETINFO, &info);
|
||||
if (error == -1)
|
||||
break;
|
||||
nchans = info.play.channels;
|
||||
}
|
||||
|
||||
return nchans;
|
||||
}
|
||||
|
||||
static int
|
||||
audiodev_getinfo(struct audiodev *adev)
|
||||
{
|
||||
|
@ -64,6 +96,8 @@ audiodev_getinfo(struct audiodev *adev)
|
|||
return -1;
|
||||
}
|
||||
|
||||
adev->pchan = audiodev_probe_pchans(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -107,7 +141,7 @@ audiodev_refresh(void)
|
|||
struct audiodev *adev;
|
||||
int fd, error;
|
||||
|
||||
fd = open(DRVCTLDEV, O_RDWR);
|
||||
fd = open(DRVCTLDEV, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
perror("open " DRVCTLDEV);
|
||||
return -1;
|
||||
|
@ -202,3 +236,49 @@ audiodev_set_default(struct audiodev *adev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
audiodev_test(struct audiodev *adev, unsigned int chanmask)
|
||||
{
|
||||
audio_info_t info;
|
||||
int16_t *buf;
|
||||
size_t buflen;
|
||||
off_t off;
|
||||
|
||||
AUDIO_INITINFO(&info);
|
||||
info.play.sample_rate = AUDIODEV_SAMPLE_RATE;
|
||||
info.play.channels = adev->pchan;
|
||||
info.play.precision = 16;
|
||||
info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
|
||||
info.mode = AUMODE_PLAY;
|
||||
if (ioctl(adev->fd, AUDIO_SETINFO, &info) == -1) {
|
||||
perror("ioctl AUDIO_SETINFO");
|
||||
return -1;
|
||||
}
|
||||
if (ioctl(adev->fd, AUDIO_GETINFO, &info) == -1) {
|
||||
perror("ioctl AUDIO_GETINFO");
|
||||
return -1;
|
||||
}
|
||||
|
||||
dtmf_new(&buf, &buflen, info.play.sample_rate, 2,
|
||||
adev->pchan, chanmask, 350.0, 440.0);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
|
||||
off = 0;
|
||||
while (buflen > 0) {
|
||||
size_t wlen = info.play.buffer_size;
|
||||
if (wlen > buflen)
|
||||
wlen = buflen;
|
||||
write(adev->fd, (char *)buf + off, wlen);
|
||||
off += wlen;
|
||||
buflen -= wlen;
|
||||
}
|
||||
|
||||
if (ioctl(adev->fd, AUDIO_DRAIN) == -1)
|
||||
perror("ioctl AUDIO_DRAIN");
|
||||
|
||||
free(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: audiodev.h,v 1.1.1.1 2010/08/30 02:19:47 mrg Exp $ */
|
||||
/* $NetBSD: audiodev.h,v 1.2 2010/09/01 09:04:16 jmcneill Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Jared D. McNeill <jmcneill@invisible.ca>
|
||||
|
@ -44,6 +44,8 @@ struct audiodev {
|
|||
dev_t dev;
|
||||
bool defaultdev;
|
||||
|
||||
int pchan;
|
||||
|
||||
audio_device_t audio_device;
|
||||
|
||||
TAILQ_ENTRY(audiodev) next;
|
||||
|
@ -53,5 +55,6 @@ int audiodev_refresh(void);
|
|||
unsigned int audiodev_count(void);
|
||||
struct audiodev * audiodev_get(unsigned int);
|
||||
int audiodev_set_default(struct audiodev *);
|
||||
int audiodev_test(struct audiodev *, unsigned int);
|
||||
|
||||
#endif /* !_HAVE_AUDIODEV_H */
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/* $NetBSD: dtmf.c,v 1.1 2010/09/01 09:04:16 jmcneill Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Jared D. McNeill <jmcneill@invisible.ca>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "dtmf.h"
|
||||
|
||||
#define PI2 (3.14159265358979323846f * 2)
|
||||
|
||||
static void
|
||||
dtmf_create(int16_t *buf, unsigned int sample_rate,
|
||||
unsigned short sample_length, unsigned short channels,
|
||||
unsigned int chanmask, float freq1, float freq2)
|
||||
{
|
||||
int c, i;
|
||||
size_t sample_count = sample_rate * sample_length;
|
||||
|
||||
for (i = 0; i < sample_count; i++) {
|
||||
for (c = 0; c < channels; c++) {
|
||||
if ((chanmask & (1 << c)) == 0)
|
||||
continue;
|
||||
buf[c] =
|
||||
(sin(i * PI2 * (freq1 / sample_rate)) +
|
||||
sin(i * PI2 * (freq2 / sample_rate))) * 16383;
|
||||
}
|
||||
buf += channels;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dtmf_new(int16_t **buf, size_t *buflen, unsigned int sample_rate,
|
||||
unsigned short sample_length, unsigned short channels,
|
||||
unsigned int chanmask, float rate1, float rate2)
|
||||
{
|
||||
*buflen = sample_rate * sizeof(int16_t) * sample_length * channels;
|
||||
*buf = calloc(1, *buflen);
|
||||
if (*buf == NULL) {
|
||||
perror("calloc");
|
||||
return;
|
||||
}
|
||||
|
||||
dtmf_create(*buf, sample_rate, sample_length, channels, chanmask,
|
||||
rate1, rate2);
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/* $NetBSD: dtmf.h,v 1.1 2010/09/01 09:04:16 jmcneill Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Jared D. McNeill <jmcneill@invisible.ca>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _HAVE_DTMF_H
|
||||
#define _HAVE_DTMF_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void dtmf_new(int16_t **, size_t *, unsigned int, unsigned short,
|
||||
unsigned short, unsigned int, float, float);
|
||||
|
||||
#endif /* !_HAVE_DTMF_H */
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: main.c,v 1.1.1.1 2010/08/30 02:19:47 mrg Exp $ */
|
||||
/* $NetBSD: main.c,v 1.2 2010/09/01 09:04:16 jmcneill Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Jared D. McNeill <jmcneill@invisible.ca>
|
||||
|
@ -39,7 +39,9 @@
|
|||
static void
|
||||
usage(const char *p)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [index]\n", p);
|
||||
fprintf(stderr, "usage: %s list\n", p);
|
||||
fprintf(stderr, " %s default [index]\n", p);
|
||||
fprintf(stderr, " %s test [index]\n", p);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
@ -52,22 +54,25 @@ main(int argc, char *argv[])
|
|||
if (audiodev_refresh() == -1)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
switch (argc) {
|
||||
case 1:
|
||||
if (argc < 2)
|
||||
usage(argv[0]);
|
||||
/* NOTREACHED */
|
||||
|
||||
if (strcmp(argv[1], "list") == 0) {
|
||||
n = audiodev_count();
|
||||
for (i = 0; i < n; i++) {
|
||||
adev = audiodev_get(i);
|
||||
printf("%u: [%c] %s: %s\n",
|
||||
printf("%u: [%c] %s: %s (%u playback channel%s)\n",
|
||||
i, adev->defaultdev ? '*' : ' ',
|
||||
adev->xname, adev->audio_device.name);
|
||||
adev->xname, adev->audio_device.name,
|
||||
adev->pchan, adev->pchan == 1 ? "" : "s");
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (*argv[1] < '0' || *argv[1] > '9')
|
||||
} else if (strcmp(argv[1], "default") == 0 && argc == 3) {
|
||||
if (*argv[2] < '0' || *argv[2] > '9')
|
||||
usage(argv[0]);
|
||||
/* NOTREACHED */
|
||||
errno = 0;
|
||||
i = strtoul(argv[1], NULL, 10);
|
||||
i = strtoul(argv[2], NULL, 10);
|
||||
if (errno)
|
||||
usage(argv[0]);
|
||||
/* NOTREACHED */
|
||||
|
@ -81,11 +86,27 @@ main(int argc, char *argv[])
|
|||
perror("couldn't set default device");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
} else if (strcmp(argv[1], "test") == 0 && argc == 3) {
|
||||
if (*argv[2] < '0' || *argv[2] > '9')
|
||||
usage(argv[0]);
|
||||
/* NOTREACHED */
|
||||
errno = 0;
|
||||
i = strtoul(argv[2], NULL, 10);
|
||||
if (errno)
|
||||
usage(argv[0]);
|
||||
/* NOTREACHED */
|
||||
adev = audiodev_get(i);
|
||||
if (adev == NULL) {
|
||||
fprintf(stderr, "no such device\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
for (i = 0; i < adev->pchan; i++) {
|
||||
printf("testing channel %d...\n", i);
|
||||
audiodev_test(adev, 1 << i);
|
||||
}
|
||||
} else
|
||||
usage(argv[0]);
|
||||
/* NOTREACHED */
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue