mirror of
				https://github.com/Ryujinx/libsoundio.git
				synced 2025-11-04 14:44:53 +00:00 
			
		
		
		
	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:
		
							parent
							
								
									baba8064e1
								
							
						
					
					
						commit
						ee7c0d3e11
					
				| 
						 | 
				
			
			@ -1,5 +1,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})
 | 
			
		||||
 | 
			
		||||
if(CMAKE_VERSION VERSION_LESS 3.0.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -135,12 +135,12 @@ endif()
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
set(LIBSOUNDIO_SOURCES
 | 
			
		||||
    "${CMAKE_SOURCE_DIR}/src/soundio.cpp"
 | 
			
		||||
    "${CMAKE_SOURCE_DIR}/src/util.cpp"
 | 
			
		||||
    "${CMAKE_SOURCE_DIR}/src/os.cpp"
 | 
			
		||||
    "${CMAKE_SOURCE_DIR}/src/dummy.cpp"
 | 
			
		||||
    "${CMAKE_SOURCE_DIR}/src/channel_layout.cpp"
 | 
			
		||||
    "${CMAKE_SOURCE_DIR}/src/ring_buffer.cpp"
 | 
			
		||||
    "${CMAKE_SOURCE_DIR}/src/soundio.c"
 | 
			
		||||
    "${CMAKE_SOURCE_DIR}/src/util.c"
 | 
			
		||||
    "${CMAKE_SOURCE_DIR}/src/os.c"
 | 
			
		||||
    "${CMAKE_SOURCE_DIR}/src/dummy.c"
 | 
			
		||||
    "${CMAKE_SOURCE_DIR}/src/channel_layout.c"
 | 
			
		||||
    "${CMAKE_SOURCE_DIR}/src/ring_buffer.c"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h")
 | 
			
		||||
| 
						 | 
				
			
			@ -152,27 +152,27 @@ set(LIBSOUNDIO_HEADERS
 | 
			
		|||
 | 
			
		||||
if(SOUNDIO_HAVE_JACK)
 | 
			
		||||
    set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
 | 
			
		||||
        "${CMAKE_SOURCE_DIR}/src/jack.cpp"
 | 
			
		||||
        "${CMAKE_SOURCE_DIR}/src/jack.c"
 | 
			
		||||
    )
 | 
			
		||||
endif()
 | 
			
		||||
if(SOUNDIO_HAVE_PULSEAUDIO)
 | 
			
		||||
    set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
 | 
			
		||||
        "${CMAKE_SOURCE_DIR}/src/pulseaudio.cpp"
 | 
			
		||||
        "${CMAKE_SOURCE_DIR}/src/pulseaudio.c"
 | 
			
		||||
    )
 | 
			
		||||
endif()
 | 
			
		||||
if(SOUNDIO_HAVE_ALSA)
 | 
			
		||||
    set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
 | 
			
		||||
        "${CMAKE_SOURCE_DIR}/src/alsa.cpp"
 | 
			
		||||
        "${CMAKE_SOURCE_DIR}/src/alsa.c"
 | 
			
		||||
    )
 | 
			
		||||
endif()
 | 
			
		||||
if(SOUNDIO_HAVE_COREAUDIO)
 | 
			
		||||
    set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
 | 
			
		||||
        "${CMAKE_SOURCE_DIR}/src/coreaudio.cpp"
 | 
			
		||||
        "${CMAKE_SOURCE_DIR}/src/coreaudio.c"
 | 
			
		||||
    )
 | 
			
		||||
endif()
 | 
			
		||||
if(SOUNDIO_HAVE_WASAPI)
 | 
			
		||||
    set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
 | 
			
		||||
        "${CMAKE_SOURCE_DIR}/src/wasapi.cpp"
 | 
			
		||||
        "${CMAKE_SOURCE_DIR}/src/wasapi.c"
 | 
			
		||||
    )
 | 
			
		||||
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_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(TEST_CFLAGS "${LIB_CFLAGS} -fprofile-arcs -ftest-coverage")
 | 
			
		||||
set(TEST_LDFLAGS "-fprofile-arcs -ftest-coverage")
 | 
			
		||||
| 
						 | 
				
			
			@ -277,7 +272,7 @@ if(BUILD_EXAMPLE_PROGRAMS)
 | 
			
		|||
endif()
 | 
			
		||||
 | 
			
		||||
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})
 | 
			
		||||
    set_target_properties(unit_tests PROPERTIES
 | 
			
		||||
        LINKER_LANGUAGE C
 | 
			
		||||
| 
						 | 
				
			
			@ -285,7 +280,7 @@ if(BUILD_TESTS)
 | 
			
		|||
        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)
 | 
			
		||||
    set_target_properties(latency PROPERTIES
 | 
			
		||||
        LINKER_LANGUAGE C
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										16
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								README.md
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -181,22 +181,6 @@ and `soundio_get_backend` to get the list of available backends.
 | 
			
		|||
 | 
			
		||||
[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
 | 
			
		||||
 | 
			
		||||
Install the dependencies:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,10 +5,13 @@
 | 
			
		|||
 * See http://opensource.org/licenses/MIT
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "alsa.hpp"
 | 
			
		||||
#include "soundio.hpp"
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include "alsa.h"
 | 
			
		||||
#include "soundio_private.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};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -20,8 +23,9 @@ static snd_pcm_access_t prioritized_access_types[] = {
 | 
			
		|||
    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);
 | 
			
		||||
    if (amt == -1) {
 | 
			
		||||
        assert(errno != EBADF);
 | 
			
		||||
| 
						 | 
				
			
			@ -32,16 +36,16 @@ static void wakeup_device_poll(SoundIoAlsa *sia) {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void destroy_alsa(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIoAlsa *sia = &si->backend_data.alsa;
 | 
			
		||||
static void destroy_alsa(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIoAlsa *sia = &si->backend_data.alsa;
 | 
			
		||||
 | 
			
		||||
    if (sia->thread) {
 | 
			
		||||
        sia->abort_flag.clear();
 | 
			
		||||
        atomic_flag_clear(&sia->abort_flag);
 | 
			
		||||
        wakeup_device_poll(sia);
 | 
			
		||||
        soundio_os_thread_destroy(sia->thread);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sia->pending_files.deinit();
 | 
			
		||||
    SoundIoListAlsaPendingFile_deinit(&sia->pending_files);
 | 
			
		||||
 | 
			
		||||
    if (sia->cond)
 | 
			
		||||
        soundio_os_cond_destroy(sia->cond);
 | 
			
		||||
| 
						 | 
				
			
			@ -71,10 +75,10 @@ static char * str_partition_on_char(char *str, char c) {
 | 
			
		|||
        }
 | 
			
		||||
        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) {
 | 
			
		||||
        case SoundIoDeviceAimOutput: return SND_PCM_STREAM_PLAYBACK;
 | 
			
		||||
        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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SoundIoChannelId from_alsa_chmap_pos(unsigned int pos) {
 | 
			
		||||
    switch ((snd_pcm_chmap_position)pos) {
 | 
			
		||||
static enum SoundIoChannelId from_alsa_chmap_pos(unsigned int pos) {
 | 
			
		||||
    switch ((enum snd_pcm_chmap_position)pos) {
 | 
			
		||||
        case SND_CHMAP_UNKNOWN: return SoundIoChannelIdInvalid;
 | 
			
		||||
        case SND_CHMAP_NA:      return SoundIoChannelIdInvalid;
 | 
			
		||||
        case SND_CHMAP_MONO:    return SoundIoChannelIdFrontCenter;
 | 
			
		||||
| 
						 | 
				
			
			@ -126,7 +130,7 @@ static SoundIoChannelId from_alsa_chmap_pos(unsigned int pos) {
 | 
			
		|||
    return SoundIoChannelIdInvalid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int to_alsa_chmap_pos(SoundIoChannelId channel_id) {
 | 
			
		||||
static int to_alsa_chmap_pos(enum SoundIoChannelId channel_id) {
 | 
			
		||||
    switch (channel_id) {
 | 
			
		||||
        case SoundIoChannelIdFrontLeft:             return SND_CHMAP_FL;
 | 
			
		||||
        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) {
 | 
			
		||||
    int channel_count = min((unsigned int)SOUNDIO_MAX_CHANNELS, chmap->channels);
 | 
			
		||||
static void get_channel_layout(struct SoundIoChannelLayout *dest, snd_pcm_chmap_t *chmap) {
 | 
			
		||||
    int channel_count = soundio_int_min(SOUNDIO_MAX_CHANNELS, chmap->channels);
 | 
			
		||||
    dest->channel_count = channel_count;
 | 
			
		||||
    for (int i = 0; i < channel_count; i += 1) {
 | 
			
		||||
        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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
        return 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -187,7 +191,7 @@ static int handle_channel_maps(SoundIoDevice *device, snd_pcm_chmap_query_t **ma
 | 
			
		|||
    // one iteration to count
 | 
			
		||||
    int layout_count = 0;
 | 
			
		||||
    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) {
 | 
			
		||||
        snd_pcm_free_chmaps(maps);
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
| 
						 | 
				
			
			@ -207,7 +211,7 @@ static int handle_channel_maps(SoundIoDevice *device, snd_pcm_chmap_query_t **ma
 | 
			
		|||
    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) {
 | 
			
		||||
    case SoundIoFormatS8:           return SND_PCM_FORMAT_S8;
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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))) {
 | 
			
		||||
        device->formats[device->format_count] = fmt;
 | 
			
		||||
        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) {
 | 
			
		||||
    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];
 | 
			
		||||
        int err = snd_pcm_hw_params_set_access(handle, hwparams, access);
 | 
			
		||||
        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
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
 | 
			
		||||
    struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
 | 
			
		||||
    int err;
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
        return SoundIoErrorOpeningDevice;
 | 
			
		||||
 | 
			
		||||
    if ((err = set_access(handle, hwparams, nullptr)))
 | 
			
		||||
    if ((err = set_access(handle, hwparams, NULL)))
 | 
			
		||||
        return err;
 | 
			
		||||
 | 
			
		||||
    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_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;
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
    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) {
 | 
			
		||||
        snd_pcm_hw_params_get_format_mask(hwparams, fmt_mask);
 | 
			
		||||
        device->formats = allocate<SoundIoFormat>(18);
 | 
			
		||||
        device->formats = ALLOCATE(enum SoundIoFormat, 18);
 | 
			
		||||
        if (!device->formats)
 | 
			
		||||
            return SoundIoErrorNoMem;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -373,7 +379,7 @@ static int probe_open_device(SoundIoDevice *device, snd_pcm_t *handle, int resam
 | 
			
		|||
    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;
 | 
			
		||||
    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.
 | 
			
		||||
            int layout_count = 0;
 | 
			
		||||
            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) {
 | 
			
		||||
                    layout_count += 1;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            device->layout_count = layout_count;
 | 
			
		||||
            device->layouts = allocate<SoundIoChannelLayout>(device->layout_count);
 | 
			
		||||
            device->layouts = ALLOCATE(struct SoundIoChannelLayout, device->layout_count);
 | 
			
		||||
            if (!device->layouts) {
 | 
			
		||||
                snd_pcm_close(handle);
 | 
			
		||||
                return SoundIoErrorNoMem;
 | 
			
		||||
            }
 | 
			
		||||
            int layout_index = 0;
 | 
			
		||||
            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) {
 | 
			
		||||
                    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);
 | 
			
		||||
        return err;
 | 
			
		||||
    }
 | 
			
		||||
    maps = nullptr;
 | 
			
		||||
    maps = NULL;
 | 
			
		||||
 | 
			
		||||
    if (!device->is_raw) {
 | 
			
		||||
        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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int refresh_devices(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoAlsa *sia = &si->backend_data.alsa;
 | 
			
		||||
static int refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoAlsa *sia = &si->backend_data.alsa;
 | 
			
		||||
 | 
			
		||||
    int err;
 | 
			
		||||
    if ((err = snd_config_update_free_global()) < 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -462,7 +468,7 @@ static int refresh_devices(SoundIoPrivate *si) {
 | 
			
		|||
    if ((err = snd_config_update()) < 0)
 | 
			
		||||
        return SoundIoErrorSystemResources;
 | 
			
		||||
 | 
			
		||||
    SoundIoDevicesInfo *devices_info = allocate<SoundIoDevicesInfo>(1);
 | 
			
		||||
    struct SoundIoDevicesInfo *devices_info = ALLOCATE(struct SoundIoDevicesInfo, 1);
 | 
			
		||||
    if (!devices_info)
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
    devices_info->default_output_index = -1;
 | 
			
		||||
| 
						 | 
				
			
			@ -517,7 +523,7 @@ static int refresh_devices(SoundIoPrivate *si) {
 | 
			
		|||
            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];
 | 
			
		||||
            if (stream == SND_PCM_STREAM_PLAYBACK && !is_playback) 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) {
 | 
			
		||||
                free(name);
 | 
			
		||||
                free(descr);
 | 
			
		||||
| 
						 | 
				
			
			@ -536,13 +542,13 @@ static int refresh_devices(SoundIoPrivate *si) {
 | 
			
		|||
                snd_device_name_free_hint(hints);
 | 
			
		||||
                return SoundIoErrorNoMem;
 | 
			
		||||
            }
 | 
			
		||||
            SoundIoDevice *device = &dev->pub;
 | 
			
		||||
            struct SoundIoDevice *device = &dev->pub;
 | 
			
		||||
            device->ref_count = 1;
 | 
			
		||||
            device->soundio = soundio;
 | 
			
		||||
            device->is_raw = false;
 | 
			
		||||
            device->id = strdup(name);
 | 
			
		||||
            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) {
 | 
			
		||||
                soundio_device_unref(device);
 | 
			
		||||
| 
						 | 
				
			
			@ -553,7 +559,7 @@ static int refresh_devices(SoundIoPrivate *si) {
 | 
			
		|||
                return SoundIoErrorNoMem;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SoundIoList<SoundIoDevice *> *device_list;
 | 
			
		||||
            struct SoundIoListDevicePtr *device_list;
 | 
			
		||||
            bool is_default = str_has_prefix(name, "default:") || strcmp(name, "default") == 0;
 | 
			
		||||
            if (stream == SND_PCM_STREAM_PLAYBACK) {
 | 
			
		||||
                device->aim = SoundIoDeviceAimOutput;
 | 
			
		||||
| 
						 | 
				
			
			@ -568,9 +574,9 @@ static int refresh_devices(SoundIoPrivate *si) {
 | 
			
		|||
                    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);
 | 
			
		||||
                free(name);
 | 
			
		||||
                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_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_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);
 | 
			
		||||
 | 
			
		||||
                SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1);
 | 
			
		||||
                struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
 | 
			
		||||
                if (!dev) {
 | 
			
		||||
                    snd_ctl_close(handle);
 | 
			
		||||
                    soundio_destroy_devices_info(devices_info);
 | 
			
		||||
                    return SoundIoErrorNoMem;
 | 
			
		||||
                }
 | 
			
		||||
                SoundIoDevice *device = &dev->pub;
 | 
			
		||||
                struct SoundIoDevice *device = &dev->pub;
 | 
			
		||||
                device->ref_count = 1;
 | 
			
		||||
                device->soundio = soundio;
 | 
			
		||||
                device->id = soundio_alloc_sprintf(nullptr, "hw:%d,%d", card_index, device_index);
 | 
			
		||||
                device->name = soundio_alloc_sprintf(nullptr, "%s %s", card_name, device_name);
 | 
			
		||||
                device->id = soundio_alloc_sprintf(NULL, "hw:%d,%d", card_index, device_index);
 | 
			
		||||
                device->name = soundio_alloc_sprintf(NULL, "%s %s", card_name, device_name);
 | 
			
		||||
                device->is_raw = true;
 | 
			
		||||
 | 
			
		||||
                if (!device->id || !device->name) {
 | 
			
		||||
| 
						 | 
				
			
			@ -667,7 +673,7 @@ static int refresh_devices(SoundIoPrivate *si) {
 | 
			
		|||
                    return SoundIoErrorNoMem;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                SoundIoList<SoundIoDevice *> *device_list;
 | 
			
		||||
                struct SoundIoListDevicePtr *device_list;
 | 
			
		||||
                if (stream == SND_PCM_STREAM_PLAYBACK) {
 | 
			
		||||
                    device->aim = SoundIoDeviceAimOutput;
 | 
			
		||||
                    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);
 | 
			
		||||
                device->probe_error = probe_device(device, maps);
 | 
			
		||||
 | 
			
		||||
                if (device_list->append(device)) {
 | 
			
		||||
                if (SoundIoListDevicePtr_append(device_list, device)) {
 | 
			
		||||
                    soundio_device_unref(device);
 | 
			
		||||
                    soundio_destroy_devices_info(devices_info);
 | 
			
		||||
                    return SoundIoErrorNoMem;
 | 
			
		||||
| 
						 | 
				
			
			@ -704,9 +710,9 @@ static int refresh_devices(SoundIoPrivate *si) {
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void shutdown_backend(SoundIoPrivate *si, int err) {
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoAlsa *sia = &si->backend_data.alsa;
 | 
			
		||||
static void shutdown_backend(struct SoundIoPrivate *si, int err) {
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoAlsa *sia = &si->backend_data.alsa;
 | 
			
		||||
    soundio_os_mutex_lock(sia->mutex);
 | 
			
		||||
    sia->shutdown_err = err;
 | 
			
		||||
    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) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)arg;
 | 
			
		||||
    SoundIoAlsa *sia = &si->backend_data.alsa;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
 | 
			
		||||
    struct SoundIoAlsa *sia = &si->backend_data.alsa;
 | 
			
		||||
 | 
			
		||||
    // Some systems cannot read integer variables if they are not
 | 
			
		||||
    // properly aligned. On other systems, incorrect alignment may
 | 
			
		||||
| 
						 | 
				
			
			@ -751,7 +757,7 @@ static void device_thread_run(void *arg) {
 | 
			
		|||
    int err;
 | 
			
		||||
    for (;;) {
 | 
			
		||||
        int poll_num = poll(fds, 2, -1);
 | 
			
		||||
        if (!sia->abort_flag.test_and_set())
 | 
			
		||||
        if (!atomic_flag_test_and_set(&sia->abort_flag))
 | 
			
		||||
            break;
 | 
			
		||||
        if (poll_num == -1) {
 | 
			
		||||
            if (errno == EINTR)
 | 
			
		||||
| 
						 | 
				
			
			@ -801,13 +807,14 @@ static void device_thread_run(void *arg) {
 | 
			
		|||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
                    if (event->mask & IN_CREATE) {
 | 
			
		||||
                        if ((err = sia->pending_files.add_one())) {
 | 
			
		||||
                        if ((err = SoundIoListAlsaPendingFile_add_one(&sia->pending_files))) {
 | 
			
		||||
                            shutdown_backend(si, SoundIoErrorNoMem);
 | 
			
		||||
                            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)) {
 | 
			
		||||
                            sia->pending_files.pop();
 | 
			
		||||
                            SoundIoListAlsaPendingFile_pop(&sia->pending_files);
 | 
			
		||||
                        }
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -817,9 +824,10 @@ static void device_thread_run(void *arg) {
 | 
			
		|||
                        if (!(event->mask & IN_CLOSE_WRITE))
 | 
			
		||||
                            continue;
 | 
			
		||||
                        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) {
 | 
			
		||||
                                sia->pending_files.swap_remove(i);
 | 
			
		||||
                                SoundIoListAlsaPendingFile_swap_remove(&sia->pending_files, i);
 | 
			
		||||
                                if (sia->pending_files.length == 0) {
 | 
			
		||||
                                    got_rescan_event = true;
 | 
			
		||||
                                }
 | 
			
		||||
| 
						 | 
				
			
			@ -864,13 +872,13 @@ static void device_thread_run(void *arg) {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void my_flush_events(SoundIoPrivate *si, bool wait) {
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoAlsa *sia = &si->backend_data.alsa;
 | 
			
		||||
static void my_flush_events(struct SoundIoPrivate *si, bool wait) {
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoAlsa *sia = &si->backend_data.alsa;
 | 
			
		||||
 | 
			
		||||
    bool change = false;
 | 
			
		||||
    bool cb_shutdown = false;
 | 
			
		||||
    SoundIoDevicesInfo *old_devices_info = nullptr;
 | 
			
		||||
    struct SoundIoDevicesInfo *old_devices_info = NULL;
 | 
			
		||||
 | 
			
		||||
    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) {
 | 
			
		||||
        old_devices_info = si->safe_devices_info;
 | 
			
		||||
        si->safe_devices_info = sia->ready_devices_info;
 | 
			
		||||
        sia->ready_devices_info = nullptr;
 | 
			
		||||
        sia->ready_devices_info = NULL;
 | 
			
		||||
        change = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -900,54 +908,54 @@ static void my_flush_events(SoundIoPrivate *si, bool wait) {
 | 
			
		|||
    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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void wait_events_alsa(SoundIoPrivate *si) {
 | 
			
		||||
static void wait_events_alsa(struct SoundIoPrivate *si) {
 | 
			
		||||
    my_flush_events(si, false);
 | 
			
		||||
    my_flush_events(si, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void wakeup_alsa(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIoAlsa *sia = &si->backend_data.alsa;
 | 
			
		||||
static void wakeup_alsa(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIoAlsa *sia = &si->backend_data.alsa;
 | 
			
		||||
    soundio_os_mutex_lock(sia->mutex);
 | 
			
		||||
    soundio_os_cond_signal(sia->cond, sia->mutex);
 | 
			
		||||
    soundio_os_mutex_unlock(sia->mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void force_device_scan_alsa(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIoAlsa *sia = &si->backend_data.alsa;
 | 
			
		||||
static void force_device_scan_alsa(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIoAlsa *sia = &si->backend_data.alsa;
 | 
			
		||||
    wakeup_device_poll(sia);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void outstream_destroy_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
static void outstream_destroy_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
 | 
			
		||||
    if (osa->thread) {
 | 
			
		||||
        osa->thread_exit_flag.clear();
 | 
			
		||||
        atomic_flag_clear(&osa->thread_exit_flag);
 | 
			
		||||
        soundio_os_thread_destroy(osa->thread);
 | 
			
		||||
        osa->thread = nullptr;
 | 
			
		||||
        osa->thread = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (osa->handle) {
 | 
			
		||||
        snd_pcm_close(osa->handle);
 | 
			
		||||
        osa->handle = nullptr;
 | 
			
		||||
        osa->handle = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    free(osa->poll_fds);
 | 
			
		||||
    osa->poll_fds = nullptr;
 | 
			
		||||
    osa->poll_fds = NULL;
 | 
			
		||||
 | 
			
		||||
    free(osa->chmap);
 | 
			
		||||
    osa->chmap = nullptr;
 | 
			
		||||
    osa->chmap = NULL;
 | 
			
		||||
 | 
			
		||||
    free(osa->sample_buffer);
 | 
			
		||||
    osa->sample_buffer = nullptr;
 | 
			
		||||
    osa->sample_buffer = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_xrun_recovery(SoundIoOutStreamPrivate *os, int err) {
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
static int outstream_xrun_recovery(struct SoundIoOutStreamPrivate *os, int err) {
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
    if (err == -EPIPE) {
 | 
			
		||||
        err = snd_pcm_prepare(osa->handle);
 | 
			
		||||
        if (err >= 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -955,7 +963,7 @@ static int outstream_xrun_recovery(SoundIoOutStreamPrivate *os, int err) {
 | 
			
		|||
    } else if (err == -ESTRPIPE) {
 | 
			
		||||
        while ((err = snd_pcm_resume(osa->handle)) == -EAGAIN) {
 | 
			
		||||
            // wait until suspend flag is released
 | 
			
		||||
            poll(nullptr, 0, 1);
 | 
			
		||||
            poll(NULL, 0, 1);
 | 
			
		||||
        }
 | 
			
		||||
        if (err < 0)
 | 
			
		||||
            err = snd_pcm_prepare(osa->handle);
 | 
			
		||||
| 
						 | 
				
			
			@ -965,9 +973,9 @@ static int outstream_xrun_recovery(SoundIoOutStreamPrivate *os, int err) {
 | 
			
		|||
    return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_xrun_recovery(SoundIoInStreamPrivate *is, int err) {
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
static int instream_xrun_recovery(struct SoundIoInStreamPrivate *is, int err) {
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
    if (err == -EPIPE) {
 | 
			
		||||
        err = snd_pcm_prepare(isa->handle);
 | 
			
		||||
        if (err >= 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -975,7 +983,7 @@ static int instream_xrun_recovery(SoundIoInStreamPrivate *is, int err) {
 | 
			
		|||
    } else if (err == -ESTRPIPE) {
 | 
			
		||||
        while ((err = snd_pcm_resume(isa->handle)) == -EAGAIN) {
 | 
			
		||||
            // wait until suspend flag is released
 | 
			
		||||
            poll(nullptr, 0, 1);
 | 
			
		||||
            poll(NULL, 0, 1);
 | 
			
		||||
        }
 | 
			
		||||
        if (err < 0)
 | 
			
		||||
            err = snd_pcm_prepare(isa->handle);
 | 
			
		||||
| 
						 | 
				
			
			@ -985,8 +993,8 @@ static int instream_xrun_recovery(SoundIoInStreamPrivate *is, int err) {
 | 
			
		|||
    return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_wait_for_poll(SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
static int outstream_wait_for_poll(struct SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
    int err;
 | 
			
		||||
    unsigned short revents;
 | 
			
		||||
    for (;;) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1006,8 +1014,8 @@ static int outstream_wait_for_poll(SoundIoOutStreamPrivate *os) {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_wait_for_poll(SoundIoInStreamPrivate *is) {
 | 
			
		||||
    SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
static int instream_wait_for_poll(struct SoundIoInStreamPrivate *is) {
 | 
			
		||||
    struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
    int err;
 | 
			
		||||
    unsigned short revents;
 | 
			
		||||
    for (;;) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1028,9 +1036,9 @@ static int instream_wait_for_poll(SoundIoInStreamPrivate *is) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static void outstream_thread_run(void *arg) {
 | 
			
		||||
    SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *) arg;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *) arg;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
 | 
			
		||||
    int err;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1055,7 +1063,7 @@ static void outstream_thread_run(void *arg) {
 | 
			
		|||
 | 
			
		||||
                if ((snd_pcm_uframes_t)avail == osa->buffer_size_frames) {
 | 
			
		||||
                    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;
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -1070,14 +1078,14 @@ static void outstream_thread_run(void *arg) {
 | 
			
		|||
            case SND_PCM_STATE_PAUSED:
 | 
			
		||||
            {
 | 
			
		||||
                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;
 | 
			
		||||
                    outstream->error_callback(outstream, SoundIoErrorStreaming);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                if (!osa->thread_exit_flag.test_and_set())
 | 
			
		||||
                if (!atomic_flag_test_and_set(&osa->thread_exit_flag))
 | 
			
		||||
                    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) {
 | 
			
		||||
                        outstream->error_callback(outstream, SoundIoErrorStreaming);
 | 
			
		||||
                        return;
 | 
			
		||||
| 
						 | 
				
			
			@ -1130,9 +1138,9 @@ static void outstream_thread_run(void *arg) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static void instream_thread_run(void *arg) {
 | 
			
		||||
    SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *) arg;
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
    struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *) arg;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
 | 
			
		||||
    int err;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1155,12 +1163,12 @@ static void instream_thread_run(void *arg) {
 | 
			
		|||
            case SND_PCM_STATE_PAUSED:
 | 
			
		||||
            {
 | 
			
		||||
                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;
 | 
			
		||||
                    instream->error_callback(instream, SoundIoErrorStreaming);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                if (!isa->thread_exit_flag.test_and_set())
 | 
			
		||||
                if (!atomic_flag_test_and_set(&isa->thread_exit_flag))
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                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) {
 | 
			
		||||
    SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    SoundIoDevice *device = outstream->device;
 | 
			
		||||
static int outstream_open_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    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)
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
    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) {
 | 
			
		||||
        outstream_destroy_alsa(si, os);
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
| 
						 | 
				
			
			@ -1272,7 +1280,7 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
 | 
			
		|||
    if (device->is_raw) {
 | 
			
		||||
        period_count = 4;
 | 
			
		||||
        unsigned int microseconds = 0.25 * outstream->software_latency * 1000000.0;
 | 
			
		||||
        if ((err = snd_pcm_hw_params_set_period_time_near(osa->handle, hwparams, µseconds, nullptr)) < 0) {
 | 
			
		||||
        if ((err = snd_pcm_hw_params_set_period_time_near(osa->handle, hwparams, µseconds, NULL)) < 0) {
 | 
			
		||||
            outstream_destroy_alsa(si, os);
 | 
			
		||||
            return SoundIoErrorOpeningDevice;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1282,14 +1290,14 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
 | 
			
		|||
        snd_pcm_uframes_t period_frames =
 | 
			
		||||
            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);
 | 
			
		||||
            return SoundIoErrorOpeningDevice;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
        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) {
 | 
			
		||||
        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) {
 | 
			
		||||
            outstream_destroy_alsa(si, os);
 | 
			
		||||
            return SoundIoErrorNoMem;
 | 
			
		||||
| 
						 | 
				
			
			@ -1356,7 +1364,7 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
 | 
			
		|||
        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) {
 | 
			
		||||
        outstream_destroy_alsa(si, os);
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
| 
						 | 
				
			
			@ -1370,26 +1378,26 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_start_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
static int outstream_start_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
 | 
			
		||||
    assert(!osa->thread);
 | 
			
		||||
 | 
			
		||||
    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)))
 | 
			
		||||
        return err;
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
    *out_areas = nullptr;
 | 
			
		||||
    SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    *out_areas = NULL;
 | 
			
		||||
    struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
 | 
			
		||||
    if (osa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
 | 
			
		||||
        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->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;
 | 
			
		||||
    } else if (osa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
 | 
			
		||||
        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->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;
 | 
			
		||||
    } else {
 | 
			
		||||
        const snd_pcm_channel_area_t *areas;
 | 
			
		||||
| 
						 | 
				
			
			@ -1435,9 +1443,9 @@ static int outstream_begin_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivat
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_end_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
static int outstream_end_write_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
 | 
			
		||||
    snd_pcm_sframes_t commitres;
 | 
			
		||||
    if (osa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1462,11 +1470,11 @@ static int outstream_end_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_clear_buffer_alsa(SoundIoPrivate *si,
 | 
			
		||||
        SoundIoOutStreamPrivate *os)
 | 
			
		||||
static int outstream_clear_buffer_alsa(struct SoundIoPrivate *si,
 | 
			
		||||
        struct SoundIoOutStreamPrivate *os)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
    osa->clear_buffer_flag.clear();
 | 
			
		||||
    struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
    atomic_flag_clear(&osa->clear_buffer_flag);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1474,7 +1482,7 @@ static int outstream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoOutStre
 | 
			
		|||
    if (!si)
 | 
			
		||||
        return SoundIoErrorInvalid;
 | 
			
		||||
 | 
			
		||||
    SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
    struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
 | 
			
		||||
    if (!osa->handle)
 | 
			
		||||
        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,
 | 
			
		||||
        double *out_latency)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
 | 
			
		||||
    int err;
 | 
			
		||||
 | 
			
		||||
    snd_pcm_sframes_t delay;
 | 
			
		||||
| 
						 | 
				
			
			@ -1507,43 +1515,43 @@ static int outstream_get_latency_alsa(struct SoundIoPrivate *si, struct SoundIoO
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void instream_destroy_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
 | 
			
		||||
    SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
static void instream_destroy_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
 | 
			
		||||
    struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
 | 
			
		||||
    if (isa->thread) {
 | 
			
		||||
        isa->thread_exit_flag.clear();
 | 
			
		||||
        atomic_flag_clear(&isa->thread_exit_flag);
 | 
			
		||||
        soundio_os_thread_destroy(isa->thread);
 | 
			
		||||
        isa->thread = nullptr;
 | 
			
		||||
        isa->thread = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (isa->handle) {
 | 
			
		||||
        snd_pcm_close(isa->handle);
 | 
			
		||||
        isa->handle = nullptr;
 | 
			
		||||
        isa->handle = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    free(isa->poll_fds);
 | 
			
		||||
    isa->poll_fds = nullptr;
 | 
			
		||||
    isa->poll_fds = NULL;
 | 
			
		||||
 | 
			
		||||
    free(isa->chmap);
 | 
			
		||||
    isa->chmap = nullptr;
 | 
			
		||||
    isa->chmap = NULL;
 | 
			
		||||
 | 
			
		||||
    free(isa->sample_buffer);
 | 
			
		||||
    isa->sample_buffer = nullptr;
 | 
			
		||||
    isa->sample_buffer = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
 | 
			
		||||
    SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    SoundIoDevice *device = instream->device;
 | 
			
		||||
static int instream_open_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
 | 
			
		||||
    struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoDevice *device = instream->device;
 | 
			
		||||
 | 
			
		||||
    if (instream->software_latency == 0.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;
 | 
			
		||||
 | 
			
		||||
    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) {
 | 
			
		||||
        instream_destroy_alsa(si, is);
 | 
			
		||||
        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);
 | 
			
		||||
    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);
 | 
			
		||||
        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) {
 | 
			
		||||
        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) {
 | 
			
		||||
            instream_destroy_alsa(si, is);
 | 
			
		||||
            return SoundIoErrorNoMem;
 | 
			
		||||
| 
						 | 
				
			
			@ -1658,7 +1666,7 @@ static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
 | 
			
		|||
        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) {
 | 
			
		||||
        instream_destroy_alsa(si, is);
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
| 
						 | 
				
			
			@ -1672,13 +1680,13 @@ static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_start_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
 | 
			
		||||
    SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
static int instream_start_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
 | 
			
		||||
    struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
 | 
			
		||||
    assert(!isa->thread);
 | 
			
		||||
 | 
			
		||||
    isa->thread_exit_flag.test_and_set();
 | 
			
		||||
    atomic_flag_test_and_set(&isa->thread_exit_flag);
 | 
			
		||||
    int err;
 | 
			
		||||
    if ((err = soundio_os_thread_create(instream_thread_run, is, soundio->emit_rtprio_warning, &isa->thread))) {
 | 
			
		||||
        instream_destroy_alsa(si, is);
 | 
			
		||||
| 
						 | 
				
			
			@ -1688,12 +1696,12 @@ static int instream_start_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_begin_read_alsa(SoundIoPrivate *si,
 | 
			
		||||
        SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count)
 | 
			
		||||
static int instream_begin_read_alsa(struct SoundIoPrivate *si,
 | 
			
		||||
        struct SoundIoInStreamPrivate *is, struct SoundIoChannelArea **out_areas, int *frame_count)
 | 
			
		||||
{
 | 
			
		||||
    *out_areas = nullptr;
 | 
			
		||||
    SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    *out_areas = NULL;
 | 
			
		||||
    struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
 | 
			
		||||
    if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
 | 
			
		||||
        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->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;
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_end_read_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
 | 
			
		||||
    SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
static int instream_end_read_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
 | 
			
		||||
    struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
 | 
			
		||||
    if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
 | 
			
		||||
        // 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) {
 | 
			
		||||
    SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
    struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
 | 
			
		||||
    if (isa->is_paused == pause)
 | 
			
		||||
        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,
 | 
			
		||||
        double *out_latency)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
 | 
			
		||||
    int err;
 | 
			
		||||
 | 
			
		||||
    snd_pcm_sframes_t delay;
 | 
			
		||||
| 
						 | 
				
			
			@ -1802,13 +1810,13 @@ static int instream_get_latency_alsa(struct SoundIoPrivate *si, struct SoundIoIn
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int soundio_alsa_init(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIoAlsa *sia = &si->backend_data.alsa;
 | 
			
		||||
int soundio_alsa_init(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIoAlsa *sia = &si->backend_data.alsa;
 | 
			
		||||
    int err;
 | 
			
		||||
 | 
			
		||||
    sia->notify_fd = -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();
 | 
			
		||||
    if (!sia->mutex) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1865,7 +1873,7 @@ int soundio_alsa_init(SoundIoPrivate *si) {
 | 
			
		|||
 | 
			
		||||
    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);
 | 
			
		||||
        return err;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -5,28 +5,31 @@
 | 
			
		|||
 * See http://opensource.org/licenses/MIT
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef SOUNDIO_ALSA_HPP
 | 
			
		||||
#define SOUNDIO_ALSA_HPP
 | 
			
		||||
#ifndef SOUNDIO_ALSA_H
 | 
			
		||||
#define SOUNDIO_ALSA_H
 | 
			
		||||
 | 
			
		||||
#include "soundio_private.h"
 | 
			
		||||
#include "soundio_internal.h"
 | 
			
		||||
#include "os.h"
 | 
			
		||||
#include "atomics.hpp"
 | 
			
		||||
#include "list.hpp"
 | 
			
		||||
#include "list.h"
 | 
			
		||||
#include "atomics.h"
 | 
			
		||||
 | 
			
		||||
#include <alsa/asoundlib.h>
 | 
			
		||||
 | 
			
		||||
struct SoundIoPrivate;
 | 
			
		||||
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
 | 
			
		||||
struct SoundIoAlsaPendingFile {
 | 
			
		||||
    char name[SOUNDIO_MAX_ALSA_SND_FILE_LEN];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
SOUNDIO_MAKE_LIST_STRUCT(struct SoundIoAlsaPendingFile, SoundIoListAlsaPendingFile, SOUNDIO_LIST_STATIC)
 | 
			
		||||
 | 
			
		||||
struct SoundIoAlsa {
 | 
			
		||||
    SoundIoOsMutex *mutex;
 | 
			
		||||
    SoundIoOsCond *cond;
 | 
			
		||||
    struct SoundIoOsMutex *mutex;
 | 
			
		||||
    struct SoundIoOsCond *cond;
 | 
			
		||||
 | 
			
		||||
    struct SoundIoOsThread *thread;
 | 
			
		||||
    atomic_flag abort_flag;
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +37,7 @@ struct SoundIoAlsa {
 | 
			
		|||
    int notify_wd;
 | 
			
		||||
    bool have_devices_flag;
 | 
			
		||||
    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
 | 
			
		||||
    struct SoundIoDevicesInfo *ready_devices_info;
 | 
			
		||||
| 
						 | 
				
			
			@ -54,13 +57,13 @@ struct SoundIoOutStreamAlsa {
 | 
			
		|||
    char *sample_buffer;
 | 
			
		||||
    int poll_fd_count;
 | 
			
		||||
    struct pollfd *poll_fds;
 | 
			
		||||
    SoundIoOsThread *thread;
 | 
			
		||||
    struct SoundIoOsThread *thread;
 | 
			
		||||
    atomic_flag thread_exit_flag;
 | 
			
		||||
    int period_size;
 | 
			
		||||
    int write_frame_count;
 | 
			
		||||
    bool is_paused;
 | 
			
		||||
    atomic_flag clear_buffer_flag;
 | 
			
		||||
    SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
    struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SoundIoInStreamAlsa {
 | 
			
		||||
| 
						 | 
				
			
			@ -73,12 +76,12 @@ struct SoundIoInStreamAlsa {
 | 
			
		|||
    char *sample_buffer;
 | 
			
		||||
    int poll_fd_count;
 | 
			
		||||
    struct pollfd *poll_fds;
 | 
			
		||||
    SoundIoOsThread *thread;
 | 
			
		||||
    struct SoundIoOsThread *thread;
 | 
			
		||||
    atomic_flag thread_exit_flag;
 | 
			
		||||
    int period_size;
 | 
			
		||||
    int read_frame_count;
 | 
			
		||||
    bool is_paused;
 | 
			
		||||
    SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
    struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										33
									
								
								src/atomics.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/atomics.h
									
									
									
									
									
										Normal 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
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -5,7 +5,7 @@
 | 
			
		|||
 * See http://opensource.org/licenses/MIT
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "soundio.hpp"
 | 
			
		||||
#include "soundio_private.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -308,12 +308,12 @@ static struct SoundIoChannelLayout builtin_channel_layouts[] = {
 | 
			
		|||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const int channel_name_alias_count = 3;
 | 
			
		||||
static const char *channel_names[][channel_name_alias_count] = {
 | 
			
		||||
#define CHANNEL_NAME_ALIAS_COUNT 3
 | 
			
		||||
static const char *channel_names[][CHANNEL_NAME_ALIAS_COUNT] = {
 | 
			
		||||
    [SoundIoChannelIdInvalid] = {
 | 
			
		||||
        "(Invalid Channel)",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdFrontLeft] = {
 | 
			
		||||
        "Front Left",
 | 
			
		||||
| 
						 | 
				
			
			@ -407,258 +407,258 @@ static const char *channel_names[][channel_name_alias_count] = {
 | 
			
		|||
    },
 | 
			
		||||
    [SoundIoChannelIdBackLeftCenter] = {
 | 
			
		||||
        "Back Left Center",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdBackRightCenter] = {
 | 
			
		||||
        "Back Right Center",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdFrontLeftWide] = {
 | 
			
		||||
        "Front Left Wide",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdFrontRightWide] = {
 | 
			
		||||
        "Front Right Wide",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdFrontLeftHigh] = {
 | 
			
		||||
        "Front Left High",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdFrontCenterHigh] = {
 | 
			
		||||
        "Front Center High",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdFrontRightHigh] = {
 | 
			
		||||
        "Front Right High",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdTopFrontLeftCenter] = {
 | 
			
		||||
        "Top Front Left Center",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdTopFrontRightCenter] = {
 | 
			
		||||
        "Top Front Right Center",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdTopSideLeft] = {
 | 
			
		||||
        "Top Side Left",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdTopSideRight] = {
 | 
			
		||||
        "Top Side Right",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdLeftLfe] = {
 | 
			
		||||
        "Left LFE",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdRightLfe] = {
 | 
			
		||||
        "Right LFE",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdLfe2] = {
 | 
			
		||||
        "LFE 2",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdBottomCenter] = {
 | 
			
		||||
        "Bottom Center",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdBottomLeftCenter] = {
 | 
			
		||||
        "Bottom Left Center",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdBottomRightCenter] = {
 | 
			
		||||
        "Bottom Right Center",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdMsMid] = {
 | 
			
		||||
        "Mid/Side Mid",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdMsSide] = {
 | 
			
		||||
        "Mid/Side Side",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAmbisonicW] = {
 | 
			
		||||
        "Ambisonic W",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAmbisonicX] = {
 | 
			
		||||
        "Ambisonic X",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAmbisonicY] = {
 | 
			
		||||
        "Ambisonic Y",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAmbisonicZ] = {
 | 
			
		||||
        "Ambisonic Z",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdXyX] = {
 | 
			
		||||
        "X-Y X",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdXyY] = {
 | 
			
		||||
        "X-Y Y",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdHeadphonesLeft] = {
 | 
			
		||||
        "Headphones Left",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdHeadphonesRight] = {
 | 
			
		||||
        "Headphones Right",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdClickTrack] = {
 | 
			
		||||
        "Click Track",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdForeignLanguage] = {
 | 
			
		||||
        "Foreign Language",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdHearingImpaired] = {
 | 
			
		||||
        "Hearing Impaired",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdNarration] = {
 | 
			
		||||
        "Narration",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdHaptic] = {
 | 
			
		||||
        "Haptic",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdDialogCentricMix] = {
 | 
			
		||||
        "Dialog Centric Mix",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAux] = {
 | 
			
		||||
        "Aux",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAux0] = {
 | 
			
		||||
        "Aux 0",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAux1] = {
 | 
			
		||||
        "Aux 1",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAux2] = {
 | 
			
		||||
        "Aux 2",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAux3] = {
 | 
			
		||||
        "Aux 3",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAux4] = {
 | 
			
		||||
        "Aux 4",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAux5] = {
 | 
			
		||||
        "Aux 5",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAux6] = {
 | 
			
		||||
        "Aux 6",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAux7] = {
 | 
			
		||||
        "Aux 7",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAux8] = {
 | 
			
		||||
        "Aux 8",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAux9] = {
 | 
			
		||||
        "Aux 9",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAux10] = {
 | 
			
		||||
        "Aux 10",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAux11] = {
 | 
			
		||||
        "Aux 11",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAux12] = {
 | 
			
		||||
        "Aux 12",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAux13] = {
 | 
			
		||||
        "Aux 13",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAux14] = {
 | 
			
		||||
        "Aux 14",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
    [SoundIoChannelIdAux15] = {
 | 
			
		||||
        "Aux 15",
 | 
			
		||||
        nullptr,
 | 
			
		||||
        nullptr,
 | 
			
		||||
        NULL,
 | 
			
		||||
        NULL,
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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)";
 | 
			
		||||
    else
 | 
			
		||||
        return channel_names[id][0];
 | 
			
		||||
| 
						 | 
				
			
			@ -680,12 +680,12 @@ bool soundio_channel_layout_equal(
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
    assert(index >= 0);
 | 
			
		||||
    assert(index <= array_length(builtin_channel_layouts));
 | 
			
		||||
    assert(index <= ARRAY_LENGTH(builtin_channel_layouts));
 | 
			
		||||
    return &builtin_channel_layouts[index];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -700,14 +700,14 @@ int soundio_channel_layout_find_channel(
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
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];
 | 
			
		||||
        if (soundio_channel_layout_equal(builtin_layout, layout)) {
 | 
			
		||||
            layout->name = builtin_layout->name;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    layout->name = nullptr;
 | 
			
		||||
    layout->name = NULL;
 | 
			
		||||
    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 8: return soundio_channel_layout_get_builtin(SoundIoChannelLayoutId7Point1);
 | 
			
		||||
    }
 | 
			
		||||
    return nullptr;
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 i = 0; i < channel_name_alias_count; i += 1) {
 | 
			
		||||
    for (int id = 0; id < ARRAY_LENGTH(channel_names); id += 1) {
 | 
			
		||||
        for (int i = 0; i < CHANNEL_NAME_ALIAS_COUNT; i += 1) {
 | 
			
		||||
            const char *alias = channel_names[id][i];
 | 
			
		||||
            if (!alias)
 | 
			
		||||
                break;
 | 
			
		||||
            int alias_len = strlen(alias);
 | 
			
		||||
            if (soundio_streql(alias, alias_len, str, str_len))
 | 
			
		||||
                return (SoundIoChannelId)id;
 | 
			
		||||
                return (enum SoundIoChannelId)id;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return SoundIoChannelIdInvalid;
 | 
			
		||||
| 
						 | 
				
			
			@ -5,8 +5,8 @@
 | 
			
		|||
 * See http://opensource.org/licenses/MIT
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "coreaudio.hpp"
 | 
			
		||||
#include "soundio.hpp"
 | 
			
		||||
#include "coreaudio.h"
 | 
			
		||||
#include "soundio_private.h"
 | 
			
		||||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -91,19 +91,21 @@ static AudioObjectPropertyAddress device_listen_props[] = {
 | 
			
		|||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static SoundIoDeviceAim aims[] = {
 | 
			
		||||
static enum SoundIoDeviceAim aims[] = {
 | 
			
		||||
    SoundIoDeviceAimInput,
 | 
			
		||||
    SoundIoDeviceAimOutput,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
SOUNDIO_MAKE_LIST_DEF(AudioDeviceID, SoundIoListAudioDeviceID, SOUNDIO_LIST_STATIC)
 | 
			
		||||
 | 
			
		||||
static OSStatus on_devices_changed(AudioObjectID in_object_id, UInt32 in_number_addresses,
 | 
			
		||||
    const AudioObjectPropertyAddress in_addresses[], void *in_client_data)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate*)in_client_data;
 | 
			
		||||
    SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate*)in_client_data;
 | 
			
		||||
    struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
 | 
			
		||||
    sica->device_scan_queued.store(true);
 | 
			
		||||
    soundio_os_cond_signal(sica->scan_devices_cond, nullptr);
 | 
			
		||||
    SOUNDIO_ATOMIC_STORE(sica->device_scan_queued, true);
 | 
			
		||||
    soundio_os_cond_signal(sica->scan_devices_cond, NULL);
 | 
			
		||||
 | 
			
		||||
    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,
 | 
			
		||||
    const AudioObjectPropertyAddress in_addresses[], void *in_client_data)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate*)in_client_data;
 | 
			
		||||
    SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate*)in_client_data;
 | 
			
		||||
    struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
 | 
			
		||||
    sica->service_restarted.store(true);
 | 
			
		||||
    soundio_os_cond_signal(sica->scan_devices_cond, nullptr);
 | 
			
		||||
    SOUNDIO_ATOMIC_STORE(sica->service_restarted, true);
 | 
			
		||||
    soundio_os_cond_signal(sica->scan_devices_cond, NULL);
 | 
			
		||||
 | 
			
		||||
    return noErr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void unsubscribe_device_listeners(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
static void unsubscribe_device_listeners(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
 | 
			
		||||
    for (int device_index = 0; device_index < sica->registered_listeners.length; device_index += 1) {
 | 
			
		||||
        AudioDeviceID device_id = sica->registered_listeners.at(device_index);
 | 
			
		||||
        for (int i = 0; i < array_length(device_listen_props); i += 1) {
 | 
			
		||||
        AudioDeviceID device_id = SoundIoListAudioDeviceID_val_at(&sica->registered_listeners, device_index);
 | 
			
		||||
        for (int i = 0; i < ARRAY_LENGTH(device_listen_props); i += 1) {
 | 
			
		||||
            AudioObjectRemovePropertyListener(device_id, &device_listen_props[i],
 | 
			
		||||
                on_devices_changed, si);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    sica->registered_listeners.clear();
 | 
			
		||||
    SoundIoListAudioDeviceID_clear(&sica->registered_listeners);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void destroy_ca(struct SoundIoPrivate *si) {
 | 
			
		||||
    SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
 | 
			
		||||
    AudioObjectPropertyAddress prop_address = {
 | 
			
		||||
        kAudioHardwarePropertyDevices,
 | 
			
		||||
| 
						 | 
				
			
			@ -147,11 +149,11 @@ static void destroy_ca(struct SoundIoPrivate *si) {
 | 
			
		|||
    AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop_address, on_service_restarted, si);
 | 
			
		||||
 | 
			
		||||
    unsubscribe_device_listeners(si);
 | 
			
		||||
    sica->registered_listeners.deinit();
 | 
			
		||||
    SoundIoListAudioDeviceID_deinit(&sica->registered_listeners);
 | 
			
		||||
 | 
			
		||||
    if (sica->thread) {
 | 
			
		||||
        sica->abort_flag.clear();
 | 
			
		||||
        soundio_os_cond_signal(sica->scan_devices_cond, nullptr);
 | 
			
		||||
        atomic_flag_clear(&sica->abort_flag);
 | 
			
		||||
        soundio_os_cond_signal(sica->scan_devices_cond, NULL);
 | 
			
		||||
        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 max_size = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
 | 
			
		||||
    char *buf = allocate_nonzero<char>(max_size);
 | 
			
		||||
    char *buf = ALLOCATE_NONZERO(char, max_size);
 | 
			
		||||
    if (!buf)
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -192,12 +194,12 @@ static int from_cf_string(CFStringRef string_ref, char **out_str, int *out_str_l
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int aim_to_scope(SoundIoDeviceAim aim) {
 | 
			
		||||
static int aim_to_scope(enum SoundIoDeviceAim aim) {
 | 
			
		||||
    return (aim == SoundIoDeviceAimInput) ?
 | 
			
		||||
        kAudioObjectPropertyScopeInput : kAudioObjectPropertyScopeOutput;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SoundIoChannelId from_channel_descr(const AudioChannelDescription *descr) {
 | 
			
		||||
static enum SoundIoChannelId from_channel_descr(const AudioChannelDescription *descr) {
 | 
			
		||||
    switch (descr->mChannelLabel) {
 | 
			
		||||
        default:                                        return SoundIoChannelIdInvalid;
 | 
			
		||||
        case kAudioChannelLabel_Left:                   return SoundIoChannelIdFrontLeft;
 | 
			
		||||
| 
						 | 
				
			
			@ -274,7 +276,7 @@ static SoundIoChannelId from_channel_descr(const AudioChannelDescription *descr)
 | 
			
		|||
// * SoundIoErrorIncompatibleDevice
 | 
			
		||||
// This does not handle all the possible layout enum values and it does not
 | 
			
		||||
// 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) {
 | 
			
		||||
    case kAudioChannelLayoutTag_UseChannelDescriptions:
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -377,15 +379,15 @@ static bool all_channels_invalid(const struct SoundIoChannelLayout *layout) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
struct RefreshDevices {
 | 
			
		||||
    SoundIoPrivate *si;
 | 
			
		||||
    SoundIoDevicesInfo *devices_info;
 | 
			
		||||
    struct SoundIoPrivate *si;
 | 
			
		||||
    struct SoundIoDevicesInfo *devices_info;
 | 
			
		||||
    int devices_size;
 | 
			
		||||
    AudioObjectID *devices;
 | 
			
		||||
    CFStringRef string_ref;
 | 
			
		||||
    char *device_name;
 | 
			
		||||
    int device_name_len;
 | 
			
		||||
    AudioBufferList *buffer_list;
 | 
			
		||||
    SoundIoDevice *device;
 | 
			
		||||
    struct SoundIoDevice *device;
 | 
			
		||||
    AudioChannelLayout *audio_channel_layout;
 | 
			
		||||
    char *device_uid;
 | 
			
		||||
    int device_uid_len;
 | 
			
		||||
| 
						 | 
				
			
			@ -393,7 +395,7 @@ struct RefreshDevices {
 | 
			
		|||
    bool ok;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void deinit_refresh_devices(RefreshDevices *rd) {
 | 
			
		||||
static void deinit_refresh_devices(struct RefreshDevices *rd) {
 | 
			
		||||
    if (!rd->ok)
 | 
			
		||||
        unsubscribe_device_listeners(rd->si);
 | 
			
		||||
    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) {
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
 | 
			
		||||
    UInt32 io_size;
 | 
			
		||||
    OSStatus os_err;
 | 
			
		||||
| 
						 | 
				
			
			@ -418,10 +420,10 @@ static int refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		|||
 | 
			
		||||
    unsubscribe_device_listeners(si);
 | 
			
		||||
 | 
			
		||||
    RefreshDevices rd = {0};
 | 
			
		||||
    struct RefreshDevices rd = {0};
 | 
			
		||||
    rd.si = si;
 | 
			
		||||
 | 
			
		||||
    if (!(rd.devices_info = allocate<SoundIoDevicesInfo>(1))) {
 | 
			
		||||
    if (!(rd.devices_info = ALLOCATE(struct SoundIoDevicesInfo, 1))) {
 | 
			
		||||
        deinit_refresh_devices(&rd);
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -433,7 +435,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		|||
    };
 | 
			
		||||
 | 
			
		||||
    if ((os_err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
 | 
			
		||||
        &prop_address, 0, nullptr, &io_size)))
 | 
			
		||||
        &prop_address, 0, NULL, &io_size)))
 | 
			
		||||
    {
 | 
			
		||||
        deinit_refresh_devices(&rd);
 | 
			
		||||
        return SoundIoErrorOpeningDevice;
 | 
			
		||||
| 
						 | 
				
			
			@ -445,13 +447,13 @@ static int refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		|||
    int device_count = io_size / (UInt32)sizeof(AudioObjectID);
 | 
			
		||||
    if (device_count >= 1) {
 | 
			
		||||
        rd.devices_size = io_size;
 | 
			
		||||
        rd.devices = (AudioObjectID *)allocate<char>(rd.devices_size);
 | 
			
		||||
        rd.devices = (AudioObjectID *)ALLOCATE(char, rd.devices_size);
 | 
			
		||||
        if (!rd.devices) {
 | 
			
		||||
            deinit_refresh_devices(&rd);
 | 
			
		||||
            return SoundIoErrorNoMem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((os_err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_address, 0, nullptr,
 | 
			
		||||
        if ((os_err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_address, 0, NULL,
 | 
			
		||||
            &io_size, rd.devices)))
 | 
			
		||||
        {
 | 
			
		||||
            deinit_refresh_devices(&rd);
 | 
			
		||||
| 
						 | 
				
			
			@ -462,7 +464,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		|||
        io_size = sizeof(AudioObjectID);
 | 
			
		||||
        prop_address.mSelector = kAudioHardwarePropertyDefaultInputDevice;
 | 
			
		||||
        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);
 | 
			
		||||
            return SoundIoErrorOpeningDevice;
 | 
			
		||||
| 
						 | 
				
			
			@ -471,7 +473,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		|||
        io_size = sizeof(AudioObjectID);
 | 
			
		||||
        prop_address.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
 | 
			
		||||
        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);
 | 
			
		||||
            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) {
 | 
			
		||||
        AudioObjectID device_id = rd.devices[device_i];
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < array_length(device_listen_props); i += 1) {
 | 
			
		||||
            if ((err = sica->registered_listeners.add_one())) {
 | 
			
		||||
        for (int i = 0; i < ARRAY_LENGTH(device_listen_props); i += 1) {
 | 
			
		||||
            if ((err = SoundIoListAudioDeviceID_add_one(&sica->registered_listeners))) {
 | 
			
		||||
                deinit_refresh_devices(&rd);
 | 
			
		||||
                return SoundIoErrorOpeningDevice;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -492,7 +494,8 @@ static int refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		|||
                deinit_refresh_devices(&rd);
 | 
			
		||||
                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;
 | 
			
		||||
| 
						 | 
				
			
			@ -501,17 +504,17 @@ static int refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		|||
        io_size = sizeof(CFStringRef);
 | 
			
		||||
        if (rd.string_ref) {
 | 
			
		||||
            CFRelease(rd.string_ref);
 | 
			
		||||
            rd.string_ref = nullptr;
 | 
			
		||||
            rd.string_ref = NULL;
 | 
			
		||||
        }
 | 
			
		||||
        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);
 | 
			
		||||
            return SoundIoErrorOpeningDevice;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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))) {
 | 
			
		||||
            deinit_refresh_devices(&rd);
 | 
			
		||||
            return err;
 | 
			
		||||
| 
						 | 
				
			
			@ -523,43 +526,43 @@ static int refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		|||
        io_size = sizeof(CFStringRef);
 | 
			
		||||
        if (rd.string_ref) {
 | 
			
		||||
            CFRelease(rd.string_ref);
 | 
			
		||||
            rd.string_ref = nullptr;
 | 
			
		||||
            rd.string_ref = NULL;
 | 
			
		||||
        }
 | 
			
		||||
        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);
 | 
			
		||||
            return SoundIoErrorOpeningDevice;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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))) {
 | 
			
		||||
            deinit_refresh_devices(&rd);
 | 
			
		||||
            return err;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        for (int aim_i = 0; aim_i < array_length(aims); aim_i += 1) {
 | 
			
		||||
            SoundIoDeviceAim aim = aims[aim_i];
 | 
			
		||||
        for (int aim_i = 0; aim_i < ARRAY_LENGTH(aims); aim_i += 1) {
 | 
			
		||||
            enum SoundIoDeviceAim aim = aims[aim_i];
 | 
			
		||||
 | 
			
		||||
            io_size = 0;
 | 
			
		||||
            prop_address.mSelector = kAudioDevicePropertyStreamConfiguration;
 | 
			
		||||
            prop_address.mScope = aim_to_scope(aim);
 | 
			
		||||
            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);
 | 
			
		||||
                return SoundIoErrorOpeningDevice;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            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) {
 | 
			
		||||
                deinit_refresh_devices(&rd);
 | 
			
		||||
                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)))
 | 
			
		||||
            {
 | 
			
		||||
                deinit_refresh_devices(&rd);
 | 
			
		||||
| 
						 | 
				
			
			@ -574,12 +577,12 @@ static int refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		|||
            if (channel_count <= 0)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1);
 | 
			
		||||
            struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
 | 
			
		||||
            if (!dev) {
 | 
			
		||||
                deinit_refresh_devices(&rd);
 | 
			
		||||
                return SoundIoErrorNoMem;
 | 
			
		||||
            }
 | 
			
		||||
            SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
 | 
			
		||||
            struct SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
 | 
			
		||||
            dca->device_id = device_id;
 | 
			
		||||
            assert(!rd.device);
 | 
			
		||||
            rd.device = &dev->pub;
 | 
			
		||||
| 
						 | 
				
			
			@ -599,14 +602,14 @@ static int refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		|||
            prop_address.mScope = aim_to_scope(aim);
 | 
			
		||||
            prop_address.mElement = kAudioObjectPropertyElementMaster;
 | 
			
		||||
            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) {
 | 
			
		||||
                    deinit_refresh_devices(&rd);
 | 
			
		||||
                    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)))
 | 
			
		||||
                {
 | 
			
		||||
                    deinit_refresh_devices(&rd);
 | 
			
		||||
| 
						 | 
				
			
			@ -635,7 +638,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		|||
            prop_address.mElement = kAudioObjectPropertyElementMaster;
 | 
			
		||||
            io_size = sizeof(double);
 | 
			
		||||
            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)))
 | 
			
		||||
            {
 | 
			
		||||
                deinit_refresh_devices(&rd);
 | 
			
		||||
| 
						 | 
				
			
			@ -659,21 +662,21 @@ static int refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		|||
                prop_address.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
 | 
			
		||||
                prop_address.mScope = aim_to_scope(aim);
 | 
			
		||||
                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)))
 | 
			
		||||
                {
 | 
			
		||||
                    deinit_refresh_devices(&rd);
 | 
			
		||||
                    return SoundIoErrorOpeningDevice;
 | 
			
		||||
                }
 | 
			
		||||
                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) {
 | 
			
		||||
                    deinit_refresh_devices(&rd);
 | 
			
		||||
                    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)))
 | 
			
		||||
                {
 | 
			
		||||
                    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);
 | 
			
		||||
                } else {
 | 
			
		||||
                    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) {
 | 
			
		||||
                        deinit_refresh_devices(&rd);
 | 
			
		||||
                        return SoundIoErrorNoMem;
 | 
			
		||||
| 
						 | 
				
			
			@ -707,7 +710,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		|||
            prop_address.mElement = kAudioObjectPropertyElementMaster;
 | 
			
		||||
            io_size = sizeof(UInt32);
 | 
			
		||||
            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)))
 | 
			
		||||
            {
 | 
			
		||||
                deinit_refresh_devices(&rd);
 | 
			
		||||
| 
						 | 
				
			
			@ -721,7 +724,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		|||
            prop_address.mElement = kAudioObjectPropertyElementMaster;
 | 
			
		||||
            io_size = sizeof(AudioValueRange);
 | 
			
		||||
            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)))
 | 
			
		||||
            {
 | 
			
		||||
                deinit_refresh_devices(&rd);
 | 
			
		||||
| 
						 | 
				
			
			@ -734,14 +737,14 @@ static int refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		|||
            prop_address.mScope = aim_to_scope(aim);
 | 
			
		||||
            prop_address.mElement = kAudioObjectPropertyElementMaster;
 | 
			
		||||
            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)))
 | 
			
		||||
            {
 | 
			
		||||
                deinit_refresh_devices(&rd);
 | 
			
		||||
                return SoundIoErrorOpeningDevice;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SoundIoList<SoundIoDevice *> *device_list;
 | 
			
		||||
            struct SoundIoListDevicePtr *device_list;
 | 
			
		||||
            if (rd.device->aim == SoundIoDeviceAimOutput) {
 | 
			
		||||
                device_list = &rd.devices_info->output_devices;
 | 
			
		||||
                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;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ((err = device_list->append(rd.device))) {
 | 
			
		||||
            if ((err = SoundIoListDevicePtr_append(device_list, rd.device))) {
 | 
			
		||||
                deinit_refresh_devices(&rd);
 | 
			
		||||
                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;
 | 
			
		||||
    soundio_os_mutex_unlock(sica->mutex);
 | 
			
		||||
 | 
			
		||||
    rd.devices_info = nullptr;
 | 
			
		||||
    rd.devices_info = NULL;
 | 
			
		||||
    rd.ok = true;
 | 
			
		||||
    deinit_refresh_devices(&rd);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void shutdown_backend(SoundIoPrivate *si, int err) {
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
static void shutdown_backend(struct SoundIoPrivate *si, int err) {
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
    soundio_os_mutex_lock(sica->mutex);
 | 
			
		||||
    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_cond_signal(sica->cond, nullptr);
 | 
			
		||||
    soundio_os_cond_signal(sica->have_devices_cond, nullptr);
 | 
			
		||||
    soundio_os_cond_signal(sica->cond, NULL);
 | 
			
		||||
    soundio_os_cond_signal(sica->have_devices_cond, NULL);
 | 
			
		||||
    soundio->on_events_signal(soundio);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void flush_events_ca(struct SoundIoPrivate *si) {
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
 | 
			
		||||
    // block until have devices
 | 
			
		||||
    while (!sica->have_devices_flag.load())
 | 
			
		||||
        soundio_os_cond_wait(sica->have_devices_cond, nullptr);
 | 
			
		||||
    while (!SOUNDIO_ATOMIC_LOAD(sica->have_devices_flag))
 | 
			
		||||
        soundio_os_cond_wait(sica->have_devices_cond, NULL);
 | 
			
		||||
 | 
			
		||||
    bool change = false;
 | 
			
		||||
    bool cb_shutdown = false;
 | 
			
		||||
    SoundIoDevicesInfo *old_devices_info = nullptr;
 | 
			
		||||
    struct SoundIoDevicesInfo *old_devices_info = NULL;
 | 
			
		||||
 | 
			
		||||
    soundio_os_mutex_lock(sica->mutex);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -805,7 +808,7 @@ static void flush_events_ca(struct SoundIoPrivate *si) {
 | 
			
		|||
    } else if (sica->ready_devices_info) {
 | 
			
		||||
        old_devices_info = si->safe_devices_info;
 | 
			
		||||
        si->safe_devices_info = sica->ready_devices_info;
 | 
			
		||||
        sica->ready_devices_info = nullptr;
 | 
			
		||||
        sica->ready_devices_info = NULL;
 | 
			
		||||
        change = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -820,65 +823,65 @@ static void flush_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);
 | 
			
		||||
    soundio_os_cond_wait(sica->cond, nullptr);
 | 
			
		||||
    soundio_os_cond_wait(sica->cond, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void wakeup_ca(struct SoundIoPrivate *si) {
 | 
			
		||||
    SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
    soundio_os_cond_signal(sica->cond, nullptr);
 | 
			
		||||
    struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
    soundio_os_cond_signal(sica->cond, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void force_device_scan_ca(struct SoundIoPrivate *si) {
 | 
			
		||||
    SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
    sica->device_scan_queued.store(true);
 | 
			
		||||
    soundio_os_cond_signal(sica->scan_devices_cond, nullptr);
 | 
			
		||||
    struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
    SOUNDIO_ATOMIC_STORE(sica->device_scan_queued, true);
 | 
			
		||||
    soundio_os_cond_signal(sica->scan_devices_cond, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void device_thread_run(void *arg) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)arg;
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
    int err;
 | 
			
		||||
 | 
			
		||||
    for (;;) {
 | 
			
		||||
        if (!sica->abort_flag.test_and_set())
 | 
			
		||||
        if (!atomic_flag_test_and_set(&sica->abort_flag))
 | 
			
		||||
            break;
 | 
			
		||||
        if (sica->service_restarted.load()) {
 | 
			
		||||
        if (SOUNDIO_ATOMIC_LOAD(sica->service_restarted)) {
 | 
			
		||||
            shutdown_backend(si, SoundIoErrorBackendDisconnected);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (sica->device_scan_queued.exchange(false)) {
 | 
			
		||||
        if (SOUNDIO_ATOMIC_EXCHANGE(sica->device_scan_queued, false)) {
 | 
			
		||||
            err = refresh_devices(si);
 | 
			
		||||
            if (err) {
 | 
			
		||||
                shutdown_backend(si, err);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            if (!sica->have_devices_flag.exchange(true))
 | 
			
		||||
                soundio_os_cond_signal(sica->have_devices_cond, nullptr);
 | 
			
		||||
            soundio_os_cond_signal(sica->cond, nullptr);
 | 
			
		||||
            if (!SOUNDIO_ATOMIC_EXCHANGE(sica->have_devices_flag, true))
 | 
			
		||||
                soundio_os_cond_signal(sica->have_devices_cond, NULL);
 | 
			
		||||
            soundio_os_cond_signal(sica->cond, NULL);
 | 
			
		||||
            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,
 | 
			
		||||
    const AudioObjectPropertyAddress in_addresses[], void *in_client_data)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)in_client_data;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)in_client_data;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    outstream->underflow_callback(outstream);
 | 
			
		||||
    return noErr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void outstream_destroy_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    SoundIoDevice *device = outstream->device;
 | 
			
		||||
    SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
 | 
			
		||||
    SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoDevice *device = outstream->device;
 | 
			
		||||
    struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
 | 
			
		||||
    struct SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
 | 
			
		||||
 | 
			
		||||
    AudioObjectPropertyAddress prop_address = {
 | 
			
		||||
        kAudioDeviceProcessorOverload,
 | 
			
		||||
| 
						 | 
				
			
			@ -890,7 +893,7 @@ static void outstream_destroy_ca(struct SoundIoPrivate *si, struct SoundIoOutStr
 | 
			
		|||
    if (osca->instance) {
 | 
			
		||||
        AudioOutputUnitStop(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,
 | 
			
		||||
    AudioBufferList *io_data)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *) userdata;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *) userdata;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
 | 
			
		||||
 | 
			
		||||
    osca->io_data = io_data;
 | 
			
		||||
    osca->buffer_index = 0;
 | 
			
		||||
    osca->frames_left = in_number_frames;
 | 
			
		||||
    outstream->write_callback(outstream, osca->frames_left, osca->frames_left);
 | 
			
		||||
    osca->io_data = nullptr;
 | 
			
		||||
    osca->io_data = NULL;
 | 
			
		||||
 | 
			
		||||
    return noErr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_open_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    SoundIoDevice *device = outstream->device;
 | 
			
		||||
    SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
 | 
			
		||||
    SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoDevice *device = outstream->device;
 | 
			
		||||
    struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
 | 
			
		||||
    struct SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
 | 
			
		||||
 | 
			
		||||
    if (outstream->software_latency == 0.0)
 | 
			
		||||
        outstream->software_latency = device->software_latency_current;
 | 
			
		||||
 | 
			
		||||
    outstream->software_latency = clamp(
 | 
			
		||||
    outstream->software_latency = soundio_double_clamp(
 | 
			
		||||
            device->software_latency_min,
 | 
			
		||||
            outstream->software_latency,
 | 
			
		||||
            device->software_latency_max);
 | 
			
		||||
| 
						 | 
				
			
			@ -931,7 +934,7 @@ static int outstream_open_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamP
 | 
			
		|||
    desc.componentSubType = kAudioUnitSubType_HALOutput;
 | 
			
		||||
    desc.componentManufacturer = kAudioUnitManufacturer_Apple;
 | 
			
		||||
 | 
			
		||||
    AudioComponent component = AudioComponentFindNext(nullptr, &desc);
 | 
			
		||||
    AudioComponent component = AudioComponentFindNext(NULL, &desc);
 | 
			
		||||
    if (!component) {
 | 
			
		||||
        outstream_destroy_ca(si, os);
 | 
			
		||||
        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;
 | 
			
		||||
    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);
 | 
			
		||||
        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) {
 | 
			
		||||
    SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
 | 
			
		||||
    OSStatus os_err;
 | 
			
		||||
    if (pause) {
 | 
			
		||||
        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,
 | 
			
		||||
        SoundIoChannelArea **out_areas, int *frame_count)
 | 
			
		||||
        struct SoundIoChannelArea **out_areas, int *frame_count)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
 | 
			
		||||
 | 
			
		||||
    if (osca->buffer_index >= osca->io_data->mNumberBuffers)
 | 
			
		||||
        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) {
 | 
			
		||||
    SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
 | 
			
		||||
    osca->buffer_index += 1;
 | 
			
		||||
    osca->frames_left -= osca->write_frame_count;
 | 
			
		||||
    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,
 | 
			
		||||
        double *out_latency)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
 | 
			
		||||
    *out_latency = osca->hardware_latency;
 | 
			
		||||
    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,
 | 
			
		||||
    const AudioObjectPropertyAddress in_addresses[], void *in_client_data)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoInStreamPrivate *os = (SoundIoInStreamPrivate *)in_client_data;
 | 
			
		||||
    SoundIoInStream *instream = &os->pub;
 | 
			
		||||
    struct SoundIoInStreamPrivate *os = (struct SoundIoInStreamPrivate *)in_client_data;
 | 
			
		||||
    struct SoundIoInStream *instream = &os->pub;
 | 
			
		||||
    instream->overflow_callback(instream);
 | 
			
		||||
    return noErr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void instream_destroy_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
 | 
			
		||||
    SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    SoundIoDevice *device = instream->device;
 | 
			
		||||
    SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
 | 
			
		||||
    SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoDevice *device = instream->device;
 | 
			
		||||
    struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
 | 
			
		||||
    struct SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
 | 
			
		||||
 | 
			
		||||
    AudioObjectPropertyAddress prop_address = {
 | 
			
		||||
        kAudioDeviceProcessorOverload,
 | 
			
		||||
| 
						 | 
				
			
			@ -1099,23 +1102,23 @@ static void instream_destroy_ca(struct SoundIoPrivate *si, struct SoundIoInStrea
 | 
			
		|||
    if (isca->instance) {
 | 
			
		||||
        AudioOutputUnitStop(isca->instance);
 | 
			
		||||
        AudioComponentInstanceDispose(isca->instance);
 | 
			
		||||
        isca->instance = nullptr;
 | 
			
		||||
        isca->instance = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    free(isca->buffer_list);
 | 
			
		||||
    isca->buffer_list = nullptr;
 | 
			
		||||
    isca->buffer_list = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static OSStatus read_callback_ca(void *userdata, AudioUnitRenderActionFlags *io_action_flags,
 | 
			
		||||
    const AudioTimeStamp *in_time_stamp, UInt32 in_bus_number, UInt32 in_number_frames,
 | 
			
		||||
    AudioBufferList *io_data)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *) userdata;
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *) userdata;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
| 
						 | 
				
			
			@ -1151,18 +1154,18 @@ static OSStatus read_callback_ca(void *userdata, AudioUnitRenderActionFlags *io_
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
 | 
			
		||||
    SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    SoundIoDevice *device = instream->device;
 | 
			
		||||
    SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
 | 
			
		||||
    SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoDevice *device = instream->device;
 | 
			
		||||
    struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
 | 
			
		||||
    struct SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
 | 
			
		||||
    UInt32 io_size;
 | 
			
		||||
    OSStatus os_err;
 | 
			
		||||
 | 
			
		||||
    if (instream->software_latency == 0.0)
 | 
			
		||||
        instream->software_latency = device->software_latency_current;
 | 
			
		||||
 | 
			
		||||
    instream->software_latency = clamp(
 | 
			
		||||
    instream->software_latency = soundio_double_clamp(
 | 
			
		||||
            device->software_latency_min,
 | 
			
		||||
            instream->software_latency,
 | 
			
		||||
            device->software_latency_max);
 | 
			
		||||
| 
						 | 
				
			
			@ -1174,20 +1177,20 @@ static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPri
 | 
			
		|||
    prop_address.mElement = kAudioObjectPropertyElementMaster;
 | 
			
		||||
    io_size = 0;
 | 
			
		||||
    if ((os_err = AudioObjectGetPropertyDataSize(dca->device_id, &prop_address,
 | 
			
		||||
        0, nullptr, &io_size)))
 | 
			
		||||
        0, NULL, &io_size)))
 | 
			
		||||
    {
 | 
			
		||||
        instream_destroy_ca(si, is);
 | 
			
		||||
        return SoundIoErrorOpeningDevice;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    isca->buffer_list = (AudioBufferList*)allocate_nonzero<char>(io_size);
 | 
			
		||||
    isca->buffer_list = (AudioBufferList*)ALLOCATE_NONZERO(char, io_size);
 | 
			
		||||
    if (!isca->buffer_list) {
 | 
			
		||||
        instream_destroy_ca(si, is);
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
        return SoundIoErrorOpeningDevice;
 | 
			
		||||
| 
						 | 
				
			
			@ -1199,7 +1202,7 @@ static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPri
 | 
			
		|||
    desc.componentSubType = kAudioUnitSubType_HALOutput;
 | 
			
		||||
    desc.componentManufacturer = kAudioUnitManufacturer_Apple;
 | 
			
		||||
 | 
			
		||||
    AudioComponent component = AudioComponentFindNext(nullptr, &desc);
 | 
			
		||||
    AudioComponent component = AudioComponentFindNext(NULL, &desc);
 | 
			
		||||
    if (!component) {
 | 
			
		||||
        instream_destroy_ca(si, is);
 | 
			
		||||
        return SoundIoErrorOpeningDevice;
 | 
			
		||||
| 
						 | 
				
			
			@ -1270,7 +1273,7 @@ static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPri
 | 
			
		|||
    prop_address.mElement = INPUT_ELEMENT;
 | 
			
		||||
    UInt32 buffer_frame_size = instream->software_latency * instream->sample_rate;
 | 
			
		||||
    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);
 | 
			
		||||
        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) {
 | 
			
		||||
    SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
 | 
			
		||||
    OSStatus os_err;
 | 
			
		||||
    if (pause) {
 | 
			
		||||
        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,
 | 
			
		||||
        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)
 | 
			
		||||
        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) {
 | 
			
		||||
    SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
 | 
			
		||||
    isca->frames_left = 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,
 | 
			
		||||
        double *out_latency)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
 | 
			
		||||
    struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
 | 
			
		||||
    *out_latency = isca->hardware_latency;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int soundio_coreaudio_init(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
int soundio_coreaudio_init(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
 | 
			
		||||
    int err;
 | 
			
		||||
 | 
			
		||||
    sica->have_devices_flag.store(false);
 | 
			
		||||
    sica->device_scan_queued.store(true);
 | 
			
		||||
    sica->service_restarted.store(false);
 | 
			
		||||
    sica->abort_flag.test_and_set();
 | 
			
		||||
    SOUNDIO_ATOMIC_STORE(sica->have_devices_flag, false);
 | 
			
		||||
    SOUNDIO_ATOMIC_STORE(sica->device_scan_queued, true);
 | 
			
		||||
    SOUNDIO_ATOMIC_STORE(sica->service_restarted, false);
 | 
			
		||||
    atomic_flag_test_and_set(&sica->abort_flag);
 | 
			
		||||
 | 
			
		||||
    sica->mutex = soundio_os_mutex_create();
 | 
			
		||||
    if (!sica->mutex) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1391,7 +1394,7 @@ int soundio_coreaudio_init(SoundIoPrivate *si) {
 | 
			
		|||
        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);
 | 
			
		||||
        return err;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -5,17 +5,18 @@
 | 
			
		|||
 * See http://opensource.org/licenses/MIT
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef SOUNDIO_COREAUDIO_HPP
 | 
			
		||||
#define SOUNDIO_COREAUDIO_HPP
 | 
			
		||||
#ifndef SOUNDIO_COREAUDIO_H
 | 
			
		||||
#define SOUNDIO_COREAUDIO_H
 | 
			
		||||
 | 
			
		||||
#include "soundio_private.h"
 | 
			
		||||
#include "soundio_internal.h"
 | 
			
		||||
#include "os.h"
 | 
			
		||||
#include "atomics.hpp"
 | 
			
		||||
#include "list.hpp"
 | 
			
		||||
#include "list.h"
 | 
			
		||||
#include "atomics.h"
 | 
			
		||||
 | 
			
		||||
#include <CoreAudio/CoreAudio.h>
 | 
			
		||||
#include <AudioUnit/AudioUnit.h>
 | 
			
		||||
 | 
			
		||||
struct SoundIoPrivate;
 | 
			
		||||
int soundio_coreaudio_init(struct SoundIoPrivate *si);
 | 
			
		||||
 | 
			
		||||
struct SoundIoDeviceCoreAudio {
 | 
			
		||||
| 
						 | 
				
			
			@ -23,21 +24,23 @@ struct SoundIoDeviceCoreAudio {
 | 
			
		|||
    UInt32 latency_frames;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
SOUNDIO_MAKE_LIST_STRUCT(AudioDeviceID, SoundIoListAudioDeviceID, SOUNDIO_LIST_STATIC)
 | 
			
		||||
 | 
			
		||||
struct SoundIoCoreAudio {
 | 
			
		||||
    SoundIoOsMutex *mutex;
 | 
			
		||||
    SoundIoOsCond *cond;
 | 
			
		||||
    struct SoundIoOsMutex *mutex;
 | 
			
		||||
    struct SoundIoOsCond *cond;
 | 
			
		||||
    struct SoundIoOsThread *thread;
 | 
			
		||||
    atomic_flag abort_flag;
 | 
			
		||||
 | 
			
		||||
    // this one is ready to be read with flush_events. protected by mutex
 | 
			
		||||
    struct SoundIoDevicesInfo *ready_devices_info;
 | 
			
		||||
    atomic_bool have_devices_flag;
 | 
			
		||||
    SoundIoOsCond *have_devices_cond;
 | 
			
		||||
    SoundIoOsCond *scan_devices_cond;
 | 
			
		||||
    SoundIoList<AudioDeviceID> registered_listeners;
 | 
			
		||||
    struct SoundIoAtomicBool have_devices_flag;
 | 
			
		||||
    struct SoundIoOsCond *have_devices_cond;
 | 
			
		||||
    struct SoundIoOsCond *scan_devices_cond;
 | 
			
		||||
    struct SoundIoListAudioDeviceID registered_listeners;
 | 
			
		||||
 | 
			
		||||
    atomic_bool device_scan_queued;
 | 
			
		||||
    atomic_bool service_restarted;
 | 
			
		||||
    struct SoundIoAtomicBool device_scan_queued;
 | 
			
		||||
    struct SoundIoAtomicBool service_restarted;
 | 
			
		||||
    int shutdown_err;
 | 
			
		||||
    bool emitted_shutdown_cb;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +52,7 @@ struct SoundIoOutStreamCoreAudio {
 | 
			
		|||
    int frames_left;
 | 
			
		||||
    int write_frame_count;
 | 
			
		||||
    double hardware_latency;
 | 
			
		||||
    SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
    struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SoundIoInStreamCoreAudio {
 | 
			
		||||
| 
						 | 
				
			
			@ -57,7 +60,7 @@ struct SoundIoInStreamCoreAudio {
 | 
			
		|||
    AudioBufferList *buffer_list;
 | 
			
		||||
    int frames_left;
 | 
			
		||||
    double hardware_latency;
 | 
			
		||||
    SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
    struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -5,16 +5,16 @@
 | 
			
		|||
 * See http://opensource.org/licenses/MIT
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "dummy.hpp"
 | 
			
		||||
#include "soundio.hpp"
 | 
			
		||||
#include "dummy.h"
 | 
			
		||||
#include "soundio_private.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
static void playback_thread_run(void *arg) {
 | 
			
		||||
    SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
 | 
			
		||||
 | 
			
		||||
    int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer);
 | 
			
		||||
    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();
 | 
			
		||||
    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 time_passed = now - start_time;
 | 
			
		||||
        double next_period = start_time +
 | 
			
		||||
            ceil_dbl(time_passed / osd->period_duration) * osd->period_duration;
 | 
			
		||||
        double relative_time = next_period - now;
 | 
			
		||||
        soundio_os_cond_timed_wait(osd->cond, nullptr, relative_time);
 | 
			
		||||
        if (!osd->clear_buffer_flag.test_and_set()) {
 | 
			
		||||
        soundio_os_cond_timed_wait(osd->cond, NULL, relative_time);
 | 
			
		||||
        if (!atomic_flag_test_and_set(&osd->clear_buffer_flag)) {
 | 
			
		||||
            soundio_ring_buffer_clear(&osd->ring_buffer);
 | 
			
		||||
            int free_bytes = soundio_ring_buffer_capacity(&osd->ring_buffer);
 | 
			
		||||
            int free_frames = free_bytes / outstream->bytes_per_frame;
 | 
			
		||||
| 
						 | 
				
			
			@ -44,7 +44,7 @@ static void playback_thread_run(void *arg) {
 | 
			
		|||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (osd->pause_requested.load()) {
 | 
			
		||||
        if (SOUNDIO_ATOMIC_LOAD(osd->pause_requested)) {
 | 
			
		||||
            start_time = now;
 | 
			
		||||
            frames_consumed = 0;
 | 
			
		||||
            continue;
 | 
			
		||||
| 
						 | 
				
			
			@ -58,7 +58,7 @@ static void playback_thread_run(void *arg) {
 | 
			
		|||
        double total_time = soundio_os_get_time() - start_time;
 | 
			
		||||
        long total_frames = total_time * outstream->sample_rate;
 | 
			
		||||
        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;
 | 
			
		||||
        soundio_ring_buffer_advance_read_ptr(&osd->ring_buffer, byte_count);
 | 
			
		||||
        frames_consumed += read_count;
 | 
			
		||||
| 
						 | 
				
			
			@ -78,21 +78,21 @@ static void playback_thread_run(void *arg) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static void capture_thread_run(void *arg) {
 | 
			
		||||
    SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    SoundIoInStreamDummy *isd = &is->backend_data.dummy;
 | 
			
		||||
    struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
 | 
			
		||||
 | 
			
		||||
    long frames_consumed = 0;
 | 
			
		||||
    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 time_passed = now - start_time;
 | 
			
		||||
        double next_period = start_time +
 | 
			
		||||
            ceil_dbl(time_passed / isd->period_duration) * isd->period_duration;
 | 
			
		||||
        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;
 | 
			
		||||
            frames_consumed = 0;
 | 
			
		||||
            continue;
 | 
			
		||||
| 
						 | 
				
			
			@ -106,7 +106,7 @@ static void capture_thread_run(void *arg) {
 | 
			
		|||
        double total_time = soundio_os_get_time() - start_time;
 | 
			
		||||
        long total_frames = total_time * instream->sample_rate;
 | 
			
		||||
        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;
 | 
			
		||||
        soundio_ring_buffer_advance_write_ptr(&isd->ring_buffer, byte_count);
 | 
			
		||||
        frames_consumed += write_count;
 | 
			
		||||
| 
						 | 
				
			
			@ -123,8 +123,8 @@ static void capture_thread_run(void *arg) {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void destroy_dummy(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIoDummy *sid = &si->backend_data.dummy;
 | 
			
		||||
static void destroy_dummy(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIoDummy *sid = &si->backend_data.dummy;
 | 
			
		||||
 | 
			
		||||
    if (sid->cond)
 | 
			
		||||
        soundio_os_cond_destroy(sid->cond);
 | 
			
		||||
| 
						 | 
				
			
			@ -133,55 +133,57 @@ static void destroy_dummy(SoundIoPrivate *si) {
 | 
			
		|||
        soundio_os_mutex_destroy(sid->mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void flush_events_dummy(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoDummy *sid = &si->backend_data.dummy;
 | 
			
		||||
static void flush_events_dummy(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoDummy *sid = &si->backend_data.dummy;
 | 
			
		||||
    if (sid->devices_emitted)
 | 
			
		||||
        return;
 | 
			
		||||
    sid->devices_emitted = true;
 | 
			
		||||
    soundio->on_devices_change(soundio);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void wait_events_dummy(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIoDummy *sid = &si->backend_data.dummy;
 | 
			
		||||
static void wait_events_dummy(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIoDummy *sid = &si->backend_data.dummy;
 | 
			
		||||
    flush_events_dummy(si);
 | 
			
		||||
    soundio_os_cond_wait(sid->cond, nullptr);
 | 
			
		||||
    soundio_os_cond_wait(sid->cond, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void wakeup_dummy(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIoDummy *sid = &si->backend_data.dummy;
 | 
			
		||||
    soundio_os_cond_signal(sid->cond, nullptr);
 | 
			
		||||
static void wakeup_dummy(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIoDummy *sid = &si->backend_data.dummy;
 | 
			
		||||
    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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void outstream_destroy_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
 | 
			
		||||
static void outstream_destroy_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
 | 
			
		||||
 | 
			
		||||
    if (osd->thread) {
 | 
			
		||||
        osd->abort_flag.clear();
 | 
			
		||||
        soundio_os_cond_signal(osd->cond, nullptr);
 | 
			
		||||
        atomic_flag_clear(&osd->abort_flag);
 | 
			
		||||
        soundio_os_cond_signal(osd->cond, NULL);
 | 
			
		||||
        soundio_os_thread_destroy(osd->thread);
 | 
			
		||||
        osd->thread = nullptr;
 | 
			
		||||
        osd->thread = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    soundio_os_cond_destroy(osd->cond);
 | 
			
		||||
    osd->cond = nullptr;
 | 
			
		||||
    osd->cond = NULL;
 | 
			
		||||
 | 
			
		||||
    soundio_ring_buffer_deinit(&osd->ring_buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_open_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    SoundIoDevice *device = outstream->device;
 | 
			
		||||
static int outstream_open_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoDevice *device = outstream->device;
 | 
			
		||||
 | 
			
		||||
    osd->clear_buffer_flag.test_and_set();
 | 
			
		||||
    osd->pause_requested.store(false);
 | 
			
		||||
    atomic_flag_test_and_set(&osd->clear_buffer_flag);
 | 
			
		||||
    SOUNDIO_ATOMIC_STORE(osd->pause_requested, false);
 | 
			
		||||
 | 
			
		||||
    if (outstream->software_latency == 0.0)
 | 
			
		||||
        outstream->software_latency = clamp(device->software_latency_min, 1.0, device->software_latency_max);
 | 
			
		||||
    if (outstream->software_latency == 0.0) {
 | 
			
		||||
        outstream->software_latency = soundio_double_clamp(
 | 
			
		||||
                device->software_latency_min, 1.0, device->software_latency_max);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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) {
 | 
			
		||||
    SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
 | 
			
		||||
    osd->pause_requested.store(pause);
 | 
			
		||||
    struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
 | 
			
		||||
    SOUNDIO_ATOMIC_STORE(osd->pause_requested, pause);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_start_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
static int outstream_start_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    assert(!osd->thread);
 | 
			
		||||
    osd->abort_flag.test_and_set();
 | 
			
		||||
    atomic_flag_test_and_set(&osd->abort_flag);
 | 
			
		||||
    int err;
 | 
			
		||||
    if ((err = soundio_os_thread_create(playback_thread_run, os,
 | 
			
		||||
                    soundio->emit_rtprio_warning, &osd->thread)))
 | 
			
		||||
| 
						 | 
				
			
			@ -224,11 +226,11 @@ static int outstream_start_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_begin_write_dummy(SoundIoPrivate *si,
 | 
			
		||||
        SoundIoOutStreamPrivate *os, SoundIoChannelArea **out_areas, int *frame_count)
 | 
			
		||||
static int outstream_begin_write_dummy(struct SoundIoPrivate *si,
 | 
			
		||||
        struct SoundIoOutStreamPrivate *os, struct SoundIoChannelArea **out_areas, int *frame_count)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
 | 
			
		||||
 | 
			
		||||
    if (*frame_count > osd->frames_left)
 | 
			
		||||
        return SoundIoErrorInvalid;
 | 
			
		||||
| 
						 | 
				
			
			@ -244,55 +246,57 @@ static int outstream_begin_write_dummy(SoundIoPrivate *si,
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_end_write_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
static int outstream_end_write_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    int byte_count = osd->write_frame_count * outstream->bytes_per_frame;
 | 
			
		||||
    soundio_ring_buffer_advance_write_ptr(&osd->ring_buffer, byte_count);
 | 
			
		||||
    osd->frames_left -= osd->write_frame_count;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_clear_buffer_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
 | 
			
		||||
    osd->clear_buffer_flag.clear();
 | 
			
		||||
    soundio_os_cond_signal(osd->cond, nullptr);
 | 
			
		||||
static int outstream_clear_buffer_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
 | 
			
		||||
    atomic_flag_clear(&osd->clear_buffer_flag);
 | 
			
		||||
    soundio_os_cond_signal(osd->cond, NULL);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_get_latency_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, double *out_latency) {
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
 | 
			
		||||
static int outstream_get_latency_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, double *out_latency) {
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
 | 
			
		||||
    int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer);
 | 
			
		||||
 | 
			
		||||
    *out_latency = (fill_bytes / outstream->bytes_per_frame) / (double)outstream->sample_rate;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void instream_destroy_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
 | 
			
		||||
    SoundIoInStreamDummy *isd = &is->backend_data.dummy;
 | 
			
		||||
static void instream_destroy_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
 | 
			
		||||
    struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
 | 
			
		||||
 | 
			
		||||
    if (isd->thread) {
 | 
			
		||||
        isd->abort_flag.clear();
 | 
			
		||||
        soundio_os_cond_signal(isd->cond, nullptr);
 | 
			
		||||
        atomic_flag_clear(&isd->abort_flag);
 | 
			
		||||
        soundio_os_cond_signal(isd->cond, NULL);
 | 
			
		||||
        soundio_os_thread_destroy(isd->thread);
 | 
			
		||||
        isd->thread = nullptr;
 | 
			
		||||
        isd->thread = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    soundio_os_cond_destroy(isd->cond);
 | 
			
		||||
    isd->cond = nullptr;
 | 
			
		||||
    isd->cond = NULL;
 | 
			
		||||
 | 
			
		||||
    soundio_ring_buffer_deinit(&isd->ring_buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_open_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
 | 
			
		||||
    SoundIoInStreamDummy *isd = &is->backend_data.dummy;
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    SoundIoDevice *device = instream->device;
 | 
			
		||||
static int instream_open_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
 | 
			
		||||
    struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoDevice *device = instream->device;
 | 
			
		||||
 | 
			
		||||
    isd->pause_requested.store(false);
 | 
			
		||||
    SOUNDIO_ATOMIC_STORE(isd->pause_requested, false);
 | 
			
		||||
 | 
			
		||||
    if (instream->software_latency == 0.0)
 | 
			
		||||
        instream->software_latency = clamp(device->software_latency_min, 1.0, device->software_latency_max);
 | 
			
		||||
    if (instream->software_latency == 0.0) {
 | 
			
		||||
        instream->software_latency = soundio_double_clamp(
 | 
			
		||||
                device->software_latency_min, 1.0, device->software_latency_max);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    isd->period_duration = instream->software_latency;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -317,17 +321,17 @@ static int instream_open_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_pause_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is, bool pause) {
 | 
			
		||||
    SoundIoInStreamDummy *isd = &is->backend_data.dummy;
 | 
			
		||||
    isd->pause_requested.store(pause);
 | 
			
		||||
static int instream_pause_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
 | 
			
		||||
    struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
 | 
			
		||||
    SOUNDIO_ATOMIC_STORE(isd->pause_requested, pause);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_start_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
 | 
			
		||||
    SoundIoInStreamDummy *isd = &is->backend_data.dummy;
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
static int instream_start_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
 | 
			
		||||
    struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    assert(!isd->thread);
 | 
			
		||||
    isd->abort_flag.test_and_set();
 | 
			
		||||
    atomic_flag_test_and_set(&isd->abort_flag);
 | 
			
		||||
    int err;
 | 
			
		||||
    if ((err = soundio_os_thread_create(capture_thread_run, is,
 | 
			
		||||
                    soundio->emit_rtprio_warning, &isd->thread)))
 | 
			
		||||
| 
						 | 
				
			
			@ -337,11 +341,11 @@ static int instream_start_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is)
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_begin_read_dummy(SoundIoPrivate *si,
 | 
			
		||||
        SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count)
 | 
			
		||||
static int instream_begin_read_dummy(struct SoundIoPrivate *si,
 | 
			
		||||
        struct SoundIoInStreamPrivate *is, struct SoundIoChannelArea **out_areas, int *frame_count)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    SoundIoInStreamDummy *isd = &is->backend_data.dummy;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
 | 
			
		||||
 | 
			
		||||
    assert(*frame_count <= isd->frames_left);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -357,27 +361,27 @@ static int instream_begin_read_dummy(SoundIoPrivate *si,
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_end_read_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
 | 
			
		||||
    SoundIoInStreamDummy *isd = &is->backend_data.dummy;
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
static int instream_end_read_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
 | 
			
		||||
    struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    int byte_count = isd->read_frame_count * instream->bytes_per_frame;
 | 
			
		||||
    soundio_ring_buffer_advance_read_ptr(&isd->ring_buffer, byte_count);
 | 
			
		||||
    isd->frames_left -= isd->read_frame_count;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_get_latency_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is, double *out_latency) {
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    SoundIoInStreamDummy *osd = &is->backend_data.dummy;
 | 
			
		||||
static int instream_get_latency_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, double *out_latency) {
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoInStreamDummy *osd = &is->backend_data.dummy;
 | 
			
		||||
    int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer);
 | 
			
		||||
 | 
			
		||||
    *out_latency = (fill_bytes / instream->bytes_per_frame) / (double)instream->sample_rate;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int set_all_device_formats(SoundIoDevice *device) {
 | 
			
		||||
static int set_all_device_formats(struct SoundIoDevice *device) {
 | 
			
		||||
    device->format_count = 18;
 | 
			
		||||
    device->formats = allocate<SoundIoFormat>(device->format_count);
 | 
			
		||||
    device->formats = ALLOCATE(enum SoundIoFormat, device->format_count);
 | 
			
		||||
    if (!device->formats)
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -403,17 +407,17 @@ static int set_all_device_formats(SoundIoDevice *device) {
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_all_device_sample_rates(SoundIoDevice *device) {
 | 
			
		||||
    SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
 | 
			
		||||
static void set_all_device_sample_rates(struct SoundIoDevice *device) {
 | 
			
		||||
    struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
 | 
			
		||||
    device->sample_rate_count = 1;
 | 
			
		||||
    device->sample_rates = &dev->prealloc_sample_rate_range;
 | 
			
		||||
    device->sample_rates[0].min = SOUNDIO_MIN_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->layouts = allocate<SoundIoChannelLayout>(device->layout_count);
 | 
			
		||||
    device->layouts = ALLOCATE(struct SoundIoChannelLayout, device->layout_count);
 | 
			
		||||
    if (!device->layouts)
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int soundio_dummy_init(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoDummy *sid = &si->backend_data.dummy;
 | 
			
		||||
int soundio_dummy_init(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoDummy *sid = &si->backend_data.dummy;
 | 
			
		||||
 | 
			
		||||
    sid->mutex = soundio_os_mutex_create();
 | 
			
		||||
    if (!sid->mutex) {
 | 
			
		||||
| 
						 | 
				
			
			@ -438,7 +442,7 @@ int soundio_dummy_init(SoundIoPrivate *si) {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    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) {
 | 
			
		||||
        destroy_dummy(si);
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
| 
						 | 
				
			
			@ -449,12 +453,12 @@ int soundio_dummy_init(SoundIoPrivate *si) {
 | 
			
		|||
 | 
			
		||||
    // create output device
 | 
			
		||||
    {
 | 
			
		||||
        SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1);
 | 
			
		||||
        struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
 | 
			
		||||
        if (!dev) {
 | 
			
		||||
            destroy_dummy(si);
 | 
			
		||||
            return SoundIoErrorNoMem;
 | 
			
		||||
        }
 | 
			
		||||
        SoundIoDevice *device = &dev->pub;
 | 
			
		||||
        struct SoundIoDevice *device = &dev->pub;
 | 
			
		||||
 | 
			
		||||
        device->ref_count = 1;
 | 
			
		||||
        device->soundio = soundio;
 | 
			
		||||
| 
						 | 
				
			
			@ -486,7 +490,7 @@ int soundio_dummy_init(SoundIoPrivate *si) {
 | 
			
		|||
        device->sample_rate_current = 48000;
 | 
			
		||||
        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);
 | 
			
		||||
            destroy_dummy(si);
 | 
			
		||||
            return SoundIoErrorNoMem;
 | 
			
		||||
| 
						 | 
				
			
			@ -495,12 +499,12 @@ int soundio_dummy_init(SoundIoPrivate *si) {
 | 
			
		|||
 | 
			
		||||
    // create input device
 | 
			
		||||
    {
 | 
			
		||||
        SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1);
 | 
			
		||||
        struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
 | 
			
		||||
        if (!dev) {
 | 
			
		||||
            destroy_dummy(si);
 | 
			
		||||
            return SoundIoErrorNoMem;
 | 
			
		||||
        }
 | 
			
		||||
        SoundIoDevice *device = &dev->pub;
 | 
			
		||||
        struct SoundIoDevice *device = &dev->pub;
 | 
			
		||||
 | 
			
		||||
        device->ref_count = 1;
 | 
			
		||||
        device->soundio = soundio;
 | 
			
		||||
| 
						 | 
				
			
			@ -531,7 +535,7 @@ int soundio_dummy_init(SoundIoPrivate *si) {
 | 
			
		|||
        device->sample_rate_current = 48000;
 | 
			
		||||
        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);
 | 
			
		||||
            destroy_dummy(si);
 | 
			
		||||
            return SoundIoErrorNoMem;
 | 
			
		||||
| 
						 | 
				
			
			@ -5,23 +5,24 @@
 | 
			
		|||
 * See http://opensource.org/licenses/MIT
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef SOUNDIO_DUMMY_HPP
 | 
			
		||||
#define SOUNDIO_DUMMY_HPP
 | 
			
		||||
#ifndef SOUNDIO_DUMMY_H
 | 
			
		||||
#define SOUNDIO_DUMMY_H
 | 
			
		||||
 | 
			
		||||
#include "soundio_private.h"
 | 
			
		||||
#include "soundio_internal.h"
 | 
			
		||||
#include "os.h"
 | 
			
		||||
#include "atomics.hpp"
 | 
			
		||||
#include "ring_buffer.hpp"
 | 
			
		||||
#include "ring_buffer.h"
 | 
			
		||||
#include "atomics.h"
 | 
			
		||||
 | 
			
		||||
struct SoundIoPrivate;
 | 
			
		||||
int soundio_dummy_init(struct SoundIoPrivate *si);
 | 
			
		||||
 | 
			
		||||
struct SoundIoDummy {
 | 
			
		||||
    SoundIoOsMutex *mutex;
 | 
			
		||||
    SoundIoOsCond *cond;
 | 
			
		||||
    struct SoundIoOsMutex *mutex;
 | 
			
		||||
    struct SoundIoOsCond *cond;
 | 
			
		||||
    bool devices_emitted;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SoundIoDeviceDummy { };
 | 
			
		||||
struct SoundIoDeviceDummy { int make_the_struct_not_empty; };
 | 
			
		||||
 | 
			
		||||
struct SoundIoOutStreamDummy {
 | 
			
		||||
    struct SoundIoOsThread *thread;
 | 
			
		||||
| 
						 | 
				
			
			@ -34,8 +35,8 @@ struct SoundIoOutStreamDummy {
 | 
			
		|||
    struct SoundIoRingBuffer ring_buffer;
 | 
			
		||||
    double playback_start_time;
 | 
			
		||||
    atomic_flag clear_buffer_flag;
 | 
			
		||||
    atomic_bool pause_requested;
 | 
			
		||||
    SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
    struct SoundIoAtomicBool pause_requested;
 | 
			
		||||
    struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SoundIoInStreamDummy {
 | 
			
		||||
| 
						 | 
				
			
			@ -47,8 +48,8 @@ struct SoundIoInStreamDummy {
 | 
			
		|||
    int read_frame_count;
 | 
			
		||||
    int buffer_frame_count;
 | 
			
		||||
    struct SoundIoRingBuffer ring_buffer;
 | 
			
		||||
    atomic_bool pause_requested;
 | 
			
		||||
    SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
    struct SoundIoAtomicBool pause_requested;
 | 
			
		||||
    struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -5,9 +5,9 @@
 | 
			
		|||
 * See http://opensource.org/licenses/MIT
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "jack.hpp"
 | 
			
		||||
#include "soundio.hpp"
 | 
			
		||||
#include "list.hpp"
 | 
			
		||||
#include "jack.h"
 | 
			
		||||
#include "soundio_private.h"
 | 
			
		||||
#include "list.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ struct SoundIoJackPort {
 | 
			
		|||
    int full_name_len;
 | 
			
		||||
    const char *name;
 | 
			
		||||
    int name_len;
 | 
			
		||||
    SoundIoChannelId channel_id;
 | 
			
		||||
    enum SoundIoChannelId channel_id;
 | 
			
		||||
    jack_latency_range_t latency_range;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -26,11 +26,14 @@ struct SoundIoJackClient {
 | 
			
		|||
    const char *name;
 | 
			
		||||
    int name_len;
 | 
			
		||||
    bool is_physical;
 | 
			
		||||
    SoundIoDeviceAim aim;
 | 
			
		||||
    enum SoundIoDeviceAim aim;
 | 
			
		||||
    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,
 | 
			
		||||
        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,
 | 
			
		||||
        SoundIoDeviceAim aim, bool is_physical, const char *client_name, int client_name_len)
 | 
			
		||||
static struct SoundIoJackClient *find_or_create_client(struct SoundIoListJackClient *clients,
 | 
			
		||||
        enum SoundIoDeviceAim aim, bool is_physical, const char *client_name, int client_name_len)
 | 
			
		||||
{
 | 
			
		||||
    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 &&
 | 
			
		||||
            client->aim == aim &&
 | 
			
		||||
            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;
 | 
			
		||||
    if ((err = clients->add_one()))
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    SoundIoJackClient *client = &clients->last();
 | 
			
		||||
    if ((err = SoundIoListJackClient_add_one(clients)))
 | 
			
		||||
        return NULL;
 | 
			
		||||
    struct SoundIoJackClient *client = SoundIoListJackClient_last_ptr(clients);
 | 
			
		||||
    client->is_physical = is_physical;
 | 
			
		||||
    client->aim = aim;
 | 
			
		||||
    client->name = client_name;
 | 
			
		||||
| 
						 | 
				
			
			@ -70,36 +73,36 @@ static SoundIoJackClient *find_or_create_client(SoundIoList<SoundIoJackClient> *
 | 
			
		|||
    return client;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void destruct_device(SoundIoDevicePrivate *dp) {
 | 
			
		||||
    SoundIoDeviceJack *dj = &dp->backend_data.jack;
 | 
			
		||||
static void destruct_device(struct SoundIoDevicePrivate *dp) {
 | 
			
		||||
    struct SoundIoDeviceJack *dj = &dp->backend_data.jack;
 | 
			
		||||
    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(dj->ports);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int refresh_devices_bare(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
static int refresh_devices_bare(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
 | 
			
		||||
    if (sij->is_shutdown)
 | 
			
		||||
        return SoundIoErrorBackendDisconnected;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    SoundIoDevicesInfo *devices_info = allocate<SoundIoDevicesInfo>(1);
 | 
			
		||||
    struct SoundIoDevicesInfo *devices_info = ALLOCATE(struct SoundIoDevicesInfo, 1);
 | 
			
		||||
    if (!devices_info)
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
 | 
			
		||||
    devices_info->default_output_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) {
 | 
			
		||||
        soundio_destroy_devices_info(devices_info);
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SoundIoList<SoundIoJackClient> clients = {0};
 | 
			
		||||
    struct SoundIoListJackClient clients = {0};
 | 
			
		||||
    const char **port_name_ptr = port_names;
 | 
			
		||||
    for (; *port_name_ptr; port_name_ptr += 1) {
 | 
			
		||||
        const char *client_and_port_name = *port_name_ptr;
 | 
			
		||||
| 
						 | 
				
			
			@ -120,12 +123,12 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
 | 
			
		|||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SoundIoDeviceAim aim = (flags & JackPortIsInput) ?
 | 
			
		||||
        enum SoundIoDeviceAim aim = (flags & JackPortIsInput) ?
 | 
			
		||||
            SoundIoDeviceAimOutput : SoundIoDeviceAimInput;
 | 
			
		||||
        bool is_physical = flags & JackPortIsPhysical;
 | 
			
		||||
 | 
			
		||||
        const char *client_name = nullptr;
 | 
			
		||||
        const char *port_name = nullptr;
 | 
			
		||||
        const char *client_name = NULL;
 | 
			
		||||
        const char *port_name = NULL;
 | 
			
		||||
        int client_name_len;
 | 
			
		||||
        int 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
 | 
			
		||||
            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);
 | 
			
		||||
        if (!client) {
 | 
			
		||||
            jack_free(port_names);
 | 
			
		||||
| 
						 | 
				
			
			@ -145,7 +148,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
 | 
			
		|||
            // we hit the channel limit, skip the leftovers
 | 
			
		||||
            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_len = client_and_port_name_len;
 | 
			
		||||
        port->name = port_name;
 | 
			
		||||
| 
						 | 
				
			
			@ -158,21 +161,21 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1);
 | 
			
		||||
        struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
 | 
			
		||||
        if (!dev) {
 | 
			
		||||
            jack_free(port_names);
 | 
			
		||||
            soundio_destroy_devices_info(devices_info);
 | 
			
		||||
            return SoundIoErrorNoMem;
 | 
			
		||||
        }
 | 
			
		||||
        SoundIoDevice *device = &dev->pub;
 | 
			
		||||
        SoundIoDeviceJack *dj = &dev->backend_data.jack;
 | 
			
		||||
        struct SoundIoDevice *device = &dev->pub;
 | 
			
		||||
        struct SoundIoDeviceJack *dj = &dev->backend_data.jack;
 | 
			
		||||
        int description_len = client->name_len + 3 + 2 * client->port_count;
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -184,7 +187,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
 | 
			
		|||
        device->is_raw = false;
 | 
			
		||||
        device->aim = client->aim;
 | 
			
		||||
        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->sample_rate_count = 1;
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
        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) {
 | 
			
		||||
            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) {
 | 
			
		||||
            SoundIoJackPort *port = &client->ports[port_index];
 | 
			
		||||
            SoundIoDeviceJackPort *djp = &dj->ports[port_index];
 | 
			
		||||
            struct SoundIoJackPort *port = &client->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_len = port->full_name_len;
 | 
			
		||||
            djp->channel_id = port->channel_id;
 | 
			
		||||
| 
						 | 
				
			
			@ -226,7 +229,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
 | 
			
		|||
        memcpy(&device->name[client->name_len], ": ", 2);
 | 
			
		||||
        int index = client->name_len + 2;
 | 
			
		||||
        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);
 | 
			
		||||
            index += port->name_len;
 | 
			
		||||
            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;
 | 
			
		||||
        bool any_invalid = false;
 | 
			
		||||
        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;
 | 
			
		||||
            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[0] = device->current_format;
 | 
			
		||||
 | 
			
		||||
        SoundIoList<SoundIoDevice *> *device_list;
 | 
			
		||||
        struct SoundIoListDevicePtr *device_list;
 | 
			
		||||
        if (device->aim == SoundIoDeviceAimOutput) {
 | 
			
		||||
            device_list = &devices_info->output_devices;
 | 
			
		||||
            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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (device_list->append(device)) {
 | 
			
		||||
        if (SoundIoListDevicePtr_append(device_list, device)) {
 | 
			
		||||
            soundio_device_unref(device);
 | 
			
		||||
            soundio_destroy_devices_info(devices_info);
 | 
			
		||||
            return SoundIoErrorNoMem;
 | 
			
		||||
| 
						 | 
				
			
			@ -283,7 +286,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int refresh_devices(SoundIoPrivate *si) {
 | 
			
		||||
static int refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		||||
    int err = SoundIoErrorInterrupted;
 | 
			
		||||
    while (err == SoundIoErrorInterrupted)
 | 
			
		||||
        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) {
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    int err;
 | 
			
		||||
 | 
			
		||||
    bool cb_shutdown = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -312,9 +315,9 @@ static void my_flush_events(struct SoundIoPrivate *si, bool wait) {
 | 
			
		|||
    if (cb_shutdown) {
 | 
			
		||||
        soundio->on_backend_disconnect(soundio, SoundIoErrorBackendDisconnected);
 | 
			
		||||
    } else {
 | 
			
		||||
        if (!sij->refresh_devices_flag.test_and_set()) {
 | 
			
		||||
        if (!atomic_flag_test_and_set(&sij->refresh_devices_flag)) {
 | 
			
		||||
            if ((err = refresh_devices(si))) {
 | 
			
		||||
                sij->refresh_devices_flag.clear();
 | 
			
		||||
                atomic_flag_clear(&sij->refresh_devices_flag);
 | 
			
		||||
            } else {
 | 
			
		||||
                soundio->on_devices_change(soundio);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -332,16 +335,16 @@ static void wait_events_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_cond_signal(sij->cond, sij->mutex);
 | 
			
		||||
    soundio_os_mutex_unlock(sij->mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void force_device_scan_jack(struct SoundIoPrivate *si) {
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    sij->refresh_devices_flag.clear();
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    atomic_flag_clear(&sij->refresh_devices_flag);
 | 
			
		||||
    soundio_os_mutex_lock(sij->mutex);
 | 
			
		||||
    soundio_os_cond_signal(sij->cond, sij->mutex);
 | 
			
		||||
    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) {
 | 
			
		||||
    SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
 | 
			
		||||
    SoundIoOutStreamJack *osj = &os->backend_data.jack;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
 | 
			
		||||
    struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    osj->frames_left = nframes;
 | 
			
		||||
    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].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) {
 | 
			
		||||
    SoundIoOutStreamJack *osj = &os->backend_data.jack;
 | 
			
		||||
    struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
 | 
			
		||||
 | 
			
		||||
    jack_client_close(osj->client);
 | 
			
		||||
    osj->client = nullptr;
 | 
			
		||||
    osj->client = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SoundIoDeviceJackPort *find_port_matching_channel(SoundIoDevice *device, SoundIoChannelId id) {
 | 
			
		||||
    SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
 | 
			
		||||
    SoundIoDeviceJack *dj = &dev->backend_data.jack;
 | 
			
		||||
static struct SoundIoDeviceJackPort *find_port_matching_channel(struct SoundIoDevice *device, enum SoundIoChannelId id) {
 | 
			
		||||
    struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
 | 
			
		||||
    struct SoundIoDeviceJack *dj = &dev->backend_data.jack;
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
            return &dj->ports[ch];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return nullptr;
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_xrun_callback(void *arg) {
 | 
			
		||||
    SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    outstream->underflow_callback(outstream);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_buffer_size_callback(jack_nframes_t nframes, void *arg) {
 | 
			
		||||
    SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
 | 
			
		||||
    SoundIoOutStreamJack *osj = &os->backend_data.jack;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
 | 
			
		||||
    struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    if ((jack_nframes_t)osj->period_size == nframes) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    } 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) {
 | 
			
		||||
    SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    if (nframes == (jack_nframes_t)outstream->sample_rate) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -413,18 +416,22 @@ static int outstream_sample_rate_callback(jack_nframes_t nframes, void *arg) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static void outstream_shutdown_callback(void *arg) {
 | 
			
		||||
    SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    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) {
 | 
			
		||||
    SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    SoundIoOutStreamJack *osj = &os->backend_data.jack;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    SoundIoDevice *device = outstream->device;
 | 
			
		||||
    SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
 | 
			
		||||
    SoundIoDeviceJack *dj = &dev->backend_data.jack;
 | 
			
		||||
    struct SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoDevice *device = outstream->device;
 | 
			
		||||
    struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
 | 
			
		||||
    struct SoundIoDeviceJack *dj = &dev->backend_data.jack;
 | 
			
		||||
 | 
			
		||||
    if (sij->is_shutdown)
 | 
			
		||||
        return SoundIoErrorBackendDisconnected;
 | 
			
		||||
| 
						 | 
				
			
			@ -472,7 +479,7 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
 | 
			
		|||
    // register ports and map channels
 | 
			
		||||
    int connected_count = 0;
 | 
			
		||||
    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);
 | 
			
		||||
        unsigned long flags = JackPortIsOutput;
 | 
			
		||||
        if (!outstream->non_terminal_hint)
 | 
			
		||||
| 
						 | 
				
			
			@ -482,15 +489,15 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
 | 
			
		|||
            outstream_destroy_jack(si, os);
 | 
			
		||||
            return SoundIoErrorOpeningDevice;
 | 
			
		||||
        }
 | 
			
		||||
        SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
 | 
			
		||||
        struct SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
 | 
			
		||||
        osjp->source_port = jport;
 | 
			
		||||
        // 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) {
 | 
			
		||||
            osjp->dest_port_name = djp->full_name;
 | 
			
		||||
            osjp->dest_port_name_len = djp->full_name_len;
 | 
			
		||||
            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
 | 
			
		||||
| 
						 | 
				
			
			@ -499,13 +506,13 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
 | 
			
		|||
        max_port_latency = 0;
 | 
			
		||||
        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) {
 | 
			
		||||
            SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
 | 
			
		||||
            SoundIoDeviceJackPort *djp = &dj->ports[ch];
 | 
			
		||||
            struct SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
 | 
			
		||||
            struct SoundIoDeviceJackPort *djp = &dj->ports[ch];
 | 
			
		||||
            osjp->dest_port_name = djp->full_name;
 | 
			
		||||
            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) {
 | 
			
		||||
    SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    struct SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
 | 
			
		||||
    if (sij->is_shutdown)
 | 
			
		||||
        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) {
 | 
			
		||||
    SoundIoOutStreamJack *osj = &os->backend_data.jack;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    int err;
 | 
			
		||||
 | 
			
		||||
    if (sij->is_shutdown)
 | 
			
		||||
| 
						 | 
				
			
			@ -536,7 +543,7 @@ static int outstream_start_jack(struct SoundIoPrivate *si, struct SoundIoOutStre
 | 
			
		|||
        return SoundIoErrorStreaming;
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
        // allow unconnected ports
 | 
			
		||||
        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,
 | 
			
		||||
        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)
 | 
			
		||||
        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) {
 | 
			
		||||
    SoundIoOutStreamJack *osj = &os->backend_data.jack;
 | 
			
		||||
    struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
 | 
			
		||||
    osj->frames_left = 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,
 | 
			
		||||
        double *out_latency)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoOutStreamJack *osj = &os->backend_data.jack;
 | 
			
		||||
    struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
 | 
			
		||||
    *out_latency = osj->hardware_latency;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
    isj->client = nullptr;
 | 
			
		||||
    isj->client = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_xrun_callback(void *arg) {
 | 
			
		||||
    SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    instream->overflow_callback(instream);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_buffer_size_callback(jack_nframes_t nframes, void *arg) {
 | 
			
		||||
    SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
 | 
			
		||||
    SoundIoInStreamJack *isj = &is->backend_data.jack;
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
 | 
			
		||||
    struct SoundIoInStreamJack *isj = &is->backend_data.jack;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
 | 
			
		||||
    if ((jack_nframes_t)isj->period_size == nframes) {
 | 
			
		||||
        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) {
 | 
			
		||||
    SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    if (nframes == (jack_nframes_t)instream->sample_rate) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -620,18 +627,18 @@ static int instream_sample_rate_callback(jack_nframes_t nframes, void *arg) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static void instream_shutdown_callback(void *arg) {
 | 
			
		||||
    SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    instream->error_callback(instream, SoundIoErrorStreaming);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_process_callback(jack_nframes_t nframes, void *arg) {
 | 
			
		||||
    SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    SoundIoInStreamJack *isj = &is->backend_data.jack;
 | 
			
		||||
    struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoInStreamJack *isj = &is->backend_data.jack;
 | 
			
		||||
    isj->frames_left = nframes;
 | 
			
		||||
    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].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) {
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    SoundIoInStreamJack *isj = &is->backend_data.jack;
 | 
			
		||||
    SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    SoundIoDevice *device = instream->device;
 | 
			
		||||
    SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
 | 
			
		||||
    SoundIoDeviceJack *dj = &dev->backend_data.jack;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoInStreamJack *isj = &is->backend_data.jack;
 | 
			
		||||
    struct SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    struct SoundIoDevice *device = instream->device;
 | 
			
		||||
    struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
 | 
			
		||||
    struct SoundIoDeviceJack *dj = &dev->backend_data.jack;
 | 
			
		||||
 | 
			
		||||
    if (sij->is_shutdown)
 | 
			
		||||
        return SoundIoErrorBackendDisconnected;
 | 
			
		||||
| 
						 | 
				
			
			@ -692,7 +699,7 @@ static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamP
 | 
			
		|||
    // register ports and map channels
 | 
			
		||||
    int connected_count = 0;
 | 
			
		||||
    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);
 | 
			
		||||
        unsigned long flags = JackPortIsInput;
 | 
			
		||||
        if (!instream->non_terminal_hint)
 | 
			
		||||
| 
						 | 
				
			
			@ -702,15 +709,15 @@ static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamP
 | 
			
		|||
            instream_destroy_jack(si, is);
 | 
			
		||||
            return SoundIoErrorOpeningDevice;
 | 
			
		||||
        }
 | 
			
		||||
        SoundIoInStreamJackPort *isjp = &isj->ports[ch];
 | 
			
		||||
        struct SoundIoInStreamJackPort *isjp = &isj->ports[ch];
 | 
			
		||||
        isjp->dest_port = jport;
 | 
			
		||||
        // 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) {
 | 
			
		||||
            isjp->source_port_name = djp->full_name;
 | 
			
		||||
            isjp->source_port_name_len = djp->full_name_len;
 | 
			
		||||
            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
 | 
			
		||||
| 
						 | 
				
			
			@ -719,13 +726,13 @@ static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamP
 | 
			
		|||
        max_port_latency = 0;
 | 
			
		||||
        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) {
 | 
			
		||||
            SoundIoInStreamJackPort *isjp = &isj->ports[ch];
 | 
			
		||||
            SoundIoDeviceJackPort *djp = &dj->ports[ch];
 | 
			
		||||
            struct SoundIoInStreamJackPort *isjp = &isj->ports[ch];
 | 
			
		||||
            struct SoundIoDeviceJackPort *djp = &dj->ports[ch];
 | 
			
		||||
            isjp->source_port_name = djp->full_name;
 | 
			
		||||
            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) {
 | 
			
		||||
    SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    struct SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
 | 
			
		||||
    if (sij->is_shutdown)
 | 
			
		||||
        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) {
 | 
			
		||||
    SoundIoInStreamJack *isj = &is->backend_data.jack;
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    struct SoundIoInStreamJack *isj = &is->backend_data.jack;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    int err;
 | 
			
		||||
 | 
			
		||||
    if (sij->is_shutdown)
 | 
			
		||||
| 
						 | 
				
			
			@ -756,7 +763,7 @@ static int instream_start_jack(struct SoundIoPrivate *si, struct SoundIoInStream
 | 
			
		|||
        return SoundIoErrorStreaming;
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
        // allow unconnected ports
 | 
			
		||||
        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,
 | 
			
		||||
        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)
 | 
			
		||||
        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) {
 | 
			
		||||
    SoundIoInStreamJack *isj = &is->backend_data.jack;
 | 
			
		||||
    struct SoundIoInStreamJack *isj = &is->backend_data.jack;
 | 
			
		||||
    isj->frames_left = 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,
 | 
			
		||||
        double *out_latency)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoInStreamJack *isj = &is->backend_data.jack;
 | 
			
		||||
    struct SoundIoInStreamJack *isj = &is->backend_data.jack;
 | 
			
		||||
    *out_latency = isj->hardware_latency;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void notify_devices_change(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    sij->refresh_devices_flag.clear();
 | 
			
		||||
static void notify_devices_change(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    atomic_flag_clear(&sij->refresh_devices_flag);
 | 
			
		||||
    soundio_os_mutex_lock(sij->mutex);
 | 
			
		||||
    soundio_os_cond_signal(sij->cond, sij->mutex);
 | 
			
		||||
    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) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)arg;
 | 
			
		||||
    SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
 | 
			
		||||
    struct SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    sij->period_size = nframes;
 | 
			
		||||
    notify_devices_change(si);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int sample_rate_callback(jack_nframes_t nframes, void *arg) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)arg;
 | 
			
		||||
    SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
 | 
			
		||||
    struct SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    sij->sample_rate = nframes;
 | 
			
		||||
    notify_devices_change(si);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void port_rename_calllback(jack_port_id_t port_id,
 | 
			
		||||
        const char *old_name, const char *new_name, void *arg)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)arg;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
 | 
			
		||||
    notify_devices_change(si);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void shutdown_callback(void *arg) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)arg;
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    soundio_os_mutex_lock(sij->mutex);
 | 
			
		||||
    sij->is_shutdown = true;
 | 
			
		||||
    soundio_os_cond_signal(sij->cond, sij->mutex);
 | 
			
		||||
| 
						 | 
				
			
			@ -845,8 +852,8 @@ static void shutdown_callback(void *arg) {
 | 
			
		|||
    soundio_os_mutex_unlock(sij->mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void destroy_jack(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
static void destroy_jack(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
 | 
			
		||||
    if (sij->client)
 | 
			
		||||
        jack_client_close(sij->client);
 | 
			
		||||
| 
						 | 
				
			
			@ -859,15 +866,15 @@ static void destroy_jack(SoundIoPrivate *si) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
int soundio_jack_init(struct SoundIoPrivate *si) {
 | 
			
		||||
    SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoJack *sij = &si->backend_data.jack;
 | 
			
		||||
    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)
 | 
			
		||||
            jack_set_error_function(soundio->jack_error_callback);
 | 
			
		||||
        if (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();
 | 
			
		||||
| 
						 | 
				
			
			@ -916,7 +923,7 @@ int soundio_jack_init(struct SoundIoPrivate *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->sample_rate = jack_get_sample_rate(sij->client);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5,33 +5,39 @@
 | 
			
		|||
 * See http://opensource.org/licenses/MIT
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef SOUNDIO_JACK_HPP
 | 
			
		||||
#define SOUNDIO_JACK_HPP
 | 
			
		||||
#ifndef SOUNDIO_JACK_H
 | 
			
		||||
#define SOUNDIO_JACK_H
 | 
			
		||||
 | 
			
		||||
#include "soundio_private.h"
 | 
			
		||||
#include "soundio_internal.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>
 | 
			
		||||
#pragma GCC diagnostic pop
 | 
			
		||||
 | 
			
		||||
struct SoundIoPrivate;
 | 
			
		||||
int soundio_jack_init(struct SoundIoPrivate *si);
 | 
			
		||||
 | 
			
		||||
struct SoundIoDeviceJackPort {
 | 
			
		||||
    char *full_name;
 | 
			
		||||
    int full_name_len;
 | 
			
		||||
    SoundIoChannelId channel_id;
 | 
			
		||||
    enum SoundIoChannelId channel_id;
 | 
			
		||||
    jack_latency_range_t latency_range;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SoundIoDeviceJack {
 | 
			
		||||
    int port_count;
 | 
			
		||||
    SoundIoDeviceJackPort *ports;
 | 
			
		||||
    struct SoundIoDeviceJackPort *ports;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SoundIoJack {
 | 
			
		||||
    jack_client_t *client;
 | 
			
		||||
    SoundIoOsMutex *mutex;
 | 
			
		||||
    SoundIoOsCond *cond;
 | 
			
		||||
    struct SoundIoOsMutex *mutex;
 | 
			
		||||
    struct SoundIoOsCond *cond;
 | 
			
		||||
    atomic_flag refresh_devices_flag;
 | 
			
		||||
    int sample_rate;
 | 
			
		||||
    int period_size;
 | 
			
		||||
| 
						 | 
				
			
			@ -50,8 +56,8 @@ struct SoundIoOutStreamJack {
 | 
			
		|||
    int period_size;
 | 
			
		||||
    int frames_left;
 | 
			
		||||
    double hardware_latency;
 | 
			
		||||
    SoundIoOutStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
    SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
    struct SoundIoOutStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
    struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SoundIoInStreamJackPort {
 | 
			
		||||
| 
						 | 
				
			
			@ -65,8 +71,8 @@ struct SoundIoInStreamJack {
 | 
			
		|||
    int period_size;
 | 
			
		||||
    int frames_left;
 | 
			
		||||
    double hardware_latency;
 | 
			
		||||
    SoundIoInStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
    SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
    struct SoundIoInStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
    struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
    char *buf_ptrs[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										145
									
								
								src/list.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								src/list.h
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										102
									
								
								src/list.hpp
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								src/list.hpp
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -5,9 +5,16 @@
 | 
			
		|||
 * 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 "soundio_private.h"
 | 
			
		||||
#include "util.hpp"
 | 
			
		||||
#include "soundio_internal.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +60,7 @@
 | 
			
		|||
#include <pthread.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#ifndef MAP_ANONYMOUS
 | 
			
		||||
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
 | 
			
		||||
#define MAP_ANONYMOUS MAP_ANON
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -159,7 +166,7 @@ double soundio_os_get_time(void) {
 | 
			
		|||
#if defined(SOUNDIO_OS_WINDOWS)
 | 
			
		||||
static DWORD WINAPI run_win32_thread(LPVOID userdata) {
 | 
			
		||||
    struct SoundIoOsThread *thread = (struct SoundIoOsThread *)userdata;
 | 
			
		||||
    HRESULT err = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
 | 
			
		||||
    HRESULT err = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
 | 
			
		||||
    assert(err == S_OK);
 | 
			
		||||
    thread->run(thread->arg);
 | 
			
		||||
    CoUninitialize();
 | 
			
		||||
| 
						 | 
				
			
			@ -184,7 +191,7 @@ int soundio_os_thread_create(
 | 
			
		|||
{
 | 
			
		||||
    *out_thread = NULL;
 | 
			
		||||
 | 
			
		||||
    struct SoundIoOsThread *thread = allocate<SoundIoOsThread>(1);
 | 
			
		||||
    struct SoundIoOsThread *thread = ALLOCATE(struct SoundIoOsThread, 1);
 | 
			
		||||
    if (!thread) {
 | 
			
		||||
        soundio_os_thread_destroy(thread);
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
| 
						 | 
				
			
			@ -276,7 +283,7 @@ void soundio_os_thread_destroy(struct SoundIoOsThread *thread) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
struct SoundIoOsMutex *soundio_os_mutex_create(void) {
 | 
			
		||||
    struct SoundIoOsMutex *mutex = allocate<SoundIoOsMutex>(1);
 | 
			
		||||
    struct SoundIoOsMutex *mutex = ALLOCATE(struct SoundIoOsMutex, 1);
 | 
			
		||||
    if (!mutex) {
 | 
			
		||||
        soundio_os_mutex_destroy(mutex);
 | 
			
		||||
        return NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -328,7 +335,7 @@ void soundio_os_mutex_unlock(struct SoundIoOsMutex *mutex) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
struct SoundIoOsCond * soundio_os_cond_create(void) {
 | 
			
		||||
    struct SoundIoOsCond *cond = allocate<SoundIoOsCond>(1);
 | 
			
		||||
    struct SoundIoOsCond *cond = ALLOCATE(struct SoundIoOsCond, 1);
 | 
			
		||||
 | 
			
		||||
    if (!cond) {
 | 
			
		||||
        soundio_os_cond_destroy(cond);
 | 
			
		||||
| 
						 | 
				
			
			@ -558,7 +565,7 @@ static int internal_init(void) {
 | 
			
		|||
    GetSystemInfo(&win32_system_info);
 | 
			
		||||
    page_size = win32_system_info.dwAllocationGranularity;
 | 
			
		||||
#else
 | 
			
		||||
    page_size = getpagesize();
 | 
			
		||||
    page_size = sysconf(_SC_PAGESIZE);
 | 
			
		||||
#if defined(__MACH__)
 | 
			
		||||
    host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -581,7 +588,7 @@ int soundio_os_init(void) {
 | 
			
		|||
    if ((err = internal_init()))
 | 
			
		||||
        return err;
 | 
			
		||||
 | 
			
		||||
    if (!InitOnceComplete(&win32_init_once, INIT_ONCE_ASYNC, nullptr))
 | 
			
		||||
    if (!InitOnceComplete(&win32_init_once, INIT_ONCE_ASYNC, NULL))
 | 
			
		||||
        return SoundIoErrorSystemResources;
 | 
			
		||||
#else
 | 
			
		||||
    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);
 | 
			
		||||
    assert(!err);
 | 
			
		||||
#endif
 | 
			
		||||
    mem->address = nullptr;
 | 
			
		||||
    mem->address = NULL;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -5,8 +5,8 @@
 | 
			
		|||
 * See http://opensource.org/licenses/MIT
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "pulseaudio.hpp"
 | 
			
		||||
#include "soundio.hpp"
 | 
			
		||||
#include "pulseaudio.h"
 | 
			
		||||
#include "soundio_private.h"
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -15,19 +15,19 @@
 | 
			
		|||
static void subscribe_callback(pa_context *context,
 | 
			
		||||
        pa_subscription_event_type_t event_bits, uint32_t index, void *userdata)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)userdata;
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)userdata;
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    sipa->device_scan_queued = true;
 | 
			
		||||
    pa_threaded_mainloop_signal(sipa->main_loop, 0);
 | 
			
		||||
    soundio->on_events_signal(soundio);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int subscribe_to_events(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
static int subscribe_to_events(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    pa_subscription_mask_t events = (pa_subscription_mask_t)(
 | 
			
		||||
            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)
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
    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) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)userdata;
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)userdata;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
 | 
			
		||||
    switch (pa_context_get_state(context)) {
 | 
			
		||||
    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) {
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
static void destroy_pa(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
 | 
			
		||||
    if (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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
    case PA_SAMPLE_U8:          return SoundIoFormatU8;
 | 
			
		||||
    case PA_SAMPLE_S16LE:       return SoundIoFormatS16LE;
 | 
			
		||||
| 
						 | 
				
			
			@ -113,7 +113,7 @@ static SoundIoFormat from_pulseaudio_format(pa_sample_spec sample_spec) {
 | 
			
		|||
    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) {
 | 
			
		||||
    case PA_CHANNEL_POSITION_MONO: return SoundIoChannelIdFrontCenter;
 | 
			
		||||
    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;
 | 
			
		||||
    for (int i = 0; i < channel_map.channels; i += 1) {
 | 
			
		||||
        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();
 | 
			
		||||
    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)) {
 | 
			
		||||
            channel_layout->name = builtin_layout->name;
 | 
			
		||||
            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->layouts = allocate<SoundIoChannelLayout>(device->layout_count);
 | 
			
		||||
    device->layouts = ALLOCATE(struct SoundIoChannelLayout, device->layout_count);
 | 
			
		||||
    if (!device->layouts)
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int set_all_device_formats(SoundIoDevice *device) {
 | 
			
		||||
static int set_all_device_formats(struct SoundIoDevice *device) {
 | 
			
		||||
    device->format_count = 9;
 | 
			
		||||
    device->formats = allocate<SoundIoFormat>(device->format_count);
 | 
			
		||||
    device->formats = ALLOCATE(enum SoundIoFormat, device->format_count);
 | 
			
		||||
    if (!device->formats)
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
    device->formats[0] = SoundIoFormatU8;
 | 
			
		||||
| 
						 | 
				
			
			@ -199,10 +199,10 @@ static int set_all_device_formats(SoundIoDevice *device) {
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int perform_operation(SoundIoPrivate *si, pa_operation *op) {
 | 
			
		||||
static int perform_operation(struct SoundIoPrivate *si, pa_operation *op) {
 | 
			
		||||
    if (!op)
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    for (;;) {
 | 
			
		||||
        switch (pa_operation_get_state(op)) {
 | 
			
		||||
        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) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)userdata;
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)userdata;
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    int err;
 | 
			
		||||
    if (eol) {
 | 
			
		||||
        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)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1);
 | 
			
		||||
    struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
 | 
			
		||||
    if (!dev) {
 | 
			
		||||
        sipa->device_query_err = SoundIoErrorNoMem;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    SoundIoDevice *device = &dev->pub;
 | 
			
		||||
    struct SoundIoDevice *device = &dev->pub;
 | 
			
		||||
 | 
			
		||||
    device->ref_count = 1;
 | 
			
		||||
    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.
 | 
			
		||||
    device->sample_rate_count = 1;
 | 
			
		||||
    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].max = max(SOUNDIO_MAX_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 = soundio_int_max(SOUNDIO_MAX_SAMPLE_RATE, device->sample_rate_current);
 | 
			
		||||
 | 
			
		||||
    device->current_format = from_pulseaudio_format(info->sample_spec);
 | 
			
		||||
    // 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;
 | 
			
		||||
 | 
			
		||||
    if (sipa->current_devices_info->output_devices.append(device)) {
 | 
			
		||||
    if (SoundIoListDevicePtr_append(&sipa->current_devices_info->output_devices, device)) {
 | 
			
		||||
        soundio_device_unref(device);
 | 
			
		||||
        sipa->device_query_err = SoundIoErrorNoMem;
 | 
			
		||||
        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) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)userdata;
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)userdata;
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    int err;
 | 
			
		||||
 | 
			
		||||
    if (eol) {
 | 
			
		||||
| 
						 | 
				
			
			@ -294,12 +294,12 @@ static void source_info_callback(pa_context *pulse_context, const pa_source_info
 | 
			
		|||
    if (sipa->device_query_err)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1);
 | 
			
		||||
    struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
 | 
			
		||||
    if (!dev) {
 | 
			
		||||
        sipa->device_query_err = SoundIoErrorNoMem;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    SoundIoDevice *device = &dev->pub;
 | 
			
		||||
    struct SoundIoDevice *device = &dev->pub;
 | 
			
		||||
 | 
			
		||||
    device->ref_count = 1;
 | 
			
		||||
    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.
 | 
			
		||||
    device->sample_rate_count = 1;
 | 
			
		||||
    device->sample_rates = &dev->prealloc_sample_rate_range;
 | 
			
		||||
    device->sample_rates[0].min = min(8000, device->sample_rate_current);
 | 
			
		||||
    device->sample_rates[0].max = max(5644800, 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 = soundio_int_max(SOUNDIO_MAX_SAMPLE_RATE, device->sample_rate_current);
 | 
			
		||||
 | 
			
		||||
    device->current_format = from_pulseaudio_format(info->sample_spec);
 | 
			
		||||
    // 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;
 | 
			
		||||
 | 
			
		||||
    if (sipa->current_devices_info->input_devices.append(device)) {
 | 
			
		||||
    if (SoundIoListDevicePtr_append(&sipa->current_devices_info->input_devices, device)) {
 | 
			
		||||
        soundio_device_unref(device);
 | 
			
		||||
        sipa->device_query_err = SoundIoErrorNoMem;
 | 
			
		||||
        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) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)userdata;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)userdata;
 | 
			
		||||
    assert(si);
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
 | 
			
		||||
    assert(!sipa->default_sink_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
 | 
			
		||||
static void cleanup_refresh_devices(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
static void cleanup_refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
 | 
			
		||||
    soundio_destroy_devices_info(sipa->current_devices_info);
 | 
			
		||||
    sipa->current_devices_info = nullptr;
 | 
			
		||||
    sipa->current_devices_info = NULL;
 | 
			
		||||
 | 
			
		||||
    free(sipa->default_sink_name);
 | 
			
		||||
    sipa->default_sink_name = nullptr;
 | 
			
		||||
    sipa->default_sink_name = NULL;
 | 
			
		||||
 | 
			
		||||
    free(sipa->default_source_name);
 | 
			
		||||
    sipa->default_source_name = nullptr;
 | 
			
		||||
    sipa->default_source_name = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// call this while holding the main loop lock
 | 
			
		||||
static int refresh_devices(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
static int refresh_devices(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
        return SoundIoErrorNoMem;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -414,7 +414,9 @@ static int refresh_devices(SoundIoPrivate *si) {
 | 
			
		|||
    if (sipa->current_devices_info->input_devices.length > 0) {
 | 
			
		||||
        sipa->current_devices_info->default_input_index = 0;
 | 
			
		||||
        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);
 | 
			
		||||
            if (strcmp(device->id, sipa->default_source_name) == 0) {
 | 
			
		||||
                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) {
 | 
			
		||||
        sipa->current_devices_info->default_output_index = 0;
 | 
			
		||||
        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);
 | 
			
		||||
            if (strcmp(device->id, sipa->default_sink_name) == 0) {
 | 
			
		||||
                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);
 | 
			
		||||
    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);
 | 
			
		||||
    soundio->on_events_signal(soundio);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void my_flush_events(SoundIoPrivate *si, bool wait) {
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
static void my_flush_events(struct SoundIoPrivate *si, bool wait) {
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
 | 
			
		||||
    bool change = false;
 | 
			
		||||
    bool cb_shutdown = false;
 | 
			
		||||
    SoundIoDevicesInfo *old_devices_info = nullptr;
 | 
			
		||||
    struct SoundIoDevicesInfo *old_devices_info = NULL;
 | 
			
		||||
 | 
			
		||||
    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) {
 | 
			
		||||
        old_devices_info = si->safe_devices_info;
 | 
			
		||||
        si->safe_devices_info = sipa->ready_devices_info;
 | 
			
		||||
        sipa->ready_devices_info = nullptr;
 | 
			
		||||
        sipa->ready_devices_info = NULL;
 | 
			
		||||
        change = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -481,25 +485,25 @@ static void my_flush_events(SoundIoPrivate *si, bool wait) {
 | 
			
		|||
    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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void wait_events_pa(SoundIoPrivate *si) {
 | 
			
		||||
static void wait_events_pa(struct SoundIoPrivate *si) {
 | 
			
		||||
    my_flush_events(si, false);
 | 
			
		||||
    my_flush_events(si, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void wakeup_pa(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
static void wakeup_pa(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    pa_threaded_mainloop_lock(sipa->main_loop);
 | 
			
		||||
    pa_threaded_mainloop_signal(sipa->main_loop, 0);
 | 
			
		||||
    pa_threaded_mainloop_unlock(sipa->main_loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void force_device_scan_pa(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
static void force_device_scan_pa(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    pa_threaded_mainloop_lock(sipa->main_loop);
 | 
			
		||||
    sipa->device_scan_queued = true;
 | 
			
		||||
    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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static pa_sample_format_t to_pulseaudio_format(SoundIoFormat format) {
 | 
			
		||||
static pa_sample_format_t to_pulseaudio_format(enum SoundIoFormat format) {
 | 
			
		||||
    switch (format) {
 | 
			
		||||
    case SoundIoFormatU8:         return PA_SAMPLE_U8;
 | 
			
		||||
    case SoundIoFormatS16LE:      return PA_SAMPLE_S16LE;
 | 
			
		||||
| 
						 | 
				
			
			@ -534,7 +538,7 @@ static pa_sample_format_t to_pulseaudio_format(SoundIoFormat format) {
 | 
			
		|||
    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) {
 | 
			
		||||
    case SoundIoChannelIdFrontLeft: return PA_CHANNEL_POSITION_FRONT_LEFT;
 | 
			
		||||
    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;
 | 
			
		||||
    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) {
 | 
			
		||||
    SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate*) userdata;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    SoundIo *soundio = outstream->device->soundio;
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate*) userdata;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIo *soundio = outstream->device->soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
 | 
			
		||||
    switch (pa_stream_get_state(stream)) {
 | 
			
		||||
        case PA_STREAM_UNCONNECTED:
 | 
			
		||||
        case PA_STREAM_CREATING:
 | 
			
		||||
        case PA_STREAM_TERMINATED:
 | 
			
		||||
            break;
 | 
			
		||||
        case PA_STREAM_READY:
 | 
			
		||||
            ospa->stream_ready = true;
 | 
			
		||||
            SOUNDIO_ATOMIC_STORE(ospa->stream_ready, true);
 | 
			
		||||
            pa_threaded_mainloop_signal(sipa->main_loop, 0);
 | 
			
		||||
            break;
 | 
			
		||||
        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) {
 | 
			
		||||
    SoundIoOutStream *outstream = (SoundIoOutStream*)userdata;
 | 
			
		||||
    struct SoundIoOutStream *outstream = (struct SoundIoOutStream*)userdata;
 | 
			
		||||
    outstream->underflow_callback(outstream);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void playback_stream_write_callback(pa_stream *stream, size_t nbytes, void *userdata) {
 | 
			
		||||
    SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate*)(userdata);
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate*)(userdata);
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    int frame_count = nbytes / outstream->bytes_per_frame;
 | 
			
		||||
    outstream->write_callback(outstream, 0, frame_count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void outstream_destroy_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
 | 
			
		||||
static void outstream_destroy_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    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;
 | 
			
		||||
    if (stream) {
 | 
			
		||||
        pa_threaded_mainloop_lock(sipa->main_loop);
 | 
			
		||||
 | 
			
		||||
        pa_stream_set_write_callback(stream, nullptr, nullptr);
 | 
			
		||||
        pa_stream_set_state_callback(stream, nullptr, nullptr);
 | 
			
		||||
        pa_stream_set_underflow_callback(stream, nullptr, nullptr);
 | 
			
		||||
        pa_stream_set_overflow_callback(stream, nullptr, nullptr);
 | 
			
		||||
        pa_stream_set_write_callback(stream, NULL, NULL);
 | 
			
		||||
        pa_stream_set_state_callback(stream, NULL, NULL);
 | 
			
		||||
        pa_stream_set_underflow_callback(stream, NULL, NULL);
 | 
			
		||||
        pa_stream_set_overflow_callback(stream, NULL, NULL);
 | 
			
		||||
        pa_stream_disconnect(stream);
 | 
			
		||||
 | 
			
		||||
        pa_stream_unref(stream);
 | 
			
		||||
 | 
			
		||||
        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) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)userdata;
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)userdata;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    pa_threaded_mainloop_signal(sipa->main_loop, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
static int outstream_open_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
 | 
			
		||||
    if ((unsigned)outstream->layout.channel_count > PA_CHANNELS_MAX)
 | 
			
		||||
        return SoundIoErrorIncompatibleBackend;
 | 
			
		||||
| 
						 | 
				
			
			@ -661,9 +665,9 @@ static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
 | 
			
		|||
    if (!outstream->name)
 | 
			
		||||
        outstream->name = "SoundIoOutStream";
 | 
			
		||||
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    ospa->stream_ready.store(false);
 | 
			
		||||
    ospa->clear_buffer_flag.test_and_set();
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    SOUNDIO_ATOMIC_STORE(ospa->stream_ready, false);
 | 
			
		||||
    atomic_flag_test_and_set(&ospa->clear_buffer_flag);
 | 
			
		||||
 | 
			
		||||
    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,
 | 
			
		||||
            outstream->device->id, &ospa->buffer_attr,
 | 
			
		||||
            flags, nullptr, nullptr);
 | 
			
		||||
            flags, NULL, NULL);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        pa_threaded_mainloop_unlock(sipa->main_loop);
 | 
			
		||||
        return SoundIoErrorOpeningDevice;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while (!ospa->stream_ready.load())
 | 
			
		||||
    while (!SOUNDIO_ATOMIC_LOAD(ospa->stream_ready))
 | 
			
		||||
        pa_threaded_mainloop_wait(sipa->main_loop);
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_start_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
 | 
			
		||||
static int outstream_start_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
    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) {
 | 
			
		||||
        pa_threaded_mainloop_unlock(sipa->main_loop);
 | 
			
		||||
        return SoundIoErrorStreaming;
 | 
			
		||||
| 
						 | 
				
			
			@ -753,11 +757,11 @@ static int outstream_start_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_begin_write_pa(SoundIoPrivate *si,
 | 
			
		||||
        SoundIoOutStreamPrivate *os, SoundIoChannelArea **out_areas, int *frame_count)
 | 
			
		||||
static int outstream_begin_write_pa(struct SoundIoPrivate *si,
 | 
			
		||||
        struct SoundIoOutStreamPrivate *os, struct SoundIoChannelArea **out_areas, int *frame_count)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
 | 
			
		||||
    pa_stream *stream = ospa->stream;
 | 
			
		||||
 | 
			
		||||
    ospa->write_byte_count = *frame_count * outstream->bytes_per_frame;
 | 
			
		||||
| 
						 | 
				
			
			@ -775,28 +779,28 @@ static int outstream_begin_write_pa(SoundIoPrivate *si,
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_end_write_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
 | 
			
		||||
static int outstream_end_write_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
 | 
			
		||||
    struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
 | 
			
		||||
    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;
 | 
			
		||||
    if (pa_stream_write(stream, ospa->write_ptr, ospa->write_byte_count, nullptr, 0, seek_mode))
 | 
			
		||||
    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, NULL, 0, seek_mode))
 | 
			
		||||
        return SoundIoErrorStreaming;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_clear_buffer_pa(SoundIoPrivate *si,
 | 
			
		||||
        SoundIoOutStreamPrivate *os)
 | 
			
		||||
static int outstream_clear_buffer_pa(struct SoundIoPrivate *si,
 | 
			
		||||
        struct SoundIoOutStreamPrivate *os)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
 | 
			
		||||
    ospa->clear_buffer_flag.clear();
 | 
			
		||||
    struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
 | 
			
		||||
    atomic_flag_clear(&ospa->clear_buffer_flag);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_pause_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, bool pause) {
 | 
			
		||||
    SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
static int outstream_pause_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
 | 
			
		||||
    struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
 | 
			
		||||
    if (!pa_threaded_mainloop_in_thread(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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int outstream_get_latency_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, double *out_latency) {
 | 
			
		||||
    SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
 | 
			
		||||
static int outstream_get_latency_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, double *out_latency) {
 | 
			
		||||
    struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
 | 
			
		||||
 | 
			
		||||
    int err;
 | 
			
		||||
    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) {
 | 
			
		||||
    SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate*)userdata;
 | 
			
		||||
    SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    SoundIo *soundio = instream->device->soundio;
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate*)userdata;
 | 
			
		||||
    struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIo *soundio = instream->device->soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    switch (pa_stream_get_state(stream)) {
 | 
			
		||||
        case PA_STREAM_UNCONNECTED:
 | 
			
		||||
        case PA_STREAM_CREATING:
 | 
			
		||||
        case PA_STREAM_TERMINATED:
 | 
			
		||||
            break;
 | 
			
		||||
        case PA_STREAM_READY:
 | 
			
		||||
            ispa->stream_ready = true;
 | 
			
		||||
            SOUNDIO_ATOMIC_STORE(ispa->stream_ready, true);
 | 
			
		||||
            pa_threaded_mainloop_signal(sipa->main_loop, 0);
 | 
			
		||||
            break;
 | 
			
		||||
        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) {
 | 
			
		||||
    SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate*)userdata;
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate*)userdata;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    assert(nbytes % instream->bytes_per_frame == 0);
 | 
			
		||||
    assert(nbytes > 0);
 | 
			
		||||
    int available_frame_count = nbytes / instream->bytes_per_frame;
 | 
			
		||||
    instream->read_callback(instream, 0, available_frame_count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void instream_destroy_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
 | 
			
		||||
    SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
static void instream_destroy_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
 | 
			
		||||
    struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    pa_stream *stream = ispa->stream;
 | 
			
		||||
    if (stream) {
 | 
			
		||||
        pa_threaded_mainloop_lock(sipa->main_loop);
 | 
			
		||||
 | 
			
		||||
        pa_stream_set_state_callback(stream, nullptr, nullptr);
 | 
			
		||||
        pa_stream_set_read_callback(stream, nullptr, nullptr);
 | 
			
		||||
        pa_stream_set_state_callback(stream, NULL, NULL);
 | 
			
		||||
        pa_stream_set_read_callback(stream, NULL, NULL);
 | 
			
		||||
        pa_stream_disconnect(stream);
 | 
			
		||||
        pa_stream_unref(stream);
 | 
			
		||||
 | 
			
		||||
        pa_threaded_mainloop_unlock(sipa->main_loop);
 | 
			
		||||
 | 
			
		||||
        ispa->stream = nullptr;
 | 
			
		||||
        ispa->stream = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_open_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
 | 
			
		||||
    SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
static int instream_open_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
 | 
			
		||||
    struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
 | 
			
		||||
    if ((unsigned)instream->layout.channel_count > PA_CHANNELS_MAX)
 | 
			
		||||
        return SoundIoErrorIncompatibleBackend;
 | 
			
		||||
    if (!instream->name)
 | 
			
		||||
        instream->name = "SoundIoInStream";
 | 
			
		||||
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    ispa->stream_ready = false;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    SOUNDIO_ATOMIC_STORE(ispa->stream_ready, false);
 | 
			
		||||
 | 
			
		||||
    pa_threaded_mainloop_lock(sipa->main_loop);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -931,10 +935,10 @@ static int instream_open_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_start_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
static int instream_start_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
    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);
 | 
			
		||||
| 
						 | 
				
			
			@ -947,7 +951,7 @@ static int instream_start_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
 | 
			
		|||
        return SoundIoErrorOpeningDevice;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while (!ispa->stream_ready)
 | 
			
		||||
    while (!SOUNDIO_ATOMIC_LOAD(ispa->stream_ready))
 | 
			
		||||
        pa_threaded_mainloop_wait(sipa->main_loop);
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_begin_read_pa(SoundIoPrivate *si,
 | 
			
		||||
        SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count)
 | 
			
		||||
static int instream_begin_read_pa(struct SoundIoPrivate *si,
 | 
			
		||||
        struct SoundIoInStreamPrivate *is, struct SoundIoChannelArea **out_areas, int *frame_count)
 | 
			
		||||
{
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
 | 
			
		||||
    pa_stream *stream = ispa->stream;
 | 
			
		||||
 | 
			
		||||
    assert(ispa->stream_ready);
 | 
			
		||||
    assert(SOUNDIO_ATOMIC_LOAD(ispa->stream_ready));
 | 
			
		||||
 | 
			
		||||
    if (!ispa->peek_buf) {
 | 
			
		||||
        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
 | 
			
		||||
        if (!ispa->peek_buf) {
 | 
			
		||||
            *frame_count = ispa->peek_buf_frames_left;
 | 
			
		||||
            *out_areas = nullptr;
 | 
			
		||||
            *out_areas = NULL;
 | 
			
		||||
            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;
 | 
			
		||||
    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;
 | 
			
		||||
| 
						 | 
				
			
			@ -997,9 +1001,9 @@ static int instream_begin_read_pa(SoundIoPrivate *si,
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_end_read_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
 | 
			
		||||
static int instream_end_read_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
 | 
			
		||||
    pa_stream *stream = ispa->stream;
 | 
			
		||||
 | 
			
		||||
    // 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 (pa_stream_drop(stream))
 | 
			
		||||
            return SoundIoErrorStreaming;
 | 
			
		||||
        ispa->peek_buf = nullptr;
 | 
			
		||||
        ispa->peek_buf = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_pause_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is, bool pause) {
 | 
			
		||||
    SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
static int instream_pause_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
 | 
			
		||||
    struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
 | 
			
		||||
    if (!pa_threaded_mainloop_in_thread(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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int instream_get_latency_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is, double *out_latency) {
 | 
			
		||||
    SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
 | 
			
		||||
static int instream_get_latency_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, double *out_latency) {
 | 
			
		||||
    struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
 | 
			
		||||
 | 
			
		||||
    int err;
 | 
			
		||||
    pa_usec_t r_usec;
 | 
			
		||||
| 
						 | 
				
			
			@ -1057,9 +1061,9 @@ static int instream_get_latency_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *i
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int soundio_pulseaudio_init(SoundIoPrivate *si) {
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
int soundio_pulseaudio_init(struct SoundIoPrivate *si) {
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
 | 
			
		||||
 | 
			
		||||
    sipa->device_scan_queued = true;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5,17 +5,18 @@
 | 
			
		|||
 * See http://opensource.org/licenses/MIT
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef SOUNDIO_PULSEAUDIO_HPP
 | 
			
		||||
#define SOUNDIO_PULSEAUDIO_HPP
 | 
			
		||||
#ifndef SOUNDIO_PULSEAUDIO_H
 | 
			
		||||
#define SOUNDIO_PULSEAUDIO_H
 | 
			
		||||
 | 
			
		||||
#include "soundio_private.h"
 | 
			
		||||
#include "atomics.hpp"
 | 
			
		||||
#include "soundio_internal.h"
 | 
			
		||||
#include "atomics.h"
 | 
			
		||||
 | 
			
		||||
#include <pulse/pulseaudio.h>
 | 
			
		||||
 | 
			
		||||
struct SoundIoPrivate;
 | 
			
		||||
int soundio_pulseaudio_init(struct SoundIoPrivate *si);
 | 
			
		||||
 | 
			
		||||
struct SoundIoDevicePulseAudio { };
 | 
			
		||||
struct SoundIoDevicePulseAudio { int make_the_struct_not_empty; };
 | 
			
		||||
 | 
			
		||||
struct SoundIoPulseAudio {
 | 
			
		||||
    int device_query_err;
 | 
			
		||||
| 
						 | 
				
			
			@ -41,24 +42,24 @@ struct SoundIoPulseAudio {
 | 
			
		|||
 | 
			
		||||
struct SoundIoOutStreamPulseAudio {
 | 
			
		||||
    pa_stream *stream;
 | 
			
		||||
    atomic_bool stream_ready;
 | 
			
		||||
    struct SoundIoAtomicBool stream_ready;
 | 
			
		||||
    pa_buffer_attr buffer_attr;
 | 
			
		||||
    char *write_ptr;
 | 
			
		||||
    size_t write_byte_count;
 | 
			
		||||
    atomic_flag clear_buffer_flag;
 | 
			
		||||
    SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
    struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SoundIoInStreamPulseAudio {
 | 
			
		||||
    pa_stream *stream;
 | 
			
		||||
    atomic_bool stream_ready;
 | 
			
		||||
    struct SoundIoAtomicBool stream_ready;
 | 
			
		||||
    pa_buffer_attr buffer_attr;
 | 
			
		||||
    char *peek_buf;
 | 
			
		||||
    size_t peek_buf_index;
 | 
			
		||||
    size_t peek_buf_size;
 | 
			
		||||
    int peek_buf_frames_left;
 | 
			
		||||
    int read_frame_count;
 | 
			
		||||
    SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
    struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -5,25 +5,25 @@
 | 
			
		|||
 * See http://opensource.org/licenses/MIT
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "ring_buffer.hpp"
 | 
			
		||||
#include "soundio.hpp"
 | 
			
		||||
#include "util.hpp"
 | 
			
		||||
#include "ring_buffer.h"
 | 
			
		||||
#include "soundio_private.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
    if (!rb) {
 | 
			
		||||
        soundio_ring_buffer_destroy(rb);
 | 
			
		||||
        return nullptr;
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (soundio_ring_buffer_init(rb, requested_capacity)) {
 | 
			
		||||
        soundio_ring_buffer_destroy(rb);
 | 
			
		||||
        return nullptr;
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return rb;
 | 
			
		||||
| 
						 | 
				
			
			@ -43,25 +43,31 @@ int soundio_ring_buffer_capacity(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) {
 | 
			
		||||
    rb->write_offset += count;
 | 
			
		||||
    SOUNDIO_ATOMIC_FETCH_ADD(rb->write_offset, count);
 | 
			
		||||
    assert(soundio_ring_buffer_fill_count(rb) >= 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
    rb->read_offset += count;
 | 
			
		||||
    SOUNDIO_ATOMIC_FETCH_ADD(rb->read_offset, count);
 | 
			
		||||
    assert(soundio_ring_buffer_fill_count(rb) >= 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 <= rb->capacity);
 | 
			
		||||
    return count;
 | 
			
		||||
| 
						 | 
				
			
			@ -72,15 +78,16 @@ int soundio_ring_buffer_free_count(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 err;
 | 
			
		||||
    if ((err = soundio_os_init_mirrored_memory(&rb->mem, requested_capacity)))
 | 
			
		||||
        return err;
 | 
			
		||||
    rb->write_offset = 0;
 | 
			
		||||
    rb->read_offset = 0;
 | 
			
		||||
    SOUNDIO_ATOMIC_STORE(rb->write_offset, 0);
 | 
			
		||||
    SOUNDIO_ATOMIC_STORE(rb->read_offset, 0);
 | 
			
		||||
    rb->capacity = rb->mem.capacity;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -5,16 +5,16 @@
 | 
			
		|||
 * See http://opensource.org/licenses/MIT
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef SOUNDIO_RING_BUFFER_HPP
 | 
			
		||||
#define SOUNDIO_RING_BUFFER_HPP
 | 
			
		||||
#ifndef SOUNDIO_RING_BUFFER_H
 | 
			
		||||
#define SOUNDIO_RING_BUFFER_H
 | 
			
		||||
 | 
			
		||||
#include "atomics.hpp"
 | 
			
		||||
#include "os.h"
 | 
			
		||||
#include "atomics.h"
 | 
			
		||||
 | 
			
		||||
struct SoundIoRingBuffer {
 | 
			
		||||
    SoundIoOsMirroredMemory mem;
 | 
			
		||||
    atomic_long write_offset;
 | 
			
		||||
    atomic_long read_offset;
 | 
			
		||||
    struct SoundIoOsMirroredMemory mem;
 | 
			
		||||
    struct SoundIoAtomicLong write_offset;
 | 
			
		||||
    struct SoundIoAtomicLong read_offset;
 | 
			
		||||
    int capacity;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5,8 +5,8 @@
 | 
			
		|||
 * See http://opensource.org/licenses/MIT
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "soundio.hpp"
 | 
			
		||||
#include "util.hpp"
 | 
			
		||||
#include "soundio_private.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
#include "os.h"
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
static const SoundIoBackend available_backends[] = {
 | 
			
		||||
static const enum SoundIoBackend available_backends[] = {
 | 
			
		||||
#ifdef SOUNDIO_HAVE_JACK
 | 
			
		||||
    SoundIoBackendJack,
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -33,36 +33,40 @@ static const SoundIoBackend available_backends[] = {
 | 
			
		|||
    SoundIoBackendDummy,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int (*backend_init_fns[])(SoundIoPrivate *) = {
 | 
			
		||||
    [SoundIoBackendNone] = nullptr,
 | 
			
		||||
static int (*backend_init_fns[])(struct SoundIoPrivate *) = {
 | 
			
		||||
    [SoundIoBackendNone] = NULL,
 | 
			
		||||
#ifdef SOUNDIO_HAVE_JACK
 | 
			
		||||
    [SoundIoBackendJack] = soundio_jack_init,
 | 
			
		||||
#else
 | 
			
		||||
    [SoundIoBackendJack] = nullptr,
 | 
			
		||||
    [SoundIoBackendJack] = NULL,
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef SOUNDIO_HAVE_PULSEAUDIO
 | 
			
		||||
    [SoundIoBackendPulseAudio] = soundio_pulseaudio_init,
 | 
			
		||||
#else
 | 
			
		||||
    [SoundIoBackendPulseAudio] = nullptr,
 | 
			
		||||
    [SoundIoBackendPulseAudio] = NULL,
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef SOUNDIO_HAVE_ALSA
 | 
			
		||||
    [SoundIoBackendAlsa] = soundio_alsa_init,
 | 
			
		||||
#else
 | 
			
		||||
    [SoundIoBackendAlsa] = nullptr,
 | 
			
		||||
    [SoundIoBackendAlsa] = NULL,
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef SOUNDIO_HAVE_COREAUDIO
 | 
			
		||||
    [SoundIoBackendCoreAudio] = soundio_coreaudio_init,
 | 
			
		||||
#else
 | 
			
		||||
    [SoundIoBackendCoreAudio] = nullptr,
 | 
			
		||||
    [SoundIoBackendCoreAudio] = NULL,
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef SOUNDIO_HAVE_WASAPI
 | 
			
		||||
    [SoundIoBackendWasapi] = soundio_wasapi_init,
 | 
			
		||||
#else
 | 
			
		||||
    [SoundIoBackendWasapi] = nullptr,
 | 
			
		||||
    [SoundIoBackendWasapi] = NULL,
 | 
			
		||||
#endif
 | 
			
		||||
    [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) {
 | 
			
		||||
    switch ((enum SoundIoError)error) {
 | 
			
		||||
        case SoundIoErrorNone: return "(no error)";
 | 
			
		||||
| 
						 | 
				
			
			@ -153,23 +157,23 @@ const char *soundio_backend_name(enum SoundIoBackend backend) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void soundio_destroy(struct SoundIo *soundio) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
 | 
			
		||||
    soundio_disconnect(soundio);
 | 
			
		||||
 | 
			
		||||
    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_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));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static atomic_flag rtprio_seen = ATOMIC_FLAG_INIT;
 | 
			
		||||
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, "See "
 | 
			
		||||
            "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) {
 | 
			
		||||
    int err;
 | 
			
		||||
    if ((err = soundio_os_init()))
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    struct SoundIoPrivate *si = allocate<SoundIoPrivate>(1);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    struct SoundIoPrivate *si = ALLOCATE(struct SoundIoPrivate, 1);
 | 
			
		||||
    if (!si)
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    SoundIo *soundio = &si->pub;
 | 
			
		||||
        return NULL;
 | 
			
		||||
    struct SoundIo *soundio = &si->pub;
 | 
			
		||||
    soundio->on_devices_change = do_nothing_cb;
 | 
			
		||||
    soundio->on_backend_disconnect = default_backend_disconnect_cb;
 | 
			
		||||
    soundio->on_events_signal = do_nothing_cb;
 | 
			
		||||
| 
						 | 
				
			
			@ -197,8 +201,8 @@ struct SoundIo *soundio_create(void) {
 | 
			
		|||
int soundio_connect(struct SoundIo *soundio) {
 | 
			
		||||
    int err = 0;
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < array_length(available_backends); i += 1) {
 | 
			
		||||
        SoundIoBackend backend = available_backends[i];
 | 
			
		||||
    for (int i = 0; i < ARRAY_LENGTH(available_backends); i += 1) {
 | 
			
		||||
        enum SoundIoBackend backend = available_backends[i];
 | 
			
		||||
        err = soundio_connect_backend(soundio, backend);
 | 
			
		||||
        if (!err)
 | 
			
		||||
            return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -209,8 +213,8 @@ int soundio_connect(struct SoundIo *soundio) {
 | 
			
		|||
    return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int soundio_connect_backend(SoundIo *soundio, SoundIoBackend backend) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
int soundio_connect_backend(struct SoundIo *soundio, enum SoundIoBackend backend) {
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
 | 
			
		||||
    if (soundio->current_backend)
 | 
			
		||||
        return SoundIoErrorInvalid;
 | 
			
		||||
| 
						 | 
				
			
			@ -218,7 +222,7 @@ int soundio_connect_backend(SoundIo *soundio, SoundIoBackend backend) {
 | 
			
		|||
    if (backend <= 0 || backend > SoundIoBackendDummy)
 | 
			
		||||
        return SoundIoErrorInvalid;
 | 
			
		||||
 | 
			
		||||
    int (*fn)(SoundIoPrivate *) = backend_init_fns[backend];
 | 
			
		||||
    int (*fn)(struct SoundIoPrivate *) = backend_init_fns[backend];
 | 
			
		||||
 | 
			
		||||
    if (!fn)
 | 
			
		||||
        return SoundIoErrorBackendUnavailable;
 | 
			
		||||
| 
						 | 
				
			
			@ -234,52 +238,52 @@ int soundio_connect_backend(SoundIo *soundio, SoundIoBackend backend) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void soundio_disconnect(struct SoundIo *soundio) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
 | 
			
		||||
    if (!si)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (si->destroy)
 | 
			
		||||
        si->destroy(si);
 | 
			
		||||
    memset(&si->backend_data, 0, sizeof(SoundIoBackendData));
 | 
			
		||||
    memset(&si->backend_data, 0, sizeof(union SoundIoBackendData));
 | 
			
		||||
 | 
			
		||||
    soundio->current_backend = SoundIoBackendNone;
 | 
			
		||||
 | 
			
		||||
    soundio_destroy_devices_info(si->safe_devices_info);
 | 
			
		||||
    si->safe_devices_info = nullptr;
 | 
			
		||||
    si->safe_devices_info = NULL;
 | 
			
		||||
 | 
			
		||||
    si->destroy = nullptr;
 | 
			
		||||
    si->flush_events = nullptr;
 | 
			
		||||
    si->wait_events = nullptr;
 | 
			
		||||
    si->wakeup = nullptr;
 | 
			
		||||
    si->force_device_scan = nullptr;
 | 
			
		||||
    si->destroy = NULL;
 | 
			
		||||
    si->flush_events = NULL;
 | 
			
		||||
    si->wait_events = NULL;
 | 
			
		||||
    si->wakeup = NULL;
 | 
			
		||||
    si->force_device_scan = NULL;
 | 
			
		||||
 | 
			
		||||
    si->outstream_open = nullptr;
 | 
			
		||||
    si->outstream_destroy = nullptr;
 | 
			
		||||
    si->outstream_start = nullptr;
 | 
			
		||||
    si->outstream_begin_write = nullptr;
 | 
			
		||||
    si->outstream_end_write = nullptr;
 | 
			
		||||
    si->outstream_clear_buffer = nullptr;
 | 
			
		||||
    si->outstream_pause = nullptr;
 | 
			
		||||
    si->outstream_get_latency = nullptr;
 | 
			
		||||
    si->outstream_open = NULL;
 | 
			
		||||
    si->outstream_destroy = NULL;
 | 
			
		||||
    si->outstream_start = NULL;
 | 
			
		||||
    si->outstream_begin_write = NULL;
 | 
			
		||||
    si->outstream_end_write = NULL;
 | 
			
		||||
    si->outstream_clear_buffer = NULL;
 | 
			
		||||
    si->outstream_pause = NULL;
 | 
			
		||||
    si->outstream_get_latency = NULL;
 | 
			
		||||
 | 
			
		||||
    si->instream_open = nullptr;
 | 
			
		||||
    si->instream_destroy = nullptr;
 | 
			
		||||
    si->instream_start = nullptr;
 | 
			
		||||
    si->instream_begin_read = nullptr;
 | 
			
		||||
    si->instream_end_read = nullptr;
 | 
			
		||||
    si->instream_pause = nullptr;
 | 
			
		||||
    si->instream_get_latency = nullptr;
 | 
			
		||||
    si->instream_open = NULL;
 | 
			
		||||
    si->instream_destroy = NULL;
 | 
			
		||||
    si->instream_start = NULL;
 | 
			
		||||
    si->instream_begin_read = NULL;
 | 
			
		||||
    si->instream_end_read = NULL;
 | 
			
		||||
    si->instream_pause = NULL;
 | 
			
		||||
    si->instream_get_latency = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void soundio_flush_events(struct SoundIo *soundio) {
 | 
			
		||||
    assert(soundio->current_backend != SoundIoBackendNone);
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    si->flush_events(si);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int soundio_input_device_count(struct SoundIo *soundio) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
 | 
			
		||||
    assert(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) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
 | 
			
		||||
    assert(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) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
 | 
			
		||||
    assert(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) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
 | 
			
		||||
    assert(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) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
 | 
			
		||||
    assert(soundio->current_backend != SoundIoBackendNone);
 | 
			
		||||
    if (soundio->current_backend == SoundIoBackendNone)
 | 
			
		||||
        return nullptr;
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    assert(si->safe_devices_info);
 | 
			
		||||
    if (!si->safe_devices_info)
 | 
			
		||||
        return nullptr;
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    assert(index >= 0);
 | 
			
		||||
    assert(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);
 | 
			
		||||
    return device;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
    if (soundio->current_backend == SoundIoBackendNone)
 | 
			
		||||
        return nullptr;
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    assert(si->safe_devices_info);
 | 
			
		||||
    if (!si->safe_devices_info)
 | 
			
		||||
        return nullptr;
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    assert(index >= 0);
 | 
			
		||||
    assert(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);
 | 
			
		||||
    return device;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -384,7 +388,7 @@ void soundio_device_unref(struct SoundIoDevice *device) {
 | 
			
		|||
    assert(device->ref_count >= 0);
 | 
			
		||||
 | 
			
		||||
    if (device->ref_count == 0) {
 | 
			
		||||
        SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
 | 
			
		||||
        struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
 | 
			
		||||
        if (dev->destruct)
 | 
			
		||||
            dev->destruct(dev);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -396,7 +400,7 @@ void soundio_device_unref(struct SoundIoDevice *device) {
 | 
			
		|||
        {
 | 
			
		||||
            free(device->sample_rates);
 | 
			
		||||
        }
 | 
			
		||||
        dev->sample_rates.deinit();
 | 
			
		||||
        SoundIoListSampleRateRange_deinit(&dev->sample_rates);
 | 
			
		||||
 | 
			
		||||
        if (device->formats != &dev->prealloc_format)
 | 
			
		||||
            free(device->formats);
 | 
			
		||||
| 
						 | 
				
			
			@ -414,35 +418,35 @@ void soundio_device_ref(struct SoundIoDevice *device) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void soundio_wait_events(struct SoundIo *soundio) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    si->wait_events(si);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void soundio_wakeup(struct SoundIo *soundio) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    si->wakeup(si);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void soundio_force_device_scan(struct SoundIo *soundio) {
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    si->force_device_scan(si);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int soundio_outstream_begin_write(struct SoundIoOutStream *outstream,
 | 
			
		||||
        SoundIoChannelArea **areas, int *frame_count)
 | 
			
		||||
        struct SoundIoChannelArea **areas, int *frame_count)
 | 
			
		||||
{
 | 
			
		||||
    SoundIo *soundio = outstream->device->soundio;
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
 | 
			
		||||
    struct SoundIo *soundio = outstream->device->soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
 | 
			
		||||
    if (*frame_count <= 0)
 | 
			
		||||
        return SoundIoErrorInvalid;
 | 
			
		||||
    return si->outstream_begin_write(si, os, areas, frame_count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int soundio_outstream_end_write(struct SoundIoOutStream *outstream) {
 | 
			
		||||
    SoundIo *soundio = outstream->device->soundio;
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
 | 
			
		||||
    struct SoundIo *soundio = outstream->device->soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
 | 
			
		||||
    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) { }
 | 
			
		||||
 | 
			
		||||
struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device) {
 | 
			
		||||
    SoundIoOutStreamPrivate *os = allocate<SoundIoOutStreamPrivate>(1);
 | 
			
		||||
    SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = ALLOCATE(struct SoundIoOutStreamPrivate, 1);
 | 
			
		||||
    struct SoundIoOutStream *outstream = &os->pub;
 | 
			
		||||
 | 
			
		||||
    if (!os)
 | 
			
		||||
        return nullptr;
 | 
			
		||||
        return NULL;
 | 
			
		||||
    if (!device)
 | 
			
		||||
        return nullptr;
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    outstream->device = device;
 | 
			
		||||
    soundio_device_ref(device);
 | 
			
		||||
| 
						 | 
				
			
			@ -471,7 +475,7 @@ struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
int soundio_outstream_open(struct SoundIoOutStream *outstream) {
 | 
			
		||||
    SoundIoDevice *device = outstream->device;
 | 
			
		||||
    struct SoundIoDevice *device = outstream->device;
 | 
			
		||||
 | 
			
		||||
    if (device->aim != SoundIoDeviceAimOutput)
 | 
			
		||||
        return SoundIoErrorInvalid;
 | 
			
		||||
| 
						 | 
				
			
			@ -491,29 +495,29 @@ int soundio_outstream_open(struct SoundIoOutStream *outstream) {
 | 
			
		|||
        return SoundIoErrorInvalid;
 | 
			
		||||
 | 
			
		||||
    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];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!outstream->sample_rate)
 | 
			
		||||
        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_sample = soundio_get_bytes_per_sample(outstream->format);
 | 
			
		||||
 | 
			
		||||
    SoundIo *soundio = device->soundio;
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIo *soundio = device->soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    return si->outstream_open(si, os);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void soundio_outstream_destroy(SoundIoOutStream *outstream) {
 | 
			
		||||
void soundio_outstream_destroy(struct SoundIoOutStream *outstream) {
 | 
			
		||||
    if (!outstream)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
 | 
			
		||||
    SoundIo *soundio = outstream->device->soundio;
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
 | 
			
		||||
    struct SoundIo *soundio = outstream->device->soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
 | 
			
		||||
    if (si->outstream_destroy)
 | 
			
		||||
        si->outstream_destroy(si, os);
 | 
			
		||||
| 
						 | 
				
			
			@ -523,30 +527,30 @@ void soundio_outstream_destroy(SoundIoOutStream *outstream) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
int soundio_outstream_start(struct SoundIoOutStream *outstream) {
 | 
			
		||||
    SoundIo *soundio = outstream->device->soundio;
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
 | 
			
		||||
    struct SoundIo *soundio = outstream->device->soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
 | 
			
		||||
    return si->outstream_start(si, os);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int soundio_outstream_pause(struct SoundIoOutStream *outstream, bool pause) {
 | 
			
		||||
    SoundIo *soundio = outstream->device->soundio;
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
 | 
			
		||||
    struct SoundIo *soundio = outstream->device->soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
 | 
			
		||||
    return si->outstream_pause(si, os, pause);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int soundio_outstream_clear_buffer(struct SoundIoOutStream *outstream) {
 | 
			
		||||
    SoundIo *soundio = outstream->device->soundio;
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
 | 
			
		||||
    struct SoundIo *soundio = outstream->device->soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
 | 
			
		||||
    return si->outstream_clear_buffer(si, os);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int soundio_outstream_get_latency(struct SoundIoOutStream *outstream, double *out_latency) {
 | 
			
		||||
    SoundIo *soundio = outstream->device->soundio;
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
 | 
			
		||||
    struct SoundIo *soundio = outstream->device->soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
 | 
			
		||||
    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) { }
 | 
			
		||||
 | 
			
		||||
struct SoundIoInStream *soundio_instream_create(struct SoundIoDevice *device) {
 | 
			
		||||
    SoundIoInStreamPrivate *is = allocate<SoundIoInStreamPrivate>(1);
 | 
			
		||||
    SoundIoInStream *instream = &is->pub;
 | 
			
		||||
    struct SoundIoInStreamPrivate *is = ALLOCATE(struct SoundIoInStreamPrivate, 1);
 | 
			
		||||
    struct SoundIoInStream *instream = &is->pub;
 | 
			
		||||
 | 
			
		||||
    if (!is)
 | 
			
		||||
        return nullptr;
 | 
			
		||||
        return NULL;
 | 
			
		||||
    if (!device)
 | 
			
		||||
        return nullptr;
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    instream->device = device;
 | 
			
		||||
    soundio_device_ref(device);
 | 
			
		||||
| 
						 | 
				
			
			@ -575,7 +579,7 @@ struct SoundIoInStream *soundio_instream_create(struct SoundIoDevice *device) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
int soundio_instream_open(struct SoundIoInStream *instream) {
 | 
			
		||||
    SoundIoDevice *device = instream->device;
 | 
			
		||||
    struct SoundIoDevice *device = instream->device;
 | 
			
		||||
    if (device->aim != SoundIoDeviceAimInput)
 | 
			
		||||
        return SoundIoErrorInvalid;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -594,7 +598,7 @@ int soundio_instream_open(struct SoundIoInStream *instream) {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    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];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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_sample = soundio_get_bytes_per_sample(instream->format);
 | 
			
		||||
    SoundIo *soundio = device->soundio;
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream;
 | 
			
		||||
    struct SoundIo *soundio = device->soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
 | 
			
		||||
    return si->instream_open(si, is);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int soundio_instream_start(struct SoundIoInStream *instream) {
 | 
			
		||||
    SoundIo *soundio = instream->device->soundio;
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream;
 | 
			
		||||
    struct SoundIo *soundio = instream->device->soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
 | 
			
		||||
    return si->instream_start(si, is);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -621,9 +625,9 @@ void soundio_instream_destroy(struct SoundIoInStream *instream) {
 | 
			
		|||
    if (!instream)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream;
 | 
			
		||||
    SoundIo *soundio = instream->device->soundio;
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
 | 
			
		||||
    struct SoundIo *soundio = instream->device->soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
 | 
			
		||||
    if (si->instream_destroy)
 | 
			
		||||
        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) {
 | 
			
		||||
    SoundIo *soundio = instream->device->soundio;
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream;
 | 
			
		||||
    struct SoundIo *soundio = instream->device->soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
 | 
			
		||||
    return si->instream_pause(si, is, pause);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int soundio_instream_begin_read(struct SoundIoInStream *instream,
 | 
			
		||||
        struct SoundIoChannelArea **areas, int *frame_count)
 | 
			
		||||
{
 | 
			
		||||
    SoundIo *soundio = instream->device->soundio;
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream;
 | 
			
		||||
    struct SoundIo *soundio = instream->device->soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
 | 
			
		||||
    return si->instream_begin_read(si, is, areas, frame_count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int soundio_instream_end_read(struct SoundIoInStream *instream) {
 | 
			
		||||
    SoundIo *soundio = instream->device->soundio;
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream;
 | 
			
		||||
    struct SoundIo *soundio = instream->device->soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
 | 
			
		||||
    return si->instream_end_read(si, is);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int soundio_instream_get_latency(struct SoundIoInStream *instream, double *out_latency) {
 | 
			
		||||
    SoundIo *soundio = instream->device->soundio;
 | 
			
		||||
    SoundIoPrivate *si = (SoundIoPrivate *)soundio;
 | 
			
		||||
    SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream;
 | 
			
		||||
    struct SoundIo *soundio = instream->device->soundio;
 | 
			
		||||
    struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
 | 
			
		||||
    struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
 | 
			
		||||
    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)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
        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();
 | 
			
		||||
    devices_info->output_devices.deinit();
 | 
			
		||||
    SoundIoListDevicePtr_deinit(&devices_info->input_devices);
 | 
			
		||||
    SoundIoListDevicePtr_deinit(&devices_info->output_devices);
 | 
			
		||||
 | 
			
		||||
    free(devices_info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool soundio_have_backend(SoundIoBackend backend) {
 | 
			
		||||
bool soundio_have_backend(enum SoundIoBackend backend) {
 | 
			
		||||
    assert(backend > 0);
 | 
			
		||||
    assert(backend <= SoundIoBackendDummy);
 | 
			
		||||
    return backend_init_fns[backend];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool layout_contains(const SoundIoChannelLayout *available_layouts, int available_layouts_count,
 | 
			
		||||
        const SoundIoChannelLayout *target_layout)
 | 
			
		||||
static bool layout_contains(const struct SoundIoChannelLayout *available_layouts, int available_layouts_count,
 | 
			
		||||
        const struct SoundIoChannelLayout *target_layout)
 | 
			
		||||
{
 | 
			
		||||
    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))
 | 
			
		||||
            return true;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -707,16 +711,16 @@ const struct SoundIoChannelLayout *soundio_best_matching_channel_layout(
 | 
			
		|||
        const struct SoundIoChannelLayout *available_layouts, int available_layouts_count)
 | 
			
		||||
{
 | 
			
		||||
    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))
 | 
			
		||||
            return preferred_layout;
 | 
			
		||||
    }
 | 
			
		||||
    return nullptr;
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int compare_layouts(const void *a, const void *b) {
 | 
			
		||||
    const SoundIoChannelLayout *layout_a = *((SoundIoChannelLayout **)a);
 | 
			
		||||
    const SoundIoChannelLayout *layout_b = *((SoundIoChannelLayout **)b);
 | 
			
		||||
    const struct SoundIoChannelLayout *layout_a = *((struct SoundIoChannelLayout **)a);
 | 
			
		||||
    const struct SoundIoChannelLayout *layout_b = *((struct SoundIoChannelLayout **)b);
 | 
			
		||||
    if (layout_a->channel_count > layout_b->channel_count)
 | 
			
		||||
        return -1;
 | 
			
		||||
    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)
 | 
			
		||||
        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) {
 | 
			
		||||
| 
						 | 
				
			
			@ -756,7 +760,7 @@ bool soundio_device_supports_layout(struct SoundIoDevice *device,
 | 
			
		|||
 | 
			
		||||
bool soundio_device_supports_sample_rate(struct SoundIoDevice *device, int sample_rate) {
 | 
			
		||||
    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)
 | 
			
		||||
            return true;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -772,8 +776,8 @@ int soundio_device_nearest_sample_rate(struct SoundIoDevice *device, int sample_
 | 
			
		|||
    int best_rate = -1;
 | 
			
		||||
    int best_delta = -1;
 | 
			
		||||
    for (int i = 0; i < device->sample_rate_count; i += 1) {
 | 
			
		||||
        SoundIoSampleRateRange *range = &device->sample_rates[i];
 | 
			
		||||
        int candidate_rate = clamp(range->min, sample_rate, range->max);
 | 
			
		||||
        struct SoundIoSampleRateRange *range = &device->sample_rates[i];
 | 
			
		||||
        int candidate_rate = soundio_int_clamp(range->min, sample_rate, range->max);
 | 
			
		||||
        if (candidate_rate == sample_rate)
 | 
			
		||||
            return candidate_rate;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										179
									
								
								src/soundio.hpp
									
									
									
									
									
								
							
							
						
						
									
										179
									
								
								src/soundio.hpp
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -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
									
								
							
							
						
						
									
										16
									
								
								src/soundio_internal.h
									
									
									
									
									
										Normal 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
 | 
			
		||||
| 
						 | 
				
			
			@ -8,9 +8,177 @@
 | 
			
		|||
#ifndef SOUNDIO_SOUNDIO_PRIVATE_H
 | 
			
		||||
#define SOUNDIO_SOUNDIO_PRIVATE_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"
 | 
			
		||||
#include "soundio_internal.h"
 | 
			
		||||
 | 
			
		||||
#ifdef SOUNDIO_HAVE_JACK
 | 
			
		||||
#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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
 | 
			
		||||
#include "util.hpp"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
void soundio_panic(const char *format, ...) {
 | 
			
		||||
    va_list ap;
 | 
			
		||||
| 
						 | 
				
			
			@ -25,13 +25,13 @@ char *soundio_alloc_sprintf(int *len, const char *format, ...) {
 | 
			
		|||
    va_start(ap, format);
 | 
			
		||||
    va_copy(ap2, ap);
 | 
			
		||||
 | 
			
		||||
    int len1 = vsnprintf(nullptr, 0, format, ap);
 | 
			
		||||
    int len1 = vsnprintf(NULL, 0, format, ap);
 | 
			
		||||
    assert(len1 >= 0);
 | 
			
		||||
 | 
			
		||||
    size_t required_size = len1 + 1;
 | 
			
		||||
    char *mem = allocate<char>(required_size);
 | 
			
		||||
    char *mem = ALLOCATE(char, required_size);
 | 
			
		||||
    if (!mem)
 | 
			
		||||
        return nullptr;
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    int len2 = vsnprintf(mem, required_size, format, ap2);
 | 
			
		||||
    assert(len2 == len1);
 | 
			
		||||
| 
						 | 
				
			
			@ -5,26 +5,44 @@
 | 
			
		|||
 * See http://opensource.org/licenses/MIT
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef SOUNDIO_UTIL_HPP
 | 
			
		||||
#define SOUNDIO_UTIL_HPP
 | 
			
		||||
#ifndef SOUNDIO_UTIL_H
 | 
			
		||||
#define SOUNDIO_UTIL_H
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
__attribute__((malloc)) static inline T *allocate_nonzero(size_t count) {
 | 
			
		||||
    return reinterpret_cast<T*>(malloc(count * sizeof(T)));
 | 
			
		||||
#define ALLOCATE_NONZERO(Type, count) malloc((count) * sizeof(Type))
 | 
			
		||||
 | 
			
		||||
#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>
 | 
			
		||||
__attribute__((malloc)) static inline T *allocate(size_t count) {
 | 
			
		||||
    return reinterpret_cast<T*>(calloc(count, sizeof(T)));
 | 
			
		||||
static inline int soundio_int_max(int a, int b) {
 | 
			
		||||
    return (a >= b) ? a : b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
static inline T *reallocate_nonzero(T * old, size_t new_count) {
 | 
			
		||||
    return reinterpret_cast<T*>(realloc(old, new_count * sizeof(T)));
 | 
			
		||||
static inline int soundio_int_clamp(int min_value, int value, int max_value) {
 | 
			
		||||
    return soundio_int_max(soundio_int_min(value, max_value), min_value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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, ...)
 | 
			
		||||
| 
						 | 
				
			
			@ -36,9 +54,9 @@ char *soundio_alloc_sprintf(int *len, const char *format, ...)
 | 
			
		|||
    __attribute__ ((format (printf, 2, 3)));
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
        return nullptr;
 | 
			
		||||
        return NULL;
 | 
			
		||||
    memcpy(out, str, str_len);
 | 
			
		||||
    out[str_len] = 0;
 | 
			
		||||
    return out;
 | 
			
		||||
| 
						 | 
				
			
			@ -61,24 +79,4 @@ static inline double ceil_dbl(double x) {
 | 
			
		|||
    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
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -5,13 +5,13 @@
 | 
			
		|||
 * See http://opensource.org/licenses/MIT
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef SOUNDIO_WASAPI_HPP
 | 
			
		||||
#define SOUNDIO_WASAPI_HPP
 | 
			
		||||
#ifndef SOUNDIO_WASAPI_H
 | 
			
		||||
#define SOUNDIO_WASAPI_H
 | 
			
		||||
 | 
			
		||||
#include "soundio_private.h"
 | 
			
		||||
#include "soundio_internal.h"
 | 
			
		||||
#include "os.h"
 | 
			
		||||
#include "atomics.hpp"
 | 
			
		||||
#include "list.hpp"
 | 
			
		||||
#include "list.h"
 | 
			
		||||
#include "atomics.h"
 | 
			
		||||
 | 
			
		||||
#define INITGUID
 | 
			
		||||
#define CINTERFACE
 | 
			
		||||
| 
						 | 
				
			
			@ -25,6 +25,7 @@
 | 
			
		|||
#include <audiosessiontypes.h>
 | 
			
		||||
#include <audiopolicy.h>
 | 
			
		||||
 | 
			
		||||
struct SoundIoPrivate;
 | 
			
		||||
int soundio_wasapi_init(struct SoundIoPrivate *si);
 | 
			
		||||
 | 
			
		||||
struct SoundIoDeviceWasapi {
 | 
			
		||||
| 
						 | 
				
			
			@ -33,10 +34,10 @@ struct SoundIoDeviceWasapi {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
struct SoundIoWasapi {
 | 
			
		||||
    SoundIoOsMutex *mutex;
 | 
			
		||||
    SoundIoOsCond *cond;
 | 
			
		||||
    SoundIoOsCond *scan_devices_cond;
 | 
			
		||||
    SoundIoOsMutex *scan_devices_mutex;
 | 
			
		||||
    struct SoundIoOsMutex *mutex;
 | 
			
		||||
    struct SoundIoOsCond *cond;
 | 
			
		||||
    struct SoundIoOsCond *scan_devices_cond;
 | 
			
		||||
    struct SoundIoOsMutex *scan_devices_mutex;
 | 
			
		||||
    struct SoundIoOsThread *thread;
 | 
			
		||||
    bool abort_flag;
 | 
			
		||||
    // this one is ready to be read with flush_events. protected by mutex
 | 
			
		||||
| 
						 | 
				
			
			@ -58,17 +59,17 @@ struct SoundIoOutStreamWasapi {
 | 
			
		|||
    IAudioSessionControl *audio_session_control;
 | 
			
		||||
    LPWSTR stream_name;
 | 
			
		||||
    bool need_resample;
 | 
			
		||||
    SoundIoOsThread *thread;
 | 
			
		||||
    SoundIoOsMutex *mutex;
 | 
			
		||||
    SoundIoOsCond *cond;
 | 
			
		||||
    SoundIoOsCond *start_cond;
 | 
			
		||||
    struct SoundIoOsThread *thread;
 | 
			
		||||
    struct SoundIoOsMutex *mutex;
 | 
			
		||||
    struct SoundIoOsCond *cond;
 | 
			
		||||
    struct SoundIoOsCond *start_cond;
 | 
			
		||||
    atomic_flag thread_exit_flag;
 | 
			
		||||
    bool is_raw;
 | 
			
		||||
    int writable_frame_count;
 | 
			
		||||
    UINT32 buffer_frame_count;
 | 
			
		||||
    int write_frame_count;
 | 
			
		||||
    HANDLE h_event;
 | 
			
		||||
    atomic_bool desired_pause_state;
 | 
			
		||||
    struct SoundIoAtomicBool desired_pause_state;
 | 
			
		||||
    atomic_flag pause_resume_flag;
 | 
			
		||||
    atomic_flag clear_buffer_flag;
 | 
			
		||||
    bool is_paused;
 | 
			
		||||
| 
						 | 
				
			
			@ -76,7 +77,7 @@ struct SoundIoOutStreamWasapi {
 | 
			
		|||
    int open_err;
 | 
			
		||||
    bool started;
 | 
			
		||||
    UINT32 min_padding_frames;
 | 
			
		||||
    SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
    struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SoundIoInStreamWasapi {
 | 
			
		||||
| 
						 | 
				
			
			@ -84,10 +85,10 @@ struct SoundIoInStreamWasapi {
 | 
			
		|||
    IAudioCaptureClient *audio_capture_client;
 | 
			
		||||
    IAudioSessionControl *audio_session_control;
 | 
			
		||||
    LPWSTR stream_name;
 | 
			
		||||
    SoundIoOsThread *thread;
 | 
			
		||||
    SoundIoOsMutex *mutex;
 | 
			
		||||
    SoundIoOsCond *cond;
 | 
			
		||||
    SoundIoOsCond *start_cond;
 | 
			
		||||
    struct SoundIoOsThread *thread;
 | 
			
		||||
    struct SoundIoOsMutex *mutex;
 | 
			
		||||
    struct SoundIoOsCond *cond;
 | 
			
		||||
    struct SoundIoOsCond *start_cond;
 | 
			
		||||
    atomic_flag thread_exit_flag;
 | 
			
		||||
    bool is_raw;
 | 
			
		||||
    int readable_frame_count;
 | 
			
		||||
| 
						 | 
				
			
			@ -100,7 +101,7 @@ struct SoundIoInStreamWasapi {
 | 
			
		|||
    bool started;
 | 
			
		||||
    char *read_buf;
 | 
			
		||||
    int read_buf_frames_left;
 | 
			
		||||
    SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
    struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -5,15 +5,15 @@
 | 
			
		|||
 * See http://opensource.org/licenses/MIT
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "soundio.hpp"
 | 
			
		||||
#include "soundio_private.h"
 | 
			
		||||
#include "os.h"
 | 
			
		||||
#include "util.hpp"
 | 
			
		||||
#include "atomics.hpp"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
static int usage(char *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 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;
 | 
			
		||||
    int err;
 | 
			
		||||
    if ((err = soundio_outstream_get_latency(outstream, &latency))) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
#undef NDEBUG
 | 
			
		||||
 | 
			
		||||
#include "soundio.hpp"
 | 
			
		||||
#include "soundio_private.h"
 | 
			
		||||
#include "os.h"
 | 
			
		||||
#include "util.hpp"
 | 
			
		||||
#include "atomics.hpp"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
#include "atomics.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -58,7 +58,7 @@ static void test_create_outstream(void) {
 | 
			
		|||
static void test_ring_buffer_basic(void) {
 | 
			
		||||
    struct SoundIo *soundio = soundio_create();
 | 
			
		||||
    assert(soundio);
 | 
			
		||||
    SoundIoRingBuffer *rb = soundio_ring_buffer_create(soundio, 10);
 | 
			
		||||
    struct SoundIoRingBuffer *rb = soundio_ring_buffer_create(soundio, 10);
 | 
			
		||||
    assert(rb);
 | 
			
		||||
 | 
			
		||||
    int page_size = soundio_os_page_size();
 | 
			
		||||
| 
						 | 
				
			
			@ -98,41 +98,41 @@ static void test_ring_buffer_basic(void) {
 | 
			
		|||
    soundio_destroy(soundio);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SoundIoRingBuffer *rb = nullptr;
 | 
			
		||||
static struct SoundIoRingBuffer *rb = NULL;
 | 
			
		||||
static const int rb_size = 3528;
 | 
			
		||||
static long expected_write_head;
 | 
			
		||||
static long expected_read_head;
 | 
			
		||||
static atomic_bool rb_done;
 | 
			
		||||
static atomic_int rb_write_it;
 | 
			
		||||
static atomic_int rb_read_it;
 | 
			
		||||
static struct SoundIoAtomicBool rb_done;
 | 
			
		||||
static struct SoundIoAtomicInt rb_write_it;
 | 
			
		||||
static struct SoundIoAtomicInt rb_read_it;
 | 
			
		||||
 | 
			
		||||
// just for testing purposes; does not need to be high quality random
 | 
			
		||||
static double random_double(void) {
 | 
			
		||||
    return ((double)rand() / (double)RAND_MAX);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void reader_thread_run(void *) {
 | 
			
		||||
    while (!rb_done) {
 | 
			
		||||
        rb_read_it += 1;
 | 
			
		||||
static void reader_thread_run(void *arg) {
 | 
			
		||||
    while (!SOUNDIO_ATOMIC_LOAD(rb_done)) {
 | 
			
		||||
        SOUNDIO_ATOMIC_FETCH_ADD(rb_read_it, 1);
 | 
			
		||||
        int fill_count = soundio_ring_buffer_fill_count(rb);
 | 
			
		||||
        assert(fill_count >= 0);
 | 
			
		||||
        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);
 | 
			
		||||
        expected_read_head += amount_to_read;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void writer_thread_run(void *) {
 | 
			
		||||
    while (!rb_done) {
 | 
			
		||||
        rb_write_it += 1;
 | 
			
		||||
static void writer_thread_run(void *arg) {
 | 
			
		||||
    while (!SOUNDIO_ATOMIC_LOAD(rb_done)) {
 | 
			
		||||
        SOUNDIO_ATOMIC_FETCH_ADD(rb_write_it, 1);
 | 
			
		||||
        int fill_count = soundio_ring_buffer_fill_count(rb);
 | 
			
		||||
        assert(fill_count >= 0);
 | 
			
		||||
        assert(fill_count <= rb_size);
 | 
			
		||||
        int free_count = rb_size - fill_count;
 | 
			
		||||
        assert(free_count >= 0);
 | 
			
		||||
        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);
 | 
			
		||||
        expected_write_head += value;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -144,18 +144,18 @@ static void test_ring_buffer_threaded(void) {
 | 
			
		|||
    rb = soundio_ring_buffer_create(soundio, rb_size);
 | 
			
		||||
    expected_write_head = 0;
 | 
			
		||||
    expected_read_head = 0;
 | 
			
		||||
    rb_read_it = 0;
 | 
			
		||||
    rb_write_it = 0;
 | 
			
		||||
    rb_done = false;
 | 
			
		||||
    SOUNDIO_ATOMIC_STORE(rb_read_it, 0);
 | 
			
		||||
    SOUNDIO_ATOMIC_STORE(rb_write_it, 0);
 | 
			
		||||
    SOUNDIO_ATOMIC_STORE(rb_done, false);
 | 
			
		||||
 | 
			
		||||
    SoundIoOsThread *reader_thread;
 | 
			
		||||
    ok_or_panic(soundio_os_thread_create(reader_thread_run, nullptr, nullptr, &reader_thread));
 | 
			
		||||
    struct SoundIoOsThread *reader_thread;
 | 
			
		||||
    ok_or_panic(soundio_os_thread_create(reader_thread_run, NULL, NULL, &reader_thread));
 | 
			
		||||
 | 
			
		||||
    SoundIoOsThread *writer_thread;
 | 
			
		||||
    ok_or_panic(soundio_os_thread_create(writer_thread_run, nullptr, nullptr, &writer_thread));
 | 
			
		||||
    struct SoundIoOsThread *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) {}
 | 
			
		||||
    rb_done = true;
 | 
			
		||||
    while (SOUNDIO_ATOMIC_LOAD(rb_read_it) < 100000 || SOUNDIO_ATOMIC_LOAD(rb_write_it) < 100000) {}
 | 
			
		||||
    SOUNDIO_ATOMIC_STORE(rb_done, true);
 | 
			
		||||
 | 
			
		||||
    soundio_os_thread_destroy(reader_thread);
 | 
			
		||||
    soundio_os_thread_destroy(writer_thread);
 | 
			
		||||
| 
						 | 
				
			
			@ -219,10 +219,10 @@ struct Test {
 | 
			
		|||
static struct Test tests[] = {
 | 
			
		||||
    {"os_get_time", test_os_get_time},
 | 
			
		||||
    {"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},
 | 
			
		||||
    {"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},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -233,7 +233,7 @@ static void exec_test(struct Test *test) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char *argv[]) {
 | 
			
		||||
    const char *match = nullptr;
 | 
			
		||||
    const char *match = NULL;
 | 
			
		||||
 | 
			
		||||
    if (argc == 2)
 | 
			
		||||
        match = argv[1];
 | 
			
		||||
		Loading…
	
		Reference in a new issue