From be2675e5516ff39b3781446894919f0f1d31bae4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 20 Jul 2015 20:13:35 -0700 Subject: [PATCH] support stream names (used for PulseAudio) --- README.md | 1 + src/dummy.cpp | 10 +++++----- src/os.hpp | 1 + src/pulseaudio.cpp | 6 ++---- src/soundio.cpp | 2 ++ src/soundio.h | 35 +++++++++++++++++++---------------- 6 files changed, 30 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 4be80ae..d6a0062 100644 --- a/README.md +++ b/README.md @@ -235,6 +235,7 @@ view `coverage/index.html` in a browser. ## Roadmap 0. implement ALSA (Linux) backend, get examples working + 0. ALSA: poll instead of callback 0. fix pulseaudio backend since I broke it 0. pipe record to playback example working with dummy linux, osx, windows 0. pipe record to playback example working with pulseaudio linux diff --git a/src/dummy.cpp b/src/dummy.cpp index e09baa5..4225972 100644 --- a/src/dummy.cpp +++ b/src/dummy.cpp @@ -39,15 +39,12 @@ static void playback_thread_run(void *arg) { SoundIoOutStream *outstream = &os->pub; SoundIoOutStreamDummy *osd = (SoundIoOutStreamDummy *)os->backend_data; - double start_time = soundio_os_get_time(); long frames_consumed = 0; - - double time_per_frame = 1.0 / (double)outstream->sample_rate; - + double start_time = soundio_os_get_time(); while (osd->abort_flag.test_and_set()) { double now = soundio_os_get_time(); double total_time = now - start_time; - long total_frames = total_time / time_per_frame; + long total_frames = total_time * outstream->sample_rate; int frames_to_kill = total_frames - frames_consumed; int fill_count = soundio_ring_buffer_fill_count(&osd->ring_buffer); int frames_in_buffer = fill_count / outstream->bytes_per_frame; @@ -59,6 +56,9 @@ static void playback_thread_run(void *arg) { if (frames_left > 0) { outstream->error_callback(outstream, SoundIoErrorUnderflow); + // simulate filling with silence + int free_count = soundio_ring_buffer_free_count(&osd->ring_buffer); + soundio_ring_buffer_advance_write_ptr(&osd->ring_buffer, free_count); } else if (read_count > 0) { outstream->write_callback(outstream, read_count); } diff --git a/src/os.hpp b/src/os.hpp index 7e105e2..4f7c884 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -13,6 +13,7 @@ // safe to call from any thread(s) multiple times, but // must be called at least once before calling any other os functions +// soundio_create calls this function. void soundio_os_init(void); double soundio_os_get_time(void); diff --git a/src/pulseaudio.cpp b/src/pulseaudio.cpp index 343ce15..6cff383 100644 --- a/src/pulseaudio.cpp +++ b/src/pulseaudio.cpp @@ -627,8 +627,7 @@ static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { // TODO handle period_duration - // TODO make this value ("SoundIo") configurable - ospa->stream = pa_stream_new(sipa->pulse_context, "SoundIo", &sample_spec, &channel_map); + ospa->stream = pa_stream_new(sipa->pulse_context, outstream->name, &sample_spec, &channel_map); if (!ospa->stream) { pa_threaded_mainloop_unlock(sipa->main_loop); outstream_destroy_pa(si, os); @@ -806,8 +805,7 @@ static int instream_open_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) { // TODO handle period_duration - // TODO make this value ("SoundIo") private - ispa->stream = pa_stream_new(sipa->pulse_context, "SoundIo", &sample_spec, &channel_map); + ispa->stream = pa_stream_new(sipa->pulse_context, instream->name, &sample_spec, &channel_map); if (!ispa->stream) { pa_threaded_mainloop_unlock(sipa->main_loop); instream_destroy_pa(si, is); diff --git a/src/soundio.cpp b/src/soundio.cpp index 6f2a16a..36d3476 100644 --- a/src/soundio.cpp +++ b/src/soundio.cpp @@ -389,6 +389,7 @@ struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device) outstream->sample_rate = clamp(device->sample_rate_min, 48000, device->sample_rate_max); outstream->buffer_duration = clamp(device->buffer_duration_min, 1.0, device->buffer_duration_max); outstream->period_duration = -1.0; + outstream->name = "SoundIo"; return outstream; } @@ -457,6 +458,7 @@ struct SoundIoInStream *soundio_instream_create(struct SoundIoDevice *device) { instream->sample_rate = clamp(device->sample_rate_min, 48000, device->sample_rate_max); instream->buffer_duration = clamp(device->buffer_duration_min, 1.0, device->buffer_duration_max); instream->period_duration = -1.0; + instream->name = "SoundIo"; return instream; } diff --git a/src/soundio.h b/src/soundio.h index 22e158b..c836cfc 100644 --- a/src/soundio.h +++ b/src/soundio.h @@ -16,9 +16,6 @@ extern "C" { #endif -struct SoundIo; -struct SoundIoDevicesInfo; - enum SoundIoError { SoundIoErrorNone, SoundIoErrorNoMem, @@ -197,6 +194,19 @@ struct SoundIoChannelArea { int step; }; +// The size of this struct is not part of the API or ABI. +struct SoundIo { + // Defaults to NULL. Put whatever you want here. + void *userdata; + // Optional callback. Called when the list of devices change. Only called + // during a call to soundio_flush_events or soundio_wait_events. + void (*on_devices_change)(struct SoundIo *); + // Optional callback. Called from an unknown thread that you should not use + // to call any soundio functions. You may use this to signal a condition + // variable to wake up. Called when soundio_wait_events would be woken up. + void (*on_events_signal)(struct SoundIo *); +}; + // The size of this struct is not part of the API or ABI. struct SoundIoDevice { // Read-only. Set automatically. @@ -314,6 +324,9 @@ struct SoundIoOutStream { void (*error_callback)(struct SoundIoOutStream *, int err); void (*write_callback)(struct SoundIoOutStream *, int requested_frame_count); + // Name of the stream. This is used by PulseAudio. Defaults to "SoundIo". + const char *name; + // computed automatically when you call soundio_outstream_open int bytes_per_frame; int bytes_per_sample; @@ -347,24 +360,14 @@ struct SoundIoInStream { void *userdata; void (*read_callback)(struct SoundIoInStream *); + // Name of the stream. This is used by PulseAudio. Defaults to "SoundIo". + const char *name; + // computed automatically when you call soundio_instream_open int bytes_per_frame; int bytes_per_sample; }; -// The size of this struct is not part of the API or ABI. -struct SoundIo { - // Defaults to NULL. Put whatever you want here. - void *userdata; - // Optional callback. Called when the list of devices change. Only called - // during a call to soundio_flush_events or soundio_wait_events. - void (*on_devices_change)(struct SoundIo *); - // Optional callback. Called from an unknown thread that you should not use - // to call any soundio functions. You may use this to signal a condition - // variable to wake up. Called when soundio_wait_events would be woken up. - void (*on_events_signal)(struct SoundIo *); -}; - // Main Context // Create a SoundIo context. You may create multiple instances of this to