convert source code to pure C

List<T> is now a really ugly macro.

Added a workaround for jack.h not putting `void` in function
prototypes for functions that take no arguments. I made upstream
pull requests to jack1 and jack2 but I don't have high hopes
about them getting merged.

I removed the lock-free atomic asserts. clang reports
non-lock-free atomics when in fact it does have lock-free
atomics. I inspected the generated code for gcc and clang
for fetch_add, load, and store, on x86_64 and armhf, and
it's all lock free.

Closes #45.
This commit is contained in:
Andrew Kelley 2015-11-01 15:18:37 -07:00
parent baba8064e1
commit ee7c0d3e11
30 changed files with 1865 additions and 1782 deletions

View file

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 2.8.5) cmake_minimum_required(VERSION 2.8.5)
project(libsoundio C CXX) project(libsoundio C)
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH}) set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
if(CMAKE_VERSION VERSION_LESS 3.0.0) if(CMAKE_VERSION VERSION_LESS 3.0.0)
@ -135,12 +135,12 @@ endif()
set(LIBSOUNDIO_SOURCES set(LIBSOUNDIO_SOURCES
"${CMAKE_SOURCE_DIR}/src/soundio.cpp" "${CMAKE_SOURCE_DIR}/src/soundio.c"
"${CMAKE_SOURCE_DIR}/src/util.cpp" "${CMAKE_SOURCE_DIR}/src/util.c"
"${CMAKE_SOURCE_DIR}/src/os.cpp" "${CMAKE_SOURCE_DIR}/src/os.c"
"${CMAKE_SOURCE_DIR}/src/dummy.cpp" "${CMAKE_SOURCE_DIR}/src/dummy.c"
"${CMAKE_SOURCE_DIR}/src/channel_layout.cpp" "${CMAKE_SOURCE_DIR}/src/channel_layout.c"
"${CMAKE_SOURCE_DIR}/src/ring_buffer.cpp" "${CMAKE_SOURCE_DIR}/src/ring_buffer.c"
) )
set(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h") set(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h")
@ -152,27 +152,27 @@ set(LIBSOUNDIO_HEADERS
if(SOUNDIO_HAVE_JACK) if(SOUNDIO_HAVE_JACK)
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES} set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
"${CMAKE_SOURCE_DIR}/src/jack.cpp" "${CMAKE_SOURCE_DIR}/src/jack.c"
) )
endif() endif()
if(SOUNDIO_HAVE_PULSEAUDIO) if(SOUNDIO_HAVE_PULSEAUDIO)
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES} set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
"${CMAKE_SOURCE_DIR}/src/pulseaudio.cpp" "${CMAKE_SOURCE_DIR}/src/pulseaudio.c"
) )
endif() endif()
if(SOUNDIO_HAVE_ALSA) if(SOUNDIO_HAVE_ALSA)
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES} set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
"${CMAKE_SOURCE_DIR}/src/alsa.cpp" "${CMAKE_SOURCE_DIR}/src/alsa.c"
) )
endif() endif()
if(SOUNDIO_HAVE_COREAUDIO) if(SOUNDIO_HAVE_COREAUDIO)
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES} set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
"${CMAKE_SOURCE_DIR}/src/coreaudio.cpp" "${CMAKE_SOURCE_DIR}/src/coreaudio.c"
) )
endif() endif()
if(SOUNDIO_HAVE_WASAPI) if(SOUNDIO_HAVE_WASAPI)
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES} set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
"${CMAKE_SOURCE_DIR}/src/wasapi.cpp" "${CMAKE_SOURCE_DIR}/src/wasapi.c"
) )
endif() endif()
@ -195,15 +195,10 @@ set(LIBSOUNDIO_LIBS
# GTFO, -lstdc++ !!
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Werror -pedantic") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Werror -pedantic")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror -pedantic")
set(LIB_CFLAGS "-std=c++11 -fno-exceptions -fno-rtti -fvisibility=hidden -Wall -Werror=strict-prototypes -Werror=old-style-definition -Werror=missing-prototypes -Wno-c99-extensions") set(LIB_CFLAGS "-std=c11 -fvisibility=hidden -Wall -Werror=strict-prototypes -Werror=old-style-definition -Werror=missing-prototypes -D_REENTRANT -D_POSIX_C_SOURCE=200809L")
set(EXAMPLE_CFLAGS "-std=c99 -Wall") set(EXAMPLE_CFLAGS "-std=c99 -Wall")
set(TEST_CFLAGS "${LIB_CFLAGS} -fprofile-arcs -ftest-coverage") set(TEST_CFLAGS "${LIB_CFLAGS} -fprofile-arcs -ftest-coverage")
set(TEST_LDFLAGS "-fprofile-arcs -ftest-coverage") set(TEST_LDFLAGS "-fprofile-arcs -ftest-coverage")
@ -277,7 +272,7 @@ if(BUILD_EXAMPLE_PROGRAMS)
endif() endif()
if(BUILD_TESTS) if(BUILD_TESTS)
add_executable(unit_tests "${CMAKE_SOURCE_DIR}/test/unit_tests.cpp" ${LIBSOUNDIO_SOURCES}) add_executable(unit_tests "${CMAKE_SOURCE_DIR}/test/unit_tests.c" ${LIBSOUNDIO_SOURCES})
target_link_libraries(unit_tests LINK_PUBLIC ${LIBSOUNDIO_LIBS}) target_link_libraries(unit_tests LINK_PUBLIC ${LIBSOUNDIO_LIBS})
set_target_properties(unit_tests PROPERTIES set_target_properties(unit_tests PROPERTIES
LINKER_LANGUAGE C LINKER_LANGUAGE C
@ -285,7 +280,7 @@ if(BUILD_TESTS)
LINK_FLAGS ${TEST_LDFLAGS} LINK_FLAGS ${TEST_LDFLAGS}
) )
add_executable(latency "${CMAKE_SOURCE_DIR}/test/latency.cpp" ${LIBSOUNDIO_SOURCES}) add_executable(latency "${CMAKE_SOURCE_DIR}/test/latency.c" ${LIBSOUNDIO_SOURCES})
target_link_libraries(latency LINK_PUBLIC ${LIBSOUNDIO_LIBS} m) target_link_libraries(latency LINK_PUBLIC ${LIBSOUNDIO_LIBS} m)
set_target_properties(latency PROPERTIES set_target_properties(latency PROPERTIES
LINKER_LANGUAGE C LINKER_LANGUAGE C

View file

@ -181,22 +181,6 @@ and `soundio_get_backend` to get the list of available backends.
[API Documentation](http://libsound.io/doc) [API Documentation](http://libsound.io/doc)
## Contributing
libsoundio is programmed in a tiny subset of C++11:
* No STL.
* No `new` or `delete`.
* No `class`. All fields in structs are `public`.
* No constructors or destructors.
* No exceptions or run-time type information.
* No references.
* No linking against libstdc++.
Do not be fooled - this is a *C library*, not a C++ library. We just take
advantage of a select few C++11 compiler features such as templates, and then
link against libc.
### Building ### Building
Install the dependencies: Install the dependencies:

View file

@ -5,10 +5,13 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#include "alsa.hpp" #define _GNU_SOURCE
#include "soundio.hpp" #include "alsa.h"
#include "soundio_private.h"
#include <sys/inotify.h> #include <sys/inotify.h>
#include <fcntl.h>
#include <unistd.h>
static snd_pcm_stream_t stream_types[] = {SND_PCM_STREAM_PLAYBACK, SND_PCM_STREAM_CAPTURE}; static snd_pcm_stream_t stream_types[] = {SND_PCM_STREAM_PLAYBACK, SND_PCM_STREAM_CAPTURE};
@ -20,8 +23,9 @@ static snd_pcm_access_t prioritized_access_types[] = {
SND_PCM_ACCESS_RW_NONINTERLEAVED, SND_PCM_ACCESS_RW_NONINTERLEAVED,
}; };
SOUNDIO_MAKE_LIST_DEF(struct SoundIoAlsaPendingFile, SoundIoListAlsaPendingFile, SOUNDIO_LIST_STATIC)
static void wakeup_device_poll(SoundIoAlsa *sia) { static void wakeup_device_poll(struct SoundIoAlsa *sia) {
ssize_t amt = write(sia->notify_pipe_fd[1], "a", 1); ssize_t amt = write(sia->notify_pipe_fd[1], "a", 1);
if (amt == -1) { if (amt == -1) {
assert(errno != EBADF); assert(errno != EBADF);
@ -32,16 +36,16 @@ static void wakeup_device_poll(SoundIoAlsa *sia) {
} }
} }
static void destroy_alsa(SoundIoPrivate *si) { static void destroy_alsa(struct SoundIoPrivate *si) {
SoundIoAlsa *sia = &si->backend_data.alsa; struct SoundIoAlsa *sia = &si->backend_data.alsa;
if (sia->thread) { if (sia->thread) {
sia->abort_flag.clear(); atomic_flag_clear(&sia->abort_flag);
wakeup_device_poll(sia); wakeup_device_poll(sia);
soundio_os_thread_destroy(sia->thread); soundio_os_thread_destroy(sia->thread);
} }
sia->pending_files.deinit(); SoundIoListAlsaPendingFile_deinit(&sia->pending_files);
if (sia->cond) if (sia->cond)
soundio_os_cond_destroy(sia->cond); soundio_os_cond_destroy(sia->cond);
@ -71,10 +75,10 @@ static char * str_partition_on_char(char *str, char c) {
} }
str += 1; str += 1;
} }
return nullptr; return NULL;
} }
static snd_pcm_stream_t aim_to_stream(SoundIoDeviceAim aim) { static snd_pcm_stream_t aim_to_stream(enum SoundIoDeviceAim aim) {
switch (aim) { switch (aim) {
case SoundIoDeviceAimOutput: return SND_PCM_STREAM_PLAYBACK; case SoundIoDeviceAimOutput: return SND_PCM_STREAM_PLAYBACK;
case SoundIoDeviceAimInput: return SND_PCM_STREAM_CAPTURE; case SoundIoDeviceAimInput: return SND_PCM_STREAM_CAPTURE;
@ -83,8 +87,8 @@ static snd_pcm_stream_t aim_to_stream(SoundIoDeviceAim aim) {
return SND_PCM_STREAM_PLAYBACK; return SND_PCM_STREAM_PLAYBACK;
} }
static SoundIoChannelId from_alsa_chmap_pos(unsigned int pos) { static enum SoundIoChannelId from_alsa_chmap_pos(unsigned int pos) {
switch ((snd_pcm_chmap_position)pos) { switch ((enum snd_pcm_chmap_position)pos) {
case SND_CHMAP_UNKNOWN: return SoundIoChannelIdInvalid; case SND_CHMAP_UNKNOWN: return SoundIoChannelIdInvalid;
case SND_CHMAP_NA: return SoundIoChannelIdInvalid; case SND_CHMAP_NA: return SoundIoChannelIdInvalid;
case SND_CHMAP_MONO: return SoundIoChannelIdFrontCenter; case SND_CHMAP_MONO: return SoundIoChannelIdFrontCenter;
@ -126,7 +130,7 @@ static SoundIoChannelId from_alsa_chmap_pos(unsigned int pos) {
return SoundIoChannelIdInvalid; return SoundIoChannelIdInvalid;
} }
static int to_alsa_chmap_pos(SoundIoChannelId channel_id) { static int to_alsa_chmap_pos(enum SoundIoChannelId channel_id) {
switch (channel_id) { switch (channel_id) {
case SoundIoChannelIdFrontLeft: return SND_CHMAP_FL; case SoundIoChannelIdFrontLeft: return SND_CHMAP_FL;
case SoundIoChannelIdFrontRight: return SND_CHMAP_FR; case SoundIoChannelIdFrontRight: return SND_CHMAP_FR;
@ -168,8 +172,8 @@ static int to_alsa_chmap_pos(SoundIoChannelId channel_id) {
} }
} }
static void get_channel_layout(SoundIoChannelLayout *dest, snd_pcm_chmap_t *chmap) { static void get_channel_layout(struct SoundIoChannelLayout *dest, snd_pcm_chmap_t *chmap) {
int channel_count = min((unsigned int)SOUNDIO_MAX_CHANNELS, chmap->channels); int channel_count = soundio_int_min(SOUNDIO_MAX_CHANNELS, chmap->channels);
dest->channel_count = channel_count; dest->channel_count = channel_count;
for (int i = 0; i < channel_count; i += 1) { for (int i = 0; i < channel_count; i += 1) {
dest->channels[i] = from_alsa_chmap_pos(chmap->pos[i]); dest->channels[i] = from_alsa_chmap_pos(chmap->pos[i]);
@ -177,7 +181,7 @@ static void get_channel_layout(SoundIoChannelLayout *dest, snd_pcm_chmap_t *chma
soundio_channel_layout_detect_builtin(dest); soundio_channel_layout_detect_builtin(dest);
} }
static int handle_channel_maps(SoundIoDevice *device, snd_pcm_chmap_query_t **maps) { static int handle_channel_maps(struct SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
if (!maps) if (!maps)
return 0; return 0;
@ -187,7 +191,7 @@ static int handle_channel_maps(SoundIoDevice *device, snd_pcm_chmap_query_t **ma
// one iteration to count // one iteration to count
int layout_count = 0; int layout_count = 0;
for (p = maps; (v = *p) && layout_count < SOUNDIO_MAX_CHANNELS; p += 1, layout_count += 1) { } for (p = maps; (v = *p) && layout_count < SOUNDIO_MAX_CHANNELS; p += 1, layout_count += 1) { }
device->layouts = allocate<SoundIoChannelLayout>(layout_count); device->layouts = ALLOCATE(struct SoundIoChannelLayout, layout_count);
if (!device->layouts) { if (!device->layouts) {
snd_pcm_free_chmaps(maps); snd_pcm_free_chmaps(maps);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
@ -207,7 +211,7 @@ static int handle_channel_maps(SoundIoDevice *device, snd_pcm_chmap_query_t **ma
return 0; return 0;
} }
static snd_pcm_format_t to_alsa_fmt(SoundIoFormat fmt) { static snd_pcm_format_t to_alsa_fmt(enum SoundIoFormat fmt) {
switch (fmt) { switch (fmt) {
case SoundIoFormatS8: return SND_PCM_FORMAT_S8; case SoundIoFormatS8: return SND_PCM_FORMAT_S8;
case SoundIoFormatU8: return SND_PCM_FORMAT_U8; case SoundIoFormatU8: return SND_PCM_FORMAT_U8;
@ -234,7 +238,9 @@ static snd_pcm_format_t to_alsa_fmt(SoundIoFormat fmt) {
return SND_PCM_FORMAT_UNKNOWN; return SND_PCM_FORMAT_UNKNOWN;
} }
static void test_fmt_mask(SoundIoDevice *device, const snd_pcm_format_mask_t *fmt_mask, SoundIoFormat fmt) { static void test_fmt_mask(struct SoundIoDevice *device, const snd_pcm_format_mask_t *fmt_mask,
enum SoundIoFormat fmt)
{
if (snd_pcm_format_mask_test(fmt_mask, to_alsa_fmt(fmt))) { if (snd_pcm_format_mask_test(fmt_mask, to_alsa_fmt(fmt))) {
device->formats[device->format_count] = fmt; device->formats[device->format_count] = fmt;
device->format_count += 1; device->format_count += 1;
@ -242,7 +248,7 @@ static void test_fmt_mask(SoundIoDevice *device, const snd_pcm_format_mask_t *fm
} }
static int set_access(snd_pcm_t *handle, snd_pcm_hw_params_t *hwparams, snd_pcm_access_t *out_access) { static int set_access(snd_pcm_t *handle, snd_pcm_hw_params_t *hwparams, snd_pcm_access_t *out_access) {
for (int i = 0; i < array_length(prioritized_access_types); i += 1) { for (int i = 0; i < ARRAY_LENGTH(prioritized_access_types); i += 1) {
snd_pcm_access_t access = prioritized_access_types[i]; snd_pcm_access_t access = prioritized_access_types[i];
int err = snd_pcm_hw_params_set_access(handle, hwparams, access); int err = snd_pcm_hw_params_set_access(handle, hwparams, access);
if (err >= 0) { if (err >= 0) {
@ -255,10 +261,10 @@ static int set_access(snd_pcm_t *handle, snd_pcm_hw_params_t *hwparams, snd_pcm_
} }
// this function does not override device->formats, so if you want it to, deallocate and set it to NULL // this function does not override device->formats, so if you want it to, deallocate and set it to NULL
static int probe_open_device(SoundIoDevice *device, snd_pcm_t *handle, int resample, static int probe_open_device(struct SoundIoDevice *device, snd_pcm_t *handle, int resample,
int *out_channels_min, int *out_channels_max) int *out_channels_min, int *out_channels_max)
{ {
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device; struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
int err; int err;
snd_pcm_hw_params_t *hwparams; snd_pcm_hw_params_t *hwparams;
@ -270,7 +276,7 @@ static int probe_open_device(SoundIoDevice *device, snd_pcm_t *handle, int resam
if ((err = snd_pcm_hw_params_set_rate_resample(handle, hwparams, resample)) < 0) if ((err = snd_pcm_hw_params_set_rate_resample(handle, hwparams, resample)) < 0)
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
if ((err = set_access(handle, hwparams, nullptr))) if ((err = set_access(handle, hwparams, NULL)))
return err; return err;
unsigned int channels_min; unsigned int channels_min;
@ -287,10 +293,10 @@ static int probe_open_device(SoundIoDevice *device, snd_pcm_t *handle, int resam
unsigned int rate_min; unsigned int rate_min;
unsigned int rate_max; unsigned int rate_max;
if ((err = snd_pcm_hw_params_get_rate_min(hwparams, &rate_min, nullptr)) < 0) if ((err = snd_pcm_hw_params_get_rate_min(hwparams, &rate_min, NULL)) < 0)
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
if ((err = snd_pcm_hw_params_set_rate_last(handle, hwparams, &rate_max, nullptr)) < 0) if ((err = snd_pcm_hw_params_set_rate_last(handle, hwparams, &rate_max, NULL)) < 0)
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
device->sample_rate_count = 1; device->sample_rate_count = 1;
@ -345,7 +351,7 @@ static int probe_open_device(SoundIoDevice *device, snd_pcm_t *handle, int resam
if (!device->formats) { if (!device->formats) {
snd_pcm_hw_params_get_format_mask(hwparams, fmt_mask); snd_pcm_hw_params_get_format_mask(hwparams, fmt_mask);
device->formats = allocate<SoundIoFormat>(18); device->formats = ALLOCATE(enum SoundIoFormat, 18);
if (!device->formats) if (!device->formats)
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
@ -373,7 +379,7 @@ static int probe_open_device(SoundIoDevice *device, snd_pcm_t *handle, int resam
return 0; return 0;
} }
static int probe_device(SoundIoDevice *device, snd_pcm_chmap_query_t **maps) { static int probe_device(struct SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
int err; int err;
snd_pcm_t *handle; snd_pcm_t *handle;
@ -398,20 +404,20 @@ static int probe_device(SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
// the min and max channel counts are correct. // the min and max channel counts are correct.
int layout_count = 0; int layout_count = 0;
for (int i = 0; i < soundio_channel_layout_builtin_count(); i += 1) { for (int i = 0; i < soundio_channel_layout_builtin_count(); i += 1) {
const SoundIoChannelLayout *layout = soundio_channel_layout_get_builtin(i); const struct SoundIoChannelLayout *layout = soundio_channel_layout_get_builtin(i);
if (layout->channel_count >= channels_min && layout->channel_count <= channels_max) { if (layout->channel_count >= channels_min && layout->channel_count <= channels_max) {
layout_count += 1; layout_count += 1;
} }
} }
device->layout_count = layout_count; device->layout_count = layout_count;
device->layouts = allocate<SoundIoChannelLayout>(device->layout_count); device->layouts = ALLOCATE(struct SoundIoChannelLayout, device->layout_count);
if (!device->layouts) { if (!device->layouts) {
snd_pcm_close(handle); snd_pcm_close(handle);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
int layout_index = 0; int layout_index = 0;
for (int i = 0; i < soundio_channel_layout_builtin_count(); i += 1) { for (int i = 0; i < soundio_channel_layout_builtin_count(); i += 1) {
const SoundIoChannelLayout *layout = soundio_channel_layout_get_builtin(i); const struct SoundIoChannelLayout *layout = soundio_channel_layout_get_builtin(i);
if (layout->channel_count >= channels_min && layout->channel_count <= channels_max) { if (layout->channel_count >= channels_min && layout->channel_count <= channels_max) {
device->layouts[layout_index++] = *soundio_channel_layout_get_builtin(i); device->layouts[layout_index++] = *soundio_channel_layout_get_builtin(i);
} }
@ -428,7 +434,7 @@ static int probe_device(SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
snd_pcm_close(handle); snd_pcm_close(handle);
return err; return err;
} }
maps = nullptr; maps = NULL;
if (!device->is_raw) { if (!device->is_raw) {
if (device->sample_rates[0].min == device->sample_rates[0].max) if (device->sample_rates[0].min == device->sample_rates[0].max)
@ -452,9 +458,9 @@ static inline bool str_has_prefix(const char *big_str, const char *prefix) {
return strncmp(big_str, prefix, strlen(prefix)) == 0; return strncmp(big_str, prefix, strlen(prefix)) == 0;
} }
static int refresh_devices(SoundIoPrivate *si) { static int refresh_devices(struct SoundIoPrivate *si) {
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoAlsa *sia = &si->backend_data.alsa; struct SoundIoAlsa *sia = &si->backend_data.alsa;
int err; int err;
if ((err = snd_config_update_free_global()) < 0) if ((err = snd_config_update_free_global()) < 0)
@ -462,7 +468,7 @@ static int refresh_devices(SoundIoPrivate *si) {
if ((err = snd_config_update()) < 0) if ((err = snd_config_update()) < 0)
return SoundIoErrorSystemResources; return SoundIoErrorSystemResources;
SoundIoDevicesInfo *devices_info = allocate<SoundIoDevicesInfo>(1); struct SoundIoDevicesInfo *devices_info = ALLOCATE(struct SoundIoDevicesInfo, 1);
if (!devices_info) if (!devices_info)
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
devices_info->default_output_index = -1; devices_info->default_output_index = -1;
@ -517,7 +523,7 @@ static int refresh_devices(SoundIoPrivate *si) {
is_capture = true; is_capture = true;
} }
for (int stream_type_i = 0; stream_type_i < array_length(stream_types); stream_type_i += 1) { for (int stream_type_i = 0; stream_type_i < ARRAY_LENGTH(stream_types); stream_type_i += 1) {
snd_pcm_stream_t stream = stream_types[stream_type_i]; snd_pcm_stream_t stream = stream_types[stream_type_i];
if (stream == SND_PCM_STREAM_PLAYBACK && !is_playback) continue; if (stream == SND_PCM_STREAM_PLAYBACK && !is_playback) continue;
if (stream == SND_PCM_STREAM_CAPTURE && !is_capture) continue; if (stream == SND_PCM_STREAM_CAPTURE && !is_capture) continue;
@ -528,7 +534,7 @@ static int refresh_devices(SoundIoPrivate *si) {
} }
SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1); struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
if (!dev) { if (!dev) {
free(name); free(name);
free(descr); free(descr);
@ -536,13 +542,13 @@ static int refresh_devices(SoundIoPrivate *si) {
snd_device_name_free_hint(hints); snd_device_name_free_hint(hints);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
SoundIoDevice *device = &dev->pub; struct SoundIoDevice *device = &dev->pub;
device->ref_count = 1; device->ref_count = 1;
device->soundio = soundio; device->soundio = soundio;
device->is_raw = false; device->is_raw = false;
device->id = strdup(name); device->id = strdup(name);
device->name = descr1 ? device->name = descr1 ?
soundio_alloc_sprintf(nullptr, "%s: %s", descr, descr1) : strdup(descr); soundio_alloc_sprintf(NULL, "%s: %s", descr, descr1) : strdup(descr);
if (!device->id || !device->name) { if (!device->id || !device->name) {
soundio_device_unref(device); soundio_device_unref(device);
@ -553,7 +559,7 @@ static int refresh_devices(SoundIoPrivate *si) {
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
SoundIoList<SoundIoDevice *> *device_list; struct SoundIoListDevicePtr *device_list;
bool is_default = str_has_prefix(name, "default:") || strcmp(name, "default") == 0; bool is_default = str_has_prefix(name, "default:") || strcmp(name, "default") == 0;
if (stream == SND_PCM_STREAM_PLAYBACK) { if (stream == SND_PCM_STREAM_PLAYBACK) {
device->aim = SoundIoDeviceAimOutput; device->aim = SoundIoDeviceAimOutput;
@ -568,9 +574,9 @@ static int refresh_devices(SoundIoPrivate *si) {
devices_info->default_input_index = device_list->length; devices_info->default_input_index = device_list->length;
} }
device->probe_error = probe_device(device, nullptr); device->probe_error = probe_device(device, NULL);
if (device_list->append(device)) { if (SoundIoListDevicePtr_append(device_list, device)) {
soundio_device_unref(device); soundio_device_unref(device);
free(name); free(name);
free(descr); free(descr);
@ -631,7 +637,7 @@ static int refresh_devices(SoundIoPrivate *si) {
snd_pcm_info_set_device(pcm_info, device_index); snd_pcm_info_set_device(pcm_info, device_index);
snd_pcm_info_set_subdevice(pcm_info, 0); snd_pcm_info_set_subdevice(pcm_info, 0);
for (int stream_type_i = 0; stream_type_i < array_length(stream_types); stream_type_i += 1) { for (int stream_type_i = 0; stream_type_i < ARRAY_LENGTH(stream_types); stream_type_i += 1) {
snd_pcm_stream_t stream = stream_types[stream_type_i]; snd_pcm_stream_t stream = stream_types[stream_type_i];
snd_pcm_info_set_stream(pcm_info, stream); snd_pcm_info_set_stream(pcm_info, stream);
@ -647,17 +653,17 @@ static int refresh_devices(SoundIoPrivate *si) {
const char *device_name = snd_pcm_info_get_name(pcm_info); const char *device_name = snd_pcm_info_get_name(pcm_info);
SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1); struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
if (!dev) { if (!dev) {
snd_ctl_close(handle); snd_ctl_close(handle);
soundio_destroy_devices_info(devices_info); soundio_destroy_devices_info(devices_info);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
SoundIoDevice *device = &dev->pub; struct SoundIoDevice *device = &dev->pub;
device->ref_count = 1; device->ref_count = 1;
device->soundio = soundio; device->soundio = soundio;
device->id = soundio_alloc_sprintf(nullptr, "hw:%d,%d", card_index, device_index); device->id = soundio_alloc_sprintf(NULL, "hw:%d,%d", card_index, device_index);
device->name = soundio_alloc_sprintf(nullptr, "%s %s", card_name, device_name); device->name = soundio_alloc_sprintf(NULL, "%s %s", card_name, device_name);
device->is_raw = true; device->is_raw = true;
if (!device->id || !device->name) { if (!device->id || !device->name) {
@ -667,7 +673,7 @@ static int refresh_devices(SoundIoPrivate *si) {
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
SoundIoList<SoundIoDevice *> *device_list; struct SoundIoListDevicePtr *device_list;
if (stream == SND_PCM_STREAM_PLAYBACK) { if (stream == SND_PCM_STREAM_PLAYBACK) {
device->aim = SoundIoDeviceAimOutput; device->aim = SoundIoDeviceAimOutput;
device_list = &devices_info->output_devices; device_list = &devices_info->output_devices;
@ -680,7 +686,7 @@ static int refresh_devices(SoundIoPrivate *si) {
snd_pcm_chmap_query_t **maps = snd_pcm_query_chmaps_from_hw(card_index, device_index, -1, stream); snd_pcm_chmap_query_t **maps = snd_pcm_query_chmaps_from_hw(card_index, device_index, -1, stream);
device->probe_error = probe_device(device, maps); device->probe_error = probe_device(device, maps);
if (device_list->append(device)) { if (SoundIoListDevicePtr_append(device_list, device)) {
soundio_device_unref(device); soundio_device_unref(device);
soundio_destroy_devices_info(devices_info); soundio_destroy_devices_info(devices_info);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
@ -704,9 +710,9 @@ static int refresh_devices(SoundIoPrivate *si) {
return 0; return 0;
} }
static void shutdown_backend(SoundIoPrivate *si, int err) { static void shutdown_backend(struct SoundIoPrivate *si, int err) {
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoAlsa *sia = &si->backend_data.alsa; struct SoundIoAlsa *sia = &si->backend_data.alsa;
soundio_os_mutex_lock(sia->mutex); soundio_os_mutex_lock(sia->mutex);
sia->shutdown_err = err; sia->shutdown_err = err;
soundio_os_cond_signal(sia->cond, sia->mutex); soundio_os_cond_signal(sia->cond, sia->mutex);
@ -730,8 +736,8 @@ static bool copy_str(char *dest, const char *src, int buf_len) {
} }
static void device_thread_run(void *arg) { static void device_thread_run(void *arg) {
SoundIoPrivate *si = (SoundIoPrivate *)arg; struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
SoundIoAlsa *sia = &si->backend_data.alsa; struct SoundIoAlsa *sia = &si->backend_data.alsa;
// Some systems cannot read integer variables if they are not // Some systems cannot read integer variables if they are not
// properly aligned. On other systems, incorrect alignment may // properly aligned. On other systems, incorrect alignment may
@ -751,7 +757,7 @@ static void device_thread_run(void *arg) {
int err; int err;
for (;;) { for (;;) {
int poll_num = poll(fds, 2, -1); int poll_num = poll(fds, 2, -1);
if (!sia->abort_flag.test_and_set()) if (!atomic_flag_test_and_set(&sia->abort_flag))
break; break;
if (poll_num == -1) { if (poll_num == -1) {
if (errno == EINTR) if (errno == EINTR)
@ -801,13 +807,14 @@ static void device_thread_run(void *arg) {
continue; continue;
} }
if (event->mask & IN_CREATE) { if (event->mask & IN_CREATE) {
if ((err = sia->pending_files.add_one())) { if ((err = SoundIoListAlsaPendingFile_add_one(&sia->pending_files))) {
shutdown_backend(si, SoundIoErrorNoMem); shutdown_backend(si, SoundIoErrorNoMem);
return; return;
} }
SoundIoAlsaPendingFile *pending_file = &sia->pending_files.last(); struct SoundIoAlsaPendingFile *pending_file =
SoundIoListAlsaPendingFile_last_ptr(&sia->pending_files);
if (!copy_str(pending_file->name, event->name, SOUNDIO_MAX_ALSA_SND_FILE_LEN)) { if (!copy_str(pending_file->name, event->name, SOUNDIO_MAX_ALSA_SND_FILE_LEN)) {
sia->pending_files.pop(); SoundIoListAlsaPendingFile_pop(&sia->pending_files);
} }
continue; continue;
} }
@ -817,9 +824,10 @@ static void device_thread_run(void *arg) {
if (!(event->mask & IN_CLOSE_WRITE)) if (!(event->mask & IN_CLOSE_WRITE))
continue; continue;
for (int i = 0; i < sia->pending_files.length; i += 1) { for (int i = 0; i < sia->pending_files.length; i += 1) {
SoundIoAlsaPendingFile *pending_file = &sia->pending_files.at(i); struct SoundIoAlsaPendingFile *pending_file =
SoundIoListAlsaPendingFile_ptr_at(&sia->pending_files, i);
if (strcmp(pending_file->name, event->name) == 0) { if (strcmp(pending_file->name, event->name) == 0) {
sia->pending_files.swap_remove(i); SoundIoListAlsaPendingFile_swap_remove(&sia->pending_files, i);
if (sia->pending_files.length == 0) { if (sia->pending_files.length == 0) {
got_rescan_event = true; got_rescan_event = true;
} }
@ -864,13 +872,13 @@ static void device_thread_run(void *arg) {
} }
} }
static void my_flush_events(SoundIoPrivate *si, bool wait) { static void my_flush_events(struct SoundIoPrivate *si, bool wait) {
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoAlsa *sia = &si->backend_data.alsa; struct SoundIoAlsa *sia = &si->backend_data.alsa;
bool change = false; bool change = false;
bool cb_shutdown = false; bool cb_shutdown = false;
SoundIoDevicesInfo *old_devices_info = nullptr; struct SoundIoDevicesInfo *old_devices_info = NULL;
soundio_os_mutex_lock(sia->mutex); soundio_os_mutex_lock(sia->mutex);
@ -886,7 +894,7 @@ static void my_flush_events(SoundIoPrivate *si, bool wait) {
} else if (sia->ready_devices_info) { } else if (sia->ready_devices_info) {
old_devices_info = si->safe_devices_info; old_devices_info = si->safe_devices_info;
si->safe_devices_info = sia->ready_devices_info; si->safe_devices_info = sia->ready_devices_info;
sia->ready_devices_info = nullptr; sia->ready_devices_info = NULL;
change = true; change = true;
} }
@ -900,54 +908,54 @@ static void my_flush_events(SoundIoPrivate *si, bool wait) {
soundio_destroy_devices_info(old_devices_info); soundio_destroy_devices_info(old_devices_info);
} }
static void flush_events_alsa(SoundIoPrivate *si) { static void flush_events_alsa(struct SoundIoPrivate *si) {
my_flush_events(si, false); my_flush_events(si, false);
} }
static void wait_events_alsa(SoundIoPrivate *si) { static void wait_events_alsa(struct SoundIoPrivate *si) {
my_flush_events(si, false); my_flush_events(si, false);
my_flush_events(si, true); my_flush_events(si, true);
} }
static void wakeup_alsa(SoundIoPrivate *si) { static void wakeup_alsa(struct SoundIoPrivate *si) {
SoundIoAlsa *sia = &si->backend_data.alsa; struct SoundIoAlsa *sia = &si->backend_data.alsa;
soundio_os_mutex_lock(sia->mutex); soundio_os_mutex_lock(sia->mutex);
soundio_os_cond_signal(sia->cond, sia->mutex); soundio_os_cond_signal(sia->cond, sia->mutex);
soundio_os_mutex_unlock(sia->mutex); soundio_os_mutex_unlock(sia->mutex);
} }
static void force_device_scan_alsa(SoundIoPrivate *si) { static void force_device_scan_alsa(struct SoundIoPrivate *si) {
SoundIoAlsa *sia = &si->backend_data.alsa; struct SoundIoAlsa *sia = &si->backend_data.alsa;
wakeup_device_poll(sia); wakeup_device_poll(sia);
} }
static void outstream_destroy_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { static void outstream_destroy_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa; struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
if (osa->thread) { if (osa->thread) {
osa->thread_exit_flag.clear(); atomic_flag_clear(&osa->thread_exit_flag);
soundio_os_thread_destroy(osa->thread); soundio_os_thread_destroy(osa->thread);
osa->thread = nullptr; osa->thread = NULL;
} }
if (osa->handle) { if (osa->handle) {
snd_pcm_close(osa->handle); snd_pcm_close(osa->handle);
osa->handle = nullptr; osa->handle = NULL;
} }
free(osa->poll_fds); free(osa->poll_fds);
osa->poll_fds = nullptr; osa->poll_fds = NULL;
free(osa->chmap); free(osa->chmap);
osa->chmap = nullptr; osa->chmap = NULL;
free(osa->sample_buffer); free(osa->sample_buffer);
osa->sample_buffer = nullptr; osa->sample_buffer = NULL;
} }
static int outstream_xrun_recovery(SoundIoOutStreamPrivate *os, int err) { static int outstream_xrun_recovery(struct SoundIoOutStreamPrivate *os, int err) {
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa; struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
if (err == -EPIPE) { if (err == -EPIPE) {
err = snd_pcm_prepare(osa->handle); err = snd_pcm_prepare(osa->handle);
if (err >= 0) if (err >= 0)
@ -955,7 +963,7 @@ static int outstream_xrun_recovery(SoundIoOutStreamPrivate *os, int err) {
} else if (err == -ESTRPIPE) { } else if (err == -ESTRPIPE) {
while ((err = snd_pcm_resume(osa->handle)) == -EAGAIN) { while ((err = snd_pcm_resume(osa->handle)) == -EAGAIN) {
// wait until suspend flag is released // wait until suspend flag is released
poll(nullptr, 0, 1); poll(NULL, 0, 1);
} }
if (err < 0) if (err < 0)
err = snd_pcm_prepare(osa->handle); err = snd_pcm_prepare(osa->handle);
@ -965,9 +973,9 @@ static int outstream_xrun_recovery(SoundIoOutStreamPrivate *os, int err) {
return err; return err;
} }
static int instream_xrun_recovery(SoundIoInStreamPrivate *is, int err) { static int instream_xrun_recovery(struct SoundIoInStreamPrivate *is, int err) {
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
SoundIoInStreamAlsa *isa = &is->backend_data.alsa; struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
if (err == -EPIPE) { if (err == -EPIPE) {
err = snd_pcm_prepare(isa->handle); err = snd_pcm_prepare(isa->handle);
if (err >= 0) if (err >= 0)
@ -975,7 +983,7 @@ static int instream_xrun_recovery(SoundIoInStreamPrivate *is, int err) {
} else if (err == -ESTRPIPE) { } else if (err == -ESTRPIPE) {
while ((err = snd_pcm_resume(isa->handle)) == -EAGAIN) { while ((err = snd_pcm_resume(isa->handle)) == -EAGAIN) {
// wait until suspend flag is released // wait until suspend flag is released
poll(nullptr, 0, 1); poll(NULL, 0, 1);
} }
if (err < 0) if (err < 0)
err = snd_pcm_prepare(isa->handle); err = snd_pcm_prepare(isa->handle);
@ -985,8 +993,8 @@ static int instream_xrun_recovery(SoundIoInStreamPrivate *is, int err) {
return err; return err;
} }
static int outstream_wait_for_poll(SoundIoOutStreamPrivate *os) { static int outstream_wait_for_poll(struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa; struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
int err; int err;
unsigned short revents; unsigned short revents;
for (;;) { for (;;) {
@ -1006,8 +1014,8 @@ static int outstream_wait_for_poll(SoundIoOutStreamPrivate *os) {
} }
} }
static int instream_wait_for_poll(SoundIoInStreamPrivate *is) { static int instream_wait_for_poll(struct SoundIoInStreamPrivate *is) {
SoundIoInStreamAlsa *isa = &is->backend_data.alsa; struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
int err; int err;
unsigned short revents; unsigned short revents;
for (;;) { for (;;) {
@ -1028,9 +1036,9 @@ static int instream_wait_for_poll(SoundIoInStreamPrivate *is) {
} }
static void outstream_thread_run(void *arg) { static void outstream_thread_run(void *arg) {
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *) arg; struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *) arg;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa; struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
int err; int err;
@ -1055,7 +1063,7 @@ static void outstream_thread_run(void *arg) {
if ((snd_pcm_uframes_t)avail == osa->buffer_size_frames) { if ((snd_pcm_uframes_t)avail == osa->buffer_size_frames) {
outstream->write_callback(outstream, 0, avail); outstream->write_callback(outstream, 0, avail);
if (!osa->thread_exit_flag.test_and_set()) if (!atomic_flag_test_and_set(&osa->thread_exit_flag))
return; return;
continue; continue;
} }
@ -1070,14 +1078,14 @@ static void outstream_thread_run(void *arg) {
case SND_PCM_STATE_PAUSED: case SND_PCM_STATE_PAUSED:
{ {
if ((err = outstream_wait_for_poll(os)) < 0) { if ((err = outstream_wait_for_poll(os)) < 0) {
if (!osa->thread_exit_flag.test_and_set()) if (!atomic_flag_test_and_set(&osa->thread_exit_flag))
return; return;
outstream->error_callback(outstream, SoundIoErrorStreaming); outstream->error_callback(outstream, SoundIoErrorStreaming);
return; return;
} }
if (!osa->thread_exit_flag.test_and_set()) if (!atomic_flag_test_and_set(&osa->thread_exit_flag))
return; return;
if (!osa->clear_buffer_flag.test_and_set()) { if (!atomic_flag_test_and_set(&osa->clear_buffer_flag)) {
if ((err = snd_pcm_drop(osa->handle)) < 0) { if ((err = snd_pcm_drop(osa->handle)) < 0) {
outstream->error_callback(outstream, SoundIoErrorStreaming); outstream->error_callback(outstream, SoundIoErrorStreaming);
return; return;
@ -1130,9 +1138,9 @@ static void outstream_thread_run(void *arg) {
} }
static void instream_thread_run(void *arg) { static void instream_thread_run(void *arg) {
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *) arg; struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *) arg;
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
SoundIoInStreamAlsa *isa = &is->backend_data.alsa; struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
int err; int err;
@ -1155,12 +1163,12 @@ static void instream_thread_run(void *arg) {
case SND_PCM_STATE_PAUSED: case SND_PCM_STATE_PAUSED:
{ {
if ((err = instream_wait_for_poll(is)) < 0) { if ((err = instream_wait_for_poll(is)) < 0) {
if (!isa->thread_exit_flag.test_and_set()) if (!atomic_flag_test_and_set(&isa->thread_exit_flag))
return; return;
instream->error_callback(instream, SoundIoErrorStreaming); instream->error_callback(instream, SoundIoErrorStreaming);
return; return;
} }
if (!isa->thread_exit_flag.test_and_set()) if (!atomic_flag_test_and_set(&isa->thread_exit_flag))
return; return;
snd_pcm_sframes_t avail = snd_pcm_avail_update(isa->handle); snd_pcm_sframes_t avail = snd_pcm_avail_update(isa->handle);
@ -1198,21 +1206,21 @@ static void instream_thread_run(void *arg) {
} }
} }
static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { static int outstream_open_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa; struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
SoundIoDevice *device = outstream->device; struct SoundIoDevice *device = outstream->device;
osa->clear_buffer_flag.test_and_set(); atomic_flag_test_and_set(&osa->clear_buffer_flag);
if (outstream->software_latency == 0.0) if (outstream->software_latency == 0.0)
outstream->software_latency = 1.0; outstream->software_latency = 1.0;
outstream->software_latency = clamp(device->software_latency_min, outstream->software_latency, device->software_latency_max); outstream->software_latency = soundio_double_clamp(device->software_latency_min, outstream->software_latency, device->software_latency_max);
int ch_count = outstream->layout.channel_count; int ch_count = outstream->layout.channel_count;
osa->chmap_size = sizeof(int) + sizeof(int) * ch_count; osa->chmap_size = sizeof(int) + sizeof(int) * ch_count;
osa->chmap = (snd_pcm_chmap_t *)allocate<char>(osa->chmap_size); osa->chmap = (snd_pcm_chmap_t *)ALLOCATE(char, osa->chmap_size);
if (!osa->chmap) { if (!osa->chmap) {
outstream_destroy_alsa(si, os); outstream_destroy_alsa(si, os);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
@ -1272,7 +1280,7 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
if (device->is_raw) { if (device->is_raw) {
period_count = 4; period_count = 4;
unsigned int microseconds = 0.25 * outstream->software_latency * 1000000.0; unsigned int microseconds = 0.25 * outstream->software_latency * 1000000.0;
if ((err = snd_pcm_hw_params_set_period_time_near(osa->handle, hwparams, &microseconds, nullptr)) < 0) { if ((err = snd_pcm_hw_params_set_period_time_near(osa->handle, hwparams, &microseconds, NULL)) < 0) {
outstream_destroy_alsa(si, os); outstream_destroy_alsa(si, os);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
@ -1282,14 +1290,14 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
snd_pcm_uframes_t period_frames = snd_pcm_uframes_t period_frames =
ceil_dbl_to_uframes(period_duration * (double)outstream->sample_rate); ceil_dbl_to_uframes(period_duration * (double)outstream->sample_rate);
if ((err = snd_pcm_hw_params_set_period_size_near(osa->handle, hwparams, &period_frames, nullptr)) < 0) { if ((err = snd_pcm_hw_params_set_period_size_near(osa->handle, hwparams, &period_frames, NULL)) < 0) {
outstream_destroy_alsa(si, os); outstream_destroy_alsa(si, os);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
} }
snd_pcm_uframes_t period_size; snd_pcm_uframes_t period_size;
if ((snd_pcm_hw_params_get_period_size(hwparams, &period_size, nullptr)) < 0) { if ((snd_pcm_hw_params_get_period_size(hwparams, &period_size, NULL)) < 0) {
outstream_destroy_alsa(si, os); outstream_destroy_alsa(si, os);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
@ -1343,7 +1351,7 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
if (osa->access == SND_PCM_ACCESS_RW_INTERLEAVED || osa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) { if (osa->access == SND_PCM_ACCESS_RW_INTERLEAVED || osa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
osa->sample_buffer_size = ch_count * osa->period_size * phys_bytes_per_sample; osa->sample_buffer_size = ch_count * osa->period_size * phys_bytes_per_sample;
osa->sample_buffer = allocate_nonzero<char>(osa->sample_buffer_size); osa->sample_buffer = ALLOCATE_NONZERO(char, osa->sample_buffer_size);
if (!osa->sample_buffer) { if (!osa->sample_buffer) {
outstream_destroy_alsa(si, os); outstream_destroy_alsa(si, os);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
@ -1356,7 +1364,7 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
osa->poll_fds = allocate<struct pollfd>(osa->poll_fd_count); osa->poll_fds = ALLOCATE(struct pollfd, osa->poll_fd_count);
if (!osa->poll_fds) { if (!osa->poll_fds) {
outstream_destroy_alsa(si, os); outstream_destroy_alsa(si, os);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
@ -1370,26 +1378,26 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
return 0; return 0;
} }
static int outstream_start_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { static int outstream_start_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa; struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
assert(!osa->thread); assert(!osa->thread);
int err; int err;
osa->thread_exit_flag.test_and_set(); atomic_flag_test_and_set(&osa->thread_exit_flag);
if ((err = soundio_os_thread_create(outstream_thread_run, os, soundio->emit_rtprio_warning, &osa->thread))) if ((err = soundio_os_thread_create(outstream_thread_run, os, soundio->emit_rtprio_warning, &osa->thread)))
return err; return err;
return 0; return 0;
} }
static int outstream_begin_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, static int outstream_begin_write_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
struct SoundIoChannelArea **out_areas, int *frame_count) struct SoundIoChannelArea **out_areas, int *frame_count)
{ {
*out_areas = nullptr; *out_areas = NULL;
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa; struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
if (osa->access == SND_PCM_ACCESS_RW_INTERLEAVED) { if (osa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) { for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
@ -1397,7 +1405,7 @@ static int outstream_begin_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivat
osa->areas[ch].step = outstream->bytes_per_frame; osa->areas[ch].step = outstream->bytes_per_frame;
} }
osa->write_frame_count = min(*frame_count, osa->period_size); osa->write_frame_count = soundio_int_min(*frame_count, osa->period_size);
*frame_count = osa->write_frame_count; *frame_count = osa->write_frame_count;
} else if (osa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) { } else if (osa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) { for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
@ -1405,7 +1413,7 @@ static int outstream_begin_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivat
osa->areas[ch].step = outstream->bytes_per_sample; osa->areas[ch].step = outstream->bytes_per_sample;
} }
osa->write_frame_count = min(*frame_count, osa->period_size); osa->write_frame_count = soundio_int_min(*frame_count, osa->period_size);
*frame_count = osa->write_frame_count; *frame_count = osa->write_frame_count;
} else { } else {
const snd_pcm_channel_area_t *areas; const snd_pcm_channel_area_t *areas;
@ -1435,9 +1443,9 @@ static int outstream_begin_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivat
return 0; return 0;
} }
static int outstream_end_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { static int outstream_end_write_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa; struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
snd_pcm_sframes_t commitres; snd_pcm_sframes_t commitres;
if (osa->access == SND_PCM_ACCESS_RW_INTERLEAVED) { if (osa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
@ -1462,11 +1470,11 @@ static int outstream_end_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate
return 0; return 0;
} }
static int outstream_clear_buffer_alsa(SoundIoPrivate *si, static int outstream_clear_buffer_alsa(struct SoundIoPrivate *si,
SoundIoOutStreamPrivate *os) struct SoundIoOutStreamPrivate *os)
{ {
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa; struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
osa->clear_buffer_flag.clear(); atomic_flag_clear(&osa->clear_buffer_flag);
return 0; return 0;
} }
@ -1474,7 +1482,7 @@ static int outstream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoOutStre
if (!si) if (!si)
return SoundIoErrorInvalid; return SoundIoErrorInvalid;
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa; struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
if (!osa->handle) if (!osa->handle)
return SoundIoErrorInvalid; return SoundIoErrorInvalid;
@ -1494,8 +1502,8 @@ static int outstream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoOutStre
static int outstream_get_latency_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, static int outstream_get_latency_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
double *out_latency) double *out_latency)
{ {
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa; struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
int err; int err;
snd_pcm_sframes_t delay; snd_pcm_sframes_t delay;
@ -1507,43 +1515,43 @@ static int outstream_get_latency_alsa(struct SoundIoPrivate *si, struct SoundIoO
return 0; return 0;
} }
static void instream_destroy_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) { static void instream_destroy_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStreamAlsa *isa = &is->backend_data.alsa; struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
if (isa->thread) { if (isa->thread) {
isa->thread_exit_flag.clear(); atomic_flag_clear(&isa->thread_exit_flag);
soundio_os_thread_destroy(isa->thread); soundio_os_thread_destroy(isa->thread);
isa->thread = nullptr; isa->thread = NULL;
} }
if (isa->handle) { if (isa->handle) {
snd_pcm_close(isa->handle); snd_pcm_close(isa->handle);
isa->handle = nullptr; isa->handle = NULL;
} }
free(isa->poll_fds); free(isa->poll_fds);
isa->poll_fds = nullptr; isa->poll_fds = NULL;
free(isa->chmap); free(isa->chmap);
isa->chmap = nullptr; isa->chmap = NULL;
free(isa->sample_buffer); free(isa->sample_buffer);
isa->sample_buffer = nullptr; isa->sample_buffer = NULL;
} }
static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) { static int instream_open_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStreamAlsa *isa = &is->backend_data.alsa; struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
SoundIoDevice *device = instream->device; struct SoundIoDevice *device = instream->device;
if (instream->software_latency == 0.0) if (instream->software_latency == 0.0)
instream->software_latency = 1.0; instream->software_latency = 1.0;
instream->software_latency = clamp(device->software_latency_min, instream->software_latency, device->software_latency_max); instream->software_latency = soundio_double_clamp(device->software_latency_min, instream->software_latency, device->software_latency_max);
int ch_count = instream->layout.channel_count; int ch_count = instream->layout.channel_count;
isa->chmap_size = sizeof(int) + sizeof(int) * ch_count; isa->chmap_size = sizeof(int) + sizeof(int) * ch_count;
isa->chmap = (snd_pcm_chmap_t *)allocate<char>(isa->chmap_size); isa->chmap = (snd_pcm_chmap_t *)ALLOCATE(char, isa->chmap_size);
if (!isa->chmap) { if (!isa->chmap) {
instream_destroy_alsa(si, is); instream_destroy_alsa(si, is);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
@ -1600,7 +1608,7 @@ static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
} }
snd_pcm_uframes_t period_frames = ceil_dbl_to_uframes(0.5 * instream->software_latency * (double)instream->sample_rate); snd_pcm_uframes_t period_frames = ceil_dbl_to_uframes(0.5 * instream->software_latency * (double)instream->sample_rate);
if ((err = snd_pcm_hw_params_set_period_size_near(isa->handle, hwparams, &period_frames, nullptr)) < 0) { if ((err = snd_pcm_hw_params_set_period_size_near(isa->handle, hwparams, &period_frames, NULL)) < 0) {
instream_destroy_alsa(si, is); instream_destroy_alsa(si, is);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
@ -1645,7 +1653,7 @@ static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED || isa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) { if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED || isa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
isa->sample_buffer_size = ch_count * isa->period_size * phys_bytes_per_sample; isa->sample_buffer_size = ch_count * isa->period_size * phys_bytes_per_sample;
isa->sample_buffer = allocate_nonzero<char>(isa->sample_buffer_size); isa->sample_buffer = ALLOCATE_NONZERO(char, isa->sample_buffer_size);
if (!isa->sample_buffer) { if (!isa->sample_buffer) {
instream_destroy_alsa(si, is); instream_destroy_alsa(si, is);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
@ -1658,7 +1666,7 @@ static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
isa->poll_fds = allocate<struct pollfd>(isa->poll_fd_count); isa->poll_fds = ALLOCATE(struct pollfd, isa->poll_fd_count);
if (!isa->poll_fds) { if (!isa->poll_fds) {
instream_destroy_alsa(si, is); instream_destroy_alsa(si, is);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
@ -1672,13 +1680,13 @@ static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
return 0; return 0;
} }
static int instream_start_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) { static int instream_start_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStreamAlsa *isa = &is->backend_data.alsa; struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
assert(!isa->thread); assert(!isa->thread);
isa->thread_exit_flag.test_and_set(); atomic_flag_test_and_set(&isa->thread_exit_flag);
int err; int err;
if ((err = soundio_os_thread_create(instream_thread_run, is, soundio->emit_rtprio_warning, &isa->thread))) { if ((err = soundio_os_thread_create(instream_thread_run, is, soundio->emit_rtprio_warning, &isa->thread))) {
instream_destroy_alsa(si, is); instream_destroy_alsa(si, is);
@ -1688,12 +1696,12 @@ static int instream_start_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
return 0; return 0;
} }
static int instream_begin_read_alsa(SoundIoPrivate *si, static int instream_begin_read_alsa(struct SoundIoPrivate *si,
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count) struct SoundIoInStreamPrivate *is, struct SoundIoChannelArea **out_areas, int *frame_count)
{ {
*out_areas = nullptr; *out_areas = NULL;
SoundIoInStreamAlsa *isa = &is->backend_data.alsa; struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED) { if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) { for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
@ -1701,7 +1709,7 @@ static int instream_begin_read_alsa(SoundIoPrivate *si,
isa->areas[ch].step = instream->bytes_per_frame; isa->areas[ch].step = instream->bytes_per_frame;
} }
isa->read_frame_count = min(*frame_count, isa->period_size); isa->read_frame_count = soundio_int_min(*frame_count, isa->period_size);
*frame_count = isa->read_frame_count; *frame_count = isa->read_frame_count;
snd_pcm_sframes_t commitres = snd_pcm_readi(isa->handle, isa->sample_buffer, isa->read_frame_count); snd_pcm_sframes_t commitres = snd_pcm_readi(isa->handle, isa->sample_buffer, isa->read_frame_count);
@ -1718,7 +1726,7 @@ static int instream_begin_read_alsa(SoundIoPrivate *si,
ptrs[ch] = isa->areas[ch].ptr; ptrs[ch] = isa->areas[ch].ptr;
} }
isa->read_frame_count = min(*frame_count, isa->period_size); isa->read_frame_count = soundio_int_min(*frame_count, isa->period_size);
*frame_count = isa->read_frame_count; *frame_count = isa->read_frame_count;
snd_pcm_sframes_t commitres = snd_pcm_readn(isa->handle, (void**)ptrs, isa->read_frame_count); snd_pcm_sframes_t commitres = snd_pcm_readn(isa->handle, (void**)ptrs, isa->read_frame_count);
@ -1753,8 +1761,8 @@ static int instream_begin_read_alsa(SoundIoPrivate *si,
return 0; return 0;
} }
static int instream_end_read_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) { static int instream_end_read_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStreamAlsa *isa = &is->backend_data.alsa; struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED) { if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
// nothing to do // nothing to do
@ -1773,7 +1781,7 @@ static int instream_end_read_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is
} }
static int instream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) { static int instream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
SoundIoInStreamAlsa *isa = &is->backend_data.alsa; struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
if (isa->is_paused == pause) if (isa->is_paused == pause)
return 0; return 0;
@ -1789,8 +1797,8 @@ static int instream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoInStream
static int instream_get_latency_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, static int instream_get_latency_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
double *out_latency) double *out_latency)
{ {
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
SoundIoInStreamAlsa *isa = &is->backend_data.alsa; struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
int err; int err;
snd_pcm_sframes_t delay; snd_pcm_sframes_t delay;
@ -1802,13 +1810,13 @@ static int instream_get_latency_alsa(struct SoundIoPrivate *si, struct SoundIoIn
return 0; return 0;
} }
int soundio_alsa_init(SoundIoPrivate *si) { int soundio_alsa_init(struct SoundIoPrivate *si) {
SoundIoAlsa *sia = &si->backend_data.alsa; struct SoundIoAlsa *sia = &si->backend_data.alsa;
int err; int err;
sia->notify_fd = -1; sia->notify_fd = -1;
sia->notify_wd = -1; sia->notify_wd = -1;
sia->abort_flag.test_and_set(); atomic_flag_test_and_set(&sia->abort_flag);
sia->mutex = soundio_os_mutex_create(); sia->mutex = soundio_os_mutex_create();
if (!sia->mutex) { if (!sia->mutex) {
@ -1865,7 +1873,7 @@ int soundio_alsa_init(SoundIoPrivate *si) {
wakeup_device_poll(sia); wakeup_device_poll(sia);
if ((err = soundio_os_thread_create(device_thread_run, si, nullptr, &sia->thread))) { if ((err = soundio_os_thread_create(device_thread_run, si, NULL, &sia->thread))) {
destroy_alsa(si); destroy_alsa(si);
return err; return err;
} }

View file

@ -5,28 +5,31 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#ifndef SOUNDIO_ALSA_HPP #ifndef SOUNDIO_ALSA_H
#define SOUNDIO_ALSA_HPP #define SOUNDIO_ALSA_H
#include "soundio_private.h" #include "soundio_internal.h"
#include "os.h" #include "os.h"
#include "atomics.hpp" #include "list.h"
#include "list.hpp" #include "atomics.h"
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
struct SoundIoPrivate;
int soundio_alsa_init(struct SoundIoPrivate *si); int soundio_alsa_init(struct SoundIoPrivate *si);
struct SoundIoDeviceAlsa { }; struct SoundIoDeviceAlsa { int make_the_struct_not_empty; };
#define SOUNDIO_MAX_ALSA_SND_FILE_LEN 16 #define SOUNDIO_MAX_ALSA_SND_FILE_LEN 16
struct SoundIoAlsaPendingFile { struct SoundIoAlsaPendingFile {
char name[SOUNDIO_MAX_ALSA_SND_FILE_LEN]; char name[SOUNDIO_MAX_ALSA_SND_FILE_LEN];
}; };
SOUNDIO_MAKE_LIST_STRUCT(struct SoundIoAlsaPendingFile, SoundIoListAlsaPendingFile, SOUNDIO_LIST_STATIC)
struct SoundIoAlsa { struct SoundIoAlsa {
SoundIoOsMutex *mutex; struct SoundIoOsMutex *mutex;
SoundIoOsCond *cond; struct SoundIoOsCond *cond;
struct SoundIoOsThread *thread; struct SoundIoOsThread *thread;
atomic_flag abort_flag; atomic_flag abort_flag;
@ -34,7 +37,7 @@ struct SoundIoAlsa {
int notify_wd; int notify_wd;
bool have_devices_flag; bool have_devices_flag;
int notify_pipe_fd[2]; int notify_pipe_fd[2];
SoundIoList<SoundIoAlsaPendingFile> pending_files; struct SoundIoListAlsaPendingFile pending_files;
// this one is ready to be read with flush_events. protected by mutex // this one is ready to be read with flush_events. protected by mutex
struct SoundIoDevicesInfo *ready_devices_info; struct SoundIoDevicesInfo *ready_devices_info;
@ -54,13 +57,13 @@ struct SoundIoOutStreamAlsa {
char *sample_buffer; char *sample_buffer;
int poll_fd_count; int poll_fd_count;
struct pollfd *poll_fds; struct pollfd *poll_fds;
SoundIoOsThread *thread; struct SoundIoOsThread *thread;
atomic_flag thread_exit_flag; atomic_flag thread_exit_flag;
int period_size; int period_size;
int write_frame_count; int write_frame_count;
bool is_paused; bool is_paused;
atomic_flag clear_buffer_flag; atomic_flag clear_buffer_flag;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS]; struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
}; };
struct SoundIoInStreamAlsa { struct SoundIoInStreamAlsa {
@ -73,12 +76,12 @@ struct SoundIoInStreamAlsa {
char *sample_buffer; char *sample_buffer;
int poll_fd_count; int poll_fd_count;
struct pollfd *poll_fds; struct pollfd *poll_fds;
SoundIoOsThread *thread; struct SoundIoOsThread *thread;
atomic_flag thread_exit_flag; atomic_flag thread_exit_flag;
int period_size; int period_size;
int read_frame_count; int read_frame_count;
bool is_paused; bool is_paused;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS]; struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
}; };
#endif #endif

33
src/atomics.h Normal file
View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2015 Andrew Kelley
*
* This file is part of libsoundio, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
#ifndef SOUNDIO_ATOMICS_H
#define SOUNDIO_ATOMICS_H
// Simple wrappers around atomic values so that the compiler will catch it if
// I accidentally use operators such as +, -, += on them.
#include <stdatomic.h>
struct SoundIoAtomicLong {
atomic_long x;
};
struct SoundIoAtomicInt {
atomic_int x;
};
struct SoundIoAtomicBool {
atomic_bool x;
};
#define SOUNDIO_ATOMIC_LOAD(a) atomic_load(&a.x)
#define SOUNDIO_ATOMIC_FETCH_ADD(a, delta) atomic_fetch_add(&a.x, delta)
#define SOUNDIO_ATOMIC_STORE(a, value) atomic_store(&a.x, value)
#define SOUNDIO_ATOMIC_EXCHANGE(a, value) atomic_exchange(&a.x, value)
#endif

View file

@ -1,34 +0,0 @@
/*
* Copyright (c) 2015 Andrew Kelley
*
* This file is part of libsoundio, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
#ifndef SOUNDIO_ATOMICS_HPP
#define SOUNDIO_ATOMICS_HPP
#include <atomic>
using std::atomic_flag;
using std::atomic_int;
using std::atomic_long;
using std::atomic_bool;
using std::atomic_uintptr_t;
#if ATOMIC_INT_LOCK_FREE != 2
#error "require atomic_int to be lock free"
#endif
#if ATOMIC_LONG_LOCK_FREE != 2
#error "require atomic_long to be lock free"
#endif
#if ATOMIC_BOOL_LOCK_FREE != 2
#error "require atomic_bool to be lock free"
#endif
#if ATOMIC_POINTER_LOCK_FREE != 2
#error "require atomic pointers to be lock free"
#endif
#endif

View file

@ -5,7 +5,7 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#include "soundio.hpp" #include "soundio_private.h"
#include <stdio.h> #include <stdio.h>
@ -308,12 +308,12 @@ static struct SoundIoChannelLayout builtin_channel_layouts[] = {
}, },
}; };
static const int channel_name_alias_count = 3; #define CHANNEL_NAME_ALIAS_COUNT 3
static const char *channel_names[][channel_name_alias_count] = { static const char *channel_names[][CHANNEL_NAME_ALIAS_COUNT] = {
[SoundIoChannelIdInvalid] = { [SoundIoChannelIdInvalid] = {
"(Invalid Channel)", "(Invalid Channel)",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdFrontLeft] = { [SoundIoChannelIdFrontLeft] = {
"Front Left", "Front Left",
@ -407,258 +407,258 @@ static const char *channel_names[][channel_name_alias_count] = {
}, },
[SoundIoChannelIdBackLeftCenter] = { [SoundIoChannelIdBackLeftCenter] = {
"Back Left Center", "Back Left Center",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdBackRightCenter] = { [SoundIoChannelIdBackRightCenter] = {
"Back Right Center", "Back Right Center",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdFrontLeftWide] = { [SoundIoChannelIdFrontLeftWide] = {
"Front Left Wide", "Front Left Wide",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdFrontRightWide] = { [SoundIoChannelIdFrontRightWide] = {
"Front Right Wide", "Front Right Wide",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdFrontLeftHigh] = { [SoundIoChannelIdFrontLeftHigh] = {
"Front Left High", "Front Left High",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdFrontCenterHigh] = { [SoundIoChannelIdFrontCenterHigh] = {
"Front Center High", "Front Center High",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdFrontRightHigh] = { [SoundIoChannelIdFrontRightHigh] = {
"Front Right High", "Front Right High",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdTopFrontLeftCenter] = { [SoundIoChannelIdTopFrontLeftCenter] = {
"Top Front Left Center", "Top Front Left Center",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdTopFrontRightCenter] = { [SoundIoChannelIdTopFrontRightCenter] = {
"Top Front Right Center", "Top Front Right Center",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdTopSideLeft] = { [SoundIoChannelIdTopSideLeft] = {
"Top Side Left", "Top Side Left",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdTopSideRight] = { [SoundIoChannelIdTopSideRight] = {
"Top Side Right", "Top Side Right",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdLeftLfe] = { [SoundIoChannelIdLeftLfe] = {
"Left LFE", "Left LFE",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdRightLfe] = { [SoundIoChannelIdRightLfe] = {
"Right LFE", "Right LFE",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdLfe2] = { [SoundIoChannelIdLfe2] = {
"LFE 2", "LFE 2",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdBottomCenter] = { [SoundIoChannelIdBottomCenter] = {
"Bottom Center", "Bottom Center",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdBottomLeftCenter] = { [SoundIoChannelIdBottomLeftCenter] = {
"Bottom Left Center", "Bottom Left Center",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdBottomRightCenter] = { [SoundIoChannelIdBottomRightCenter] = {
"Bottom Right Center", "Bottom Right Center",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdMsMid] = { [SoundIoChannelIdMsMid] = {
"Mid/Side Mid", "Mid/Side Mid",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdMsSide] = { [SoundIoChannelIdMsSide] = {
"Mid/Side Side", "Mid/Side Side",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAmbisonicW] = { [SoundIoChannelIdAmbisonicW] = {
"Ambisonic W", "Ambisonic W",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAmbisonicX] = { [SoundIoChannelIdAmbisonicX] = {
"Ambisonic X", "Ambisonic X",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAmbisonicY] = { [SoundIoChannelIdAmbisonicY] = {
"Ambisonic Y", "Ambisonic Y",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAmbisonicZ] = { [SoundIoChannelIdAmbisonicZ] = {
"Ambisonic Z", "Ambisonic Z",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdXyX] = { [SoundIoChannelIdXyX] = {
"X-Y X", "X-Y X",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdXyY] = { [SoundIoChannelIdXyY] = {
"X-Y Y", "X-Y Y",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdHeadphonesLeft] = { [SoundIoChannelIdHeadphonesLeft] = {
"Headphones Left", "Headphones Left",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdHeadphonesRight] = { [SoundIoChannelIdHeadphonesRight] = {
"Headphones Right", "Headphones Right",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdClickTrack] = { [SoundIoChannelIdClickTrack] = {
"Click Track", "Click Track",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdForeignLanguage] = { [SoundIoChannelIdForeignLanguage] = {
"Foreign Language", "Foreign Language",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdHearingImpaired] = { [SoundIoChannelIdHearingImpaired] = {
"Hearing Impaired", "Hearing Impaired",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdNarration] = { [SoundIoChannelIdNarration] = {
"Narration", "Narration",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdHaptic] = { [SoundIoChannelIdHaptic] = {
"Haptic", "Haptic",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdDialogCentricMix] = { [SoundIoChannelIdDialogCentricMix] = {
"Dialog Centric Mix", "Dialog Centric Mix",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAux] = { [SoundIoChannelIdAux] = {
"Aux", "Aux",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAux0] = { [SoundIoChannelIdAux0] = {
"Aux 0", "Aux 0",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAux1] = { [SoundIoChannelIdAux1] = {
"Aux 1", "Aux 1",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAux2] = { [SoundIoChannelIdAux2] = {
"Aux 2", "Aux 2",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAux3] = { [SoundIoChannelIdAux3] = {
"Aux 3", "Aux 3",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAux4] = { [SoundIoChannelIdAux4] = {
"Aux 4", "Aux 4",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAux5] = { [SoundIoChannelIdAux5] = {
"Aux 5", "Aux 5",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAux6] = { [SoundIoChannelIdAux6] = {
"Aux 6", "Aux 6",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAux7] = { [SoundIoChannelIdAux7] = {
"Aux 7", "Aux 7",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAux8] = { [SoundIoChannelIdAux8] = {
"Aux 8", "Aux 8",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAux9] = { [SoundIoChannelIdAux9] = {
"Aux 9", "Aux 9",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAux10] = { [SoundIoChannelIdAux10] = {
"Aux 10", "Aux 10",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAux11] = { [SoundIoChannelIdAux11] = {
"Aux 11", "Aux 11",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAux12] = { [SoundIoChannelIdAux12] = {
"Aux 12", "Aux 12",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAux13] = { [SoundIoChannelIdAux13] = {
"Aux 13", "Aux 13",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAux14] = { [SoundIoChannelIdAux14] = {
"Aux 14", "Aux 14",
nullptr, NULL,
nullptr, NULL,
}, },
[SoundIoChannelIdAux15] = { [SoundIoChannelIdAux15] = {
"Aux 15", "Aux 15",
nullptr, NULL,
nullptr, NULL,
}, },
}; };
const char *soundio_get_channel_name(enum SoundIoChannelId id) { const char *soundio_get_channel_name(enum SoundIoChannelId id) {
if (id < 0 || id > array_length(channel_names)) if (id >= ARRAY_LENGTH(channel_names))
return "(Invalid Channel)"; return "(Invalid Channel)";
else else
return channel_names[id][0]; return channel_names[id][0];
@ -680,12 +680,12 @@ bool soundio_channel_layout_equal(
} }
int soundio_channel_layout_builtin_count(void) { int soundio_channel_layout_builtin_count(void) {
return array_length(builtin_channel_layouts); return ARRAY_LENGTH(builtin_channel_layouts);
} }
const struct SoundIoChannelLayout *soundio_channel_layout_get_builtin(int index) { const struct SoundIoChannelLayout *soundio_channel_layout_get_builtin(int index) {
assert(index >= 0); assert(index >= 0);
assert(index <= array_length(builtin_channel_layouts)); assert(index <= ARRAY_LENGTH(builtin_channel_layouts));
return &builtin_channel_layouts[index]; return &builtin_channel_layouts[index];
} }
@ -700,14 +700,14 @@ int soundio_channel_layout_find_channel(
} }
bool soundio_channel_layout_detect_builtin(struct SoundIoChannelLayout *layout) { bool soundio_channel_layout_detect_builtin(struct SoundIoChannelLayout *layout) {
for (int i = 0; i < array_length(builtin_channel_layouts); i += 1) { for (int i = 0; i < ARRAY_LENGTH(builtin_channel_layouts); i += 1) {
const struct SoundIoChannelLayout *builtin_layout = &builtin_channel_layouts[i]; const struct SoundIoChannelLayout *builtin_layout = &builtin_channel_layouts[i];
if (soundio_channel_layout_equal(builtin_layout, layout)) { if (soundio_channel_layout_equal(builtin_layout, layout)) {
layout->name = builtin_layout->name; layout->name = builtin_layout->name;
return true; return true;
} }
} }
layout->name = nullptr; layout->name = NULL;
return false; return false;
} }
@ -722,18 +722,18 @@ const struct SoundIoChannelLayout *soundio_channel_layout_get_default(int channe
case 7: return soundio_channel_layout_get_builtin(SoundIoChannelLayoutId6Point1); case 7: return soundio_channel_layout_get_builtin(SoundIoChannelLayoutId6Point1);
case 8: return soundio_channel_layout_get_builtin(SoundIoChannelLayoutId7Point1); case 8: return soundio_channel_layout_get_builtin(SoundIoChannelLayoutId7Point1);
} }
return nullptr; return NULL;
} }
enum SoundIoChannelId soundio_parse_channel_id(const char *str, int str_len) { enum SoundIoChannelId soundio_parse_channel_id(const char *str, int str_len) {
for (int id = 0; id < array_length(channel_names); id += 1) { for (int id = 0; id < ARRAY_LENGTH(channel_names); id += 1) {
for (int i = 0; i < channel_name_alias_count; i += 1) { for (int i = 0; i < CHANNEL_NAME_ALIAS_COUNT; i += 1) {
const char *alias = channel_names[id][i]; const char *alias = channel_names[id][i];
if (!alias) if (!alias)
break; break;
int alias_len = strlen(alias); int alias_len = strlen(alias);
if (soundio_streql(alias, alias_len, str, str_len)) if (soundio_streql(alias, alias_len, str, str_len))
return (SoundIoChannelId)id; return (enum SoundIoChannelId)id;
} }
} }
return SoundIoChannelIdInvalid; return SoundIoChannelIdInvalid;

View file

@ -5,8 +5,8 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#include "coreaudio.hpp" #include "coreaudio.h"
#include "soundio.hpp" #include "soundio_private.h"
#include <assert.h> #include <assert.h>
@ -91,19 +91,21 @@ static AudioObjectPropertyAddress device_listen_props[] = {
}, },
}; };
static SoundIoDeviceAim aims[] = { static enum SoundIoDeviceAim aims[] = {
SoundIoDeviceAimInput, SoundIoDeviceAimInput,
SoundIoDeviceAimOutput, SoundIoDeviceAimOutput,
}; };
SOUNDIO_MAKE_LIST_DEF(AudioDeviceID, SoundIoListAudioDeviceID, SOUNDIO_LIST_STATIC)
static OSStatus on_devices_changed(AudioObjectID in_object_id, UInt32 in_number_addresses, static OSStatus on_devices_changed(AudioObjectID in_object_id, UInt32 in_number_addresses,
const AudioObjectPropertyAddress in_addresses[], void *in_client_data) const AudioObjectPropertyAddress in_addresses[], void *in_client_data)
{ {
SoundIoPrivate *si = (SoundIoPrivate*)in_client_data; struct SoundIoPrivate *si = (struct SoundIoPrivate*)in_client_data;
SoundIoCoreAudio *sica = &si->backend_data.coreaudio; struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
sica->device_scan_queued.store(true); SOUNDIO_ATOMIC_STORE(sica->device_scan_queued, true);
soundio_os_cond_signal(sica->scan_devices_cond, nullptr); soundio_os_cond_signal(sica->scan_devices_cond, NULL);
return noErr; return noErr;
} }
@ -111,30 +113,30 @@ static OSStatus on_devices_changed(AudioObjectID in_object_id, UInt32 in_number_
static OSStatus on_service_restarted(AudioObjectID in_object_id, UInt32 in_number_addresses, static OSStatus on_service_restarted(AudioObjectID in_object_id, UInt32 in_number_addresses,
const AudioObjectPropertyAddress in_addresses[], void *in_client_data) const AudioObjectPropertyAddress in_addresses[], void *in_client_data)
{ {
SoundIoPrivate *si = (SoundIoPrivate*)in_client_data; struct SoundIoPrivate *si = (struct SoundIoPrivate*)in_client_data;
SoundIoCoreAudio *sica = &si->backend_data.coreaudio; struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
sica->service_restarted.store(true); SOUNDIO_ATOMIC_STORE(sica->service_restarted, true);
soundio_os_cond_signal(sica->scan_devices_cond, nullptr); soundio_os_cond_signal(sica->scan_devices_cond, NULL);
return noErr; return noErr;
} }
static void unsubscribe_device_listeners(SoundIoPrivate *si) { static void unsubscribe_device_listeners(struct SoundIoPrivate *si) {
SoundIoCoreAudio *sica = &si->backend_data.coreaudio; struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
for (int device_index = 0; device_index < sica->registered_listeners.length; device_index += 1) { for (int device_index = 0; device_index < sica->registered_listeners.length; device_index += 1) {
AudioDeviceID device_id = sica->registered_listeners.at(device_index); AudioDeviceID device_id = SoundIoListAudioDeviceID_val_at(&sica->registered_listeners, device_index);
for (int i = 0; i < array_length(device_listen_props); i += 1) { for (int i = 0; i < ARRAY_LENGTH(device_listen_props); i += 1) {
AudioObjectRemovePropertyListener(device_id, &device_listen_props[i], AudioObjectRemovePropertyListener(device_id, &device_listen_props[i],
on_devices_changed, si); on_devices_changed, si);
} }
} }
sica->registered_listeners.clear(); SoundIoListAudioDeviceID_clear(&sica->registered_listeners);
} }
static void destroy_ca(struct SoundIoPrivate *si) { static void destroy_ca(struct SoundIoPrivate *si) {
SoundIoCoreAudio *sica = &si->backend_data.coreaudio; struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
AudioObjectPropertyAddress prop_address = { AudioObjectPropertyAddress prop_address = {
kAudioHardwarePropertyDevices, kAudioHardwarePropertyDevices,
@ -147,11 +149,11 @@ static void destroy_ca(struct SoundIoPrivate *si) {
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop_address, on_service_restarted, si); AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop_address, on_service_restarted, si);
unsubscribe_device_listeners(si); unsubscribe_device_listeners(si);
sica->registered_listeners.deinit(); SoundIoListAudioDeviceID_deinit(&sica->registered_listeners);
if (sica->thread) { if (sica->thread) {
sica->abort_flag.clear(); atomic_flag_clear(&sica->abort_flag);
soundio_os_cond_signal(sica->scan_devices_cond, nullptr); soundio_os_cond_signal(sica->scan_devices_cond, NULL);
soundio_os_thread_destroy(sica->thread); soundio_os_thread_destroy(sica->thread);
} }
@ -178,7 +180,7 @@ static int from_cf_string(CFStringRef string_ref, char **out_str, int *out_str_l
CFIndex length = CFStringGetLength(string_ref); CFIndex length = CFStringGetLength(string_ref);
CFIndex max_size = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8); CFIndex max_size = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
char *buf = allocate_nonzero<char>(max_size); char *buf = ALLOCATE_NONZERO(char, max_size);
if (!buf) if (!buf)
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
@ -192,12 +194,12 @@ static int from_cf_string(CFStringRef string_ref, char **out_str, int *out_str_l
return 0; return 0;
} }
static int aim_to_scope(SoundIoDeviceAim aim) { static int aim_to_scope(enum SoundIoDeviceAim aim) {
return (aim == SoundIoDeviceAimInput) ? return (aim == SoundIoDeviceAimInput) ?
kAudioObjectPropertyScopeInput : kAudioObjectPropertyScopeOutput; kAudioObjectPropertyScopeInput : kAudioObjectPropertyScopeOutput;
} }
static SoundIoChannelId from_channel_descr(const AudioChannelDescription *descr) { static enum SoundIoChannelId from_channel_descr(const AudioChannelDescription *descr) {
switch (descr->mChannelLabel) { switch (descr->mChannelLabel) {
default: return SoundIoChannelIdInvalid; default: return SoundIoChannelIdInvalid;
case kAudioChannelLabel_Left: return SoundIoChannelIdFrontLeft; case kAudioChannelLabel_Left: return SoundIoChannelIdFrontLeft;
@ -274,7 +276,7 @@ static SoundIoChannelId from_channel_descr(const AudioChannelDescription *descr)
// * SoundIoErrorIncompatibleDevice // * SoundIoErrorIncompatibleDevice
// This does not handle all the possible layout enum values and it does not // This does not handle all the possible layout enum values and it does not
// handle channel bitmaps. // handle channel bitmaps.
static int from_coreaudio_layout(const AudioChannelLayout *ca_layout, SoundIoChannelLayout *layout) { static int from_coreaudio_layout(const AudioChannelLayout *ca_layout, struct SoundIoChannelLayout *layout) {
switch (ca_layout->mChannelLayoutTag) { switch (ca_layout->mChannelLayoutTag) {
case kAudioChannelLayoutTag_UseChannelDescriptions: case kAudioChannelLayoutTag_UseChannelDescriptions:
{ {
@ -377,15 +379,15 @@ static bool all_channels_invalid(const struct SoundIoChannelLayout *layout) {
} }
struct RefreshDevices { struct RefreshDevices {
SoundIoPrivate *si; struct SoundIoPrivate *si;
SoundIoDevicesInfo *devices_info; struct SoundIoDevicesInfo *devices_info;
int devices_size; int devices_size;
AudioObjectID *devices; AudioObjectID *devices;
CFStringRef string_ref; CFStringRef string_ref;
char *device_name; char *device_name;
int device_name_len; int device_name_len;
AudioBufferList *buffer_list; AudioBufferList *buffer_list;
SoundIoDevice *device; struct SoundIoDevice *device;
AudioChannelLayout *audio_channel_layout; AudioChannelLayout *audio_channel_layout;
char *device_uid; char *device_uid;
int device_uid_len; int device_uid_len;
@ -393,7 +395,7 @@ struct RefreshDevices {
bool ok; bool ok;
}; };
static void deinit_refresh_devices(RefreshDevices *rd) { static void deinit_refresh_devices(struct RefreshDevices *rd) {
if (!rd->ok) if (!rd->ok)
unsubscribe_device_listeners(rd->si); unsubscribe_device_listeners(rd->si);
soundio_destroy_devices_info(rd->devices_info); soundio_destroy_devices_info(rd->devices_info);
@ -409,8 +411,8 @@ static void deinit_refresh_devices(RefreshDevices *rd) {
} }
static int refresh_devices(struct SoundIoPrivate *si) { static int refresh_devices(struct SoundIoPrivate *si) {
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoCoreAudio *sica = &si->backend_data.coreaudio; struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
UInt32 io_size; UInt32 io_size;
OSStatus os_err; OSStatus os_err;
@ -418,10 +420,10 @@ static int refresh_devices(struct SoundIoPrivate *si) {
unsubscribe_device_listeners(si); unsubscribe_device_listeners(si);
RefreshDevices rd = {0}; struct RefreshDevices rd = {0};
rd.si = si; rd.si = si;
if (!(rd.devices_info = allocate<SoundIoDevicesInfo>(1))) { if (!(rd.devices_info = ALLOCATE(struct SoundIoDevicesInfo, 1))) {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
@ -433,7 +435,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
}; };
if ((os_err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, if ((os_err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
&prop_address, 0, nullptr, &io_size))) &prop_address, 0, NULL, &io_size)))
{ {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
@ -445,13 +447,13 @@ static int refresh_devices(struct SoundIoPrivate *si) {
int device_count = io_size / (UInt32)sizeof(AudioObjectID); int device_count = io_size / (UInt32)sizeof(AudioObjectID);
if (device_count >= 1) { if (device_count >= 1) {
rd.devices_size = io_size; rd.devices_size = io_size;
rd.devices = (AudioObjectID *)allocate<char>(rd.devices_size); rd.devices = (AudioObjectID *)ALLOCATE(char, rd.devices_size);
if (!rd.devices) { if (!rd.devices) {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
if ((os_err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_address, 0, nullptr, if ((os_err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_address, 0, NULL,
&io_size, rd.devices))) &io_size, rd.devices)))
{ {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
@ -462,7 +464,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
io_size = sizeof(AudioObjectID); io_size = sizeof(AudioObjectID);
prop_address.mSelector = kAudioHardwarePropertyDefaultInputDevice; prop_address.mSelector = kAudioHardwarePropertyDefaultInputDevice;
if ((os_err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_address, if ((os_err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_address,
0, nullptr, &io_size, &default_input_id))) 0, NULL, &io_size, &default_input_id)))
{ {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
@ -471,7 +473,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
io_size = sizeof(AudioObjectID); io_size = sizeof(AudioObjectID);
prop_address.mSelector = kAudioHardwarePropertyDefaultOutputDevice; prop_address.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
if ((os_err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_address, if ((os_err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_address,
0, nullptr, &io_size, &default_output_id))) 0, NULL, &io_size, &default_output_id)))
{ {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
@ -481,8 +483,8 @@ static int refresh_devices(struct SoundIoPrivate *si) {
for (int device_i = 0; device_i < device_count; device_i += 1) { for (int device_i = 0; device_i < device_count; device_i += 1) {
AudioObjectID device_id = rd.devices[device_i]; AudioObjectID device_id = rd.devices[device_i];
for (int i = 0; i < array_length(device_listen_props); i += 1) { for (int i = 0; i < ARRAY_LENGTH(device_listen_props); i += 1) {
if ((err = sica->registered_listeners.add_one())) { if ((err = SoundIoListAudioDeviceID_add_one(&sica->registered_listeners))) {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
@ -492,7 +494,8 @@ static int refresh_devices(struct SoundIoPrivate *si) {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
sica->registered_listeners.last() = device_id; AudioDeviceID *last_device_id = SoundIoListAudioDeviceID_last_ptr(&sica->registered_listeners);
*last_device_id = device_id;
} }
prop_address.mSelector = kAudioObjectPropertyName; prop_address.mSelector = kAudioObjectPropertyName;
@ -501,17 +504,17 @@ static int refresh_devices(struct SoundIoPrivate *si) {
io_size = sizeof(CFStringRef); io_size = sizeof(CFStringRef);
if (rd.string_ref) { if (rd.string_ref) {
CFRelease(rd.string_ref); CFRelease(rd.string_ref);
rd.string_ref = nullptr; rd.string_ref = NULL;
} }
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address,
0, nullptr, &io_size, &rd.string_ref))) 0, NULL, &io_size, &rd.string_ref)))
{ {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
free(rd.device_name); free(rd.device_name);
rd.device_name = nullptr; rd.device_name = NULL;
if ((err = from_cf_string(rd.string_ref, &rd.device_name, &rd.device_name_len))) { if ((err = from_cf_string(rd.string_ref, &rd.device_name, &rd.device_name_len))) {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return err; return err;
@ -523,43 +526,43 @@ static int refresh_devices(struct SoundIoPrivate *si) {
io_size = sizeof(CFStringRef); io_size = sizeof(CFStringRef);
if (rd.string_ref) { if (rd.string_ref) {
CFRelease(rd.string_ref); CFRelease(rd.string_ref);
rd.string_ref = nullptr; rd.string_ref = NULL;
} }
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address,
0, nullptr, &io_size, &rd.string_ref))) 0, NULL, &io_size, &rd.string_ref)))
{ {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
free(rd.device_uid); free(rd.device_uid);
rd.device_uid = nullptr; rd.device_uid = NULL;
if ((err = from_cf_string(rd.string_ref, &rd.device_uid, &rd.device_uid_len))) { if ((err = from_cf_string(rd.string_ref, &rd.device_uid, &rd.device_uid_len))) {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return err; return err;
} }
for (int aim_i = 0; aim_i < array_length(aims); aim_i += 1) { for (int aim_i = 0; aim_i < ARRAY_LENGTH(aims); aim_i += 1) {
SoundIoDeviceAim aim = aims[aim_i]; enum SoundIoDeviceAim aim = aims[aim_i];
io_size = 0; io_size = 0;
prop_address.mSelector = kAudioDevicePropertyStreamConfiguration; prop_address.mSelector = kAudioDevicePropertyStreamConfiguration;
prop_address.mScope = aim_to_scope(aim); prop_address.mScope = aim_to_scope(aim);
prop_address.mElement = kAudioObjectPropertyElementMaster; prop_address.mElement = kAudioObjectPropertyElementMaster;
if ((os_err = AudioObjectGetPropertyDataSize(device_id, &prop_address, 0, nullptr, &io_size))) { if ((os_err = AudioObjectGetPropertyDataSize(device_id, &prop_address, 0, NULL, &io_size))) {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
free(rd.buffer_list); free(rd.buffer_list);
rd.buffer_list = (AudioBufferList*)allocate_nonzero<char>(io_size); rd.buffer_list = (AudioBufferList*)ALLOCATE_NONZERO(char, io_size);
if (!rd.buffer_list) { if (!rd.buffer_list) {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, nullptr, if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, NULL,
&io_size, rd.buffer_list))) &io_size, rd.buffer_list)))
{ {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
@ -574,12 +577,12 @@ static int refresh_devices(struct SoundIoPrivate *si) {
if (channel_count <= 0) if (channel_count <= 0)
continue; continue;
SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1); struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
if (!dev) { if (!dev) {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio; struct SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
dca->device_id = device_id; dca->device_id = device_id;
assert(!rd.device); assert(!rd.device);
rd.device = &dev->pub; rd.device = &dev->pub;
@ -599,14 +602,14 @@ static int refresh_devices(struct SoundIoPrivate *si) {
prop_address.mScope = aim_to_scope(aim); prop_address.mScope = aim_to_scope(aim);
prop_address.mElement = kAudioObjectPropertyElementMaster; prop_address.mElement = kAudioObjectPropertyElementMaster;
if (!(os_err = AudioObjectGetPropertyDataSize(device_id, &prop_address, if (!(os_err = AudioObjectGetPropertyDataSize(device_id, &prop_address,
0, nullptr, &io_size))) 0, NULL, &io_size)))
{ {
rd.audio_channel_layout = (AudioChannelLayout *)allocate<char>(io_size); rd.audio_channel_layout = (AudioChannelLayout *)ALLOCATE(char, io_size);
if (!rd.audio_channel_layout) { if (!rd.audio_channel_layout) {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, nullptr, if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, NULL,
&io_size, rd.audio_channel_layout))) &io_size, rd.audio_channel_layout)))
{ {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
@ -635,7 +638,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
prop_address.mElement = kAudioObjectPropertyElementMaster; prop_address.mElement = kAudioObjectPropertyElementMaster;
io_size = sizeof(double); io_size = sizeof(double);
double value; double value;
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, nullptr, if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, NULL,
&io_size, &value))) &io_size, &value)))
{ {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
@ -659,21 +662,21 @@ static int refresh_devices(struct SoundIoPrivate *si) {
prop_address.mSelector = kAudioDevicePropertyAvailableNominalSampleRates; prop_address.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
prop_address.mScope = aim_to_scope(aim); prop_address.mScope = aim_to_scope(aim);
prop_address.mElement = kAudioObjectPropertyElementMaster; prop_address.mElement = kAudioObjectPropertyElementMaster;
if ((os_err = AudioObjectGetPropertyDataSize(device_id, &prop_address, 0, nullptr, if ((os_err = AudioObjectGetPropertyDataSize(device_id, &prop_address, 0, NULL,
&io_size))) &io_size)))
{ {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
int avr_array_len = io_size / sizeof(AudioValueRange); int avr_array_len = io_size / sizeof(AudioValueRange);
rd.avr_array = (AudioValueRange*)allocate<char>(io_size); rd.avr_array = (AudioValueRange*)ALLOCATE(char, io_size);
if (!rd.avr_array) { if (!rd.avr_array) {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, nullptr, if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, NULL,
&io_size, rd.avr_array))) &io_size, rd.avr_array)))
{ {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
@ -687,7 +690,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
rd.device->sample_rates[0].max = (int)(rd.avr_array[0].mMaximum); rd.device->sample_rates[0].max = (int)(rd.avr_array[0].mMaximum);
} else { } else {
rd.device->sample_rate_count = avr_array_len; rd.device->sample_rate_count = avr_array_len;
rd.device->sample_rates = allocate<SoundIoSampleRateRange>(avr_array_len); rd.device->sample_rates = ALLOCATE(struct SoundIoSampleRateRange, avr_array_len);
if (!rd.device->sample_rates) { if (!rd.device->sample_rates) {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
@ -707,7 +710,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
prop_address.mElement = kAudioObjectPropertyElementMaster; prop_address.mElement = kAudioObjectPropertyElementMaster;
io_size = sizeof(UInt32); io_size = sizeof(UInt32);
UInt32 buffer_frame_size; UInt32 buffer_frame_size;
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, nullptr, if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, NULL,
&io_size, &buffer_frame_size))) &io_size, &buffer_frame_size)))
{ {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
@ -721,7 +724,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
prop_address.mElement = kAudioObjectPropertyElementMaster; prop_address.mElement = kAudioObjectPropertyElementMaster;
io_size = sizeof(AudioValueRange); io_size = sizeof(AudioValueRange);
AudioValueRange avr; AudioValueRange avr;
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, nullptr, if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, NULL,
&io_size, &avr))) &io_size, &avr)))
{ {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
@ -734,14 +737,14 @@ static int refresh_devices(struct SoundIoPrivate *si) {
prop_address.mScope = aim_to_scope(aim); prop_address.mScope = aim_to_scope(aim);
prop_address.mElement = kAudioObjectPropertyElementMaster; prop_address.mElement = kAudioObjectPropertyElementMaster;
io_size = sizeof(UInt32); io_size = sizeof(UInt32);
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, nullptr, if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, NULL,
&io_size, &dca->latency_frames))) &io_size, &dca->latency_frames)))
{ {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
SoundIoList<SoundIoDevice *> *device_list; struct SoundIoListDevicePtr *device_list;
if (rd.device->aim == SoundIoDeviceAimOutput) { if (rd.device->aim == SoundIoDeviceAimOutput) {
device_list = &rd.devices_info->output_devices; device_list = &rd.devices_info->output_devices;
if (device_id == default_output_id) if (device_id == default_output_id)
@ -753,11 +756,11 @@ static int refresh_devices(struct SoundIoPrivate *si) {
rd.devices_info->default_input_index = device_list->length; rd.devices_info->default_input_index = device_list->length;
} }
if ((err = device_list->append(rd.device))) { if ((err = SoundIoListDevicePtr_append(device_list, rd.device))) {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return err; return err;
} }
rd.device = nullptr; rd.device = NULL;
} }
} }
@ -766,36 +769,36 @@ static int refresh_devices(struct SoundIoPrivate *si) {
sica->ready_devices_info = rd.devices_info; sica->ready_devices_info = rd.devices_info;
soundio_os_mutex_unlock(sica->mutex); soundio_os_mutex_unlock(sica->mutex);
rd.devices_info = nullptr; rd.devices_info = NULL;
rd.ok = true; rd.ok = true;
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return 0; return 0;
} }
static void shutdown_backend(SoundIoPrivate *si, int err) { static void shutdown_backend(struct SoundIoPrivate *si, int err) {
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoCoreAudio *sica = &si->backend_data.coreaudio; struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
soundio_os_mutex_lock(sica->mutex); soundio_os_mutex_lock(sica->mutex);
sica->shutdown_err = err; sica->shutdown_err = err;
sica->have_devices_flag.store(true); SOUNDIO_ATOMIC_STORE(sica->have_devices_flag, true);
soundio_os_mutex_unlock(sica->mutex); soundio_os_mutex_unlock(sica->mutex);
soundio_os_cond_signal(sica->cond, nullptr); soundio_os_cond_signal(sica->cond, NULL);
soundio_os_cond_signal(sica->have_devices_cond, nullptr); soundio_os_cond_signal(sica->have_devices_cond, NULL);
soundio->on_events_signal(soundio); soundio->on_events_signal(soundio);
} }
static void flush_events_ca(struct SoundIoPrivate *si) { static void flush_events_ca(struct SoundIoPrivate *si) {
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoCoreAudio *sica = &si->backend_data.coreaudio; struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
// block until have devices // block until have devices
while (!sica->have_devices_flag.load()) while (!SOUNDIO_ATOMIC_LOAD(sica->have_devices_flag))
soundio_os_cond_wait(sica->have_devices_cond, nullptr); soundio_os_cond_wait(sica->have_devices_cond, NULL);
bool change = false; bool change = false;
bool cb_shutdown = false; bool cb_shutdown = false;
SoundIoDevicesInfo *old_devices_info = nullptr; struct SoundIoDevicesInfo *old_devices_info = NULL;
soundio_os_mutex_lock(sica->mutex); soundio_os_mutex_lock(sica->mutex);
@ -805,7 +808,7 @@ static void flush_events_ca(struct SoundIoPrivate *si) {
} else if (sica->ready_devices_info) { } else if (sica->ready_devices_info) {
old_devices_info = si->safe_devices_info; old_devices_info = si->safe_devices_info;
si->safe_devices_info = sica->ready_devices_info; si->safe_devices_info = sica->ready_devices_info;
sica->ready_devices_info = nullptr; sica->ready_devices_info = NULL;
change = true; change = true;
} }
@ -820,65 +823,65 @@ static void flush_events_ca(struct SoundIoPrivate *si) {
} }
static void wait_events_ca(struct SoundIoPrivate *si) { static void wait_events_ca(struct SoundIoPrivate *si) {
SoundIoCoreAudio *sica = &si->backend_data.coreaudio; struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
flush_events_ca(si); flush_events_ca(si);
soundio_os_cond_wait(sica->cond, nullptr); soundio_os_cond_wait(sica->cond, NULL);
} }
static void wakeup_ca(struct SoundIoPrivate *si) { static void wakeup_ca(struct SoundIoPrivate *si) {
SoundIoCoreAudio *sica = &si->backend_data.coreaudio; struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
soundio_os_cond_signal(sica->cond, nullptr); soundio_os_cond_signal(sica->cond, NULL);
} }
static void force_device_scan_ca(struct SoundIoPrivate *si) { static void force_device_scan_ca(struct SoundIoPrivate *si) {
SoundIoCoreAudio *sica = &si->backend_data.coreaudio; struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
sica->device_scan_queued.store(true); SOUNDIO_ATOMIC_STORE(sica->device_scan_queued, true);
soundio_os_cond_signal(sica->scan_devices_cond, nullptr); soundio_os_cond_signal(sica->scan_devices_cond, NULL);
} }
static void device_thread_run(void *arg) { static void device_thread_run(void *arg) {
SoundIoPrivate *si = (SoundIoPrivate *)arg; struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoCoreAudio *sica = &si->backend_data.coreaudio; struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
int err; int err;
for (;;) { for (;;) {
if (!sica->abort_flag.test_and_set()) if (!atomic_flag_test_and_set(&sica->abort_flag))
break; break;
if (sica->service_restarted.load()) { if (SOUNDIO_ATOMIC_LOAD(sica->service_restarted)) {
shutdown_backend(si, SoundIoErrorBackendDisconnected); shutdown_backend(si, SoundIoErrorBackendDisconnected);
return; return;
} }
if (sica->device_scan_queued.exchange(false)) { if (SOUNDIO_ATOMIC_EXCHANGE(sica->device_scan_queued, false)) {
err = refresh_devices(si); err = refresh_devices(si);
if (err) { if (err) {
shutdown_backend(si, err); shutdown_backend(si, err);
return; return;
} }
if (!sica->have_devices_flag.exchange(true)) if (!SOUNDIO_ATOMIC_EXCHANGE(sica->have_devices_flag, true))
soundio_os_cond_signal(sica->have_devices_cond, nullptr); soundio_os_cond_signal(sica->have_devices_cond, NULL);
soundio_os_cond_signal(sica->cond, nullptr); soundio_os_cond_signal(sica->cond, NULL);
soundio->on_events_signal(soundio); soundio->on_events_signal(soundio);
} }
soundio_os_cond_wait(sica->scan_devices_cond, nullptr); soundio_os_cond_wait(sica->scan_devices_cond, NULL);
} }
} }
static OSStatus on_outstream_device_overload(AudioObjectID in_object_id, UInt32 in_number_addresses, static OSStatus on_outstream_device_overload(AudioObjectID in_object_id, UInt32 in_number_addresses,
const AudioObjectPropertyAddress in_addresses[], void *in_client_data) const AudioObjectPropertyAddress in_addresses[], void *in_client_data)
{ {
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)in_client_data; struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)in_client_data;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
outstream->underflow_callback(outstream); outstream->underflow_callback(outstream);
return noErr; return noErr;
} }
static void outstream_destroy_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) { static void outstream_destroy_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio; struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
SoundIoDevice *device = outstream->device; struct SoundIoDevice *device = outstream->device;
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device; struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio; struct SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
AudioObjectPropertyAddress prop_address = { AudioObjectPropertyAddress prop_address = {
kAudioDeviceProcessorOverload, kAudioDeviceProcessorOverload,
@ -890,7 +893,7 @@ static void outstream_destroy_ca(struct SoundIoPrivate *si, struct SoundIoOutStr
if (osca->instance) { if (osca->instance) {
AudioOutputUnitStop(osca->instance); AudioOutputUnitStop(osca->instance);
AudioComponentInstanceDispose(osca->instance); AudioComponentInstanceDispose(osca->instance);
osca->instance = nullptr; osca->instance = NULL;
} }
} }
@ -898,30 +901,30 @@ static OSStatus write_callback_ca(void *userdata, AudioUnitRenderActionFlags *io
const AudioTimeStamp *in_time_stamp, UInt32 in_bus_number, UInt32 in_number_frames, const AudioTimeStamp *in_time_stamp, UInt32 in_bus_number, UInt32 in_number_frames,
AudioBufferList *io_data) AudioBufferList *io_data)
{ {
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *) userdata; struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *) userdata;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio; struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
osca->io_data = io_data; osca->io_data = io_data;
osca->buffer_index = 0; osca->buffer_index = 0;
osca->frames_left = in_number_frames; osca->frames_left = in_number_frames;
outstream->write_callback(outstream, osca->frames_left, osca->frames_left); outstream->write_callback(outstream, osca->frames_left, osca->frames_left);
osca->io_data = nullptr; osca->io_data = NULL;
return noErr; return noErr;
} }
static int outstream_open_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) { static int outstream_open_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio; struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
SoundIoDevice *device = outstream->device; struct SoundIoDevice *device = outstream->device;
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device; struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio; struct SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
if (outstream->software_latency == 0.0) if (outstream->software_latency == 0.0)
outstream->software_latency = device->software_latency_current; outstream->software_latency = device->software_latency_current;
outstream->software_latency = clamp( outstream->software_latency = soundio_double_clamp(
device->software_latency_min, device->software_latency_min,
outstream->software_latency, outstream->software_latency,
device->software_latency_max); device->software_latency_max);
@ -931,7 +934,7 @@ static int outstream_open_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamP
desc.componentSubType = kAudioUnitSubType_HALOutput; desc.componentSubType = kAudioUnitSubType_HALOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentManufacturer = kAudioUnitManufacturer_Apple;
AudioComponent component = AudioComponentFindNext(nullptr, &desc); AudioComponent component = AudioComponentFindNext(NULL, &desc);
if (!component) { if (!component) {
outstream_destroy_ca(si, os); outstream_destroy_ca(si, os);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
@ -987,7 +990,7 @@ static int outstream_open_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamP
}; };
UInt32 buffer_frame_size = outstream->software_latency * outstream->sample_rate; UInt32 buffer_frame_size = outstream->software_latency * outstream->sample_rate;
if ((os_err = AudioObjectSetPropertyData(dca->device_id, &prop_address, if ((os_err = AudioObjectSetPropertyData(dca->device_id, &prop_address,
0, nullptr, sizeof(UInt32), &buffer_frame_size))) 0, NULL, sizeof(UInt32), &buffer_frame_size)))
{ {
outstream_destroy_ca(si, os); outstream_destroy_ca(si, os);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
@ -1009,7 +1012,7 @@ static int outstream_open_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamP
} }
static int outstream_pause_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) { static int outstream_pause_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio; struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
OSStatus os_err; OSStatus os_err;
if (pause) { if (pause) {
if ((os_err = AudioOutputUnitStop(osca->instance))) { if ((os_err = AudioOutputUnitStop(osca->instance))) {
@ -1029,10 +1032,10 @@ static int outstream_start_ca(struct SoundIoPrivate *si, struct SoundIoOutStream
} }
static int outstream_begin_write_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, static int outstream_begin_write_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
SoundIoChannelArea **out_areas, int *frame_count) struct SoundIoChannelArea **out_areas, int *frame_count)
{ {
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio; struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
if (osca->buffer_index >= osca->io_data->mNumberBuffers) if (osca->buffer_index >= osca->io_data->mNumberBuffers)
return SoundIoErrorInvalid; return SoundIoErrorInvalid;
@ -1054,7 +1057,7 @@ static int outstream_begin_write_ca(struct SoundIoPrivate *si, struct SoundIoOut
} }
static int outstream_end_write_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) { static int outstream_end_write_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio; struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
osca->buffer_index += 1; osca->buffer_index += 1;
osca->frames_left -= osca->write_frame_count; osca->frames_left -= osca->write_frame_count;
assert(osca->frames_left >= 0); assert(osca->frames_left >= 0);
@ -1068,7 +1071,7 @@ static int outstream_clear_buffer_ca(struct SoundIoPrivate *si, struct SoundIoOu
static int outstream_get_latency_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, static int outstream_get_latency_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
double *out_latency) double *out_latency)
{ {
SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio; struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
*out_latency = osca->hardware_latency; *out_latency = osca->hardware_latency;
return 0; return 0;
} }
@ -1076,18 +1079,18 @@ static int outstream_get_latency_ca(struct SoundIoPrivate *si, struct SoundIoOut
static OSStatus on_instream_device_overload(AudioObjectID in_object_id, UInt32 in_number_addresses, static OSStatus on_instream_device_overload(AudioObjectID in_object_id, UInt32 in_number_addresses,
const AudioObjectPropertyAddress in_addresses[], void *in_client_data) const AudioObjectPropertyAddress in_addresses[], void *in_client_data)
{ {
SoundIoInStreamPrivate *os = (SoundIoInStreamPrivate *)in_client_data; struct SoundIoInStreamPrivate *os = (struct SoundIoInStreamPrivate *)in_client_data;
SoundIoInStream *instream = &os->pub; struct SoundIoInStream *instream = &os->pub;
instream->overflow_callback(instream); instream->overflow_callback(instream);
return noErr; return noErr;
} }
static void instream_destroy_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) { static void instream_destroy_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio; struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
SoundIoDevice *device = instream->device; struct SoundIoDevice *device = instream->device;
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device; struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio; struct SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
AudioObjectPropertyAddress prop_address = { AudioObjectPropertyAddress prop_address = {
kAudioDeviceProcessorOverload, kAudioDeviceProcessorOverload,
@ -1099,23 +1102,23 @@ static void instream_destroy_ca(struct SoundIoPrivate *si, struct SoundIoInStrea
if (isca->instance) { if (isca->instance) {
AudioOutputUnitStop(isca->instance); AudioOutputUnitStop(isca->instance);
AudioComponentInstanceDispose(isca->instance); AudioComponentInstanceDispose(isca->instance);
isca->instance = nullptr; isca->instance = NULL;
} }
free(isca->buffer_list); free(isca->buffer_list);
isca->buffer_list = nullptr; isca->buffer_list = NULL;
} }
static OSStatus read_callback_ca(void *userdata, AudioUnitRenderActionFlags *io_action_flags, static OSStatus read_callback_ca(void *userdata, AudioUnitRenderActionFlags *io_action_flags,
const AudioTimeStamp *in_time_stamp, UInt32 in_bus_number, UInt32 in_number_frames, const AudioTimeStamp *in_time_stamp, UInt32 in_bus_number, UInt32 in_number_frames,
AudioBufferList *io_data) AudioBufferList *io_data)
{ {
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *) userdata; struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *) userdata;
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio; struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
for (int i = 0; i < isca->buffer_list->mNumberBuffers; i += 1) { for (int i = 0; i < isca->buffer_list->mNumberBuffers; i += 1) {
isca->buffer_list->mBuffers[i].mData = nullptr; isca->buffer_list->mBuffers[i].mData = NULL;
} }
OSStatus os_err; OSStatus os_err;
@ -1151,18 +1154,18 @@ static OSStatus read_callback_ca(void *userdata, AudioUnitRenderActionFlags *io_
} }
static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) { static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio; struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
SoundIoDevice *device = instream->device; struct SoundIoDevice *device = instream->device;
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device; struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio; struct SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
UInt32 io_size; UInt32 io_size;
OSStatus os_err; OSStatus os_err;
if (instream->software_latency == 0.0) if (instream->software_latency == 0.0)
instream->software_latency = device->software_latency_current; instream->software_latency = device->software_latency_current;
instream->software_latency = clamp( instream->software_latency = soundio_double_clamp(
device->software_latency_min, device->software_latency_min,
instream->software_latency, instream->software_latency,
device->software_latency_max); device->software_latency_max);
@ -1174,20 +1177,20 @@ static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPri
prop_address.mElement = kAudioObjectPropertyElementMaster; prop_address.mElement = kAudioObjectPropertyElementMaster;
io_size = 0; io_size = 0;
if ((os_err = AudioObjectGetPropertyDataSize(dca->device_id, &prop_address, if ((os_err = AudioObjectGetPropertyDataSize(dca->device_id, &prop_address,
0, nullptr, &io_size))) 0, NULL, &io_size)))
{ {
instream_destroy_ca(si, is); instream_destroy_ca(si, is);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
isca->buffer_list = (AudioBufferList*)allocate_nonzero<char>(io_size); isca->buffer_list = (AudioBufferList*)ALLOCATE_NONZERO(char, io_size);
if (!isca->buffer_list) { if (!isca->buffer_list) {
instream_destroy_ca(si, is); instream_destroy_ca(si, is);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
if ((os_err = AudioObjectGetPropertyData(dca->device_id, &prop_address, if ((os_err = AudioObjectGetPropertyData(dca->device_id, &prop_address,
0, nullptr, &io_size, isca->buffer_list))) 0, NULL, &io_size, isca->buffer_list)))
{ {
instream_destroy_ca(si, is); instream_destroy_ca(si, is);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
@ -1199,7 +1202,7 @@ static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPri
desc.componentSubType = kAudioUnitSubType_HALOutput; desc.componentSubType = kAudioUnitSubType_HALOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentManufacturer = kAudioUnitManufacturer_Apple;
AudioComponent component = AudioComponentFindNext(nullptr, &desc); AudioComponent component = AudioComponentFindNext(NULL, &desc);
if (!component) { if (!component) {
instream_destroy_ca(si, is); instream_destroy_ca(si, is);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
@ -1270,7 +1273,7 @@ static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPri
prop_address.mElement = INPUT_ELEMENT; prop_address.mElement = INPUT_ELEMENT;
UInt32 buffer_frame_size = instream->software_latency * instream->sample_rate; UInt32 buffer_frame_size = instream->software_latency * instream->sample_rate;
if ((os_err = AudioObjectSetPropertyData(dca->device_id, &prop_address, if ((os_err = AudioObjectSetPropertyData(dca->device_id, &prop_address,
0, nullptr, sizeof(UInt32), &buffer_frame_size))) 0, NULL, sizeof(UInt32), &buffer_frame_size)))
{ {
instream_destroy_ca(si, is); instream_destroy_ca(si, is);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
@ -1291,7 +1294,7 @@ static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPri
} }
static int instream_pause_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) { static int instream_pause_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio; struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
OSStatus os_err; OSStatus os_err;
if (pause) { if (pause) {
if ((os_err = AudioOutputUnitStop(isca->instance))) { if ((os_err = AudioOutputUnitStop(isca->instance))) {
@ -1311,9 +1314,9 @@ static int instream_start_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPr
} }
static int instream_begin_read_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, static int instream_begin_read_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
SoundIoChannelArea **out_areas, int *frame_count) struct SoundIoChannelArea **out_areas, int *frame_count)
{ {
SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio; struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
if (*frame_count != isca->frames_left) if (*frame_count != isca->frames_left)
return SoundIoErrorInvalid; return SoundIoErrorInvalid;
@ -1324,7 +1327,7 @@ static int instream_begin_read_ca(struct SoundIoPrivate *si, struct SoundIoInStr
} }
static int instream_end_read_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) { static int instream_end_read_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio; struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
isca->frames_left = 0; isca->frames_left = 0;
return 0; return 0;
} }
@ -1332,20 +1335,20 @@ static int instream_end_read_ca(struct SoundIoPrivate *si, struct SoundIoInStrea
static int instream_get_latency_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, static int instream_get_latency_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
double *out_latency) double *out_latency)
{ {
SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio; struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
*out_latency = isca->hardware_latency; *out_latency = isca->hardware_latency;
return 0; return 0;
} }
int soundio_coreaudio_init(SoundIoPrivate *si) { int soundio_coreaudio_init(struct SoundIoPrivate *si) {
SoundIoCoreAudio *sica = &si->backend_data.coreaudio; struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
int err; int err;
sica->have_devices_flag.store(false); SOUNDIO_ATOMIC_STORE(sica->have_devices_flag, false);
sica->device_scan_queued.store(true); SOUNDIO_ATOMIC_STORE(sica->device_scan_queued, true);
sica->service_restarted.store(false); SOUNDIO_ATOMIC_STORE(sica->service_restarted, false);
sica->abort_flag.test_and_set(); atomic_flag_test_and_set(&sica->abort_flag);
sica->mutex = soundio_os_mutex_create(); sica->mutex = soundio_os_mutex_create();
if (!sica->mutex) { if (!sica->mutex) {
@ -1391,7 +1394,7 @@ int soundio_coreaudio_init(SoundIoPrivate *si) {
return SoundIoErrorSystemResources; return SoundIoErrorSystemResources;
} }
if ((err = soundio_os_thread_create(device_thread_run, si, nullptr, &sica->thread))) { if ((err = soundio_os_thread_create(device_thread_run, si, NULL, &sica->thread))) {
destroy_ca(si); destroy_ca(si);
return err; return err;
} }

View file

@ -5,17 +5,18 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#ifndef SOUNDIO_COREAUDIO_HPP #ifndef SOUNDIO_COREAUDIO_H
#define SOUNDIO_COREAUDIO_HPP #define SOUNDIO_COREAUDIO_H
#include "soundio_private.h" #include "soundio_internal.h"
#include "os.h" #include "os.h"
#include "atomics.hpp" #include "list.h"
#include "list.hpp" #include "atomics.h"
#include <CoreAudio/CoreAudio.h> #include <CoreAudio/CoreAudio.h>
#include <AudioUnit/AudioUnit.h> #include <AudioUnit/AudioUnit.h>
struct SoundIoPrivate;
int soundio_coreaudio_init(struct SoundIoPrivate *si); int soundio_coreaudio_init(struct SoundIoPrivate *si);
struct SoundIoDeviceCoreAudio { struct SoundIoDeviceCoreAudio {
@ -23,21 +24,23 @@ struct SoundIoDeviceCoreAudio {
UInt32 latency_frames; UInt32 latency_frames;
}; };
SOUNDIO_MAKE_LIST_STRUCT(AudioDeviceID, SoundIoListAudioDeviceID, SOUNDIO_LIST_STATIC)
struct SoundIoCoreAudio { struct SoundIoCoreAudio {
SoundIoOsMutex *mutex; struct SoundIoOsMutex *mutex;
SoundIoOsCond *cond; struct SoundIoOsCond *cond;
struct SoundIoOsThread *thread; struct SoundIoOsThread *thread;
atomic_flag abort_flag; atomic_flag abort_flag;
// this one is ready to be read with flush_events. protected by mutex // this one is ready to be read with flush_events. protected by mutex
struct SoundIoDevicesInfo *ready_devices_info; struct SoundIoDevicesInfo *ready_devices_info;
atomic_bool have_devices_flag; struct SoundIoAtomicBool have_devices_flag;
SoundIoOsCond *have_devices_cond; struct SoundIoOsCond *have_devices_cond;
SoundIoOsCond *scan_devices_cond; struct SoundIoOsCond *scan_devices_cond;
SoundIoList<AudioDeviceID> registered_listeners; struct SoundIoListAudioDeviceID registered_listeners;
atomic_bool device_scan_queued; struct SoundIoAtomicBool device_scan_queued;
atomic_bool service_restarted; struct SoundIoAtomicBool service_restarted;
int shutdown_err; int shutdown_err;
bool emitted_shutdown_cb; bool emitted_shutdown_cb;
}; };
@ -49,7 +52,7 @@ struct SoundIoOutStreamCoreAudio {
int frames_left; int frames_left;
int write_frame_count; int write_frame_count;
double hardware_latency; double hardware_latency;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS]; struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
}; };
struct SoundIoInStreamCoreAudio { struct SoundIoInStreamCoreAudio {
@ -57,7 +60,7 @@ struct SoundIoInStreamCoreAudio {
AudioBufferList *buffer_list; AudioBufferList *buffer_list;
int frames_left; int frames_left;
double hardware_latency; double hardware_latency;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS]; struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
}; };
#endif #endif

View file

@ -5,16 +5,16 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#include "dummy.hpp" #include "dummy.h"
#include "soundio.hpp" #include "soundio_private.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
static void playback_thread_run(void *arg) { static void playback_thread_run(void *arg) {
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg; struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
SoundIoOutStreamDummy *osd = &os->backend_data.dummy; struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer); int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer);
int free_bytes = soundio_ring_buffer_capacity(&osd->ring_buffer) - fill_bytes; int free_bytes = soundio_ring_buffer_capacity(&osd->ring_buffer) - fill_bytes;
@ -25,14 +25,14 @@ static void playback_thread_run(void *arg) {
double start_time = soundio_os_get_time(); double start_time = soundio_os_get_time();
long frames_consumed = 0; long frames_consumed = 0;
while (osd->abort_flag.test_and_set()) { while (atomic_flag_test_and_set(&osd->abort_flag)) {
double now = soundio_os_get_time(); double now = soundio_os_get_time();
double time_passed = now - start_time; double time_passed = now - start_time;
double next_period = start_time + double next_period = start_time +
ceil_dbl(time_passed / osd->period_duration) * osd->period_duration; ceil_dbl(time_passed / osd->period_duration) * osd->period_duration;
double relative_time = next_period - now; double relative_time = next_period - now;
soundio_os_cond_timed_wait(osd->cond, nullptr, relative_time); soundio_os_cond_timed_wait(osd->cond, NULL, relative_time);
if (!osd->clear_buffer_flag.test_and_set()) { if (!atomic_flag_test_and_set(&osd->clear_buffer_flag)) {
soundio_ring_buffer_clear(&osd->ring_buffer); soundio_ring_buffer_clear(&osd->ring_buffer);
int free_bytes = soundio_ring_buffer_capacity(&osd->ring_buffer); int free_bytes = soundio_ring_buffer_capacity(&osd->ring_buffer);
int free_frames = free_bytes / outstream->bytes_per_frame; int free_frames = free_bytes / outstream->bytes_per_frame;
@ -44,7 +44,7 @@ static void playback_thread_run(void *arg) {
continue; continue;
} }
if (osd->pause_requested.load()) { if (SOUNDIO_ATOMIC_LOAD(osd->pause_requested)) {
start_time = now; start_time = now;
frames_consumed = 0; frames_consumed = 0;
continue; continue;
@ -58,7 +58,7 @@ static void playback_thread_run(void *arg) {
double total_time = soundio_os_get_time() - start_time; double total_time = soundio_os_get_time() - start_time;
long total_frames = total_time * outstream->sample_rate; long total_frames = total_time * outstream->sample_rate;
int frames_to_kill = total_frames - frames_consumed; int frames_to_kill = total_frames - frames_consumed;
int read_count = min(frames_to_kill, fill_frames); int read_count = soundio_int_min(frames_to_kill, fill_frames);
int byte_count = read_count * outstream->bytes_per_frame; int byte_count = read_count * outstream->bytes_per_frame;
soundio_ring_buffer_advance_read_ptr(&osd->ring_buffer, byte_count); soundio_ring_buffer_advance_read_ptr(&osd->ring_buffer, byte_count);
frames_consumed += read_count; frames_consumed += read_count;
@ -78,21 +78,21 @@ static void playback_thread_run(void *arg) {
} }
static void capture_thread_run(void *arg) { static void capture_thread_run(void *arg) {
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg; struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
SoundIoInStreamDummy *isd = &is->backend_data.dummy; struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
long frames_consumed = 0; long frames_consumed = 0;
double start_time = soundio_os_get_time(); double start_time = soundio_os_get_time();
while (isd->abort_flag.test_and_set()) { while (atomic_flag_test_and_set(&isd->abort_flag)) {
double now = soundio_os_get_time(); double now = soundio_os_get_time();
double time_passed = now - start_time; double time_passed = now - start_time;
double next_period = start_time + double next_period = start_time +
ceil_dbl(time_passed / isd->period_duration) * isd->period_duration; ceil_dbl(time_passed / isd->period_duration) * isd->period_duration;
double relative_time = next_period - now; double relative_time = next_period - now;
soundio_os_cond_timed_wait(isd->cond, nullptr, relative_time); soundio_os_cond_timed_wait(isd->cond, NULL, relative_time);
if (isd->pause_requested.load()) { if (SOUNDIO_ATOMIC_LOAD(isd->pause_requested)) {
start_time = now; start_time = now;
frames_consumed = 0; frames_consumed = 0;
continue; continue;
@ -106,7 +106,7 @@ static void capture_thread_run(void *arg) {
double total_time = soundio_os_get_time() - start_time; double total_time = soundio_os_get_time() - start_time;
long total_frames = total_time * instream->sample_rate; long total_frames = total_time * instream->sample_rate;
int frames_to_kill = total_frames - frames_consumed; int frames_to_kill = total_frames - frames_consumed;
int write_count = min(frames_to_kill, free_frames); int write_count = soundio_int_min(frames_to_kill, free_frames);
int byte_count = write_count * instream->bytes_per_frame; int byte_count = write_count * instream->bytes_per_frame;
soundio_ring_buffer_advance_write_ptr(&isd->ring_buffer, byte_count); soundio_ring_buffer_advance_write_ptr(&isd->ring_buffer, byte_count);
frames_consumed += write_count; frames_consumed += write_count;
@ -123,8 +123,8 @@ static void capture_thread_run(void *arg) {
} }
} }
static void destroy_dummy(SoundIoPrivate *si) { static void destroy_dummy(struct SoundIoPrivate *si) {
SoundIoDummy *sid = &si->backend_data.dummy; struct SoundIoDummy *sid = &si->backend_data.dummy;
if (sid->cond) if (sid->cond)
soundio_os_cond_destroy(sid->cond); soundio_os_cond_destroy(sid->cond);
@ -133,55 +133,57 @@ static void destroy_dummy(SoundIoPrivate *si) {
soundio_os_mutex_destroy(sid->mutex); soundio_os_mutex_destroy(sid->mutex);
} }
static void flush_events_dummy(SoundIoPrivate *si) { static void flush_events_dummy(struct SoundIoPrivate *si) {
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoDummy *sid = &si->backend_data.dummy; struct SoundIoDummy *sid = &si->backend_data.dummy;
if (sid->devices_emitted) if (sid->devices_emitted)
return; return;
sid->devices_emitted = true; sid->devices_emitted = true;
soundio->on_devices_change(soundio); soundio->on_devices_change(soundio);
} }
static void wait_events_dummy(SoundIoPrivate *si) { static void wait_events_dummy(struct SoundIoPrivate *si) {
SoundIoDummy *sid = &si->backend_data.dummy; struct SoundIoDummy *sid = &si->backend_data.dummy;
flush_events_dummy(si); flush_events_dummy(si);
soundio_os_cond_wait(sid->cond, nullptr); soundio_os_cond_wait(sid->cond, NULL);
} }
static void wakeup_dummy(SoundIoPrivate *si) { static void wakeup_dummy(struct SoundIoPrivate *si) {
SoundIoDummy *sid = &si->backend_data.dummy; struct SoundIoDummy *sid = &si->backend_data.dummy;
soundio_os_cond_signal(sid->cond, nullptr); soundio_os_cond_signal(sid->cond, NULL);
} }
static void force_device_scan_dummy(SoundIoPrivate *si) { static void force_device_scan_dummy(struct SoundIoPrivate *si) {
// nothing to do; dummy devices never change // nothing to do; dummy devices never change
} }
static void outstream_destroy_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { static void outstream_destroy_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamDummy *osd = &os->backend_data.dummy; struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
if (osd->thread) { if (osd->thread) {
osd->abort_flag.clear(); atomic_flag_clear(&osd->abort_flag);
soundio_os_cond_signal(osd->cond, nullptr); soundio_os_cond_signal(osd->cond, NULL);
soundio_os_thread_destroy(osd->thread); soundio_os_thread_destroy(osd->thread);
osd->thread = nullptr; osd->thread = NULL;
} }
soundio_os_cond_destroy(osd->cond); soundio_os_cond_destroy(osd->cond);
osd->cond = nullptr; osd->cond = NULL;
soundio_ring_buffer_deinit(&osd->ring_buffer); soundio_ring_buffer_deinit(&osd->ring_buffer);
} }
static int outstream_open_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { static int outstream_open_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamDummy *osd = &os->backend_data.dummy; struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
SoundIoDevice *device = outstream->device; struct SoundIoDevice *device = outstream->device;
osd->clear_buffer_flag.test_and_set(); atomic_flag_test_and_set(&osd->clear_buffer_flag);
osd->pause_requested.store(false); SOUNDIO_ATOMIC_STORE(osd->pause_requested, false);
if (outstream->software_latency == 0.0) if (outstream->software_latency == 0.0) {
outstream->software_latency = clamp(device->software_latency_min, 1.0, device->software_latency_max); outstream->software_latency = soundio_double_clamp(
device->software_latency_min, 1.0, device->software_latency_max);
}
osd->period_duration = outstream->software_latency / 2.0; osd->period_duration = outstream->software_latency / 2.0;
@ -205,16 +207,16 @@ static int outstream_open_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
} }
static int outstream_pause_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) { static int outstream_pause_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
SoundIoOutStreamDummy *osd = &os->backend_data.dummy; struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
osd->pause_requested.store(pause); SOUNDIO_ATOMIC_STORE(osd->pause_requested, pause);
return 0; return 0;
} }
static int outstream_start_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { static int outstream_start_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamDummy *osd = &os->backend_data.dummy; struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
assert(!osd->thread); assert(!osd->thread);
osd->abort_flag.test_and_set(); atomic_flag_test_and_set(&osd->abort_flag);
int err; int err;
if ((err = soundio_os_thread_create(playback_thread_run, os, if ((err = soundio_os_thread_create(playback_thread_run, os,
soundio->emit_rtprio_warning, &osd->thread))) soundio->emit_rtprio_warning, &osd->thread)))
@ -224,11 +226,11 @@ static int outstream_start_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os
return 0; return 0;
} }
static int outstream_begin_write_dummy(SoundIoPrivate *si, static int outstream_begin_write_dummy(struct SoundIoPrivate *si,
SoundIoOutStreamPrivate *os, SoundIoChannelArea **out_areas, int *frame_count) struct SoundIoOutStreamPrivate *os, struct SoundIoChannelArea **out_areas, int *frame_count)
{ {
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
SoundIoOutStreamDummy *osd = &os->backend_data.dummy; struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
if (*frame_count > osd->frames_left) if (*frame_count > osd->frames_left)
return SoundIoErrorInvalid; return SoundIoErrorInvalid;
@ -244,55 +246,57 @@ static int outstream_begin_write_dummy(SoundIoPrivate *si,
return 0; return 0;
} }
static int outstream_end_write_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { static int outstream_end_write_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamDummy *osd = &os->backend_data.dummy; struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
int byte_count = osd->write_frame_count * outstream->bytes_per_frame; int byte_count = osd->write_frame_count * outstream->bytes_per_frame;
soundio_ring_buffer_advance_write_ptr(&osd->ring_buffer, byte_count); soundio_ring_buffer_advance_write_ptr(&osd->ring_buffer, byte_count);
osd->frames_left -= osd->write_frame_count; osd->frames_left -= osd->write_frame_count;
return 0; return 0;
} }
static int outstream_clear_buffer_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { static int outstream_clear_buffer_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamDummy *osd = &os->backend_data.dummy; struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
osd->clear_buffer_flag.clear(); atomic_flag_clear(&osd->clear_buffer_flag);
soundio_os_cond_signal(osd->cond, nullptr); soundio_os_cond_signal(osd->cond, NULL);
return 0; return 0;
} }
static int outstream_get_latency_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, double *out_latency) { static int outstream_get_latency_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, double *out_latency) {
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
SoundIoOutStreamDummy *osd = &os->backend_data.dummy; struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer); int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer);
*out_latency = (fill_bytes / outstream->bytes_per_frame) / (double)outstream->sample_rate; *out_latency = (fill_bytes / outstream->bytes_per_frame) / (double)outstream->sample_rate;
return 0; return 0;
} }
static void instream_destroy_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) { static void instream_destroy_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStreamDummy *isd = &is->backend_data.dummy; struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
if (isd->thread) { if (isd->thread) {
isd->abort_flag.clear(); atomic_flag_clear(&isd->abort_flag);
soundio_os_cond_signal(isd->cond, nullptr); soundio_os_cond_signal(isd->cond, NULL);
soundio_os_thread_destroy(isd->thread); soundio_os_thread_destroy(isd->thread);
isd->thread = nullptr; isd->thread = NULL;
} }
soundio_os_cond_destroy(isd->cond); soundio_os_cond_destroy(isd->cond);
isd->cond = nullptr; isd->cond = NULL;
soundio_ring_buffer_deinit(&isd->ring_buffer); soundio_ring_buffer_deinit(&isd->ring_buffer);
} }
static int instream_open_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) { static int instream_open_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStreamDummy *isd = &is->backend_data.dummy; struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
SoundIoDevice *device = instream->device; struct SoundIoDevice *device = instream->device;
isd->pause_requested.store(false); SOUNDIO_ATOMIC_STORE(isd->pause_requested, false);
if (instream->software_latency == 0.0) if (instream->software_latency == 0.0) {
instream->software_latency = clamp(device->software_latency_min, 1.0, device->software_latency_max); instream->software_latency = soundio_double_clamp(
device->software_latency_min, 1.0, device->software_latency_max);
}
isd->period_duration = instream->software_latency; isd->period_duration = instream->software_latency;
@ -317,17 +321,17 @@ static int instream_open_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
return 0; return 0;
} }
static int instream_pause_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is, bool pause) { static int instream_pause_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
SoundIoInStreamDummy *isd = &is->backend_data.dummy; struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
isd->pause_requested.store(pause); SOUNDIO_ATOMIC_STORE(isd->pause_requested, pause);
return 0; return 0;
} }
static int instream_start_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) { static int instream_start_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStreamDummy *isd = &is->backend_data.dummy; struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
assert(!isd->thread); assert(!isd->thread);
isd->abort_flag.test_and_set(); atomic_flag_test_and_set(&isd->abort_flag);
int err; int err;
if ((err = soundio_os_thread_create(capture_thread_run, is, if ((err = soundio_os_thread_create(capture_thread_run, is,
soundio->emit_rtprio_warning, &isd->thread))) soundio->emit_rtprio_warning, &isd->thread)))
@ -337,11 +341,11 @@ static int instream_start_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is)
return 0; return 0;
} }
static int instream_begin_read_dummy(SoundIoPrivate *si, static int instream_begin_read_dummy(struct SoundIoPrivate *si,
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count) struct SoundIoInStreamPrivate *is, struct SoundIoChannelArea **out_areas, int *frame_count)
{ {
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
SoundIoInStreamDummy *isd = &is->backend_data.dummy; struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
assert(*frame_count <= isd->frames_left); assert(*frame_count <= isd->frames_left);
@ -357,27 +361,27 @@ static int instream_begin_read_dummy(SoundIoPrivate *si,
return 0; return 0;
} }
static int instream_end_read_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) { static int instream_end_read_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStreamDummy *isd = &is->backend_data.dummy; struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
int byte_count = isd->read_frame_count * instream->bytes_per_frame; int byte_count = isd->read_frame_count * instream->bytes_per_frame;
soundio_ring_buffer_advance_read_ptr(&isd->ring_buffer, byte_count); soundio_ring_buffer_advance_read_ptr(&isd->ring_buffer, byte_count);
isd->frames_left -= isd->read_frame_count; isd->frames_left -= isd->read_frame_count;
return 0; return 0;
} }
static int instream_get_latency_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is, double *out_latency) { static int instream_get_latency_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, double *out_latency) {
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
SoundIoInStreamDummy *osd = &is->backend_data.dummy; struct SoundIoInStreamDummy *osd = &is->backend_data.dummy;
int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer); int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer);
*out_latency = (fill_bytes / instream->bytes_per_frame) / (double)instream->sample_rate; *out_latency = (fill_bytes / instream->bytes_per_frame) / (double)instream->sample_rate;
return 0; return 0;
} }
static int set_all_device_formats(SoundIoDevice *device) { static int set_all_device_formats(struct SoundIoDevice *device) {
device->format_count = 18; device->format_count = 18;
device->formats = allocate<SoundIoFormat>(device->format_count); device->formats = ALLOCATE(enum SoundIoFormat, device->format_count);
if (!device->formats) if (!device->formats)
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
@ -403,17 +407,17 @@ static int set_all_device_formats(SoundIoDevice *device) {
return 0; return 0;
} }
static void set_all_device_sample_rates(SoundIoDevice *device) { static void set_all_device_sample_rates(struct SoundIoDevice *device) {
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device; struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
device->sample_rate_count = 1; device->sample_rate_count = 1;
device->sample_rates = &dev->prealloc_sample_rate_range; device->sample_rates = &dev->prealloc_sample_rate_range;
device->sample_rates[0].min = SOUNDIO_MIN_SAMPLE_RATE; device->sample_rates[0].min = SOUNDIO_MIN_SAMPLE_RATE;
device->sample_rates[0].max = SOUNDIO_MAX_SAMPLE_RATE; device->sample_rates[0].max = SOUNDIO_MAX_SAMPLE_RATE;
} }
static int set_all_device_channel_layouts(SoundIoDevice *device) { static int set_all_device_channel_layouts(struct SoundIoDevice *device) {
device->layout_count = soundio_channel_layout_builtin_count(); device->layout_count = soundio_channel_layout_builtin_count();
device->layouts = allocate<SoundIoChannelLayout>(device->layout_count); device->layouts = ALLOCATE(struct SoundIoChannelLayout, device->layout_count);
if (!device->layouts) if (!device->layouts)
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
for (int i = 0; i < device->layout_count; i += 1) for (int i = 0; i < device->layout_count; i += 1)
@ -421,9 +425,9 @@ static int set_all_device_channel_layouts(SoundIoDevice *device) {
return 0; return 0;
} }
int soundio_dummy_init(SoundIoPrivate *si) { int soundio_dummy_init(struct SoundIoPrivate *si) {
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoDummy *sid = &si->backend_data.dummy; struct SoundIoDummy *sid = &si->backend_data.dummy;
sid->mutex = soundio_os_mutex_create(); sid->mutex = soundio_os_mutex_create();
if (!sid->mutex) { if (!sid->mutex) {
@ -438,7 +442,7 @@ int soundio_dummy_init(SoundIoPrivate *si) {
} }
assert(!si->safe_devices_info); assert(!si->safe_devices_info);
si->safe_devices_info = allocate<SoundIoDevicesInfo>(1); si->safe_devices_info = ALLOCATE(struct SoundIoDevicesInfo, 1);
if (!si->safe_devices_info) { if (!si->safe_devices_info) {
destroy_dummy(si); destroy_dummy(si);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
@ -449,12 +453,12 @@ int soundio_dummy_init(SoundIoPrivate *si) {
// create output device // create output device
{ {
SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1); struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
if (!dev) { if (!dev) {
destroy_dummy(si); destroy_dummy(si);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
SoundIoDevice *device = &dev->pub; struct SoundIoDevice *device = &dev->pub;
device->ref_count = 1; device->ref_count = 1;
device->soundio = soundio; device->soundio = soundio;
@ -486,7 +490,7 @@ int soundio_dummy_init(SoundIoPrivate *si) {
device->sample_rate_current = 48000; device->sample_rate_current = 48000;
device->aim = SoundIoDeviceAimOutput; device->aim = SoundIoDeviceAimOutput;
if (si->safe_devices_info->output_devices.append(device)) { if (SoundIoListDevicePtr_append(&si->safe_devices_info->output_devices, device)) {
soundio_device_unref(device); soundio_device_unref(device);
destroy_dummy(si); destroy_dummy(si);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
@ -495,12 +499,12 @@ int soundio_dummy_init(SoundIoPrivate *si) {
// create input device // create input device
{ {
SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1); struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
if (!dev) { if (!dev) {
destroy_dummy(si); destroy_dummy(si);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
SoundIoDevice *device = &dev->pub; struct SoundIoDevice *device = &dev->pub;
device->ref_count = 1; device->ref_count = 1;
device->soundio = soundio; device->soundio = soundio;
@ -531,7 +535,7 @@ int soundio_dummy_init(SoundIoPrivate *si) {
device->sample_rate_current = 48000; device->sample_rate_current = 48000;
device->aim = SoundIoDeviceAimInput; device->aim = SoundIoDeviceAimInput;
if (si->safe_devices_info->input_devices.append(device)) { if (SoundIoListDevicePtr_append(&si->safe_devices_info->input_devices, device)) {
soundio_device_unref(device); soundio_device_unref(device);
destroy_dummy(si); destroy_dummy(si);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;

View file

@ -5,23 +5,24 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#ifndef SOUNDIO_DUMMY_HPP #ifndef SOUNDIO_DUMMY_H
#define SOUNDIO_DUMMY_HPP #define SOUNDIO_DUMMY_H
#include "soundio_private.h" #include "soundio_internal.h"
#include "os.h" #include "os.h"
#include "atomics.hpp" #include "ring_buffer.h"
#include "ring_buffer.hpp" #include "atomics.h"
struct SoundIoPrivate;
int soundio_dummy_init(struct SoundIoPrivate *si); int soundio_dummy_init(struct SoundIoPrivate *si);
struct SoundIoDummy { struct SoundIoDummy {
SoundIoOsMutex *mutex; struct SoundIoOsMutex *mutex;
SoundIoOsCond *cond; struct SoundIoOsCond *cond;
bool devices_emitted; bool devices_emitted;
}; };
struct SoundIoDeviceDummy { }; struct SoundIoDeviceDummy { int make_the_struct_not_empty; };
struct SoundIoOutStreamDummy { struct SoundIoOutStreamDummy {
struct SoundIoOsThread *thread; struct SoundIoOsThread *thread;
@ -34,8 +35,8 @@ struct SoundIoOutStreamDummy {
struct SoundIoRingBuffer ring_buffer; struct SoundIoRingBuffer ring_buffer;
double playback_start_time; double playback_start_time;
atomic_flag clear_buffer_flag; atomic_flag clear_buffer_flag;
atomic_bool pause_requested; struct SoundIoAtomicBool pause_requested;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS]; struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
}; };
struct SoundIoInStreamDummy { struct SoundIoInStreamDummy {
@ -47,8 +48,8 @@ struct SoundIoInStreamDummy {
int read_frame_count; int read_frame_count;
int buffer_frame_count; int buffer_frame_count;
struct SoundIoRingBuffer ring_buffer; struct SoundIoRingBuffer ring_buffer;
atomic_bool pause_requested; struct SoundIoAtomicBool pause_requested;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS]; struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
}; };
#endif #endif

View file

@ -5,9 +5,9 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#include "jack.hpp" #include "jack.h"
#include "soundio.hpp" #include "soundio_private.h"
#include "list.hpp" #include "list.h"
#include <stdio.h> #include <stdio.h>
@ -18,7 +18,7 @@ struct SoundIoJackPort {
int full_name_len; int full_name_len;
const char *name; const char *name;
int name_len; int name_len;
SoundIoChannelId channel_id; enum SoundIoChannelId channel_id;
jack_latency_range_t latency_range; jack_latency_range_t latency_range;
}; };
@ -26,11 +26,14 @@ struct SoundIoJackClient {
const char *name; const char *name;
int name_len; int name_len;
bool is_physical; bool is_physical;
SoundIoDeviceAim aim; enum SoundIoDeviceAim aim;
int port_count; int port_count;
SoundIoJackPort ports[SOUNDIO_MAX_CHANNELS]; struct SoundIoJackPort ports[SOUNDIO_MAX_CHANNELS];
}; };
SOUNDIO_MAKE_LIST_STRUCT(struct SoundIoJackClient, SoundIoListJackClient, SOUNDIO_LIST_STATIC)
SOUNDIO_MAKE_LIST_DEF(struct SoundIoJackClient, SoundIoListJackClient, SOUNDIO_LIST_STATIC)
static void split_str(const char *input_str, int input_str_len, char c, static void split_str(const char *input_str, int input_str_len, char c,
const char **out_1, int *out_len_1, const char **out_2, int *out_len_2) const char **out_1, int *out_len_1, const char **out_2, int *out_len_2)
{ {
@ -46,11 +49,11 @@ static void split_str(const char *input_str, int input_str_len, char c,
} }
} }
static SoundIoJackClient *find_or_create_client(SoundIoList<SoundIoJackClient> *clients, static struct SoundIoJackClient *find_or_create_client(struct SoundIoListJackClient *clients,
SoundIoDeviceAim aim, bool is_physical, const char *client_name, int client_name_len) enum SoundIoDeviceAim aim, bool is_physical, const char *client_name, int client_name_len)
{ {
for (int i = 0; i < clients->length; i += 1) { for (int i = 0; i < clients->length; i += 1) {
SoundIoJackClient *client = &clients->at(i); struct SoundIoJackClient *client = SoundIoListJackClient_ptr_at(clients, i);
if (client->is_physical == is_physical && if (client->is_physical == is_physical &&
client->aim == aim && client->aim == aim &&
soundio_streql(client->name, client->name_len, client_name, client_name_len)) soundio_streql(client->name, client->name_len, client_name, client_name_len))
@ -59,9 +62,9 @@ static SoundIoJackClient *find_or_create_client(SoundIoList<SoundIoJackClient> *
} }
} }
int err; int err;
if ((err = clients->add_one())) if ((err = SoundIoListJackClient_add_one(clients)))
return nullptr; return NULL;
SoundIoJackClient *client = &clients->last(); struct SoundIoJackClient *client = SoundIoListJackClient_last_ptr(clients);
client->is_physical = is_physical; client->is_physical = is_physical;
client->aim = aim; client->aim = aim;
client->name = client_name; client->name = client_name;
@ -70,36 +73,36 @@ static SoundIoJackClient *find_or_create_client(SoundIoList<SoundIoJackClient> *
return client; return client;
} }
static void destruct_device(SoundIoDevicePrivate *dp) { static void destruct_device(struct SoundIoDevicePrivate *dp) {
SoundIoDeviceJack *dj = &dp->backend_data.jack; struct SoundIoDeviceJack *dj = &dp->backend_data.jack;
for (int i = 0; i < dj->port_count; i += 1) { for (int i = 0; i < dj->port_count; i += 1) {
SoundIoDeviceJackPort *djp = &dj->ports[i]; struct SoundIoDeviceJackPort *djp = &dj->ports[i];
free(djp->full_name); free(djp->full_name);
} }
free(dj->ports); free(dj->ports);
} }
static int refresh_devices_bare(SoundIoPrivate *si) { static int refresh_devices_bare(struct SoundIoPrivate *si) {
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoJack *sij = &si->backend_data.jack; struct SoundIoJack *sij = &si->backend_data.jack;
if (sij->is_shutdown) if (sij->is_shutdown)
return SoundIoErrorBackendDisconnected; return SoundIoErrorBackendDisconnected;
SoundIoDevicesInfo *devices_info = allocate<SoundIoDevicesInfo>(1); struct SoundIoDevicesInfo *devices_info = ALLOCATE(struct SoundIoDevicesInfo, 1);
if (!devices_info) if (!devices_info)
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
devices_info->default_output_index = -1; devices_info->default_output_index = -1;
devices_info->default_input_index = -1; devices_info->default_input_index = -1;
const char **port_names = jack_get_ports(sij->client, nullptr, nullptr, 0); const char **port_names = jack_get_ports(sij->client, NULL, NULL, 0);
if (!port_names) { if (!port_names) {
soundio_destroy_devices_info(devices_info); soundio_destroy_devices_info(devices_info);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
SoundIoList<SoundIoJackClient> clients = {0}; struct SoundIoListJackClient clients = {0};
const char **port_name_ptr = port_names; const char **port_name_ptr = port_names;
for (; *port_name_ptr; port_name_ptr += 1) { for (; *port_name_ptr; port_name_ptr += 1) {
const char *client_and_port_name = *port_name_ptr; const char *client_and_port_name = *port_name_ptr;
@ -120,12 +123,12 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
continue; continue;
} }
SoundIoDeviceAim aim = (flags & JackPortIsInput) ? enum SoundIoDeviceAim aim = (flags & JackPortIsInput) ?
SoundIoDeviceAimOutput : SoundIoDeviceAimInput; SoundIoDeviceAimOutput : SoundIoDeviceAimInput;
bool is_physical = flags & JackPortIsPhysical; bool is_physical = flags & JackPortIsPhysical;
const char *client_name = nullptr; const char *client_name = NULL;
const char *port_name = nullptr; const char *port_name = NULL;
int client_name_len; int client_name_len;
int port_name_len; int port_name_len;
split_str(client_and_port_name, client_and_port_name_len, ':', split_str(client_and_port_name, client_and_port_name_len, ':',
@ -134,7 +137,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
// device does not have colon, skip it // device does not have colon, skip it
continue; continue;
} }
SoundIoJackClient *client = find_or_create_client(&clients, aim, is_physical, struct SoundIoJackClient *client = find_or_create_client(&clients, aim, is_physical,
client_name, client_name_len); client_name, client_name_len);
if (!client) { if (!client) {
jack_free(port_names); jack_free(port_names);
@ -145,7 +148,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
// we hit the channel limit, skip the leftovers // we hit the channel limit, skip the leftovers
continue; continue;
} }
SoundIoJackPort *port = &client->ports[client->port_count++]; struct SoundIoJackPort *port = &client->ports[client->port_count++];
port->full_name = client_and_port_name; port->full_name = client_and_port_name;
port->full_name_len = client_and_port_name_len; port->full_name_len = client_and_port_name_len;
port->name = port_name; port->name = port_name;
@ -158,21 +161,21 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
} }
for (int i = 0; i < clients.length; i += 1) { for (int i = 0; i < clients.length; i += 1) {
SoundIoJackClient *client = &clients.at(i); struct SoundIoJackClient *client = SoundIoListJackClient_ptr_at(&clients, i);
if (client->port_count <= 0) if (client->port_count <= 0)
continue; continue;
SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1); struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
if (!dev) { if (!dev) {
jack_free(port_names); jack_free(port_names);
soundio_destroy_devices_info(devices_info); soundio_destroy_devices_info(devices_info);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
SoundIoDevice *device = &dev->pub; struct SoundIoDevice *device = &dev->pub;
SoundIoDeviceJack *dj = &dev->backend_data.jack; struct SoundIoDeviceJack *dj = &dev->backend_data.jack;
int description_len = client->name_len + 3 + 2 * client->port_count; int description_len = client->name_len + 3 + 2 * client->port_count;
for (int port_index = 0; port_index < client->port_count; port_index += 1) { for (int port_index = 0; port_index < client->port_count; port_index += 1) {
SoundIoJackPort *port = &client->ports[port_index]; struct SoundIoJackPort *port = &client->ports[port_index];
description_len += port->name_len; description_len += port->name_len;
} }
@ -184,7 +187,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
device->is_raw = false; device->is_raw = false;
device->aim = client->aim; device->aim = client->aim;
device->id = soundio_str_dupe(client->name, client->name_len); device->id = soundio_str_dupe(client->name, client->name_len);
device->name = allocate<char>(description_len); device->name = ALLOCATE(char, description_len);
device->current_format = SoundIoFormatFloat32NE; device->current_format = SoundIoFormatFloat32NE;
device->sample_rate_count = 1; device->sample_rate_count = 1;
device->sample_rates = &dev->prealloc_sample_rate_range; device->sample_rates = &dev->prealloc_sample_rate_range;
@ -197,7 +200,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
device->software_latency_max = sij->period_size / (double) sij->sample_rate; device->software_latency_max = sij->period_size / (double) sij->sample_rate;
dj->port_count = client->port_count; dj->port_count = client->port_count;
dj->ports = allocate<SoundIoDeviceJackPort>(dj->port_count); dj->ports = ALLOCATE(struct SoundIoDeviceJackPort, dj->port_count);
if (!device->id || !device->name || !dj->ports) { if (!device->id || !device->name || !dj->ports) {
jack_free(port_names); jack_free(port_names);
@ -207,8 +210,8 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
} }
for (int port_index = 0; port_index < client->port_count; port_index += 1) { for (int port_index = 0; port_index < client->port_count; port_index += 1) {
SoundIoJackPort *port = &client->ports[port_index]; struct SoundIoJackPort *port = &client->ports[port_index];
SoundIoDeviceJackPort *djp = &dj->ports[port_index]; struct SoundIoDeviceJackPort *djp = &dj->ports[port_index];
djp->full_name = soundio_str_dupe(port->full_name, port->full_name_len); djp->full_name = soundio_str_dupe(port->full_name, port->full_name_len);
djp->full_name_len = port->full_name_len; djp->full_name_len = port->full_name_len;
djp->channel_id = port->channel_id; djp->channel_id = port->channel_id;
@ -226,7 +229,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
memcpy(&device->name[client->name_len], ": ", 2); memcpy(&device->name[client->name_len], ": ", 2);
int index = client->name_len + 2; int index = client->name_len + 2;
for (int port_index = 0; port_index < client->port_count; port_index += 1) { for (int port_index = 0; port_index < client->port_count; port_index += 1) {
SoundIoJackPort *port = &client->ports[port_index]; struct SoundIoJackPort *port = &client->ports[port_index];
memcpy(&device->name[index], port->name, port->name_len); memcpy(&device->name[index], port->name, port->name_len);
index += port->name_len; index += port->name_len;
if (port_index + 1 < client->port_count) { if (port_index + 1 < client->port_count) {
@ -238,7 +241,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
device->current_layout.channel_count = client->port_count; device->current_layout.channel_count = client->port_count;
bool any_invalid = false; bool any_invalid = false;
for (int port_index = 0; port_index < client->port_count; port_index += 1) { for (int port_index = 0; port_index < client->port_count; port_index += 1) {
SoundIoJackPort *port = &client->ports[port_index]; struct SoundIoJackPort *port = &client->ports[port_index];
device->current_layout.channels[port_index] = port->channel_id; device->current_layout.channels[port_index] = port->channel_id;
any_invalid = any_invalid || (port->channel_id == SoundIoChannelIdInvalid); any_invalid = any_invalid || (port->channel_id == SoundIoChannelIdInvalid);
} }
@ -256,7 +259,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
device->formats = &dev->prealloc_format; device->formats = &dev->prealloc_format;
device->formats[0] = device->current_format; device->formats[0] = device->current_format;
SoundIoList<SoundIoDevice *> *device_list; struct SoundIoListDevicePtr *device_list;
if (device->aim == SoundIoDeviceAimOutput) { if (device->aim == SoundIoDeviceAimOutput) {
device_list = &devices_info->output_devices; device_list = &devices_info->output_devices;
if (devices_info->default_output_index < 0 && client->is_physical) if (devices_info->default_output_index < 0 && client->is_physical)
@ -268,7 +271,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
devices_info->default_input_index = device_list->length; devices_info->default_input_index = device_list->length;
} }
if (device_list->append(device)) { if (SoundIoListDevicePtr_append(device_list, device)) {
soundio_device_unref(device); soundio_device_unref(device);
soundio_destroy_devices_info(devices_info); soundio_destroy_devices_info(devices_info);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
@ -283,7 +286,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
return 0; return 0;
} }
static int refresh_devices(SoundIoPrivate *si) { static int refresh_devices(struct SoundIoPrivate *si) {
int err = SoundIoErrorInterrupted; int err = SoundIoErrorInterrupted;
while (err == SoundIoErrorInterrupted) while (err == SoundIoErrorInterrupted)
err = refresh_devices_bare(si); err = refresh_devices_bare(si);
@ -291,8 +294,8 @@ static int refresh_devices(SoundIoPrivate *si) {
} }
static void my_flush_events(struct SoundIoPrivate *si, bool wait) { static void my_flush_events(struct SoundIoPrivate *si, bool wait) {
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoJack *sij = &si->backend_data.jack; struct SoundIoJack *sij = &si->backend_data.jack;
int err; int err;
bool cb_shutdown = false; bool cb_shutdown = false;
@ -312,9 +315,9 @@ static void my_flush_events(struct SoundIoPrivate *si, bool wait) {
if (cb_shutdown) { if (cb_shutdown) {
soundio->on_backend_disconnect(soundio, SoundIoErrorBackendDisconnected); soundio->on_backend_disconnect(soundio, SoundIoErrorBackendDisconnected);
} else { } else {
if (!sij->refresh_devices_flag.test_and_set()) { if (!atomic_flag_test_and_set(&sij->refresh_devices_flag)) {
if ((err = refresh_devices(si))) { if ((err = refresh_devices(si))) {
sij->refresh_devices_flag.clear(); atomic_flag_clear(&sij->refresh_devices_flag);
} else { } else {
soundio->on_devices_change(soundio); soundio->on_devices_change(soundio);
} }
@ -332,16 +335,16 @@ static void wait_events_jack(struct SoundIoPrivate *si) {
} }
static void wakeup_jack(struct SoundIoPrivate *si) { static void wakeup_jack(struct SoundIoPrivate *si) {
SoundIoJack *sij = &si->backend_data.jack; struct SoundIoJack *sij = &si->backend_data.jack;
soundio_os_mutex_lock(sij->mutex); soundio_os_mutex_lock(sij->mutex);
soundio_os_cond_signal(sij->cond, sij->mutex); soundio_os_cond_signal(sij->cond, sij->mutex);
soundio_os_mutex_unlock(sij->mutex); soundio_os_mutex_unlock(sij->mutex);
} }
static void force_device_scan_jack(struct SoundIoPrivate *si) { static void force_device_scan_jack(struct SoundIoPrivate *si) {
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoJack *sij = &si->backend_data.jack; struct SoundIoJack *sij = &si->backend_data.jack;
sij->refresh_devices_flag.clear(); atomic_flag_clear(&sij->refresh_devices_flag);
soundio_os_mutex_lock(sij->mutex); soundio_os_mutex_lock(sij->mutex);
soundio_os_cond_signal(sij->cond, sij->mutex); soundio_os_cond_signal(sij->cond, sij->mutex);
soundio->on_events_signal(soundio); soundio->on_events_signal(soundio);
@ -349,12 +352,12 @@ static void force_device_scan_jack(struct SoundIoPrivate *si) {
} }
static int outstream_process_callback(jack_nframes_t nframes, void *arg) { static int outstream_process_callback(jack_nframes_t nframes, void *arg) {
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg; struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
SoundIoOutStreamJack *osj = &os->backend_data.jack; struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
osj->frames_left = nframes; osj->frames_left = nframes;
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) { for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
SoundIoOutStreamJackPort *osjp = &osj->ports[ch]; struct SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
osj->areas[ch].ptr = (char*)jack_port_get_buffer(osjp->source_port, nframes); osj->areas[ch].ptr = (char*)jack_port_get_buffer(osjp->source_port, nframes);
osj->areas[ch].step = outstream->bytes_per_sample; osj->areas[ch].step = outstream->bytes_per_sample;
} }
@ -363,36 +366,36 @@ static int outstream_process_callback(jack_nframes_t nframes, void *arg) {
} }
static void outstream_destroy_jack(struct SoundIoPrivate *is, struct SoundIoOutStreamPrivate *os) { static void outstream_destroy_jack(struct SoundIoPrivate *is, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamJack *osj = &os->backend_data.jack; struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
jack_client_close(osj->client); jack_client_close(osj->client);
osj->client = nullptr; osj->client = NULL;
} }
static SoundIoDeviceJackPort *find_port_matching_channel(SoundIoDevice *device, SoundIoChannelId id) { static struct SoundIoDeviceJackPort *find_port_matching_channel(struct SoundIoDevice *device, enum SoundIoChannelId id) {
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device; struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
SoundIoDeviceJack *dj = &dev->backend_data.jack; struct SoundIoDeviceJack *dj = &dev->backend_data.jack;
for (int ch = 0; ch < device->current_layout.channel_count; ch += 1) { for (int ch = 0; ch < device->current_layout.channel_count; ch += 1) {
SoundIoChannelId chan_id = device->current_layout.channels[ch]; enum SoundIoChannelId chan_id = device->current_layout.channels[ch];
if (chan_id == id) if (chan_id == id)
return &dj->ports[ch]; return &dj->ports[ch];
} }
return nullptr; return NULL;
} }
static int outstream_xrun_callback(void *arg) { static int outstream_xrun_callback(void *arg) {
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg; struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
outstream->underflow_callback(outstream); outstream->underflow_callback(outstream);
return 0; return 0;
} }
static int outstream_buffer_size_callback(jack_nframes_t nframes, void *arg) { static int outstream_buffer_size_callback(jack_nframes_t nframes, void *arg) {
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg; struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
SoundIoOutStreamJack *osj = &os->backend_data.jack; struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
if ((jack_nframes_t)osj->period_size == nframes) { if ((jack_nframes_t)osj->period_size == nframes) {
return 0; return 0;
} else { } else {
@ -402,8 +405,8 @@ static int outstream_buffer_size_callback(jack_nframes_t nframes, void *arg) {
} }
static int outstream_sample_rate_callback(jack_nframes_t nframes, void *arg) { static int outstream_sample_rate_callback(jack_nframes_t nframes, void *arg) {
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg; struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
if (nframes == (jack_nframes_t)outstream->sample_rate) { if (nframes == (jack_nframes_t)outstream->sample_rate) {
return 0; return 0;
} else { } else {
@ -413,18 +416,22 @@ static int outstream_sample_rate_callback(jack_nframes_t nframes, void *arg) {
} }
static void outstream_shutdown_callback(void *arg) { static void outstream_shutdown_callback(void *arg) {
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg; struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
outstream->error_callback(outstream, SoundIoErrorStreaming); outstream->error_callback(outstream, SoundIoErrorStreaming);
} }
static inline jack_nframes_t nframes_max(jack_nframes_t a, jack_nframes_t b) {
return (a >= b) ? a : b;
}
static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) { static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoJack *sij = &si->backend_data.jack; struct SoundIoJack *sij = &si->backend_data.jack;
SoundIoOutStreamJack *osj = &os->backend_data.jack; struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
SoundIoDevice *device = outstream->device; struct SoundIoDevice *device = outstream->device;
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device; struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
SoundIoDeviceJack *dj = &dev->backend_data.jack; struct SoundIoDeviceJack *dj = &dev->backend_data.jack;
if (sij->is_shutdown) if (sij->is_shutdown)
return SoundIoErrorBackendDisconnected; return SoundIoErrorBackendDisconnected;
@ -472,7 +479,7 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
// register ports and map channels // register ports and map channels
int connected_count = 0; int connected_count = 0;
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) { for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
SoundIoChannelId my_channel_id = outstream->layout.channels[ch]; enum SoundIoChannelId my_channel_id = outstream->layout.channels[ch];
const char *channel_name = soundio_get_channel_name(my_channel_id); const char *channel_name = soundio_get_channel_name(my_channel_id);
unsigned long flags = JackPortIsOutput; unsigned long flags = JackPortIsOutput;
if (!outstream->non_terminal_hint) if (!outstream->non_terminal_hint)
@ -482,15 +489,15 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
outstream_destroy_jack(si, os); outstream_destroy_jack(si, os);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
SoundIoOutStreamJackPort *osjp = &osj->ports[ch]; struct SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
osjp->source_port = jport; osjp->source_port = jport;
// figure out which dest port this connects to // figure out which dest port this connects to
SoundIoDeviceJackPort *djp = find_port_matching_channel(device, my_channel_id); struct SoundIoDeviceJackPort *djp = find_port_matching_channel(device, my_channel_id);
if (djp) { if (djp) {
osjp->dest_port_name = djp->full_name; osjp->dest_port_name = djp->full_name;
osjp->dest_port_name_len = djp->full_name_len; osjp->dest_port_name_len = djp->full_name_len;
connected_count += 1; connected_count += 1;
max_port_latency = max(max_port_latency, djp->latency_range.max); max_port_latency = nframes_max(max_port_latency, djp->latency_range.max);
} }
} }
// If nothing got connected, channel layouts aren't working. Just send the // If nothing got connected, channel layouts aren't working. Just send the
@ -499,13 +506,13 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
max_port_latency = 0; max_port_latency = 0;
outstream->layout_error = SoundIoErrorIncompatibleDevice; outstream->layout_error = SoundIoErrorIncompatibleDevice;
int ch_count = min(outstream->layout.channel_count, dj->port_count); int ch_count = soundio_int_min(outstream->layout.channel_count, dj->port_count);
for (int ch = 0; ch < ch_count; ch += 1) { for (int ch = 0; ch < ch_count; ch += 1) {
SoundIoOutStreamJackPort *osjp = &osj->ports[ch]; struct SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
SoundIoDeviceJackPort *djp = &dj->ports[ch]; struct SoundIoDeviceJackPort *djp = &dj->ports[ch];
osjp->dest_port_name = djp->full_name; osjp->dest_port_name = djp->full_name;
osjp->dest_port_name_len = djp->full_name_len; osjp->dest_port_name_len = djp->full_name_len;
max_port_latency = max(max_port_latency, djp->latency_range.max); max_port_latency = nframes_max(max_port_latency, djp->latency_range.max);
} }
} }
@ -515,7 +522,7 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
} }
static int outstream_pause_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) { static int outstream_pause_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
SoundIoJack *sij = &si->backend_data.jack; struct SoundIoJack *sij = &si->backend_data.jack;
if (sij->is_shutdown) if (sij->is_shutdown)
return SoundIoErrorBackendDisconnected; return SoundIoErrorBackendDisconnected;
@ -524,9 +531,9 @@ static int outstream_pause_jack(struct SoundIoPrivate *si, struct SoundIoOutStre
} }
static int outstream_start_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) { static int outstream_start_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamJack *osj = &os->backend_data.jack; struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
SoundIoJack *sij = &si->backend_data.jack; struct SoundIoJack *sij = &si->backend_data.jack;
int err; int err;
if (sij->is_shutdown) if (sij->is_shutdown)
@ -536,7 +543,7 @@ static int outstream_start_jack(struct SoundIoPrivate *si, struct SoundIoOutStre
return SoundIoErrorStreaming; return SoundIoErrorStreaming;
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) { for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
SoundIoOutStreamJackPort *osjp = &osj->ports[ch]; struct SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
const char *dest_port_name = osjp->dest_port_name; const char *dest_port_name = osjp->dest_port_name;
// allow unconnected ports // allow unconnected ports
if (!dest_port_name) if (!dest_port_name)
@ -550,9 +557,9 @@ static int outstream_start_jack(struct SoundIoPrivate *si, struct SoundIoOutStre
} }
static int outstream_begin_write_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, static int outstream_begin_write_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
SoundIoChannelArea **out_areas, int *frame_count) struct SoundIoChannelArea **out_areas, int *frame_count)
{ {
SoundIoOutStreamJack *osj = &os->backend_data.jack; struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
if (*frame_count != osj->frames_left) if (*frame_count != osj->frames_left)
return SoundIoErrorInvalid; return SoundIoErrorInvalid;
@ -563,7 +570,7 @@ static int outstream_begin_write_jack(struct SoundIoPrivate *si, struct SoundIoO
} }
static int outstream_end_write_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) { static int outstream_end_write_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamJack *osj = &os->backend_data.jack; struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
osj->frames_left = 0; osj->frames_left = 0;
return 0; return 0;
} }
@ -575,30 +582,30 @@ static int outstream_clear_buffer_jack(struct SoundIoPrivate *si, struct SoundIo
static int outstream_get_latency_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, static int outstream_get_latency_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
double *out_latency) double *out_latency)
{ {
SoundIoOutStreamJack *osj = &os->backend_data.jack; struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
*out_latency = osj->hardware_latency; *out_latency = osj->hardware_latency;
return 0; return 0;
} }
static void instream_destroy_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) { static void instream_destroy_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStreamJack *isj = &is->backend_data.jack; struct SoundIoInStreamJack *isj = &is->backend_data.jack;
jack_client_close(isj->client); jack_client_close(isj->client);
isj->client = nullptr; isj->client = NULL;
} }
static int instream_xrun_callback(void *arg) { static int instream_xrun_callback(void *arg) {
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg; struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
instream->overflow_callback(instream); instream->overflow_callback(instream);
return 0; return 0;
} }
static int instream_buffer_size_callback(jack_nframes_t nframes, void *arg) { static int instream_buffer_size_callback(jack_nframes_t nframes, void *arg) {
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg; struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
SoundIoInStreamJack *isj = &is->backend_data.jack; struct SoundIoInStreamJack *isj = &is->backend_data.jack;
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
if ((jack_nframes_t)isj->period_size == nframes) { if ((jack_nframes_t)isj->period_size == nframes) {
return 0; return 0;
@ -609,8 +616,8 @@ static int instream_buffer_size_callback(jack_nframes_t nframes, void *arg) {
} }
static int instream_sample_rate_callback(jack_nframes_t nframes, void *arg) { static int instream_sample_rate_callback(jack_nframes_t nframes, void *arg) {
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg; struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
if (nframes == (jack_nframes_t)instream->sample_rate) { if (nframes == (jack_nframes_t)instream->sample_rate) {
return 0; return 0;
} else { } else {
@ -620,18 +627,18 @@ static int instream_sample_rate_callback(jack_nframes_t nframes, void *arg) {
} }
static void instream_shutdown_callback(void *arg) { static void instream_shutdown_callback(void *arg) {
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg; struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
instream->error_callback(instream, SoundIoErrorStreaming); instream->error_callback(instream, SoundIoErrorStreaming);
} }
static int instream_process_callback(jack_nframes_t nframes, void *arg) { static int instream_process_callback(jack_nframes_t nframes, void *arg) {
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg; struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
SoundIoInStreamJack *isj = &is->backend_data.jack; struct SoundIoInStreamJack *isj = &is->backend_data.jack;
isj->frames_left = nframes; isj->frames_left = nframes;
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) { for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
SoundIoInStreamJackPort *isjp = &isj->ports[ch]; struct SoundIoInStreamJackPort *isjp = &isj->ports[ch];
isj->areas[ch].ptr = (char*)jack_port_get_buffer(isjp->dest_port, nframes); isj->areas[ch].ptr = (char*)jack_port_get_buffer(isjp->dest_port, nframes);
isj->areas[ch].step = instream->bytes_per_sample; isj->areas[ch].step = instream->bytes_per_sample;
} }
@ -640,12 +647,12 @@ static int instream_process_callback(jack_nframes_t nframes, void *arg) {
} }
static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) { static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
SoundIoInStreamJack *isj = &is->backend_data.jack; struct SoundIoInStreamJack *isj = &is->backend_data.jack;
SoundIoJack *sij = &si->backend_data.jack; struct SoundIoJack *sij = &si->backend_data.jack;
SoundIoDevice *device = instream->device; struct SoundIoDevice *device = instream->device;
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device; struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
SoundIoDeviceJack *dj = &dev->backend_data.jack; struct SoundIoDeviceJack *dj = &dev->backend_data.jack;
if (sij->is_shutdown) if (sij->is_shutdown)
return SoundIoErrorBackendDisconnected; return SoundIoErrorBackendDisconnected;
@ -692,7 +699,7 @@ static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamP
// register ports and map channels // register ports and map channels
int connected_count = 0; int connected_count = 0;
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) { for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
SoundIoChannelId my_channel_id = instream->layout.channels[ch]; enum SoundIoChannelId my_channel_id = instream->layout.channels[ch];
const char *channel_name = soundio_get_channel_name(my_channel_id); const char *channel_name = soundio_get_channel_name(my_channel_id);
unsigned long flags = JackPortIsInput; unsigned long flags = JackPortIsInput;
if (!instream->non_terminal_hint) if (!instream->non_terminal_hint)
@ -702,15 +709,15 @@ static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamP
instream_destroy_jack(si, is); instream_destroy_jack(si, is);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
SoundIoInStreamJackPort *isjp = &isj->ports[ch]; struct SoundIoInStreamJackPort *isjp = &isj->ports[ch];
isjp->dest_port = jport; isjp->dest_port = jport;
// figure out which source port this connects to // figure out which source port this connects to
SoundIoDeviceJackPort *djp = find_port_matching_channel(device, my_channel_id); struct SoundIoDeviceJackPort *djp = find_port_matching_channel(device, my_channel_id);
if (djp) { if (djp) {
isjp->source_port_name = djp->full_name; isjp->source_port_name = djp->full_name;
isjp->source_port_name_len = djp->full_name_len; isjp->source_port_name_len = djp->full_name_len;
connected_count += 1; connected_count += 1;
max_port_latency = max(max_port_latency, djp->latency_range.max); max_port_latency = nframes_max(max_port_latency, djp->latency_range.max);
} }
} }
// If nothing got connected, channel layouts aren't working. Just send the // If nothing got connected, channel layouts aren't working. Just send the
@ -719,13 +726,13 @@ static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamP
max_port_latency = 0; max_port_latency = 0;
instream->layout_error = SoundIoErrorIncompatibleDevice; instream->layout_error = SoundIoErrorIncompatibleDevice;
int ch_count = min(instream->layout.channel_count, dj->port_count); int ch_count = soundio_int_min(instream->layout.channel_count, dj->port_count);
for (int ch = 0; ch < ch_count; ch += 1) { for (int ch = 0; ch < ch_count; ch += 1) {
SoundIoInStreamJackPort *isjp = &isj->ports[ch]; struct SoundIoInStreamJackPort *isjp = &isj->ports[ch];
SoundIoDeviceJackPort *djp = &dj->ports[ch]; struct SoundIoDeviceJackPort *djp = &dj->ports[ch];
isjp->source_port_name = djp->full_name; isjp->source_port_name = djp->full_name;
isjp->source_port_name_len = djp->full_name_len; isjp->source_port_name_len = djp->full_name_len;
max_port_latency = max(max_port_latency, djp->latency_range.max); max_port_latency = nframes_max(max_port_latency, djp->latency_range.max);
} }
} }
@ -735,7 +742,7 @@ static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamP
} }
static int instream_pause_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) { static int instream_pause_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
SoundIoJack *sij = &si->backend_data.jack; struct SoundIoJack *sij = &si->backend_data.jack;
if (sij->is_shutdown) if (sij->is_shutdown)
return SoundIoErrorBackendDisconnected; return SoundIoErrorBackendDisconnected;
@ -744,9 +751,9 @@ static int instream_pause_jack(struct SoundIoPrivate *si, struct SoundIoInStream
} }
static int instream_start_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) { static int instream_start_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStreamJack *isj = &is->backend_data.jack; struct SoundIoInStreamJack *isj = &is->backend_data.jack;
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
SoundIoJack *sij = &si->backend_data.jack; struct SoundIoJack *sij = &si->backend_data.jack;
int err; int err;
if (sij->is_shutdown) if (sij->is_shutdown)
@ -756,7 +763,7 @@ static int instream_start_jack(struct SoundIoPrivate *si, struct SoundIoInStream
return SoundIoErrorStreaming; return SoundIoErrorStreaming;
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) { for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
SoundIoInStreamJackPort *isjp = &isj->ports[ch]; struct SoundIoInStreamJackPort *isjp = &isj->ports[ch];
const char *source_port_name = isjp->source_port_name; const char *source_port_name = isjp->source_port_name;
// allow unconnected ports // allow unconnected ports
if (!source_port_name) if (!source_port_name)
@ -770,9 +777,9 @@ static int instream_start_jack(struct SoundIoPrivate *si, struct SoundIoInStream
} }
static int instream_begin_read_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, static int instream_begin_read_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
SoundIoChannelArea **out_areas, int *frame_count) struct SoundIoChannelArea **out_areas, int *frame_count)
{ {
SoundIoInStreamJack *isj = &is->backend_data.jack; struct SoundIoInStreamJack *isj = &is->backend_data.jack;
if (*frame_count != isj->frames_left) if (*frame_count != isj->frames_left)
return SoundIoErrorInvalid; return SoundIoErrorInvalid;
@ -783,7 +790,7 @@ static int instream_begin_read_jack(struct SoundIoPrivate *si, struct SoundIoInS
} }
static int instream_end_read_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) { static int instream_end_read_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStreamJack *isj = &is->backend_data.jack; struct SoundIoInStreamJack *isj = &is->backend_data.jack;
isj->frames_left = 0; isj->frames_left = 0;
return 0; return 0;
} }
@ -791,15 +798,15 @@ static int instream_end_read_jack(struct SoundIoPrivate *si, struct SoundIoInStr
static int instream_get_latency_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, static int instream_get_latency_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
double *out_latency) double *out_latency)
{ {
SoundIoInStreamJack *isj = &is->backend_data.jack; struct SoundIoInStreamJack *isj = &is->backend_data.jack;
*out_latency = isj->hardware_latency; *out_latency = isj->hardware_latency;
return 0; return 0;
} }
static void notify_devices_change(SoundIoPrivate *si) { static void notify_devices_change(struct SoundIoPrivate *si) {
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoJack *sij = &si->backend_data.jack; struct SoundIoJack *sij = &si->backend_data.jack;
sij->refresh_devices_flag.clear(); atomic_flag_clear(&sij->refresh_devices_flag);
soundio_os_mutex_lock(sij->mutex); soundio_os_mutex_lock(sij->mutex);
soundio_os_cond_signal(sij->cond, sij->mutex); soundio_os_cond_signal(sij->cond, sij->mutex);
soundio->on_events_signal(soundio); soundio->on_events_signal(soundio);
@ -807,37 +814,37 @@ static void notify_devices_change(SoundIoPrivate *si) {
} }
static int buffer_size_callback(jack_nframes_t nframes, void *arg) { static int buffer_size_callback(jack_nframes_t nframes, void *arg) {
SoundIoPrivate *si = (SoundIoPrivate *)arg; struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
SoundIoJack *sij = &si->backend_data.jack; struct SoundIoJack *sij = &si->backend_data.jack;
sij->period_size = nframes; sij->period_size = nframes;
notify_devices_change(si); notify_devices_change(si);
return 0; return 0;
} }
static int sample_rate_callback(jack_nframes_t nframes, void *arg) { static int sample_rate_callback(jack_nframes_t nframes, void *arg) {
SoundIoPrivate *si = (SoundIoPrivate *)arg; struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
SoundIoJack *sij = &si->backend_data.jack; struct SoundIoJack *sij = &si->backend_data.jack;
sij->sample_rate = nframes; sij->sample_rate = nframes;
notify_devices_change(si); notify_devices_change(si);
return 0; return 0;
} }
static void port_registration_callback(jack_port_id_t port_id, int reg, void *arg) { static void port_registration_callback(jack_port_id_t port_id, int reg, void *arg) {
SoundIoPrivate *si = (SoundIoPrivate *)arg; struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
notify_devices_change(si); notify_devices_change(si);
} }
static void port_rename_calllback(jack_port_id_t port_id, static void port_rename_calllback(jack_port_id_t port_id,
const char *old_name, const char *new_name, void *arg) const char *old_name, const char *new_name, void *arg)
{ {
SoundIoPrivate *si = (SoundIoPrivate *)arg; struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
notify_devices_change(si); notify_devices_change(si);
} }
static void shutdown_callback(void *arg) { static void shutdown_callback(void *arg) {
SoundIoPrivate *si = (SoundIoPrivate *)arg; struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoJack *sij = &si->backend_data.jack; struct SoundIoJack *sij = &si->backend_data.jack;
soundio_os_mutex_lock(sij->mutex); soundio_os_mutex_lock(sij->mutex);
sij->is_shutdown = true; sij->is_shutdown = true;
soundio_os_cond_signal(sij->cond, sij->mutex); soundio_os_cond_signal(sij->cond, sij->mutex);
@ -845,8 +852,8 @@ static void shutdown_callback(void *arg) {
soundio_os_mutex_unlock(sij->mutex); soundio_os_mutex_unlock(sij->mutex);
} }
static void destroy_jack(SoundIoPrivate *si) { static void destroy_jack(struct SoundIoPrivate *si) {
SoundIoJack *sij = &si->backend_data.jack; struct SoundIoJack *sij = &si->backend_data.jack;
if (sij->client) if (sij->client)
jack_client_close(sij->client); jack_client_close(sij->client);
@ -859,15 +866,15 @@ static void destroy_jack(SoundIoPrivate *si) {
} }
int soundio_jack_init(struct SoundIoPrivate *si) { int soundio_jack_init(struct SoundIoPrivate *si) {
SoundIoJack *sij = &si->backend_data.jack; struct SoundIoJack *sij = &si->backend_data.jack;
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
if (!global_msg_callback_flag.test_and_set()) { if (!atomic_flag_test_and_set(&global_msg_callback_flag)) {
if (soundio->jack_error_callback) if (soundio->jack_error_callback)
jack_set_error_function(soundio->jack_error_callback); jack_set_error_function(soundio->jack_error_callback);
if (soundio->jack_info_callback) if (soundio->jack_info_callback)
jack_set_info_function(soundio->jack_info_callback); jack_set_info_function(soundio->jack_info_callback);
global_msg_callback_flag.clear(); atomic_flag_clear(&global_msg_callback_flag);
} }
sij->mutex = soundio_os_mutex_create(); sij->mutex = soundio_os_mutex_create();
@ -916,7 +923,7 @@ int soundio_jack_init(struct SoundIoPrivate *si) {
} }
jack_on_shutdown(sij->client, shutdown_callback, si); jack_on_shutdown(sij->client, shutdown_callback, si);
sij->refresh_devices_flag.clear(); atomic_flag_clear(&sij->refresh_devices_flag);
sij->period_size = jack_get_buffer_size(sij->client); sij->period_size = jack_get_buffer_size(sij->client);
sij->sample_rate = jack_get_sample_rate(sij->client); sij->sample_rate = jack_get_sample_rate(sij->client);

View file

@ -5,33 +5,39 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#ifndef SOUNDIO_JACK_HPP #ifndef SOUNDIO_JACK_H
#define SOUNDIO_JACK_HPP #define SOUNDIO_JACK_H
#include "soundio_private.h" #include "soundio_internal.h"
#include "os.h" #include "os.h"
#include "atomics.hpp" #include "atomics.h"
// jack.h does not properly put `void` in function prototypes with no
// arguments, so we're forced to temporarily disable -Werror=strict-prototypes
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
#include <jack/jack.h> #include <jack/jack.h>
#pragma GCC diagnostic pop
struct SoundIoPrivate;
int soundio_jack_init(struct SoundIoPrivate *si); int soundio_jack_init(struct SoundIoPrivate *si);
struct SoundIoDeviceJackPort { struct SoundIoDeviceJackPort {
char *full_name; char *full_name;
int full_name_len; int full_name_len;
SoundIoChannelId channel_id; enum SoundIoChannelId channel_id;
jack_latency_range_t latency_range; jack_latency_range_t latency_range;
}; };
struct SoundIoDeviceJack { struct SoundIoDeviceJack {
int port_count; int port_count;
SoundIoDeviceJackPort *ports; struct SoundIoDeviceJackPort *ports;
}; };
struct SoundIoJack { struct SoundIoJack {
jack_client_t *client; jack_client_t *client;
SoundIoOsMutex *mutex; struct SoundIoOsMutex *mutex;
SoundIoOsCond *cond; struct SoundIoOsCond *cond;
atomic_flag refresh_devices_flag; atomic_flag refresh_devices_flag;
int sample_rate; int sample_rate;
int period_size; int period_size;
@ -50,8 +56,8 @@ struct SoundIoOutStreamJack {
int period_size; int period_size;
int frames_left; int frames_left;
double hardware_latency; double hardware_latency;
SoundIoOutStreamJackPort ports[SOUNDIO_MAX_CHANNELS]; struct SoundIoOutStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS]; struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
}; };
struct SoundIoInStreamJackPort { struct SoundIoInStreamJackPort {
@ -65,8 +71,8 @@ struct SoundIoInStreamJack {
int period_size; int period_size;
int frames_left; int frames_left;
double hardware_latency; double hardware_latency;
SoundIoInStreamJackPort ports[SOUNDIO_MAX_CHANNELS]; struct SoundIoInStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS]; struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
char *buf_ptrs[SOUNDIO_MAX_CHANNELS]; char *buf_ptrs[SOUNDIO_MAX_CHANNELS];
}; };

145
src/list.h Normal file
View file

@ -0,0 +1,145 @@
/*
* Copyright (c) 2015 Andrew Kelley
*
* This file is part of libsoundio, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
#ifndef SOUNDIO_LIST_H
#define SOUNDIO_LIST_H
#include "util.h"
#include "soundio_internal.h"
#include <assert.h>
#define SOUNDIO_LIST_STATIC static
#define SOUNDIO_LIST_NOT_STATIC
#define SOUNDIO_MAKE_LIST_STRUCT(Type, Name, static_kw) \
struct Name { \
Type *items; \
int length; \
int capacity; \
};
#define SOUNDIO_MAKE_LIST_PROTO(Type, Name, static_kw) \
static_kw void Name##_deinit(struct Name *s); \
static_kw int __attribute__((warn_unused_result)) Name##_append(struct Name *s, Type item); \
static_kw Type Name##_val_at(struct Name *s, int index); \
static_kw Type * Name##_ptr_at(struct Name *s, int index); \
static_kw Type Name##_pop(struct Name *s); \
static_kw int __attribute__((warn_unused_result)) Name##_add_one(struct Name *s); \
static_kw Type Name##_last_val(struct Name *s); \
static_kw Type *Name##_last_ptr(struct Name *s); \
static_kw int __attribute__((warn_unused_result)) Name##_resize(struct Name *s, int new_length); \
static_kw void Name##_clear(struct Name *s); \
static_kw int __attribute__((warn_unused_result)) \
Name##_ensure_capacity(struct Name *s, int new_capacity); \
static_kw Type Name##_swap_remove(struct Name *s, int index);
#define SOUNDIO_MAKE_LIST_DEF(Type, Name, static_kw) \
__attribute__ ((unused)) \
static_kw void Name##_deinit(struct Name *s) { \
free(s->items); \
} \
\
__attribute__ ((unused)) \
__attribute__ ((warn_unused_result)) \
static_kw int Name##_ensure_capacity(struct Name *s, int new_capacity) { \
int better_capacity = soundio_int_max(s->capacity, 16); \
while (better_capacity < new_capacity) \
better_capacity = better_capacity * 2; \
if (better_capacity != s->capacity) { \
Type *new_items = REALLOCATE_NONZERO(Type, s->items, better_capacity); \
if (!new_items) \
return SoundIoErrorNoMem; \
s->items = new_items; \
s->capacity = better_capacity; \
} \
return 0; \
} \
\
__attribute__ ((unused)) \
__attribute__ ((warn_unused_result)) \
static_kw int Name##_append(struct Name *s, Type item) { \
int err = Name##_ensure_capacity(s, s->length + 1); \
if (err) \
return err; \
s->items[s->length] = item; \
s->length += 1; \
return 0; \
} \
\
__attribute__ ((unused)) \
static_kw Type Name##_val_at(struct Name *s, int index) { \
assert(index >= 0); \
assert(index < s->length); \
return s->items[index]; \
} \
\
/* remember that the pointer to this item is invalid after you \
* modify the length of the list \
*/ \
__attribute__ ((unused)) \
static_kw Type * Name##_ptr_at(struct Name *s, int index) { \
assert(index >= 0); \
assert(index < s->length); \
return &s->items[index]; \
} \
\
__attribute__ ((unused)) \
static_kw Type Name##_pop(struct Name *s) { \
assert(s->length >= 1); \
s->length -= 1; \
return s->items[s->length]; \
} \
\
__attribute__ ((unused)) \
__attribute__ ((warn_unused_result)) \
static_kw int Name##_resize(struct Name *s, int new_length) { \
assert(new_length >= 0); \
int err = Name##_ensure_capacity(s, new_length); \
if (err) \
return err; \
s->length = new_length; \
return 0; \
} \
\
__attribute__ ((unused)) \
__attribute__ ((warn_unused_result)) \
static_kw int Name##_add_one(struct Name *s) { \
return Name##_resize(s, s->length + 1); \
} \
\
__attribute__ ((unused)) \
static_kw Type Name##_last_val(struct Name *s) { \
assert(s->length >= 1); \
return s->items[s->length - 1]; \
} \
\
__attribute__ ((unused)) \
static_kw Type *Name##_last_ptr(struct Name *s) { \
assert(s->length >= 1); \
return &s->items[s->length - 1]; \
} \
\
__attribute__ ((unused)) \
static_kw void Name##_clear(struct Name *s) { \
s->length = 0; \
} \
\
__attribute__ ((unused)) \
static_kw Type Name##_swap_remove(struct Name *s, int index) { \
assert(index >= 0); \
assert(index < s->length); \
Type last = Name##_pop(s); \
if (index == s->length) \
return last; \
Type item = s->items[index]; \
s->items[index] = last; \
return item; \
}
#endif

View file

@ -1,102 +0,0 @@
/*
* Copyright (c) 2015 Andrew Kelley
*
* This file is part of libsoundio, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
#ifndef SOUNDIO_LIST_HPP
#define SOUNDIO_LIST_HPP
#include "util.hpp"
#include "soundio_private.h"
#include <assert.h>
template<typename T>
struct SoundIoList {
void deinit() {
free(items);
}
int __attribute__((warn_unused_result)) append(T item) {
int err = ensure_capacity(length + 1);
if (err)
return err;
items[length++] = item;
return 0;
}
// remember that the pointer to this item is invalid after you
// modify the length of the list
const T & at(int index) const {
assert(index >= 0);
assert(index < length);
return items[index];
}
T & at(int index) {
assert(index >= 0);
assert(index < length);
return items[index];
}
T pop() {
assert(length >= 1);
return items[--length];
}
int __attribute__((warn_unused_result)) add_one() {
return resize(length + 1);
}
const T & last() const {
assert(length >= 1);
return items[length - 1];
}
T & last() {
assert(length >= 1);
return items[length - 1];
}
int __attribute__((warn_unused_result)) resize(int new_length) {
assert(new_length >= 0);
int err = ensure_capacity(new_length);
if (err)
return err;
length = new_length;
return 0;
}
void clear() {
length = 0;
}
int __attribute__((warn_unused_result)) ensure_capacity(int new_capacity) {
int better_capacity = max(capacity, 16);
while (better_capacity < new_capacity)
better_capacity = better_capacity * 2;
if (better_capacity != capacity) {
T *new_items = reallocate_nonzero(items, better_capacity);
if (!new_items)
return SoundIoErrorNoMem;
items = new_items;
capacity = better_capacity;
}
return 0;
}
T swap_remove(int index) {
assert(index >= 0);
assert(index < length);
T last = pop();
if (index == length)
return last;
T item = items[index];
items[index] = last;
return item;
}
T * items;
int length;
int capacity;
};
#endif

View file

@ -5,9 +5,16 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#if defined(__APPLE__)
#define _DARWIN_C_SOURCE
#undef _POSIX_C_SOURCE
#else
#define _GNU_SOURCE
#endif
#include "os.h" #include "os.h"
#include "soundio_private.h" #include "soundio_internal.h"
#include "util.hpp" #include "util.h"
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
@ -53,7 +60,7 @@
#include <pthread.h> #include <pthread.h>
#include <unistd.h> #include <unistd.h>
#include <sys/mman.h> #include <sys/mman.h>
#ifndef MAP_ANONYMOUS #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
#define MAP_ANONYMOUS MAP_ANON #define MAP_ANONYMOUS MAP_ANON
#endif #endif
@ -159,7 +166,7 @@ double soundio_os_get_time(void) {
#if defined(SOUNDIO_OS_WINDOWS) #if defined(SOUNDIO_OS_WINDOWS)
static DWORD WINAPI run_win32_thread(LPVOID userdata) { static DWORD WINAPI run_win32_thread(LPVOID userdata) {
struct SoundIoOsThread *thread = (struct SoundIoOsThread *)userdata; struct SoundIoOsThread *thread = (struct SoundIoOsThread *)userdata;
HRESULT err = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); HRESULT err = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
assert(err == S_OK); assert(err == S_OK);
thread->run(thread->arg); thread->run(thread->arg);
CoUninitialize(); CoUninitialize();
@ -184,7 +191,7 @@ int soundio_os_thread_create(
{ {
*out_thread = NULL; *out_thread = NULL;
struct SoundIoOsThread *thread = allocate<SoundIoOsThread>(1); struct SoundIoOsThread *thread = ALLOCATE(struct SoundIoOsThread, 1);
if (!thread) { if (!thread) {
soundio_os_thread_destroy(thread); soundio_os_thread_destroy(thread);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
@ -276,7 +283,7 @@ void soundio_os_thread_destroy(struct SoundIoOsThread *thread) {
} }
struct SoundIoOsMutex *soundio_os_mutex_create(void) { struct SoundIoOsMutex *soundio_os_mutex_create(void) {
struct SoundIoOsMutex *mutex = allocate<SoundIoOsMutex>(1); struct SoundIoOsMutex *mutex = ALLOCATE(struct SoundIoOsMutex, 1);
if (!mutex) { if (!mutex) {
soundio_os_mutex_destroy(mutex); soundio_os_mutex_destroy(mutex);
return NULL; return NULL;
@ -328,7 +335,7 @@ void soundio_os_mutex_unlock(struct SoundIoOsMutex *mutex) {
} }
struct SoundIoOsCond * soundio_os_cond_create(void) { struct SoundIoOsCond * soundio_os_cond_create(void) {
struct SoundIoOsCond *cond = allocate<SoundIoOsCond>(1); struct SoundIoOsCond *cond = ALLOCATE(struct SoundIoOsCond, 1);
if (!cond) { if (!cond) {
soundio_os_cond_destroy(cond); soundio_os_cond_destroy(cond);
@ -558,7 +565,7 @@ static int internal_init(void) {
GetSystemInfo(&win32_system_info); GetSystemInfo(&win32_system_info);
page_size = win32_system_info.dwAllocationGranularity; page_size = win32_system_info.dwAllocationGranularity;
#else #else
page_size = getpagesize(); page_size = sysconf(_SC_PAGESIZE);
#if defined(__MACH__) #if defined(__MACH__)
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
#endif #endif
@ -581,7 +588,7 @@ int soundio_os_init(void) {
if ((err = internal_init())) if ((err = internal_init()))
return err; return err;
if (!InitOnceComplete(&win32_init_once, INIT_ONCE_ASYNC, nullptr)) if (!InitOnceComplete(&win32_init_once, INIT_ONCE_ASYNC, NULL))
return SoundIoErrorSystemResources; return SoundIoErrorSystemResources;
#else #else
assert_no_err(pthread_mutex_lock(&init_mutex)); assert_no_err(pthread_mutex_lock(&init_mutex));
@ -734,5 +741,5 @@ void soundio_os_deinit_mirrored_memory(struct SoundIoOsMirroredMemory *mem) {
int err = munmap(mem->address, 2 * mem->capacity); int err = munmap(mem->address, 2 * mem->capacity);
assert(!err); assert(!err);
#endif #endif
mem->address = nullptr; mem->address = NULL;
} }

View file

@ -5,8 +5,8 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#include "pulseaudio.hpp" #include "pulseaudio.h"
#include "soundio.hpp" #include "soundio_private.h"
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
@ -15,19 +15,19 @@
static void subscribe_callback(pa_context *context, static void subscribe_callback(pa_context *context,
pa_subscription_event_type_t event_bits, uint32_t index, void *userdata) pa_subscription_event_type_t event_bits, uint32_t index, void *userdata)
{ {
SoundIoPrivate *si = (SoundIoPrivate *)userdata; struct SoundIoPrivate *si = (struct SoundIoPrivate *)userdata;
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
sipa->device_scan_queued = true; sipa->device_scan_queued = true;
pa_threaded_mainloop_signal(sipa->main_loop, 0); pa_threaded_mainloop_signal(sipa->main_loop, 0);
soundio->on_events_signal(soundio); soundio->on_events_signal(soundio);
} }
static int subscribe_to_events(SoundIoPrivate *si) { static int subscribe_to_events(struct SoundIoPrivate *si) {
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
pa_subscription_mask_t events = (pa_subscription_mask_t)( pa_subscription_mask_t events = (pa_subscription_mask_t)(
PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE|PA_SUBSCRIPTION_MASK_SERVER); PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE|PA_SUBSCRIPTION_MASK_SERVER);
pa_operation *subscribe_op = pa_context_subscribe(sipa->pulse_context, events, nullptr, si); pa_operation *subscribe_op = pa_context_subscribe(sipa->pulse_context, events, NULL, si);
if (!subscribe_op) if (!subscribe_op)
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
pa_operation_unref(subscribe_op); pa_operation_unref(subscribe_op);
@ -35,9 +35,9 @@ static int subscribe_to_events(SoundIoPrivate *si) {
} }
static void context_state_callback(pa_context *context, void *userdata) { static void context_state_callback(pa_context *context, void *userdata) {
SoundIoPrivate *si = (SoundIoPrivate *)userdata; struct SoundIoPrivate *si = (struct SoundIoPrivate *)userdata;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
switch (pa_context_get_state(context)) { switch (pa_context_get_state(context)) {
case PA_CONTEXT_UNCONNECTED: // The context hasn't been connected yet. case PA_CONTEXT_UNCONNECTED: // The context hasn't been connected yet.
@ -68,8 +68,8 @@ static void context_state_callback(pa_context *context, void *userdata) {
} }
} }
static void destroy_pa(SoundIoPrivate *si) { static void destroy_pa(struct SoundIoPrivate *si) {
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
if (sipa->main_loop) if (sipa->main_loop)
pa_threaded_mainloop_stop(sipa->main_loop); pa_threaded_mainloop_stop(sipa->main_loop);
@ -90,7 +90,7 @@ static void destroy_pa(SoundIoPrivate *si) {
free(sipa->default_source_name); free(sipa->default_source_name);
} }
static SoundIoFormat from_pulseaudio_format(pa_sample_spec sample_spec) { static enum SoundIoFormat from_pulseaudio_format(pa_sample_spec sample_spec) {
switch (sample_spec.format) { switch (sample_spec.format) {
case PA_SAMPLE_U8: return SoundIoFormatU8; case PA_SAMPLE_U8: return SoundIoFormatU8;
case PA_SAMPLE_S16LE: return SoundIoFormatS16LE; case PA_SAMPLE_S16LE: return SoundIoFormatS16LE;
@ -113,7 +113,7 @@ static SoundIoFormat from_pulseaudio_format(pa_sample_spec sample_spec) {
return SoundIoFormatInvalid; return SoundIoFormatInvalid;
} }
static SoundIoChannelId from_pulseaudio_channel_pos(pa_channel_position_t pos) { static enum SoundIoChannelId from_pulseaudio_channel_pos(pa_channel_position_t pos) {
switch (pos) { switch (pos) {
case PA_CHANNEL_POSITION_MONO: return SoundIoChannelIdFrontCenter; case PA_CHANNEL_POSITION_MONO: return SoundIoChannelIdFrontCenter;
case PA_CHANNEL_POSITION_FRONT_LEFT: return SoundIoChannelIdFrontLeft; case PA_CHANNEL_POSITION_FRONT_LEFT: return SoundIoChannelIdFrontLeft;
@ -156,15 +156,15 @@ static SoundIoChannelId from_pulseaudio_channel_pos(pa_channel_position_t pos) {
} }
} }
static void set_from_pulseaudio_channel_map(pa_channel_map channel_map, SoundIoChannelLayout *channel_layout) { static void set_from_pulseaudio_channel_map(pa_channel_map channel_map, struct SoundIoChannelLayout *channel_layout) {
channel_layout->channel_count = channel_map.channels; channel_layout->channel_count = channel_map.channels;
for (int i = 0; i < channel_map.channels; i += 1) { for (int i = 0; i < channel_map.channels; i += 1) {
channel_layout->channels[i] = from_pulseaudio_channel_pos(channel_map.map[i]); channel_layout->channels[i] = from_pulseaudio_channel_pos(channel_map.map[i]);
} }
channel_layout->name = nullptr; channel_layout->name = NULL;
int builtin_layout_count = soundio_channel_layout_builtin_count(); int builtin_layout_count = soundio_channel_layout_builtin_count();
for (int i = 0; i < builtin_layout_count; i += 1) { for (int i = 0; i < builtin_layout_count; i += 1) {
const SoundIoChannelLayout *builtin_layout = soundio_channel_layout_get_builtin(i); const struct SoundIoChannelLayout *builtin_layout = soundio_channel_layout_get_builtin(i);
if (soundio_channel_layout_equal(builtin_layout, channel_layout)) { if (soundio_channel_layout_equal(builtin_layout, channel_layout)) {
channel_layout->name = builtin_layout->name; channel_layout->name = builtin_layout->name;
break; break;
@ -172,9 +172,9 @@ static void set_from_pulseaudio_channel_map(pa_channel_map channel_map, SoundIoC
} }
} }
static int set_all_device_channel_layouts(SoundIoDevice *device) { static int set_all_device_channel_layouts(struct SoundIoDevice *device) {
device->layout_count = soundio_channel_layout_builtin_count(); device->layout_count = soundio_channel_layout_builtin_count();
device->layouts = allocate<SoundIoChannelLayout>(device->layout_count); device->layouts = ALLOCATE(struct SoundIoChannelLayout, device->layout_count);
if (!device->layouts) if (!device->layouts)
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
for (int i = 0; i < device->layout_count; i += 1) for (int i = 0; i < device->layout_count; i += 1)
@ -182,9 +182,9 @@ static int set_all_device_channel_layouts(SoundIoDevice *device) {
return 0; return 0;
} }
static int set_all_device_formats(SoundIoDevice *device) { static int set_all_device_formats(struct SoundIoDevice *device) {
device->format_count = 9; device->format_count = 9;
device->formats = allocate<SoundIoFormat>(device->format_count); device->formats = ALLOCATE(enum SoundIoFormat, device->format_count);
if (!device->formats) if (!device->formats)
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
device->formats[0] = SoundIoFormatU8; device->formats[0] = SoundIoFormatU8;
@ -199,10 +199,10 @@ static int set_all_device_formats(SoundIoDevice *device) {
return 0; return 0;
} }
static int perform_operation(SoundIoPrivate *si, pa_operation *op) { static int perform_operation(struct SoundIoPrivate *si, pa_operation *op) {
if (!op) if (!op)
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
for (;;) { for (;;) {
switch (pa_operation_get_state(op)) { switch (pa_operation_get_state(op)) {
case PA_OPERATION_RUNNING: case PA_OPERATION_RUNNING:
@ -219,9 +219,9 @@ static int perform_operation(SoundIoPrivate *si, pa_operation *op) {
} }
static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *info, int eol, void *userdata) { static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *info, int eol, void *userdata) {
SoundIoPrivate *si = (SoundIoPrivate *)userdata; struct SoundIoPrivate *si = (struct SoundIoPrivate *)userdata;
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
int err; int err;
if (eol) { if (eol) {
pa_threaded_mainloop_signal(sipa->main_loop, 0); pa_threaded_mainloop_signal(sipa->main_loop, 0);
@ -230,12 +230,12 @@ static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *in
if (sipa->device_query_err) if (sipa->device_query_err)
return; return;
SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1); struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
if (!dev) { if (!dev) {
sipa->device_query_err = SoundIoErrorNoMem; sipa->device_query_err = SoundIoErrorNoMem;
return; return;
} }
SoundIoDevice *device = &dev->pub; struct SoundIoDevice *device = &dev->pub;
device->ref_count = 1; device->ref_count = 1;
device->soundio = soundio; device->soundio = soundio;
@ -252,8 +252,8 @@ static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *in
// some reasonable min and max values. // some reasonable min and max values.
device->sample_rate_count = 1; device->sample_rate_count = 1;
device->sample_rates = &dev->prealloc_sample_rate_range; device->sample_rates = &dev->prealloc_sample_rate_range;
device->sample_rates[0].min = min(SOUNDIO_MIN_SAMPLE_RATE, device->sample_rate_current); device->sample_rates[0].min = soundio_int_min(SOUNDIO_MIN_SAMPLE_RATE, device->sample_rate_current);
device->sample_rates[0].max = max(SOUNDIO_MAX_SAMPLE_RATE, device->sample_rate_current); device->sample_rates[0].max = soundio_int_max(SOUNDIO_MAX_SAMPLE_RATE, device->sample_rate_current);
device->current_format = from_pulseaudio_format(info->sample_spec); device->current_format = from_pulseaudio_format(info->sample_spec);
// PulseAudio performs sample format conversion, so any PulseAudio // PulseAudio performs sample format conversion, so any PulseAudio
@ -274,7 +274,7 @@ static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *in
device->aim = SoundIoDeviceAimOutput; device->aim = SoundIoDeviceAimOutput;
if (sipa->current_devices_info->output_devices.append(device)) { if (SoundIoListDevicePtr_append(&sipa->current_devices_info->output_devices, device)) {
soundio_device_unref(device); soundio_device_unref(device);
sipa->device_query_err = SoundIoErrorNoMem; sipa->device_query_err = SoundIoErrorNoMem;
return; return;
@ -282,9 +282,9 @@ static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *in
} }
static void source_info_callback(pa_context *pulse_context, const pa_source_info *info, int eol, void *userdata) { static void source_info_callback(pa_context *pulse_context, const pa_source_info *info, int eol, void *userdata) {
SoundIoPrivate *si = (SoundIoPrivate *)userdata; struct SoundIoPrivate *si = (struct SoundIoPrivate *)userdata;
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
int err; int err;
if (eol) { if (eol) {
@ -294,12 +294,12 @@ static void source_info_callback(pa_context *pulse_context, const pa_source_info
if (sipa->device_query_err) if (sipa->device_query_err)
return; return;
SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1); struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
if (!dev) { if (!dev) {
sipa->device_query_err = SoundIoErrorNoMem; sipa->device_query_err = SoundIoErrorNoMem;
return; return;
} }
SoundIoDevice *device = &dev->pub; struct SoundIoDevice *device = &dev->pub;
device->ref_count = 1; device->ref_count = 1;
device->soundio = soundio; device->soundio = soundio;
@ -316,8 +316,8 @@ static void source_info_callback(pa_context *pulse_context, const pa_source_info
// some reasonable min and max values. // some reasonable min and max values.
device->sample_rate_count = 1; device->sample_rate_count = 1;
device->sample_rates = &dev->prealloc_sample_rate_range; device->sample_rates = &dev->prealloc_sample_rate_range;
device->sample_rates[0].min = min(8000, device->sample_rate_current); device->sample_rates[0].min = soundio_int_min(SOUNDIO_MIN_SAMPLE_RATE, device->sample_rate_current);
device->sample_rates[0].max = max(5644800, device->sample_rate_current); device->sample_rates[0].max = soundio_int_max(SOUNDIO_MAX_SAMPLE_RATE, device->sample_rate_current);
device->current_format = from_pulseaudio_format(info->sample_spec); device->current_format = from_pulseaudio_format(info->sample_spec);
// PulseAudio performs sample format conversion, so any PulseAudio // PulseAudio performs sample format conversion, so any PulseAudio
@ -338,7 +338,7 @@ static void source_info_callback(pa_context *pulse_context, const pa_source_info
device->aim = SoundIoDeviceAimInput; device->aim = SoundIoDeviceAimInput;
if (sipa->current_devices_info->input_devices.append(device)) { if (SoundIoListDevicePtr_append(&sipa->current_devices_info->input_devices, device)) {
soundio_device_unref(device); soundio_device_unref(device);
sipa->device_query_err = SoundIoErrorNoMem; sipa->device_query_err = SoundIoErrorNoMem;
return; return;
@ -346,9 +346,9 @@ static void source_info_callback(pa_context *pulse_context, const pa_source_info
} }
static void server_info_callback(pa_context *pulse_context, const pa_server_info *info, void *userdata) { static void server_info_callback(pa_context *pulse_context, const pa_server_info *info, void *userdata) {
SoundIoPrivate *si = (SoundIoPrivate *)userdata; struct SoundIoPrivate *si = (struct SoundIoPrivate *)userdata;
assert(si); assert(si);
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
assert(!sipa->default_sink_name); assert(!sipa->default_sink_name);
assert(!sipa->default_source_name); assert(!sipa->default_source_name);
@ -363,26 +363,26 @@ static void server_info_callback(pa_context *pulse_context, const pa_server_info
} }
// always called even when refresh_devices succeeds // always called even when refresh_devices succeeds
static void cleanup_refresh_devices(SoundIoPrivate *si) { static void cleanup_refresh_devices(struct SoundIoPrivate *si) {
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
soundio_destroy_devices_info(sipa->current_devices_info); soundio_destroy_devices_info(sipa->current_devices_info);
sipa->current_devices_info = nullptr; sipa->current_devices_info = NULL;
free(sipa->default_sink_name); free(sipa->default_sink_name);
sipa->default_sink_name = nullptr; sipa->default_sink_name = NULL;
free(sipa->default_source_name); free(sipa->default_source_name);
sipa->default_source_name = nullptr; sipa->default_source_name = NULL;
} }
// call this while holding the main loop lock // call this while holding the main loop lock
static int refresh_devices(SoundIoPrivate *si) { static int refresh_devices(struct SoundIoPrivate *si) {
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
assert(!sipa->current_devices_info); assert(!sipa->current_devices_info);
sipa->current_devices_info = allocate<SoundIoDevicesInfo>(1); sipa->current_devices_info = ALLOCATE(struct SoundIoDevicesInfo, 1);
if (!sipa->current_devices_info) if (!sipa->current_devices_info)
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
@ -414,7 +414,9 @@ static int refresh_devices(SoundIoPrivate *si) {
if (sipa->current_devices_info->input_devices.length > 0) { if (sipa->current_devices_info->input_devices.length > 0) {
sipa->current_devices_info->default_input_index = 0; sipa->current_devices_info->default_input_index = 0;
for (int i = 0; i < sipa->current_devices_info->input_devices.length; i += 1) { for (int i = 0; i < sipa->current_devices_info->input_devices.length; i += 1) {
SoundIoDevice *device = sipa->current_devices_info->input_devices.at(i); struct SoundIoDevice *device = SoundIoListDevicePtr_val_at(
&sipa->current_devices_info->input_devices, i);
assert(device->aim == SoundIoDeviceAimInput); assert(device->aim == SoundIoDeviceAimInput);
if (strcmp(device->id, sipa->default_source_name) == 0) { if (strcmp(device->id, sipa->default_source_name) == 0) {
sipa->current_devices_info->default_input_index = i; sipa->current_devices_info->default_input_index = i;
@ -425,7 +427,9 @@ static int refresh_devices(SoundIoPrivate *si) {
if (sipa->current_devices_info->output_devices.length > 0) { if (sipa->current_devices_info->output_devices.length > 0) {
sipa->current_devices_info->default_output_index = 0; sipa->current_devices_info->default_output_index = 0;
for (int i = 0; i < sipa->current_devices_info->output_devices.length; i += 1) { for (int i = 0; i < sipa->current_devices_info->output_devices.length; i += 1) {
SoundIoDevice *device = sipa->current_devices_info->output_devices.at(i); struct SoundIoDevice *device = SoundIoListDevicePtr_val_at(
&sipa->current_devices_info->output_devices, i);
assert(device->aim == SoundIoDeviceAimOutput); assert(device->aim == SoundIoDeviceAimOutput);
if (strcmp(device->id, sipa->default_sink_name) == 0) { if (strcmp(device->id, sipa->default_sink_name) == 0) {
sipa->current_devices_info->default_output_index = i; sipa->current_devices_info->default_output_index = i;
@ -435,20 +439,20 @@ static int refresh_devices(SoundIoPrivate *si) {
soundio_destroy_devices_info(sipa->ready_devices_info); soundio_destroy_devices_info(sipa->ready_devices_info);
sipa->ready_devices_info = sipa->current_devices_info; sipa->ready_devices_info = sipa->current_devices_info;
sipa->current_devices_info = nullptr; sipa->current_devices_info = NULL;
pa_threaded_mainloop_signal(sipa->main_loop, 0); pa_threaded_mainloop_signal(sipa->main_loop, 0);
soundio->on_events_signal(soundio); soundio->on_events_signal(soundio);
return 0; return 0;
} }
static void my_flush_events(SoundIoPrivate *si, bool wait) { static void my_flush_events(struct SoundIoPrivate *si, bool wait) {
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
bool change = false; bool change = false;
bool cb_shutdown = false; bool cb_shutdown = false;
SoundIoDevicesInfo *old_devices_info = nullptr; struct SoundIoDevicesInfo *old_devices_info = NULL;
pa_threaded_mainloop_lock(sipa->main_loop); pa_threaded_mainloop_lock(sipa->main_loop);
@ -467,7 +471,7 @@ static void my_flush_events(SoundIoPrivate *si, bool wait) {
} else if (sipa->ready_devices_info) { } else if (sipa->ready_devices_info) {
old_devices_info = si->safe_devices_info; old_devices_info = si->safe_devices_info;
si->safe_devices_info = sipa->ready_devices_info; si->safe_devices_info = sipa->ready_devices_info;
sipa->ready_devices_info = nullptr; sipa->ready_devices_info = NULL;
change = true; change = true;
} }
@ -481,25 +485,25 @@ static void my_flush_events(SoundIoPrivate *si, bool wait) {
soundio_destroy_devices_info(old_devices_info); soundio_destroy_devices_info(old_devices_info);
} }
static void flush_events_pa(SoundIoPrivate *si) { static void flush_events_pa(struct SoundIoPrivate *si) {
my_flush_events(si, false); my_flush_events(si, false);
} }
static void wait_events_pa(SoundIoPrivate *si) { static void wait_events_pa(struct SoundIoPrivate *si) {
my_flush_events(si, false); my_flush_events(si, false);
my_flush_events(si, true); my_flush_events(si, true);
} }
static void wakeup_pa(SoundIoPrivate *si) { static void wakeup_pa(struct SoundIoPrivate *si) {
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
pa_threaded_mainloop_lock(sipa->main_loop); pa_threaded_mainloop_lock(sipa->main_loop);
pa_threaded_mainloop_signal(sipa->main_loop, 0); pa_threaded_mainloop_signal(sipa->main_loop, 0);
pa_threaded_mainloop_unlock(sipa->main_loop); pa_threaded_mainloop_unlock(sipa->main_loop);
} }
static void force_device_scan_pa(SoundIoPrivate *si) { static void force_device_scan_pa(struct SoundIoPrivate *si) {
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
pa_threaded_mainloop_lock(sipa->main_loop); pa_threaded_mainloop_lock(sipa->main_loop);
sipa->device_scan_queued = true; sipa->device_scan_queued = true;
pa_threaded_mainloop_signal(sipa->main_loop, 0); pa_threaded_mainloop_signal(sipa->main_loop, 0);
@ -507,7 +511,7 @@ static void force_device_scan_pa(SoundIoPrivate *si) {
pa_threaded_mainloop_unlock(sipa->main_loop); pa_threaded_mainloop_unlock(sipa->main_loop);
} }
static pa_sample_format_t to_pulseaudio_format(SoundIoFormat format) { static pa_sample_format_t to_pulseaudio_format(enum SoundIoFormat format) {
switch (format) { switch (format) {
case SoundIoFormatU8: return PA_SAMPLE_U8; case SoundIoFormatU8: return PA_SAMPLE_U8;
case SoundIoFormatS16LE: return PA_SAMPLE_S16LE; case SoundIoFormatS16LE: return PA_SAMPLE_S16LE;
@ -534,7 +538,7 @@ static pa_sample_format_t to_pulseaudio_format(SoundIoFormat format) {
return PA_SAMPLE_INVALID; return PA_SAMPLE_INVALID;
} }
static pa_channel_position_t to_pulseaudio_channel_pos(SoundIoChannelId channel_id) { static pa_channel_position_t to_pulseaudio_channel_pos(enum SoundIoChannelId channel_id) {
switch (channel_id) { switch (channel_id) {
case SoundIoChannelIdFrontLeft: return PA_CHANNEL_POSITION_FRONT_LEFT; case SoundIoChannelIdFrontLeft: return PA_CHANNEL_POSITION_FRONT_LEFT;
case SoundIoChannelIdFrontRight: return PA_CHANNEL_POSITION_FRONT_RIGHT; case SoundIoChannelIdFrontRight: return PA_CHANNEL_POSITION_FRONT_RIGHT;
@ -577,7 +581,7 @@ static pa_channel_position_t to_pulseaudio_channel_pos(SoundIoChannelId channel_
} }
} }
static pa_channel_map to_pulseaudio_channel_map(const SoundIoChannelLayout *channel_layout) { static pa_channel_map to_pulseaudio_channel_map(const struct SoundIoChannelLayout *channel_layout) {
pa_channel_map channel_map; pa_channel_map channel_map;
channel_map.channels = channel_layout->channel_count; channel_map.channels = channel_layout->channel_count;
@ -590,19 +594,19 @@ static pa_channel_map to_pulseaudio_channel_map(const SoundIoChannelLayout *chan
} }
static void playback_stream_state_callback(pa_stream *stream, void *userdata) { static void playback_stream_state_callback(pa_stream *stream, void *userdata) {
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate*) userdata; struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate*) userdata;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
SoundIo *soundio = outstream->device->soundio; struct SoundIo *soundio = outstream->device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio; struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
switch (pa_stream_get_state(stream)) { switch (pa_stream_get_state(stream)) {
case PA_STREAM_UNCONNECTED: case PA_STREAM_UNCONNECTED:
case PA_STREAM_CREATING: case PA_STREAM_CREATING:
case PA_STREAM_TERMINATED: case PA_STREAM_TERMINATED:
break; break;
case PA_STREAM_READY: case PA_STREAM_READY:
ospa->stream_ready = true; SOUNDIO_ATOMIC_STORE(ospa->stream_ready, true);
pa_threaded_mainloop_signal(sipa->main_loop, 0); pa_threaded_mainloop_signal(sipa->main_loop, 0);
break; break;
case PA_STREAM_FAILED: case PA_STREAM_FAILED:
@ -612,48 +616,48 @@ static void playback_stream_state_callback(pa_stream *stream, void *userdata) {
} }
static void playback_stream_underflow_callback(pa_stream *stream, void *userdata) { static void playback_stream_underflow_callback(pa_stream *stream, void *userdata) {
SoundIoOutStream *outstream = (SoundIoOutStream*)userdata; struct SoundIoOutStream *outstream = (struct SoundIoOutStream*)userdata;
outstream->underflow_callback(outstream); outstream->underflow_callback(outstream);
} }
static void playback_stream_write_callback(pa_stream *stream, size_t nbytes, void *userdata) { static void playback_stream_write_callback(pa_stream *stream, size_t nbytes, void *userdata) {
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate*)(userdata); struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate*)(userdata);
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
int frame_count = nbytes / outstream->bytes_per_frame; int frame_count = nbytes / outstream->bytes_per_frame;
outstream->write_callback(outstream, 0, frame_count); outstream->write_callback(outstream, 0, frame_count);
} }
static void outstream_destroy_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { static void outstream_destroy_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio; struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
pa_stream *stream = ospa->stream; pa_stream *stream = ospa->stream;
if (stream) { if (stream) {
pa_threaded_mainloop_lock(sipa->main_loop); pa_threaded_mainloop_lock(sipa->main_loop);
pa_stream_set_write_callback(stream, nullptr, nullptr); pa_stream_set_write_callback(stream, NULL, NULL);
pa_stream_set_state_callback(stream, nullptr, nullptr); pa_stream_set_state_callback(stream, NULL, NULL);
pa_stream_set_underflow_callback(stream, nullptr, nullptr); pa_stream_set_underflow_callback(stream, NULL, NULL);
pa_stream_set_overflow_callback(stream, nullptr, nullptr); pa_stream_set_overflow_callback(stream, NULL, NULL);
pa_stream_disconnect(stream); pa_stream_disconnect(stream);
pa_stream_unref(stream); pa_stream_unref(stream);
pa_threaded_mainloop_unlock(sipa->main_loop); pa_threaded_mainloop_unlock(sipa->main_loop);
ospa->stream = nullptr; ospa->stream = NULL;
} }
} }
static void timing_update_callback(pa_stream *stream, int success, void *userdata) { static void timing_update_callback(pa_stream *stream, int success, void *userdata) {
SoundIoPrivate *si = (SoundIoPrivate *)userdata; struct SoundIoPrivate *si = (struct SoundIoPrivate *)userdata;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
pa_threaded_mainloop_signal(sipa->main_loop, 0); pa_threaded_mainloop_signal(sipa->main_loop, 0);
} }
static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { static int outstream_open_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio; struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
if ((unsigned)outstream->layout.channel_count > PA_CHANNELS_MAX) if ((unsigned)outstream->layout.channel_count > PA_CHANNELS_MAX)
return SoundIoErrorIncompatibleBackend; return SoundIoErrorIncompatibleBackend;
@ -661,9 +665,9 @@ static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
if (!outstream->name) if (!outstream->name)
outstream->name = "SoundIoOutStream"; outstream->name = "SoundIoOutStream";
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
ospa->stream_ready.store(false); SOUNDIO_ATOMIC_STORE(ospa->stream_ready, false);
ospa->clear_buffer_flag.test_and_set(); atomic_flag_test_and_set(&ospa->clear_buffer_flag);
assert(sipa->pulse_context); assert(sipa->pulse_context);
@ -704,13 +708,13 @@ static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
int err = pa_stream_connect_playback(ospa->stream, int err = pa_stream_connect_playback(ospa->stream,
outstream->device->id, &ospa->buffer_attr, outstream->device->id, &ospa->buffer_attr,
flags, nullptr, nullptr); flags, NULL, NULL);
if (err) { if (err) {
pa_threaded_mainloop_unlock(sipa->main_loop); pa_threaded_mainloop_unlock(sipa->main_loop);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
while (!ospa->stream_ready.load()) while (!SOUNDIO_ATOMIC_LOAD(ospa->stream_ready))
pa_threaded_mainloop_wait(sipa->main_loop); pa_threaded_mainloop_wait(sipa->main_loop);
pa_operation *update_timing_info_op = pa_stream_update_timing_info(ospa->stream, timing_update_callback, si); pa_operation *update_timing_info_op = pa_stream_update_timing_info(ospa->stream, timing_update_callback, si);
@ -727,10 +731,10 @@ static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
return 0; return 0;
} }
static int outstream_start_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { static int outstream_start_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio; struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
pa_threaded_mainloop_lock(sipa->main_loop); pa_threaded_mainloop_lock(sipa->main_loop);
@ -738,7 +742,7 @@ static int outstream_start_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
int frame_count = ospa->write_byte_count / outstream->bytes_per_frame; int frame_count = ospa->write_byte_count / outstream->bytes_per_frame;
outstream->write_callback(outstream, 0, frame_count); outstream->write_callback(outstream, 0, frame_count);
pa_operation *op = pa_stream_cork(ospa->stream, false, nullptr, nullptr); pa_operation *op = pa_stream_cork(ospa->stream, false, NULL, NULL);
if (!op) { if (!op) {
pa_threaded_mainloop_unlock(sipa->main_loop); pa_threaded_mainloop_unlock(sipa->main_loop);
return SoundIoErrorStreaming; return SoundIoErrorStreaming;
@ -753,11 +757,11 @@ static int outstream_start_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
return 0; return 0;
} }
static int outstream_begin_write_pa(SoundIoPrivate *si, static int outstream_begin_write_pa(struct SoundIoPrivate *si,
SoundIoOutStreamPrivate *os, SoundIoChannelArea **out_areas, int *frame_count) struct SoundIoOutStreamPrivate *os, struct SoundIoChannelArea **out_areas, int *frame_count)
{ {
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio; struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
pa_stream *stream = ospa->stream; pa_stream *stream = ospa->stream;
ospa->write_byte_count = *frame_count * outstream->bytes_per_frame; ospa->write_byte_count = *frame_count * outstream->bytes_per_frame;
@ -775,28 +779,28 @@ static int outstream_begin_write_pa(SoundIoPrivate *si,
return 0; return 0;
} }
static int outstream_end_write_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { static int outstream_end_write_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio; struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
pa_stream *stream = ospa->stream; pa_stream *stream = ospa->stream;
pa_seek_mode_t seek_mode = ospa->clear_buffer_flag.test_and_set() ? PA_SEEK_RELATIVE : PA_SEEK_RELATIVE_ON_READ; pa_seek_mode_t seek_mode = atomic_flag_test_and_set(&ospa->clear_buffer_flag) ? PA_SEEK_RELATIVE : PA_SEEK_RELATIVE_ON_READ;
if (pa_stream_write(stream, ospa->write_ptr, ospa->write_byte_count, nullptr, 0, seek_mode)) if (pa_stream_write(stream, ospa->write_ptr, ospa->write_byte_count, NULL, 0, seek_mode))
return SoundIoErrorStreaming; return SoundIoErrorStreaming;
return 0; return 0;
} }
static int outstream_clear_buffer_pa(SoundIoPrivate *si, static int outstream_clear_buffer_pa(struct SoundIoPrivate *si,
SoundIoOutStreamPrivate *os) struct SoundIoOutStreamPrivate *os)
{ {
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio; struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
ospa->clear_buffer_flag.clear(); atomic_flag_clear(&ospa->clear_buffer_flag);
return 0; return 0;
} }
static int outstream_pause_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, bool pause) { static int outstream_pause_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio; struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
if (!pa_threaded_mainloop_in_thread(sipa->main_loop)) { if (!pa_threaded_mainloop_in_thread(sipa->main_loop)) {
pa_threaded_mainloop_lock(sipa->main_loop); pa_threaded_mainloop_lock(sipa->main_loop);
@ -818,8 +822,8 @@ static int outstream_pause_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, b
return 0; return 0;
} }
static int outstream_get_latency_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, double *out_latency) { static int outstream_get_latency_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, double *out_latency) {
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio; struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
int err; int err;
pa_usec_t r_usec; pa_usec_t r_usec;
@ -832,19 +836,19 @@ static int outstream_get_latency_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate
} }
static void recording_stream_state_callback(pa_stream *stream, void *userdata) { static void recording_stream_state_callback(pa_stream *stream, void *userdata) {
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate*)userdata; struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate*)userdata;
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio; struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
SoundIo *soundio = instream->device->soundio; struct SoundIo *soundio = instream->device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
switch (pa_stream_get_state(stream)) { switch (pa_stream_get_state(stream)) {
case PA_STREAM_UNCONNECTED: case PA_STREAM_UNCONNECTED:
case PA_STREAM_CREATING: case PA_STREAM_CREATING:
case PA_STREAM_TERMINATED: case PA_STREAM_TERMINATED:
break; break;
case PA_STREAM_READY: case PA_STREAM_READY:
ispa->stream_ready = true; SOUNDIO_ATOMIC_STORE(ispa->stream_ready, true);
pa_threaded_mainloop_signal(sipa->main_loop, 0); pa_threaded_mainloop_signal(sipa->main_loop, 0);
break; break;
case PA_STREAM_FAILED: case PA_STREAM_FAILED:
@ -854,43 +858,43 @@ static void recording_stream_state_callback(pa_stream *stream, void *userdata) {
} }
static void recording_stream_read_callback(pa_stream *stream, size_t nbytes, void *userdata) { static void recording_stream_read_callback(pa_stream *stream, size_t nbytes, void *userdata) {
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate*)userdata; struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate*)userdata;
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
assert(nbytes % instream->bytes_per_frame == 0); assert(nbytes % instream->bytes_per_frame == 0);
assert(nbytes > 0); assert(nbytes > 0);
int available_frame_count = nbytes / instream->bytes_per_frame; int available_frame_count = nbytes / instream->bytes_per_frame;
instream->read_callback(instream, 0, available_frame_count); instream->read_callback(instream, 0, available_frame_count);
} }
static void instream_destroy_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) { static void instream_destroy_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio; struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
pa_stream *stream = ispa->stream; pa_stream *stream = ispa->stream;
if (stream) { if (stream) {
pa_threaded_mainloop_lock(sipa->main_loop); pa_threaded_mainloop_lock(sipa->main_loop);
pa_stream_set_state_callback(stream, nullptr, nullptr); pa_stream_set_state_callback(stream, NULL, NULL);
pa_stream_set_read_callback(stream, nullptr, nullptr); pa_stream_set_read_callback(stream, NULL, NULL);
pa_stream_disconnect(stream); pa_stream_disconnect(stream);
pa_stream_unref(stream); pa_stream_unref(stream);
pa_threaded_mainloop_unlock(sipa->main_loop); pa_threaded_mainloop_unlock(sipa->main_loop);
ispa->stream = nullptr; ispa->stream = NULL;
} }
} }
static int instream_open_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) { static int instream_open_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio; struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
if ((unsigned)instream->layout.channel_count > PA_CHANNELS_MAX) if ((unsigned)instream->layout.channel_count > PA_CHANNELS_MAX)
return SoundIoErrorIncompatibleBackend; return SoundIoErrorIncompatibleBackend;
if (!instream->name) if (!instream->name)
instream->name = "SoundIoInStream"; instream->name = "SoundIoInStream";
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
ispa->stream_ready = false; SOUNDIO_ATOMIC_STORE(ispa->stream_ready, false);
pa_threaded_mainloop_lock(sipa->main_loop); pa_threaded_mainloop_lock(sipa->main_loop);
@ -931,10 +935,10 @@ static int instream_open_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
return 0; return 0;
} }
static int instream_start_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) { static int instream_start_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio; struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
pa_threaded_mainloop_lock(sipa->main_loop); pa_threaded_mainloop_lock(sipa->main_loop);
pa_stream_flags_t flags = (pa_stream_flags_t)(PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING); pa_stream_flags_t flags = (pa_stream_flags_t)(PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING);
@ -947,7 +951,7 @@ static int instream_start_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
while (!ispa->stream_ready) while (!SOUNDIO_ATOMIC_LOAD(ispa->stream_ready))
pa_threaded_mainloop_wait(sipa->main_loop); pa_threaded_mainloop_wait(sipa->main_loop);
pa_operation *update_timing_info_op = pa_stream_update_timing_info(ispa->stream, timing_update_callback, si); pa_operation *update_timing_info_op = pa_stream_update_timing_info(ispa->stream, timing_update_callback, si);
@ -961,14 +965,14 @@ static int instream_start_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
return 0; return 0;
} }
static int instream_begin_read_pa(SoundIoPrivate *si, static int instream_begin_read_pa(struct SoundIoPrivate *si,
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count) struct SoundIoInStreamPrivate *is, struct SoundIoChannelArea **out_areas, int *frame_count)
{ {
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio; struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
pa_stream *stream = ispa->stream; pa_stream *stream = ispa->stream;
assert(ispa->stream_ready); assert(SOUNDIO_ATOMIC_LOAD(ispa->stream_ready));
if (!ispa->peek_buf) { if (!ispa->peek_buf) {
if (pa_stream_peek(stream, (const void **)&ispa->peek_buf, &ispa->peek_buf_size)) if (pa_stream_peek(stream, (const void **)&ispa->peek_buf, &ispa->peek_buf_size))
@ -980,12 +984,12 @@ static int instream_begin_read_pa(SoundIoPrivate *si,
// hole // hole
if (!ispa->peek_buf) { if (!ispa->peek_buf) {
*frame_count = ispa->peek_buf_frames_left; *frame_count = ispa->peek_buf_frames_left;
*out_areas = nullptr; *out_areas = NULL;
return 0; return 0;
} }
} }
ispa->read_frame_count = min(*frame_count, ispa->peek_buf_frames_left); ispa->read_frame_count = soundio_int_min(*frame_count, ispa->peek_buf_frames_left);
*frame_count = ispa->read_frame_count; *frame_count = ispa->read_frame_count;
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) { for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
ispa->areas[ch].ptr = ispa->peek_buf + ispa->peek_buf_index + instream->bytes_per_sample * ch; ispa->areas[ch].ptr = ispa->peek_buf + ispa->peek_buf_index + instream->bytes_per_sample * ch;
@ -997,9 +1001,9 @@ static int instream_begin_read_pa(SoundIoPrivate *si,
return 0; return 0;
} }
static int instream_end_read_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) { static int instream_end_read_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio; struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
pa_stream *stream = ispa->stream; pa_stream *stream = ispa->stream;
// hole // hole
@ -1016,15 +1020,15 @@ static int instream_end_read_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is)
if (ispa->peek_buf_index >= ispa->peek_buf_size) { if (ispa->peek_buf_index >= ispa->peek_buf_size) {
if (pa_stream_drop(stream)) if (pa_stream_drop(stream))
return SoundIoErrorStreaming; return SoundIoErrorStreaming;
ispa->peek_buf = nullptr; ispa->peek_buf = NULL;
} }
return 0; return 0;
} }
static int instream_pause_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is, bool pause) { static int instream_pause_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio; struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
if (!pa_threaded_mainloop_in_thread(sipa->main_loop)) { if (!pa_threaded_mainloop_in_thread(sipa->main_loop)) {
pa_threaded_mainloop_lock(sipa->main_loop); pa_threaded_mainloop_lock(sipa->main_loop);
@ -1044,8 +1048,8 @@ static int instream_pause_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is, boo
return 0; return 0;
} }
static int instream_get_latency_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is, double *out_latency) { static int instream_get_latency_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, double *out_latency) {
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio; struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
int err; int err;
pa_usec_t r_usec; pa_usec_t r_usec;
@ -1057,9 +1061,9 @@ static int instream_get_latency_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *i
return 0; return 0;
} }
int soundio_pulseaudio_init(SoundIoPrivate *si) { int soundio_pulseaudio_init(struct SoundIoPrivate *si) {
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
sipa->device_scan_queued = true; sipa->device_scan_queued = true;

View file

@ -5,17 +5,18 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#ifndef SOUNDIO_PULSEAUDIO_HPP #ifndef SOUNDIO_PULSEAUDIO_H
#define SOUNDIO_PULSEAUDIO_HPP #define SOUNDIO_PULSEAUDIO_H
#include "soundio_private.h" #include "soundio_internal.h"
#include "atomics.hpp" #include "atomics.h"
#include <pulse/pulseaudio.h> #include <pulse/pulseaudio.h>
struct SoundIoPrivate;
int soundio_pulseaudio_init(struct SoundIoPrivate *si); int soundio_pulseaudio_init(struct SoundIoPrivate *si);
struct SoundIoDevicePulseAudio { }; struct SoundIoDevicePulseAudio { int make_the_struct_not_empty; };
struct SoundIoPulseAudio { struct SoundIoPulseAudio {
int device_query_err; int device_query_err;
@ -41,24 +42,24 @@ struct SoundIoPulseAudio {
struct SoundIoOutStreamPulseAudio { struct SoundIoOutStreamPulseAudio {
pa_stream *stream; pa_stream *stream;
atomic_bool stream_ready; struct SoundIoAtomicBool stream_ready;
pa_buffer_attr buffer_attr; pa_buffer_attr buffer_attr;
char *write_ptr; char *write_ptr;
size_t write_byte_count; size_t write_byte_count;
atomic_flag clear_buffer_flag; atomic_flag clear_buffer_flag;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS]; struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
}; };
struct SoundIoInStreamPulseAudio { struct SoundIoInStreamPulseAudio {
pa_stream *stream; pa_stream *stream;
atomic_bool stream_ready; struct SoundIoAtomicBool stream_ready;
pa_buffer_attr buffer_attr; pa_buffer_attr buffer_attr;
char *peek_buf; char *peek_buf;
size_t peek_buf_index; size_t peek_buf_index;
size_t peek_buf_size; size_t peek_buf_size;
int peek_buf_frames_left; int peek_buf_frames_left;
int read_frame_count; int read_frame_count;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS]; struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
}; };
#endif #endif

View file

@ -5,25 +5,25 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#include "ring_buffer.hpp" #include "ring_buffer.h"
#include "soundio.hpp" #include "soundio_private.h"
#include "util.hpp" #include "util.h"
#include <stdlib.h> #include <stdlib.h>
struct SoundIoRingBuffer *soundio_ring_buffer_create(struct SoundIo *soundio, int requested_capacity) { struct SoundIoRingBuffer *soundio_ring_buffer_create(struct SoundIo *soundio, int requested_capacity) {
SoundIoRingBuffer *rb = allocate<SoundIoRingBuffer>(1); struct SoundIoRingBuffer *rb = ALLOCATE(struct SoundIoRingBuffer, 1);
assert(requested_capacity > 0); assert(requested_capacity > 0);
if (!rb) { if (!rb) {
soundio_ring_buffer_destroy(rb); soundio_ring_buffer_destroy(rb);
return nullptr; return NULL;
} }
if (soundio_ring_buffer_init(rb, requested_capacity)) { if (soundio_ring_buffer_init(rb, requested_capacity)) {
soundio_ring_buffer_destroy(rb); soundio_ring_buffer_destroy(rb);
return nullptr; return NULL;
} }
return rb; return rb;
@ -43,25 +43,31 @@ int soundio_ring_buffer_capacity(struct SoundIoRingBuffer *rb) {
} }
char *soundio_ring_buffer_write_ptr(struct SoundIoRingBuffer *rb) { char *soundio_ring_buffer_write_ptr(struct SoundIoRingBuffer *rb) {
return rb->mem.address + (rb->write_offset % rb->capacity); long write_offset = SOUNDIO_ATOMIC_LOAD(rb->write_offset);
return rb->mem.address + (write_offset % rb->capacity);
} }
void soundio_ring_buffer_advance_write_ptr(struct SoundIoRingBuffer *rb, int count) { void soundio_ring_buffer_advance_write_ptr(struct SoundIoRingBuffer *rb, int count) {
rb->write_offset += count; SOUNDIO_ATOMIC_FETCH_ADD(rb->write_offset, count);
assert(soundio_ring_buffer_fill_count(rb) >= 0); assert(soundio_ring_buffer_fill_count(rb) >= 0);
} }
char *soundio_ring_buffer_read_ptr(struct SoundIoRingBuffer *rb) { char *soundio_ring_buffer_read_ptr(struct SoundIoRingBuffer *rb) {
return rb->mem.address + (rb->read_offset % rb->capacity); long read_offset = SOUNDIO_ATOMIC_LOAD(rb->read_offset);
return rb->mem.address + (read_offset % rb->capacity);
} }
void soundio_ring_buffer_advance_read_ptr(struct SoundIoRingBuffer *rb, int count) { void soundio_ring_buffer_advance_read_ptr(struct SoundIoRingBuffer *rb, int count) {
rb->read_offset += count; SOUNDIO_ATOMIC_FETCH_ADD(rb->read_offset, count);
assert(soundio_ring_buffer_fill_count(rb) >= 0); assert(soundio_ring_buffer_fill_count(rb) >= 0);
} }
int soundio_ring_buffer_fill_count(struct SoundIoRingBuffer *rb) { int soundio_ring_buffer_fill_count(struct SoundIoRingBuffer *rb) {
int count = rb->write_offset - rb->read_offset; // Whichever offset we load first might have a smaller value. So we load
// the read_offset first.
long read_offset = SOUNDIO_ATOMIC_LOAD(rb->read_offset);
long write_offset = SOUNDIO_ATOMIC_LOAD(rb->write_offset);
int count = write_offset - read_offset;
assert(count >= 0); assert(count >= 0);
assert(count <= rb->capacity); assert(count <= rb->capacity);
return count; return count;
@ -72,15 +78,16 @@ int soundio_ring_buffer_free_count(struct SoundIoRingBuffer *rb) {
} }
void soundio_ring_buffer_clear(struct SoundIoRingBuffer *rb) { void soundio_ring_buffer_clear(struct SoundIoRingBuffer *rb) {
return rb->write_offset.store(rb->read_offset.load()); long read_offset = SOUNDIO_ATOMIC_LOAD(rb->read_offset);
SOUNDIO_ATOMIC_STORE(rb->write_offset, read_offset);
} }
int soundio_ring_buffer_init(struct SoundIoRingBuffer *rb, int requested_capacity) { int soundio_ring_buffer_init(struct SoundIoRingBuffer *rb, int requested_capacity) {
int err; int err;
if ((err = soundio_os_init_mirrored_memory(&rb->mem, requested_capacity))) if ((err = soundio_os_init_mirrored_memory(&rb->mem, requested_capacity)))
return err; return err;
rb->write_offset = 0; SOUNDIO_ATOMIC_STORE(rb->write_offset, 0);
rb->read_offset = 0; SOUNDIO_ATOMIC_STORE(rb->read_offset, 0);
rb->capacity = rb->mem.capacity; rb->capacity = rb->mem.capacity;
return 0; return 0;

View file

@ -5,16 +5,16 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#ifndef SOUNDIO_RING_BUFFER_HPP #ifndef SOUNDIO_RING_BUFFER_H
#define SOUNDIO_RING_BUFFER_HPP #define SOUNDIO_RING_BUFFER_H
#include "atomics.hpp"
#include "os.h" #include "os.h"
#include "atomics.h"
struct SoundIoRingBuffer { struct SoundIoRingBuffer {
SoundIoOsMirroredMemory mem; struct SoundIoOsMirroredMemory mem;
atomic_long write_offset; struct SoundIoAtomicLong write_offset;
atomic_long read_offset; struct SoundIoAtomicLong read_offset;
int capacity; int capacity;
}; };

View file

@ -5,8 +5,8 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#include "soundio.hpp" #include "soundio_private.h"
#include "util.hpp" #include "util.h"
#include "os.h" #include "os.h"
#include "config.h" #include "config.h"
@ -14,7 +14,7 @@
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
static const SoundIoBackend available_backends[] = { static const enum SoundIoBackend available_backends[] = {
#ifdef SOUNDIO_HAVE_JACK #ifdef SOUNDIO_HAVE_JACK
SoundIoBackendJack, SoundIoBackendJack,
#endif #endif
@ -33,36 +33,40 @@ static const SoundIoBackend available_backends[] = {
SoundIoBackendDummy, SoundIoBackendDummy,
}; };
static int (*backend_init_fns[])(SoundIoPrivate *) = { static int (*backend_init_fns[])(struct SoundIoPrivate *) = {
[SoundIoBackendNone] = nullptr, [SoundIoBackendNone] = NULL,
#ifdef SOUNDIO_HAVE_JACK #ifdef SOUNDIO_HAVE_JACK
[SoundIoBackendJack] = soundio_jack_init, [SoundIoBackendJack] = soundio_jack_init,
#else #else
[SoundIoBackendJack] = nullptr, [SoundIoBackendJack] = NULL,
#endif #endif
#ifdef SOUNDIO_HAVE_PULSEAUDIO #ifdef SOUNDIO_HAVE_PULSEAUDIO
[SoundIoBackendPulseAudio] = soundio_pulseaudio_init, [SoundIoBackendPulseAudio] = soundio_pulseaudio_init,
#else #else
[SoundIoBackendPulseAudio] = nullptr, [SoundIoBackendPulseAudio] = NULL,
#endif #endif
#ifdef SOUNDIO_HAVE_ALSA #ifdef SOUNDIO_HAVE_ALSA
[SoundIoBackendAlsa] = soundio_alsa_init, [SoundIoBackendAlsa] = soundio_alsa_init,
#else #else
[SoundIoBackendAlsa] = nullptr, [SoundIoBackendAlsa] = NULL,
#endif #endif
#ifdef SOUNDIO_HAVE_COREAUDIO #ifdef SOUNDIO_HAVE_COREAUDIO
[SoundIoBackendCoreAudio] = soundio_coreaudio_init, [SoundIoBackendCoreAudio] = soundio_coreaudio_init,
#else #else
[SoundIoBackendCoreAudio] = nullptr, [SoundIoBackendCoreAudio] = NULL,
#endif #endif
#ifdef SOUNDIO_HAVE_WASAPI #ifdef SOUNDIO_HAVE_WASAPI
[SoundIoBackendWasapi] = soundio_wasapi_init, [SoundIoBackendWasapi] = soundio_wasapi_init,
#else #else
[SoundIoBackendWasapi] = nullptr, [SoundIoBackendWasapi] = NULL,
#endif #endif
[SoundIoBackendDummy] = soundio_dummy_init, [SoundIoBackendDummy] = soundio_dummy_init,
}; };
SOUNDIO_MAKE_LIST_DEF(struct SoundIoDevice*, SoundIoListDevicePtr, SOUNDIO_LIST_NOT_STATIC)
SOUNDIO_MAKE_LIST_DEF(struct SoundIoSampleRateRange, SoundIoListSampleRateRange, SOUNDIO_LIST_NOT_STATIC)
const char *soundio_strerror(int error) { const char *soundio_strerror(int error) {
switch ((enum SoundIoError)error) { switch ((enum SoundIoError)error) {
case SoundIoErrorNone: return "(no error)"; case SoundIoErrorNone: return "(no error)";
@ -153,23 +157,23 @@ const char *soundio_backend_name(enum SoundIoBackend backend) {
} }
void soundio_destroy(struct SoundIo *soundio) { void soundio_destroy(struct SoundIo *soundio) {
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
soundio_disconnect(soundio); soundio_disconnect(soundio);
free(si); free(si);
} }
static void do_nothing_cb(struct SoundIo *) { } static void do_nothing_cb(struct SoundIo *soundio) { }
static void default_msg_callback(const char *msg) { } static void default_msg_callback(const char *msg) { }
static void default_backend_disconnect_cb(struct SoundIo *, int err) { static void default_backend_disconnect_cb(struct SoundIo *soundio, int err) {
soundio_panic("libsoundio: backend disconnected: %s", soundio_strerror(err)); soundio_panic("libsoundio: backend disconnected: %s", soundio_strerror(err));
} }
static atomic_flag rtprio_seen = ATOMIC_FLAG_INIT; static atomic_flag rtprio_seen = ATOMIC_FLAG_INIT;
static void default_emit_rtprio_warning(void) { static void default_emit_rtprio_warning(void) {
if (!rtprio_seen.test_and_set()) { if (!atomic_flag_test_and_set(&rtprio_seen)) {
fprintf(stderr, "warning: unable to set high priority thread: Operation not permitted\n"); fprintf(stderr, "warning: unable to set high priority thread: Operation not permitted\n");
fprintf(stderr, "See " fprintf(stderr, "See "
"https://github.com/andrewrk/genesis/wiki/warning:-unable-to-set-high-priority-thread:-Operation-not-permitted\n"); "https://github.com/andrewrk/genesis/wiki/warning:-unable-to-set-high-priority-thread:-Operation-not-permitted\n");
@ -179,11 +183,11 @@ static void default_emit_rtprio_warning(void) {
struct SoundIo *soundio_create(void) { struct SoundIo *soundio_create(void) {
int err; int err;
if ((err = soundio_os_init())) if ((err = soundio_os_init()))
return nullptr; return NULL;
struct SoundIoPrivate *si = allocate<SoundIoPrivate>(1); struct SoundIoPrivate *si = ALLOCATE(struct SoundIoPrivate, 1);
if (!si) if (!si)
return nullptr; return NULL;
SoundIo *soundio = &si->pub; struct SoundIo *soundio = &si->pub;
soundio->on_devices_change = do_nothing_cb; soundio->on_devices_change = do_nothing_cb;
soundio->on_backend_disconnect = default_backend_disconnect_cb; soundio->on_backend_disconnect = default_backend_disconnect_cb;
soundio->on_events_signal = do_nothing_cb; soundio->on_events_signal = do_nothing_cb;
@ -197,8 +201,8 @@ struct SoundIo *soundio_create(void) {
int soundio_connect(struct SoundIo *soundio) { int soundio_connect(struct SoundIo *soundio) {
int err = 0; int err = 0;
for (int i = 0; i < array_length(available_backends); i += 1) { for (int i = 0; i < ARRAY_LENGTH(available_backends); i += 1) {
SoundIoBackend backend = available_backends[i]; enum SoundIoBackend backend = available_backends[i];
err = soundio_connect_backend(soundio, backend); err = soundio_connect_backend(soundio, backend);
if (!err) if (!err)
return 0; return 0;
@ -209,8 +213,8 @@ int soundio_connect(struct SoundIo *soundio) {
return err; return err;
} }
int soundio_connect_backend(SoundIo *soundio, SoundIoBackend backend) { int soundio_connect_backend(struct SoundIo *soundio, enum SoundIoBackend backend) {
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
if (soundio->current_backend) if (soundio->current_backend)
return SoundIoErrorInvalid; return SoundIoErrorInvalid;
@ -218,7 +222,7 @@ int soundio_connect_backend(SoundIo *soundio, SoundIoBackend backend) {
if (backend <= 0 || backend > SoundIoBackendDummy) if (backend <= 0 || backend > SoundIoBackendDummy)
return SoundIoErrorInvalid; return SoundIoErrorInvalid;
int (*fn)(SoundIoPrivate *) = backend_init_fns[backend]; int (*fn)(struct SoundIoPrivate *) = backend_init_fns[backend];
if (!fn) if (!fn)
return SoundIoErrorBackendUnavailable; return SoundIoErrorBackendUnavailable;
@ -234,52 +238,52 @@ int soundio_connect_backend(SoundIo *soundio, SoundIoBackend backend) {
} }
void soundio_disconnect(struct SoundIo *soundio) { void soundio_disconnect(struct SoundIo *soundio) {
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
if (!si) if (!si)
return; return;
if (si->destroy) if (si->destroy)
si->destroy(si); si->destroy(si);
memset(&si->backend_data, 0, sizeof(SoundIoBackendData)); memset(&si->backend_data, 0, sizeof(union SoundIoBackendData));
soundio->current_backend = SoundIoBackendNone; soundio->current_backend = SoundIoBackendNone;
soundio_destroy_devices_info(si->safe_devices_info); soundio_destroy_devices_info(si->safe_devices_info);
si->safe_devices_info = nullptr; si->safe_devices_info = NULL;
si->destroy = nullptr; si->destroy = NULL;
si->flush_events = nullptr; si->flush_events = NULL;
si->wait_events = nullptr; si->wait_events = NULL;
si->wakeup = nullptr; si->wakeup = NULL;
si->force_device_scan = nullptr; si->force_device_scan = NULL;
si->outstream_open = nullptr; si->outstream_open = NULL;
si->outstream_destroy = nullptr; si->outstream_destroy = NULL;
si->outstream_start = nullptr; si->outstream_start = NULL;
si->outstream_begin_write = nullptr; si->outstream_begin_write = NULL;
si->outstream_end_write = nullptr; si->outstream_end_write = NULL;
si->outstream_clear_buffer = nullptr; si->outstream_clear_buffer = NULL;
si->outstream_pause = nullptr; si->outstream_pause = NULL;
si->outstream_get_latency = nullptr; si->outstream_get_latency = NULL;
si->instream_open = nullptr; si->instream_open = NULL;
si->instream_destroy = nullptr; si->instream_destroy = NULL;
si->instream_start = nullptr; si->instream_start = NULL;
si->instream_begin_read = nullptr; si->instream_begin_read = NULL;
si->instream_end_read = nullptr; si->instream_end_read = NULL;
si->instream_pause = nullptr; si->instream_pause = NULL;
si->instream_get_latency = nullptr; si->instream_get_latency = NULL;
} }
void soundio_flush_events(struct SoundIo *soundio) { void soundio_flush_events(struct SoundIo *soundio) {
assert(soundio->current_backend != SoundIoBackendNone); assert(soundio->current_backend != SoundIoBackendNone);
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
si->flush_events(si); si->flush_events(si);
} }
int soundio_input_device_count(struct SoundIo *soundio) { int soundio_input_device_count(struct SoundIo *soundio) {
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
assert(si->safe_devices_info); assert(si->safe_devices_info);
if (!si->safe_devices_info) if (!si->safe_devices_info)
@ -293,7 +297,7 @@ int soundio_input_device_count(struct SoundIo *soundio) {
} }
int soundio_output_device_count(struct SoundIo *soundio) { int soundio_output_device_count(struct SoundIo *soundio) {
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
assert(si->safe_devices_info); assert(si->safe_devices_info);
if (!si->safe_devices_info) if (!si->safe_devices_info)
@ -307,7 +311,7 @@ int soundio_output_device_count(struct SoundIo *soundio) {
} }
int soundio_default_input_device_index(struct SoundIo *soundio) { int soundio_default_input_device_index(struct SoundIo *soundio) {
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
assert(si->safe_devices_info); assert(si->safe_devices_info);
if (!si->safe_devices_info) if (!si->safe_devices_info)
@ -321,7 +325,7 @@ int soundio_default_input_device_index(struct SoundIo *soundio) {
} }
int soundio_default_output_device_index(struct SoundIo *soundio) { int soundio_default_output_device_index(struct SoundIo *soundio) {
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
assert(si->safe_devices_info); assert(si->safe_devices_info);
if (!si->safe_devices_info) if (!si->safe_devices_info)
@ -335,43 +339,43 @@ int soundio_default_output_device_index(struct SoundIo *soundio) {
} }
struct SoundIoDevice *soundio_get_input_device(struct SoundIo *soundio, int index) { struct SoundIoDevice *soundio_get_input_device(struct SoundIo *soundio, int index) {
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
assert(soundio->current_backend != SoundIoBackendNone); assert(soundio->current_backend != SoundIoBackendNone);
if (soundio->current_backend == SoundIoBackendNone) if (soundio->current_backend == SoundIoBackendNone)
return nullptr; return NULL;
assert(si->safe_devices_info); assert(si->safe_devices_info);
if (!si->safe_devices_info) if (!si->safe_devices_info)
return nullptr; return NULL;
assert(index >= 0); assert(index >= 0);
assert(index < si->safe_devices_info->input_devices.length); assert(index < si->safe_devices_info->input_devices.length);
if (index < 0 || index >= si->safe_devices_info->input_devices.length) if (index < 0 || index >= si->safe_devices_info->input_devices.length)
return nullptr; return NULL;
SoundIoDevice *device = si->safe_devices_info->input_devices.at(index); struct SoundIoDevice *device = SoundIoListDevicePtr_val_at(&si->safe_devices_info->input_devices, index);
soundio_device_ref(device); soundio_device_ref(device);
return device; return device;
} }
struct SoundIoDevice *soundio_get_output_device(struct SoundIo *soundio, int index) { struct SoundIoDevice *soundio_get_output_device(struct SoundIo *soundio, int index) {
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
assert(soundio->current_backend != SoundIoBackendNone); assert(soundio->current_backend != SoundIoBackendNone);
if (soundio->current_backend == SoundIoBackendNone) if (soundio->current_backend == SoundIoBackendNone)
return nullptr; return NULL;
assert(si->safe_devices_info); assert(si->safe_devices_info);
if (!si->safe_devices_info) if (!si->safe_devices_info)
return nullptr; return NULL;
assert(index >= 0); assert(index >= 0);
assert(index < si->safe_devices_info->output_devices.length); assert(index < si->safe_devices_info->output_devices.length);
if (index < 0 || index >= si->safe_devices_info->output_devices.length) if (index < 0 || index >= si->safe_devices_info->output_devices.length)
return nullptr; return NULL;
SoundIoDevice *device = si->safe_devices_info->output_devices.at(index); struct SoundIoDevice *device = SoundIoListDevicePtr_val_at(&si->safe_devices_info->output_devices, index);
soundio_device_ref(device); soundio_device_ref(device);
return device; return device;
} }
@ -384,7 +388,7 @@ void soundio_device_unref(struct SoundIoDevice *device) {
assert(device->ref_count >= 0); assert(device->ref_count >= 0);
if (device->ref_count == 0) { if (device->ref_count == 0) {
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device; struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
if (dev->destruct) if (dev->destruct)
dev->destruct(dev); dev->destruct(dev);
@ -396,7 +400,7 @@ void soundio_device_unref(struct SoundIoDevice *device) {
{ {
free(device->sample_rates); free(device->sample_rates);
} }
dev->sample_rates.deinit(); SoundIoListSampleRateRange_deinit(&dev->sample_rates);
if (device->formats != &dev->prealloc_format) if (device->formats != &dev->prealloc_format)
free(device->formats); free(device->formats);
@ -414,35 +418,35 @@ void soundio_device_ref(struct SoundIoDevice *device) {
} }
void soundio_wait_events(struct SoundIo *soundio) { void soundio_wait_events(struct SoundIo *soundio) {
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
si->wait_events(si); si->wait_events(si);
} }
void soundio_wakeup(struct SoundIo *soundio) { void soundio_wakeup(struct SoundIo *soundio) {
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
si->wakeup(si); si->wakeup(si);
} }
void soundio_force_device_scan(struct SoundIo *soundio) { void soundio_force_device_scan(struct SoundIo *soundio) {
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
si->force_device_scan(si); si->force_device_scan(si);
} }
int soundio_outstream_begin_write(struct SoundIoOutStream *outstream, int soundio_outstream_begin_write(struct SoundIoOutStream *outstream,
SoundIoChannelArea **areas, int *frame_count) struct SoundIoChannelArea **areas, int *frame_count)
{ {
SoundIo *soundio = outstream->device->soundio; struct SoundIo *soundio = outstream->device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream; struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
if (*frame_count <= 0) if (*frame_count <= 0)
return SoundIoErrorInvalid; return SoundIoErrorInvalid;
return si->outstream_begin_write(si, os, areas, frame_count); return si->outstream_begin_write(si, os, areas, frame_count);
} }
int soundio_outstream_end_write(struct SoundIoOutStream *outstream) { int soundio_outstream_end_write(struct SoundIoOutStream *outstream) {
SoundIo *soundio = outstream->device->soundio; struct SoundIo *soundio = outstream->device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream; struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
return si->outstream_end_write(si, os); return si->outstream_end_write(si, os);
} }
@ -453,13 +457,13 @@ static void default_outstream_error_callback(struct SoundIoOutStream *os, int er
static void default_underflow_callback(struct SoundIoOutStream *outstream) { } static void default_underflow_callback(struct SoundIoOutStream *outstream) { }
struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device) { struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device) {
SoundIoOutStreamPrivate *os = allocate<SoundIoOutStreamPrivate>(1); struct SoundIoOutStreamPrivate *os = ALLOCATE(struct SoundIoOutStreamPrivate, 1);
SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStream *outstream = &os->pub;
if (!os) if (!os)
return nullptr; return NULL;
if (!device) if (!device)
return nullptr; return NULL;
outstream->device = device; outstream->device = device;
soundio_device_ref(device); soundio_device_ref(device);
@ -471,7 +475,7 @@ struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device)
} }
int soundio_outstream_open(struct SoundIoOutStream *outstream) { int soundio_outstream_open(struct SoundIoOutStream *outstream) {
SoundIoDevice *device = outstream->device; struct SoundIoDevice *device = outstream->device;
if (device->aim != SoundIoDeviceAimOutput) if (device->aim != SoundIoDeviceAimOutput)
return SoundIoErrorInvalid; return SoundIoErrorInvalid;
@ -491,29 +495,29 @@ int soundio_outstream_open(struct SoundIoOutStream *outstream) {
return SoundIoErrorInvalid; return SoundIoErrorInvalid;
if (!outstream->layout.channel_count) { if (!outstream->layout.channel_count) {
const SoundIoChannelLayout *stereo = soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdStereo); const struct SoundIoChannelLayout *stereo = soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdStereo);
outstream->layout = soundio_device_supports_layout(device, stereo) ? *stereo : device->layouts[0]; outstream->layout = soundio_device_supports_layout(device, stereo) ? *stereo : device->layouts[0];
} }
if (!outstream->sample_rate) if (!outstream->sample_rate)
outstream->sample_rate = soundio_device_nearest_sample_rate(device, 48000); outstream->sample_rate = soundio_device_nearest_sample_rate(device, 48000);
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream; struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
outstream->bytes_per_frame = soundio_get_bytes_per_frame(outstream->format, outstream->layout.channel_count); outstream->bytes_per_frame = soundio_get_bytes_per_frame(outstream->format, outstream->layout.channel_count);
outstream->bytes_per_sample = soundio_get_bytes_per_sample(outstream->format); outstream->bytes_per_sample = soundio_get_bytes_per_sample(outstream->format);
SoundIo *soundio = device->soundio; struct SoundIo *soundio = device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
return si->outstream_open(si, os); return si->outstream_open(si, os);
} }
void soundio_outstream_destroy(SoundIoOutStream *outstream) { void soundio_outstream_destroy(struct SoundIoOutStream *outstream) {
if (!outstream) if (!outstream)
return; return;
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream; struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
SoundIo *soundio = outstream->device->soundio; struct SoundIo *soundio = outstream->device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
if (si->outstream_destroy) if (si->outstream_destroy)
si->outstream_destroy(si, os); si->outstream_destroy(si, os);
@ -523,30 +527,30 @@ void soundio_outstream_destroy(SoundIoOutStream *outstream) {
} }
int soundio_outstream_start(struct SoundIoOutStream *outstream) { int soundio_outstream_start(struct SoundIoOutStream *outstream) {
SoundIo *soundio = outstream->device->soundio; struct SoundIo *soundio = outstream->device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream; struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
return si->outstream_start(si, os); return si->outstream_start(si, os);
} }
int soundio_outstream_pause(struct SoundIoOutStream *outstream, bool pause) { int soundio_outstream_pause(struct SoundIoOutStream *outstream, bool pause) {
SoundIo *soundio = outstream->device->soundio; struct SoundIo *soundio = outstream->device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream; struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
return si->outstream_pause(si, os, pause); return si->outstream_pause(si, os, pause);
} }
int soundio_outstream_clear_buffer(struct SoundIoOutStream *outstream) { int soundio_outstream_clear_buffer(struct SoundIoOutStream *outstream) {
SoundIo *soundio = outstream->device->soundio; struct SoundIo *soundio = outstream->device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream; struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
return si->outstream_clear_buffer(si, os); return si->outstream_clear_buffer(si, os);
} }
int soundio_outstream_get_latency(struct SoundIoOutStream *outstream, double *out_latency) { int soundio_outstream_get_latency(struct SoundIoOutStream *outstream, double *out_latency) {
SoundIo *soundio = outstream->device->soundio; struct SoundIo *soundio = outstream->device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream; struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
return si->outstream_get_latency(si, os, out_latency); return si->outstream_get_latency(si, os, out_latency);
} }
@ -557,13 +561,13 @@ static void default_instream_error_callback(struct SoundIoInStream *is, int err)
static void default_overflow_callback(struct SoundIoInStream *instream) { } static void default_overflow_callback(struct SoundIoInStream *instream) { }
struct SoundIoInStream *soundio_instream_create(struct SoundIoDevice *device) { struct SoundIoInStream *soundio_instream_create(struct SoundIoDevice *device) {
SoundIoInStreamPrivate *is = allocate<SoundIoInStreamPrivate>(1); struct SoundIoInStreamPrivate *is = ALLOCATE(struct SoundIoInStreamPrivate, 1);
SoundIoInStream *instream = &is->pub; struct SoundIoInStream *instream = &is->pub;
if (!is) if (!is)
return nullptr; return NULL;
if (!device) if (!device)
return nullptr; return NULL;
instream->device = device; instream->device = device;
soundio_device_ref(device); soundio_device_ref(device);
@ -575,7 +579,7 @@ struct SoundIoInStream *soundio_instream_create(struct SoundIoDevice *device) {
} }
int soundio_instream_open(struct SoundIoInStream *instream) { int soundio_instream_open(struct SoundIoInStream *instream) {
SoundIoDevice *device = instream->device; struct SoundIoDevice *device = instream->device;
if (device->aim != SoundIoDeviceAimInput) if (device->aim != SoundIoDeviceAimInput)
return SoundIoErrorInvalid; return SoundIoErrorInvalid;
@ -594,7 +598,7 @@ int soundio_instream_open(struct SoundIoInStream *instream) {
} }
if (!instream->layout.channel_count) { if (!instream->layout.channel_count) {
const SoundIoChannelLayout *stereo = soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdStereo); const struct SoundIoChannelLayout *stereo = soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdStereo);
instream->layout = soundio_device_supports_layout(device, stereo) ? *stereo : device->layouts[0]; instream->layout = soundio_device_supports_layout(device, stereo) ? *stereo : device->layouts[0];
} }
@ -604,16 +608,16 @@ int soundio_instream_open(struct SoundIoInStream *instream) {
instream->bytes_per_frame = soundio_get_bytes_per_frame(instream->format, instream->layout.channel_count); instream->bytes_per_frame = soundio_get_bytes_per_frame(instream->format, instream->layout.channel_count);
instream->bytes_per_sample = soundio_get_bytes_per_sample(instream->format); instream->bytes_per_sample = soundio_get_bytes_per_sample(instream->format);
SoundIo *soundio = device->soundio; struct SoundIo *soundio = device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream; struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
return si->instream_open(si, is); return si->instream_open(si, is);
} }
int soundio_instream_start(struct SoundIoInStream *instream) { int soundio_instream_start(struct SoundIoInStream *instream) {
SoundIo *soundio = instream->device->soundio; struct SoundIo *soundio = instream->device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream; struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
return si->instream_start(si, is); return si->instream_start(si, is);
} }
@ -621,9 +625,9 @@ void soundio_instream_destroy(struct SoundIoInStream *instream) {
if (!instream) if (!instream)
return; return;
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream; struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
SoundIo *soundio = instream->device->soundio; struct SoundIo *soundio = instream->device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
if (si->instream_destroy) if (si->instream_destroy)
si->instream_destroy(si, is); si->instream_destroy(si, is);
@ -633,69 +637,69 @@ void soundio_instream_destroy(struct SoundIoInStream *instream) {
} }
int soundio_instream_pause(struct SoundIoInStream *instream, bool pause) { int soundio_instream_pause(struct SoundIoInStream *instream, bool pause) {
SoundIo *soundio = instream->device->soundio; struct SoundIo *soundio = instream->device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream; struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
return si->instream_pause(si, is, pause); return si->instream_pause(si, is, pause);
} }
int soundio_instream_begin_read(struct SoundIoInStream *instream, int soundio_instream_begin_read(struct SoundIoInStream *instream,
struct SoundIoChannelArea **areas, int *frame_count) struct SoundIoChannelArea **areas, int *frame_count)
{ {
SoundIo *soundio = instream->device->soundio; struct SoundIo *soundio = instream->device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream; struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
return si->instream_begin_read(si, is, areas, frame_count); return si->instream_begin_read(si, is, areas, frame_count);
} }
int soundio_instream_end_read(struct SoundIoInStream *instream) { int soundio_instream_end_read(struct SoundIoInStream *instream) {
SoundIo *soundio = instream->device->soundio; struct SoundIo *soundio = instream->device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream; struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
return si->instream_end_read(si, is); return si->instream_end_read(si, is);
} }
int soundio_instream_get_latency(struct SoundIoInStream *instream, double *out_latency) { int soundio_instream_get_latency(struct SoundIoInStream *instream, double *out_latency) {
SoundIo *soundio = instream->device->soundio; struct SoundIo *soundio = instream->device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio; struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream; struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
return si->instream_get_latency(si, is, out_latency); return si->instream_get_latency(si, is, out_latency);
} }
void soundio_destroy_devices_info(SoundIoDevicesInfo *devices_info) { void soundio_destroy_devices_info(struct SoundIoDevicesInfo *devices_info) {
if (!devices_info) if (!devices_info)
return; return;
for (int i = 0; i < devices_info->input_devices.length; i += 1) for (int i = 0; i < devices_info->input_devices.length; i += 1)
soundio_device_unref(devices_info->input_devices.at(i)); soundio_device_unref(SoundIoListDevicePtr_val_at(&devices_info->input_devices, i));
for (int i = 0; i < devices_info->output_devices.length; i += 1) for (int i = 0; i < devices_info->output_devices.length; i += 1)
soundio_device_unref(devices_info->output_devices.at(i)); soundio_device_unref(SoundIoListDevicePtr_val_at(&devices_info->output_devices, i));
devices_info->input_devices.deinit(); SoundIoListDevicePtr_deinit(&devices_info->input_devices);
devices_info->output_devices.deinit(); SoundIoListDevicePtr_deinit(&devices_info->output_devices);
free(devices_info); free(devices_info);
} }
bool soundio_have_backend(SoundIoBackend backend) { bool soundio_have_backend(enum SoundIoBackend backend) {
assert(backend > 0); assert(backend > 0);
assert(backend <= SoundIoBackendDummy); assert(backend <= SoundIoBackendDummy);
return backend_init_fns[backend]; return backend_init_fns[backend];
} }
int soundio_backend_count(struct SoundIo *soundio) { int soundio_backend_count(struct SoundIo *soundio) {
return array_length(available_backends); return ARRAY_LENGTH(available_backends);
} }
SoundIoBackend soundio_get_backend(struct SoundIo *soundio, int index) { enum SoundIoBackend soundio_get_backend(struct SoundIo *soundio, int index) {
return available_backends[index]; return available_backends[index];
} }
static bool layout_contains(const SoundIoChannelLayout *available_layouts, int available_layouts_count, static bool layout_contains(const struct SoundIoChannelLayout *available_layouts, int available_layouts_count,
const SoundIoChannelLayout *target_layout) const struct SoundIoChannelLayout *target_layout)
{ {
for (int i = 0; i < available_layouts_count; i += 1) { for (int i = 0; i < available_layouts_count; i += 1) {
const SoundIoChannelLayout *available_layout = &available_layouts[i]; const struct SoundIoChannelLayout *available_layout = &available_layouts[i];
if (soundio_channel_layout_equal(target_layout, available_layout)) if (soundio_channel_layout_equal(target_layout, available_layout))
return true; return true;
} }
@ -707,16 +711,16 @@ const struct SoundIoChannelLayout *soundio_best_matching_channel_layout(
const struct SoundIoChannelLayout *available_layouts, int available_layouts_count) const struct SoundIoChannelLayout *available_layouts, int available_layouts_count)
{ {
for (int i = 0; i < preferred_layouts_count; i += 1) { for (int i = 0; i < preferred_layouts_count; i += 1) {
const SoundIoChannelLayout *preferred_layout = &preferred_layouts[i]; const struct SoundIoChannelLayout *preferred_layout = &preferred_layouts[i];
if (layout_contains(available_layouts, available_layouts_count, preferred_layout)) if (layout_contains(available_layouts, available_layouts_count, preferred_layout))
return preferred_layout; return preferred_layout;
} }
return nullptr; return NULL;
} }
static int compare_layouts(const void *a, const void *b) { static int compare_layouts(const void *a, const void *b) {
const SoundIoChannelLayout *layout_a = *((SoundIoChannelLayout **)a); const struct SoundIoChannelLayout *layout_a = *((struct SoundIoChannelLayout **)a);
const SoundIoChannelLayout *layout_b = *((SoundIoChannelLayout **)b); const struct SoundIoChannelLayout *layout_b = *((struct SoundIoChannelLayout **)b);
if (layout_a->channel_count > layout_b->channel_count) if (layout_a->channel_count > layout_b->channel_count)
return -1; return -1;
else if (layout_a->channel_count < layout_b->channel_count) else if (layout_a->channel_count < layout_b->channel_count)
@ -729,7 +733,7 @@ void soundio_sort_channel_layouts(struct SoundIoChannelLayout *layouts, int layo
if (!layouts) if (!layouts)
return; return;
qsort(layouts, layouts_count, sizeof(SoundIoChannelLayout), compare_layouts); qsort(layouts, layouts_count, sizeof(struct SoundIoChannelLayout), compare_layouts);
} }
void soundio_device_sort_channel_layouts(struct SoundIoDevice *device) { void soundio_device_sort_channel_layouts(struct SoundIoDevice *device) {
@ -756,7 +760,7 @@ bool soundio_device_supports_layout(struct SoundIoDevice *device,
bool soundio_device_supports_sample_rate(struct SoundIoDevice *device, int sample_rate) { bool soundio_device_supports_sample_rate(struct SoundIoDevice *device, int sample_rate) {
for (int i = 0; i < device->sample_rate_count; i += 1) { for (int i = 0; i < device->sample_rate_count; i += 1) {
SoundIoSampleRateRange *range = &device->sample_rates[i]; struct SoundIoSampleRateRange *range = &device->sample_rates[i];
if (sample_rate >= range->min && sample_rate <= range->max) if (sample_rate >= range->min && sample_rate <= range->max)
return true; return true;
} }
@ -772,8 +776,8 @@ int soundio_device_nearest_sample_rate(struct SoundIoDevice *device, int sample_
int best_rate = -1; int best_rate = -1;
int best_delta = -1; int best_delta = -1;
for (int i = 0; i < device->sample_rate_count; i += 1) { for (int i = 0; i < device->sample_rate_count; i += 1) {
SoundIoSampleRateRange *range = &device->sample_rates[i]; struct SoundIoSampleRateRange *range = &device->sample_rates[i];
int candidate_rate = clamp(range->min, sample_rate, range->max); int candidate_rate = soundio_int_clamp(range->min, sample_rate, range->max);
if (candidate_rate == sample_rate) if (candidate_rate == sample_rate)
return candidate_rate; return candidate_rate;

View file

@ -1,179 +0,0 @@
/*
* Copyright (c) 2015 Andrew Kelley
*
* This file is part of libsoundio, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
#ifndef SOUNDIO_SOUNDIO_HPP
#define SOUNDIO_SOUNDIO_HPP
#include "soundio_private.h"
#include "list.hpp"
#ifdef SOUNDIO_HAVE_JACK
#include "jack.hpp"
#endif
#ifdef SOUNDIO_HAVE_PULSEAUDIO
#include "pulseaudio.hpp"
#endif
#ifdef SOUNDIO_HAVE_ALSA
#include "alsa.hpp"
#endif
#ifdef SOUNDIO_HAVE_COREAUDIO
#include "coreaudio.hpp"
#endif
#ifdef SOUNDIO_HAVE_WASAPI
#include "wasapi.hpp"
#endif
#include "dummy.hpp"
union SoundIoBackendData {
#ifdef SOUNDIO_HAVE_JACK
SoundIoJack jack;
#endif
#ifdef SOUNDIO_HAVE_PULSEAUDIO
SoundIoPulseAudio pulseaudio;
#endif
#ifdef SOUNDIO_HAVE_ALSA
SoundIoAlsa alsa;
#endif
#ifdef SOUNDIO_HAVE_COREAUDIO
SoundIoCoreAudio coreaudio;
#endif
#ifdef SOUNDIO_HAVE_WASAPI
SoundIoWasapi wasapi;
#endif
SoundIoDummy dummy;
};
union SoundIoDeviceBackendData {
#ifdef SOUNDIO_HAVE_JACK
SoundIoDeviceJack jack;
#endif
#ifdef SOUNDIO_HAVE_PULSEAUDIO
SoundIoDevicePulseAudio pulseaudio;
#endif
#ifdef SOUNDIO_HAVE_ALSA
SoundIoDeviceAlsa alsa;
#endif
#ifdef SOUNDIO_HAVE_COREAUDIO
SoundIoDeviceCoreAudio coreaudio;
#endif
#ifdef SOUNDIO_HAVE_WASAPI
SoundIoDeviceWasapi wasapi;
#endif
SoundIoDeviceDummy dummy;
};
union SoundIoOutStreamBackendData {
#ifdef SOUNDIO_HAVE_JACK
SoundIoOutStreamJack jack;
#endif
#ifdef SOUNDIO_HAVE_PULSEAUDIO
SoundIoOutStreamPulseAudio pulseaudio;
#endif
#ifdef SOUNDIO_HAVE_ALSA
SoundIoOutStreamAlsa alsa;
#endif
#ifdef SOUNDIO_HAVE_COREAUDIO
SoundIoOutStreamCoreAudio coreaudio;
#endif
#ifdef SOUNDIO_HAVE_WASAPI
SoundIoOutStreamWasapi wasapi;
#endif
SoundIoOutStreamDummy dummy;
};
union SoundIoInStreamBackendData {
#ifdef SOUNDIO_HAVE_JACK
SoundIoInStreamJack jack;
#endif
#ifdef SOUNDIO_HAVE_PULSEAUDIO
SoundIoInStreamPulseAudio pulseaudio;
#endif
#ifdef SOUNDIO_HAVE_ALSA
SoundIoInStreamAlsa alsa;
#endif
#ifdef SOUNDIO_HAVE_COREAUDIO
SoundIoInStreamCoreAudio coreaudio;
#endif
#ifdef SOUNDIO_HAVE_WASAPI
SoundIoInStreamWasapi wasapi;
#endif
SoundIoInStreamDummy dummy;
};
struct SoundIoDevicesInfo {
SoundIoList<SoundIoDevice *> input_devices;
SoundIoList<SoundIoDevice *> output_devices;
// can be -1 when default device is unknown
int default_output_index;
int default_input_index;
};
struct SoundIoOutStreamPrivate {
SoundIoOutStream pub;
SoundIoOutStreamBackendData backend_data;
};
struct SoundIoInStreamPrivate {
SoundIoInStream pub;
SoundIoInStreamBackendData backend_data;
};
struct SoundIoPrivate {
struct SoundIo pub;
// Safe to read from a single thread without a mutex.
struct SoundIoDevicesInfo *safe_devices_info;
void (*destroy)(struct SoundIoPrivate *);
void (*flush_events)(struct SoundIoPrivate *);
void (*wait_events)(struct SoundIoPrivate *);
void (*wakeup)(struct SoundIoPrivate *);
void (*force_device_scan)(struct SoundIoPrivate *);
int (*outstream_open)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
void (*outstream_destroy)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
int (*outstream_start)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
int (*outstream_begin_write)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *,
SoundIoChannelArea **out_areas, int *out_frame_count);
int (*outstream_end_write)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
int (*outstream_clear_buffer)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
int (*outstream_pause)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, bool pause);
int (*outstream_get_latency)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, double *out_latency);
int (*instream_open)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
void (*instream_destroy)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
int (*instream_start)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
int (*instream_begin_read)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *,
SoundIoChannelArea **out_areas, int *out_frame_count);
int (*instream_end_read)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
int (*instream_pause)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *, bool pause);
int (*instream_get_latency)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *, double *out_latency);
SoundIoBackendData backend_data;
};
struct SoundIoDevicePrivate {
SoundIoDevice pub;
SoundIoDeviceBackendData backend_data;
void (*destruct)(SoundIoDevicePrivate *);
SoundIoSampleRateRange prealloc_sample_rate_range;
SoundIoList<SoundIoSampleRateRange> sample_rates;
SoundIoFormat prealloc_format;
};
void soundio_destroy_devices_info(struct SoundIoDevicesInfo *devices_info);
static const int SOUNDIO_MIN_SAMPLE_RATE = 8000;
static const int SOUNDIO_MAX_SAMPLE_RATE = 5644800;
#endif

16
src/soundio_internal.h Normal file
View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2015 Andrew Kelley
*
* This file is part of libsoundio, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
#ifndef SOUNDIO_SOUNDIO_INTERNAL_H
#define SOUNDIO_SOUNDIO_INTERNAL_H
// This exists for __declspec(dllexport) and __declspec(dllimport) to be
// defined correctly without the library user having to do anything.
#define SOUNDIO_BUILDING_LIBRARY
#include "soundio/soundio.h"
#endif

View file

@ -8,9 +8,177 @@
#ifndef SOUNDIO_SOUNDIO_PRIVATE_H #ifndef SOUNDIO_SOUNDIO_PRIVATE_H
#define SOUNDIO_SOUNDIO_PRIVATE_H #define SOUNDIO_SOUNDIO_PRIVATE_H
// This exists for __declspec(dllexport) and __declspec(dllimport) to be #include "soundio_internal.h"
// defined correctly without the library user having to do anything.
#define SOUNDIO_BUILDING_LIBRARY #ifdef SOUNDIO_HAVE_JACK
#include "soundio/soundio.h" #include "jack.h"
#endif
#ifdef SOUNDIO_HAVE_PULSEAUDIO
#include "pulseaudio.h"
#endif
#ifdef SOUNDIO_HAVE_ALSA
#include "alsa.h"
#endif
#ifdef SOUNDIO_HAVE_COREAUDIO
#include "coreaudio.h"
#endif
#ifdef SOUNDIO_HAVE_WASAPI
#include "wasapi.h"
#endif
#include "dummy.h"
union SoundIoBackendData {
#ifdef SOUNDIO_HAVE_JACK
struct SoundIoJack jack;
#endif
#ifdef SOUNDIO_HAVE_PULSEAUDIO
struct SoundIoPulseAudio pulseaudio;
#endif
#ifdef SOUNDIO_HAVE_ALSA
struct SoundIoAlsa alsa;
#endif
#ifdef SOUNDIO_HAVE_COREAUDIO
struct SoundIoCoreAudio coreaudio;
#endif
#ifdef SOUNDIO_HAVE_WASAPI
struct SoundIoWasapi wasapi;
#endif
struct SoundIoDummy dummy;
};
union SoundIoDeviceBackendData {
#ifdef SOUNDIO_HAVE_JACK
struct SoundIoDeviceJack jack;
#endif
#ifdef SOUNDIO_HAVE_PULSEAUDIO
struct SoundIoDevicePulseAudio pulseaudio;
#endif
#ifdef SOUNDIO_HAVE_ALSA
struct SoundIoDeviceAlsa alsa;
#endif
#ifdef SOUNDIO_HAVE_COREAUDIO
struct SoundIoDeviceCoreAudio coreaudio;
#endif
#ifdef SOUNDIO_HAVE_WASAPI
struct SoundIoDeviceWasapi wasapi;
#endif
struct SoundIoDeviceDummy dummy;
};
union SoundIoOutStreamBackendData {
#ifdef SOUNDIO_HAVE_JACK
struct SoundIoOutStreamJack jack;
#endif
#ifdef SOUNDIO_HAVE_PULSEAUDIO
struct SoundIoOutStreamPulseAudio pulseaudio;
#endif
#ifdef SOUNDIO_HAVE_ALSA
struct SoundIoOutStreamAlsa alsa;
#endif
#ifdef SOUNDIO_HAVE_COREAUDIO
struct SoundIoOutStreamCoreAudio coreaudio;
#endif
#ifdef SOUNDIO_HAVE_WASAPI
struct SoundIoOutStreamWasapi wasapi;
#endif
struct SoundIoOutStreamDummy dummy;
};
union SoundIoInStreamBackendData {
#ifdef SOUNDIO_HAVE_JACK
struct SoundIoInStreamJack jack;
#endif
#ifdef SOUNDIO_HAVE_PULSEAUDIO
struct SoundIoInStreamPulseAudio pulseaudio;
#endif
#ifdef SOUNDIO_HAVE_ALSA
struct SoundIoInStreamAlsa alsa;
#endif
#ifdef SOUNDIO_HAVE_COREAUDIO
struct SoundIoInStreamCoreAudio coreaudio;
#endif
#ifdef SOUNDIO_HAVE_WASAPI
struct SoundIoInStreamWasapi wasapi;
#endif
struct SoundIoInStreamDummy dummy;
};
SOUNDIO_MAKE_LIST_STRUCT(struct SoundIoDevice*, SoundIoListDevicePtr, SOUNDIO_LIST_NOT_STATIC)
SOUNDIO_MAKE_LIST_PROTO(struct SoundIoDevice*, SoundIoListDevicePtr, SOUNDIO_LIST_NOT_STATIC)
struct SoundIoDevicesInfo {
struct SoundIoListDevicePtr input_devices;
struct SoundIoListDevicePtr output_devices;
// can be -1 when default device is unknown
int default_output_index;
int default_input_index;
};
struct SoundIoOutStreamPrivate {
struct SoundIoOutStream pub;
union SoundIoOutStreamBackendData backend_data;
};
struct SoundIoInStreamPrivate {
struct SoundIoInStream pub;
union SoundIoInStreamBackendData backend_data;
};
struct SoundIoPrivate {
struct SoundIo pub;
// Safe to read from a single thread without a mutex.
struct SoundIoDevicesInfo *safe_devices_info;
void (*destroy)(struct SoundIoPrivate *);
void (*flush_events)(struct SoundIoPrivate *);
void (*wait_events)(struct SoundIoPrivate *);
void (*wakeup)(struct SoundIoPrivate *);
void (*force_device_scan)(struct SoundIoPrivate *);
int (*outstream_open)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
void (*outstream_destroy)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
int (*outstream_start)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
int (*outstream_begin_write)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *,
struct SoundIoChannelArea **out_areas, int *out_frame_count);
int (*outstream_end_write)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
int (*outstream_clear_buffer)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
int (*outstream_pause)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, bool pause);
int (*outstream_get_latency)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, double *out_latency);
int (*instream_open)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
void (*instream_destroy)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
int (*instream_start)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
int (*instream_begin_read)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *,
struct SoundIoChannelArea **out_areas, int *out_frame_count);
int (*instream_end_read)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
int (*instream_pause)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *, bool pause);
int (*instream_get_latency)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *, double *out_latency);
union SoundIoBackendData backend_data;
};
SOUNDIO_MAKE_LIST_STRUCT(struct SoundIoSampleRateRange, SoundIoListSampleRateRange, SOUNDIO_LIST_NOT_STATIC)
SOUNDIO_MAKE_LIST_PROTO(struct SoundIoSampleRateRange, SoundIoListSampleRateRange, SOUNDIO_LIST_NOT_STATIC)
struct SoundIoDevicePrivate {
struct SoundIoDevice pub;
union SoundIoDeviceBackendData backend_data;
void (*destruct)(struct SoundIoDevicePrivate *);
struct SoundIoSampleRateRange prealloc_sample_rate_range;
struct SoundIoListSampleRateRange sample_rates;
enum SoundIoFormat prealloc_format;
};
void soundio_destroy_devices_info(struct SoundIoDevicesInfo *devices_info);
static const int SOUNDIO_MIN_SAMPLE_RATE = 8000;
static const int SOUNDIO_MAX_SAMPLE_RATE = 5644800;
#endif #endif

View file

@ -9,7 +9,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include "util.hpp" #include "util.h"
void soundio_panic(const char *format, ...) { void soundio_panic(const char *format, ...) {
va_list ap; va_list ap;
@ -25,13 +25,13 @@ char *soundio_alloc_sprintf(int *len, const char *format, ...) {
va_start(ap, format); va_start(ap, format);
va_copy(ap2, ap); va_copy(ap2, ap);
int len1 = vsnprintf(nullptr, 0, format, ap); int len1 = vsnprintf(NULL, 0, format, ap);
assert(len1 >= 0); assert(len1 >= 0);
size_t required_size = len1 + 1; size_t required_size = len1 + 1;
char *mem = allocate<char>(required_size); char *mem = ALLOCATE(char, required_size);
if (!mem) if (!mem)
return nullptr; return NULL;
int len2 = vsnprintf(mem, required_size, format, ap2); int len2 = vsnprintf(mem, required_size, format, ap2);
assert(len2 == len1); assert(len2 == len1);

View file

@ -5,26 +5,44 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#ifndef SOUNDIO_UTIL_HPP #ifndef SOUNDIO_UTIL_H
#define SOUNDIO_UTIL_HPP #define SOUNDIO_UTIL_H
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <stdbool.h>
template<typename T> #define ALLOCATE_NONZERO(Type, count) malloc((count) * sizeof(Type))
__attribute__((malloc)) static inline T *allocate_nonzero(size_t count) {
return reinterpret_cast<T*>(malloc(count * sizeof(T))); #define ALLOCATE(Type, count) calloc(count, sizeof(Type))
#define REALLOCATE_NONZERO(Type, old, new_count) realloc(old, (new_count) * sizeof(Type))
#define ARRAY_LENGTH(array) (sizeof(array)/sizeof((array)[0]))
static inline int soundio_int_min(int a, int b) {
return (a <= b) ? a : b;
} }
template<typename T> static inline int soundio_int_max(int a, int b) {
__attribute__((malloc)) static inline T *allocate(size_t count) { return (a >= b) ? a : b;
return reinterpret_cast<T*>(calloc(count, sizeof(T)));
} }
template<typename T> static inline int soundio_int_clamp(int min_value, int value, int max_value) {
static inline T *reallocate_nonzero(T * old, size_t new_count) { return soundio_int_max(soundio_int_min(value, max_value), min_value);
return reinterpret_cast<T*>(realloc(old, new_count * sizeof(T))); }
static inline double soundio_double_min(double a, double b) {
return (a <= b) ? a : b;
}
static inline double soundio_double_max(double a, double b) {
return (a >= b) ? a : b;
}
static inline double soundio_double_clamp(double min_value, double value, double max_value) {
return soundio_double_max(soundio_double_min(value, max_value), min_value);
} }
void soundio_panic(const char *format, ...) void soundio_panic(const char *format, ...)
@ -36,9 +54,9 @@ char *soundio_alloc_sprintf(int *len, const char *format, ...)
__attribute__ ((format (printf, 2, 3))); __attribute__ ((format (printf, 2, 3)));
static inline char *soundio_str_dupe(const char *str, int str_len) { static inline char *soundio_str_dupe(const char *str, int str_len) {
char *out = allocate_nonzero<char>(str_len + 1); char *out = ALLOCATE_NONZERO(char, str_len + 1);
if (!out) if (!out)
return nullptr; return NULL;
memcpy(out, str, str_len); memcpy(out, str, str_len);
out[str_len] = 0; out[str_len] = 0;
return out; return out;
@ -61,24 +79,4 @@ static inline double ceil_dbl(double x) {
return ceiling; return ceiling;
} }
template <typename T, long n>
static constexpr long array_length(const T (&)[n]) {
return n;
}
template <typename T>
static inline T max(T a, T b) {
return (a >= b) ? a : b;
}
template <typename T>
static inline T min(T a, T b) {
return (a <= b) ? a : b;
}
template<typename T>
static inline T clamp(T min_value, T value, T max_value) {
return max(min(value, max_value), min_value);
}
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -5,13 +5,13 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#ifndef SOUNDIO_WASAPI_HPP #ifndef SOUNDIO_WASAPI_H
#define SOUNDIO_WASAPI_HPP #define SOUNDIO_WASAPI_H
#include "soundio_private.h" #include "soundio_internal.h"
#include "os.h" #include "os.h"
#include "atomics.hpp" #include "list.h"
#include "list.hpp" #include "atomics.h"
#define INITGUID #define INITGUID
#define CINTERFACE #define CINTERFACE
@ -25,6 +25,7 @@
#include <audiosessiontypes.h> #include <audiosessiontypes.h>
#include <audiopolicy.h> #include <audiopolicy.h>
struct SoundIoPrivate;
int soundio_wasapi_init(struct SoundIoPrivate *si); int soundio_wasapi_init(struct SoundIoPrivate *si);
struct SoundIoDeviceWasapi { struct SoundIoDeviceWasapi {
@ -33,10 +34,10 @@ struct SoundIoDeviceWasapi {
}; };
struct SoundIoWasapi { struct SoundIoWasapi {
SoundIoOsMutex *mutex; struct SoundIoOsMutex *mutex;
SoundIoOsCond *cond; struct SoundIoOsCond *cond;
SoundIoOsCond *scan_devices_cond; struct SoundIoOsCond *scan_devices_cond;
SoundIoOsMutex *scan_devices_mutex; struct SoundIoOsMutex *scan_devices_mutex;
struct SoundIoOsThread *thread; struct SoundIoOsThread *thread;
bool abort_flag; bool abort_flag;
// this one is ready to be read with flush_events. protected by mutex // this one is ready to be read with flush_events. protected by mutex
@ -58,17 +59,17 @@ struct SoundIoOutStreamWasapi {
IAudioSessionControl *audio_session_control; IAudioSessionControl *audio_session_control;
LPWSTR stream_name; LPWSTR stream_name;
bool need_resample; bool need_resample;
SoundIoOsThread *thread; struct SoundIoOsThread *thread;
SoundIoOsMutex *mutex; struct SoundIoOsMutex *mutex;
SoundIoOsCond *cond; struct SoundIoOsCond *cond;
SoundIoOsCond *start_cond; struct SoundIoOsCond *start_cond;
atomic_flag thread_exit_flag; atomic_flag thread_exit_flag;
bool is_raw; bool is_raw;
int writable_frame_count; int writable_frame_count;
UINT32 buffer_frame_count; UINT32 buffer_frame_count;
int write_frame_count; int write_frame_count;
HANDLE h_event; HANDLE h_event;
atomic_bool desired_pause_state; struct SoundIoAtomicBool desired_pause_state;
atomic_flag pause_resume_flag; atomic_flag pause_resume_flag;
atomic_flag clear_buffer_flag; atomic_flag clear_buffer_flag;
bool is_paused; bool is_paused;
@ -76,7 +77,7 @@ struct SoundIoOutStreamWasapi {
int open_err; int open_err;
bool started; bool started;
UINT32 min_padding_frames; UINT32 min_padding_frames;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS]; struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
}; };
struct SoundIoInStreamWasapi { struct SoundIoInStreamWasapi {
@ -84,10 +85,10 @@ struct SoundIoInStreamWasapi {
IAudioCaptureClient *audio_capture_client; IAudioCaptureClient *audio_capture_client;
IAudioSessionControl *audio_session_control; IAudioSessionControl *audio_session_control;
LPWSTR stream_name; LPWSTR stream_name;
SoundIoOsThread *thread; struct SoundIoOsThread *thread;
SoundIoOsMutex *mutex; struct SoundIoOsMutex *mutex;
SoundIoOsCond *cond; struct SoundIoOsCond *cond;
SoundIoOsCond *start_cond; struct SoundIoOsCond *start_cond;
atomic_flag thread_exit_flag; atomic_flag thread_exit_flag;
bool is_raw; bool is_raw;
int readable_frame_count; int readable_frame_count;
@ -100,7 +101,7 @@ struct SoundIoInStreamWasapi {
bool started; bool started;
char *read_buf; char *read_buf;
int read_buf_frames_left; int read_buf_frames_left;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS]; struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
}; };
#endif #endif

View file

@ -5,15 +5,15 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#include "soundio.hpp" #include "soundio_private.h"
#include "os.h" #include "os.h"
#include "util.hpp" #include "util.h"
#include "atomics.hpp"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include <stdint.h>
static int usage(char *exe) { static int usage(char *exe) {
fprintf(stderr, "Usage: %s [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi] [--latency seconds]\n", exe); fprintf(stderr, "Usage: %s [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi] [--latency seconds]\n", exe);
@ -51,9 +51,9 @@ static int pulse_frames_left = -1;
static const double PI = 3.14159265358979323846264338328; static const double PI = 3.14159265358979323846264338328;
static double seconds_offset = 0.0; static double seconds_offset = 0.0;
static SoundIoRingBuffer pulse_rb; static struct SoundIoRingBuffer pulse_rb;
static void write_time(SoundIoOutStream *outstream, double extra) { static void write_time(struct SoundIoOutStream *outstream, double extra) {
double latency; double latency;
int err; int err;
if ((err = soundio_outstream_get_latency(outstream, &latency))) { if ((err = soundio_outstream_get_latency(outstream, &latency))) {

View file

@ -1,9 +1,9 @@
#undef NDEBUG #undef NDEBUG
#include "soundio.hpp" #include "soundio_private.h"
#include "os.h" #include "os.h"
#include "util.hpp" #include "util.h"
#include "atomics.hpp" #include "atomics.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -58,7 +58,7 @@ static void test_create_outstream(void) {
static void test_ring_buffer_basic(void) { static void test_ring_buffer_basic(void) {
struct SoundIo *soundio = soundio_create(); struct SoundIo *soundio = soundio_create();
assert(soundio); assert(soundio);
SoundIoRingBuffer *rb = soundio_ring_buffer_create(soundio, 10); struct SoundIoRingBuffer *rb = soundio_ring_buffer_create(soundio, 10);
assert(rb); assert(rb);
int page_size = soundio_os_page_size(); int page_size = soundio_os_page_size();
@ -98,41 +98,41 @@ static void test_ring_buffer_basic(void) {
soundio_destroy(soundio); soundio_destroy(soundio);
} }
static SoundIoRingBuffer *rb = nullptr; static struct SoundIoRingBuffer *rb = NULL;
static const int rb_size = 3528; static const int rb_size = 3528;
static long expected_write_head; static long expected_write_head;
static long expected_read_head; static long expected_read_head;
static atomic_bool rb_done; static struct SoundIoAtomicBool rb_done;
static atomic_int rb_write_it; static struct SoundIoAtomicInt rb_write_it;
static atomic_int rb_read_it; static struct SoundIoAtomicInt rb_read_it;
// just for testing purposes; does not need to be high quality random // just for testing purposes; does not need to be high quality random
static double random_double(void) { static double random_double(void) {
return ((double)rand() / (double)RAND_MAX); return ((double)rand() / (double)RAND_MAX);
} }
static void reader_thread_run(void *) { static void reader_thread_run(void *arg) {
while (!rb_done) { while (!SOUNDIO_ATOMIC_LOAD(rb_done)) {
rb_read_it += 1; SOUNDIO_ATOMIC_FETCH_ADD(rb_read_it, 1);
int fill_count = soundio_ring_buffer_fill_count(rb); int fill_count = soundio_ring_buffer_fill_count(rb);
assert(fill_count >= 0); assert(fill_count >= 0);
assert(fill_count <= rb_size); assert(fill_count <= rb_size);
int amount_to_read = min((int)(random_double() * 2.0 * fill_count), fill_count); int amount_to_read = soundio_int_min(random_double() * 2.0 * fill_count, fill_count);
soundio_ring_buffer_advance_read_ptr(rb, amount_to_read); soundio_ring_buffer_advance_read_ptr(rb, amount_to_read);
expected_read_head += amount_to_read; expected_read_head += amount_to_read;
} }
} }
static void writer_thread_run(void *) { static void writer_thread_run(void *arg) {
while (!rb_done) { while (!SOUNDIO_ATOMIC_LOAD(rb_done)) {
rb_write_it += 1; SOUNDIO_ATOMIC_FETCH_ADD(rb_write_it, 1);
int fill_count = soundio_ring_buffer_fill_count(rb); int fill_count = soundio_ring_buffer_fill_count(rb);
assert(fill_count >= 0); assert(fill_count >= 0);
assert(fill_count <= rb_size); assert(fill_count <= rb_size);
int free_count = rb_size - fill_count; int free_count = rb_size - fill_count;
assert(free_count >= 0); assert(free_count >= 0);
assert(free_count <= rb_size); assert(free_count <= rb_size);
int value = min((int)(random_double() * 2.0 * free_count), free_count); int value = soundio_int_min(random_double() * 2.0 * free_count, free_count);
soundio_ring_buffer_advance_write_ptr(rb, value); soundio_ring_buffer_advance_write_ptr(rb, value);
expected_write_head += value; expected_write_head += value;
} }
@ -144,18 +144,18 @@ static void test_ring_buffer_threaded(void) {
rb = soundio_ring_buffer_create(soundio, rb_size); rb = soundio_ring_buffer_create(soundio, rb_size);
expected_write_head = 0; expected_write_head = 0;
expected_read_head = 0; expected_read_head = 0;
rb_read_it = 0; SOUNDIO_ATOMIC_STORE(rb_read_it, 0);
rb_write_it = 0; SOUNDIO_ATOMIC_STORE(rb_write_it, 0);
rb_done = false; SOUNDIO_ATOMIC_STORE(rb_done, false);
SoundIoOsThread *reader_thread; struct SoundIoOsThread *reader_thread;
ok_or_panic(soundio_os_thread_create(reader_thread_run, nullptr, nullptr, &reader_thread)); ok_or_panic(soundio_os_thread_create(reader_thread_run, NULL, NULL, &reader_thread));
SoundIoOsThread *writer_thread; struct SoundIoOsThread *writer_thread;
ok_or_panic(soundio_os_thread_create(writer_thread_run, nullptr, nullptr, &writer_thread)); ok_or_panic(soundio_os_thread_create(writer_thread_run, NULL, NULL, &writer_thread));
while (rb_read_it < 100000 || rb_write_it < 100000) {} while (SOUNDIO_ATOMIC_LOAD(rb_read_it) < 100000 || SOUNDIO_ATOMIC_LOAD(rb_write_it) < 100000) {}
rb_done = true; SOUNDIO_ATOMIC_STORE(rb_done, true);
soundio_os_thread_destroy(reader_thread); soundio_os_thread_destroy(reader_thread);
soundio_os_thread_destroy(writer_thread); soundio_os_thread_destroy(writer_thread);
@ -219,10 +219,10 @@ struct Test {
static struct Test tests[] = { static struct Test tests[] = {
{"os_get_time", test_os_get_time}, {"os_get_time", test_os_get_time},
{"create output stream", test_create_outstream}, {"create output stream", test_create_outstream},
{"ring buffer basic", test_ring_buffer_basic},
{"ring buffer threaded", test_ring_buffer_threaded},
{"mirrored memory", test_mirrored_memory}, {"mirrored memory", test_mirrored_memory},
{"soundio_device_nearest_sample_rate", test_nearest_sample_rate}, {"soundio_device_nearest_sample_rate", test_nearest_sample_rate},
{"ring buffer basic", test_ring_buffer_basic},
{"ring buffer threaded", test_ring_buffer_threaded},
{NULL, NULL}, {NULL, NULL},
}; };
@ -233,7 +233,7 @@ static void exec_test(struct Test *test) {
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
const char *match = nullptr; const char *match = NULL;
if (argc == 2) if (argc == 2)
match = argv[1]; match = argv[1];