Pull request 322 - SNDIO support for BSD.

This commit is contained in:
wb2osz 2021-04-10 21:14:26 -04:00
commit 6370b26d85
6 changed files with 302 additions and 14 deletions

View File

@ -145,6 +145,10 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
configure_file("${CMAKE_SOURCE_DIR}/cmake/cpack/${CMAKE_PROJECT_NAME}.desktop.in"
"${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.desktop" @ONLY)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
set(OPENBSD TRUE)
set(HAVE_SNDIO TRUE)
elseif(APPLE)
if("${CMAKE_OSX_DEPLOYMENT_TARGET}" STREQUAL "")
message(STATUS "Build for macOS target: local version")
@ -301,6 +305,12 @@ if(LINUX)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_AVAHI_CLIENT")
endif()
elseif (HAVE_SNDIO)
find_package(sndio REQUIRED)
if(SNDIO_FOUND)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_SNDIO")
endif()
elseif (NOT WIN32 AND NOT CYGWIN)
find_package(Portaudio REQUIRED)
if(PORTAUDIO_FOUND)
@ -316,6 +326,8 @@ else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_CM108")
set(PORTAUDIO_INCLUDE_DIRS "")
set(PORTAUDIO_LIBRARIES "")
set(SNDIO_INCLUDE_DIRS "")
set(SNDIO_LIBRARIES "")
endif()
# manage and fetch new data

View File

@ -0,0 +1,42 @@
# - Try to find sndio
#
# SNDIO_FOUND - system has sndio
# SNDIO_LIBRARIES - location of the library for sndio
# SNDIO_INCLUDE_DIRS - location of the include files for sndio
set(SNDIO_ROOT_DIR
"${SNDIO_ROOT_DIR}"
CACHE
PATH
"Directory to search for sndio")
# no need to check pkg-config
find_path(SNDIO_INCLUDE_DIRS
NAMES
sndio.h
PATHS
/usr/local/include
/usr/include
/opt/local/include
HINTS
${SNDIO_ROOT_DIR}
)
find_library(SNDIO_LIBRARIES
NAMES
sndio
PATHS
/usr/local/lib
/usr/lib
/usr/lib64
/opt/local/lib
HINTS
${SNDIIO_ROOT_DIR}
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(SNDIO DEFAULT_MSG SNDIO_INCLUDE_DIRS SNDIO_LIBRARIES)
mark_as_advanced(SNDIO_INCLUDE_DIRS SNDIO_LIBRARIES)

View File

@ -8,6 +8,7 @@ include_directories(
${ALSA_INCLUDE_DIRS}
${UDEV_INCLUDE_DIRS}
${PORTAUDIO_INCLUDE_DIRS}
${SNDIO_INCLUDE_DIRS}
${CUSTOM_GEOTRANZ_DIR}
${CUSTOM_HIDAPI_DIR}
)
@ -116,7 +117,11 @@ if(LINUX)
list(REMOVE_ITEM direwolf_SOURCES
dwgpsd.c
)
else() # macOS freebsd openbsd
elseif(HAVE_SNDIO)
list(APPEND direwolf_SOURCES
audio.c
)
else() # macOS freebsd
list(APPEND direwolf_SOURCES
audio_portaudio.c
)
@ -143,6 +148,7 @@ target_link_libraries(direwolf
${ALSA_LIBRARIES}
${UDEV_LIBRARIES}
${PORTAUDIO_LIBRARIES}
${SNDIO_LIBRARIES}
${AVAHI_LIBRARIES}
)

View File

@ -75,18 +75,17 @@
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#if USE_ALSA
#include <alsa/asoundlib.h>
#else
#include <errno.h>
#ifdef __OpenBSD__
#include <soundcard.h>
#elif USE_SNDIO
#include <sndio.h>
#include <poll.h>
#else
#include <sys/soundcard.h>
#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; 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;
#endif
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");
#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
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);
}
#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,9 @@ __attribute__((hot))
int audio_get (int a)
{
int n;
#if USE_ALSA
int retries = 0;
#endif
#if STATISTICS
/* Gather numbers for read from audio device. */
@ -970,7 +1128,28 @@ 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);
if (poll_sndio (adev[a].sndio_in_handle, POLLIN) < 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 +1429,37 @@ int audio_flush (int a)
adev[a].outbuf_len = 0;
return (-1);
#elif USE_SNDIO
int k;
unsigned char *ptr;
int len;
ptr = adev[a].outbuf_ptr;
len = adev[a].outbuf_len;
while (len > 0) {
assert (adev[a].sndio_out_handle != NULL);
if (poll_sndio (adev[a].sndio_out_handle, POLLOUT) < 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 +1561,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 +1610,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) {

View File

@ -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

View File

@ -67,9 +67,8 @@
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#ifdef __OpenBSD__
#include <soundcard.h>
#elif __APPLE__
#if USE_SNDIO || __APPLE__
// no need to include <soundcard.h>
#else
#include <sys/soundcard.h>
#endif