diff --git a/src/audio.c b/src/audio.c index 613be06..705e9fa 100644 --- a/src/audio.c +++ b/src/audio.c @@ -75,18 +75,17 @@ #include #include #include +#include #if USE_ALSA #include -#else -#include -#ifdef __OpenBSD__ -#include +#elif USE_SNDIO +#include +#include #else #include #endif -#endif #include "audio.h" @@ -111,6 +110,9 @@ static struct adev_s { int bytes_per_frame; /* number of bytes for a sample from all channels. */ /* e.g. 4 for stereo 16 bit. */ +#elif USE_SNDIO + struct sio_hdl *sndio_in_handle; + struct sio_hdl *sndio_out_handle; #else int oss_audio_device_fd; /* Single device, both directions. */ @@ -141,6 +143,9 @@ static struct adev_s { #if USE_ALSA 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); +#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 static int set_oss_params (int a, int fd, struct audio_s *pa); #endif @@ -212,7 +217,9 @@ static int calcbufsize(int rate, int chans, int bits) int audio_open (struct audio_s *pa) { +#if !USE_SNDIO int err; +#endif int chan; int a; char audio_in_name[30]; @@ -224,7 +231,11 @@ int audio_open (struct audio_s *pa) memset (adev, 0, sizeof(adev)); for (a=0; aadev[a].adevice_in, O_RDWR); @@ -439,6 +468,27 @@ int audio_open (struct audio_s *pa) 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 /* @@ -675,6 +725,112 @@ static int set_alsa_params (int a, snd_pcm_t *handle, struct audio_s *pa, char * } /* 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 @@ -842,7 +998,11 @@ __attribute__((hot)) int audio_get (int a) { int n; +#if USE_ALSA int retries = 0; +#elif USE_SNDIO + int err; +#endif #if STATISTICS /* 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 */ /* so the OSS version did not process stdin or UDP. */ @@ -1250,6 +1432,38 @@ int audio_flush (int a) adev[a].outbuf_len = 0; 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 */ int k; @@ -1351,6 +1565,10 @@ void audio_wait (int a) * Either way, the caller will now compensate for it. */ +#elif USE_SNDIO + + poll_sndio (adev[a].sndio_out_handle, POLLOUT); + #else assert (adev[a].oss_audio_device_fd > 0); @@ -1396,7 +1614,22 @@ int audio_close (void) snd_pcm_close (adev[a].audio_in_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 if (adev[a].oss_audio_device_fd > 0) { diff --git a/src/audio.h b/src/audio.h index 32868c5..7eca120 100644 --- a/src/audio.h +++ b/src/audio.h @@ -352,8 +352,8 @@ struct audio_s { #define DEFAULT_ADEVICE "" /* Mac OSX: Empty string = default audio device. */ #elif USE_ALSA #define DEFAULT_ADEVICE "default" /* Use default device for ALSA. */ -#elif __OpenBSD__ -#define DEFAULT_ADEVICE "default" /* Use default device for OpenBSD-portaudio. */ +#elif USE_SNDIO +#define DEFAULT_ADEVICE "default" /* Use default device for sndio. */ #else #define DEFAULT_ADEVICE "/dev/dsp" /* First audio device for OSS. (FreeBSD) */ #endif diff --git a/src/direwolf.c b/src/direwolf.c index 10c6cb1..fd3e293 100644 --- a/src/direwolf.c +++ b/src/direwolf.c @@ -67,9 +67,8 @@ #include #include #include -#ifdef __OpenBSD__ -#include -#elif __APPLE__ +#if USE_SNDIO || __APPLE__ +// no need to include #else #include #endif