mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2024-12-23 02:45:29 +00:00
ALSA implement clear buffer
This commit is contained in:
parent
ab8a2c2ffe
commit
5906bc93d9
|
@ -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
|
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
|
which is why we have to pre-fill the ring buffer with silence for
|
||||||
the microphone example.
|
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. implement ASIO (Windows) backend, get examples working
|
||||||
0. clean up API and improve documentation
|
0. clean up API and improve documentation
|
||||||
- make sure every function which can return an error documents which errors
|
- make sure every function which can return an error documents which errors
|
||||||
|
|
34
src/alsa.cpp
34
src/alsa.cpp
|
@ -909,7 +909,6 @@ static void outstream_destroy_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *
|
||||||
|
|
||||||
if (osa->thread) {
|
if (osa->thread) {
|
||||||
osa->thread_exit_flag.clear();
|
osa->thread_exit_flag.clear();
|
||||||
// TODO wake up poll
|
|
||||||
soundio_os_thread_destroy(osa->thread);
|
soundio_os_thread_destroy(osa->thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1007,8 +1006,6 @@ void outstream_thread_run(void *arg) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
snd_pcm_state_t state = snd_pcm_state(osa->handle);
|
snd_pcm_state_t state = snd_pcm_state(osa->handle);
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case SND_PCM_STATE_OPEN:
|
|
||||||
soundio_panic("TODO open");
|
|
||||||
case SND_PCM_STATE_SETUP:
|
case SND_PCM_STATE_SETUP:
|
||||||
if ((err = snd_pcm_prepare(osa->handle)) < 0) {
|
if ((err = snd_pcm_prepare(osa->handle)) < 0) {
|
||||||
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||||
|
@ -1050,18 +1047,18 @@ void outstream_thread_run(void *arg) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
case SND_PCM_STATE_DRAINING:
|
|
||||||
soundio_panic("TODO draining");
|
|
||||||
case SND_PCM_STATE_PAUSED:
|
|
||||||
soundio_panic("TODO paused");
|
|
||||||
case SND_PCM_STATE_SUSPENDED:
|
case SND_PCM_STATE_SUSPENDED:
|
||||||
if ((err = xrun_recovery(os, -ESTRPIPE)) < 0) {
|
if ((err = xrun_recovery(os, -ESTRPIPE)) < 0) {
|
||||||
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
case SND_PCM_STATE_OPEN:
|
||||||
|
case SND_PCM_STATE_DRAINING:
|
||||||
|
case SND_PCM_STATE_PAUSED:
|
||||||
case SND_PCM_STATE_DISCONNECTED:
|
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 (;;) {
|
for (;;) {
|
||||||
snd_pcm_state_t state = snd_pcm_state(osa->handle);
|
snd_pcm_state_t state = snd_pcm_state(osa->handle);
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case SND_PCM_STATE_OPEN:
|
|
||||||
soundio_panic("TODO open");
|
|
||||||
case SND_PCM_STATE_SETUP:
|
case SND_PCM_STATE_SETUP:
|
||||||
if ((err = snd_pcm_prepare(osa->handle)) < 0) {
|
if ((err = snd_pcm_prepare(osa->handle)) < 0) {
|
||||||
instream->error_callback(instream, SoundIoErrorStreaming);
|
instream->error_callback(instream, SoundIoErrorStreaming);
|
||||||
|
@ -1119,18 +1114,18 @@ static void instream_thread_run(void *arg) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
case SND_PCM_STATE_DRAINING:
|
|
||||||
soundio_panic("TODO draining");
|
|
||||||
case SND_PCM_STATE_PAUSED:
|
|
||||||
soundio_panic("TODO paused");
|
|
||||||
case SND_PCM_STATE_SUSPENDED:
|
case SND_PCM_STATE_SUSPENDED:
|
||||||
if ((err = instream_xrun_recovery(is, -ESTRPIPE)) < 0) {
|
if ((err = instream_xrun_recovery(is, -ESTRPIPE)) < 0) {
|
||||||
instream->error_callback(instream, SoundIoErrorStreaming);
|
instream->error_callback(instream, SoundIoErrorStreaming);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
case SND_PCM_STATE_OPEN:
|
||||||
|
case SND_PCM_STATE_DRAINING:
|
||||||
|
case SND_PCM_STATE_PAUSED:
|
||||||
case SND_PCM_STATE_DISCONNECTED:
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void outstream_clear_buffer_alsa(SoundIoPrivate *si,
|
static int outstream_clear_buffer_alsa(SoundIoPrivate *si,
|
||||||
SoundIoOutStreamPrivate *os)
|
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) {
|
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) {
|
if (isa->thread) {
|
||||||
isa->thread_exit_flag.clear();
|
isa->thread_exit_flag.clear();
|
||||||
// TODO wake up poll
|
|
||||||
soundio_os_thread_destroy(isa->thread);
|
soundio_os_thread_destroy(isa->thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -290,9 +290,11 @@ static int outstream_end_write_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate
|
||||||
return 0;
|
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;
|
SoundIoOutStreamDummy *osd = (SoundIoOutStreamDummy *)os->backend_data;
|
||||||
soundio_ring_buffer_clear(&osd->ring_buffer);
|
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) {
|
static void instream_destroy_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
|
|
|
@ -782,7 +782,7 @@ static int outstream_end_write_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *o
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void outstream_clear_buffer_pa(SoundIoPrivate *si,
|
static int outstream_clear_buffer_pa(SoundIoPrivate *si,
|
||||||
SoundIoOutStreamPrivate *os)
|
SoundIoOutStreamPrivate *os)
|
||||||
{
|
{
|
||||||
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
|
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_threaded_mainloop_lock(sipa->main_loop);
|
||||||
pa_operation *op = pa_stream_flush(stream, NULL, NULL);
|
pa_operation *op = pa_stream_flush(stream, NULL, NULL);
|
||||||
if (!op)
|
if (!op)
|
||||||
soundio_panic("pa_stream_flush failed: %s", pa_strerror(pa_context_errno(sipa->pulse_context)));
|
return SoundIoErrorStreaming;
|
||||||
pa_operation_unref(op);
|
pa_operation_unref(op);
|
||||||
pa_threaded_mainloop_unlock(sipa->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_pause_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, bool pause) {
|
static int outstream_pause_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, bool pause) {
|
||||||
|
|
|
@ -340,14 +340,14 @@ struct SoundIoOutStream {
|
||||||
// This optional callback happens when the sound device runs out of buffered
|
// This optional callback happens when the sound device runs out of buffered
|
||||||
// audio data to play. After this occurs, the outstream waits until the
|
// audio data to play. After this occurs, the outstream waits until the
|
||||||
// buffer is full to resume playback.
|
// 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 *);
|
void (*underflow_callback)(struct SoundIoOutStream *);
|
||||||
// Optional callback. `err` is always SoundIoErrorStreaming.
|
// Optional callback. `err` is always SoundIoErrorStreaming.
|
||||||
// SoundIoErrorStreaming is an unrecoverable error. The stream is in an
|
// SoundIoErrorStreaming is an unrecoverable error. The stream is in an
|
||||||
// invalid state and must be destroyed.
|
// invalid state and must be destroyed.
|
||||||
// If you do not supply `error_callback`, the default callback will print
|
// If you do not supply `error_callback`, the default callback will print
|
||||||
// a message to stderr and then call `abort`.
|
// 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);
|
void (*error_callback)(struct SoundIoOutStream *, int err);
|
||||||
|
|
||||||
// Name of the stream. This is used by PulseAudio. Defaults to "SoundIo".
|
// Name of the stream. This is used by PulseAudio. Defaults to "SoundIo".
|
||||||
|
@ -398,7 +398,7 @@ struct SoundIoInStream {
|
||||||
// invalid state and must be destroyed.
|
// invalid state and must be destroyed.
|
||||||
// If you do not supply `error_callback`, the default callback will print
|
// If you do not supply `error_callback`, the default callback will print
|
||||||
// a message to stderr and then abort().
|
// 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);
|
void (*error_callback)(struct SoundIoInStream *, int err);
|
||||||
|
|
||||||
// Name of the stream. This is used by PulseAudio. Defaults to "SoundIo".
|
// 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);
|
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);
|
void soundio_outstream_destroy(struct SoundIoOutStream *outstream);
|
||||||
|
|
||||||
int soundio_outstream_start(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
|
// 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
|
// correct number of times as determined by `requested_frame_count` from
|
||||||
// `write_callback`. See sine.c for an example.
|
// `write_callback`. See sine.c for an example.
|
||||||
// You must call this function only from `write_callback`. After calling this
|
// You must call this function only from the `write_callback` thread context.
|
||||||
// function, write data to `areas` and then call `soundio_outstream_end_write`.
|
// After calling this function, write data to `areas` and then call `soundio_outstream_end_write`.
|
||||||
int soundio_outstream_begin_write(struct SoundIoOutStream *outstream,
|
int soundio_outstream_begin_write(struct SoundIoOutStream *outstream,
|
||||||
struct SoundIoChannelArea **areas, int *frame_count);
|
struct SoundIoChannelArea **areas, int *frame_count);
|
||||||
|
|
||||||
// Commits the write that you began with `soundio_outstream_begin_write`.
|
// 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);
|
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
|
// If the underyling device supports pausing, this pauses the stream and
|
||||||
// prevents `write_callback` from being called. Otherwise this returns
|
// prevents `write_callback` from being called. Otherwise this returns
|
||||||
// `SoundIoErrorIncompatibleDevice`.
|
// `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);
|
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
|
// 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
|
// correct number of times as determined by `available_frame_count` from
|
||||||
// `read_callback`. See microphone.c for an example.
|
// `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
|
// After calling this function, read data from `areas` and then use
|
||||||
// `soundio_instream_end_read` to actually remove the data from the buffer
|
// `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
|
// 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);
|
struct SoundIoChannelArea **areas, int *frame_count);
|
||||||
// This will drop all of the frames from when you called
|
// This will drop all of the frames from when you called
|
||||||
// `soundio_instream_begin_read`.
|
// `soundio_instream_begin_read`.
|
||||||
// You must call this function only from `read_callback` after a successful
|
// You must call this function only from the `read_callback` thread context.
|
||||||
// call to `soundio_instream_begin_read`.
|
// You must call this function only after a successful call to
|
||||||
|
// `soundio_instream_begin_read`.
|
||||||
int soundio_instream_end_read(struct SoundIoInStream *instream);
|
int soundio_instream_end_read(struct SoundIoInStream *instream);
|
||||||
|
|
||||||
// If the underyling device supports pausing, this pauses the stream and
|
// If the underyling device supports pausing, this pauses the stream and
|
||||||
// prevents `read_callback` from being called. Otherwise this returns
|
// prevents `read_callback` from being called. Otherwise this returns
|
||||||
// `SoundIoErrorIncompatibleDevice`.
|
// `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);
|
int soundio_instream_pause(struct SoundIoInStream *instream, bool pause);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ struct SoundIoPrivate {
|
||||||
int (*outstream_begin_write)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *,
|
int (*outstream_begin_write)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *,
|
||||||
SoundIoChannelArea **out_areas, int *frame_count);
|
SoundIoChannelArea **out_areas, int *frame_count);
|
||||||
int (*outstream_end_write)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, 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);
|
int (*outstream_pause)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, bool pause);
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue