Skip to content

Commit

Permalink
Initial Sndio implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
davidebeatrici committed Apr 3, 2024
1 parent 190735b commit 31165fa
Show file tree
Hide file tree
Showing 10 changed files with 789 additions and 4 deletions.
207 changes: 207 additions & 0 deletions 3rdparty/Sndio/sndio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2008 Alexandre Ratchov <[email protected]>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef SNDIO_H
#define SNDIO_H

#include <sys/types.h>

/*
* default audio device and MIDI port
*/
#define SIO_DEVANY "default"
#define MIO_PORTANY "default"

/*
* limits
*/
#define SIOCTL_NAMEMAX 12 /* max name length */

/*
* private ``handle'' structure
*/
struct sio_hdl;
struct mio_hdl;
struct sioctl_hdl;

/*
* parameters of a full-duplex stream
*/
struct sio_par {
unsigned int bits; /* bits per sample */
unsigned int bps; /* bytes per sample */
unsigned int sig; /* 1 = signed, 0 = unsigned */
unsigned int le; /* 1 = LE, 0 = BE byte order */
unsigned int msb; /* 1 = MSB, 0 = LSB aligned */
unsigned int rchan; /* number channels for recording direction */
unsigned int pchan; /* number channels for playback direction */
unsigned int rate; /* frames per second */
unsigned int bufsz; /* end-to-end buffer size */
#define SIO_IGNORE 0 /* pause during xrun */
#define SIO_SYNC 1 /* resync after xrun */
#define SIO_ERROR 2 /* terminate on xrun */
unsigned int xrun; /* what to do on overruns/underruns */
unsigned int round; /* optimal bufsz divisor */
unsigned int appbufsz; /* minimum buffer size */
int __pad[3]; /* for future use */
unsigned int __magic; /* for internal/debug purposes only */
};

/*
* capabilities of a stream
*/
struct sio_cap {
#define SIO_NENC 8
#define SIO_NCHAN 8
#define SIO_NRATE 16
#define SIO_NCONF 4
struct sio_enc { /* allowed sample encodings */
unsigned int bits;
unsigned int bps;
unsigned int sig;
unsigned int le;
unsigned int msb;
} enc[SIO_NENC];
unsigned int rchan[SIO_NCHAN]; /* allowed values for rchan */
unsigned int pchan[SIO_NCHAN]; /* allowed values for pchan */
unsigned int rate[SIO_NRATE]; /* allowed rates */
int __pad[7]; /* for future use */
unsigned int nconf; /* number of elements in confs[] */
struct sio_conf {
unsigned int enc; /* mask of enc[] indexes */
unsigned int rchan; /* mask of chan[] indexes (rec) */
unsigned int pchan; /* mask of chan[] indexes (play) */
unsigned int rate; /* mask of rate[] indexes */
} confs[SIO_NCONF];
};

#define SIO_XSTRINGS { "ignore", "sync", "error" }

/*
* controlled component of the device
*/
struct sioctl_node {
char name[SIOCTL_NAMEMAX]; /* ex. "spkr" */
int unit; /* optional number or -1 */
};

/*
* description of a control (index, value) pair
*/
struct sioctl_desc {
unsigned int addr; /* control address */
#define SIOCTL_NONE 0 /* deleted */
#define SIOCTL_NUM 2 /* integer in the 0..maxval range */
#define SIOCTL_SW 3 /* on/off switch (0 or 1) */
#define SIOCTL_VEC 4 /* number, element of vector */
#define SIOCTL_LIST 5 /* switch, element of a list */
#define SIOCTL_SEL 6 /* element of a selector */
unsigned int type; /* one of above */
char func[SIOCTL_NAMEMAX]; /* function name, ex. "level" */
char group[SIOCTL_NAMEMAX]; /* group this control belongs to */
struct sioctl_node node0; /* affected node */
struct sioctl_node node1; /* dito for SIOCTL_{VEC,LIST,SEL} */
unsigned int maxval; /* max value */
int __pad[3];
};

/*
* mode bitmap
*/
#define SIO_PLAY 1
#define SIO_REC 2
#define MIO_OUT 4
#define MIO_IN 8
#define SIOCTL_READ 0x100
#define SIOCTL_WRITE 0x200

/*
* default bytes per sample for the given bits per sample
*/
#define SIO_BPS(bits) (((bits) <= 8) ? 1 : (((bits) <= 16) ? 2 : 4))

/*
* default value of "sio_par->le" flag
*/
#if BYTE_ORDER == LITTLE_ENDIAN
#define SIO_LE_NATIVE 1
#else
#define SIO_LE_NATIVE 0
#endif

/*
* maximum value of volume, eg. for sio_setvol()
*/
#define SIO_MAXVOL 127

#ifdef __cplusplus
extern "C" {
#endif

struct pollfd;

void sio_initpar(struct sio_par *);
struct sio_hdl *sio_open(const char *, unsigned int, int);
void sio_close(struct sio_hdl *);
int sio_setpar(struct sio_hdl *, struct sio_par *);
int sio_getpar(struct sio_hdl *, struct sio_par *);
int sio_getcap(struct sio_hdl *, struct sio_cap *);
void sio_onmove(struct sio_hdl *, void (*)(void *, int), void *);
size_t sio_write(struct sio_hdl *, const void *, size_t);
size_t sio_read(struct sio_hdl *, void *, size_t);
int sio_start(struct sio_hdl *);
int sio_stop(struct sio_hdl *);
int sio_flush(struct sio_hdl *);
int sio_nfds(struct sio_hdl *);
int sio_pollfd(struct sio_hdl *, struct pollfd *, int);
int sio_revents(struct sio_hdl *, struct pollfd *);
int sio_eof(struct sio_hdl *);
int sio_setvol(struct sio_hdl *, unsigned int);
int sio_onvol(struct sio_hdl *, void (*)(void *, unsigned int), void *);

struct mio_hdl *mio_open(const char *, unsigned int, int);
void mio_close(struct mio_hdl *);
size_t mio_write(struct mio_hdl *, const void *, size_t);
size_t mio_read(struct mio_hdl *, void *, size_t);
int mio_nfds(struct mio_hdl *);
int mio_pollfd(struct mio_hdl *, struct pollfd *, int);
int mio_revents(struct mio_hdl *, struct pollfd *);
int mio_eof(struct mio_hdl *);

struct sioctl_hdl *sioctl_open(const char *, unsigned int, int);
void sioctl_close(struct sioctl_hdl *);
int sioctl_ondesc(struct sioctl_hdl *,
void (*)(void *, struct sioctl_desc *, int), void *);
int sioctl_onval(struct sioctl_hdl *,
void (*)(void *, unsigned int, unsigned int), void *);
int sioctl_setval(struct sioctl_hdl *, unsigned int, unsigned int);
int sioctl_nfds(struct sioctl_hdl *);
int sioctl_pollfd(struct sioctl_hdl *, struct pollfd *, int);
int sioctl_revents(struct sioctl_hdl *, struct pollfd *);
int sioctl_eof(struct sioctl_hdl *);

int mio_rmidi_getfd(const char *, unsigned int, int);
struct mio_hdl *mio_rmidi_fdopen(int, unsigned int, int);
int sio_sun_getfd(const char *, unsigned int, int);
struct sio_hdl *sio_sun_fdopen(int, unsigned int, int);
int sioctl_sun_getfd(const char *, unsigned int, int);
struct sioctl_hdl *sioctl_sun_fdopen(int, unsigned int, int);

#ifdef __cplusplus
}
#endif

#endif /* !defined(SNDIO_H) */
2 changes: 1 addition & 1 deletion include/crossaudio/Backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ enum CrossAudio_Backend {
CROSSAUDIO_BACKEND_WASAPI,
CROSSAUDIO_BACKEND_COREAUDIO,
CROSSAUDIO_BACKEND_PULSEAUDIO,
CROSSAUDIO_BACKEND_JACKAUDIO,
CROSSAUDIO_BACKEND_SNDIO,
CROSSAUDIO_BACKEND_PIPEWIRE
};

Expand Down
6 changes: 3 additions & 3 deletions src/Backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@ static inline const BE_Impl *backendGetImpl(const Backend backend) {
return NULL;
#endif
}
case CROSSAUDIO_BACKEND_JACKAUDIO: {
#ifdef HAS_JACKAUDIO
GET_BACKEND(JackAudio)
case CROSSAUDIO_BACKEND_SNDIO: {
#ifdef HAS_SNDIO
GET_BACKEND(Sndio)
#else
return NULL;
#endif
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ target_link_libraries(crossaudio
$<TARGET_NAME_IF_EXISTS:be_oss>
$<TARGET_NAME_IF_EXISTS:be_pipewire>
$<TARGET_NAME_IF_EXISTS:be_pulseaudio>
$<TARGET_NAME_IF_EXISTS:be_sndio>
$<TARGET_NAME_IF_EXISTS:be_wasapi>
)

Expand Down
1 change: 1 addition & 0 deletions src/backends/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ if(UNIX)
add_subdirectory(OSS)
add_subdirectory(PipeWire)
add_subdirectory(PulseAudio)
add_subdirectory(Sndio)
endif()

if(WIN32)
Expand Down
34 changes: 34 additions & 0 deletions src/backends/Sndio/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Copyright 2024 The Mumble Developers. All rights reserved.
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file at the root of the
# Mumble source tree or at <https://www.mumble.info/LICENSE>.

include(CrossAudioCompiler)

add_library(be_sndio OBJECT)

target_pedantic_warnings(be_sndio)

target_compile_definitions(be_sndio
INTERFACE
"HAS_SNDIO"
)

target_include_directories(be_sndio
PRIVATE
${SRC_DIR}
${INCLUDE_DIR}
)

target_include_directories(be_sndio
SYSTEM PRIVATE
"${3RDPARTY_DIR}/Sndio"
)

target_sources(be_sndio
PRIVATE
"Library.cpp"
"Library.hpp"
"Sndio.cpp"
"Sndio.hpp"
)
56 changes: 56 additions & 0 deletions src/backends/Sndio/Library.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2024 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.

#include "Library.hpp"

#include <dlfcn.h>

#define LOAD_SYM(var) \
*(void **) &var = dlsym(m_handle, "sio_" #var); \
if (!var) { \
unload(); \
return CROSSAUDIO_EC_SYMBOL; \
}

using namespace sndio;

Library::Library() : m_handle(nullptr) {
}

Library::~Library() {
unload();
}

ErrorCode Library::load(const std::string_view libraryName) {
if (!(m_handle = dlopen(libraryName.data(), RTLD_LAZY))) {
return CROSSAUDIO_EC_LIBRARY;
}

LOAD_SYM(open)
LOAD_SYM(close)

LOAD_SYM(start)
LOAD_SYM(stop)

LOAD_SYM(read)
LOAD_SYM(write)

LOAD_SYM(initpar)
LOAD_SYM(getpar)
LOAD_SYM(setpar)

LOAD_SYM(nfds)
LOAD_SYM(pollfd)
LOAD_SYM(revents)

return CROSSAUDIO_EC_OK;
}

void Library::unload() {
if (m_handle) {
dlclose(m_handle);
m_handle = nullptr;
}
}
57 changes: 57 additions & 0 deletions src/backends/Sndio/Library.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2024 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.

#ifndef CROSSAUDIO_SRC_BACKENDS_SNDIO_LIBRARY_HPP
#define CROSSAUDIO_SRC_BACKENDS_SNDIO_LIBRARY_HPP

#include "crossaudio/ErrorCode.h"

#include <cstddef>
#include <string_view>

using ErrorCode = CrossAudio_ErrorCode;

typedef struct pollfd PollFD;

struct sio_hdl;
struct sio_par;

namespace sndio {
class Library {
public:
Library();
~Library();

explicit operator bool() const { return m_handle; }

ErrorCode load(const std::string_view libraryName);
void unload();

void *m_handle;

sio_hdl *(*open)(const char *name, unsigned int mode, int nbio_flag);
void (*close)(sio_hdl *hdl);

int (*start)(sio_hdl *hdl);
int (*stop)(sio_hdl *hdl);

size_t (*read)(sio_hdl *hdl, void *addr, size_t nbytes);
size_t (*write)(sio_hdl *hdl, const void *addr, size_t nbytes);

void (*initpar)(sio_par *par);
int (*getpar)(sio_hdl *hdl, sio_par *par);
int (*setpar)(sio_hdl *hdl, sio_par *par);

int (*nfds)(sio_hdl *hdl);
int (*pollfd)(sio_hdl *hdl, PollFD *pfd, int events);
int (*revents)(sio_hdl *hdl, PollFD *pfd);

private:
Library(const Library &) = delete;
Library &operator=(const Library &) = delete;
};
} // namespace sndio

#endif
Loading

0 comments on commit 31165fa

Please sign in to comment.