From cd72f45f0659b234bb1494d729f45b0d9de3b524 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 1 Sep 2015 15:06:33 -0700 Subject: [PATCH] ALSA: fix clear buffer behavior --- README.md | 7 +++++-- example/sio_sine.c | 2 ++ src/alsa.cpp | 24 ++++++++++++++++++++---- src/alsa.hpp | 1 + 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index bce8f2a..6a0fd1a 100644 --- a/README.md +++ b/README.md @@ -252,8 +252,11 @@ For each backend, do the following: 0. Run `./sio_list_devices --watch` and make sure it detects when you plug and unplug a USB microphone. 0. Run `./sio_sine` and make sure you hear a sine wave. For backends with raw - devices, run `./sio_sine --device id` (where 'id' is a device id you got - from `sio_list_devices` and make sure you hear a sine wave. + devices, run `./sio_sine --device id --raw` (where 'id' is a device id you + got from `sio_list_devices` and make sure you hear a sine wave. + - Use 'p' to test pausing, 'u' to test unpausing, 'q' to test cleanup. + - 'c' for clear buffer. Clear buffer should not pause the stream and it + should also not cause an underflow. 0. Run `./underflow` and read the testing instructions that it prints. 0. Run `./sio_microphone` and ensure that it is both recording and playing back correctly. If possible use the `--in-device` and `--out-device` diff --git a/example/sio_sine.c b/example/sio_sine.c index 253e843..fc8c240 100644 --- a/example/sio_sine.c +++ b/example/sio_sine.c @@ -241,6 +241,8 @@ int main(int argc, char **argv) { } else if (c == 'c') { fprintf(stderr, "clear buffer result: %s\n", soundio_strerror(soundio_outstream_clear_buffer(outstream))); + } else if (c == 'q') { + break; } else if (c == '\r' || c == '\n') { // ignore } else { diff --git a/src/alsa.cpp b/src/alsa.cpp index 0d34ef2..e255874 100644 --- a/src/alsa.cpp +++ b/src/alsa.cpp @@ -1064,6 +1064,23 @@ void outstream_thread_run(void *arg) { } if (!osa->thread_exit_flag.test_and_set()) return; + if (!osa->clear_buffer_flag.test_and_set()) { + if ((err = snd_pcm_drop(osa->handle)) < 0) { + outstream->error_callback(outstream, SoundIoErrorStreaming); + return; + } + if ((err = snd_pcm_reset(osa->handle)) < 0) { + if (err == -EBADFD) { + // If this happens the snd_pcm_drop will have done + // the function of the reset so it's ok that this + // did not work. + } else { + outstream->error_callback(outstream, SoundIoErrorStreaming); + return; + } + } + continue; + } snd_pcm_sframes_t avail = snd_pcm_avail_update(osa->handle); if (avail < 0) { @@ -1172,6 +1189,8 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) SoundIoOutStream *outstream = &os->pub; SoundIoDevice *device = outstream->device; + osa->clear_buffer_flag.test_and_set(); + if (outstream->software_latency == 0.0) outstream->software_latency = clamp(device->software_latency_min, 1.0, device->software_latency_max); @@ -1429,9 +1448,7 @@ static int outstream_clear_buffer_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { SoundIoOutStreamAlsa *osa = &os->backend_data.alsa; - int err; - if ((err = snd_pcm_reset(osa->handle)) < 0) - return SoundIoErrorStreaming; + osa->clear_buffer_flag.clear(); return 0; } @@ -1443,7 +1460,6 @@ static int outstream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoOutStre int err; if ((err = snd_pcm_pause(osa->handle, pause)) < 0) { - fprintf(stderr, "alsa pause result: %s\n", snd_strerror(err)); return SoundIoErrorIncompatibleDevice; } diff --git a/src/alsa.hpp b/src/alsa.hpp index 8a74487..cb6eda2 100644 --- a/src/alsa.hpp +++ b/src/alsa.hpp @@ -59,6 +59,7 @@ struct SoundIoOutStreamAlsa { int period_size; int write_frame_count; bool is_paused; + atomic_flag clear_buffer_flag; SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS]; };