Bug 1221580 - Update libcubeb to revision 7d00ea6705. r=kinetik,achronop

MozReview-Commit-ID: 8q8Va6I2hru

--HG--
extra : rebase_source : bbc96137fdd4469d57fe99f41ad1baa97e05d468
This commit is contained in:
Paul Adenot 2017-11-10 12:31:24 +01:00
Родитель 611b41a2e4
Коммит 8ad630e34b
2 изменённых файлов: 236 добавлений и 71 удалений

Просмотреть файл

@ -25,8 +25,15 @@ typedef enum {
* Create a resampler to adapt the requested sample rate into something that
* is accepted by the audio backend.
* @param stream A cubeb_stream instance supplied to the data callback.
* @param params Used to calculate bytes per frame and buffer size for resampling.
* @param target_rate The sampling rate after resampling.
* @param input_params Used to calculate bytes per frame and buffer size for
* resampling of the input side of the stream. NULL if input should not be
* resampled.
* @param output_params Used to calculate bytes per frame and buffer size for
* resampling of the output side of the stream. NULL if output should not be
* resampled.
* @param target_rate The sampling rate after resampling for the input side of
* the stream, and/or the sampling rate prior to resampling of the output side
* of the stream.
* @param callback A callback to request data for resampling.
* @param user_ptr User data supplied to the data callback.
* @param quality Quality of the resampler.
@ -47,8 +54,8 @@ cubeb_resampler * cubeb_resampler_create(cubeb_stream * stream,
* @param input_buffer A buffer of input samples
* @param input_frame_count The size of the buffer. Returns the number of frames
* consumed.
* @param buffer The buffer to be filled.
* @param frames_needed Number of frames that should be produced.
* @param output_buffer The buffer to be filled.
* @param output_frames_needed Number of frames that should be produced.
* @retval Number of frames that are actually produced.
* @retval CUBEB_ERROR on error.
*/

Просмотреть файл

@ -4,6 +4,7 @@
* 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>
@ -32,14 +33,19 @@ struct cubeb_stream {
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 *buf; /* data is prepared here */
unsigned int nfr; /* number of frames in buf */
unsigned int bpf; /* bytes per frame */
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 */
uint64_t rdpos; /* frame number Joe hears right now */
uint64_t wrpos; /* number of written frames */
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 */
cubeb_data_callback data_cb; /* cb to preapare data */
cubeb_state_callback state_cb; /* cb to notify about state changes */
void *arg; /* user arg to {data,state}_cb */
@ -62,12 +68,24 @@ float_to_s16(void *ptr, long nsamp)
}
}
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->rdpos += delta * s->bpf;
s->hwpos += delta;
}
static void *
@ -76,8 +94,8 @@ sndio_mainloop(void *arg)
#define MAXFDS 8
struct pollfd pfds[MAXFDS];
cubeb_stream *s = arg;
int n, nfds, revents, state = CUBEB_STATE_STARTED;
size_t start = 0, end = 0;
int n, eof = 0, prime, nfds, events, revents, state = CUBEB_STATE_STARTED;
size_t pstart = 0, pend = 0, rstart = 0, rend = 0;
long nfr;
DPR("sndio_mainloop()\n");
@ -89,35 +107,82 @@ sndio_mainloop(void *arg)
}
DPR("sndio_mainloop(), started\n");
start = end = s->nfr;
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;
}
for (;;) {
if (!s->active) {
DPR("sndio_mainloop() stopped\n");
state = CUBEB_STATE_STOPPED;
break;
}
if (start == end) {
if (end < s->nfr) {
/* do we have a complete block? */
if ((!(s->mode & SIO_PLAY) || pstart == pend) &&
(!(s->mode & SIO_REC) || rstart == rend)) {
if (eof) {
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, NULL, s->buf, s->nfr);
nfr = s->data_cb(s, s->arg, s->rbuf, s->pbuf, s->nfr);
pthread_mutex_lock(&s->mtx);
if (nfr < 0) {
DPR("sndio_mainloop() cb err\n");
state = CUBEB_STATE_ERROR;
break;
}
if (s->conv)
float_to_s16(s->buf, nfr * s->pchan);
start = 0;
end = nfr * s->bpf;
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) && s->conv)
float_to_s16(s->pbuf, nfr * s->pchan);
if (s->mode & SIO_REC)
rstart = 0;
if (s->mode & SIO_PLAY)
pstart = 0;
}
if (end == 0)
continue;
nfds = sio_pollfd(s->hdl, pfds, POLLOUT);
events = 0;
if ((s->mode & SIO_REC) && rstart < rend && prime == 0)
events |= POLLIN;
if ((s->mode & SIO_PLAY) && pstart < pend)
events |= POLLOUT;
nfds = sio_pollfd(s->hdl, pfds, events);
if (nfds > 0) {
pthread_mutex_unlock(&s->mtx);
n = poll(pfds, nfds, -1);
@ -125,22 +190,40 @@ sndio_mainloop(void *arg)
if (n < 0)
continue;
}
revents = sio_revents(s->hdl, pfds);
if (revents & POLLHUP)
if (revents & POLLHUP) {
state = CUBEB_STATE_ERROR;
break;
}
if (revents & POLLOUT) {
n = sio_write(s->hdl, s->buf + start, end - start);
if (n == 0) {
n = sio_write(s->hdl, s->pbuf + pstart, pend - pstart);
if (n == 0 && sio_eof(s->hdl)) {
DPR("sndio_mainloop() werr\n");
state = CUBEB_STATE_ERROR;
break;
}
s->wrpos += n;
start += n;
pstart += n;
}
if (revents & POLLIN) {
n = sio_read(s->hdl, s->rbuf + rstart, rend - rstart);
if (n == 0 && 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;
}
sio_stop(s->hdl);
s->rdpos = s->wrpos;
s->hwpos = s->swpos;
pthread_mutex_unlock(&s->mtx);
s->state_cb(s, s->arg, state);
return NULL;
@ -184,29 +267,41 @@ sndio_stream_init(cubeb * context,
{
cubeb_stream *s;
struct sio_par wpar, rpar;
DPR("sndio_stream_init(%s)\n", stream_name);
size_t size;
cubeb_sample_format format;
int rate;
size_t bps;
assert(!input_stream_params && "not supported.");
if (input_device || output_device) {
/* Device selection not yet implemented. */
return CUBEB_ERROR_DEVICE_UNAVAILABLE;
}
DPR("sndio_stream_init(%s)\n", stream_name);
s = malloc(sizeof(cubeb_stream));
if (s == NULL)
return CUBEB_ERROR;
memset(s, 0, sizeof(cubeb_stream));
s->mode = 0;
if (input_stream_params) {
s->mode |= SIO_REC;
format = input_stream_params->format;
rate = input_stream_params->rate;
}
if (output_stream_params) {
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 = sio_open(NULL, SIO_PLAY, 1);
s->hdl = sio_open(NULL, s->mode, 1);
if (s->hdl == NULL) {
free(s);
DPR("sndio_stream_init(), sio_open() failed\n");
return CUBEB_ERROR;
goto err;
}
sio_initpar(&wpar);
wpar.sig = 1;
wpar.bits = 16;
switch (output_stream_params->format) {
switch (format) {
case CUBEB_SAMPLE_S16LE:
wpar.le = 1;
break;
@ -217,56 +312,70 @@ sndio_stream_init(cubeb * context,
wpar.le = SIO_LE_NATIVE;
break;
default:
sio_close(s->hdl);
free(s);
DPR("sndio_stream_init() unsupported format\n");
return CUBEB_ERROR_INVALID_FORMAT;
goto err;
}
wpar.rate = output_stream_params->rate;
wpar.pchan = output_stream_params->channels;
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.appbufsz = latency_frames;
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");
return CUBEB_ERROR;
goto err;
}
if (rpar.bits != wpar.bits || rpar.le != wpar.le ||
rpar.sig != wpar.sig || rpar.rate != wpar.rate ||
rpar.pchan != wpar.pchan) {
sio_close(s->hdl);
free(s);
((s->mode & SIO_REC) && rpar.rchan != wpar.rchan) ||
((s->mode & SIO_PLAY) && rpar.pchan != wpar.pchan)) {
DPR("sndio_stream_init() unsupported params\n");
return CUBEB_ERROR_INVALID_FORMAT;
goto err;
}
sio_onmove(s->hdl, sndio_onmove, s);
s->active = 0;
s->nfr = rpar.round;
s->bpf = rpar.bps * rpar.pchan;
s->rbpf = rpar.bps * rpar.rchan;
s->pbpf = rpar.bps * rpar.pchan;
s->rchan = rpar.rchan;
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->rdpos = s->wrpos = 0;
if (output_stream_params->format == CUBEB_SAMPLE_FLOAT32LE) {
s->hwpos = s->swpos = 0;
if (format == CUBEB_SAMPLE_FLOAT32LE) {
s->conv = 1;
size = rpar.round * rpar.pchan * sizeof(float);
bps = sizeof(float);
} else {
s->conv = 0;
size = rpar.round * rpar.pchan * rpar.bps;
bps = rpar.bps;
}
s->buf = malloc(size);
if (s->buf == NULL) {
sio_close(s->hdl);
free(s);
return CUBEB_ERROR;
if (s->mode & SIO_PLAY) {
s->pbuf = malloc(bps * rpar.pchan * rpar.round);
if (s->pbuf == NULL)
goto err;
}
if (s->mode & SIO_REC) {
s->rbuf = malloc(bps * rpar.rchan * rpar.round);
if (s->rbuf == NULL)
goto err;
}
*stream = s;
DPR("sndio_stream_init() end, ok\n");
(void)context;
(void)stream_name;
return CUBEB_OK;
err:
if (s->hdl)
sio_close(s->hdl);
if (s->pbuf)
free(s->pbuf);
if (s->rbuf)
free(s->pbuf);
free(s);
return CUBEB_ERROR;
}
static int
@ -282,16 +391,21 @@ sndio_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
static int
sndio_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
{
// XXX Not yet implemented.
*rate = 44100;
/*
* 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;
return CUBEB_OK;
}
static int
sndio_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames)
{
// XXX Not yet implemented.
/*
* We've no device-independent minimum latency.
*/
*latency_frames = 2048;
return CUBEB_OK;
@ -302,6 +416,10 @@ sndio_stream_destroy(cubeb_stream *s)
{
DPR("sndio_stream_destroy()\n");
sio_close(s->hdl);
if (s->mode & SIO_PLAY)
free(s->pbuf);
if (s->mode & SIO_REC)
free(s->rbuf);
free(s);
}
@ -337,8 +455,8 @@ static int
sndio_stream_get_position(cubeb_stream *s, uint64_t *p)
{
pthread_mutex_lock(&s->mtx);
DPR("sndio_stream_get_position() %lld\n", s->rdpos);
*p = s->rdpos / s->bpf;
DPR("sndio_stream_get_position() %" PRId64 "\n", s->hwpos);
*p = s->hwpos;
pthread_mutex_unlock(&s->mtx);
return CUBEB_OK;
}
@ -358,7 +476,47 @@ 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->wrpos - stm->rdpos) / stm->bpf;
*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);
return CUBEB_OK;
}
@ -369,8 +527,8 @@ static struct cubeb_ops const sndio_ops = {
.get_min_latency = sndio_get_min_latency,
.get_preferred_sample_rate = sndio_get_preferred_sample_rate,
.get_preferred_channel_layout = NULL,
.enumerate_devices = NULL,
.device_collection_destroy = NULL,
.enumerate_devices = sndio_enumerate_devices,
.device_collection_destroy = sndio_device_collection_destroy,
.destroy = sndio_destroy,
.stream_init = sndio_stream_init,
.stream_destroy = sndio_stream_destroy,