summaryrefslogtreecommitdiffstats
path: root/media/libcubeb/src/cubeb_sndio.c
diff options
context:
space:
mode:
Diffstat (limited to 'media/libcubeb/src/cubeb_sndio.c')
-rw-r--r--media/libcubeb/src/cubeb_sndio.c416
1 files changed, 83 insertions, 333 deletions
diff --git a/media/libcubeb/src/cubeb_sndio.c b/media/libcubeb/src/cubeb_sndio.c
index 4a05bd845..793789765 100644
--- a/media/libcubeb/src/cubeb_sndio.c
+++ b/media/libcubeb/src/cubeb_sndio.c
@@ -4,7 +4,6 @@
* This program is made available under an ISC-style license. See the
* accompanying file LICENSE for details.
*/
-#include <inttypes.h>
#include <math.h>
#include <poll.h>
#include <pthread.h>
@@ -12,7 +11,6 @@
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
-#include <dlfcn.h>
#include <assert.h>
#include "cubeb/cubeb.h"
#include "cubeb-internal.h"
@@ -23,87 +21,39 @@
#define DPR(...) do {} while(0)
#endif
-#ifdef DISABLE_LIBSNDIO_DLOPEN
-#define WRAP(x) x
-#else
-#define WRAP(x) cubeb_##x
-#define LIBSNDIO_API_VISIT(X) \
- X(sio_close) \
- X(sio_eof) \
- X(sio_getpar) \
- X(sio_initpar) \
- X(sio_onmove) \
- X(sio_open) \
- X(sio_pollfd) \
- X(sio_read) \
- X(sio_revents) \
- X(sio_setpar) \
- X(sio_start) \
- X(sio_stop) \
- X(sio_write) \
-
-#define MAKE_TYPEDEF(x) static typeof(x) * cubeb_##x;
-LIBSNDIO_API_VISIT(MAKE_TYPEDEF);
-#undef MAKE_TYPEDEF
-#endif
-
static struct cubeb_ops const sndio_ops;
struct cubeb {
struct cubeb_ops const * ops;
- void * libsndio;
};
struct cubeb_stream {
- /* Note: Must match cubeb_stream layout in cubeb.c. */
cubeb * context;
- void * arg; /* user arg to {data,state}_cb */
- /**/
- pthread_t th; /* to run real-time audio i/o */
- pthread_mutex_t mtx; /* protects hdl and pos */
- struct sio_hdl *hdl; /* link us to sndio */
- int mode; /* bitmap of SIO_{PLAY,REC} */
- int active; /* cubec_start() called */
- int conv; /* need float->s16 conversion */
- unsigned char *rbuf; /* rec data consumed from here */
- unsigned char *pbuf; /* play data is prepared here */
- unsigned int nfr; /* number of frames in ibuf and obuf */
- unsigned int rbpf; /* rec bytes per frame */
- unsigned int pbpf; /* play bytes per frame */
- unsigned int rchan; /* number of rec channels */
- unsigned int pchan; /* number of play channels */
- unsigned int nblks; /* number of blocks in the buffer */
- uint64_t hwpos; /* frame number Joe hears right now */
- uint64_t swpos; /* number of frames produced/consumed */
+ pthread_t th; /* to run real-time audio i/o */
+ pthread_mutex_t mtx; /* protects hdl and pos */
+ struct sio_hdl *hdl; /* link us to sndio */
+ int active; /* cubec_start() called */
+ int conv; /* need float->s16 conversion */
+ unsigned char *buf; /* data is prepared here */
+ unsigned int nfr; /* number of frames in buf */
+ unsigned int bpf; /* bytes per frame */
+ unsigned int pchan; /* number of play channels */
+ uint64_t rdpos; /* frame number Joe hears right now */
+ uint64_t wrpos; /* number of written frames */
cubeb_data_callback data_cb; /* cb to preapare data */
cubeb_state_callback state_cb; /* cb to notify about state changes */
- float volume; /* current volume */
+ void *arg; /* user arg to {data,state}_cb */
};
static void
-s16_setvol(void *ptr, long nsamp, float volume)
-{
- int16_t *dst = ptr;
- int32_t mult = volume * 32768;
- int32_t s;
-
- while (nsamp-- > 0) {
- s = *dst;
- s = (s * mult) >> 15;
- *(dst++) = s;
- }
-}
-
-static void
-float_to_s16(void *ptr, long nsamp, float volume)
+float_to_s16(void *ptr, long nsamp)
{
int16_t *dst = ptr;
float *src = ptr;
- float mult = volume * 32768;
int s;
while (nsamp-- > 0) {
- s = lrintf(*(src++) * mult);
+ s = lrintf(*(src++) * 32768);
if (s < -32768)
s = -32768;
else if (s > 32767)
@@ -113,23 +63,11 @@ float_to_s16(void *ptr, long nsamp, float volume)
}
static void
-s16_to_float(void *ptr, long nsamp)
-{
- int16_t *src = ptr;
- float *dst = ptr;
-
- src += nsamp;
- dst += nsamp;
- while (nsamp-- > 0)
- *(--dst) = (1. / 32768) * *(--src);
-}
-
-static void
sndio_onmove(void *arg, int delta)
{
cubeb_stream *s = (cubeb_stream *)arg;
- s->hwpos += delta;
+ s->rdpos += delta * s->bpf;
}
static void *
@@ -138,99 +76,48 @@ sndio_mainloop(void *arg)
#define MAXFDS 8
struct pollfd pfds[MAXFDS];
cubeb_stream *s = arg;
- int n, eof = 0, prime, nfds, events, revents, state = CUBEB_STATE_STARTED;
- size_t pstart = 0, pend = 0, rstart = 0, rend = 0;
+ int n, nfds, revents, state = CUBEB_STATE_STARTED;
+ size_t start = 0, end = 0;
long nfr;
DPR("sndio_mainloop()\n");
s->state_cb(s, s->arg, CUBEB_STATE_STARTED);
pthread_mutex_lock(&s->mtx);
- if (!WRAP(sio_start)(s->hdl)) {
+ if (!sio_start(s->hdl)) {
pthread_mutex_unlock(&s->mtx);
return NULL;
}
DPR("sndio_mainloop(), started\n");
- if (s->mode & SIO_PLAY) {
- pstart = pend = s->nfr * s->pbpf;
- prime = s->nblks;
- if (s->mode & SIO_REC) {
- memset(s->rbuf, 0, s->nfr * s->rbpf);
- rstart = rend = s->nfr * s->rbpf;
- }
- } else {
- prime = 0;
- rstart = 0;
- rend = s->nfr * s->rbpf;
- }
-
+ start = end = s->nfr;
for (;;) {
if (!s->active) {
DPR("sndio_mainloop() stopped\n");
state = CUBEB_STATE_STOPPED;
break;
}
-
- /* do we have a complete block? */
- if ((!(s->mode & SIO_PLAY) || pstart == pend) &&
- (!(s->mode & SIO_REC) || rstart == rend)) {
-
- if (eof) {
+ if (start == end) {
+ if (end < s->nfr) {
DPR("sndio_mainloop() drained\n");
state = CUBEB_STATE_DRAINED;
break;
}
-
- if ((s->mode & SIO_REC) && s->conv)
- s16_to_float(s->rbuf, s->nfr * s->rchan);
-
- /* invoke call-back, it returns less that s->nfr if done */
pthread_mutex_unlock(&s->mtx);
- nfr = s->data_cb(s, s->arg, s->rbuf, s->pbuf, s->nfr);
+ nfr = s->data_cb(s, s->arg, NULL, s->buf, s->nfr);
pthread_mutex_lock(&s->mtx);
if (nfr < 0) {
DPR("sndio_mainloop() cb err\n");
state = CUBEB_STATE_ERROR;
break;
}
- s->swpos += nfr;
-
- /* was this last call-back invocation (aka end-of-stream) ? */
- if (nfr < s->nfr) {
-
- if (!(s->mode & SIO_PLAY) || nfr == 0) {
- state = CUBEB_STATE_DRAINED;
- break;
- }
-
- /* need to write (aka drain) the partial play block we got */
- pend = nfr * s->pbpf;
- eof = 1;
- }
-
- if (prime > 0)
- prime--;
-
- if (s->mode & SIO_PLAY) {
- if (s->conv)
- float_to_s16(s->pbuf, nfr * s->pchan, s->volume);
- else
- s16_setvol(s->pbuf, nfr * s->pchan, s->volume);
- }
-
- if (s->mode & SIO_REC)
- rstart = 0;
- if (s->mode & SIO_PLAY)
- pstart = 0;
+ if (s->conv)
+ float_to_s16(s->buf, nfr * s->pchan);
+ start = 0;
+ end = nfr * s->bpf;
}
-
- events = 0;
- if ((s->mode & SIO_REC) && rstart < rend && prime == 0)
- events |= POLLIN;
- if ((s->mode & SIO_PLAY) && pstart < pend)
- events |= POLLOUT;
- nfds = WRAP(sio_pollfd)(s->hdl, pfds, events);
-
+ if (end == 0)
+ continue;
+ nfds = sio_pollfd(s->hdl, pfds, POLLOUT);
if (nfds > 0) {
pthread_mutex_unlock(&s->mtx);
n = poll(pfds, nfds, -1);
@@ -238,40 +125,22 @@ sndio_mainloop(void *arg)
if (n < 0)
continue;
}
-
- revents = WRAP(sio_revents)(s->hdl, pfds);
-
- if (revents & POLLHUP) {
- state = CUBEB_STATE_ERROR;
+ revents = sio_revents(s->hdl, pfds);
+ if (revents & POLLHUP)
break;
- }
-
if (revents & POLLOUT) {
- n = WRAP(sio_write)(s->hdl, s->pbuf + pstart, pend - pstart);
- if (n == 0 && WRAP(sio_eof)(s->hdl)) {
+ n = sio_write(s->hdl, s->buf + start, end - start);
+ if (n == 0) {
DPR("sndio_mainloop() werr\n");
state = CUBEB_STATE_ERROR;
break;
}
- pstart += n;
+ s->wrpos += n;
+ start += n;
}
-
- if (revents & POLLIN) {
- n = WRAP(sio_read)(s->hdl, s->rbuf + rstart, rend - rstart);
- if (n == 0 && WRAP(sio_eof)(s->hdl)) {
- DPR("sndio_mainloop() rerr\n");
- state = CUBEB_STATE_ERROR;
- break;
- }
- rstart += n;
- }
-
- /* skip rec block, if not recording (yet) */
- if (prime > 0 && (s->mode & SIO_REC))
- rstart = rend;
}
- WRAP(sio_stop)(s->hdl);
- s->hwpos = s->swpos;
+ sio_stop(s->hdl);
+ s->rdpos = s->wrpos;
pthread_mutex_unlock(&s->mtx);
s->state_cb(s, s->arg, state);
return NULL;
@@ -280,34 +149,8 @@ sndio_mainloop(void *arg)
/*static*/ int
sndio_init(cubeb **context, char const *context_name)
{
- void * libsndio = NULL;
-
-#ifndef DISABLE_LIBSNDIO_DLOPEN
- libsndio = dlopen("libsndio.so.7.0", RTLD_LAZY);
- if (!libsndio) {
- libsndio = dlopen("libsndio.so", RTLD_LAZY);
- if (!libsndio) {
- DPR("sndio_init(%s) failed dlopen(libsndio.so)\n", context_name);
- return CUBEB_ERROR;
- }
- }
-
-#define LOAD(x) { \
- cubeb_##x = dlsym(libsndio, #x); \
- if (!cubeb_##x) { \
- DPR("sndio_init(%s) failed dlsym(%s)\n", context_name, #x); \
- dlclose(libsndio); \
- return CUBEB_ERROR; \
- } \
- }
-
- LIBSNDIO_API_VISIT(LOAD);
-#undef LOAD
-#endif
-
DPR("sndio_init(%s)\n", context_name);
*context = malloc(sizeof(*context));
- (*context)->libsndio = libsndio;
(*context)->ops = &sndio_ops;
(void)context_name;
return CUBEB_OK;
@@ -323,8 +166,6 @@ static void
sndio_destroy(cubeb *context)
{
DPR("sndio_destroy()\n");
- if (context->libsndio)
- dlclose(context->libsndio);
free(context);
}
@@ -343,49 +184,29 @@ sndio_stream_init(cubeb * context,
{
cubeb_stream *s;
struct sio_par wpar, rpar;
- cubeb_sample_format format;
- int rate;
- size_t bps;
-
DPR("sndio_stream_init(%s)\n", stream_name);
+ size_t size;
+
+ assert(!input_stream_params && "not supported.");
+ if (input_device || output_device) {
+ /* Device selection not yet implemented. */
+ return CUBEB_ERROR_DEVICE_UNAVAILABLE;
+ }
s = malloc(sizeof(cubeb_stream));
if (s == NULL)
return CUBEB_ERROR;
- memset(s, 0, sizeof(cubeb_stream));
- s->mode = 0;
- if (input_stream_params) {
- if (input_stream_params->prefs & CUBEB_STREAM_PREF_LOOPBACK) {
- DPR("sndio_stream_init(), loopback not supported\n");
- goto err;
- }
- s->mode |= SIO_REC;
- format = input_stream_params->format;
- rate = input_stream_params->rate;
- }
- if (output_stream_params) {
- if (output_stream_params->prefs & CUBEB_STREAM_PREF_LOOPBACK) {
- DPR("sndio_stream_init(), loopback not supported\n");
- goto err;
- }
- s->mode |= SIO_PLAY;
- format = output_stream_params->format;
- rate = output_stream_params->rate;
- }
- if (s->mode == 0) {
- DPR("sndio_stream_init(), neither playing nor recording\n");
- goto err;
- }
s->context = context;
- s->hdl = WRAP(sio_open)(NULL, s->mode, 1);
+ s->hdl = sio_open(NULL, SIO_PLAY, 1);
if (s->hdl == NULL) {
+ free(s);
DPR("sndio_stream_init(), sio_open() failed\n");
- goto err;
+ return CUBEB_ERROR;
}
- WRAP(sio_initpar)(&wpar);
+ sio_initpar(&wpar);
wpar.sig = 1;
wpar.bits = 16;
- switch (format) {
+ switch (output_stream_params->format) {
case CUBEB_SAMPLE_S16LE:
wpar.le = 1;
break;
@@ -397,70 +218,53 @@ sndio_stream_init(cubeb * context,
break;
default:
DPR("sndio_stream_init() unsupported format\n");
- goto err;
+ return CUBEB_ERROR_INVALID_FORMAT;
}
- wpar.rate = rate;
- if (s->mode & SIO_REC)
- wpar.rchan = input_stream_params->channels;
- if (s->mode & SIO_PLAY)
- wpar.pchan = output_stream_params->channels;
+ wpar.rate = output_stream_params->rate;
+ wpar.pchan = output_stream_params->channels;
wpar.appbufsz = latency_frames;
- if (!WRAP(sio_setpar)(s->hdl, &wpar) || !WRAP(sio_getpar)(s->hdl, &rpar)) {
+ if (!sio_setpar(s->hdl, &wpar) || !sio_getpar(s->hdl, &rpar)) {
+ sio_close(s->hdl);
+ free(s);
DPR("sndio_stream_init(), sio_setpar() failed\n");
- goto err;
+ return CUBEB_ERROR;
}
if (rpar.bits != wpar.bits || rpar.le != wpar.le ||
rpar.sig != wpar.sig || rpar.rate != wpar.rate ||
- ((s->mode & SIO_REC) && rpar.rchan != wpar.rchan) ||
- ((s->mode & SIO_PLAY) && rpar.pchan != wpar.pchan)) {
+ rpar.pchan != wpar.pchan) {
+ sio_close(s->hdl);
+ free(s);
DPR("sndio_stream_init() unsupported params\n");
- goto err;
+ return CUBEB_ERROR_INVALID_FORMAT;
}
- WRAP(sio_onmove)(s->hdl, sndio_onmove, s);
+ sio_onmove(s->hdl, sndio_onmove, s);
s->active = 0;
s->nfr = rpar.round;
- s->rbpf = rpar.bps * rpar.rchan;
- s->pbpf = rpar.bps * rpar.pchan;
- s->rchan = rpar.rchan;
+ s->bpf = rpar.bps * rpar.pchan;
s->pchan = rpar.pchan;
- s->nblks = rpar.bufsz / rpar.round;
s->data_cb = data_callback;
s->state_cb = state_callback;
s->arg = user_ptr;
- s->mtx = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
- s->hwpos = s->swpos = 0;
- if (format == CUBEB_SAMPLE_FLOAT32LE) {
+ s->mtx = PTHREAD_MUTEX_INITIALIZER;
+ s->rdpos = s->wrpos = 0;
+ if (output_stream_params->format == CUBEB_SAMPLE_FLOAT32LE) {
s->conv = 1;
- bps = sizeof(float);
+ size = rpar.round * rpar.pchan * sizeof(float);
} else {
s->conv = 0;
- bps = rpar.bps;
- }
- if (s->mode & SIO_PLAY) {
- s->pbuf = malloc(bps * rpar.pchan * rpar.round);
- if (s->pbuf == NULL)
- goto err;
+ size = rpar.round * rpar.pchan * rpar.bps;
}
- if (s->mode & SIO_REC) {
- s->rbuf = malloc(bps * rpar.rchan * rpar.round);
- if (s->rbuf == NULL)
- goto err;
+ s->buf = malloc(size);
+ if (s->buf == NULL) {
+ sio_close(s->hdl);
+ free(s);
+ return CUBEB_ERROR;
}
- s->volume = 1.;
*stream = s;
DPR("sndio_stream_init() end, ok\n");
(void)context;
(void)stream_name;
return CUBEB_OK;
-err:
- if (s->hdl)
- WRAP(sio_close)(s->hdl);
- if (s->pbuf)
- free(s->pbuf);
- if (s->rbuf)
- free(s->pbuf);
- free(s);
- return CUBEB_ERROR;
}
static int
@@ -476,21 +280,16 @@ sndio_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
static int
sndio_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
{
- /*
- * We've no device-independent prefered rate; any rate will work if
- * sndiod is running. If it isn't, 48kHz is what is most likely to
- * work as most (but not all) devices support it.
- */
- *rate = 48000;
+ // XXX Not yet implemented.
+ *rate = 44100;
+
return CUBEB_OK;
}
static int
sndio_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames)
{
- /*
- * We've no device-independent minimum latency.
- */
+ // XXX Not yet implemented.
*latency_frames = 2048;
return CUBEB_OK;
@@ -500,11 +299,7 @@ static void
sndio_stream_destroy(cubeb_stream *s)
{
DPR("sndio_stream_destroy()\n");
- WRAP(sio_close)(s->hdl);
- if (s->mode & SIO_PLAY)
- free(s->pbuf);
- if (s->mode & SIO_REC)
- free(s->rbuf);
+ sio_close(s->hdl);
free(s);
}
@@ -540,8 +335,8 @@ static int
sndio_stream_get_position(cubeb_stream *s, uint64_t *p)
{
pthread_mutex_lock(&s->mtx);
- DPR("sndio_stream_get_position() %" PRId64 "\n", s->hwpos);
- *p = s->hwpos;
+ DPR("sndio_stream_get_position() %lld\n", s->rdpos);
+ *p = s->rdpos / s->bpf;
pthread_mutex_unlock(&s->mtx);
return CUBEB_OK;
}
@@ -551,11 +346,7 @@ sndio_stream_set_volume(cubeb_stream *s, float volume)
{
DPR("sndio_stream_set_volume(%f)\n", volume);
pthread_mutex_lock(&s->mtx);
- if (volume < 0.)
- volume = 0.;
- else if (volume > 1.0)
- volume = 1.;
- s->volume = volume;
+ sio_setvol(s->hdl, SIO_MAXVOL * volume);
pthread_mutex_unlock(&s->mtx);
return CUBEB_OK;
}
@@ -565,47 +356,7 @@ sndio_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
{
// http://www.openbsd.org/cgi-bin/man.cgi?query=sio_open
// in the "Measuring the latency and buffers usage" paragraph.
- *latency = stm->swpos - stm->hwpos;
- return CUBEB_OK;
-}
-
-static int
-sndio_enumerate_devices(cubeb *context, cubeb_device_type type,
- cubeb_device_collection *collection)
-{
- static char dev[] = SIO_DEVANY;
- cubeb_device_info *device;
-
- device = malloc(sizeof(cubeb_device_info));
- if (device == NULL)
- return CUBEB_ERROR;
-
- device->devid = dev; /* passed to stream_init() */
- device->device_id = dev; /* printable in UI */
- device->friendly_name = dev; /* same, but friendly */
- device->group_id = dev; /* actual device if full-duplex */
- device->vendor_name = NULL; /* may be NULL */
- device->type = type; /* Input/Output */
- device->state = CUBEB_DEVICE_STATE_ENABLED;
- device->preferred = CUBEB_DEVICE_PREF_ALL;
- device->format = CUBEB_DEVICE_FMT_S16NE;
- device->default_format = CUBEB_DEVICE_FMT_S16NE;
- device->max_channels = 16;
- device->default_rate = 48000;
- device->min_rate = 4000;
- device->max_rate = 192000;
- device->latency_lo = 480;
- device->latency_hi = 9600;
- collection->device = device;
- collection->count = 1;
- return CUBEB_OK;
-}
-
-static int
-sndio_device_collection_destroy(cubeb * context,
- cubeb_device_collection * collection)
-{
- free(collection->device);
+ *latency = (stm->wrpos - stm->rdpos) / stm->bpf;
return CUBEB_OK;
}
@@ -615,17 +366,16 @@ static struct cubeb_ops const sndio_ops = {
.get_max_channel_count = sndio_get_max_channel_count,
.get_min_latency = sndio_get_min_latency,
.get_preferred_sample_rate = sndio_get_preferred_sample_rate,
- .enumerate_devices = sndio_enumerate_devices,
- .device_collection_destroy = sndio_device_collection_destroy,
+ .enumerate_devices = NULL,
.destroy = sndio_destroy,
.stream_init = sndio_stream_init,
.stream_destroy = sndio_stream_destroy,
.stream_start = sndio_stream_start,
.stream_stop = sndio_stream_stop,
- .stream_reset_default_device = NULL,
.stream_get_position = sndio_stream_get_position,
.stream_get_latency = sndio_stream_get_latency,
.stream_set_volume = sndio_stream_set_volume,
+ .stream_set_panning = NULL,
.stream_get_current_device = NULL,
.stream_device_destroy = NULL,
.stream_register_device_changed_callback = NULL,