mirror of https://github.com/wb2osz/direwolf.git
add sndio support
This commit is contained in:
parent
04b32c41c2
commit
677117bff0
247
src/audio.c
247
src/audio.c
|
@ -75,18 +75,17 @@
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
|
||||||
#if USE_ALSA
|
#if USE_ALSA
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
#else
|
#elif USE_SNDIO
|
||||||
#include <errno.h>
|
#include <sndio.h>
|
||||||
#ifdef __OpenBSD__
|
#include <poll.h>
|
||||||
#include <soundcard.h>
|
|
||||||
#else
|
#else
|
||||||
#include <sys/soundcard.h>
|
#include <sys/soundcard.h>
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
|
@ -111,6 +110,9 @@ static struct adev_s {
|
||||||
|
|
||||||
int bytes_per_frame; /* number of bytes for a sample from all channels. */
|
int bytes_per_frame; /* number of bytes for a sample from all channels. */
|
||||||
/* e.g. 4 for stereo 16 bit. */
|
/* e.g. 4 for stereo 16 bit. */
|
||||||
|
#elif USE_SNDIO
|
||||||
|
struct sio_hdl *sndio_in_handle;
|
||||||
|
struct sio_hdl *sndio_out_handle;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
int oss_audio_device_fd; /* Single device, both directions. */
|
int oss_audio_device_fd; /* Single device, both directions. */
|
||||||
|
@ -141,6 +143,9 @@ static struct adev_s {
|
||||||
#if USE_ALSA
|
#if USE_ALSA
|
||||||
static int set_alsa_params (int a, snd_pcm_t *handle, struct audio_s *pa, char *name, char *dir);
|
static int set_alsa_params (int a, snd_pcm_t *handle, struct audio_s *pa, char *name, char *dir);
|
||||||
//static void alsa_select_device (char *pick_dev, int direction, char *result);
|
//static void alsa_select_device (char *pick_dev, int direction, char *result);
|
||||||
|
#elif USE_SNDIO
|
||||||
|
static int set_sndio_params (int a, struct sio_hdl *handle, struct audio_s *pa, char *devname, char *inout);
|
||||||
|
static int poll_sndio (struct sio_hdl *hdl, int events);
|
||||||
#else
|
#else
|
||||||
static int set_oss_params (int a, int fd, struct audio_s *pa);
|
static int set_oss_params (int a, int fd, struct audio_s *pa);
|
||||||
#endif
|
#endif
|
||||||
|
@ -212,7 +217,9 @@ static int calcbufsize(int rate, int chans, int bits)
|
||||||
|
|
||||||
int audio_open (struct audio_s *pa)
|
int audio_open (struct audio_s *pa)
|
||||||
{
|
{
|
||||||
|
#if !USE_SNDIO
|
||||||
int err;
|
int err;
|
||||||
|
#endif
|
||||||
int chan;
|
int chan;
|
||||||
int a;
|
int a;
|
||||||
char audio_in_name[30];
|
char audio_in_name[30];
|
||||||
|
@ -224,7 +231,11 @@ int audio_open (struct audio_s *pa)
|
||||||
memset (adev, 0, sizeof(adev));
|
memset (adev, 0, sizeof(adev));
|
||||||
|
|
||||||
for (a=0; a<MAX_ADEVS; a++) {
|
for (a=0; a<MAX_ADEVS; a++) {
|
||||||
#ifndef USE_ALSA
|
#if USE_ALSA
|
||||||
|
adev[a].audio_in_handle = adev[a].audio_out_handle = NULL;
|
||||||
|
#elif USE_SNDIO
|
||||||
|
adev[a].sndio_in_handle = adev[a].sndio_out_handle = NULL;
|
||||||
|
#else
|
||||||
adev[a].oss_audio_device_fd = -1;
|
adev[a].oss_audio_device_fd = -1;
|
||||||
#endif
|
#endif
|
||||||
adev[a].udp_sock = -1;
|
adev[a].udp_sock = -1;
|
||||||
|
@ -348,6 +359,24 @@ int audio_open (struct audio_s *pa)
|
||||||
|
|
||||||
adev[a].inbuf_size_in_bytes = set_alsa_params (a, adev[a].audio_in_handle, pa, audio_in_name, "input");
|
adev[a].inbuf_size_in_bytes = set_alsa_params (a, adev[a].audio_in_handle, pa, audio_in_name, "input");
|
||||||
|
|
||||||
|
#elif USE_SNDIO
|
||||||
|
adev[a].sndio_in_handle = sio_open (audio_in_name, SIO_REC, 0);
|
||||||
|
if (adev[a].sndio_in_handle == NULL) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Could not open audio device %s for input\n",
|
||||||
|
audio_in_name);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
adev[a].inbuf_size_in_bytes = set_sndio_params (a, adev[a].sndio_in_handle, pa, audio_in_name, "input");
|
||||||
|
|
||||||
|
if (!sio_start (adev[a].sndio_in_handle)) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Could not start audio device %s for input\n",
|
||||||
|
audio_in_name);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
#else // OSS
|
#else // OSS
|
||||||
adev[a].oss_audio_device_fd = open (pa->adev[a].adevice_in, O_RDWR);
|
adev[a].oss_audio_device_fd = open (pa->adev[a].adevice_in, O_RDWR);
|
||||||
|
|
||||||
|
@ -439,6 +468,27 @@ int audio_open (struct audio_s *pa)
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif USE_SNDIO
|
||||||
|
adev[a].sndio_out_handle = sio_open (audio_out_name, SIO_PLAY, 0);
|
||||||
|
if (adev[a].sndio_out_handle == NULL) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Could not open audio device %s for output\n",
|
||||||
|
audio_out_name);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
adev[a].outbuf_size_in_bytes = set_sndio_params (a, adev[a].sndio_out_handle, pa, audio_out_name, "output");
|
||||||
|
|
||||||
|
if (adev[a].inbuf_size_in_bytes <= 0 || adev[a].outbuf_size_in_bytes <= 0) {
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sio_start (adev[a].sndio_out_handle)) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Could not start audio device %s for output\n",
|
||||||
|
audio_out_name);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -675,6 +725,112 @@ static int set_alsa_params (int a, snd_pcm_t *handle, struct audio_s *pa, char *
|
||||||
} /* end alsa_set_params */
|
} /* end alsa_set_params */
|
||||||
|
|
||||||
|
|
||||||
|
#elif USE_SNDIO
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set parameters for sound card. (sndio)
|
||||||
|
*
|
||||||
|
* See /usr/include/sndio.h for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int set_sndio_params (int a, struct sio_hdl *handle, struct audio_s *pa, char *devname, char *inout)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct sio_par q, r;
|
||||||
|
|
||||||
|
/* Signed 16 bit little endian or unsigned 8 bit. */
|
||||||
|
sio_initpar (&q);
|
||||||
|
q.bits = pa->adev[a].bits_per_sample;
|
||||||
|
q.bps = (q.bits + 7) / 8;
|
||||||
|
q.sig = (q.bits == 8) ? 0 : 1;
|
||||||
|
q.le = 1; /* always little endian */
|
||||||
|
q.msb = 0; /* LSB aligned */
|
||||||
|
q.rchan = q.pchan = pa->adev[a].num_channels;
|
||||||
|
q.rate = pa->adev[a].samples_per_sec;
|
||||||
|
q.xrun = SIO_IGNORE;
|
||||||
|
q.appbufsz = calcbufsize(pa->adev[a].samples_per_sec, pa->adev[a].num_channels, pa->adev[a].bits_per_sample);
|
||||||
|
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("suggest buffer size %d bytes for %s %s.\n",
|
||||||
|
q.appbufsz, devname, inout);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* challenge new setting */
|
||||||
|
if (!sio_setpar (handle, &q)) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Could not set hardware parameter for %s %s.\n",
|
||||||
|
devname, inout);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get response */
|
||||||
|
if (!sio_getpar (handle, &r)) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Could not obtain current hardware setting for %s %s.\n",
|
||||||
|
devname, inout);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("audio buffer size %d bytes for %s %s.\n",
|
||||||
|
r.appbufsz, devname, inout);
|
||||||
|
#endif
|
||||||
|
if (q.rate != r.rate) {
|
||||||
|
text_color_set(DW_COLOR_INFO);
|
||||||
|
dw_printf ("Asked for %d samples/sec but got %d for %s %s.",
|
||||||
|
pa->adev[a].samples_per_sec, r.rate, devname, inout);
|
||||||
|
pa->adev[a].samples_per_sec = r.rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* not supported */
|
||||||
|
if (q.bits != r.bits || q.bps != r.bps || q.sig != r.sig ||
|
||||||
|
(q.bits > 8 && q.le != r.le) ||
|
||||||
|
(*inout == 'o' && q.pchan != r.pchan) ||
|
||||||
|
(*inout == 'i' && q.rchan != r.rchan)) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Unsupported format for %s %s.\n", devname, inout);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.appbufsz;
|
||||||
|
|
||||||
|
} /* end set_sndio_params */
|
||||||
|
|
||||||
|
static int poll_sndio (struct sio_hdl *hdl, int events)
|
||||||
|
{
|
||||||
|
struct pollfd *pfds;
|
||||||
|
int nfds, revents;
|
||||||
|
|
||||||
|
nfds = sio_nfds (hdl);
|
||||||
|
pfds = alloca (nfds * sizeof(struct pollfd));
|
||||||
|
|
||||||
|
do {
|
||||||
|
nfds = sio_pollfd (hdl, pfds, events);
|
||||||
|
if (nfds < 1) {
|
||||||
|
/* no need to wait */
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
if (poll (pfds, nfds, -1) < 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("poll %d\n", errno);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
revents = sio_revents (hdl, pfds);
|
||||||
|
} while (!(revents & (events | POLLHUP)));
|
||||||
|
|
||||||
|
/* unrecoverable error occured */
|
||||||
|
if (revents & POLLHUP) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("waited for %s, POLLHUP received\n", (events & POLLIN) ? "POLLIN" : "POLLOUT");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|
||||||
|
@ -842,7 +998,11 @@ __attribute__((hot))
|
||||||
int audio_get (int a)
|
int audio_get (int a)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
|
#if USE_ALSA
|
||||||
int retries = 0;
|
int retries = 0;
|
||||||
|
#elif USE_SNDIO
|
||||||
|
int err;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if STATISTICS
|
#if STATISTICS
|
||||||
/* Gather numbers for read from audio device. */
|
/* Gather numbers for read from audio device. */
|
||||||
|
@ -970,7 +1130,29 @@ int audio_get (int a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#else /* end ALSA, begin OSS */
|
#elif USE_SNDIO
|
||||||
|
|
||||||
|
while (adev[a].inbuf_next >= adev[a].inbuf_len) {
|
||||||
|
|
||||||
|
assert (adev[a].sndio_in_handle != NULL);
|
||||||
|
err = poll_sndio (adev[a].sndio_in_handle, POLLIN);
|
||||||
|
if (err < 0) {
|
||||||
|
adev[a].inbuf_len = 0;
|
||||||
|
adev[a].inbuf_next = 0;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
n = sio_read (adev[a].sndio_in_handle, adev[a].inbuf_ptr, adev[a].inbuf_size_in_bytes);
|
||||||
|
adev[a].inbuf_len = n;
|
||||||
|
adev[a].inbuf_next = 0;
|
||||||
|
|
||||||
|
audio_stats (a,
|
||||||
|
save_audio_config_p->adev[a].num_channels,
|
||||||
|
n / (save_audio_config_p->adev[a].num_channels * save_audio_config_p->adev[a].bits_per_sample / 8),
|
||||||
|
save_audio_config_p->statistics_interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* begin OSS */
|
||||||
|
|
||||||
/* Fixed in 1.2. This was formerly outside of the switch */
|
/* Fixed in 1.2. This was formerly outside of the switch */
|
||||||
/* so the OSS version did not process stdin or UDP. */
|
/* so the OSS version did not process stdin or UDP. */
|
||||||
|
@ -1250,6 +1432,38 @@ int audio_flush (int a)
|
||||||
adev[a].outbuf_len = 0;
|
adev[a].outbuf_len = 0;
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
|
#elif USE_SNDIO
|
||||||
|
|
||||||
|
int k;
|
||||||
|
unsigned char *ptr;
|
||||||
|
int len, err;
|
||||||
|
|
||||||
|
ptr = adev[a].outbuf_ptr;
|
||||||
|
len = adev[a].outbuf_len;
|
||||||
|
|
||||||
|
while (len > 0) {
|
||||||
|
assert (adev[a].sndio_out_handle != NULL);
|
||||||
|
err = poll_sndio (adev[a].sndio_out_handle, POLLOUT);
|
||||||
|
if (err < 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
perror("Can't write to audio device");
|
||||||
|
adev[a].outbuf_len = 0;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
k = sio_write (adev[a].sndio_out_handle, ptr, len);
|
||||||
|
#if DEBUGx
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("audio_flush(): write %d returns %d\n", len, k);
|
||||||
|
fflush (stdout);
|
||||||
|
#endif
|
||||||
|
ptr += k;
|
||||||
|
len -= k;
|
||||||
|
}
|
||||||
|
|
||||||
|
adev[a].outbuf_len = 0;
|
||||||
|
return (0);
|
||||||
|
|
||||||
#else /* OSS */
|
#else /* OSS */
|
||||||
|
|
||||||
int k;
|
int k;
|
||||||
|
@ -1351,6 +1565,10 @@ void audio_wait (int a)
|
||||||
* Either way, the caller will now compensate for it.
|
* Either way, the caller will now compensate for it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#elif USE_SNDIO
|
||||||
|
|
||||||
|
poll_sndio (adev[a].sndio_out_handle, POLLOUT);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
assert (adev[a].oss_audio_device_fd > 0);
|
assert (adev[a].oss_audio_device_fd > 0);
|
||||||
|
@ -1397,6 +1615,21 @@ int audio_close (void)
|
||||||
snd_pcm_close (adev[a].audio_in_handle);
|
snd_pcm_close (adev[a].audio_in_handle);
|
||||||
snd_pcm_close (adev[a].audio_out_handle);
|
snd_pcm_close (adev[a].audio_out_handle);
|
||||||
|
|
||||||
|
adev[a].audio_in_handle = adev[a].audio_out_handle = NULL;
|
||||||
|
|
||||||
|
#elif USE_SNDIO
|
||||||
|
|
||||||
|
if (adev[a].sndio_in_handle != NULL && adev[a].sndio_out_handle != NULL) {
|
||||||
|
|
||||||
|
audio_wait (a);
|
||||||
|
|
||||||
|
sio_stop (adev[a].sndio_in_handle);
|
||||||
|
sio_stop (adev[a].sndio_out_handle);
|
||||||
|
sio_close (adev[a].sndio_in_handle);
|
||||||
|
sio_close (adev[a].sndio_out_handle);
|
||||||
|
|
||||||
|
adev[a].sndio_in_handle = adev[a].sndio_out_handle = NULL;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
if (adev[a].oss_audio_device_fd > 0) {
|
if (adev[a].oss_audio_device_fd > 0) {
|
||||||
|
|
|
@ -352,8 +352,8 @@ struct audio_s {
|
||||||
#define DEFAULT_ADEVICE "" /* Mac OSX: Empty string = default audio device. */
|
#define DEFAULT_ADEVICE "" /* Mac OSX: Empty string = default audio device. */
|
||||||
#elif USE_ALSA
|
#elif USE_ALSA
|
||||||
#define DEFAULT_ADEVICE "default" /* Use default device for ALSA. */
|
#define DEFAULT_ADEVICE "default" /* Use default device for ALSA. */
|
||||||
#elif __OpenBSD__
|
#elif USE_SNDIO
|
||||||
#define DEFAULT_ADEVICE "default" /* Use default device for OpenBSD-portaudio. */
|
#define DEFAULT_ADEVICE "default" /* Use default device for sndio. */
|
||||||
#else
|
#else
|
||||||
#define DEFAULT_ADEVICE "/dev/dsp" /* First audio device for OSS. (FreeBSD) */
|
#define DEFAULT_ADEVICE "/dev/dsp" /* First audio device for OSS. (FreeBSD) */
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -67,9 +67,8 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#ifdef __OpenBSD__
|
#if USE_SNDIO || __APPLE__
|
||||||
#include <soundcard.h>
|
// no need to include <soundcard.h>
|
||||||
#elif __APPLE__
|
|
||||||
#else
|
#else
|
||||||
#include <sys/soundcard.h>
|
#include <sys/soundcard.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue