Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,20 @@ lib_LTLIBRARIES += src/libpcaudio.la

src_libpcaudio_la_LDFLAGS = -version-info $(LIBPCAUDIO_VERSION) \
${ALSA_LIBS} \
${SNDIO_LIBS} \
${PULSEAUDIO_LIBS} \
${QSA_LIBS} \
${COREAUDIO_LIBS}

src_libpcaudio_la_CFLAGS = ${AM_CFLAGS} \
${ALSA_CFLAGS} \
${SNDIO_CFLAGS} \
${PULSEAUDIO_CFLAGS} \
${COREAUDIO_CFLAGS}

src_libpcaudio_la_SOURCES = \
src/alsa.c \
src/sndio.c \
src/qsa.c \
src/oss.c \
src/pulseaudio.c \
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ devices. It supports:
| PulseAudio | Linux |
| QSA | QNX |
| XAudio2 | Windows |
| sndio | BSD, Linux |

See the [CHANGELOG](CHANGELOG.md) for a description of the changes in the
various releases.
Expand Down Expand Up @@ -53,6 +54,7 @@ Optional Libraries:
|----------------|--------------------------------------------|
| alsa | `sudo apt-get install libasound2-dev` |
| pulseaudio | `sudo apt-get install libpulse-dev` |
| sndio | `sudo apt-get install libsndio-dev` |

### Mac OS

Expand Down
24 changes: 24 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,29 @@ AS_IF([test "x$with_alsa" = "xno"], [
AC_SUBST(ALSA_CFLAGS)
AC_SUBST(ALSA_LIBS)

dnl ================================================================
dnl sndio checks.
dnl ================================================================

AC_ARG_WITH([sndio],
[AS_HELP_STRING([--with-sndio], [support for sndio audio output @<:@default=yes@:>@])],
[])

AS_IF([test "x$with_sndio" = "xno"], [
echo "Disabling sndio audio output support";
have_sndio=no
], [
PKG_CHECK_MODULES(SNDIO, [sndio],
[
AC_DEFINE(HAVE_SNDIO_H, [], [Do we have sndio])
have_sndio=yes
],[
have_sndio=no
])])

AC_SUBST(SNDIO_CFLAGS)
AC_SUBST(SNDIO_LIBS)

dnl ================================================================
dnl QSA checks.
dnl ================================================================
Expand Down Expand Up @@ -172,4 +195,5 @@ AC_MSG_NOTICE([
QSA support: ${have_qsa}
Coreaudio support: ${have_coreaudio}
OSS support: ${have_oss}
sndio support: ${have_sndio}
])
2 changes: 2 additions & 0 deletions src/audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ create_audio_device_object(const char *device,
#else
if ((object = create_pulseaudio_object(device, application_name, description)) != NULL)
return object;
if ((object = create_sndio_object(device, application_name, description)) != NULL)
return object;
if ((object = create_alsa_object(device, application_name, description)) != NULL)
return object;
if ((object = create_qsa_object(device, application_name, description)) != NULL)
Expand Down
5 changes: 5 additions & 0 deletions src/audio_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ create_pulseaudio_object(const char *device,
const char *application_name,
const char *description);

struct audio_object *
create_sndio_object(const char *device,
const char *application_name,
const char *description);

struct audio_object *
create_alsa_object(const char *device,
const char *application_name,
Expand Down
284 changes: 284 additions & 0 deletions src/sndio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
/* sndio Output.
*
* Copyright (C) 2021 Haelwenn (lanodan) Monnier
*
* This file is part of pcaudiolib.
*
* pcaudiolib is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pcaudiolib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pcaudiolib. If not, see <http://www.gnu.org/licenses/>.
*/

#include "config.h"
#include "audio_priv.h"

#ifdef HAVE_SNDIO_H

#include <sndio.h>
#include <string.h> /* strdup */

struct sndio_object
{
struct audio_object vtable;
struct sio_hdl *hdl;
char *application_name;
char *description;
};

#define to_sndio_object(object) container_of(object, struct sndio_object, vtable)

int
audio_format_get_bits(enum audio_object_format format) {
switch(format)
{
case AUDIO_OBJECT_FORMAT_S8:
case AUDIO_OBJECT_FORMAT_U8:
return 8;
break;

case AUDIO_OBJECT_FORMAT_S16LE:
case AUDIO_OBJECT_FORMAT_S16BE:
case AUDIO_OBJECT_FORMAT_U16LE:
case AUDIO_OBJECT_FORMAT_U16BE:
return 16;
break;

case AUDIO_OBJECT_FORMAT_S18LE:
case AUDIO_OBJECT_FORMAT_S18BE:
case AUDIO_OBJECT_FORMAT_U18LE:
case AUDIO_OBJECT_FORMAT_U18BE:
return 18;
break;

case AUDIO_OBJECT_FORMAT_S20LE:
case AUDIO_OBJECT_FORMAT_S20BE:
case AUDIO_OBJECT_FORMAT_U20LE:
case AUDIO_OBJECT_FORMAT_U20BE:
return 20;
break;

case AUDIO_OBJECT_FORMAT_S24LE:
case AUDIO_OBJECT_FORMAT_S24BE:
case AUDIO_OBJECT_FORMAT_U24LE:
case AUDIO_OBJECT_FORMAT_U24BE:
return 24;
break;

case AUDIO_OBJECT_FORMAT_S24_32LE:
case AUDIO_OBJECT_FORMAT_S24_32BE:
case AUDIO_OBJECT_FORMAT_U24_32LE:
case AUDIO_OBJECT_FORMAT_U24_32BE:
return -1; // ???
break;

case AUDIO_OBJECT_FORMAT_S32LE:
case AUDIO_OBJECT_FORMAT_S32BE:
case AUDIO_OBJECT_FORMAT_U32LE:
case AUDIO_OBJECT_FORMAT_U32BE:
return 32;
break;
default:
return -1;
}
}

int
audio_format_is_sig(enum audio_object_format format) {
switch(format)
{
case AUDIO_OBJECT_FORMAT_S8:
case AUDIO_OBJECT_FORMAT_S16LE:
case AUDIO_OBJECT_FORMAT_S16BE:
case AUDIO_OBJECT_FORMAT_S18LE:
case AUDIO_OBJECT_FORMAT_S18BE:
case AUDIO_OBJECT_FORMAT_S20LE:
case AUDIO_OBJECT_FORMAT_S20BE:
case AUDIO_OBJECT_FORMAT_S24LE:
case AUDIO_OBJECT_FORMAT_S24BE:
case AUDIO_OBJECT_FORMAT_S24_32LE:
case AUDIO_OBJECT_FORMAT_S24_32BE:
case AUDIO_OBJECT_FORMAT_S32LE:
case AUDIO_OBJECT_FORMAT_S32BE:
return 1;
case AUDIO_OBJECT_FORMAT_U8:
case AUDIO_OBJECT_FORMAT_U16LE:
case AUDIO_OBJECT_FORMAT_U16BE:
case AUDIO_OBJECT_FORMAT_U18LE:
case AUDIO_OBJECT_FORMAT_U18BE:
case AUDIO_OBJECT_FORMAT_U20LE:
case AUDIO_OBJECT_FORMAT_U20BE:
case AUDIO_OBJECT_FORMAT_U24LE:
case AUDIO_OBJECT_FORMAT_U24BE:
case AUDIO_OBJECT_FORMAT_U24_32LE:
case AUDIO_OBJECT_FORMAT_U24_32BE:
case AUDIO_OBJECT_FORMAT_U32LE:
case AUDIO_OBJECT_FORMAT_U32BE:
return 0;
break;
default:
return -1;
}
}

int
audio_format_is_le(enum audio_object_format format) {
switch(format)
{
case AUDIO_OBJECT_FORMAT_S8:
case AUDIO_OBJECT_FORMAT_U8:
case AUDIO_OBJECT_FORMAT_S16BE:
case AUDIO_OBJECT_FORMAT_U16BE:
case AUDIO_OBJECT_FORMAT_S18BE:
case AUDIO_OBJECT_FORMAT_U18BE:
case AUDIO_OBJECT_FORMAT_S20BE:
case AUDIO_OBJECT_FORMAT_U20BE:
case AUDIO_OBJECT_FORMAT_S24BE:
case AUDIO_OBJECT_FORMAT_U24BE:
case AUDIO_OBJECT_FORMAT_S24_32BE:
case AUDIO_OBJECT_FORMAT_U24_32BE:
return 0;

case AUDIO_OBJECT_FORMAT_S16LE:
case AUDIO_OBJECT_FORMAT_U16LE:
case AUDIO_OBJECT_FORMAT_S18LE:
case AUDIO_OBJECT_FORMAT_U18LE:
case AUDIO_OBJECT_FORMAT_S20LE:
case AUDIO_OBJECT_FORMAT_U20LE:
case AUDIO_OBJECT_FORMAT_S24LE:
case AUDIO_OBJECT_FORMAT_U24LE:
case AUDIO_OBJECT_FORMAT_S24_32LE:
case AUDIO_OBJECT_FORMAT_U24_32LE:
return 1;

default:
return -1;
}
}

int
sndio_object_open(struct audio_object *object,
enum audio_object_format format,
uint32_t rate,
uint8_t channels)
{
struct sndio_object *self = to_sndio_object(object);
struct sio_par par;
if (self->hdl)
return -1;

self->hdl = sio_open(self->application_name, SIO_PLAY, 0);
if(!self->hdl) {
return -1;
}

sio_initpar(&par);

int bits = audio_format_get_bits(format);
if(bits != -1) {
par.bits = bits;
}

int sig = audio_format_is_sig(format);
if(sig != -1) {
par.sig = sig;
}

int le = audio_format_is_le(format);
if(le != -1) {
par.le = le;
}

par.rate = rate;
par.rchan = 0;
par.pchan = channels;

if(!sio_setpar(self->hdl, &par))
return -1;

if(!sio_getpar(self->hdl, &par))
return -1;

if(par.bits != bits)
return -1;
if(par.sig != sig)
return -1;
if(par.le != le)
return -1;

return 0;
}

void
sndio_object_close(struct audio_object *object)
{
struct sndio_object *self = to_sndio_object(object);

if (self->hdl) {
sio_close(self->hdl);
self->hdl = NULL;
}
}

void
sndio_object_destroy(struct audio_object *object)
{
struct sndio_object *self = to_sndio_object(object);

free(self->application_name);
free(self->description);
free(self);
}

int
sndio_object_write(struct audio_object *object,
const void *data,
size_t bytes)
{
struct sndio_object *self = to_sndio_object(object);
if (!self->hdl)
return 0;

return sio_write(self->hdl, data, bytes) == bytes;
}

struct audio_object *
create_sndio_object(const char *device,
const char *application_name,
const char *description)
{
struct sndio_object *self = malloc(sizeof(struct sndio_object));
if (!self)
return NULL;

self->hdl = NULL;
self->application_name = application_name ? strdup(application_name) : NULL;
self->description = description ? strdup(description) : NULL;

self->vtable.open = sndio_object_open;
self->vtable.close = sndio_object_close;
self->vtable.destroy = sndio_object_destroy;
self->vtable.write = sndio_object_write;

return &self->vtable;
}

#else

struct audio_object *
create_sndio_object(const char *device,
const char *application_name,
const char *description)
{
return NULL;
}

#endif