ALSA implement clear buffer

This commit is contained in:
Andrew Kelley 2015-07-24 14:03:49 -07:00
parent ab8a2c2ffe
commit 5906bc93d9
6 changed files with 42 additions and 35 deletions

View file

@ -242,6 +242,9 @@ view `coverage/index.html` in a browser.
0. Figure out a way to test prebuf. I suspect prebuf not working for ALSA
which is why we have to pre-fill the ring buffer with silence for
the microphone example.
0. In ALSA do we need to wake up the poll when destroying the in or out stream?
0. Create a test for clearing the playback buffer.
0. Create a test for pausing and resuming input and output streams.
0. implement ASIO (Windows) backend, get examples working
0. clean up API and improve documentation
- make sure every function which can return an error documents which errors

View file

@ -909,7 +909,6 @@ static void outstream_destroy_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *
if (osa->thread) {
osa->thread_exit_flag.clear();
// TODO wake up poll
soundio_os_thread_destroy(osa->thread);
}
@ -1007,8 +1006,6 @@ void outstream_thread_run(void *arg) {
for (;;) {
snd_pcm_state_t state = snd_pcm_state(osa->handle);
switch (state) {
case SND_PCM_STATE_OPEN:
soundio_panic("TODO open");
case SND_PCM_STATE_SETUP:
if ((err = snd_pcm_prepare(osa->handle)) < 0) {
outstream->error_callback(outstream, SoundIoErrorStreaming);
@ -1050,18 +1047,18 @@ void outstream_thread_run(void *arg) {
return;
}
continue;
case SND_PCM_STATE_DRAINING:
soundio_panic("TODO draining");
case SND_PCM_STATE_PAUSED:
soundio_panic("TODO paused");
case SND_PCM_STATE_SUSPENDED:
if ((err = xrun_recovery(os, -ESTRPIPE)) < 0) {
outstream->error_callback(outstream, SoundIoErrorStreaming);
return;
}
continue;
case SND_PCM_STATE_OPEN:
case SND_PCM_STATE_DRAINING:
case SND_PCM_STATE_PAUSED:
case SND_PCM_STATE_DISCONNECTED:
soundio_panic("TODO disconnected");
outstream->error_callback(outstream, SoundIoErrorStreaming);
return;
}
}
}
@ -1076,8 +1073,6 @@ static void instream_thread_run(void *arg) {
for (;;) {
snd_pcm_state_t state = snd_pcm_state(osa->handle);
switch (state) {
case SND_PCM_STATE_OPEN:
soundio_panic("TODO open");
case SND_PCM_STATE_SETUP:
if ((err = snd_pcm_prepare(osa->handle)) < 0) {
instream->error_callback(instream, SoundIoErrorStreaming);
@ -1119,18 +1114,18 @@ static void instream_thread_run(void *arg) {
return;
}
continue;
case SND_PCM_STATE_DRAINING:
soundio_panic("TODO draining");
case SND_PCM_STATE_PAUSED:
soundio_panic("TODO paused");
case SND_PCM_STATE_SUSPENDED:
if ((err = instream_xrun_recovery(is, -ESTRPIPE)) < 0) {
instream->error_callback(instream, SoundIoErrorStreaming);
return;
}
continue;
case SND_PCM_STATE_OPEN:
case SND_PCM_STATE_DRAINING:
case SND_PCM_STATE_PAUSED:
case SND_PCM_STATE_DISCONNECTED:
soundio_panic("TODO disconnected");
instream->error_callback(instream, SoundIoErrorStreaming);
return;
}
}
}
@ -1395,10 +1390,14 @@ static int outstream_end_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate
return 0;
}
static void outstream_clear_buffer_alsa(SoundIoPrivate *si,
static int outstream_clear_buffer_alsa(SoundIoPrivate *si,
SoundIoOutStreamPrivate *os)
{
soundio_panic("TODO");
SoundIoOutStreamAlsa *osa = (SoundIoOutStreamAlsa *) os->backend_data;
int err;
if ((err = snd_pcm_reset(osa->handle)) < 0)
return SoundIoErrorStreaming;
return 0;
}
static int outstream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
@ -1416,7 +1415,6 @@ static void instream_destroy_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is
if (isa->thread) {
isa->thread_exit_flag.clear();
// TODO wake up poll
soundio_os_thread_destroy(isa->thread);
}

View file

@ -290,9 +290,11 @@ static int outstream_end_write_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate
return 0;
}
static void outstream_clear_buffer_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
static int outstream_clear_buffer_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
SoundIoOutStreamDummy *osd = (SoundIoOutStreamDummy *)os->backend_data;
soundio_ring_buffer_clear(&osd->ring_buffer);
osd->prebuf_frames_left = osd->prebuf_frame_count;
return 0;
}
static void instream_destroy_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {

View file

@ -782,7 +782,7 @@ static int outstream_end_write_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *o
return 0;
}
static void outstream_clear_buffer_pa(SoundIoPrivate *si,
static int outstream_clear_buffer_pa(SoundIoPrivate *si,
SoundIoOutStreamPrivate *os)
{
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
@ -791,9 +791,10 @@ static void outstream_clear_buffer_pa(SoundIoPrivate *si,
pa_threaded_mainloop_lock(sipa->main_loop);
pa_operation *op = pa_stream_flush(stream, NULL, NULL);
if (!op)
soundio_panic("pa_stream_flush failed: %s", pa_strerror(pa_context_errno(sipa->pulse_context)));
return SoundIoErrorStreaming;
pa_operation_unref(op);
pa_threaded_mainloop_unlock(sipa->main_loop);
return 0;
}
static int outstream_pause_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, bool pause) {

View file

@ -340,14 +340,14 @@ struct SoundIoOutStream {
// This optional callback happens when the sound device runs out of buffered
// audio data to play. After this occurs, the outstream waits until the
// buffer is full to resume playback.
// This callback is called in the same thread context as `write_callback`.
// This is called from the `write_callback` thread context.
void (*underflow_callback)(struct SoundIoOutStream *);
// Optional callback. `err` is always SoundIoErrorStreaming.
// SoundIoErrorStreaming is an unrecoverable error. The stream is in an
// invalid state and must be destroyed.
// If you do not supply `error_callback`, the default callback will print
// a message to stderr and then call `abort`.
// This callback is called in the same thread context as `write_callback`.
// This is called fram the `write_callback` thread context.
void (*error_callback)(struct SoundIoOutStream *, int err);
// Name of the stream. This is used by PulseAudio. Defaults to "SoundIo".
@ -398,7 +398,7 @@ struct SoundIoInStream {
// invalid state and must be destroyed.
// If you do not supply `error_callback`, the default callback will print
// a message to stderr and then abort().
// This is called from the same thread context as `read_callback`.
// This is called from the `read_callback` thread context.
void (*error_callback)(struct SoundIoInStream *, int err);
// Name of the stream. This is used by PulseAudio. Defaults to "SoundIo".
@ -555,7 +555,7 @@ struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device);
int soundio_outstream_open(struct SoundIoOutStream *outstream);
// You may not call this function from `write_callback`.
// You may not call this function from the `write_callback` thread context.
void soundio_outstream_destroy(struct SoundIoOutStream *outstream);
int soundio_outstream_start(struct SoundIoOutStream *outstream);
@ -569,21 +569,23 @@ int soundio_outstream_start(struct SoundIoOutStream *outstream);
// It is your responsibility to call this function no more and no fewer than the
// correct number of times as determined by `requested_frame_count` from
// `write_callback`. See sine.c for an example.
// You must call this function only from `write_callback`. After calling this
// function, write data to `areas` and then call `soundio_outstream_end_write`.
// You must call this function only from the `write_callback` thread context.
// After calling this function, write data to `areas` and then call `soundio_outstream_end_write`.
int soundio_outstream_begin_write(struct SoundIoOutStream *outstream,
struct SoundIoChannelArea **areas, int *frame_count);
// Commits the write that you began with `soundio_outstream_begin_write`.
// You must call this function only from `write_callback`.
// You must call this function only from the `write_callback` thread context.
int soundio_outstream_end_write(struct SoundIoOutStream *outstream, int frame_count);
void soundio_outstream_clear_buffer(struct SoundIoOutStream *outstream);
// Clears the output stream buffer and the stream goes into prebuffering mode.
// You must call this function only from the `write_callback` thread context.
int soundio_outstream_clear_buffer(struct SoundIoOutStream *outstream);
// If the underyling device supports pausing, this pauses the stream and
// prevents `write_callback` from being called. Otherwise this returns
// `SoundIoErrorIncompatibleDevice`.
// You must call this function only from `write_callback`.
// You must call this function only from the `write_callback` thread context.
int soundio_outstream_pause(struct SoundIoOutStream *outstream, bool pause);
@ -613,7 +615,7 @@ int soundio_instream_start(struct SoundIoInStream *instream);
// It is your responsibility to call this function no more and no fewer than the
// correct number of times as determined by `available_frame_count` from
// `read_callback`. See microphone.c for an example.
// You must call this function only from `read_callback`.
// You must call this function only from the `read_callback` thread context.
// After calling this function, read data from `areas` and then use
// `soundio_instream_end_read` to actually remove the data from the buffer
// and move the read index forward. `soundio_instream_end_read` should not be
@ -623,14 +625,15 @@ int soundio_instream_begin_read(struct SoundIoInStream *instream,
struct SoundIoChannelArea **areas, int *frame_count);
// This will drop all of the frames from when you called
// `soundio_instream_begin_read`.
// You must call this function only from `read_callback` after a successful
// call to `soundio_instream_begin_read`.
// You must call this function only from the `read_callback` thread context.
// You must call this function only after a successful call to
// `soundio_instream_begin_read`.
int soundio_instream_end_read(struct SoundIoInStream *instream);
// If the underyling device supports pausing, this pauses the stream and
// prevents `read_callback` from being called. Otherwise this returns
// `SoundIoErrorIncompatibleDevice`.
// You must call this function only from `read_callback`.
// You must call this function only from the `read_callback` thread context.
int soundio_instream_pause(struct SoundIoInStream *instream, bool pause);

View file

@ -49,7 +49,7 @@ struct SoundIoPrivate {
int (*outstream_begin_write)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *,
SoundIoChannelArea **out_areas, int *frame_count);
int (*outstream_end_write)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, int frame_count);
void (*outstream_clear_buffer)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
int (*outstream_clear_buffer)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
int (*outstream_pause)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, bool pause);