mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2024-12-22 17:55:37 +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)
|
cmake_minimum_required(VERSION 2.8.5)
|
||||||
project(libsoundio C CXX)
|
project(libsoundio C)
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
|
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
|
||||||
|
|
||||||
if(CMAKE_VERSION VERSION_LESS 3.0.0)
|
if(CMAKE_VERSION VERSION_LESS 3.0.0)
|
||||||
|
@ -135,12 +135,12 @@ endif()
|
||||||
|
|
||||||
|
|
||||||
set(LIBSOUNDIO_SOURCES
|
set(LIBSOUNDIO_SOURCES
|
||||||
"${CMAKE_SOURCE_DIR}/src/soundio.cpp"
|
"${CMAKE_SOURCE_DIR}/src/soundio.c"
|
||||||
"${CMAKE_SOURCE_DIR}/src/util.cpp"
|
"${CMAKE_SOURCE_DIR}/src/util.c"
|
||||||
"${CMAKE_SOURCE_DIR}/src/os.cpp"
|
"${CMAKE_SOURCE_DIR}/src/os.c"
|
||||||
"${CMAKE_SOURCE_DIR}/src/dummy.cpp"
|
"${CMAKE_SOURCE_DIR}/src/dummy.c"
|
||||||
"${CMAKE_SOURCE_DIR}/src/channel_layout.cpp"
|
"${CMAKE_SOURCE_DIR}/src/channel_layout.c"
|
||||||
"${CMAKE_SOURCE_DIR}/src/ring_buffer.cpp"
|
"${CMAKE_SOURCE_DIR}/src/ring_buffer.c"
|
||||||
)
|
)
|
||||||
|
|
||||||
set(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h")
|
set(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h")
|
||||||
|
@ -152,27 +152,27 @@ set(LIBSOUNDIO_HEADERS
|
||||||
|
|
||||||
if(SOUNDIO_HAVE_JACK)
|
if(SOUNDIO_HAVE_JACK)
|
||||||
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
|
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
|
||||||
"${CMAKE_SOURCE_DIR}/src/jack.cpp"
|
"${CMAKE_SOURCE_DIR}/src/jack.c"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
if(SOUNDIO_HAVE_PULSEAUDIO)
|
if(SOUNDIO_HAVE_PULSEAUDIO)
|
||||||
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
|
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
|
||||||
"${CMAKE_SOURCE_DIR}/src/pulseaudio.cpp"
|
"${CMAKE_SOURCE_DIR}/src/pulseaudio.c"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
if(SOUNDIO_HAVE_ALSA)
|
if(SOUNDIO_HAVE_ALSA)
|
||||||
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
|
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
|
||||||
"${CMAKE_SOURCE_DIR}/src/alsa.cpp"
|
"${CMAKE_SOURCE_DIR}/src/alsa.c"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
if(SOUNDIO_HAVE_COREAUDIO)
|
if(SOUNDIO_HAVE_COREAUDIO)
|
||||||
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
|
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
|
||||||
"${CMAKE_SOURCE_DIR}/src/coreaudio.cpp"
|
"${CMAKE_SOURCE_DIR}/src/coreaudio.c"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
if(SOUNDIO_HAVE_WASAPI)
|
if(SOUNDIO_HAVE_WASAPI)
|
||||||
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
|
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
|
||||||
"${CMAKE_SOURCE_DIR}/src/wasapi.cpp"
|
"${CMAKE_SOURCE_DIR}/src/wasapi.c"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -195,15 +195,10 @@ set(LIBSOUNDIO_LIBS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# GTFO, -lstdc++ !!
|
|
||||||
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
|
|
||||||
set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "")
|
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Werror -pedantic")
|
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Werror -pedantic")
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror -pedantic")
|
|
||||||
|
|
||||||
|
|
||||||
set(LIB_CFLAGS "-std=c++11 -fno-exceptions -fno-rtti -fvisibility=hidden -Wall -Werror=strict-prototypes -Werror=old-style-definition -Werror=missing-prototypes -Wno-c99-extensions")
|
set(LIB_CFLAGS "-std=c11 -fvisibility=hidden -Wall -Werror=strict-prototypes -Werror=old-style-definition -Werror=missing-prototypes -D_REENTRANT -D_POSIX_C_SOURCE=200809L")
|
||||||
set(EXAMPLE_CFLAGS "-std=c99 -Wall")
|
set(EXAMPLE_CFLAGS "-std=c99 -Wall")
|
||||||
set(TEST_CFLAGS "${LIB_CFLAGS} -fprofile-arcs -ftest-coverage")
|
set(TEST_CFLAGS "${LIB_CFLAGS} -fprofile-arcs -ftest-coverage")
|
||||||
set(TEST_LDFLAGS "-fprofile-arcs -ftest-coverage")
|
set(TEST_LDFLAGS "-fprofile-arcs -ftest-coverage")
|
||||||
|
@ -277,7 +272,7 @@ if(BUILD_EXAMPLE_PROGRAMS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(BUILD_TESTS)
|
if(BUILD_TESTS)
|
||||||
add_executable(unit_tests "${CMAKE_SOURCE_DIR}/test/unit_tests.cpp" ${LIBSOUNDIO_SOURCES})
|
add_executable(unit_tests "${CMAKE_SOURCE_DIR}/test/unit_tests.c" ${LIBSOUNDIO_SOURCES})
|
||||||
target_link_libraries(unit_tests LINK_PUBLIC ${LIBSOUNDIO_LIBS})
|
target_link_libraries(unit_tests LINK_PUBLIC ${LIBSOUNDIO_LIBS})
|
||||||
set_target_properties(unit_tests PROPERTIES
|
set_target_properties(unit_tests PROPERTIES
|
||||||
LINKER_LANGUAGE C
|
LINKER_LANGUAGE C
|
||||||
|
@ -285,7 +280,7 @@ if(BUILD_TESTS)
|
||||||
LINK_FLAGS ${TEST_LDFLAGS}
|
LINK_FLAGS ${TEST_LDFLAGS}
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(latency "${CMAKE_SOURCE_DIR}/test/latency.cpp" ${LIBSOUNDIO_SOURCES})
|
add_executable(latency "${CMAKE_SOURCE_DIR}/test/latency.c" ${LIBSOUNDIO_SOURCES})
|
||||||
target_link_libraries(latency LINK_PUBLIC ${LIBSOUNDIO_LIBS} m)
|
target_link_libraries(latency LINK_PUBLIC ${LIBSOUNDIO_LIBS} m)
|
||||||
set_target_properties(latency PROPERTIES
|
set_target_properties(latency PROPERTIES
|
||||||
LINKER_LANGUAGE C
|
LINKER_LANGUAGE C
|
||||||
|
|
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)
|
[API Documentation](http://libsound.io/doc)
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
libsoundio is programmed in a tiny subset of C++11:
|
|
||||||
|
|
||||||
* No STL.
|
|
||||||
* No `new` or `delete`.
|
|
||||||
* No `class`. All fields in structs are `public`.
|
|
||||||
* No constructors or destructors.
|
|
||||||
* No exceptions or run-time type information.
|
|
||||||
* No references.
|
|
||||||
* No linking against libstdc++.
|
|
||||||
|
|
||||||
Do not be fooled - this is a *C library*, not a C++ library. We just take
|
|
||||||
advantage of a select few C++11 compiler features such as templates, and then
|
|
||||||
link against libc.
|
|
||||||
|
|
||||||
### Building
|
### Building
|
||||||
|
|
||||||
Install the dependencies:
|
Install the dependencies:
|
||||||
|
|
|
@ -5,10 +5,13 @@
|
||||||
* See http://opensource.org/licenses/MIT
|
* See http://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "alsa.hpp"
|
#define _GNU_SOURCE
|
||||||
#include "soundio.hpp"
|
#include "alsa.h"
|
||||||
|
#include "soundio_private.h"
|
||||||
|
|
||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
static snd_pcm_stream_t stream_types[] = {SND_PCM_STREAM_PLAYBACK, SND_PCM_STREAM_CAPTURE};
|
static snd_pcm_stream_t stream_types[] = {SND_PCM_STREAM_PLAYBACK, SND_PCM_STREAM_CAPTURE};
|
||||||
|
|
||||||
|
@ -20,8 +23,9 @@ static snd_pcm_access_t prioritized_access_types[] = {
|
||||||
SND_PCM_ACCESS_RW_NONINTERLEAVED,
|
SND_PCM_ACCESS_RW_NONINTERLEAVED,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SOUNDIO_MAKE_LIST_DEF(struct SoundIoAlsaPendingFile, SoundIoListAlsaPendingFile, SOUNDIO_LIST_STATIC)
|
||||||
|
|
||||||
static void wakeup_device_poll(SoundIoAlsa *sia) {
|
static void wakeup_device_poll(struct SoundIoAlsa *sia) {
|
||||||
ssize_t amt = write(sia->notify_pipe_fd[1], "a", 1);
|
ssize_t amt = write(sia->notify_pipe_fd[1], "a", 1);
|
||||||
if (amt == -1) {
|
if (amt == -1) {
|
||||||
assert(errno != EBADF);
|
assert(errno != EBADF);
|
||||||
|
@ -32,16 +36,16 @@ static void wakeup_device_poll(SoundIoAlsa *sia) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy_alsa(SoundIoPrivate *si) {
|
static void destroy_alsa(struct SoundIoPrivate *si) {
|
||||||
SoundIoAlsa *sia = &si->backend_data.alsa;
|
struct SoundIoAlsa *sia = &si->backend_data.alsa;
|
||||||
|
|
||||||
if (sia->thread) {
|
if (sia->thread) {
|
||||||
sia->abort_flag.clear();
|
atomic_flag_clear(&sia->abort_flag);
|
||||||
wakeup_device_poll(sia);
|
wakeup_device_poll(sia);
|
||||||
soundio_os_thread_destroy(sia->thread);
|
soundio_os_thread_destroy(sia->thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
sia->pending_files.deinit();
|
SoundIoListAlsaPendingFile_deinit(&sia->pending_files);
|
||||||
|
|
||||||
if (sia->cond)
|
if (sia->cond)
|
||||||
soundio_os_cond_destroy(sia->cond);
|
soundio_os_cond_destroy(sia->cond);
|
||||||
|
@ -71,10 +75,10 @@ static char * str_partition_on_char(char *str, char c) {
|
||||||
}
|
}
|
||||||
str += 1;
|
str += 1;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static snd_pcm_stream_t aim_to_stream(SoundIoDeviceAim aim) {
|
static snd_pcm_stream_t aim_to_stream(enum SoundIoDeviceAim aim) {
|
||||||
switch (aim) {
|
switch (aim) {
|
||||||
case SoundIoDeviceAimOutput: return SND_PCM_STREAM_PLAYBACK;
|
case SoundIoDeviceAimOutput: return SND_PCM_STREAM_PLAYBACK;
|
||||||
case SoundIoDeviceAimInput: return SND_PCM_STREAM_CAPTURE;
|
case SoundIoDeviceAimInput: return SND_PCM_STREAM_CAPTURE;
|
||||||
|
@ -83,8 +87,8 @@ static snd_pcm_stream_t aim_to_stream(SoundIoDeviceAim aim) {
|
||||||
return SND_PCM_STREAM_PLAYBACK;
|
return SND_PCM_STREAM_PLAYBACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SoundIoChannelId from_alsa_chmap_pos(unsigned int pos) {
|
static enum SoundIoChannelId from_alsa_chmap_pos(unsigned int pos) {
|
||||||
switch ((snd_pcm_chmap_position)pos) {
|
switch ((enum snd_pcm_chmap_position)pos) {
|
||||||
case SND_CHMAP_UNKNOWN: return SoundIoChannelIdInvalid;
|
case SND_CHMAP_UNKNOWN: return SoundIoChannelIdInvalid;
|
||||||
case SND_CHMAP_NA: return SoundIoChannelIdInvalid;
|
case SND_CHMAP_NA: return SoundIoChannelIdInvalid;
|
||||||
case SND_CHMAP_MONO: return SoundIoChannelIdFrontCenter;
|
case SND_CHMAP_MONO: return SoundIoChannelIdFrontCenter;
|
||||||
|
@ -126,7 +130,7 @@ static SoundIoChannelId from_alsa_chmap_pos(unsigned int pos) {
|
||||||
return SoundIoChannelIdInvalid;
|
return SoundIoChannelIdInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int to_alsa_chmap_pos(SoundIoChannelId channel_id) {
|
static int to_alsa_chmap_pos(enum SoundIoChannelId channel_id) {
|
||||||
switch (channel_id) {
|
switch (channel_id) {
|
||||||
case SoundIoChannelIdFrontLeft: return SND_CHMAP_FL;
|
case SoundIoChannelIdFrontLeft: return SND_CHMAP_FL;
|
||||||
case SoundIoChannelIdFrontRight: return SND_CHMAP_FR;
|
case SoundIoChannelIdFrontRight: return SND_CHMAP_FR;
|
||||||
|
@ -168,8 +172,8 @@ static int to_alsa_chmap_pos(SoundIoChannelId channel_id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_channel_layout(SoundIoChannelLayout *dest, snd_pcm_chmap_t *chmap) {
|
static void get_channel_layout(struct SoundIoChannelLayout *dest, snd_pcm_chmap_t *chmap) {
|
||||||
int channel_count = min((unsigned int)SOUNDIO_MAX_CHANNELS, chmap->channels);
|
int channel_count = soundio_int_min(SOUNDIO_MAX_CHANNELS, chmap->channels);
|
||||||
dest->channel_count = channel_count;
|
dest->channel_count = channel_count;
|
||||||
for (int i = 0; i < channel_count; i += 1) {
|
for (int i = 0; i < channel_count; i += 1) {
|
||||||
dest->channels[i] = from_alsa_chmap_pos(chmap->pos[i]);
|
dest->channels[i] = from_alsa_chmap_pos(chmap->pos[i]);
|
||||||
|
@ -177,7 +181,7 @@ static void get_channel_layout(SoundIoChannelLayout *dest, snd_pcm_chmap_t *chma
|
||||||
soundio_channel_layout_detect_builtin(dest);
|
soundio_channel_layout_detect_builtin(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_channel_maps(SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
|
static int handle_channel_maps(struct SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
|
||||||
if (!maps)
|
if (!maps)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -187,7 +191,7 @@ static int handle_channel_maps(SoundIoDevice *device, snd_pcm_chmap_query_t **ma
|
||||||
// one iteration to count
|
// one iteration to count
|
||||||
int layout_count = 0;
|
int layout_count = 0;
|
||||||
for (p = maps; (v = *p) && layout_count < SOUNDIO_MAX_CHANNELS; p += 1, layout_count += 1) { }
|
for (p = maps; (v = *p) && layout_count < SOUNDIO_MAX_CHANNELS; p += 1, layout_count += 1) { }
|
||||||
device->layouts = allocate<SoundIoChannelLayout>(layout_count);
|
device->layouts = ALLOCATE(struct SoundIoChannelLayout, layout_count);
|
||||||
if (!device->layouts) {
|
if (!device->layouts) {
|
||||||
snd_pcm_free_chmaps(maps);
|
snd_pcm_free_chmaps(maps);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
|
@ -207,7 +211,7 @@ static int handle_channel_maps(SoundIoDevice *device, snd_pcm_chmap_query_t **ma
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static snd_pcm_format_t to_alsa_fmt(SoundIoFormat fmt) {
|
static snd_pcm_format_t to_alsa_fmt(enum SoundIoFormat fmt) {
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case SoundIoFormatS8: return SND_PCM_FORMAT_S8;
|
case SoundIoFormatS8: return SND_PCM_FORMAT_S8;
|
||||||
case SoundIoFormatU8: return SND_PCM_FORMAT_U8;
|
case SoundIoFormatU8: return SND_PCM_FORMAT_U8;
|
||||||
|
@ -234,7 +238,9 @@ static snd_pcm_format_t to_alsa_fmt(SoundIoFormat fmt) {
|
||||||
return SND_PCM_FORMAT_UNKNOWN;
|
return SND_PCM_FORMAT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_fmt_mask(SoundIoDevice *device, const snd_pcm_format_mask_t *fmt_mask, SoundIoFormat fmt) {
|
static void test_fmt_mask(struct SoundIoDevice *device, const snd_pcm_format_mask_t *fmt_mask,
|
||||||
|
enum SoundIoFormat fmt)
|
||||||
|
{
|
||||||
if (snd_pcm_format_mask_test(fmt_mask, to_alsa_fmt(fmt))) {
|
if (snd_pcm_format_mask_test(fmt_mask, to_alsa_fmt(fmt))) {
|
||||||
device->formats[device->format_count] = fmt;
|
device->formats[device->format_count] = fmt;
|
||||||
device->format_count += 1;
|
device->format_count += 1;
|
||||||
|
@ -242,7 +248,7 @@ static void test_fmt_mask(SoundIoDevice *device, const snd_pcm_format_mask_t *fm
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_access(snd_pcm_t *handle, snd_pcm_hw_params_t *hwparams, snd_pcm_access_t *out_access) {
|
static int set_access(snd_pcm_t *handle, snd_pcm_hw_params_t *hwparams, snd_pcm_access_t *out_access) {
|
||||||
for (int i = 0; i < array_length(prioritized_access_types); i += 1) {
|
for (int i = 0; i < ARRAY_LENGTH(prioritized_access_types); i += 1) {
|
||||||
snd_pcm_access_t access = prioritized_access_types[i];
|
snd_pcm_access_t access = prioritized_access_types[i];
|
||||||
int err = snd_pcm_hw_params_set_access(handle, hwparams, access);
|
int err = snd_pcm_hw_params_set_access(handle, hwparams, access);
|
||||||
if (err >= 0) {
|
if (err >= 0) {
|
||||||
|
@ -255,10 +261,10 @@ static int set_access(snd_pcm_t *handle, snd_pcm_hw_params_t *hwparams, snd_pcm_
|
||||||
}
|
}
|
||||||
|
|
||||||
// this function does not override device->formats, so if you want it to, deallocate and set it to NULL
|
// this function does not override device->formats, so if you want it to, deallocate and set it to NULL
|
||||||
static int probe_open_device(SoundIoDevice *device, snd_pcm_t *handle, int resample,
|
static int probe_open_device(struct SoundIoDevice *device, snd_pcm_t *handle, int resample,
|
||||||
int *out_channels_min, int *out_channels_max)
|
int *out_channels_min, int *out_channels_max)
|
||||||
{
|
{
|
||||||
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
snd_pcm_hw_params_t *hwparams;
|
snd_pcm_hw_params_t *hwparams;
|
||||||
|
@ -270,7 +276,7 @@ static int probe_open_device(SoundIoDevice *device, snd_pcm_t *handle, int resam
|
||||||
if ((err = snd_pcm_hw_params_set_rate_resample(handle, hwparams, resample)) < 0)
|
if ((err = snd_pcm_hw_params_set_rate_resample(handle, hwparams, resample)) < 0)
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
|
|
||||||
if ((err = set_access(handle, hwparams, nullptr)))
|
if ((err = set_access(handle, hwparams, NULL)))
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
unsigned int channels_min;
|
unsigned int channels_min;
|
||||||
|
@ -287,10 +293,10 @@ static int probe_open_device(SoundIoDevice *device, snd_pcm_t *handle, int resam
|
||||||
unsigned int rate_min;
|
unsigned int rate_min;
|
||||||
unsigned int rate_max;
|
unsigned int rate_max;
|
||||||
|
|
||||||
if ((err = snd_pcm_hw_params_get_rate_min(hwparams, &rate_min, nullptr)) < 0)
|
if ((err = snd_pcm_hw_params_get_rate_min(hwparams, &rate_min, NULL)) < 0)
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
|
|
||||||
if ((err = snd_pcm_hw_params_set_rate_last(handle, hwparams, &rate_max, nullptr)) < 0)
|
if ((err = snd_pcm_hw_params_set_rate_last(handle, hwparams, &rate_max, NULL)) < 0)
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
|
|
||||||
device->sample_rate_count = 1;
|
device->sample_rate_count = 1;
|
||||||
|
@ -345,7 +351,7 @@ static int probe_open_device(SoundIoDevice *device, snd_pcm_t *handle, int resam
|
||||||
|
|
||||||
if (!device->formats) {
|
if (!device->formats) {
|
||||||
snd_pcm_hw_params_get_format_mask(hwparams, fmt_mask);
|
snd_pcm_hw_params_get_format_mask(hwparams, fmt_mask);
|
||||||
device->formats = allocate<SoundIoFormat>(18);
|
device->formats = ALLOCATE(enum SoundIoFormat, 18);
|
||||||
if (!device->formats)
|
if (!device->formats)
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
|
|
||||||
|
@ -373,7 +379,7 @@ static int probe_open_device(SoundIoDevice *device, snd_pcm_t *handle, int resam
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int probe_device(SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
|
static int probe_device(struct SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
|
||||||
int err;
|
int err;
|
||||||
snd_pcm_t *handle;
|
snd_pcm_t *handle;
|
||||||
|
|
||||||
|
@ -398,20 +404,20 @@ static int probe_device(SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
|
||||||
// the min and max channel counts are correct.
|
// the min and max channel counts are correct.
|
||||||
int layout_count = 0;
|
int layout_count = 0;
|
||||||
for (int i = 0; i < soundio_channel_layout_builtin_count(); i += 1) {
|
for (int i = 0; i < soundio_channel_layout_builtin_count(); i += 1) {
|
||||||
const SoundIoChannelLayout *layout = soundio_channel_layout_get_builtin(i);
|
const struct SoundIoChannelLayout *layout = soundio_channel_layout_get_builtin(i);
|
||||||
if (layout->channel_count >= channels_min && layout->channel_count <= channels_max) {
|
if (layout->channel_count >= channels_min && layout->channel_count <= channels_max) {
|
||||||
layout_count += 1;
|
layout_count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
device->layout_count = layout_count;
|
device->layout_count = layout_count;
|
||||||
device->layouts = allocate<SoundIoChannelLayout>(device->layout_count);
|
device->layouts = ALLOCATE(struct SoundIoChannelLayout, device->layout_count);
|
||||||
if (!device->layouts) {
|
if (!device->layouts) {
|
||||||
snd_pcm_close(handle);
|
snd_pcm_close(handle);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
int layout_index = 0;
|
int layout_index = 0;
|
||||||
for (int i = 0; i < soundio_channel_layout_builtin_count(); i += 1) {
|
for (int i = 0; i < soundio_channel_layout_builtin_count(); i += 1) {
|
||||||
const SoundIoChannelLayout *layout = soundio_channel_layout_get_builtin(i);
|
const struct SoundIoChannelLayout *layout = soundio_channel_layout_get_builtin(i);
|
||||||
if (layout->channel_count >= channels_min && layout->channel_count <= channels_max) {
|
if (layout->channel_count >= channels_min && layout->channel_count <= channels_max) {
|
||||||
device->layouts[layout_index++] = *soundio_channel_layout_get_builtin(i);
|
device->layouts[layout_index++] = *soundio_channel_layout_get_builtin(i);
|
||||||
}
|
}
|
||||||
|
@ -428,7 +434,7 @@ static int probe_device(SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
|
||||||
snd_pcm_close(handle);
|
snd_pcm_close(handle);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
maps = nullptr;
|
maps = NULL;
|
||||||
|
|
||||||
if (!device->is_raw) {
|
if (!device->is_raw) {
|
||||||
if (device->sample_rates[0].min == device->sample_rates[0].max)
|
if (device->sample_rates[0].min == device->sample_rates[0].max)
|
||||||
|
@ -452,9 +458,9 @@ static inline bool str_has_prefix(const char *big_str, const char *prefix) {
|
||||||
return strncmp(big_str, prefix, strlen(prefix)) == 0;
|
return strncmp(big_str, prefix, strlen(prefix)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int refresh_devices(SoundIoPrivate *si) {
|
static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoAlsa *sia = &si->backend_data.alsa;
|
struct SoundIoAlsa *sia = &si->backend_data.alsa;
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
if ((err = snd_config_update_free_global()) < 0)
|
if ((err = snd_config_update_free_global()) < 0)
|
||||||
|
@ -462,7 +468,7 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
if ((err = snd_config_update()) < 0)
|
if ((err = snd_config_update()) < 0)
|
||||||
return SoundIoErrorSystemResources;
|
return SoundIoErrorSystemResources;
|
||||||
|
|
||||||
SoundIoDevicesInfo *devices_info = allocate<SoundIoDevicesInfo>(1);
|
struct SoundIoDevicesInfo *devices_info = ALLOCATE(struct SoundIoDevicesInfo, 1);
|
||||||
if (!devices_info)
|
if (!devices_info)
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
devices_info->default_output_index = -1;
|
devices_info->default_output_index = -1;
|
||||||
|
@ -517,7 +523,7 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
is_capture = true;
|
is_capture = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int stream_type_i = 0; stream_type_i < array_length(stream_types); stream_type_i += 1) {
|
for (int stream_type_i = 0; stream_type_i < ARRAY_LENGTH(stream_types); stream_type_i += 1) {
|
||||||
snd_pcm_stream_t stream = stream_types[stream_type_i];
|
snd_pcm_stream_t stream = stream_types[stream_type_i];
|
||||||
if (stream == SND_PCM_STREAM_PLAYBACK && !is_playback) continue;
|
if (stream == SND_PCM_STREAM_PLAYBACK && !is_playback) continue;
|
||||||
if (stream == SND_PCM_STREAM_CAPTURE && !is_capture) continue;
|
if (stream == SND_PCM_STREAM_CAPTURE && !is_capture) continue;
|
||||||
|
@ -528,7 +534,7 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1);
|
struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
free(name);
|
free(name);
|
||||||
free(descr);
|
free(descr);
|
||||||
|
@ -536,13 +542,13 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
snd_device_name_free_hint(hints);
|
snd_device_name_free_hint(hints);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
SoundIoDevice *device = &dev->pub;
|
struct SoundIoDevice *device = &dev->pub;
|
||||||
device->ref_count = 1;
|
device->ref_count = 1;
|
||||||
device->soundio = soundio;
|
device->soundio = soundio;
|
||||||
device->is_raw = false;
|
device->is_raw = false;
|
||||||
device->id = strdup(name);
|
device->id = strdup(name);
|
||||||
device->name = descr1 ?
|
device->name = descr1 ?
|
||||||
soundio_alloc_sprintf(nullptr, "%s: %s", descr, descr1) : strdup(descr);
|
soundio_alloc_sprintf(NULL, "%s: %s", descr, descr1) : strdup(descr);
|
||||||
|
|
||||||
if (!device->id || !device->name) {
|
if (!device->id || !device->name) {
|
||||||
soundio_device_unref(device);
|
soundio_device_unref(device);
|
||||||
|
@ -553,7 +559,7 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundIoList<SoundIoDevice *> *device_list;
|
struct SoundIoListDevicePtr *device_list;
|
||||||
bool is_default = str_has_prefix(name, "default:") || strcmp(name, "default") == 0;
|
bool is_default = str_has_prefix(name, "default:") || strcmp(name, "default") == 0;
|
||||||
if (stream == SND_PCM_STREAM_PLAYBACK) {
|
if (stream == SND_PCM_STREAM_PLAYBACK) {
|
||||||
device->aim = SoundIoDeviceAimOutput;
|
device->aim = SoundIoDeviceAimOutput;
|
||||||
|
@ -568,9 +574,9 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
devices_info->default_input_index = device_list->length;
|
devices_info->default_input_index = device_list->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
device->probe_error = probe_device(device, nullptr);
|
device->probe_error = probe_device(device, NULL);
|
||||||
|
|
||||||
if (device_list->append(device)) {
|
if (SoundIoListDevicePtr_append(device_list, device)) {
|
||||||
soundio_device_unref(device);
|
soundio_device_unref(device);
|
||||||
free(name);
|
free(name);
|
||||||
free(descr);
|
free(descr);
|
||||||
|
@ -631,7 +637,7 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
snd_pcm_info_set_device(pcm_info, device_index);
|
snd_pcm_info_set_device(pcm_info, device_index);
|
||||||
snd_pcm_info_set_subdevice(pcm_info, 0);
|
snd_pcm_info_set_subdevice(pcm_info, 0);
|
||||||
|
|
||||||
for (int stream_type_i = 0; stream_type_i < array_length(stream_types); stream_type_i += 1) {
|
for (int stream_type_i = 0; stream_type_i < ARRAY_LENGTH(stream_types); stream_type_i += 1) {
|
||||||
snd_pcm_stream_t stream = stream_types[stream_type_i];
|
snd_pcm_stream_t stream = stream_types[stream_type_i];
|
||||||
snd_pcm_info_set_stream(pcm_info, stream);
|
snd_pcm_info_set_stream(pcm_info, stream);
|
||||||
|
|
||||||
|
@ -647,17 +653,17 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
|
|
||||||
const char *device_name = snd_pcm_info_get_name(pcm_info);
|
const char *device_name = snd_pcm_info_get_name(pcm_info);
|
||||||
|
|
||||||
SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1);
|
struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
snd_ctl_close(handle);
|
snd_ctl_close(handle);
|
||||||
soundio_destroy_devices_info(devices_info);
|
soundio_destroy_devices_info(devices_info);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
SoundIoDevice *device = &dev->pub;
|
struct SoundIoDevice *device = &dev->pub;
|
||||||
device->ref_count = 1;
|
device->ref_count = 1;
|
||||||
device->soundio = soundio;
|
device->soundio = soundio;
|
||||||
device->id = soundio_alloc_sprintf(nullptr, "hw:%d,%d", card_index, device_index);
|
device->id = soundio_alloc_sprintf(NULL, "hw:%d,%d", card_index, device_index);
|
||||||
device->name = soundio_alloc_sprintf(nullptr, "%s %s", card_name, device_name);
|
device->name = soundio_alloc_sprintf(NULL, "%s %s", card_name, device_name);
|
||||||
device->is_raw = true;
|
device->is_raw = true;
|
||||||
|
|
||||||
if (!device->id || !device->name) {
|
if (!device->id || !device->name) {
|
||||||
|
@ -667,7 +673,7 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundIoList<SoundIoDevice *> *device_list;
|
struct SoundIoListDevicePtr *device_list;
|
||||||
if (stream == SND_PCM_STREAM_PLAYBACK) {
|
if (stream == SND_PCM_STREAM_PLAYBACK) {
|
||||||
device->aim = SoundIoDeviceAimOutput;
|
device->aim = SoundIoDeviceAimOutput;
|
||||||
device_list = &devices_info->output_devices;
|
device_list = &devices_info->output_devices;
|
||||||
|
@ -680,7 +686,7 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
snd_pcm_chmap_query_t **maps = snd_pcm_query_chmaps_from_hw(card_index, device_index, -1, stream);
|
snd_pcm_chmap_query_t **maps = snd_pcm_query_chmaps_from_hw(card_index, device_index, -1, stream);
|
||||||
device->probe_error = probe_device(device, maps);
|
device->probe_error = probe_device(device, maps);
|
||||||
|
|
||||||
if (device_list->append(device)) {
|
if (SoundIoListDevicePtr_append(device_list, device)) {
|
||||||
soundio_device_unref(device);
|
soundio_device_unref(device);
|
||||||
soundio_destroy_devices_info(devices_info);
|
soundio_destroy_devices_info(devices_info);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
|
@ -704,9 +710,9 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void shutdown_backend(SoundIoPrivate *si, int err) {
|
static void shutdown_backend(struct SoundIoPrivate *si, int err) {
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoAlsa *sia = &si->backend_data.alsa;
|
struct SoundIoAlsa *sia = &si->backend_data.alsa;
|
||||||
soundio_os_mutex_lock(sia->mutex);
|
soundio_os_mutex_lock(sia->mutex);
|
||||||
sia->shutdown_err = err;
|
sia->shutdown_err = err;
|
||||||
soundio_os_cond_signal(sia->cond, sia->mutex);
|
soundio_os_cond_signal(sia->cond, sia->mutex);
|
||||||
|
@ -730,8 +736,8 @@ static bool copy_str(char *dest, const char *src, int buf_len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void device_thread_run(void *arg) {
|
static void device_thread_run(void *arg) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
|
||||||
SoundIoAlsa *sia = &si->backend_data.alsa;
|
struct SoundIoAlsa *sia = &si->backend_data.alsa;
|
||||||
|
|
||||||
// Some systems cannot read integer variables if they are not
|
// Some systems cannot read integer variables if they are not
|
||||||
// properly aligned. On other systems, incorrect alignment may
|
// properly aligned. On other systems, incorrect alignment may
|
||||||
|
@ -751,7 +757,7 @@ static void device_thread_run(void *arg) {
|
||||||
int err;
|
int err;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int poll_num = poll(fds, 2, -1);
|
int poll_num = poll(fds, 2, -1);
|
||||||
if (!sia->abort_flag.test_and_set())
|
if (!atomic_flag_test_and_set(&sia->abort_flag))
|
||||||
break;
|
break;
|
||||||
if (poll_num == -1) {
|
if (poll_num == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
|
@ -801,13 +807,14 @@ static void device_thread_run(void *arg) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (event->mask & IN_CREATE) {
|
if (event->mask & IN_CREATE) {
|
||||||
if ((err = sia->pending_files.add_one())) {
|
if ((err = SoundIoListAlsaPendingFile_add_one(&sia->pending_files))) {
|
||||||
shutdown_backend(si, SoundIoErrorNoMem);
|
shutdown_backend(si, SoundIoErrorNoMem);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SoundIoAlsaPendingFile *pending_file = &sia->pending_files.last();
|
struct SoundIoAlsaPendingFile *pending_file =
|
||||||
|
SoundIoListAlsaPendingFile_last_ptr(&sia->pending_files);
|
||||||
if (!copy_str(pending_file->name, event->name, SOUNDIO_MAX_ALSA_SND_FILE_LEN)) {
|
if (!copy_str(pending_file->name, event->name, SOUNDIO_MAX_ALSA_SND_FILE_LEN)) {
|
||||||
sia->pending_files.pop();
|
SoundIoListAlsaPendingFile_pop(&sia->pending_files);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -817,9 +824,10 @@ static void device_thread_run(void *arg) {
|
||||||
if (!(event->mask & IN_CLOSE_WRITE))
|
if (!(event->mask & IN_CLOSE_WRITE))
|
||||||
continue;
|
continue;
|
||||||
for (int i = 0; i < sia->pending_files.length; i += 1) {
|
for (int i = 0; i < sia->pending_files.length; i += 1) {
|
||||||
SoundIoAlsaPendingFile *pending_file = &sia->pending_files.at(i);
|
struct SoundIoAlsaPendingFile *pending_file =
|
||||||
|
SoundIoListAlsaPendingFile_ptr_at(&sia->pending_files, i);
|
||||||
if (strcmp(pending_file->name, event->name) == 0) {
|
if (strcmp(pending_file->name, event->name) == 0) {
|
||||||
sia->pending_files.swap_remove(i);
|
SoundIoListAlsaPendingFile_swap_remove(&sia->pending_files, i);
|
||||||
if (sia->pending_files.length == 0) {
|
if (sia->pending_files.length == 0) {
|
||||||
got_rescan_event = true;
|
got_rescan_event = true;
|
||||||
}
|
}
|
||||||
|
@ -864,13 +872,13 @@ static void device_thread_run(void *arg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void my_flush_events(SoundIoPrivate *si, bool wait) {
|
static void my_flush_events(struct SoundIoPrivate *si, bool wait) {
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoAlsa *sia = &si->backend_data.alsa;
|
struct SoundIoAlsa *sia = &si->backend_data.alsa;
|
||||||
|
|
||||||
bool change = false;
|
bool change = false;
|
||||||
bool cb_shutdown = false;
|
bool cb_shutdown = false;
|
||||||
SoundIoDevicesInfo *old_devices_info = nullptr;
|
struct SoundIoDevicesInfo *old_devices_info = NULL;
|
||||||
|
|
||||||
soundio_os_mutex_lock(sia->mutex);
|
soundio_os_mutex_lock(sia->mutex);
|
||||||
|
|
||||||
|
@ -886,7 +894,7 @@ static void my_flush_events(SoundIoPrivate *si, bool wait) {
|
||||||
} else if (sia->ready_devices_info) {
|
} else if (sia->ready_devices_info) {
|
||||||
old_devices_info = si->safe_devices_info;
|
old_devices_info = si->safe_devices_info;
|
||||||
si->safe_devices_info = sia->ready_devices_info;
|
si->safe_devices_info = sia->ready_devices_info;
|
||||||
sia->ready_devices_info = nullptr;
|
sia->ready_devices_info = NULL;
|
||||||
change = true;
|
change = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -900,54 +908,54 @@ static void my_flush_events(SoundIoPrivate *si, bool wait) {
|
||||||
soundio_destroy_devices_info(old_devices_info);
|
soundio_destroy_devices_info(old_devices_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flush_events_alsa(SoundIoPrivate *si) {
|
static void flush_events_alsa(struct SoundIoPrivate *si) {
|
||||||
my_flush_events(si, false);
|
my_flush_events(si, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wait_events_alsa(SoundIoPrivate *si) {
|
static void wait_events_alsa(struct SoundIoPrivate *si) {
|
||||||
my_flush_events(si, false);
|
my_flush_events(si, false);
|
||||||
my_flush_events(si, true);
|
my_flush_events(si, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wakeup_alsa(SoundIoPrivate *si) {
|
static void wakeup_alsa(struct SoundIoPrivate *si) {
|
||||||
SoundIoAlsa *sia = &si->backend_data.alsa;
|
struct SoundIoAlsa *sia = &si->backend_data.alsa;
|
||||||
soundio_os_mutex_lock(sia->mutex);
|
soundio_os_mutex_lock(sia->mutex);
|
||||||
soundio_os_cond_signal(sia->cond, sia->mutex);
|
soundio_os_cond_signal(sia->cond, sia->mutex);
|
||||||
soundio_os_mutex_unlock(sia->mutex);
|
soundio_os_mutex_unlock(sia->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void force_device_scan_alsa(SoundIoPrivate *si) {
|
static void force_device_scan_alsa(struct SoundIoPrivate *si) {
|
||||||
SoundIoAlsa *sia = &si->backend_data.alsa;
|
struct SoundIoAlsa *sia = &si->backend_data.alsa;
|
||||||
wakeup_device_poll(sia);
|
wakeup_device_poll(sia);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void outstream_destroy_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
static void outstream_destroy_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
|
|
||||||
if (osa->thread) {
|
if (osa->thread) {
|
||||||
osa->thread_exit_flag.clear();
|
atomic_flag_clear(&osa->thread_exit_flag);
|
||||||
soundio_os_thread_destroy(osa->thread);
|
soundio_os_thread_destroy(osa->thread);
|
||||||
osa->thread = nullptr;
|
osa->thread = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (osa->handle) {
|
if (osa->handle) {
|
||||||
snd_pcm_close(osa->handle);
|
snd_pcm_close(osa->handle);
|
||||||
osa->handle = nullptr;
|
osa->handle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(osa->poll_fds);
|
free(osa->poll_fds);
|
||||||
osa->poll_fds = nullptr;
|
osa->poll_fds = NULL;
|
||||||
|
|
||||||
free(osa->chmap);
|
free(osa->chmap);
|
||||||
osa->chmap = nullptr;
|
osa->chmap = NULL;
|
||||||
|
|
||||||
free(osa->sample_buffer);
|
free(osa->sample_buffer);
|
||||||
osa->sample_buffer = nullptr;
|
osa->sample_buffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_xrun_recovery(SoundIoOutStreamPrivate *os, int err) {
|
static int outstream_xrun_recovery(struct SoundIoOutStreamPrivate *os, int err) {
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
if (err == -EPIPE) {
|
if (err == -EPIPE) {
|
||||||
err = snd_pcm_prepare(osa->handle);
|
err = snd_pcm_prepare(osa->handle);
|
||||||
if (err >= 0)
|
if (err >= 0)
|
||||||
|
@ -955,7 +963,7 @@ static int outstream_xrun_recovery(SoundIoOutStreamPrivate *os, int err) {
|
||||||
} else if (err == -ESTRPIPE) {
|
} else if (err == -ESTRPIPE) {
|
||||||
while ((err = snd_pcm_resume(osa->handle)) == -EAGAIN) {
|
while ((err = snd_pcm_resume(osa->handle)) == -EAGAIN) {
|
||||||
// wait until suspend flag is released
|
// wait until suspend flag is released
|
||||||
poll(nullptr, 0, 1);
|
poll(NULL, 0, 1);
|
||||||
}
|
}
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
err = snd_pcm_prepare(osa->handle);
|
err = snd_pcm_prepare(osa->handle);
|
||||||
|
@ -965,9 +973,9 @@ static int outstream_xrun_recovery(SoundIoOutStreamPrivate *os, int err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_xrun_recovery(SoundIoInStreamPrivate *is, int err) {
|
static int instream_xrun_recovery(struct SoundIoInStreamPrivate *is, int err) {
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||||
if (err == -EPIPE) {
|
if (err == -EPIPE) {
|
||||||
err = snd_pcm_prepare(isa->handle);
|
err = snd_pcm_prepare(isa->handle);
|
||||||
if (err >= 0)
|
if (err >= 0)
|
||||||
|
@ -975,7 +983,7 @@ static int instream_xrun_recovery(SoundIoInStreamPrivate *is, int err) {
|
||||||
} else if (err == -ESTRPIPE) {
|
} else if (err == -ESTRPIPE) {
|
||||||
while ((err = snd_pcm_resume(isa->handle)) == -EAGAIN) {
|
while ((err = snd_pcm_resume(isa->handle)) == -EAGAIN) {
|
||||||
// wait until suspend flag is released
|
// wait until suspend flag is released
|
||||||
poll(nullptr, 0, 1);
|
poll(NULL, 0, 1);
|
||||||
}
|
}
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
err = snd_pcm_prepare(isa->handle);
|
err = snd_pcm_prepare(isa->handle);
|
||||||
|
@ -985,8 +993,8 @@ static int instream_xrun_recovery(SoundIoInStreamPrivate *is, int err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_wait_for_poll(SoundIoOutStreamPrivate *os) {
|
static int outstream_wait_for_poll(struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
int err;
|
int err;
|
||||||
unsigned short revents;
|
unsigned short revents;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -1006,8 +1014,8 @@ static int outstream_wait_for_poll(SoundIoOutStreamPrivate *os) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_wait_for_poll(SoundIoInStreamPrivate *is) {
|
static int instream_wait_for_poll(struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||||
int err;
|
int err;
|
||||||
unsigned short revents;
|
unsigned short revents;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -1028,9 +1036,9 @@ static int instream_wait_for_poll(SoundIoInStreamPrivate *is) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void outstream_thread_run(void *arg) {
|
static void outstream_thread_run(void *arg) {
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *) arg;
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *) arg;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -1055,7 +1063,7 @@ static void outstream_thread_run(void *arg) {
|
||||||
|
|
||||||
if ((snd_pcm_uframes_t)avail == osa->buffer_size_frames) {
|
if ((snd_pcm_uframes_t)avail == osa->buffer_size_frames) {
|
||||||
outstream->write_callback(outstream, 0, avail);
|
outstream->write_callback(outstream, 0, avail);
|
||||||
if (!osa->thread_exit_flag.test_and_set())
|
if (!atomic_flag_test_and_set(&osa->thread_exit_flag))
|
||||||
return;
|
return;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1070,14 +1078,14 @@ static void outstream_thread_run(void *arg) {
|
||||||
case SND_PCM_STATE_PAUSED:
|
case SND_PCM_STATE_PAUSED:
|
||||||
{
|
{
|
||||||
if ((err = outstream_wait_for_poll(os)) < 0) {
|
if ((err = outstream_wait_for_poll(os)) < 0) {
|
||||||
if (!osa->thread_exit_flag.test_and_set())
|
if (!atomic_flag_test_and_set(&osa->thread_exit_flag))
|
||||||
return;
|
return;
|
||||||
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!osa->thread_exit_flag.test_and_set())
|
if (!atomic_flag_test_and_set(&osa->thread_exit_flag))
|
||||||
return;
|
return;
|
||||||
if (!osa->clear_buffer_flag.test_and_set()) {
|
if (!atomic_flag_test_and_set(&osa->clear_buffer_flag)) {
|
||||||
if ((err = snd_pcm_drop(osa->handle)) < 0) {
|
if ((err = snd_pcm_drop(osa->handle)) < 0) {
|
||||||
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||||
return;
|
return;
|
||||||
|
@ -1130,9 +1138,9 @@ static void outstream_thread_run(void *arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void instream_thread_run(void *arg) {
|
static void instream_thread_run(void *arg) {
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *) arg;
|
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *) arg;
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -1155,12 +1163,12 @@ static void instream_thread_run(void *arg) {
|
||||||
case SND_PCM_STATE_PAUSED:
|
case SND_PCM_STATE_PAUSED:
|
||||||
{
|
{
|
||||||
if ((err = instream_wait_for_poll(is)) < 0) {
|
if ((err = instream_wait_for_poll(is)) < 0) {
|
||||||
if (!isa->thread_exit_flag.test_and_set())
|
if (!atomic_flag_test_and_set(&isa->thread_exit_flag))
|
||||||
return;
|
return;
|
||||||
instream->error_callback(instream, SoundIoErrorStreaming);
|
instream->error_callback(instream, SoundIoErrorStreaming);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!isa->thread_exit_flag.test_and_set())
|
if (!atomic_flag_test_and_set(&isa->thread_exit_flag))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
snd_pcm_sframes_t avail = snd_pcm_avail_update(isa->handle);
|
snd_pcm_sframes_t avail = snd_pcm_avail_update(isa->handle);
|
||||||
|
@ -1198,21 +1206,21 @@ static void instream_thread_run(void *arg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
static int outstream_open_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoDevice *device = outstream->device;
|
struct SoundIoDevice *device = outstream->device;
|
||||||
|
|
||||||
osa->clear_buffer_flag.test_and_set();
|
atomic_flag_test_and_set(&osa->clear_buffer_flag);
|
||||||
|
|
||||||
if (outstream->software_latency == 0.0)
|
if (outstream->software_latency == 0.0)
|
||||||
outstream->software_latency = 1.0;
|
outstream->software_latency = 1.0;
|
||||||
outstream->software_latency = clamp(device->software_latency_min, outstream->software_latency, device->software_latency_max);
|
outstream->software_latency = soundio_double_clamp(device->software_latency_min, outstream->software_latency, device->software_latency_max);
|
||||||
|
|
||||||
int ch_count = outstream->layout.channel_count;
|
int ch_count = outstream->layout.channel_count;
|
||||||
|
|
||||||
osa->chmap_size = sizeof(int) + sizeof(int) * ch_count;
|
osa->chmap_size = sizeof(int) + sizeof(int) * ch_count;
|
||||||
osa->chmap = (snd_pcm_chmap_t *)allocate<char>(osa->chmap_size);
|
osa->chmap = (snd_pcm_chmap_t *)ALLOCATE(char, osa->chmap_size);
|
||||||
if (!osa->chmap) {
|
if (!osa->chmap) {
|
||||||
outstream_destroy_alsa(si, os);
|
outstream_destroy_alsa(si, os);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
|
@ -1272,7 +1280,7 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
|
||||||
if (device->is_raw) {
|
if (device->is_raw) {
|
||||||
period_count = 4;
|
period_count = 4;
|
||||||
unsigned int microseconds = 0.25 * outstream->software_latency * 1000000.0;
|
unsigned int microseconds = 0.25 * outstream->software_latency * 1000000.0;
|
||||||
if ((err = snd_pcm_hw_params_set_period_time_near(osa->handle, hwparams, µseconds, nullptr)) < 0) {
|
if ((err = snd_pcm_hw_params_set_period_time_near(osa->handle, hwparams, µseconds, NULL)) < 0) {
|
||||||
outstream_destroy_alsa(si, os);
|
outstream_destroy_alsa(si, os);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
@ -1282,14 +1290,14 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
|
||||||
snd_pcm_uframes_t period_frames =
|
snd_pcm_uframes_t period_frames =
|
||||||
ceil_dbl_to_uframes(period_duration * (double)outstream->sample_rate);
|
ceil_dbl_to_uframes(period_duration * (double)outstream->sample_rate);
|
||||||
|
|
||||||
if ((err = snd_pcm_hw_params_set_period_size_near(osa->handle, hwparams, &period_frames, nullptr)) < 0) {
|
if ((err = snd_pcm_hw_params_set_period_size_near(osa->handle, hwparams, &period_frames, NULL)) < 0) {
|
||||||
outstream_destroy_alsa(si, os);
|
outstream_destroy_alsa(si, os);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
snd_pcm_uframes_t period_size;
|
snd_pcm_uframes_t period_size;
|
||||||
if ((snd_pcm_hw_params_get_period_size(hwparams, &period_size, nullptr)) < 0) {
|
if ((snd_pcm_hw_params_get_period_size(hwparams, &period_size, NULL)) < 0) {
|
||||||
outstream_destroy_alsa(si, os);
|
outstream_destroy_alsa(si, os);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
@ -1343,7 +1351,7 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
|
||||||
|
|
||||||
if (osa->access == SND_PCM_ACCESS_RW_INTERLEAVED || osa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
|
if (osa->access == SND_PCM_ACCESS_RW_INTERLEAVED || osa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
|
||||||
osa->sample_buffer_size = ch_count * osa->period_size * phys_bytes_per_sample;
|
osa->sample_buffer_size = ch_count * osa->period_size * phys_bytes_per_sample;
|
||||||
osa->sample_buffer = allocate_nonzero<char>(osa->sample_buffer_size);
|
osa->sample_buffer = ALLOCATE_NONZERO(char, osa->sample_buffer_size);
|
||||||
if (!osa->sample_buffer) {
|
if (!osa->sample_buffer) {
|
||||||
outstream_destroy_alsa(si, os);
|
outstream_destroy_alsa(si, os);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
|
@ -1356,7 +1364,7 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
osa->poll_fds = allocate<struct pollfd>(osa->poll_fd_count);
|
osa->poll_fds = ALLOCATE(struct pollfd, osa->poll_fd_count);
|
||||||
if (!osa->poll_fds) {
|
if (!osa->poll_fds) {
|
||||||
outstream_destroy_alsa(si, os);
|
outstream_destroy_alsa(si, os);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
|
@ -1370,26 +1378,26 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_start_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
static int outstream_start_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
|
|
||||||
assert(!osa->thread);
|
assert(!osa->thread);
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
osa->thread_exit_flag.test_and_set();
|
atomic_flag_test_and_set(&osa->thread_exit_flag);
|
||||||
if ((err = soundio_os_thread_create(outstream_thread_run, os, soundio->emit_rtprio_warning, &osa->thread)))
|
if ((err = soundio_os_thread_create(outstream_thread_run, os, soundio->emit_rtprio_warning, &osa->thread)))
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_begin_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os,
|
static int outstream_begin_write_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
||||||
struct SoundIoChannelArea **out_areas, int *frame_count)
|
struct SoundIoChannelArea **out_areas, int *frame_count)
|
||||||
{
|
{
|
||||||
*out_areas = nullptr;
|
*out_areas = NULL;
|
||||||
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
|
|
||||||
if (osa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
if (osa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
||||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||||
|
@ -1397,7 +1405,7 @@ static int outstream_begin_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivat
|
||||||
osa->areas[ch].step = outstream->bytes_per_frame;
|
osa->areas[ch].step = outstream->bytes_per_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
osa->write_frame_count = min(*frame_count, osa->period_size);
|
osa->write_frame_count = soundio_int_min(*frame_count, osa->period_size);
|
||||||
*frame_count = osa->write_frame_count;
|
*frame_count = osa->write_frame_count;
|
||||||
} else if (osa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
|
} else if (osa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
|
||||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||||
|
@ -1405,7 +1413,7 @@ static int outstream_begin_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivat
|
||||||
osa->areas[ch].step = outstream->bytes_per_sample;
|
osa->areas[ch].step = outstream->bytes_per_sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
osa->write_frame_count = min(*frame_count, osa->period_size);
|
osa->write_frame_count = soundio_int_min(*frame_count, osa->period_size);
|
||||||
*frame_count = osa->write_frame_count;
|
*frame_count = osa->write_frame_count;
|
||||||
} else {
|
} else {
|
||||||
const snd_pcm_channel_area_t *areas;
|
const snd_pcm_channel_area_t *areas;
|
||||||
|
@ -1435,9 +1443,9 @@ static int outstream_begin_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivat
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_end_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
static int outstream_end_write_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
|
|
||||||
snd_pcm_sframes_t commitres;
|
snd_pcm_sframes_t commitres;
|
||||||
if (osa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
if (osa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
||||||
|
@ -1462,11 +1470,11 @@ static int outstream_end_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_clear_buffer_alsa(SoundIoPrivate *si,
|
static int outstream_clear_buffer_alsa(struct SoundIoPrivate *si,
|
||||||
SoundIoOutStreamPrivate *os)
|
struct SoundIoOutStreamPrivate *os)
|
||||||
{
|
{
|
||||||
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
osa->clear_buffer_flag.clear();
|
atomic_flag_clear(&osa->clear_buffer_flag);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1474,7 +1482,7 @@ static int outstream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoOutStre
|
||||||
if (!si)
|
if (!si)
|
||||||
return SoundIoErrorInvalid;
|
return SoundIoErrorInvalid;
|
||||||
|
|
||||||
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
|
|
||||||
if (!osa->handle)
|
if (!osa->handle)
|
||||||
return SoundIoErrorInvalid;
|
return SoundIoErrorInvalid;
|
||||||
|
@ -1494,8 +1502,8 @@ static int outstream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoOutStre
|
||||||
static int outstream_get_latency_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
static int outstream_get_latency_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
||||||
double *out_latency)
|
double *out_latency)
|
||||||
{
|
{
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
struct SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
snd_pcm_sframes_t delay;
|
snd_pcm_sframes_t delay;
|
||||||
|
@ -1507,43 +1515,43 @@ static int outstream_get_latency_alsa(struct SoundIoPrivate *si, struct SoundIoO
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void instream_destroy_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
static void instream_destroy_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||||
|
|
||||||
if (isa->thread) {
|
if (isa->thread) {
|
||||||
isa->thread_exit_flag.clear();
|
atomic_flag_clear(&isa->thread_exit_flag);
|
||||||
soundio_os_thread_destroy(isa->thread);
|
soundio_os_thread_destroy(isa->thread);
|
||||||
isa->thread = nullptr;
|
isa->thread = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isa->handle) {
|
if (isa->handle) {
|
||||||
snd_pcm_close(isa->handle);
|
snd_pcm_close(isa->handle);
|
||||||
isa->handle = nullptr;
|
isa->handle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(isa->poll_fds);
|
free(isa->poll_fds);
|
||||||
isa->poll_fds = nullptr;
|
isa->poll_fds = NULL;
|
||||||
|
|
||||||
free(isa->chmap);
|
free(isa->chmap);
|
||||||
isa->chmap = nullptr;
|
isa->chmap = NULL;
|
||||||
|
|
||||||
free(isa->sample_buffer);
|
free(isa->sample_buffer);
|
||||||
isa->sample_buffer = nullptr;
|
isa->sample_buffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
static int instream_open_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoDevice *device = instream->device;
|
struct SoundIoDevice *device = instream->device;
|
||||||
|
|
||||||
if (instream->software_latency == 0.0)
|
if (instream->software_latency == 0.0)
|
||||||
instream->software_latency = 1.0;
|
instream->software_latency = 1.0;
|
||||||
instream->software_latency = clamp(device->software_latency_min, instream->software_latency, device->software_latency_max);
|
instream->software_latency = soundio_double_clamp(device->software_latency_min, instream->software_latency, device->software_latency_max);
|
||||||
|
|
||||||
int ch_count = instream->layout.channel_count;
|
int ch_count = instream->layout.channel_count;
|
||||||
|
|
||||||
isa->chmap_size = sizeof(int) + sizeof(int) * ch_count;
|
isa->chmap_size = sizeof(int) + sizeof(int) * ch_count;
|
||||||
isa->chmap = (snd_pcm_chmap_t *)allocate<char>(isa->chmap_size);
|
isa->chmap = (snd_pcm_chmap_t *)ALLOCATE(char, isa->chmap_size);
|
||||||
if (!isa->chmap) {
|
if (!isa->chmap) {
|
||||||
instream_destroy_alsa(si, is);
|
instream_destroy_alsa(si, is);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
|
@ -1600,7 +1608,7 @@ static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
}
|
}
|
||||||
|
|
||||||
snd_pcm_uframes_t period_frames = ceil_dbl_to_uframes(0.5 * instream->software_latency * (double)instream->sample_rate);
|
snd_pcm_uframes_t period_frames = ceil_dbl_to_uframes(0.5 * instream->software_latency * (double)instream->sample_rate);
|
||||||
if ((err = snd_pcm_hw_params_set_period_size_near(isa->handle, hwparams, &period_frames, nullptr)) < 0) {
|
if ((err = snd_pcm_hw_params_set_period_size_near(isa->handle, hwparams, &period_frames, NULL)) < 0) {
|
||||||
instream_destroy_alsa(si, is);
|
instream_destroy_alsa(si, is);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
@ -1645,7 +1653,7 @@ static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
|
|
||||||
if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED || isa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
|
if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED || isa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
|
||||||
isa->sample_buffer_size = ch_count * isa->period_size * phys_bytes_per_sample;
|
isa->sample_buffer_size = ch_count * isa->period_size * phys_bytes_per_sample;
|
||||||
isa->sample_buffer = allocate_nonzero<char>(isa->sample_buffer_size);
|
isa->sample_buffer = ALLOCATE_NONZERO(char, isa->sample_buffer_size);
|
||||||
if (!isa->sample_buffer) {
|
if (!isa->sample_buffer) {
|
||||||
instream_destroy_alsa(si, is);
|
instream_destroy_alsa(si, is);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
|
@ -1658,7 +1666,7 @@ static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
isa->poll_fds = allocate<struct pollfd>(isa->poll_fd_count);
|
isa->poll_fds = ALLOCATE(struct pollfd, isa->poll_fd_count);
|
||||||
if (!isa->poll_fds) {
|
if (!isa->poll_fds) {
|
||||||
instream_destroy_alsa(si, is);
|
instream_destroy_alsa(si, is);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
|
@ -1672,13 +1680,13 @@ static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_start_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
static int instream_start_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
|
|
||||||
assert(!isa->thread);
|
assert(!isa->thread);
|
||||||
|
|
||||||
isa->thread_exit_flag.test_and_set();
|
atomic_flag_test_and_set(&isa->thread_exit_flag);
|
||||||
int err;
|
int err;
|
||||||
if ((err = soundio_os_thread_create(instream_thread_run, is, soundio->emit_rtprio_warning, &isa->thread))) {
|
if ((err = soundio_os_thread_create(instream_thread_run, is, soundio->emit_rtprio_warning, &isa->thread))) {
|
||||||
instream_destroy_alsa(si, is);
|
instream_destroy_alsa(si, is);
|
||||||
|
@ -1688,12 +1696,12 @@ static int instream_start_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_begin_read_alsa(SoundIoPrivate *si,
|
static int instream_begin_read_alsa(struct SoundIoPrivate *si,
|
||||||
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count)
|
struct SoundIoInStreamPrivate *is, struct SoundIoChannelArea **out_areas, int *frame_count)
|
||||||
{
|
{
|
||||||
*out_areas = nullptr;
|
*out_areas = NULL;
|
||||||
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
|
|
||||||
if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
||||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||||
|
@ -1701,7 +1709,7 @@ static int instream_begin_read_alsa(SoundIoPrivate *si,
|
||||||
isa->areas[ch].step = instream->bytes_per_frame;
|
isa->areas[ch].step = instream->bytes_per_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
isa->read_frame_count = min(*frame_count, isa->period_size);
|
isa->read_frame_count = soundio_int_min(*frame_count, isa->period_size);
|
||||||
*frame_count = isa->read_frame_count;
|
*frame_count = isa->read_frame_count;
|
||||||
|
|
||||||
snd_pcm_sframes_t commitres = snd_pcm_readi(isa->handle, isa->sample_buffer, isa->read_frame_count);
|
snd_pcm_sframes_t commitres = snd_pcm_readi(isa->handle, isa->sample_buffer, isa->read_frame_count);
|
||||||
|
@ -1718,7 +1726,7 @@ static int instream_begin_read_alsa(SoundIoPrivate *si,
|
||||||
ptrs[ch] = isa->areas[ch].ptr;
|
ptrs[ch] = isa->areas[ch].ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
isa->read_frame_count = min(*frame_count, isa->period_size);
|
isa->read_frame_count = soundio_int_min(*frame_count, isa->period_size);
|
||||||
*frame_count = isa->read_frame_count;
|
*frame_count = isa->read_frame_count;
|
||||||
|
|
||||||
snd_pcm_sframes_t commitres = snd_pcm_readn(isa->handle, (void**)ptrs, isa->read_frame_count);
|
snd_pcm_sframes_t commitres = snd_pcm_readn(isa->handle, (void**)ptrs, isa->read_frame_count);
|
||||||
|
@ -1753,8 +1761,8 @@ static int instream_begin_read_alsa(SoundIoPrivate *si,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_end_read_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
static int instream_end_read_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||||
|
|
||||||
if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
|
@ -1773,7 +1781,7 @@ static int instream_end_read_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
|
static int instream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
|
||||||
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||||
|
|
||||||
if (isa->is_paused == pause)
|
if (isa->is_paused == pause)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1789,8 +1797,8 @@ static int instream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoInStream
|
||||||
static int instream_get_latency_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
|
static int instream_get_latency_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
|
||||||
double *out_latency)
|
double *out_latency)
|
||||||
{
|
{
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
snd_pcm_sframes_t delay;
|
snd_pcm_sframes_t delay;
|
||||||
|
@ -1802,13 +1810,13 @@ static int instream_get_latency_alsa(struct SoundIoPrivate *si, struct SoundIoIn
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_alsa_init(SoundIoPrivate *si) {
|
int soundio_alsa_init(struct SoundIoPrivate *si) {
|
||||||
SoundIoAlsa *sia = &si->backend_data.alsa;
|
struct SoundIoAlsa *sia = &si->backend_data.alsa;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
sia->notify_fd = -1;
|
sia->notify_fd = -1;
|
||||||
sia->notify_wd = -1;
|
sia->notify_wd = -1;
|
||||||
sia->abort_flag.test_and_set();
|
atomic_flag_test_and_set(&sia->abort_flag);
|
||||||
|
|
||||||
sia->mutex = soundio_os_mutex_create();
|
sia->mutex = soundio_os_mutex_create();
|
||||||
if (!sia->mutex) {
|
if (!sia->mutex) {
|
||||||
|
@ -1865,7 +1873,7 @@ int soundio_alsa_init(SoundIoPrivate *si) {
|
||||||
|
|
||||||
wakeup_device_poll(sia);
|
wakeup_device_poll(sia);
|
||||||
|
|
||||||
if ((err = soundio_os_thread_create(device_thread_run, si, nullptr, &sia->thread))) {
|
if ((err = soundio_os_thread_create(device_thread_run, si, NULL, &sia->thread))) {
|
||||||
destroy_alsa(si);
|
destroy_alsa(si);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
|
@ -5,28 +5,31 @@
|
||||||
* See http://opensource.org/licenses/MIT
|
* See http://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SOUNDIO_ALSA_HPP
|
#ifndef SOUNDIO_ALSA_H
|
||||||
#define SOUNDIO_ALSA_HPP
|
#define SOUNDIO_ALSA_H
|
||||||
|
|
||||||
#include "soundio_private.h"
|
#include "soundio_internal.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "atomics.hpp"
|
#include "list.h"
|
||||||
#include "list.hpp"
|
#include "atomics.h"
|
||||||
|
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
|
|
||||||
|
struct SoundIoPrivate;
|
||||||
int soundio_alsa_init(struct SoundIoPrivate *si);
|
int soundio_alsa_init(struct SoundIoPrivate *si);
|
||||||
|
|
||||||
struct SoundIoDeviceAlsa { };
|
struct SoundIoDeviceAlsa { int make_the_struct_not_empty; };
|
||||||
|
|
||||||
#define SOUNDIO_MAX_ALSA_SND_FILE_LEN 16
|
#define SOUNDIO_MAX_ALSA_SND_FILE_LEN 16
|
||||||
struct SoundIoAlsaPendingFile {
|
struct SoundIoAlsaPendingFile {
|
||||||
char name[SOUNDIO_MAX_ALSA_SND_FILE_LEN];
|
char name[SOUNDIO_MAX_ALSA_SND_FILE_LEN];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SOUNDIO_MAKE_LIST_STRUCT(struct SoundIoAlsaPendingFile, SoundIoListAlsaPendingFile, SOUNDIO_LIST_STATIC)
|
||||||
|
|
||||||
struct SoundIoAlsa {
|
struct SoundIoAlsa {
|
||||||
SoundIoOsMutex *mutex;
|
struct SoundIoOsMutex *mutex;
|
||||||
SoundIoOsCond *cond;
|
struct SoundIoOsCond *cond;
|
||||||
|
|
||||||
struct SoundIoOsThread *thread;
|
struct SoundIoOsThread *thread;
|
||||||
atomic_flag abort_flag;
|
atomic_flag abort_flag;
|
||||||
|
@ -34,7 +37,7 @@ struct SoundIoAlsa {
|
||||||
int notify_wd;
|
int notify_wd;
|
||||||
bool have_devices_flag;
|
bool have_devices_flag;
|
||||||
int notify_pipe_fd[2];
|
int notify_pipe_fd[2];
|
||||||
SoundIoList<SoundIoAlsaPendingFile> pending_files;
|
struct SoundIoListAlsaPendingFile pending_files;
|
||||||
|
|
||||||
// this one is ready to be read with flush_events. protected by mutex
|
// this one is ready to be read with flush_events. protected by mutex
|
||||||
struct SoundIoDevicesInfo *ready_devices_info;
|
struct SoundIoDevicesInfo *ready_devices_info;
|
||||||
|
@ -54,13 +57,13 @@ struct SoundIoOutStreamAlsa {
|
||||||
char *sample_buffer;
|
char *sample_buffer;
|
||||||
int poll_fd_count;
|
int poll_fd_count;
|
||||||
struct pollfd *poll_fds;
|
struct pollfd *poll_fds;
|
||||||
SoundIoOsThread *thread;
|
struct SoundIoOsThread *thread;
|
||||||
atomic_flag thread_exit_flag;
|
atomic_flag thread_exit_flag;
|
||||||
int period_size;
|
int period_size;
|
||||||
int write_frame_count;
|
int write_frame_count;
|
||||||
bool is_paused;
|
bool is_paused;
|
||||||
atomic_flag clear_buffer_flag;
|
atomic_flag clear_buffer_flag;
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoInStreamAlsa {
|
struct SoundIoInStreamAlsa {
|
||||||
|
@ -73,12 +76,12 @@ struct SoundIoInStreamAlsa {
|
||||||
char *sample_buffer;
|
char *sample_buffer;
|
||||||
int poll_fd_count;
|
int poll_fd_count;
|
||||||
struct pollfd *poll_fds;
|
struct pollfd *poll_fds;
|
||||||
SoundIoOsThread *thread;
|
struct SoundIoOsThread *thread;
|
||||||
atomic_flag thread_exit_flag;
|
atomic_flag thread_exit_flag;
|
||||||
int period_size;
|
int period_size;
|
||||||
int read_frame_count;
|
int read_frame_count;
|
||||||
bool is_paused;
|
bool is_paused;
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
33
src/atomics.h
Normal file
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
|
* See http://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "soundio.hpp"
|
#include "soundio_private.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
@ -308,12 +308,12 @@ static struct SoundIoChannelLayout builtin_channel_layouts[] = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int channel_name_alias_count = 3;
|
#define CHANNEL_NAME_ALIAS_COUNT 3
|
||||||
static const char *channel_names[][channel_name_alias_count] = {
|
static const char *channel_names[][CHANNEL_NAME_ALIAS_COUNT] = {
|
||||||
[SoundIoChannelIdInvalid] = {
|
[SoundIoChannelIdInvalid] = {
|
||||||
"(Invalid Channel)",
|
"(Invalid Channel)",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdFrontLeft] = {
|
[SoundIoChannelIdFrontLeft] = {
|
||||||
"Front Left",
|
"Front Left",
|
||||||
|
@ -407,258 +407,258 @@ static const char *channel_names[][channel_name_alias_count] = {
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdBackLeftCenter] = {
|
[SoundIoChannelIdBackLeftCenter] = {
|
||||||
"Back Left Center",
|
"Back Left Center",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdBackRightCenter] = {
|
[SoundIoChannelIdBackRightCenter] = {
|
||||||
"Back Right Center",
|
"Back Right Center",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdFrontLeftWide] = {
|
[SoundIoChannelIdFrontLeftWide] = {
|
||||||
"Front Left Wide",
|
"Front Left Wide",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdFrontRightWide] = {
|
[SoundIoChannelIdFrontRightWide] = {
|
||||||
"Front Right Wide",
|
"Front Right Wide",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdFrontLeftHigh] = {
|
[SoundIoChannelIdFrontLeftHigh] = {
|
||||||
"Front Left High",
|
"Front Left High",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdFrontCenterHigh] = {
|
[SoundIoChannelIdFrontCenterHigh] = {
|
||||||
"Front Center High",
|
"Front Center High",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdFrontRightHigh] = {
|
[SoundIoChannelIdFrontRightHigh] = {
|
||||||
"Front Right High",
|
"Front Right High",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdTopFrontLeftCenter] = {
|
[SoundIoChannelIdTopFrontLeftCenter] = {
|
||||||
"Top Front Left Center",
|
"Top Front Left Center",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdTopFrontRightCenter] = {
|
[SoundIoChannelIdTopFrontRightCenter] = {
|
||||||
"Top Front Right Center",
|
"Top Front Right Center",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdTopSideLeft] = {
|
[SoundIoChannelIdTopSideLeft] = {
|
||||||
"Top Side Left",
|
"Top Side Left",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdTopSideRight] = {
|
[SoundIoChannelIdTopSideRight] = {
|
||||||
"Top Side Right",
|
"Top Side Right",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdLeftLfe] = {
|
[SoundIoChannelIdLeftLfe] = {
|
||||||
"Left LFE",
|
"Left LFE",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdRightLfe] = {
|
[SoundIoChannelIdRightLfe] = {
|
||||||
"Right LFE",
|
"Right LFE",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdLfe2] = {
|
[SoundIoChannelIdLfe2] = {
|
||||||
"LFE 2",
|
"LFE 2",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdBottomCenter] = {
|
[SoundIoChannelIdBottomCenter] = {
|
||||||
"Bottom Center",
|
"Bottom Center",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdBottomLeftCenter] = {
|
[SoundIoChannelIdBottomLeftCenter] = {
|
||||||
"Bottom Left Center",
|
"Bottom Left Center",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdBottomRightCenter] = {
|
[SoundIoChannelIdBottomRightCenter] = {
|
||||||
"Bottom Right Center",
|
"Bottom Right Center",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdMsMid] = {
|
[SoundIoChannelIdMsMid] = {
|
||||||
"Mid/Side Mid",
|
"Mid/Side Mid",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdMsSide] = {
|
[SoundIoChannelIdMsSide] = {
|
||||||
"Mid/Side Side",
|
"Mid/Side Side",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAmbisonicW] = {
|
[SoundIoChannelIdAmbisonicW] = {
|
||||||
"Ambisonic W",
|
"Ambisonic W",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAmbisonicX] = {
|
[SoundIoChannelIdAmbisonicX] = {
|
||||||
"Ambisonic X",
|
"Ambisonic X",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAmbisonicY] = {
|
[SoundIoChannelIdAmbisonicY] = {
|
||||||
"Ambisonic Y",
|
"Ambisonic Y",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAmbisonicZ] = {
|
[SoundIoChannelIdAmbisonicZ] = {
|
||||||
"Ambisonic Z",
|
"Ambisonic Z",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdXyX] = {
|
[SoundIoChannelIdXyX] = {
|
||||||
"X-Y X",
|
"X-Y X",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdXyY] = {
|
[SoundIoChannelIdXyY] = {
|
||||||
"X-Y Y",
|
"X-Y Y",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdHeadphonesLeft] = {
|
[SoundIoChannelIdHeadphonesLeft] = {
|
||||||
"Headphones Left",
|
"Headphones Left",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdHeadphonesRight] = {
|
[SoundIoChannelIdHeadphonesRight] = {
|
||||||
"Headphones Right",
|
"Headphones Right",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdClickTrack] = {
|
[SoundIoChannelIdClickTrack] = {
|
||||||
"Click Track",
|
"Click Track",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdForeignLanguage] = {
|
[SoundIoChannelIdForeignLanguage] = {
|
||||||
"Foreign Language",
|
"Foreign Language",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdHearingImpaired] = {
|
[SoundIoChannelIdHearingImpaired] = {
|
||||||
"Hearing Impaired",
|
"Hearing Impaired",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdNarration] = {
|
[SoundIoChannelIdNarration] = {
|
||||||
"Narration",
|
"Narration",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdHaptic] = {
|
[SoundIoChannelIdHaptic] = {
|
||||||
"Haptic",
|
"Haptic",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdDialogCentricMix] = {
|
[SoundIoChannelIdDialogCentricMix] = {
|
||||||
"Dialog Centric Mix",
|
"Dialog Centric Mix",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAux] = {
|
[SoundIoChannelIdAux] = {
|
||||||
"Aux",
|
"Aux",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAux0] = {
|
[SoundIoChannelIdAux0] = {
|
||||||
"Aux 0",
|
"Aux 0",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAux1] = {
|
[SoundIoChannelIdAux1] = {
|
||||||
"Aux 1",
|
"Aux 1",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAux2] = {
|
[SoundIoChannelIdAux2] = {
|
||||||
"Aux 2",
|
"Aux 2",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAux3] = {
|
[SoundIoChannelIdAux3] = {
|
||||||
"Aux 3",
|
"Aux 3",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAux4] = {
|
[SoundIoChannelIdAux4] = {
|
||||||
"Aux 4",
|
"Aux 4",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAux5] = {
|
[SoundIoChannelIdAux5] = {
|
||||||
"Aux 5",
|
"Aux 5",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAux6] = {
|
[SoundIoChannelIdAux6] = {
|
||||||
"Aux 6",
|
"Aux 6",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAux7] = {
|
[SoundIoChannelIdAux7] = {
|
||||||
"Aux 7",
|
"Aux 7",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAux8] = {
|
[SoundIoChannelIdAux8] = {
|
||||||
"Aux 8",
|
"Aux 8",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAux9] = {
|
[SoundIoChannelIdAux9] = {
|
||||||
"Aux 9",
|
"Aux 9",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAux10] = {
|
[SoundIoChannelIdAux10] = {
|
||||||
"Aux 10",
|
"Aux 10",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAux11] = {
|
[SoundIoChannelIdAux11] = {
|
||||||
"Aux 11",
|
"Aux 11",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAux12] = {
|
[SoundIoChannelIdAux12] = {
|
||||||
"Aux 12",
|
"Aux 12",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAux13] = {
|
[SoundIoChannelIdAux13] = {
|
||||||
"Aux 13",
|
"Aux 13",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAux14] = {
|
[SoundIoChannelIdAux14] = {
|
||||||
"Aux 14",
|
"Aux 14",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
[SoundIoChannelIdAux15] = {
|
[SoundIoChannelIdAux15] = {
|
||||||
"Aux 15",
|
"Aux 15",
|
||||||
nullptr,
|
NULL,
|
||||||
nullptr,
|
NULL,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *soundio_get_channel_name(enum SoundIoChannelId id) {
|
const char *soundio_get_channel_name(enum SoundIoChannelId id) {
|
||||||
if (id < 0 || id > array_length(channel_names))
|
if (id >= ARRAY_LENGTH(channel_names))
|
||||||
return "(Invalid Channel)";
|
return "(Invalid Channel)";
|
||||||
else
|
else
|
||||||
return channel_names[id][0];
|
return channel_names[id][0];
|
||||||
|
@ -680,12 +680,12 @@ bool soundio_channel_layout_equal(
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_channel_layout_builtin_count(void) {
|
int soundio_channel_layout_builtin_count(void) {
|
||||||
return array_length(builtin_channel_layouts);
|
return ARRAY_LENGTH(builtin_channel_layouts);
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct SoundIoChannelLayout *soundio_channel_layout_get_builtin(int index) {
|
const struct SoundIoChannelLayout *soundio_channel_layout_get_builtin(int index) {
|
||||||
assert(index >= 0);
|
assert(index >= 0);
|
||||||
assert(index <= array_length(builtin_channel_layouts));
|
assert(index <= ARRAY_LENGTH(builtin_channel_layouts));
|
||||||
return &builtin_channel_layouts[index];
|
return &builtin_channel_layouts[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -700,14 +700,14 @@ int soundio_channel_layout_find_channel(
|
||||||
}
|
}
|
||||||
|
|
||||||
bool soundio_channel_layout_detect_builtin(struct SoundIoChannelLayout *layout) {
|
bool soundio_channel_layout_detect_builtin(struct SoundIoChannelLayout *layout) {
|
||||||
for (int i = 0; i < array_length(builtin_channel_layouts); i += 1) {
|
for (int i = 0; i < ARRAY_LENGTH(builtin_channel_layouts); i += 1) {
|
||||||
const struct SoundIoChannelLayout *builtin_layout = &builtin_channel_layouts[i];
|
const struct SoundIoChannelLayout *builtin_layout = &builtin_channel_layouts[i];
|
||||||
if (soundio_channel_layout_equal(builtin_layout, layout)) {
|
if (soundio_channel_layout_equal(builtin_layout, layout)) {
|
||||||
layout->name = builtin_layout->name;
|
layout->name = builtin_layout->name;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
layout->name = nullptr;
|
layout->name = NULL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -722,18 +722,18 @@ const struct SoundIoChannelLayout *soundio_channel_layout_get_default(int channe
|
||||||
case 7: return soundio_channel_layout_get_builtin(SoundIoChannelLayoutId6Point1);
|
case 7: return soundio_channel_layout_get_builtin(SoundIoChannelLayoutId6Point1);
|
||||||
case 8: return soundio_channel_layout_get_builtin(SoundIoChannelLayoutId7Point1);
|
case 8: return soundio_channel_layout_get_builtin(SoundIoChannelLayoutId7Point1);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SoundIoChannelId soundio_parse_channel_id(const char *str, int str_len) {
|
enum SoundIoChannelId soundio_parse_channel_id(const char *str, int str_len) {
|
||||||
for (int id = 0; id < array_length(channel_names); id += 1) {
|
for (int id = 0; id < ARRAY_LENGTH(channel_names); id += 1) {
|
||||||
for (int i = 0; i < channel_name_alias_count; i += 1) {
|
for (int i = 0; i < CHANNEL_NAME_ALIAS_COUNT; i += 1) {
|
||||||
const char *alias = channel_names[id][i];
|
const char *alias = channel_names[id][i];
|
||||||
if (!alias)
|
if (!alias)
|
||||||
break;
|
break;
|
||||||
int alias_len = strlen(alias);
|
int alias_len = strlen(alias);
|
||||||
if (soundio_streql(alias, alias_len, str, str_len))
|
if (soundio_streql(alias, alias_len, str, str_len))
|
||||||
return (SoundIoChannelId)id;
|
return (enum SoundIoChannelId)id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return SoundIoChannelIdInvalid;
|
return SoundIoChannelIdInvalid;
|
|
@ -5,8 +5,8 @@
|
||||||
* See http://opensource.org/licenses/MIT
|
* See http://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "coreaudio.hpp"
|
#include "coreaudio.h"
|
||||||
#include "soundio.hpp"
|
#include "soundio_private.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
@ -91,19 +91,21 @@ static AudioObjectPropertyAddress device_listen_props[] = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static SoundIoDeviceAim aims[] = {
|
static enum SoundIoDeviceAim aims[] = {
|
||||||
SoundIoDeviceAimInput,
|
SoundIoDeviceAimInput,
|
||||||
SoundIoDeviceAimOutput,
|
SoundIoDeviceAimOutput,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SOUNDIO_MAKE_LIST_DEF(AudioDeviceID, SoundIoListAudioDeviceID, SOUNDIO_LIST_STATIC)
|
||||||
|
|
||||||
static OSStatus on_devices_changed(AudioObjectID in_object_id, UInt32 in_number_addresses,
|
static OSStatus on_devices_changed(AudioObjectID in_object_id, UInt32 in_number_addresses,
|
||||||
const AudioObjectPropertyAddress in_addresses[], void *in_client_data)
|
const AudioObjectPropertyAddress in_addresses[], void *in_client_data)
|
||||||
{
|
{
|
||||||
SoundIoPrivate *si = (SoundIoPrivate*)in_client_data;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate*)in_client_data;
|
||||||
SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
||||||
|
|
||||||
sica->device_scan_queued.store(true);
|
SOUNDIO_ATOMIC_STORE(sica->device_scan_queued, true);
|
||||||
soundio_os_cond_signal(sica->scan_devices_cond, nullptr);
|
soundio_os_cond_signal(sica->scan_devices_cond, NULL);
|
||||||
|
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
@ -111,30 +113,30 @@ static OSStatus on_devices_changed(AudioObjectID in_object_id, UInt32 in_number_
|
||||||
static OSStatus on_service_restarted(AudioObjectID in_object_id, UInt32 in_number_addresses,
|
static OSStatus on_service_restarted(AudioObjectID in_object_id, UInt32 in_number_addresses,
|
||||||
const AudioObjectPropertyAddress in_addresses[], void *in_client_data)
|
const AudioObjectPropertyAddress in_addresses[], void *in_client_data)
|
||||||
{
|
{
|
||||||
SoundIoPrivate *si = (SoundIoPrivate*)in_client_data;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate*)in_client_data;
|
||||||
SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
||||||
|
|
||||||
sica->service_restarted.store(true);
|
SOUNDIO_ATOMIC_STORE(sica->service_restarted, true);
|
||||||
soundio_os_cond_signal(sica->scan_devices_cond, nullptr);
|
soundio_os_cond_signal(sica->scan_devices_cond, NULL);
|
||||||
|
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unsubscribe_device_listeners(SoundIoPrivate *si) {
|
static void unsubscribe_device_listeners(struct SoundIoPrivate *si) {
|
||||||
SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
||||||
|
|
||||||
for (int device_index = 0; device_index < sica->registered_listeners.length; device_index += 1) {
|
for (int device_index = 0; device_index < sica->registered_listeners.length; device_index += 1) {
|
||||||
AudioDeviceID device_id = sica->registered_listeners.at(device_index);
|
AudioDeviceID device_id = SoundIoListAudioDeviceID_val_at(&sica->registered_listeners, device_index);
|
||||||
for (int i = 0; i < array_length(device_listen_props); i += 1) {
|
for (int i = 0; i < ARRAY_LENGTH(device_listen_props); i += 1) {
|
||||||
AudioObjectRemovePropertyListener(device_id, &device_listen_props[i],
|
AudioObjectRemovePropertyListener(device_id, &device_listen_props[i],
|
||||||
on_devices_changed, si);
|
on_devices_changed, si);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sica->registered_listeners.clear();
|
SoundIoListAudioDeviceID_clear(&sica->registered_listeners);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy_ca(struct SoundIoPrivate *si) {
|
static void destroy_ca(struct SoundIoPrivate *si) {
|
||||||
SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
||||||
|
|
||||||
AudioObjectPropertyAddress prop_address = {
|
AudioObjectPropertyAddress prop_address = {
|
||||||
kAudioHardwarePropertyDevices,
|
kAudioHardwarePropertyDevices,
|
||||||
|
@ -147,11 +149,11 @@ static void destroy_ca(struct SoundIoPrivate *si) {
|
||||||
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop_address, on_service_restarted, si);
|
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop_address, on_service_restarted, si);
|
||||||
|
|
||||||
unsubscribe_device_listeners(si);
|
unsubscribe_device_listeners(si);
|
||||||
sica->registered_listeners.deinit();
|
SoundIoListAudioDeviceID_deinit(&sica->registered_listeners);
|
||||||
|
|
||||||
if (sica->thread) {
|
if (sica->thread) {
|
||||||
sica->abort_flag.clear();
|
atomic_flag_clear(&sica->abort_flag);
|
||||||
soundio_os_cond_signal(sica->scan_devices_cond, nullptr);
|
soundio_os_cond_signal(sica->scan_devices_cond, NULL);
|
||||||
soundio_os_thread_destroy(sica->thread);
|
soundio_os_thread_destroy(sica->thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +180,7 @@ static int from_cf_string(CFStringRef string_ref, char **out_str, int *out_str_l
|
||||||
|
|
||||||
CFIndex length = CFStringGetLength(string_ref);
|
CFIndex length = CFStringGetLength(string_ref);
|
||||||
CFIndex max_size = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
|
CFIndex max_size = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
|
||||||
char *buf = allocate_nonzero<char>(max_size);
|
char *buf = ALLOCATE_NONZERO(char, max_size);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
|
|
||||||
|
@ -192,12 +194,12 @@ static int from_cf_string(CFStringRef string_ref, char **out_str, int *out_str_l
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int aim_to_scope(SoundIoDeviceAim aim) {
|
static int aim_to_scope(enum SoundIoDeviceAim aim) {
|
||||||
return (aim == SoundIoDeviceAimInput) ?
|
return (aim == SoundIoDeviceAimInput) ?
|
||||||
kAudioObjectPropertyScopeInput : kAudioObjectPropertyScopeOutput;
|
kAudioObjectPropertyScopeInput : kAudioObjectPropertyScopeOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SoundIoChannelId from_channel_descr(const AudioChannelDescription *descr) {
|
static enum SoundIoChannelId from_channel_descr(const AudioChannelDescription *descr) {
|
||||||
switch (descr->mChannelLabel) {
|
switch (descr->mChannelLabel) {
|
||||||
default: return SoundIoChannelIdInvalid;
|
default: return SoundIoChannelIdInvalid;
|
||||||
case kAudioChannelLabel_Left: return SoundIoChannelIdFrontLeft;
|
case kAudioChannelLabel_Left: return SoundIoChannelIdFrontLeft;
|
||||||
|
@ -274,7 +276,7 @@ static SoundIoChannelId from_channel_descr(const AudioChannelDescription *descr)
|
||||||
// * SoundIoErrorIncompatibleDevice
|
// * SoundIoErrorIncompatibleDevice
|
||||||
// This does not handle all the possible layout enum values and it does not
|
// This does not handle all the possible layout enum values and it does not
|
||||||
// handle channel bitmaps.
|
// handle channel bitmaps.
|
||||||
static int from_coreaudio_layout(const AudioChannelLayout *ca_layout, SoundIoChannelLayout *layout) {
|
static int from_coreaudio_layout(const AudioChannelLayout *ca_layout, struct SoundIoChannelLayout *layout) {
|
||||||
switch (ca_layout->mChannelLayoutTag) {
|
switch (ca_layout->mChannelLayoutTag) {
|
||||||
case kAudioChannelLayoutTag_UseChannelDescriptions:
|
case kAudioChannelLayoutTag_UseChannelDescriptions:
|
||||||
{
|
{
|
||||||
|
@ -377,15 +379,15 @@ static bool all_channels_invalid(const struct SoundIoChannelLayout *layout) {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RefreshDevices {
|
struct RefreshDevices {
|
||||||
SoundIoPrivate *si;
|
struct SoundIoPrivate *si;
|
||||||
SoundIoDevicesInfo *devices_info;
|
struct SoundIoDevicesInfo *devices_info;
|
||||||
int devices_size;
|
int devices_size;
|
||||||
AudioObjectID *devices;
|
AudioObjectID *devices;
|
||||||
CFStringRef string_ref;
|
CFStringRef string_ref;
|
||||||
char *device_name;
|
char *device_name;
|
||||||
int device_name_len;
|
int device_name_len;
|
||||||
AudioBufferList *buffer_list;
|
AudioBufferList *buffer_list;
|
||||||
SoundIoDevice *device;
|
struct SoundIoDevice *device;
|
||||||
AudioChannelLayout *audio_channel_layout;
|
AudioChannelLayout *audio_channel_layout;
|
||||||
char *device_uid;
|
char *device_uid;
|
||||||
int device_uid_len;
|
int device_uid_len;
|
||||||
|
@ -393,7 +395,7 @@ struct RefreshDevices {
|
||||||
bool ok;
|
bool ok;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void deinit_refresh_devices(RefreshDevices *rd) {
|
static void deinit_refresh_devices(struct RefreshDevices *rd) {
|
||||||
if (!rd->ok)
|
if (!rd->ok)
|
||||||
unsubscribe_device_listeners(rd->si);
|
unsubscribe_device_listeners(rd->si);
|
||||||
soundio_destroy_devices_info(rd->devices_info);
|
soundio_destroy_devices_info(rd->devices_info);
|
||||||
|
@ -409,8 +411,8 @@ static void deinit_refresh_devices(RefreshDevices *rd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int refresh_devices(struct SoundIoPrivate *si) {
|
static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
||||||
|
|
||||||
UInt32 io_size;
|
UInt32 io_size;
|
||||||
OSStatus os_err;
|
OSStatus os_err;
|
||||||
|
@ -418,10 +420,10 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
|
|
||||||
unsubscribe_device_listeners(si);
|
unsubscribe_device_listeners(si);
|
||||||
|
|
||||||
RefreshDevices rd = {0};
|
struct RefreshDevices rd = {0};
|
||||||
rd.si = si;
|
rd.si = si;
|
||||||
|
|
||||||
if (!(rd.devices_info = allocate<SoundIoDevicesInfo>(1))) {
|
if (!(rd.devices_info = ALLOCATE(struct SoundIoDevicesInfo, 1))) {
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
@ -433,7 +435,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((os_err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
|
if ((os_err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
|
||||||
&prop_address, 0, nullptr, &io_size)))
|
&prop_address, 0, NULL, &io_size)))
|
||||||
{
|
{
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
|
@ -445,13 +447,13 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
int device_count = io_size / (UInt32)sizeof(AudioObjectID);
|
int device_count = io_size / (UInt32)sizeof(AudioObjectID);
|
||||||
if (device_count >= 1) {
|
if (device_count >= 1) {
|
||||||
rd.devices_size = io_size;
|
rd.devices_size = io_size;
|
||||||
rd.devices = (AudioObjectID *)allocate<char>(rd.devices_size);
|
rd.devices = (AudioObjectID *)ALLOCATE(char, rd.devices_size);
|
||||||
if (!rd.devices) {
|
if (!rd.devices) {
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((os_err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_address, 0, nullptr,
|
if ((os_err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_address, 0, NULL,
|
||||||
&io_size, rd.devices)))
|
&io_size, rd.devices)))
|
||||||
{
|
{
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
|
@ -462,7 +464,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
io_size = sizeof(AudioObjectID);
|
io_size = sizeof(AudioObjectID);
|
||||||
prop_address.mSelector = kAudioHardwarePropertyDefaultInputDevice;
|
prop_address.mSelector = kAudioHardwarePropertyDefaultInputDevice;
|
||||||
if ((os_err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_address,
|
if ((os_err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_address,
|
||||||
0, nullptr, &io_size, &default_input_id)))
|
0, NULL, &io_size, &default_input_id)))
|
||||||
{
|
{
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
|
@ -471,7 +473,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
io_size = sizeof(AudioObjectID);
|
io_size = sizeof(AudioObjectID);
|
||||||
prop_address.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
|
prop_address.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
|
||||||
if ((os_err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_address,
|
if ((os_err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_address,
|
||||||
0, nullptr, &io_size, &default_output_id)))
|
0, NULL, &io_size, &default_output_id)))
|
||||||
{
|
{
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
|
@ -481,8 +483,8 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
for (int device_i = 0; device_i < device_count; device_i += 1) {
|
for (int device_i = 0; device_i < device_count; device_i += 1) {
|
||||||
AudioObjectID device_id = rd.devices[device_i];
|
AudioObjectID device_id = rd.devices[device_i];
|
||||||
|
|
||||||
for (int i = 0; i < array_length(device_listen_props); i += 1) {
|
for (int i = 0; i < ARRAY_LENGTH(device_listen_props); i += 1) {
|
||||||
if ((err = sica->registered_listeners.add_one())) {
|
if ((err = SoundIoListAudioDeviceID_add_one(&sica->registered_listeners))) {
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
@ -492,7 +494,8 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
sica->registered_listeners.last() = device_id;
|
AudioDeviceID *last_device_id = SoundIoListAudioDeviceID_last_ptr(&sica->registered_listeners);
|
||||||
|
*last_device_id = device_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
prop_address.mSelector = kAudioObjectPropertyName;
|
prop_address.mSelector = kAudioObjectPropertyName;
|
||||||
|
@ -501,17 +504,17 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
io_size = sizeof(CFStringRef);
|
io_size = sizeof(CFStringRef);
|
||||||
if (rd.string_ref) {
|
if (rd.string_ref) {
|
||||||
CFRelease(rd.string_ref);
|
CFRelease(rd.string_ref);
|
||||||
rd.string_ref = nullptr;
|
rd.string_ref = NULL;
|
||||||
}
|
}
|
||||||
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address,
|
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address,
|
||||||
0, nullptr, &io_size, &rd.string_ref)))
|
0, NULL, &io_size, &rd.string_ref)))
|
||||||
{
|
{
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(rd.device_name);
|
free(rd.device_name);
|
||||||
rd.device_name = nullptr;
|
rd.device_name = NULL;
|
||||||
if ((err = from_cf_string(rd.string_ref, &rd.device_name, &rd.device_name_len))) {
|
if ((err = from_cf_string(rd.string_ref, &rd.device_name, &rd.device_name_len))) {
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return err;
|
return err;
|
||||||
|
@ -523,43 +526,43 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
io_size = sizeof(CFStringRef);
|
io_size = sizeof(CFStringRef);
|
||||||
if (rd.string_ref) {
|
if (rd.string_ref) {
|
||||||
CFRelease(rd.string_ref);
|
CFRelease(rd.string_ref);
|
||||||
rd.string_ref = nullptr;
|
rd.string_ref = NULL;
|
||||||
}
|
}
|
||||||
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address,
|
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address,
|
||||||
0, nullptr, &io_size, &rd.string_ref)))
|
0, NULL, &io_size, &rd.string_ref)))
|
||||||
{
|
{
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(rd.device_uid);
|
free(rd.device_uid);
|
||||||
rd.device_uid = nullptr;
|
rd.device_uid = NULL;
|
||||||
if ((err = from_cf_string(rd.string_ref, &rd.device_uid, &rd.device_uid_len))) {
|
if ((err = from_cf_string(rd.string_ref, &rd.device_uid, &rd.device_uid_len))) {
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (int aim_i = 0; aim_i < array_length(aims); aim_i += 1) {
|
for (int aim_i = 0; aim_i < ARRAY_LENGTH(aims); aim_i += 1) {
|
||||||
SoundIoDeviceAim aim = aims[aim_i];
|
enum SoundIoDeviceAim aim = aims[aim_i];
|
||||||
|
|
||||||
io_size = 0;
|
io_size = 0;
|
||||||
prop_address.mSelector = kAudioDevicePropertyStreamConfiguration;
|
prop_address.mSelector = kAudioDevicePropertyStreamConfiguration;
|
||||||
prop_address.mScope = aim_to_scope(aim);
|
prop_address.mScope = aim_to_scope(aim);
|
||||||
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
||||||
if ((os_err = AudioObjectGetPropertyDataSize(device_id, &prop_address, 0, nullptr, &io_size))) {
|
if ((os_err = AudioObjectGetPropertyDataSize(device_id, &prop_address, 0, NULL, &io_size))) {
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(rd.buffer_list);
|
free(rd.buffer_list);
|
||||||
rd.buffer_list = (AudioBufferList*)allocate_nonzero<char>(io_size);
|
rd.buffer_list = (AudioBufferList*)ALLOCATE_NONZERO(char, io_size);
|
||||||
if (!rd.buffer_list) {
|
if (!rd.buffer_list) {
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, nullptr,
|
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, NULL,
|
||||||
&io_size, rd.buffer_list)))
|
&io_size, rd.buffer_list)))
|
||||||
{
|
{
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
|
@ -574,12 +577,12 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
if (channel_count <= 0)
|
if (channel_count <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1);
|
struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
|
struct SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
|
||||||
dca->device_id = device_id;
|
dca->device_id = device_id;
|
||||||
assert(!rd.device);
|
assert(!rd.device);
|
||||||
rd.device = &dev->pub;
|
rd.device = &dev->pub;
|
||||||
|
@ -599,14 +602,14 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
prop_address.mScope = aim_to_scope(aim);
|
prop_address.mScope = aim_to_scope(aim);
|
||||||
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
||||||
if (!(os_err = AudioObjectGetPropertyDataSize(device_id, &prop_address,
|
if (!(os_err = AudioObjectGetPropertyDataSize(device_id, &prop_address,
|
||||||
0, nullptr, &io_size)))
|
0, NULL, &io_size)))
|
||||||
{
|
{
|
||||||
rd.audio_channel_layout = (AudioChannelLayout *)allocate<char>(io_size);
|
rd.audio_channel_layout = (AudioChannelLayout *)ALLOCATE(char, io_size);
|
||||||
if (!rd.audio_channel_layout) {
|
if (!rd.audio_channel_layout) {
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, nullptr,
|
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, NULL,
|
||||||
&io_size, rd.audio_channel_layout)))
|
&io_size, rd.audio_channel_layout)))
|
||||||
{
|
{
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
|
@ -635,7 +638,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
||||||
io_size = sizeof(double);
|
io_size = sizeof(double);
|
||||||
double value;
|
double value;
|
||||||
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, nullptr,
|
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, NULL,
|
||||||
&io_size, &value)))
|
&io_size, &value)))
|
||||||
{
|
{
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
|
@ -659,21 +662,21 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
prop_address.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
|
prop_address.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
|
||||||
prop_address.mScope = aim_to_scope(aim);
|
prop_address.mScope = aim_to_scope(aim);
|
||||||
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
||||||
if ((os_err = AudioObjectGetPropertyDataSize(device_id, &prop_address, 0, nullptr,
|
if ((os_err = AudioObjectGetPropertyDataSize(device_id, &prop_address, 0, NULL,
|
||||||
&io_size)))
|
&io_size)))
|
||||||
{
|
{
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
int avr_array_len = io_size / sizeof(AudioValueRange);
|
int avr_array_len = io_size / sizeof(AudioValueRange);
|
||||||
rd.avr_array = (AudioValueRange*)allocate<char>(io_size);
|
rd.avr_array = (AudioValueRange*)ALLOCATE(char, io_size);
|
||||||
|
|
||||||
if (!rd.avr_array) {
|
if (!rd.avr_array) {
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, nullptr,
|
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, NULL,
|
||||||
&io_size, rd.avr_array)))
|
&io_size, rd.avr_array)))
|
||||||
{
|
{
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
|
@ -687,7 +690,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
rd.device->sample_rates[0].max = (int)(rd.avr_array[0].mMaximum);
|
rd.device->sample_rates[0].max = (int)(rd.avr_array[0].mMaximum);
|
||||||
} else {
|
} else {
|
||||||
rd.device->sample_rate_count = avr_array_len;
|
rd.device->sample_rate_count = avr_array_len;
|
||||||
rd.device->sample_rates = allocate<SoundIoSampleRateRange>(avr_array_len);
|
rd.device->sample_rates = ALLOCATE(struct SoundIoSampleRateRange, avr_array_len);
|
||||||
if (!rd.device->sample_rates) {
|
if (!rd.device->sample_rates) {
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
|
@ -707,7 +710,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
||||||
io_size = sizeof(UInt32);
|
io_size = sizeof(UInt32);
|
||||||
UInt32 buffer_frame_size;
|
UInt32 buffer_frame_size;
|
||||||
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, nullptr,
|
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, NULL,
|
||||||
&io_size, &buffer_frame_size)))
|
&io_size, &buffer_frame_size)))
|
||||||
{
|
{
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
|
@ -721,7 +724,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
||||||
io_size = sizeof(AudioValueRange);
|
io_size = sizeof(AudioValueRange);
|
||||||
AudioValueRange avr;
|
AudioValueRange avr;
|
||||||
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, nullptr,
|
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, NULL,
|
||||||
&io_size, &avr)))
|
&io_size, &avr)))
|
||||||
{
|
{
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
|
@ -734,14 +737,14 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
prop_address.mScope = aim_to_scope(aim);
|
prop_address.mScope = aim_to_scope(aim);
|
||||||
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
||||||
io_size = sizeof(UInt32);
|
io_size = sizeof(UInt32);
|
||||||
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, nullptr,
|
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, NULL,
|
||||||
&io_size, &dca->latency_frames)))
|
&io_size, &dca->latency_frames)))
|
||||||
{
|
{
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundIoList<SoundIoDevice *> *device_list;
|
struct SoundIoListDevicePtr *device_list;
|
||||||
if (rd.device->aim == SoundIoDeviceAimOutput) {
|
if (rd.device->aim == SoundIoDeviceAimOutput) {
|
||||||
device_list = &rd.devices_info->output_devices;
|
device_list = &rd.devices_info->output_devices;
|
||||||
if (device_id == default_output_id)
|
if (device_id == default_output_id)
|
||||||
|
@ -753,11 +756,11 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
rd.devices_info->default_input_index = device_list->length;
|
rd.devices_info->default_input_index = device_list->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = device_list->append(rd.device))) {
|
if ((err = SoundIoListDevicePtr_append(device_list, rd.device))) {
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
rd.device = nullptr;
|
rd.device = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -766,36 +769,36 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
sica->ready_devices_info = rd.devices_info;
|
sica->ready_devices_info = rd.devices_info;
|
||||||
soundio_os_mutex_unlock(sica->mutex);
|
soundio_os_mutex_unlock(sica->mutex);
|
||||||
|
|
||||||
rd.devices_info = nullptr;
|
rd.devices_info = NULL;
|
||||||
rd.ok = true;
|
rd.ok = true;
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void shutdown_backend(SoundIoPrivate *si, int err) {
|
static void shutdown_backend(struct SoundIoPrivate *si, int err) {
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
||||||
soundio_os_mutex_lock(sica->mutex);
|
soundio_os_mutex_lock(sica->mutex);
|
||||||
sica->shutdown_err = err;
|
sica->shutdown_err = err;
|
||||||
sica->have_devices_flag.store(true);
|
SOUNDIO_ATOMIC_STORE(sica->have_devices_flag, true);
|
||||||
soundio_os_mutex_unlock(sica->mutex);
|
soundio_os_mutex_unlock(sica->mutex);
|
||||||
soundio_os_cond_signal(sica->cond, nullptr);
|
soundio_os_cond_signal(sica->cond, NULL);
|
||||||
soundio_os_cond_signal(sica->have_devices_cond, nullptr);
|
soundio_os_cond_signal(sica->have_devices_cond, NULL);
|
||||||
soundio->on_events_signal(soundio);
|
soundio->on_events_signal(soundio);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flush_events_ca(struct SoundIoPrivate *si) {
|
static void flush_events_ca(struct SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
||||||
|
|
||||||
// block until have devices
|
// block until have devices
|
||||||
while (!sica->have_devices_flag.load())
|
while (!SOUNDIO_ATOMIC_LOAD(sica->have_devices_flag))
|
||||||
soundio_os_cond_wait(sica->have_devices_cond, nullptr);
|
soundio_os_cond_wait(sica->have_devices_cond, NULL);
|
||||||
|
|
||||||
bool change = false;
|
bool change = false;
|
||||||
bool cb_shutdown = false;
|
bool cb_shutdown = false;
|
||||||
SoundIoDevicesInfo *old_devices_info = nullptr;
|
struct SoundIoDevicesInfo *old_devices_info = NULL;
|
||||||
|
|
||||||
soundio_os_mutex_lock(sica->mutex);
|
soundio_os_mutex_lock(sica->mutex);
|
||||||
|
|
||||||
|
@ -805,7 +808,7 @@ static void flush_events_ca(struct SoundIoPrivate *si) {
|
||||||
} else if (sica->ready_devices_info) {
|
} else if (sica->ready_devices_info) {
|
||||||
old_devices_info = si->safe_devices_info;
|
old_devices_info = si->safe_devices_info;
|
||||||
si->safe_devices_info = sica->ready_devices_info;
|
si->safe_devices_info = sica->ready_devices_info;
|
||||||
sica->ready_devices_info = nullptr;
|
sica->ready_devices_info = NULL;
|
||||||
change = true;
|
change = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -820,65 +823,65 @@ static void flush_events_ca(struct SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wait_events_ca(struct SoundIoPrivate *si) {
|
static void wait_events_ca(struct SoundIoPrivate *si) {
|
||||||
SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
||||||
flush_events_ca(si);
|
flush_events_ca(si);
|
||||||
soundio_os_cond_wait(sica->cond, nullptr);
|
soundio_os_cond_wait(sica->cond, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wakeup_ca(struct SoundIoPrivate *si) {
|
static void wakeup_ca(struct SoundIoPrivate *si) {
|
||||||
SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
||||||
soundio_os_cond_signal(sica->cond, nullptr);
|
soundio_os_cond_signal(sica->cond, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void force_device_scan_ca(struct SoundIoPrivate *si) {
|
static void force_device_scan_ca(struct SoundIoPrivate *si) {
|
||||||
SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
||||||
sica->device_scan_queued.store(true);
|
SOUNDIO_ATOMIC_STORE(sica->device_scan_queued, true);
|
||||||
soundio_os_cond_signal(sica->scan_devices_cond, nullptr);
|
soundio_os_cond_signal(sica->scan_devices_cond, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void device_thread_run(void *arg) {
|
static void device_thread_run(void *arg) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (!sica->abort_flag.test_and_set())
|
if (!atomic_flag_test_and_set(&sica->abort_flag))
|
||||||
break;
|
break;
|
||||||
if (sica->service_restarted.load()) {
|
if (SOUNDIO_ATOMIC_LOAD(sica->service_restarted)) {
|
||||||
shutdown_backend(si, SoundIoErrorBackendDisconnected);
|
shutdown_backend(si, SoundIoErrorBackendDisconnected);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sica->device_scan_queued.exchange(false)) {
|
if (SOUNDIO_ATOMIC_EXCHANGE(sica->device_scan_queued, false)) {
|
||||||
err = refresh_devices(si);
|
err = refresh_devices(si);
|
||||||
if (err) {
|
if (err) {
|
||||||
shutdown_backend(si, err);
|
shutdown_backend(si, err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!sica->have_devices_flag.exchange(true))
|
if (!SOUNDIO_ATOMIC_EXCHANGE(sica->have_devices_flag, true))
|
||||||
soundio_os_cond_signal(sica->have_devices_cond, nullptr);
|
soundio_os_cond_signal(sica->have_devices_cond, NULL);
|
||||||
soundio_os_cond_signal(sica->cond, nullptr);
|
soundio_os_cond_signal(sica->cond, NULL);
|
||||||
soundio->on_events_signal(soundio);
|
soundio->on_events_signal(soundio);
|
||||||
}
|
}
|
||||||
soundio_os_cond_wait(sica->scan_devices_cond, nullptr);
|
soundio_os_cond_wait(sica->scan_devices_cond, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static OSStatus on_outstream_device_overload(AudioObjectID in_object_id, UInt32 in_number_addresses,
|
static OSStatus on_outstream_device_overload(AudioObjectID in_object_id, UInt32 in_number_addresses,
|
||||||
const AudioObjectPropertyAddress in_addresses[], void *in_client_data)
|
const AudioObjectPropertyAddress in_addresses[], void *in_client_data)
|
||||||
{
|
{
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)in_client_data;
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)in_client_data;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
outstream->underflow_callback(outstream);
|
outstream->underflow_callback(outstream);
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void outstream_destroy_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
static void outstream_destroy_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
|
struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoDevice *device = outstream->device;
|
struct SoundIoDevice *device = outstream->device;
|
||||||
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
|
||||||
SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
|
struct SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
|
||||||
|
|
||||||
AudioObjectPropertyAddress prop_address = {
|
AudioObjectPropertyAddress prop_address = {
|
||||||
kAudioDeviceProcessorOverload,
|
kAudioDeviceProcessorOverload,
|
||||||
|
@ -890,7 +893,7 @@ static void outstream_destroy_ca(struct SoundIoPrivate *si, struct SoundIoOutStr
|
||||||
if (osca->instance) {
|
if (osca->instance) {
|
||||||
AudioOutputUnitStop(osca->instance);
|
AudioOutputUnitStop(osca->instance);
|
||||||
AudioComponentInstanceDispose(osca->instance);
|
AudioComponentInstanceDispose(osca->instance);
|
||||||
osca->instance = nullptr;
|
osca->instance = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -898,30 +901,30 @@ static OSStatus write_callback_ca(void *userdata, AudioUnitRenderActionFlags *io
|
||||||
const AudioTimeStamp *in_time_stamp, UInt32 in_bus_number, UInt32 in_number_frames,
|
const AudioTimeStamp *in_time_stamp, UInt32 in_bus_number, UInt32 in_number_frames,
|
||||||
AudioBufferList *io_data)
|
AudioBufferList *io_data)
|
||||||
{
|
{
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *) userdata;
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *) userdata;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
|
struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
|
||||||
|
|
||||||
osca->io_data = io_data;
|
osca->io_data = io_data;
|
||||||
osca->buffer_index = 0;
|
osca->buffer_index = 0;
|
||||||
osca->frames_left = in_number_frames;
|
osca->frames_left = in_number_frames;
|
||||||
outstream->write_callback(outstream, osca->frames_left, osca->frames_left);
|
outstream->write_callback(outstream, osca->frames_left, osca->frames_left);
|
||||||
osca->io_data = nullptr;
|
osca->io_data = NULL;
|
||||||
|
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_open_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
static int outstream_open_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
|
struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoDevice *device = outstream->device;
|
struct SoundIoDevice *device = outstream->device;
|
||||||
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
|
||||||
SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
|
struct SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
|
||||||
|
|
||||||
if (outstream->software_latency == 0.0)
|
if (outstream->software_latency == 0.0)
|
||||||
outstream->software_latency = device->software_latency_current;
|
outstream->software_latency = device->software_latency_current;
|
||||||
|
|
||||||
outstream->software_latency = clamp(
|
outstream->software_latency = soundio_double_clamp(
|
||||||
device->software_latency_min,
|
device->software_latency_min,
|
||||||
outstream->software_latency,
|
outstream->software_latency,
|
||||||
device->software_latency_max);
|
device->software_latency_max);
|
||||||
|
@ -931,7 +934,7 @@ static int outstream_open_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamP
|
||||||
desc.componentSubType = kAudioUnitSubType_HALOutput;
|
desc.componentSubType = kAudioUnitSubType_HALOutput;
|
||||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||||
|
|
||||||
AudioComponent component = AudioComponentFindNext(nullptr, &desc);
|
AudioComponent component = AudioComponentFindNext(NULL, &desc);
|
||||||
if (!component) {
|
if (!component) {
|
||||||
outstream_destroy_ca(si, os);
|
outstream_destroy_ca(si, os);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
|
@ -987,7 +990,7 @@ static int outstream_open_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamP
|
||||||
};
|
};
|
||||||
UInt32 buffer_frame_size = outstream->software_latency * outstream->sample_rate;
|
UInt32 buffer_frame_size = outstream->software_latency * outstream->sample_rate;
|
||||||
if ((os_err = AudioObjectSetPropertyData(dca->device_id, &prop_address,
|
if ((os_err = AudioObjectSetPropertyData(dca->device_id, &prop_address,
|
||||||
0, nullptr, sizeof(UInt32), &buffer_frame_size)))
|
0, NULL, sizeof(UInt32), &buffer_frame_size)))
|
||||||
{
|
{
|
||||||
outstream_destroy_ca(si, os);
|
outstream_destroy_ca(si, os);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
|
@ -1009,7 +1012,7 @@ static int outstream_open_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamP
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_pause_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
|
static int outstream_pause_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
|
||||||
SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
|
struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
|
||||||
OSStatus os_err;
|
OSStatus os_err;
|
||||||
if (pause) {
|
if (pause) {
|
||||||
if ((os_err = AudioOutputUnitStop(osca->instance))) {
|
if ((os_err = AudioOutputUnitStop(osca->instance))) {
|
||||||
|
@ -1029,10 +1032,10 @@ static int outstream_start_ca(struct SoundIoPrivate *si, struct SoundIoOutStream
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_begin_write_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
static int outstream_begin_write_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
||||||
SoundIoChannelArea **out_areas, int *frame_count)
|
struct SoundIoChannelArea **out_areas, int *frame_count)
|
||||||
{
|
{
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
|
struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
|
||||||
|
|
||||||
if (osca->buffer_index >= osca->io_data->mNumberBuffers)
|
if (osca->buffer_index >= osca->io_data->mNumberBuffers)
|
||||||
return SoundIoErrorInvalid;
|
return SoundIoErrorInvalid;
|
||||||
|
@ -1054,7 +1057,7 @@ static int outstream_begin_write_ca(struct SoundIoPrivate *si, struct SoundIoOut
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_end_write_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
static int outstream_end_write_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
|
struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
|
||||||
osca->buffer_index += 1;
|
osca->buffer_index += 1;
|
||||||
osca->frames_left -= osca->write_frame_count;
|
osca->frames_left -= osca->write_frame_count;
|
||||||
assert(osca->frames_left >= 0);
|
assert(osca->frames_left >= 0);
|
||||||
|
@ -1068,7 +1071,7 @@ static int outstream_clear_buffer_ca(struct SoundIoPrivate *si, struct SoundIoOu
|
||||||
static int outstream_get_latency_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
static int outstream_get_latency_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
||||||
double *out_latency)
|
double *out_latency)
|
||||||
{
|
{
|
||||||
SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
|
struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
|
||||||
*out_latency = osca->hardware_latency;
|
*out_latency = osca->hardware_latency;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1076,18 +1079,18 @@ static int outstream_get_latency_ca(struct SoundIoPrivate *si, struct SoundIoOut
|
||||||
static OSStatus on_instream_device_overload(AudioObjectID in_object_id, UInt32 in_number_addresses,
|
static OSStatus on_instream_device_overload(AudioObjectID in_object_id, UInt32 in_number_addresses,
|
||||||
const AudioObjectPropertyAddress in_addresses[], void *in_client_data)
|
const AudioObjectPropertyAddress in_addresses[], void *in_client_data)
|
||||||
{
|
{
|
||||||
SoundIoInStreamPrivate *os = (SoundIoInStreamPrivate *)in_client_data;
|
struct SoundIoInStreamPrivate *os = (struct SoundIoInStreamPrivate *)in_client_data;
|
||||||
SoundIoInStream *instream = &os->pub;
|
struct SoundIoInStream *instream = &os->pub;
|
||||||
instream->overflow_callback(instream);
|
instream->overflow_callback(instream);
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void instream_destroy_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
static void instream_destroy_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
|
struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoDevice *device = instream->device;
|
struct SoundIoDevice *device = instream->device;
|
||||||
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
|
||||||
SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
|
struct SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
|
||||||
|
|
||||||
AudioObjectPropertyAddress prop_address = {
|
AudioObjectPropertyAddress prop_address = {
|
||||||
kAudioDeviceProcessorOverload,
|
kAudioDeviceProcessorOverload,
|
||||||
|
@ -1099,23 +1102,23 @@ static void instream_destroy_ca(struct SoundIoPrivate *si, struct SoundIoInStrea
|
||||||
if (isca->instance) {
|
if (isca->instance) {
|
||||||
AudioOutputUnitStop(isca->instance);
|
AudioOutputUnitStop(isca->instance);
|
||||||
AudioComponentInstanceDispose(isca->instance);
|
AudioComponentInstanceDispose(isca->instance);
|
||||||
isca->instance = nullptr;
|
isca->instance = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(isca->buffer_list);
|
free(isca->buffer_list);
|
||||||
isca->buffer_list = nullptr;
|
isca->buffer_list = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static OSStatus read_callback_ca(void *userdata, AudioUnitRenderActionFlags *io_action_flags,
|
static OSStatus read_callback_ca(void *userdata, AudioUnitRenderActionFlags *io_action_flags,
|
||||||
const AudioTimeStamp *in_time_stamp, UInt32 in_bus_number, UInt32 in_number_frames,
|
const AudioTimeStamp *in_time_stamp, UInt32 in_bus_number, UInt32 in_number_frames,
|
||||||
AudioBufferList *io_data)
|
AudioBufferList *io_data)
|
||||||
{
|
{
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *) userdata;
|
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *) userdata;
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
|
struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
|
||||||
|
|
||||||
for (int i = 0; i < isca->buffer_list->mNumberBuffers; i += 1) {
|
for (int i = 0; i < isca->buffer_list->mNumberBuffers; i += 1) {
|
||||||
isca->buffer_list->mBuffers[i].mData = nullptr;
|
isca->buffer_list->mBuffers[i].mData = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
OSStatus os_err;
|
OSStatus os_err;
|
||||||
|
@ -1151,18 +1154,18 @@ static OSStatus read_callback_ca(void *userdata, AudioUnitRenderActionFlags *io_
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
|
struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoDevice *device = instream->device;
|
struct SoundIoDevice *device = instream->device;
|
||||||
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
|
||||||
SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
|
struct SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
|
||||||
UInt32 io_size;
|
UInt32 io_size;
|
||||||
OSStatus os_err;
|
OSStatus os_err;
|
||||||
|
|
||||||
if (instream->software_latency == 0.0)
|
if (instream->software_latency == 0.0)
|
||||||
instream->software_latency = device->software_latency_current;
|
instream->software_latency = device->software_latency_current;
|
||||||
|
|
||||||
instream->software_latency = clamp(
|
instream->software_latency = soundio_double_clamp(
|
||||||
device->software_latency_min,
|
device->software_latency_min,
|
||||||
instream->software_latency,
|
instream->software_latency,
|
||||||
device->software_latency_max);
|
device->software_latency_max);
|
||||||
|
@ -1174,20 +1177,20 @@ static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPri
|
||||||
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
||||||
io_size = 0;
|
io_size = 0;
|
||||||
if ((os_err = AudioObjectGetPropertyDataSize(dca->device_id, &prop_address,
|
if ((os_err = AudioObjectGetPropertyDataSize(dca->device_id, &prop_address,
|
||||||
0, nullptr, &io_size)))
|
0, NULL, &io_size)))
|
||||||
{
|
{
|
||||||
instream_destroy_ca(si, is);
|
instream_destroy_ca(si, is);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
isca->buffer_list = (AudioBufferList*)allocate_nonzero<char>(io_size);
|
isca->buffer_list = (AudioBufferList*)ALLOCATE_NONZERO(char, io_size);
|
||||||
if (!isca->buffer_list) {
|
if (!isca->buffer_list) {
|
||||||
instream_destroy_ca(si, is);
|
instream_destroy_ca(si, is);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((os_err = AudioObjectGetPropertyData(dca->device_id, &prop_address,
|
if ((os_err = AudioObjectGetPropertyData(dca->device_id, &prop_address,
|
||||||
0, nullptr, &io_size, isca->buffer_list)))
|
0, NULL, &io_size, isca->buffer_list)))
|
||||||
{
|
{
|
||||||
instream_destroy_ca(si, is);
|
instream_destroy_ca(si, is);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
|
@ -1199,7 +1202,7 @@ static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPri
|
||||||
desc.componentSubType = kAudioUnitSubType_HALOutput;
|
desc.componentSubType = kAudioUnitSubType_HALOutput;
|
||||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||||
|
|
||||||
AudioComponent component = AudioComponentFindNext(nullptr, &desc);
|
AudioComponent component = AudioComponentFindNext(NULL, &desc);
|
||||||
if (!component) {
|
if (!component) {
|
||||||
instream_destroy_ca(si, is);
|
instream_destroy_ca(si, is);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
|
@ -1270,7 +1273,7 @@ static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPri
|
||||||
prop_address.mElement = INPUT_ELEMENT;
|
prop_address.mElement = INPUT_ELEMENT;
|
||||||
UInt32 buffer_frame_size = instream->software_latency * instream->sample_rate;
|
UInt32 buffer_frame_size = instream->software_latency * instream->sample_rate;
|
||||||
if ((os_err = AudioObjectSetPropertyData(dca->device_id, &prop_address,
|
if ((os_err = AudioObjectSetPropertyData(dca->device_id, &prop_address,
|
||||||
0, nullptr, sizeof(UInt32), &buffer_frame_size)))
|
0, NULL, sizeof(UInt32), &buffer_frame_size)))
|
||||||
{
|
{
|
||||||
instream_destroy_ca(si, is);
|
instream_destroy_ca(si, is);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
|
@ -1291,7 +1294,7 @@ static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPri
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_pause_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
|
static int instream_pause_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
|
||||||
SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
|
struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
|
||||||
OSStatus os_err;
|
OSStatus os_err;
|
||||||
if (pause) {
|
if (pause) {
|
||||||
if ((os_err = AudioOutputUnitStop(isca->instance))) {
|
if ((os_err = AudioOutputUnitStop(isca->instance))) {
|
||||||
|
@ -1311,9 +1314,9 @@ static int instream_start_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPr
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_begin_read_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
|
static int instream_begin_read_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
|
||||||
SoundIoChannelArea **out_areas, int *frame_count)
|
struct SoundIoChannelArea **out_areas, int *frame_count)
|
||||||
{
|
{
|
||||||
SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
|
struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
|
||||||
|
|
||||||
if (*frame_count != isca->frames_left)
|
if (*frame_count != isca->frames_left)
|
||||||
return SoundIoErrorInvalid;
|
return SoundIoErrorInvalid;
|
||||||
|
@ -1324,7 +1327,7 @@ static int instream_begin_read_ca(struct SoundIoPrivate *si, struct SoundIoInStr
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_end_read_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
static int instream_end_read_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
|
struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
|
||||||
isca->frames_left = 0;
|
isca->frames_left = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1332,20 +1335,20 @@ static int instream_end_read_ca(struct SoundIoPrivate *si, struct SoundIoInStrea
|
||||||
static int instream_get_latency_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
|
static int instream_get_latency_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
|
||||||
double *out_latency)
|
double *out_latency)
|
||||||
{
|
{
|
||||||
SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
|
struct SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
|
||||||
*out_latency = isca->hardware_latency;
|
*out_latency = isca->hardware_latency;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int soundio_coreaudio_init(SoundIoPrivate *si) {
|
int soundio_coreaudio_init(struct SoundIoPrivate *si) {
|
||||||
SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
struct SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
sica->have_devices_flag.store(false);
|
SOUNDIO_ATOMIC_STORE(sica->have_devices_flag, false);
|
||||||
sica->device_scan_queued.store(true);
|
SOUNDIO_ATOMIC_STORE(sica->device_scan_queued, true);
|
||||||
sica->service_restarted.store(false);
|
SOUNDIO_ATOMIC_STORE(sica->service_restarted, false);
|
||||||
sica->abort_flag.test_and_set();
|
atomic_flag_test_and_set(&sica->abort_flag);
|
||||||
|
|
||||||
sica->mutex = soundio_os_mutex_create();
|
sica->mutex = soundio_os_mutex_create();
|
||||||
if (!sica->mutex) {
|
if (!sica->mutex) {
|
||||||
|
@ -1391,7 +1394,7 @@ int soundio_coreaudio_init(SoundIoPrivate *si) {
|
||||||
return SoundIoErrorSystemResources;
|
return SoundIoErrorSystemResources;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = soundio_os_thread_create(device_thread_run, si, nullptr, &sica->thread))) {
|
if ((err = soundio_os_thread_create(device_thread_run, si, NULL, &sica->thread))) {
|
||||||
destroy_ca(si);
|
destroy_ca(si);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
|
@ -5,17 +5,18 @@
|
||||||
* See http://opensource.org/licenses/MIT
|
* See http://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SOUNDIO_COREAUDIO_HPP
|
#ifndef SOUNDIO_COREAUDIO_H
|
||||||
#define SOUNDIO_COREAUDIO_HPP
|
#define SOUNDIO_COREAUDIO_H
|
||||||
|
|
||||||
#include "soundio_private.h"
|
#include "soundio_internal.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "atomics.hpp"
|
#include "list.h"
|
||||||
#include "list.hpp"
|
#include "atomics.h"
|
||||||
|
|
||||||
#include <CoreAudio/CoreAudio.h>
|
#include <CoreAudio/CoreAudio.h>
|
||||||
#include <AudioUnit/AudioUnit.h>
|
#include <AudioUnit/AudioUnit.h>
|
||||||
|
|
||||||
|
struct SoundIoPrivate;
|
||||||
int soundio_coreaudio_init(struct SoundIoPrivate *si);
|
int soundio_coreaudio_init(struct SoundIoPrivate *si);
|
||||||
|
|
||||||
struct SoundIoDeviceCoreAudio {
|
struct SoundIoDeviceCoreAudio {
|
||||||
|
@ -23,21 +24,23 @@ struct SoundIoDeviceCoreAudio {
|
||||||
UInt32 latency_frames;
|
UInt32 latency_frames;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SOUNDIO_MAKE_LIST_STRUCT(AudioDeviceID, SoundIoListAudioDeviceID, SOUNDIO_LIST_STATIC)
|
||||||
|
|
||||||
struct SoundIoCoreAudio {
|
struct SoundIoCoreAudio {
|
||||||
SoundIoOsMutex *mutex;
|
struct SoundIoOsMutex *mutex;
|
||||||
SoundIoOsCond *cond;
|
struct SoundIoOsCond *cond;
|
||||||
struct SoundIoOsThread *thread;
|
struct SoundIoOsThread *thread;
|
||||||
atomic_flag abort_flag;
|
atomic_flag abort_flag;
|
||||||
|
|
||||||
// this one is ready to be read with flush_events. protected by mutex
|
// this one is ready to be read with flush_events. protected by mutex
|
||||||
struct SoundIoDevicesInfo *ready_devices_info;
|
struct SoundIoDevicesInfo *ready_devices_info;
|
||||||
atomic_bool have_devices_flag;
|
struct SoundIoAtomicBool have_devices_flag;
|
||||||
SoundIoOsCond *have_devices_cond;
|
struct SoundIoOsCond *have_devices_cond;
|
||||||
SoundIoOsCond *scan_devices_cond;
|
struct SoundIoOsCond *scan_devices_cond;
|
||||||
SoundIoList<AudioDeviceID> registered_listeners;
|
struct SoundIoListAudioDeviceID registered_listeners;
|
||||||
|
|
||||||
atomic_bool device_scan_queued;
|
struct SoundIoAtomicBool device_scan_queued;
|
||||||
atomic_bool service_restarted;
|
struct SoundIoAtomicBool service_restarted;
|
||||||
int shutdown_err;
|
int shutdown_err;
|
||||||
bool emitted_shutdown_cb;
|
bool emitted_shutdown_cb;
|
||||||
};
|
};
|
||||||
|
@ -49,7 +52,7 @@ struct SoundIoOutStreamCoreAudio {
|
||||||
int frames_left;
|
int frames_left;
|
||||||
int write_frame_count;
|
int write_frame_count;
|
||||||
double hardware_latency;
|
double hardware_latency;
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoInStreamCoreAudio {
|
struct SoundIoInStreamCoreAudio {
|
||||||
|
@ -57,7 +60,7 @@ struct SoundIoInStreamCoreAudio {
|
||||||
AudioBufferList *buffer_list;
|
AudioBufferList *buffer_list;
|
||||||
int frames_left;
|
int frames_left;
|
||||||
double hardware_latency;
|
double hardware_latency;
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -5,16 +5,16 @@
|
||||||
* See http://opensource.org/licenses/MIT
|
* See http://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dummy.hpp"
|
#include "dummy.h"
|
||||||
#include "soundio.hpp"
|
#include "soundio_private.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static void playback_thread_run(void *arg) {
|
static void playback_thread_run(void *arg) {
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||||
|
|
||||||
int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer);
|
int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer);
|
||||||
int free_bytes = soundio_ring_buffer_capacity(&osd->ring_buffer) - fill_bytes;
|
int free_bytes = soundio_ring_buffer_capacity(&osd->ring_buffer) - fill_bytes;
|
||||||
|
@ -25,14 +25,14 @@ static void playback_thread_run(void *arg) {
|
||||||
double start_time = soundio_os_get_time();
|
double start_time = soundio_os_get_time();
|
||||||
long frames_consumed = 0;
|
long frames_consumed = 0;
|
||||||
|
|
||||||
while (osd->abort_flag.test_and_set()) {
|
while (atomic_flag_test_and_set(&osd->abort_flag)) {
|
||||||
double now = soundio_os_get_time();
|
double now = soundio_os_get_time();
|
||||||
double time_passed = now - start_time;
|
double time_passed = now - start_time;
|
||||||
double next_period = start_time +
|
double next_period = start_time +
|
||||||
ceil_dbl(time_passed / osd->period_duration) * osd->period_duration;
|
ceil_dbl(time_passed / osd->period_duration) * osd->period_duration;
|
||||||
double relative_time = next_period - now;
|
double relative_time = next_period - now;
|
||||||
soundio_os_cond_timed_wait(osd->cond, nullptr, relative_time);
|
soundio_os_cond_timed_wait(osd->cond, NULL, relative_time);
|
||||||
if (!osd->clear_buffer_flag.test_and_set()) {
|
if (!atomic_flag_test_and_set(&osd->clear_buffer_flag)) {
|
||||||
soundio_ring_buffer_clear(&osd->ring_buffer);
|
soundio_ring_buffer_clear(&osd->ring_buffer);
|
||||||
int free_bytes = soundio_ring_buffer_capacity(&osd->ring_buffer);
|
int free_bytes = soundio_ring_buffer_capacity(&osd->ring_buffer);
|
||||||
int free_frames = free_bytes / outstream->bytes_per_frame;
|
int free_frames = free_bytes / outstream->bytes_per_frame;
|
||||||
|
@ -44,7 +44,7 @@ static void playback_thread_run(void *arg) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (osd->pause_requested.load()) {
|
if (SOUNDIO_ATOMIC_LOAD(osd->pause_requested)) {
|
||||||
start_time = now;
|
start_time = now;
|
||||||
frames_consumed = 0;
|
frames_consumed = 0;
|
||||||
continue;
|
continue;
|
||||||
|
@ -58,7 +58,7 @@ static void playback_thread_run(void *arg) {
|
||||||
double total_time = soundio_os_get_time() - start_time;
|
double total_time = soundio_os_get_time() - start_time;
|
||||||
long total_frames = total_time * outstream->sample_rate;
|
long total_frames = total_time * outstream->sample_rate;
|
||||||
int frames_to_kill = total_frames - frames_consumed;
|
int frames_to_kill = total_frames - frames_consumed;
|
||||||
int read_count = min(frames_to_kill, fill_frames);
|
int read_count = soundio_int_min(frames_to_kill, fill_frames);
|
||||||
int byte_count = read_count * outstream->bytes_per_frame;
|
int byte_count = read_count * outstream->bytes_per_frame;
|
||||||
soundio_ring_buffer_advance_read_ptr(&osd->ring_buffer, byte_count);
|
soundio_ring_buffer_advance_read_ptr(&osd->ring_buffer, byte_count);
|
||||||
frames_consumed += read_count;
|
frames_consumed += read_count;
|
||||||
|
@ -78,21 +78,21 @@ static void playback_thread_run(void *arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_thread_run(void *arg) {
|
static void capture_thread_run(void *arg) {
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
|
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||||
|
|
||||||
long frames_consumed = 0;
|
long frames_consumed = 0;
|
||||||
double start_time = soundio_os_get_time();
|
double start_time = soundio_os_get_time();
|
||||||
while (isd->abort_flag.test_and_set()) {
|
while (atomic_flag_test_and_set(&isd->abort_flag)) {
|
||||||
double now = soundio_os_get_time();
|
double now = soundio_os_get_time();
|
||||||
double time_passed = now - start_time;
|
double time_passed = now - start_time;
|
||||||
double next_period = start_time +
|
double next_period = start_time +
|
||||||
ceil_dbl(time_passed / isd->period_duration) * isd->period_duration;
|
ceil_dbl(time_passed / isd->period_duration) * isd->period_duration;
|
||||||
double relative_time = next_period - now;
|
double relative_time = next_period - now;
|
||||||
soundio_os_cond_timed_wait(isd->cond, nullptr, relative_time);
|
soundio_os_cond_timed_wait(isd->cond, NULL, relative_time);
|
||||||
|
|
||||||
if (isd->pause_requested.load()) {
|
if (SOUNDIO_ATOMIC_LOAD(isd->pause_requested)) {
|
||||||
start_time = now;
|
start_time = now;
|
||||||
frames_consumed = 0;
|
frames_consumed = 0;
|
||||||
continue;
|
continue;
|
||||||
|
@ -106,7 +106,7 @@ static void capture_thread_run(void *arg) {
|
||||||
double total_time = soundio_os_get_time() - start_time;
|
double total_time = soundio_os_get_time() - start_time;
|
||||||
long total_frames = total_time * instream->sample_rate;
|
long total_frames = total_time * instream->sample_rate;
|
||||||
int frames_to_kill = total_frames - frames_consumed;
|
int frames_to_kill = total_frames - frames_consumed;
|
||||||
int write_count = min(frames_to_kill, free_frames);
|
int write_count = soundio_int_min(frames_to_kill, free_frames);
|
||||||
int byte_count = write_count * instream->bytes_per_frame;
|
int byte_count = write_count * instream->bytes_per_frame;
|
||||||
soundio_ring_buffer_advance_write_ptr(&isd->ring_buffer, byte_count);
|
soundio_ring_buffer_advance_write_ptr(&isd->ring_buffer, byte_count);
|
||||||
frames_consumed += write_count;
|
frames_consumed += write_count;
|
||||||
|
@ -123,8 +123,8 @@ static void capture_thread_run(void *arg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy_dummy(SoundIoPrivate *si) {
|
static void destroy_dummy(struct SoundIoPrivate *si) {
|
||||||
SoundIoDummy *sid = &si->backend_data.dummy;
|
struct SoundIoDummy *sid = &si->backend_data.dummy;
|
||||||
|
|
||||||
if (sid->cond)
|
if (sid->cond)
|
||||||
soundio_os_cond_destroy(sid->cond);
|
soundio_os_cond_destroy(sid->cond);
|
||||||
|
@ -133,55 +133,57 @@ static void destroy_dummy(SoundIoPrivate *si) {
|
||||||
soundio_os_mutex_destroy(sid->mutex);
|
soundio_os_mutex_destroy(sid->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flush_events_dummy(SoundIoPrivate *si) {
|
static void flush_events_dummy(struct SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoDummy *sid = &si->backend_data.dummy;
|
struct SoundIoDummy *sid = &si->backend_data.dummy;
|
||||||
if (sid->devices_emitted)
|
if (sid->devices_emitted)
|
||||||
return;
|
return;
|
||||||
sid->devices_emitted = true;
|
sid->devices_emitted = true;
|
||||||
soundio->on_devices_change(soundio);
|
soundio->on_devices_change(soundio);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wait_events_dummy(SoundIoPrivate *si) {
|
static void wait_events_dummy(struct SoundIoPrivate *si) {
|
||||||
SoundIoDummy *sid = &si->backend_data.dummy;
|
struct SoundIoDummy *sid = &si->backend_data.dummy;
|
||||||
flush_events_dummy(si);
|
flush_events_dummy(si);
|
||||||
soundio_os_cond_wait(sid->cond, nullptr);
|
soundio_os_cond_wait(sid->cond, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wakeup_dummy(SoundIoPrivate *si) {
|
static void wakeup_dummy(struct SoundIoPrivate *si) {
|
||||||
SoundIoDummy *sid = &si->backend_data.dummy;
|
struct SoundIoDummy *sid = &si->backend_data.dummy;
|
||||||
soundio_os_cond_signal(sid->cond, nullptr);
|
soundio_os_cond_signal(sid->cond, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void force_device_scan_dummy(SoundIoPrivate *si) {
|
static void force_device_scan_dummy(struct SoundIoPrivate *si) {
|
||||||
// nothing to do; dummy devices never change
|
// nothing to do; dummy devices never change
|
||||||
}
|
}
|
||||||
|
|
||||||
static void outstream_destroy_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
static void outstream_destroy_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||||
|
|
||||||
if (osd->thread) {
|
if (osd->thread) {
|
||||||
osd->abort_flag.clear();
|
atomic_flag_clear(&osd->abort_flag);
|
||||||
soundio_os_cond_signal(osd->cond, nullptr);
|
soundio_os_cond_signal(osd->cond, NULL);
|
||||||
soundio_os_thread_destroy(osd->thread);
|
soundio_os_thread_destroy(osd->thread);
|
||||||
osd->thread = nullptr;
|
osd->thread = NULL;
|
||||||
}
|
}
|
||||||
soundio_os_cond_destroy(osd->cond);
|
soundio_os_cond_destroy(osd->cond);
|
||||||
osd->cond = nullptr;
|
osd->cond = NULL;
|
||||||
|
|
||||||
soundio_ring_buffer_deinit(&osd->ring_buffer);
|
soundio_ring_buffer_deinit(&osd->ring_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_open_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
static int outstream_open_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoDevice *device = outstream->device;
|
struct SoundIoDevice *device = outstream->device;
|
||||||
|
|
||||||
osd->clear_buffer_flag.test_and_set();
|
atomic_flag_test_and_set(&osd->clear_buffer_flag);
|
||||||
osd->pause_requested.store(false);
|
SOUNDIO_ATOMIC_STORE(osd->pause_requested, false);
|
||||||
|
|
||||||
if (outstream->software_latency == 0.0)
|
if (outstream->software_latency == 0.0) {
|
||||||
outstream->software_latency = clamp(device->software_latency_min, 1.0, device->software_latency_max);
|
outstream->software_latency = soundio_double_clamp(
|
||||||
|
device->software_latency_min, 1.0, device->software_latency_max);
|
||||||
|
}
|
||||||
|
|
||||||
osd->period_duration = outstream->software_latency / 2.0;
|
osd->period_duration = outstream->software_latency / 2.0;
|
||||||
|
|
||||||
|
@ -205,16 +207,16 @@ static int outstream_open_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_pause_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
|
static int outstream_pause_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
|
||||||
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||||
osd->pause_requested.store(pause);
|
SOUNDIO_ATOMIC_STORE(osd->pause_requested, pause);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_start_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
static int outstream_start_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
assert(!osd->thread);
|
assert(!osd->thread);
|
||||||
osd->abort_flag.test_and_set();
|
atomic_flag_test_and_set(&osd->abort_flag);
|
||||||
int err;
|
int err;
|
||||||
if ((err = soundio_os_thread_create(playback_thread_run, os,
|
if ((err = soundio_os_thread_create(playback_thread_run, os,
|
||||||
soundio->emit_rtprio_warning, &osd->thread)))
|
soundio->emit_rtprio_warning, &osd->thread)))
|
||||||
|
@ -224,11 +226,11 @@ static int outstream_start_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_begin_write_dummy(SoundIoPrivate *si,
|
static int outstream_begin_write_dummy(struct SoundIoPrivate *si,
|
||||||
SoundIoOutStreamPrivate *os, SoundIoChannelArea **out_areas, int *frame_count)
|
struct SoundIoOutStreamPrivate *os, struct SoundIoChannelArea **out_areas, int *frame_count)
|
||||||
{
|
{
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||||
|
|
||||||
if (*frame_count > osd->frames_left)
|
if (*frame_count > osd->frames_left)
|
||||||
return SoundIoErrorInvalid;
|
return SoundIoErrorInvalid;
|
||||||
|
@ -244,55 +246,57 @@ static int outstream_begin_write_dummy(SoundIoPrivate *si,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_end_write_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
static int outstream_end_write_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
int byte_count = osd->write_frame_count * outstream->bytes_per_frame;
|
int byte_count = osd->write_frame_count * outstream->bytes_per_frame;
|
||||||
soundio_ring_buffer_advance_write_ptr(&osd->ring_buffer, byte_count);
|
soundio_ring_buffer_advance_write_ptr(&osd->ring_buffer, byte_count);
|
||||||
osd->frames_left -= osd->write_frame_count;
|
osd->frames_left -= osd->write_frame_count;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_clear_buffer_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
static int outstream_clear_buffer_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||||
osd->clear_buffer_flag.clear();
|
atomic_flag_clear(&osd->clear_buffer_flag);
|
||||||
soundio_os_cond_signal(osd->cond, nullptr);
|
soundio_os_cond_signal(osd->cond, NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_get_latency_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, double *out_latency) {
|
static int outstream_get_latency_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, double *out_latency) {
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||||
int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer);
|
int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer);
|
||||||
|
|
||||||
*out_latency = (fill_bytes / outstream->bytes_per_frame) / (double)outstream->sample_rate;
|
*out_latency = (fill_bytes / outstream->bytes_per_frame) / (double)outstream->sample_rate;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void instream_destroy_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
static void instream_destroy_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||||
|
|
||||||
if (isd->thread) {
|
if (isd->thread) {
|
||||||
isd->abort_flag.clear();
|
atomic_flag_clear(&isd->abort_flag);
|
||||||
soundio_os_cond_signal(isd->cond, nullptr);
|
soundio_os_cond_signal(isd->cond, NULL);
|
||||||
soundio_os_thread_destroy(isd->thread);
|
soundio_os_thread_destroy(isd->thread);
|
||||||
isd->thread = nullptr;
|
isd->thread = NULL;
|
||||||
}
|
}
|
||||||
soundio_os_cond_destroy(isd->cond);
|
soundio_os_cond_destroy(isd->cond);
|
||||||
isd->cond = nullptr;
|
isd->cond = NULL;
|
||||||
|
|
||||||
soundio_ring_buffer_deinit(&isd->ring_buffer);
|
soundio_ring_buffer_deinit(&isd->ring_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_open_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
static int instream_open_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoDevice *device = instream->device;
|
struct SoundIoDevice *device = instream->device;
|
||||||
|
|
||||||
isd->pause_requested.store(false);
|
SOUNDIO_ATOMIC_STORE(isd->pause_requested, false);
|
||||||
|
|
||||||
if (instream->software_latency == 0.0)
|
if (instream->software_latency == 0.0) {
|
||||||
instream->software_latency = clamp(device->software_latency_min, 1.0, device->software_latency_max);
|
instream->software_latency = soundio_double_clamp(
|
||||||
|
device->software_latency_min, 1.0, device->software_latency_max);
|
||||||
|
}
|
||||||
|
|
||||||
isd->period_duration = instream->software_latency;
|
isd->period_duration = instream->software_latency;
|
||||||
|
|
||||||
|
@ -317,17 +321,17 @@ static int instream_open_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_pause_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is, bool pause) {
|
static int instream_pause_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
|
||||||
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||||
isd->pause_requested.store(pause);
|
SOUNDIO_ATOMIC_STORE(isd->pause_requested, pause);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_start_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
static int instream_start_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
assert(!isd->thread);
|
assert(!isd->thread);
|
||||||
isd->abort_flag.test_and_set();
|
atomic_flag_test_and_set(&isd->abort_flag);
|
||||||
int err;
|
int err;
|
||||||
if ((err = soundio_os_thread_create(capture_thread_run, is,
|
if ((err = soundio_os_thread_create(capture_thread_run, is,
|
||||||
soundio->emit_rtprio_warning, &isd->thread)))
|
soundio->emit_rtprio_warning, &isd->thread)))
|
||||||
|
@ -337,11 +341,11 @@ static int instream_start_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_begin_read_dummy(SoundIoPrivate *si,
|
static int instream_begin_read_dummy(struct SoundIoPrivate *si,
|
||||||
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count)
|
struct SoundIoInStreamPrivate *is, struct SoundIoChannelArea **out_areas, int *frame_count)
|
||||||
{
|
{
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||||
|
|
||||||
assert(*frame_count <= isd->frames_left);
|
assert(*frame_count <= isd->frames_left);
|
||||||
|
|
||||||
|
@ -357,27 +361,27 @@ static int instream_begin_read_dummy(SoundIoPrivate *si,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_end_read_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
static int instream_end_read_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
int byte_count = isd->read_frame_count * instream->bytes_per_frame;
|
int byte_count = isd->read_frame_count * instream->bytes_per_frame;
|
||||||
soundio_ring_buffer_advance_read_ptr(&isd->ring_buffer, byte_count);
|
soundio_ring_buffer_advance_read_ptr(&isd->ring_buffer, byte_count);
|
||||||
isd->frames_left -= isd->read_frame_count;
|
isd->frames_left -= isd->read_frame_count;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_get_latency_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is, double *out_latency) {
|
static int instream_get_latency_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, double *out_latency) {
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamDummy *osd = &is->backend_data.dummy;
|
struct SoundIoInStreamDummy *osd = &is->backend_data.dummy;
|
||||||
int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer);
|
int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer);
|
||||||
|
|
||||||
*out_latency = (fill_bytes / instream->bytes_per_frame) / (double)instream->sample_rate;
|
*out_latency = (fill_bytes / instream->bytes_per_frame) / (double)instream->sample_rate;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_all_device_formats(SoundIoDevice *device) {
|
static int set_all_device_formats(struct SoundIoDevice *device) {
|
||||||
device->format_count = 18;
|
device->format_count = 18;
|
||||||
device->formats = allocate<SoundIoFormat>(device->format_count);
|
device->formats = ALLOCATE(enum SoundIoFormat, device->format_count);
|
||||||
if (!device->formats)
|
if (!device->formats)
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
|
|
||||||
|
@ -403,17 +407,17 @@ static int set_all_device_formats(SoundIoDevice *device) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_all_device_sample_rates(SoundIoDevice *device) {
|
static void set_all_device_sample_rates(struct SoundIoDevice *device) {
|
||||||
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
|
||||||
device->sample_rate_count = 1;
|
device->sample_rate_count = 1;
|
||||||
device->sample_rates = &dev->prealloc_sample_rate_range;
|
device->sample_rates = &dev->prealloc_sample_rate_range;
|
||||||
device->sample_rates[0].min = SOUNDIO_MIN_SAMPLE_RATE;
|
device->sample_rates[0].min = SOUNDIO_MIN_SAMPLE_RATE;
|
||||||
device->sample_rates[0].max = SOUNDIO_MAX_SAMPLE_RATE;
|
device->sample_rates[0].max = SOUNDIO_MAX_SAMPLE_RATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_all_device_channel_layouts(SoundIoDevice *device) {
|
static int set_all_device_channel_layouts(struct SoundIoDevice *device) {
|
||||||
device->layout_count = soundio_channel_layout_builtin_count();
|
device->layout_count = soundio_channel_layout_builtin_count();
|
||||||
device->layouts = allocate<SoundIoChannelLayout>(device->layout_count);
|
device->layouts = ALLOCATE(struct SoundIoChannelLayout, device->layout_count);
|
||||||
if (!device->layouts)
|
if (!device->layouts)
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
for (int i = 0; i < device->layout_count; i += 1)
|
for (int i = 0; i < device->layout_count; i += 1)
|
||||||
|
@ -421,9 +425,9 @@ static int set_all_device_channel_layouts(SoundIoDevice *device) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_dummy_init(SoundIoPrivate *si) {
|
int soundio_dummy_init(struct SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoDummy *sid = &si->backend_data.dummy;
|
struct SoundIoDummy *sid = &si->backend_data.dummy;
|
||||||
|
|
||||||
sid->mutex = soundio_os_mutex_create();
|
sid->mutex = soundio_os_mutex_create();
|
||||||
if (!sid->mutex) {
|
if (!sid->mutex) {
|
||||||
|
@ -438,7 +442,7 @@ int soundio_dummy_init(SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(!si->safe_devices_info);
|
assert(!si->safe_devices_info);
|
||||||
si->safe_devices_info = allocate<SoundIoDevicesInfo>(1);
|
si->safe_devices_info = ALLOCATE(struct SoundIoDevicesInfo, 1);
|
||||||
if (!si->safe_devices_info) {
|
if (!si->safe_devices_info) {
|
||||||
destroy_dummy(si);
|
destroy_dummy(si);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
|
@ -449,12 +453,12 @@ int soundio_dummy_init(SoundIoPrivate *si) {
|
||||||
|
|
||||||
// create output device
|
// create output device
|
||||||
{
|
{
|
||||||
SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1);
|
struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
destroy_dummy(si);
|
destroy_dummy(si);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
SoundIoDevice *device = &dev->pub;
|
struct SoundIoDevice *device = &dev->pub;
|
||||||
|
|
||||||
device->ref_count = 1;
|
device->ref_count = 1;
|
||||||
device->soundio = soundio;
|
device->soundio = soundio;
|
||||||
|
@ -486,7 +490,7 @@ int soundio_dummy_init(SoundIoPrivate *si) {
|
||||||
device->sample_rate_current = 48000;
|
device->sample_rate_current = 48000;
|
||||||
device->aim = SoundIoDeviceAimOutput;
|
device->aim = SoundIoDeviceAimOutput;
|
||||||
|
|
||||||
if (si->safe_devices_info->output_devices.append(device)) {
|
if (SoundIoListDevicePtr_append(&si->safe_devices_info->output_devices, device)) {
|
||||||
soundio_device_unref(device);
|
soundio_device_unref(device);
|
||||||
destroy_dummy(si);
|
destroy_dummy(si);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
|
@ -495,12 +499,12 @@ int soundio_dummy_init(SoundIoPrivate *si) {
|
||||||
|
|
||||||
// create input device
|
// create input device
|
||||||
{
|
{
|
||||||
SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1);
|
struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
destroy_dummy(si);
|
destroy_dummy(si);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
SoundIoDevice *device = &dev->pub;
|
struct SoundIoDevice *device = &dev->pub;
|
||||||
|
|
||||||
device->ref_count = 1;
|
device->ref_count = 1;
|
||||||
device->soundio = soundio;
|
device->soundio = soundio;
|
||||||
|
@ -531,7 +535,7 @@ int soundio_dummy_init(SoundIoPrivate *si) {
|
||||||
device->sample_rate_current = 48000;
|
device->sample_rate_current = 48000;
|
||||||
device->aim = SoundIoDeviceAimInput;
|
device->aim = SoundIoDeviceAimInput;
|
||||||
|
|
||||||
if (si->safe_devices_info->input_devices.append(device)) {
|
if (SoundIoListDevicePtr_append(&si->safe_devices_info->input_devices, device)) {
|
||||||
soundio_device_unref(device);
|
soundio_device_unref(device);
|
||||||
destroy_dummy(si);
|
destroy_dummy(si);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
|
@ -5,23 +5,24 @@
|
||||||
* See http://opensource.org/licenses/MIT
|
* See http://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SOUNDIO_DUMMY_HPP
|
#ifndef SOUNDIO_DUMMY_H
|
||||||
#define SOUNDIO_DUMMY_HPP
|
#define SOUNDIO_DUMMY_H
|
||||||
|
|
||||||
#include "soundio_private.h"
|
#include "soundio_internal.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "atomics.hpp"
|
#include "ring_buffer.h"
|
||||||
#include "ring_buffer.hpp"
|
#include "atomics.h"
|
||||||
|
|
||||||
|
struct SoundIoPrivate;
|
||||||
int soundio_dummy_init(struct SoundIoPrivate *si);
|
int soundio_dummy_init(struct SoundIoPrivate *si);
|
||||||
|
|
||||||
struct SoundIoDummy {
|
struct SoundIoDummy {
|
||||||
SoundIoOsMutex *mutex;
|
struct SoundIoOsMutex *mutex;
|
||||||
SoundIoOsCond *cond;
|
struct SoundIoOsCond *cond;
|
||||||
bool devices_emitted;
|
bool devices_emitted;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoDeviceDummy { };
|
struct SoundIoDeviceDummy { int make_the_struct_not_empty; };
|
||||||
|
|
||||||
struct SoundIoOutStreamDummy {
|
struct SoundIoOutStreamDummy {
|
||||||
struct SoundIoOsThread *thread;
|
struct SoundIoOsThread *thread;
|
||||||
|
@ -34,8 +35,8 @@ struct SoundIoOutStreamDummy {
|
||||||
struct SoundIoRingBuffer ring_buffer;
|
struct SoundIoRingBuffer ring_buffer;
|
||||||
double playback_start_time;
|
double playback_start_time;
|
||||||
atomic_flag clear_buffer_flag;
|
atomic_flag clear_buffer_flag;
|
||||||
atomic_bool pause_requested;
|
struct SoundIoAtomicBool pause_requested;
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoInStreamDummy {
|
struct SoundIoInStreamDummy {
|
||||||
|
@ -47,8 +48,8 @@ struct SoundIoInStreamDummy {
|
||||||
int read_frame_count;
|
int read_frame_count;
|
||||||
int buffer_frame_count;
|
int buffer_frame_count;
|
||||||
struct SoundIoRingBuffer ring_buffer;
|
struct SoundIoRingBuffer ring_buffer;
|
||||||
atomic_bool pause_requested;
|
struct SoundIoAtomicBool pause_requested;
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -5,9 +5,9 @@
|
||||||
* See http://opensource.org/licenses/MIT
|
* See http://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "jack.hpp"
|
#include "jack.h"
|
||||||
#include "soundio.hpp"
|
#include "soundio_private.h"
|
||||||
#include "list.hpp"
|
#include "list.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ struct SoundIoJackPort {
|
||||||
int full_name_len;
|
int full_name_len;
|
||||||
const char *name;
|
const char *name;
|
||||||
int name_len;
|
int name_len;
|
||||||
SoundIoChannelId channel_id;
|
enum SoundIoChannelId channel_id;
|
||||||
jack_latency_range_t latency_range;
|
jack_latency_range_t latency_range;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,11 +26,14 @@ struct SoundIoJackClient {
|
||||||
const char *name;
|
const char *name;
|
||||||
int name_len;
|
int name_len;
|
||||||
bool is_physical;
|
bool is_physical;
|
||||||
SoundIoDeviceAim aim;
|
enum SoundIoDeviceAim aim;
|
||||||
int port_count;
|
int port_count;
|
||||||
SoundIoJackPort ports[SOUNDIO_MAX_CHANNELS];
|
struct SoundIoJackPort ports[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SOUNDIO_MAKE_LIST_STRUCT(struct SoundIoJackClient, SoundIoListJackClient, SOUNDIO_LIST_STATIC)
|
||||||
|
SOUNDIO_MAKE_LIST_DEF(struct SoundIoJackClient, SoundIoListJackClient, SOUNDIO_LIST_STATIC)
|
||||||
|
|
||||||
static void split_str(const char *input_str, int input_str_len, char c,
|
static void split_str(const char *input_str, int input_str_len, char c,
|
||||||
const char **out_1, int *out_len_1, const char **out_2, int *out_len_2)
|
const char **out_1, int *out_len_1, const char **out_2, int *out_len_2)
|
||||||
{
|
{
|
||||||
|
@ -46,11 +49,11 @@ static void split_str(const char *input_str, int input_str_len, char c,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static SoundIoJackClient *find_or_create_client(SoundIoList<SoundIoJackClient> *clients,
|
static struct SoundIoJackClient *find_or_create_client(struct SoundIoListJackClient *clients,
|
||||||
SoundIoDeviceAim aim, bool is_physical, const char *client_name, int client_name_len)
|
enum SoundIoDeviceAim aim, bool is_physical, const char *client_name, int client_name_len)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < clients->length; i += 1) {
|
for (int i = 0; i < clients->length; i += 1) {
|
||||||
SoundIoJackClient *client = &clients->at(i);
|
struct SoundIoJackClient *client = SoundIoListJackClient_ptr_at(clients, i);
|
||||||
if (client->is_physical == is_physical &&
|
if (client->is_physical == is_physical &&
|
||||||
client->aim == aim &&
|
client->aim == aim &&
|
||||||
soundio_streql(client->name, client->name_len, client_name, client_name_len))
|
soundio_streql(client->name, client->name_len, client_name, client_name_len))
|
||||||
|
@ -59,9 +62,9 @@ static SoundIoJackClient *find_or_create_client(SoundIoList<SoundIoJackClient> *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int err;
|
int err;
|
||||||
if ((err = clients->add_one()))
|
if ((err = SoundIoListJackClient_add_one(clients)))
|
||||||
return nullptr;
|
return NULL;
|
||||||
SoundIoJackClient *client = &clients->last();
|
struct SoundIoJackClient *client = SoundIoListJackClient_last_ptr(clients);
|
||||||
client->is_physical = is_physical;
|
client->is_physical = is_physical;
|
||||||
client->aim = aim;
|
client->aim = aim;
|
||||||
client->name = client_name;
|
client->name = client_name;
|
||||||
|
@ -70,36 +73,36 @@ static SoundIoJackClient *find_or_create_client(SoundIoList<SoundIoJackClient> *
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destruct_device(SoundIoDevicePrivate *dp) {
|
static void destruct_device(struct SoundIoDevicePrivate *dp) {
|
||||||
SoundIoDeviceJack *dj = &dp->backend_data.jack;
|
struct SoundIoDeviceJack *dj = &dp->backend_data.jack;
|
||||||
for (int i = 0; i < dj->port_count; i += 1) {
|
for (int i = 0; i < dj->port_count; i += 1) {
|
||||||
SoundIoDeviceJackPort *djp = &dj->ports[i];
|
struct SoundIoDeviceJackPort *djp = &dj->ports[i];
|
||||||
free(djp->full_name);
|
free(djp->full_name);
|
||||||
}
|
}
|
||||||
free(dj->ports);
|
free(dj->ports);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int refresh_devices_bare(SoundIoPrivate *si) {
|
static int refresh_devices_bare(struct SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoJack *sij = &si->backend_data.jack;
|
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||||
|
|
||||||
if (sij->is_shutdown)
|
if (sij->is_shutdown)
|
||||||
return SoundIoErrorBackendDisconnected;
|
return SoundIoErrorBackendDisconnected;
|
||||||
|
|
||||||
|
|
||||||
SoundIoDevicesInfo *devices_info = allocate<SoundIoDevicesInfo>(1);
|
struct SoundIoDevicesInfo *devices_info = ALLOCATE(struct SoundIoDevicesInfo, 1);
|
||||||
if (!devices_info)
|
if (!devices_info)
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
|
|
||||||
devices_info->default_output_index = -1;
|
devices_info->default_output_index = -1;
|
||||||
devices_info->default_input_index = -1;
|
devices_info->default_input_index = -1;
|
||||||
const char **port_names = jack_get_ports(sij->client, nullptr, nullptr, 0);
|
const char **port_names = jack_get_ports(sij->client, NULL, NULL, 0);
|
||||||
if (!port_names) {
|
if (!port_names) {
|
||||||
soundio_destroy_devices_info(devices_info);
|
soundio_destroy_devices_info(devices_info);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundIoList<SoundIoJackClient> clients = {0};
|
struct SoundIoListJackClient clients = {0};
|
||||||
const char **port_name_ptr = port_names;
|
const char **port_name_ptr = port_names;
|
||||||
for (; *port_name_ptr; port_name_ptr += 1) {
|
for (; *port_name_ptr; port_name_ptr += 1) {
|
||||||
const char *client_and_port_name = *port_name_ptr;
|
const char *client_and_port_name = *port_name_ptr;
|
||||||
|
@ -120,12 +123,12 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundIoDeviceAim aim = (flags & JackPortIsInput) ?
|
enum SoundIoDeviceAim aim = (flags & JackPortIsInput) ?
|
||||||
SoundIoDeviceAimOutput : SoundIoDeviceAimInput;
|
SoundIoDeviceAimOutput : SoundIoDeviceAimInput;
|
||||||
bool is_physical = flags & JackPortIsPhysical;
|
bool is_physical = flags & JackPortIsPhysical;
|
||||||
|
|
||||||
const char *client_name = nullptr;
|
const char *client_name = NULL;
|
||||||
const char *port_name = nullptr;
|
const char *port_name = NULL;
|
||||||
int client_name_len;
|
int client_name_len;
|
||||||
int port_name_len;
|
int port_name_len;
|
||||||
split_str(client_and_port_name, client_and_port_name_len, ':',
|
split_str(client_and_port_name, client_and_port_name_len, ':',
|
||||||
|
@ -134,7 +137,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
|
||||||
// device does not have colon, skip it
|
// device does not have colon, skip it
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SoundIoJackClient *client = find_or_create_client(&clients, aim, is_physical,
|
struct SoundIoJackClient *client = find_or_create_client(&clients, aim, is_physical,
|
||||||
client_name, client_name_len);
|
client_name, client_name_len);
|
||||||
if (!client) {
|
if (!client) {
|
||||||
jack_free(port_names);
|
jack_free(port_names);
|
||||||
|
@ -145,7 +148,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
|
||||||
// we hit the channel limit, skip the leftovers
|
// we hit the channel limit, skip the leftovers
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SoundIoJackPort *port = &client->ports[client->port_count++];
|
struct SoundIoJackPort *port = &client->ports[client->port_count++];
|
||||||
port->full_name = client_and_port_name;
|
port->full_name = client_and_port_name;
|
||||||
port->full_name_len = client_and_port_name_len;
|
port->full_name_len = client_and_port_name_len;
|
||||||
port->name = port_name;
|
port->name = port_name;
|
||||||
|
@ -158,21 +161,21 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < clients.length; i += 1) {
|
for (int i = 0; i < clients.length; i += 1) {
|
||||||
SoundIoJackClient *client = &clients.at(i);
|
struct SoundIoJackClient *client = SoundIoListJackClient_ptr_at(&clients, i);
|
||||||
if (client->port_count <= 0)
|
if (client->port_count <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1);
|
struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
jack_free(port_names);
|
jack_free(port_names);
|
||||||
soundio_destroy_devices_info(devices_info);
|
soundio_destroy_devices_info(devices_info);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
SoundIoDevice *device = &dev->pub;
|
struct SoundIoDevice *device = &dev->pub;
|
||||||
SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
struct SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
||||||
int description_len = client->name_len + 3 + 2 * client->port_count;
|
int description_len = client->name_len + 3 + 2 * client->port_count;
|
||||||
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
||||||
SoundIoJackPort *port = &client->ports[port_index];
|
struct SoundIoJackPort *port = &client->ports[port_index];
|
||||||
|
|
||||||
description_len += port->name_len;
|
description_len += port->name_len;
|
||||||
}
|
}
|
||||||
|
@ -184,7 +187,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
|
||||||
device->is_raw = false;
|
device->is_raw = false;
|
||||||
device->aim = client->aim;
|
device->aim = client->aim;
|
||||||
device->id = soundio_str_dupe(client->name, client->name_len);
|
device->id = soundio_str_dupe(client->name, client->name_len);
|
||||||
device->name = allocate<char>(description_len);
|
device->name = ALLOCATE(char, description_len);
|
||||||
device->current_format = SoundIoFormatFloat32NE;
|
device->current_format = SoundIoFormatFloat32NE;
|
||||||
device->sample_rate_count = 1;
|
device->sample_rate_count = 1;
|
||||||
device->sample_rates = &dev->prealloc_sample_rate_range;
|
device->sample_rates = &dev->prealloc_sample_rate_range;
|
||||||
|
@ -197,7 +200,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
|
||||||
device->software_latency_max = sij->period_size / (double) sij->sample_rate;
|
device->software_latency_max = sij->period_size / (double) sij->sample_rate;
|
||||||
|
|
||||||
dj->port_count = client->port_count;
|
dj->port_count = client->port_count;
|
||||||
dj->ports = allocate<SoundIoDeviceJackPort>(dj->port_count);
|
dj->ports = ALLOCATE(struct SoundIoDeviceJackPort, dj->port_count);
|
||||||
|
|
||||||
if (!device->id || !device->name || !dj->ports) {
|
if (!device->id || !device->name || !dj->ports) {
|
||||||
jack_free(port_names);
|
jack_free(port_names);
|
||||||
|
@ -207,8 +210,8 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
||||||
SoundIoJackPort *port = &client->ports[port_index];
|
struct SoundIoJackPort *port = &client->ports[port_index];
|
||||||
SoundIoDeviceJackPort *djp = &dj->ports[port_index];
|
struct SoundIoDeviceJackPort *djp = &dj->ports[port_index];
|
||||||
djp->full_name = soundio_str_dupe(port->full_name, port->full_name_len);
|
djp->full_name = soundio_str_dupe(port->full_name, port->full_name_len);
|
||||||
djp->full_name_len = port->full_name_len;
|
djp->full_name_len = port->full_name_len;
|
||||||
djp->channel_id = port->channel_id;
|
djp->channel_id = port->channel_id;
|
||||||
|
@ -226,7 +229,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
|
||||||
memcpy(&device->name[client->name_len], ": ", 2);
|
memcpy(&device->name[client->name_len], ": ", 2);
|
||||||
int index = client->name_len + 2;
|
int index = client->name_len + 2;
|
||||||
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
||||||
SoundIoJackPort *port = &client->ports[port_index];
|
struct SoundIoJackPort *port = &client->ports[port_index];
|
||||||
memcpy(&device->name[index], port->name, port->name_len);
|
memcpy(&device->name[index], port->name, port->name_len);
|
||||||
index += port->name_len;
|
index += port->name_len;
|
||||||
if (port_index + 1 < client->port_count) {
|
if (port_index + 1 < client->port_count) {
|
||||||
|
@ -238,7 +241,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
|
||||||
device->current_layout.channel_count = client->port_count;
|
device->current_layout.channel_count = client->port_count;
|
||||||
bool any_invalid = false;
|
bool any_invalid = false;
|
||||||
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
||||||
SoundIoJackPort *port = &client->ports[port_index];
|
struct SoundIoJackPort *port = &client->ports[port_index];
|
||||||
device->current_layout.channels[port_index] = port->channel_id;
|
device->current_layout.channels[port_index] = port->channel_id;
|
||||||
any_invalid = any_invalid || (port->channel_id == SoundIoChannelIdInvalid);
|
any_invalid = any_invalid || (port->channel_id == SoundIoChannelIdInvalid);
|
||||||
}
|
}
|
||||||
|
@ -256,7 +259,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
|
||||||
device->formats = &dev->prealloc_format;
|
device->formats = &dev->prealloc_format;
|
||||||
device->formats[0] = device->current_format;
|
device->formats[0] = device->current_format;
|
||||||
|
|
||||||
SoundIoList<SoundIoDevice *> *device_list;
|
struct SoundIoListDevicePtr *device_list;
|
||||||
if (device->aim == SoundIoDeviceAimOutput) {
|
if (device->aim == SoundIoDeviceAimOutput) {
|
||||||
device_list = &devices_info->output_devices;
|
device_list = &devices_info->output_devices;
|
||||||
if (devices_info->default_output_index < 0 && client->is_physical)
|
if (devices_info->default_output_index < 0 && client->is_physical)
|
||||||
|
@ -268,7 +271,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
|
||||||
devices_info->default_input_index = device_list->length;
|
devices_info->default_input_index = device_list->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device_list->append(device)) {
|
if (SoundIoListDevicePtr_append(device_list, device)) {
|
||||||
soundio_device_unref(device);
|
soundio_device_unref(device);
|
||||||
soundio_destroy_devices_info(devices_info);
|
soundio_destroy_devices_info(devices_info);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
|
@ -283,7 +286,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int refresh_devices(SoundIoPrivate *si) {
|
static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
int err = SoundIoErrorInterrupted;
|
int err = SoundIoErrorInterrupted;
|
||||||
while (err == SoundIoErrorInterrupted)
|
while (err == SoundIoErrorInterrupted)
|
||||||
err = refresh_devices_bare(si);
|
err = refresh_devices_bare(si);
|
||||||
|
@ -291,8 +294,8 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void my_flush_events(struct SoundIoPrivate *si, bool wait) {
|
static void my_flush_events(struct SoundIoPrivate *si, bool wait) {
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoJack *sij = &si->backend_data.jack;
|
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
bool cb_shutdown = false;
|
bool cb_shutdown = false;
|
||||||
|
@ -312,9 +315,9 @@ static void my_flush_events(struct SoundIoPrivate *si, bool wait) {
|
||||||
if (cb_shutdown) {
|
if (cb_shutdown) {
|
||||||
soundio->on_backend_disconnect(soundio, SoundIoErrorBackendDisconnected);
|
soundio->on_backend_disconnect(soundio, SoundIoErrorBackendDisconnected);
|
||||||
} else {
|
} else {
|
||||||
if (!sij->refresh_devices_flag.test_and_set()) {
|
if (!atomic_flag_test_and_set(&sij->refresh_devices_flag)) {
|
||||||
if ((err = refresh_devices(si))) {
|
if ((err = refresh_devices(si))) {
|
||||||
sij->refresh_devices_flag.clear();
|
atomic_flag_clear(&sij->refresh_devices_flag);
|
||||||
} else {
|
} else {
|
||||||
soundio->on_devices_change(soundio);
|
soundio->on_devices_change(soundio);
|
||||||
}
|
}
|
||||||
|
@ -332,16 +335,16 @@ static void wait_events_jack(struct SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wakeup_jack(struct SoundIoPrivate *si) {
|
static void wakeup_jack(struct SoundIoPrivate *si) {
|
||||||
SoundIoJack *sij = &si->backend_data.jack;
|
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||||
soundio_os_mutex_lock(sij->mutex);
|
soundio_os_mutex_lock(sij->mutex);
|
||||||
soundio_os_cond_signal(sij->cond, sij->mutex);
|
soundio_os_cond_signal(sij->cond, sij->mutex);
|
||||||
soundio_os_mutex_unlock(sij->mutex);
|
soundio_os_mutex_unlock(sij->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void force_device_scan_jack(struct SoundIoPrivate *si) {
|
static void force_device_scan_jack(struct SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoJack *sij = &si->backend_data.jack;
|
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||||
sij->refresh_devices_flag.clear();
|
atomic_flag_clear(&sij->refresh_devices_flag);
|
||||||
soundio_os_mutex_lock(sij->mutex);
|
soundio_os_mutex_lock(sij->mutex);
|
||||||
soundio_os_cond_signal(sij->cond, sij->mutex);
|
soundio_os_cond_signal(sij->cond, sij->mutex);
|
||||||
soundio->on_events_signal(soundio);
|
soundio->on_events_signal(soundio);
|
||||||
|
@ -349,12 +352,12 @@ static void force_device_scan_jack(struct SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_process_callback(jack_nframes_t nframes, void *arg) {
|
static int outstream_process_callback(jack_nframes_t nframes, void *arg) {
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
|
||||||
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
osj->frames_left = nframes;
|
osj->frames_left = nframes;
|
||||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||||
SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
struct SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
||||||
osj->areas[ch].ptr = (char*)jack_port_get_buffer(osjp->source_port, nframes);
|
osj->areas[ch].ptr = (char*)jack_port_get_buffer(osjp->source_port, nframes);
|
||||||
osj->areas[ch].step = outstream->bytes_per_sample;
|
osj->areas[ch].step = outstream->bytes_per_sample;
|
||||||
}
|
}
|
||||||
|
@ -363,36 +366,36 @@ static int outstream_process_callback(jack_nframes_t nframes, void *arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void outstream_destroy_jack(struct SoundIoPrivate *is, struct SoundIoOutStreamPrivate *os) {
|
static void outstream_destroy_jack(struct SoundIoPrivate *is, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||||
|
|
||||||
jack_client_close(osj->client);
|
jack_client_close(osj->client);
|
||||||
osj->client = nullptr;
|
osj->client = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SoundIoDeviceJackPort *find_port_matching_channel(SoundIoDevice *device, SoundIoChannelId id) {
|
static struct SoundIoDeviceJackPort *find_port_matching_channel(struct SoundIoDevice *device, enum SoundIoChannelId id) {
|
||||||
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
|
||||||
SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
struct SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
||||||
|
|
||||||
for (int ch = 0; ch < device->current_layout.channel_count; ch += 1) {
|
for (int ch = 0; ch < device->current_layout.channel_count; ch += 1) {
|
||||||
SoundIoChannelId chan_id = device->current_layout.channels[ch];
|
enum SoundIoChannelId chan_id = device->current_layout.channels[ch];
|
||||||
if (chan_id == id)
|
if (chan_id == id)
|
||||||
return &dj->ports[ch];
|
return &dj->ports[ch];
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_xrun_callback(void *arg) {
|
static int outstream_xrun_callback(void *arg) {
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
outstream->underflow_callback(outstream);
|
outstream->underflow_callback(outstream);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_buffer_size_callback(jack_nframes_t nframes, void *arg) {
|
static int outstream_buffer_size_callback(jack_nframes_t nframes, void *arg) {
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
|
||||||
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
if ((jack_nframes_t)osj->period_size == nframes) {
|
if ((jack_nframes_t)osj->period_size == nframes) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -402,8 +405,8 @@ static int outstream_buffer_size_callback(jack_nframes_t nframes, void *arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_sample_rate_callback(jack_nframes_t nframes, void *arg) {
|
static int outstream_sample_rate_callback(jack_nframes_t nframes, void *arg) {
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
if (nframes == (jack_nframes_t)outstream->sample_rate) {
|
if (nframes == (jack_nframes_t)outstream->sample_rate) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -413,18 +416,22 @@ static int outstream_sample_rate_callback(jack_nframes_t nframes, void *arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void outstream_shutdown_callback(void *arg) {
|
static void outstream_shutdown_callback(void *arg) {
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline jack_nframes_t nframes_max(jack_nframes_t a, jack_nframes_t b) {
|
||||||
|
return (a >= b) ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoJack *sij = &si->backend_data.jack;
|
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||||
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoDevice *device = outstream->device;
|
struct SoundIoDevice *device = outstream->device;
|
||||||
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
|
||||||
SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
struct SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
||||||
|
|
||||||
if (sij->is_shutdown)
|
if (sij->is_shutdown)
|
||||||
return SoundIoErrorBackendDisconnected;
|
return SoundIoErrorBackendDisconnected;
|
||||||
|
@ -472,7 +479,7 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
|
||||||
// register ports and map channels
|
// register ports and map channels
|
||||||
int connected_count = 0;
|
int connected_count = 0;
|
||||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||||
SoundIoChannelId my_channel_id = outstream->layout.channels[ch];
|
enum SoundIoChannelId my_channel_id = outstream->layout.channels[ch];
|
||||||
const char *channel_name = soundio_get_channel_name(my_channel_id);
|
const char *channel_name = soundio_get_channel_name(my_channel_id);
|
||||||
unsigned long flags = JackPortIsOutput;
|
unsigned long flags = JackPortIsOutput;
|
||||||
if (!outstream->non_terminal_hint)
|
if (!outstream->non_terminal_hint)
|
||||||
|
@ -482,15 +489,15 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
|
||||||
outstream_destroy_jack(si, os);
|
outstream_destroy_jack(si, os);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
struct SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
||||||
osjp->source_port = jport;
|
osjp->source_port = jport;
|
||||||
// figure out which dest port this connects to
|
// figure out which dest port this connects to
|
||||||
SoundIoDeviceJackPort *djp = find_port_matching_channel(device, my_channel_id);
|
struct SoundIoDeviceJackPort *djp = find_port_matching_channel(device, my_channel_id);
|
||||||
if (djp) {
|
if (djp) {
|
||||||
osjp->dest_port_name = djp->full_name;
|
osjp->dest_port_name = djp->full_name;
|
||||||
osjp->dest_port_name_len = djp->full_name_len;
|
osjp->dest_port_name_len = djp->full_name_len;
|
||||||
connected_count += 1;
|
connected_count += 1;
|
||||||
max_port_latency = max(max_port_latency, djp->latency_range.max);
|
max_port_latency = nframes_max(max_port_latency, djp->latency_range.max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If nothing got connected, channel layouts aren't working. Just send the
|
// If nothing got connected, channel layouts aren't working. Just send the
|
||||||
|
@ -499,13 +506,13 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
|
||||||
max_port_latency = 0;
|
max_port_latency = 0;
|
||||||
outstream->layout_error = SoundIoErrorIncompatibleDevice;
|
outstream->layout_error = SoundIoErrorIncompatibleDevice;
|
||||||
|
|
||||||
int ch_count = min(outstream->layout.channel_count, dj->port_count);
|
int ch_count = soundio_int_min(outstream->layout.channel_count, dj->port_count);
|
||||||
for (int ch = 0; ch < ch_count; ch += 1) {
|
for (int ch = 0; ch < ch_count; ch += 1) {
|
||||||
SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
struct SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
||||||
SoundIoDeviceJackPort *djp = &dj->ports[ch];
|
struct SoundIoDeviceJackPort *djp = &dj->ports[ch];
|
||||||
osjp->dest_port_name = djp->full_name;
|
osjp->dest_port_name = djp->full_name;
|
||||||
osjp->dest_port_name_len = djp->full_name_len;
|
osjp->dest_port_name_len = djp->full_name_len;
|
||||||
max_port_latency = max(max_port_latency, djp->latency_range.max);
|
max_port_latency = nframes_max(max_port_latency, djp->latency_range.max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,7 +522,7 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_pause_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
|
static int outstream_pause_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
|
||||||
SoundIoJack *sij = &si->backend_data.jack;
|
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||||
|
|
||||||
if (sij->is_shutdown)
|
if (sij->is_shutdown)
|
||||||
return SoundIoErrorBackendDisconnected;
|
return SoundIoErrorBackendDisconnected;
|
||||||
|
@ -524,9 +531,9 @@ static int outstream_pause_jack(struct SoundIoPrivate *si, struct SoundIoOutStre
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_start_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
static int outstream_start_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoJack *sij = &si->backend_data.jack;
|
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (sij->is_shutdown)
|
if (sij->is_shutdown)
|
||||||
|
@ -536,7 +543,7 @@ static int outstream_start_jack(struct SoundIoPrivate *si, struct SoundIoOutStre
|
||||||
return SoundIoErrorStreaming;
|
return SoundIoErrorStreaming;
|
||||||
|
|
||||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||||
SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
struct SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
||||||
const char *dest_port_name = osjp->dest_port_name;
|
const char *dest_port_name = osjp->dest_port_name;
|
||||||
// allow unconnected ports
|
// allow unconnected ports
|
||||||
if (!dest_port_name)
|
if (!dest_port_name)
|
||||||
|
@ -550,9 +557,9 @@ static int outstream_start_jack(struct SoundIoPrivate *si, struct SoundIoOutStre
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_begin_write_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
static int outstream_begin_write_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
||||||
SoundIoChannelArea **out_areas, int *frame_count)
|
struct SoundIoChannelArea **out_areas, int *frame_count)
|
||||||
{
|
{
|
||||||
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||||
|
|
||||||
if (*frame_count != osj->frames_left)
|
if (*frame_count != osj->frames_left)
|
||||||
return SoundIoErrorInvalid;
|
return SoundIoErrorInvalid;
|
||||||
|
@ -563,7 +570,7 @@ static int outstream_begin_write_jack(struct SoundIoPrivate *si, struct SoundIoO
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_end_write_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
static int outstream_end_write_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||||
osj->frames_left = 0;
|
osj->frames_left = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -575,30 +582,30 @@ static int outstream_clear_buffer_jack(struct SoundIoPrivate *si, struct SoundIo
|
||||||
static int outstream_get_latency_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
static int outstream_get_latency_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
||||||
double *out_latency)
|
double *out_latency)
|
||||||
{
|
{
|
||||||
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||||
*out_latency = osj->hardware_latency;
|
*out_latency = osj->hardware_latency;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void instream_destroy_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
static void instream_destroy_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamJack *isj = &is->backend_data.jack;
|
struct SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||||
|
|
||||||
jack_client_close(isj->client);
|
jack_client_close(isj->client);
|
||||||
isj->client = nullptr;
|
isj->client = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_xrun_callback(void *arg) {
|
static int instream_xrun_callback(void *arg) {
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
|
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
instream->overflow_callback(instream);
|
instream->overflow_callback(instream);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_buffer_size_callback(jack_nframes_t nframes, void *arg) {
|
static int instream_buffer_size_callback(jack_nframes_t nframes, void *arg) {
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
|
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
|
||||||
SoundIoInStreamJack *isj = &is->backend_data.jack;
|
struct SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
|
|
||||||
if ((jack_nframes_t)isj->period_size == nframes) {
|
if ((jack_nframes_t)isj->period_size == nframes) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -609,8 +616,8 @@ static int instream_buffer_size_callback(jack_nframes_t nframes, void *arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_sample_rate_callback(jack_nframes_t nframes, void *arg) {
|
static int instream_sample_rate_callback(jack_nframes_t nframes, void *arg) {
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
|
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
if (nframes == (jack_nframes_t)instream->sample_rate) {
|
if (nframes == (jack_nframes_t)instream->sample_rate) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -620,18 +627,18 @@ static int instream_sample_rate_callback(jack_nframes_t nframes, void *arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void instream_shutdown_callback(void *arg) {
|
static void instream_shutdown_callback(void *arg) {
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
|
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
instream->error_callback(instream, SoundIoErrorStreaming);
|
instream->error_callback(instream, SoundIoErrorStreaming);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_process_callback(jack_nframes_t nframes, void *arg) {
|
static int instream_process_callback(jack_nframes_t nframes, void *arg) {
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
|
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamJack *isj = &is->backend_data.jack;
|
struct SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||||
isj->frames_left = nframes;
|
isj->frames_left = nframes;
|
||||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||||
SoundIoInStreamJackPort *isjp = &isj->ports[ch];
|
struct SoundIoInStreamJackPort *isjp = &isj->ports[ch];
|
||||||
isj->areas[ch].ptr = (char*)jack_port_get_buffer(isjp->dest_port, nframes);
|
isj->areas[ch].ptr = (char*)jack_port_get_buffer(isjp->dest_port, nframes);
|
||||||
isj->areas[ch].step = instream->bytes_per_sample;
|
isj->areas[ch].step = instream->bytes_per_sample;
|
||||||
}
|
}
|
||||||
|
@ -640,12 +647,12 @@ static int instream_process_callback(jack_nframes_t nframes, void *arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamJack *isj = &is->backend_data.jack;
|
struct SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||||
SoundIoJack *sij = &si->backend_data.jack;
|
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||||
SoundIoDevice *device = instream->device;
|
struct SoundIoDevice *device = instream->device;
|
||||||
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
|
||||||
SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
struct SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
||||||
|
|
||||||
if (sij->is_shutdown)
|
if (sij->is_shutdown)
|
||||||
return SoundIoErrorBackendDisconnected;
|
return SoundIoErrorBackendDisconnected;
|
||||||
|
@ -692,7 +699,7 @@ static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamP
|
||||||
// register ports and map channels
|
// register ports and map channels
|
||||||
int connected_count = 0;
|
int connected_count = 0;
|
||||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||||
SoundIoChannelId my_channel_id = instream->layout.channels[ch];
|
enum SoundIoChannelId my_channel_id = instream->layout.channels[ch];
|
||||||
const char *channel_name = soundio_get_channel_name(my_channel_id);
|
const char *channel_name = soundio_get_channel_name(my_channel_id);
|
||||||
unsigned long flags = JackPortIsInput;
|
unsigned long flags = JackPortIsInput;
|
||||||
if (!instream->non_terminal_hint)
|
if (!instream->non_terminal_hint)
|
||||||
|
@ -702,15 +709,15 @@ static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamP
|
||||||
instream_destroy_jack(si, is);
|
instream_destroy_jack(si, is);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
SoundIoInStreamJackPort *isjp = &isj->ports[ch];
|
struct SoundIoInStreamJackPort *isjp = &isj->ports[ch];
|
||||||
isjp->dest_port = jport;
|
isjp->dest_port = jport;
|
||||||
// figure out which source port this connects to
|
// figure out which source port this connects to
|
||||||
SoundIoDeviceJackPort *djp = find_port_matching_channel(device, my_channel_id);
|
struct SoundIoDeviceJackPort *djp = find_port_matching_channel(device, my_channel_id);
|
||||||
if (djp) {
|
if (djp) {
|
||||||
isjp->source_port_name = djp->full_name;
|
isjp->source_port_name = djp->full_name;
|
||||||
isjp->source_port_name_len = djp->full_name_len;
|
isjp->source_port_name_len = djp->full_name_len;
|
||||||
connected_count += 1;
|
connected_count += 1;
|
||||||
max_port_latency = max(max_port_latency, djp->latency_range.max);
|
max_port_latency = nframes_max(max_port_latency, djp->latency_range.max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If nothing got connected, channel layouts aren't working. Just send the
|
// If nothing got connected, channel layouts aren't working. Just send the
|
||||||
|
@ -719,13 +726,13 @@ static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamP
|
||||||
max_port_latency = 0;
|
max_port_latency = 0;
|
||||||
instream->layout_error = SoundIoErrorIncompatibleDevice;
|
instream->layout_error = SoundIoErrorIncompatibleDevice;
|
||||||
|
|
||||||
int ch_count = min(instream->layout.channel_count, dj->port_count);
|
int ch_count = soundio_int_min(instream->layout.channel_count, dj->port_count);
|
||||||
for (int ch = 0; ch < ch_count; ch += 1) {
|
for (int ch = 0; ch < ch_count; ch += 1) {
|
||||||
SoundIoInStreamJackPort *isjp = &isj->ports[ch];
|
struct SoundIoInStreamJackPort *isjp = &isj->ports[ch];
|
||||||
SoundIoDeviceJackPort *djp = &dj->ports[ch];
|
struct SoundIoDeviceJackPort *djp = &dj->ports[ch];
|
||||||
isjp->source_port_name = djp->full_name;
|
isjp->source_port_name = djp->full_name;
|
||||||
isjp->source_port_name_len = djp->full_name_len;
|
isjp->source_port_name_len = djp->full_name_len;
|
||||||
max_port_latency = max(max_port_latency, djp->latency_range.max);
|
max_port_latency = nframes_max(max_port_latency, djp->latency_range.max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -735,7 +742,7 @@ static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamP
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_pause_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
|
static int instream_pause_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
|
||||||
SoundIoJack *sij = &si->backend_data.jack;
|
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||||
|
|
||||||
if (sij->is_shutdown)
|
if (sij->is_shutdown)
|
||||||
return SoundIoErrorBackendDisconnected;
|
return SoundIoErrorBackendDisconnected;
|
||||||
|
@ -744,9 +751,9 @@ static int instream_pause_jack(struct SoundIoPrivate *si, struct SoundIoInStream
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_start_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
static int instream_start_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamJack *isj = &is->backend_data.jack;
|
struct SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoJack *sij = &si->backend_data.jack;
|
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (sij->is_shutdown)
|
if (sij->is_shutdown)
|
||||||
|
@ -756,7 +763,7 @@ static int instream_start_jack(struct SoundIoPrivate *si, struct SoundIoInStream
|
||||||
return SoundIoErrorStreaming;
|
return SoundIoErrorStreaming;
|
||||||
|
|
||||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||||
SoundIoInStreamJackPort *isjp = &isj->ports[ch];
|
struct SoundIoInStreamJackPort *isjp = &isj->ports[ch];
|
||||||
const char *source_port_name = isjp->source_port_name;
|
const char *source_port_name = isjp->source_port_name;
|
||||||
// allow unconnected ports
|
// allow unconnected ports
|
||||||
if (!source_port_name)
|
if (!source_port_name)
|
||||||
|
@ -770,9 +777,9 @@ static int instream_start_jack(struct SoundIoPrivate *si, struct SoundIoInStream
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_begin_read_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
|
static int instream_begin_read_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
|
||||||
SoundIoChannelArea **out_areas, int *frame_count)
|
struct SoundIoChannelArea **out_areas, int *frame_count)
|
||||||
{
|
{
|
||||||
SoundIoInStreamJack *isj = &is->backend_data.jack;
|
struct SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||||
|
|
||||||
if (*frame_count != isj->frames_left)
|
if (*frame_count != isj->frames_left)
|
||||||
return SoundIoErrorInvalid;
|
return SoundIoErrorInvalid;
|
||||||
|
@ -783,7 +790,7 @@ static int instream_begin_read_jack(struct SoundIoPrivate *si, struct SoundIoInS
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_end_read_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
static int instream_end_read_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamJack *isj = &is->backend_data.jack;
|
struct SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||||
isj->frames_left = 0;
|
isj->frames_left = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -791,15 +798,15 @@ static int instream_end_read_jack(struct SoundIoPrivate *si, struct SoundIoInStr
|
||||||
static int instream_get_latency_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
|
static int instream_get_latency_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
|
||||||
double *out_latency)
|
double *out_latency)
|
||||||
{
|
{
|
||||||
SoundIoInStreamJack *isj = &is->backend_data.jack;
|
struct SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||||
*out_latency = isj->hardware_latency;
|
*out_latency = isj->hardware_latency;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void notify_devices_change(SoundIoPrivate *si) {
|
static void notify_devices_change(struct SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoJack *sij = &si->backend_data.jack;
|
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||||
sij->refresh_devices_flag.clear();
|
atomic_flag_clear(&sij->refresh_devices_flag);
|
||||||
soundio_os_mutex_lock(sij->mutex);
|
soundio_os_mutex_lock(sij->mutex);
|
||||||
soundio_os_cond_signal(sij->cond, sij->mutex);
|
soundio_os_cond_signal(sij->cond, sij->mutex);
|
||||||
soundio->on_events_signal(soundio);
|
soundio->on_events_signal(soundio);
|
||||||
|
@ -807,37 +814,37 @@ static void notify_devices_change(SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int buffer_size_callback(jack_nframes_t nframes, void *arg) {
|
static int buffer_size_callback(jack_nframes_t nframes, void *arg) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
|
||||||
SoundIoJack *sij = &si->backend_data.jack;
|
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||||
sij->period_size = nframes;
|
sij->period_size = nframes;
|
||||||
notify_devices_change(si);
|
notify_devices_change(si);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sample_rate_callback(jack_nframes_t nframes, void *arg) {
|
static int sample_rate_callback(jack_nframes_t nframes, void *arg) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
|
||||||
SoundIoJack *sij = &si->backend_data.jack;
|
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||||
sij->sample_rate = nframes;
|
sij->sample_rate = nframes;
|
||||||
notify_devices_change(si);
|
notify_devices_change(si);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void port_registration_callback(jack_port_id_t port_id, int reg, void *arg) {
|
static void port_registration_callback(jack_port_id_t port_id, int reg, void *arg) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
|
||||||
notify_devices_change(si);
|
notify_devices_change(si);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void port_rename_calllback(jack_port_id_t port_id,
|
static void port_rename_calllback(jack_port_id_t port_id,
|
||||||
const char *old_name, const char *new_name, void *arg)
|
const char *old_name, const char *new_name, void *arg)
|
||||||
{
|
{
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
|
||||||
notify_devices_change(si);
|
notify_devices_change(si);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void shutdown_callback(void *arg) {
|
static void shutdown_callback(void *arg) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoJack *sij = &si->backend_data.jack;
|
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||||
soundio_os_mutex_lock(sij->mutex);
|
soundio_os_mutex_lock(sij->mutex);
|
||||||
sij->is_shutdown = true;
|
sij->is_shutdown = true;
|
||||||
soundio_os_cond_signal(sij->cond, sij->mutex);
|
soundio_os_cond_signal(sij->cond, sij->mutex);
|
||||||
|
@ -845,8 +852,8 @@ static void shutdown_callback(void *arg) {
|
||||||
soundio_os_mutex_unlock(sij->mutex);
|
soundio_os_mutex_unlock(sij->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy_jack(SoundIoPrivate *si) {
|
static void destroy_jack(struct SoundIoPrivate *si) {
|
||||||
SoundIoJack *sij = &si->backend_data.jack;
|
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||||
|
|
||||||
if (sij->client)
|
if (sij->client)
|
||||||
jack_client_close(sij->client);
|
jack_client_close(sij->client);
|
||||||
|
@ -859,15 +866,15 @@ static void destroy_jack(SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_jack_init(struct SoundIoPrivate *si) {
|
int soundio_jack_init(struct SoundIoPrivate *si) {
|
||||||
SoundIoJack *sij = &si->backend_data.jack;
|
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
|
|
||||||
if (!global_msg_callback_flag.test_and_set()) {
|
if (!atomic_flag_test_and_set(&global_msg_callback_flag)) {
|
||||||
if (soundio->jack_error_callback)
|
if (soundio->jack_error_callback)
|
||||||
jack_set_error_function(soundio->jack_error_callback);
|
jack_set_error_function(soundio->jack_error_callback);
|
||||||
if (soundio->jack_info_callback)
|
if (soundio->jack_info_callback)
|
||||||
jack_set_info_function(soundio->jack_info_callback);
|
jack_set_info_function(soundio->jack_info_callback);
|
||||||
global_msg_callback_flag.clear();
|
atomic_flag_clear(&global_msg_callback_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
sij->mutex = soundio_os_mutex_create();
|
sij->mutex = soundio_os_mutex_create();
|
||||||
|
@ -916,7 +923,7 @@ int soundio_jack_init(struct SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
jack_on_shutdown(sij->client, shutdown_callback, si);
|
jack_on_shutdown(sij->client, shutdown_callback, si);
|
||||||
|
|
||||||
sij->refresh_devices_flag.clear();
|
atomic_flag_clear(&sij->refresh_devices_flag);
|
||||||
sij->period_size = jack_get_buffer_size(sij->client);
|
sij->period_size = jack_get_buffer_size(sij->client);
|
||||||
sij->sample_rate = jack_get_sample_rate(sij->client);
|
sij->sample_rate = jack_get_sample_rate(sij->client);
|
||||||
|
|
|
@ -5,33 +5,39 @@
|
||||||
* See http://opensource.org/licenses/MIT
|
* See http://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SOUNDIO_JACK_HPP
|
#ifndef SOUNDIO_JACK_H
|
||||||
#define SOUNDIO_JACK_HPP
|
#define SOUNDIO_JACK_H
|
||||||
|
|
||||||
#include "soundio_private.h"
|
#include "soundio_internal.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "atomics.hpp"
|
#include "atomics.h"
|
||||||
|
|
||||||
|
// jack.h does not properly put `void` in function prototypes with no
|
||||||
|
// arguments, so we're forced to temporarily disable -Werror=strict-prototypes
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
|
||||||
#include <jack/jack.h>
|
#include <jack/jack.h>
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
struct SoundIoPrivate;
|
||||||
int soundio_jack_init(struct SoundIoPrivate *si);
|
int soundio_jack_init(struct SoundIoPrivate *si);
|
||||||
|
|
||||||
struct SoundIoDeviceJackPort {
|
struct SoundIoDeviceJackPort {
|
||||||
char *full_name;
|
char *full_name;
|
||||||
int full_name_len;
|
int full_name_len;
|
||||||
SoundIoChannelId channel_id;
|
enum SoundIoChannelId channel_id;
|
||||||
jack_latency_range_t latency_range;
|
jack_latency_range_t latency_range;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoDeviceJack {
|
struct SoundIoDeviceJack {
|
||||||
int port_count;
|
int port_count;
|
||||||
SoundIoDeviceJackPort *ports;
|
struct SoundIoDeviceJackPort *ports;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoJack {
|
struct SoundIoJack {
|
||||||
jack_client_t *client;
|
jack_client_t *client;
|
||||||
SoundIoOsMutex *mutex;
|
struct SoundIoOsMutex *mutex;
|
||||||
SoundIoOsCond *cond;
|
struct SoundIoOsCond *cond;
|
||||||
atomic_flag refresh_devices_flag;
|
atomic_flag refresh_devices_flag;
|
||||||
int sample_rate;
|
int sample_rate;
|
||||||
int period_size;
|
int period_size;
|
||||||
|
@ -50,8 +56,8 @@ struct SoundIoOutStreamJack {
|
||||||
int period_size;
|
int period_size;
|
||||||
int frames_left;
|
int frames_left;
|
||||||
double hardware_latency;
|
double hardware_latency;
|
||||||
SoundIoOutStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
|
struct SoundIoOutStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoInStreamJackPort {
|
struct SoundIoInStreamJackPort {
|
||||||
|
@ -65,8 +71,8 @@ struct SoundIoInStreamJack {
|
||||||
int period_size;
|
int period_size;
|
||||||
int frames_left;
|
int frames_left;
|
||||||
double hardware_latency;
|
double hardware_latency;
|
||||||
SoundIoInStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
|
struct SoundIoInStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
char *buf_ptrs[SOUNDIO_MAX_CHANNELS];
|
char *buf_ptrs[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
145
src/list.h
Normal file
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
|
* See http://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#define _DARWIN_C_SOURCE
|
||||||
|
#undef _POSIX_C_SOURCE
|
||||||
|
#else
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "soundio_private.h"
|
#include "soundio_internal.h"
|
||||||
#include "util.hpp"
|
#include "util.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
@ -53,7 +60,7 @@
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#ifndef MAP_ANONYMOUS
|
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
|
||||||
#define MAP_ANONYMOUS MAP_ANON
|
#define MAP_ANONYMOUS MAP_ANON
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -159,7 +166,7 @@ double soundio_os_get_time(void) {
|
||||||
#if defined(SOUNDIO_OS_WINDOWS)
|
#if defined(SOUNDIO_OS_WINDOWS)
|
||||||
static DWORD WINAPI run_win32_thread(LPVOID userdata) {
|
static DWORD WINAPI run_win32_thread(LPVOID userdata) {
|
||||||
struct SoundIoOsThread *thread = (struct SoundIoOsThread *)userdata;
|
struct SoundIoOsThread *thread = (struct SoundIoOsThread *)userdata;
|
||||||
HRESULT err = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
HRESULT err = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||||
assert(err == S_OK);
|
assert(err == S_OK);
|
||||||
thread->run(thread->arg);
|
thread->run(thread->arg);
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
|
@ -184,7 +191,7 @@ int soundio_os_thread_create(
|
||||||
{
|
{
|
||||||
*out_thread = NULL;
|
*out_thread = NULL;
|
||||||
|
|
||||||
struct SoundIoOsThread *thread = allocate<SoundIoOsThread>(1);
|
struct SoundIoOsThread *thread = ALLOCATE(struct SoundIoOsThread, 1);
|
||||||
if (!thread) {
|
if (!thread) {
|
||||||
soundio_os_thread_destroy(thread);
|
soundio_os_thread_destroy(thread);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
|
@ -276,7 +283,7 @@ void soundio_os_thread_destroy(struct SoundIoOsThread *thread) {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SoundIoOsMutex *soundio_os_mutex_create(void) {
|
struct SoundIoOsMutex *soundio_os_mutex_create(void) {
|
||||||
struct SoundIoOsMutex *mutex = allocate<SoundIoOsMutex>(1);
|
struct SoundIoOsMutex *mutex = ALLOCATE(struct SoundIoOsMutex, 1);
|
||||||
if (!mutex) {
|
if (!mutex) {
|
||||||
soundio_os_mutex_destroy(mutex);
|
soundio_os_mutex_destroy(mutex);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -328,7 +335,7 @@ void soundio_os_mutex_unlock(struct SoundIoOsMutex *mutex) {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SoundIoOsCond * soundio_os_cond_create(void) {
|
struct SoundIoOsCond * soundio_os_cond_create(void) {
|
||||||
struct SoundIoOsCond *cond = allocate<SoundIoOsCond>(1);
|
struct SoundIoOsCond *cond = ALLOCATE(struct SoundIoOsCond, 1);
|
||||||
|
|
||||||
if (!cond) {
|
if (!cond) {
|
||||||
soundio_os_cond_destroy(cond);
|
soundio_os_cond_destroy(cond);
|
||||||
|
@ -558,7 +565,7 @@ static int internal_init(void) {
|
||||||
GetSystemInfo(&win32_system_info);
|
GetSystemInfo(&win32_system_info);
|
||||||
page_size = win32_system_info.dwAllocationGranularity;
|
page_size = win32_system_info.dwAllocationGranularity;
|
||||||
#else
|
#else
|
||||||
page_size = getpagesize();
|
page_size = sysconf(_SC_PAGESIZE);
|
||||||
#if defined(__MACH__)
|
#if defined(__MACH__)
|
||||||
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
|
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
|
||||||
#endif
|
#endif
|
||||||
|
@ -581,7 +588,7 @@ int soundio_os_init(void) {
|
||||||
if ((err = internal_init()))
|
if ((err = internal_init()))
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (!InitOnceComplete(&win32_init_once, INIT_ONCE_ASYNC, nullptr))
|
if (!InitOnceComplete(&win32_init_once, INIT_ONCE_ASYNC, NULL))
|
||||||
return SoundIoErrorSystemResources;
|
return SoundIoErrorSystemResources;
|
||||||
#else
|
#else
|
||||||
assert_no_err(pthread_mutex_lock(&init_mutex));
|
assert_no_err(pthread_mutex_lock(&init_mutex));
|
||||||
|
@ -734,5 +741,5 @@ void soundio_os_deinit_mirrored_memory(struct SoundIoOsMirroredMemory *mem) {
|
||||||
int err = munmap(mem->address, 2 * mem->capacity);
|
int err = munmap(mem->address, 2 * mem->capacity);
|
||||||
assert(!err);
|
assert(!err);
|
||||||
#endif
|
#endif
|
||||||
mem->address = nullptr;
|
mem->address = NULL;
|
||||||
}
|
}
|
|
@ -5,8 +5,8 @@
|
||||||
* See http://opensource.org/licenses/MIT
|
* See http://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pulseaudio.hpp"
|
#include "pulseaudio.h"
|
||||||
#include "soundio.hpp"
|
#include "soundio_private.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -15,19 +15,19 @@
|
||||||
static void subscribe_callback(pa_context *context,
|
static void subscribe_callback(pa_context *context,
|
||||||
pa_subscription_event_type_t event_bits, uint32_t index, void *userdata)
|
pa_subscription_event_type_t event_bits, uint32_t index, void *userdata)
|
||||||
{
|
{
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)userdata;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)userdata;
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
sipa->device_scan_queued = true;
|
sipa->device_scan_queued = true;
|
||||||
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
soundio->on_events_signal(soundio);
|
soundio->on_events_signal(soundio);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int subscribe_to_events(SoundIoPrivate *si) {
|
static int subscribe_to_events(struct SoundIoPrivate *si) {
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
pa_subscription_mask_t events = (pa_subscription_mask_t)(
|
pa_subscription_mask_t events = (pa_subscription_mask_t)(
|
||||||
PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE|PA_SUBSCRIPTION_MASK_SERVER);
|
PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE|PA_SUBSCRIPTION_MASK_SERVER);
|
||||||
pa_operation *subscribe_op = pa_context_subscribe(sipa->pulse_context, events, nullptr, si);
|
pa_operation *subscribe_op = pa_context_subscribe(sipa->pulse_context, events, NULL, si);
|
||||||
if (!subscribe_op)
|
if (!subscribe_op)
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
pa_operation_unref(subscribe_op);
|
pa_operation_unref(subscribe_op);
|
||||||
|
@ -35,9 +35,9 @@ static int subscribe_to_events(SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void context_state_callback(pa_context *context, void *userdata) {
|
static void context_state_callback(pa_context *context, void *userdata) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)userdata;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)userdata;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
|
|
||||||
switch (pa_context_get_state(context)) {
|
switch (pa_context_get_state(context)) {
|
||||||
case PA_CONTEXT_UNCONNECTED: // The context hasn't been connected yet.
|
case PA_CONTEXT_UNCONNECTED: // The context hasn't been connected yet.
|
||||||
|
@ -68,8 +68,8 @@ static void context_state_callback(pa_context *context, void *userdata) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy_pa(SoundIoPrivate *si) {
|
static void destroy_pa(struct SoundIoPrivate *si) {
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
|
|
||||||
if (sipa->main_loop)
|
if (sipa->main_loop)
|
||||||
pa_threaded_mainloop_stop(sipa->main_loop);
|
pa_threaded_mainloop_stop(sipa->main_loop);
|
||||||
|
@ -90,7 +90,7 @@ static void destroy_pa(SoundIoPrivate *si) {
|
||||||
free(sipa->default_source_name);
|
free(sipa->default_source_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SoundIoFormat from_pulseaudio_format(pa_sample_spec sample_spec) {
|
static enum SoundIoFormat from_pulseaudio_format(pa_sample_spec sample_spec) {
|
||||||
switch (sample_spec.format) {
|
switch (sample_spec.format) {
|
||||||
case PA_SAMPLE_U8: return SoundIoFormatU8;
|
case PA_SAMPLE_U8: return SoundIoFormatU8;
|
||||||
case PA_SAMPLE_S16LE: return SoundIoFormatS16LE;
|
case PA_SAMPLE_S16LE: return SoundIoFormatS16LE;
|
||||||
|
@ -113,7 +113,7 @@ static SoundIoFormat from_pulseaudio_format(pa_sample_spec sample_spec) {
|
||||||
return SoundIoFormatInvalid;
|
return SoundIoFormatInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SoundIoChannelId from_pulseaudio_channel_pos(pa_channel_position_t pos) {
|
static enum SoundIoChannelId from_pulseaudio_channel_pos(pa_channel_position_t pos) {
|
||||||
switch (pos) {
|
switch (pos) {
|
||||||
case PA_CHANNEL_POSITION_MONO: return SoundIoChannelIdFrontCenter;
|
case PA_CHANNEL_POSITION_MONO: return SoundIoChannelIdFrontCenter;
|
||||||
case PA_CHANNEL_POSITION_FRONT_LEFT: return SoundIoChannelIdFrontLeft;
|
case PA_CHANNEL_POSITION_FRONT_LEFT: return SoundIoChannelIdFrontLeft;
|
||||||
|
@ -156,15 +156,15 @@ static SoundIoChannelId from_pulseaudio_channel_pos(pa_channel_position_t pos) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_from_pulseaudio_channel_map(pa_channel_map channel_map, SoundIoChannelLayout *channel_layout) {
|
static void set_from_pulseaudio_channel_map(pa_channel_map channel_map, struct SoundIoChannelLayout *channel_layout) {
|
||||||
channel_layout->channel_count = channel_map.channels;
|
channel_layout->channel_count = channel_map.channels;
|
||||||
for (int i = 0; i < channel_map.channels; i += 1) {
|
for (int i = 0; i < channel_map.channels; i += 1) {
|
||||||
channel_layout->channels[i] = from_pulseaudio_channel_pos(channel_map.map[i]);
|
channel_layout->channels[i] = from_pulseaudio_channel_pos(channel_map.map[i]);
|
||||||
}
|
}
|
||||||
channel_layout->name = nullptr;
|
channel_layout->name = NULL;
|
||||||
int builtin_layout_count = soundio_channel_layout_builtin_count();
|
int builtin_layout_count = soundio_channel_layout_builtin_count();
|
||||||
for (int i = 0; i < builtin_layout_count; i += 1) {
|
for (int i = 0; i < builtin_layout_count; i += 1) {
|
||||||
const SoundIoChannelLayout *builtin_layout = soundio_channel_layout_get_builtin(i);
|
const struct SoundIoChannelLayout *builtin_layout = soundio_channel_layout_get_builtin(i);
|
||||||
if (soundio_channel_layout_equal(builtin_layout, channel_layout)) {
|
if (soundio_channel_layout_equal(builtin_layout, channel_layout)) {
|
||||||
channel_layout->name = builtin_layout->name;
|
channel_layout->name = builtin_layout->name;
|
||||||
break;
|
break;
|
||||||
|
@ -172,9 +172,9 @@ static void set_from_pulseaudio_channel_map(pa_channel_map channel_map, SoundIoC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_all_device_channel_layouts(SoundIoDevice *device) {
|
static int set_all_device_channel_layouts(struct SoundIoDevice *device) {
|
||||||
device->layout_count = soundio_channel_layout_builtin_count();
|
device->layout_count = soundio_channel_layout_builtin_count();
|
||||||
device->layouts = allocate<SoundIoChannelLayout>(device->layout_count);
|
device->layouts = ALLOCATE(struct SoundIoChannelLayout, device->layout_count);
|
||||||
if (!device->layouts)
|
if (!device->layouts)
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
for (int i = 0; i < device->layout_count; i += 1)
|
for (int i = 0; i < device->layout_count; i += 1)
|
||||||
|
@ -182,9 +182,9 @@ static int set_all_device_channel_layouts(SoundIoDevice *device) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_all_device_formats(SoundIoDevice *device) {
|
static int set_all_device_formats(struct SoundIoDevice *device) {
|
||||||
device->format_count = 9;
|
device->format_count = 9;
|
||||||
device->formats = allocate<SoundIoFormat>(device->format_count);
|
device->formats = ALLOCATE(enum SoundIoFormat, device->format_count);
|
||||||
if (!device->formats)
|
if (!device->formats)
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
device->formats[0] = SoundIoFormatU8;
|
device->formats[0] = SoundIoFormatU8;
|
||||||
|
@ -199,10 +199,10 @@ static int set_all_device_formats(SoundIoDevice *device) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int perform_operation(SoundIoPrivate *si, pa_operation *op) {
|
static int perform_operation(struct SoundIoPrivate *si, pa_operation *op) {
|
||||||
if (!op)
|
if (!op)
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
switch (pa_operation_get_state(op)) {
|
switch (pa_operation_get_state(op)) {
|
||||||
case PA_OPERATION_RUNNING:
|
case PA_OPERATION_RUNNING:
|
||||||
|
@ -219,9 +219,9 @@ static int perform_operation(SoundIoPrivate *si, pa_operation *op) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *info, int eol, void *userdata) {
|
static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *info, int eol, void *userdata) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)userdata;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)userdata;
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
int err;
|
int err;
|
||||||
if (eol) {
|
if (eol) {
|
||||||
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
|
@ -230,12 +230,12 @@ static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *in
|
||||||
if (sipa->device_query_err)
|
if (sipa->device_query_err)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1);
|
struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
sipa->device_query_err = SoundIoErrorNoMem;
|
sipa->device_query_err = SoundIoErrorNoMem;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SoundIoDevice *device = &dev->pub;
|
struct SoundIoDevice *device = &dev->pub;
|
||||||
|
|
||||||
device->ref_count = 1;
|
device->ref_count = 1;
|
||||||
device->soundio = soundio;
|
device->soundio = soundio;
|
||||||
|
@ -252,8 +252,8 @@ static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *in
|
||||||
// some reasonable min and max values.
|
// some reasonable min and max values.
|
||||||
device->sample_rate_count = 1;
|
device->sample_rate_count = 1;
|
||||||
device->sample_rates = &dev->prealloc_sample_rate_range;
|
device->sample_rates = &dev->prealloc_sample_rate_range;
|
||||||
device->sample_rates[0].min = min(SOUNDIO_MIN_SAMPLE_RATE, device->sample_rate_current);
|
device->sample_rates[0].min = soundio_int_min(SOUNDIO_MIN_SAMPLE_RATE, device->sample_rate_current);
|
||||||
device->sample_rates[0].max = max(SOUNDIO_MAX_SAMPLE_RATE, device->sample_rate_current);
|
device->sample_rates[0].max = soundio_int_max(SOUNDIO_MAX_SAMPLE_RATE, device->sample_rate_current);
|
||||||
|
|
||||||
device->current_format = from_pulseaudio_format(info->sample_spec);
|
device->current_format = from_pulseaudio_format(info->sample_spec);
|
||||||
// PulseAudio performs sample format conversion, so any PulseAudio
|
// PulseAudio performs sample format conversion, so any PulseAudio
|
||||||
|
@ -274,7 +274,7 @@ static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *in
|
||||||
|
|
||||||
device->aim = SoundIoDeviceAimOutput;
|
device->aim = SoundIoDeviceAimOutput;
|
||||||
|
|
||||||
if (sipa->current_devices_info->output_devices.append(device)) {
|
if (SoundIoListDevicePtr_append(&sipa->current_devices_info->output_devices, device)) {
|
||||||
soundio_device_unref(device);
|
soundio_device_unref(device);
|
||||||
sipa->device_query_err = SoundIoErrorNoMem;
|
sipa->device_query_err = SoundIoErrorNoMem;
|
||||||
return;
|
return;
|
||||||
|
@ -282,9 +282,9 @@ static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *in
|
||||||
}
|
}
|
||||||
|
|
||||||
static void source_info_callback(pa_context *pulse_context, const pa_source_info *info, int eol, void *userdata) {
|
static void source_info_callback(pa_context *pulse_context, const pa_source_info *info, int eol, void *userdata) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)userdata;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)userdata;
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (eol) {
|
if (eol) {
|
||||||
|
@ -294,12 +294,12 @@ static void source_info_callback(pa_context *pulse_context, const pa_source_info
|
||||||
if (sipa->device_query_err)
|
if (sipa->device_query_err)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SoundIoDevicePrivate *dev = allocate<SoundIoDevicePrivate>(1);
|
struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
sipa->device_query_err = SoundIoErrorNoMem;
|
sipa->device_query_err = SoundIoErrorNoMem;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SoundIoDevice *device = &dev->pub;
|
struct SoundIoDevice *device = &dev->pub;
|
||||||
|
|
||||||
device->ref_count = 1;
|
device->ref_count = 1;
|
||||||
device->soundio = soundio;
|
device->soundio = soundio;
|
||||||
|
@ -316,8 +316,8 @@ static void source_info_callback(pa_context *pulse_context, const pa_source_info
|
||||||
// some reasonable min and max values.
|
// some reasonable min and max values.
|
||||||
device->sample_rate_count = 1;
|
device->sample_rate_count = 1;
|
||||||
device->sample_rates = &dev->prealloc_sample_rate_range;
|
device->sample_rates = &dev->prealloc_sample_rate_range;
|
||||||
device->sample_rates[0].min = min(8000, device->sample_rate_current);
|
device->sample_rates[0].min = soundio_int_min(SOUNDIO_MIN_SAMPLE_RATE, device->sample_rate_current);
|
||||||
device->sample_rates[0].max = max(5644800, device->sample_rate_current);
|
device->sample_rates[0].max = soundio_int_max(SOUNDIO_MAX_SAMPLE_RATE, device->sample_rate_current);
|
||||||
|
|
||||||
device->current_format = from_pulseaudio_format(info->sample_spec);
|
device->current_format = from_pulseaudio_format(info->sample_spec);
|
||||||
// PulseAudio performs sample format conversion, so any PulseAudio
|
// PulseAudio performs sample format conversion, so any PulseAudio
|
||||||
|
@ -338,7 +338,7 @@ static void source_info_callback(pa_context *pulse_context, const pa_source_info
|
||||||
|
|
||||||
device->aim = SoundIoDeviceAimInput;
|
device->aim = SoundIoDeviceAimInput;
|
||||||
|
|
||||||
if (sipa->current_devices_info->input_devices.append(device)) {
|
if (SoundIoListDevicePtr_append(&sipa->current_devices_info->input_devices, device)) {
|
||||||
soundio_device_unref(device);
|
soundio_device_unref(device);
|
||||||
sipa->device_query_err = SoundIoErrorNoMem;
|
sipa->device_query_err = SoundIoErrorNoMem;
|
||||||
return;
|
return;
|
||||||
|
@ -346,9 +346,9 @@ static void source_info_callback(pa_context *pulse_context, const pa_source_info
|
||||||
}
|
}
|
||||||
|
|
||||||
static void server_info_callback(pa_context *pulse_context, const pa_server_info *info, void *userdata) {
|
static void server_info_callback(pa_context *pulse_context, const pa_server_info *info, void *userdata) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)userdata;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)userdata;
|
||||||
assert(si);
|
assert(si);
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
|
|
||||||
assert(!sipa->default_sink_name);
|
assert(!sipa->default_sink_name);
|
||||||
assert(!sipa->default_source_name);
|
assert(!sipa->default_source_name);
|
||||||
|
@ -363,26 +363,26 @@ static void server_info_callback(pa_context *pulse_context, const pa_server_info
|
||||||
}
|
}
|
||||||
|
|
||||||
// always called even when refresh_devices succeeds
|
// always called even when refresh_devices succeeds
|
||||||
static void cleanup_refresh_devices(SoundIoPrivate *si) {
|
static void cleanup_refresh_devices(struct SoundIoPrivate *si) {
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
|
|
||||||
soundio_destroy_devices_info(sipa->current_devices_info);
|
soundio_destroy_devices_info(sipa->current_devices_info);
|
||||||
sipa->current_devices_info = nullptr;
|
sipa->current_devices_info = NULL;
|
||||||
|
|
||||||
free(sipa->default_sink_name);
|
free(sipa->default_sink_name);
|
||||||
sipa->default_sink_name = nullptr;
|
sipa->default_sink_name = NULL;
|
||||||
|
|
||||||
free(sipa->default_source_name);
|
free(sipa->default_source_name);
|
||||||
sipa->default_source_name = nullptr;
|
sipa->default_source_name = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// call this while holding the main loop lock
|
// call this while holding the main loop lock
|
||||||
static int refresh_devices(SoundIoPrivate *si) {
|
static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
|
|
||||||
assert(!sipa->current_devices_info);
|
assert(!sipa->current_devices_info);
|
||||||
sipa->current_devices_info = allocate<SoundIoDevicesInfo>(1);
|
sipa->current_devices_info = ALLOCATE(struct SoundIoDevicesInfo, 1);
|
||||||
if (!sipa->current_devices_info)
|
if (!sipa->current_devices_info)
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
|
|
||||||
|
@ -414,7 +414,9 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
if (sipa->current_devices_info->input_devices.length > 0) {
|
if (sipa->current_devices_info->input_devices.length > 0) {
|
||||||
sipa->current_devices_info->default_input_index = 0;
|
sipa->current_devices_info->default_input_index = 0;
|
||||||
for (int i = 0; i < sipa->current_devices_info->input_devices.length; i += 1) {
|
for (int i = 0; i < sipa->current_devices_info->input_devices.length; i += 1) {
|
||||||
SoundIoDevice *device = sipa->current_devices_info->input_devices.at(i);
|
struct SoundIoDevice *device = SoundIoListDevicePtr_val_at(
|
||||||
|
&sipa->current_devices_info->input_devices, i);
|
||||||
|
|
||||||
assert(device->aim == SoundIoDeviceAimInput);
|
assert(device->aim == SoundIoDeviceAimInput);
|
||||||
if (strcmp(device->id, sipa->default_source_name) == 0) {
|
if (strcmp(device->id, sipa->default_source_name) == 0) {
|
||||||
sipa->current_devices_info->default_input_index = i;
|
sipa->current_devices_info->default_input_index = i;
|
||||||
|
@ -425,7 +427,9 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
if (sipa->current_devices_info->output_devices.length > 0) {
|
if (sipa->current_devices_info->output_devices.length > 0) {
|
||||||
sipa->current_devices_info->default_output_index = 0;
|
sipa->current_devices_info->default_output_index = 0;
|
||||||
for (int i = 0; i < sipa->current_devices_info->output_devices.length; i += 1) {
|
for (int i = 0; i < sipa->current_devices_info->output_devices.length; i += 1) {
|
||||||
SoundIoDevice *device = sipa->current_devices_info->output_devices.at(i);
|
struct SoundIoDevice *device = SoundIoListDevicePtr_val_at(
|
||||||
|
&sipa->current_devices_info->output_devices, i);
|
||||||
|
|
||||||
assert(device->aim == SoundIoDeviceAimOutput);
|
assert(device->aim == SoundIoDeviceAimOutput);
|
||||||
if (strcmp(device->id, sipa->default_sink_name) == 0) {
|
if (strcmp(device->id, sipa->default_sink_name) == 0) {
|
||||||
sipa->current_devices_info->default_output_index = i;
|
sipa->current_devices_info->default_output_index = i;
|
||||||
|
@ -435,20 +439,20 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
|
|
||||||
soundio_destroy_devices_info(sipa->ready_devices_info);
|
soundio_destroy_devices_info(sipa->ready_devices_info);
|
||||||
sipa->ready_devices_info = sipa->current_devices_info;
|
sipa->ready_devices_info = sipa->current_devices_info;
|
||||||
sipa->current_devices_info = nullptr;
|
sipa->current_devices_info = NULL;
|
||||||
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
soundio->on_events_signal(soundio);
|
soundio->on_events_signal(soundio);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void my_flush_events(SoundIoPrivate *si, bool wait) {
|
static void my_flush_events(struct SoundIoPrivate *si, bool wait) {
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
|
|
||||||
bool change = false;
|
bool change = false;
|
||||||
bool cb_shutdown = false;
|
bool cb_shutdown = false;
|
||||||
SoundIoDevicesInfo *old_devices_info = nullptr;
|
struct SoundIoDevicesInfo *old_devices_info = NULL;
|
||||||
|
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
|
@ -467,7 +471,7 @@ static void my_flush_events(SoundIoPrivate *si, bool wait) {
|
||||||
} else if (sipa->ready_devices_info) {
|
} else if (sipa->ready_devices_info) {
|
||||||
old_devices_info = si->safe_devices_info;
|
old_devices_info = si->safe_devices_info;
|
||||||
si->safe_devices_info = sipa->ready_devices_info;
|
si->safe_devices_info = sipa->ready_devices_info;
|
||||||
sipa->ready_devices_info = nullptr;
|
sipa->ready_devices_info = NULL;
|
||||||
change = true;
|
change = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,25 +485,25 @@ static void my_flush_events(SoundIoPrivate *si, bool wait) {
|
||||||
soundio_destroy_devices_info(old_devices_info);
|
soundio_destroy_devices_info(old_devices_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flush_events_pa(SoundIoPrivate *si) {
|
static void flush_events_pa(struct SoundIoPrivate *si) {
|
||||||
my_flush_events(si, false);
|
my_flush_events(si, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wait_events_pa(SoundIoPrivate *si) {
|
static void wait_events_pa(struct SoundIoPrivate *si) {
|
||||||
my_flush_events(si, false);
|
my_flush_events(si, false);
|
||||||
my_flush_events(si, true);
|
my_flush_events(si, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wakeup_pa(SoundIoPrivate *si) {
|
static void wakeup_pa(struct SoundIoPrivate *si) {
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
pa_threaded_mainloop_unlock(sipa->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void force_device_scan_pa(SoundIoPrivate *si) {
|
static void force_device_scan_pa(struct SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
sipa->device_scan_queued = true;
|
sipa->device_scan_queued = true;
|
||||||
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
|
@ -507,7 +511,7 @@ static void force_device_scan_pa(SoundIoPrivate *si) {
|
||||||
pa_threaded_mainloop_unlock(sipa->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static pa_sample_format_t to_pulseaudio_format(SoundIoFormat format) {
|
static pa_sample_format_t to_pulseaudio_format(enum SoundIoFormat format) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case SoundIoFormatU8: return PA_SAMPLE_U8;
|
case SoundIoFormatU8: return PA_SAMPLE_U8;
|
||||||
case SoundIoFormatS16LE: return PA_SAMPLE_S16LE;
|
case SoundIoFormatS16LE: return PA_SAMPLE_S16LE;
|
||||||
|
@ -534,7 +538,7 @@ static pa_sample_format_t to_pulseaudio_format(SoundIoFormat format) {
|
||||||
return PA_SAMPLE_INVALID;
|
return PA_SAMPLE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pa_channel_position_t to_pulseaudio_channel_pos(SoundIoChannelId channel_id) {
|
static pa_channel_position_t to_pulseaudio_channel_pos(enum SoundIoChannelId channel_id) {
|
||||||
switch (channel_id) {
|
switch (channel_id) {
|
||||||
case SoundIoChannelIdFrontLeft: return PA_CHANNEL_POSITION_FRONT_LEFT;
|
case SoundIoChannelIdFrontLeft: return PA_CHANNEL_POSITION_FRONT_LEFT;
|
||||||
case SoundIoChannelIdFrontRight: return PA_CHANNEL_POSITION_FRONT_RIGHT;
|
case SoundIoChannelIdFrontRight: return PA_CHANNEL_POSITION_FRONT_RIGHT;
|
||||||
|
@ -577,7 +581,7 @@ static pa_channel_position_t to_pulseaudio_channel_pos(SoundIoChannelId channel_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static pa_channel_map to_pulseaudio_channel_map(const SoundIoChannelLayout *channel_layout) {
|
static pa_channel_map to_pulseaudio_channel_map(const struct SoundIoChannelLayout *channel_layout) {
|
||||||
pa_channel_map channel_map;
|
pa_channel_map channel_map;
|
||||||
channel_map.channels = channel_layout->channel_count;
|
channel_map.channels = channel_layout->channel_count;
|
||||||
|
|
||||||
|
@ -590,19 +594,19 @@ static pa_channel_map to_pulseaudio_channel_map(const SoundIoChannelLayout *chan
|
||||||
}
|
}
|
||||||
|
|
||||||
static void playback_stream_state_callback(pa_stream *stream, void *userdata) {
|
static void playback_stream_state_callback(pa_stream *stream, void *userdata) {
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate*) userdata;
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate*) userdata;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIo *soundio = outstream->device->soundio;
|
struct SoundIo *soundio = outstream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
||||||
switch (pa_stream_get_state(stream)) {
|
switch (pa_stream_get_state(stream)) {
|
||||||
case PA_STREAM_UNCONNECTED:
|
case PA_STREAM_UNCONNECTED:
|
||||||
case PA_STREAM_CREATING:
|
case PA_STREAM_CREATING:
|
||||||
case PA_STREAM_TERMINATED:
|
case PA_STREAM_TERMINATED:
|
||||||
break;
|
break;
|
||||||
case PA_STREAM_READY:
|
case PA_STREAM_READY:
|
||||||
ospa->stream_ready = true;
|
SOUNDIO_ATOMIC_STORE(ospa->stream_ready, true);
|
||||||
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
break;
|
break;
|
||||||
case PA_STREAM_FAILED:
|
case PA_STREAM_FAILED:
|
||||||
|
@ -612,48 +616,48 @@ static void playback_stream_state_callback(pa_stream *stream, void *userdata) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void playback_stream_underflow_callback(pa_stream *stream, void *userdata) {
|
static void playback_stream_underflow_callback(pa_stream *stream, void *userdata) {
|
||||||
SoundIoOutStream *outstream = (SoundIoOutStream*)userdata;
|
struct SoundIoOutStream *outstream = (struct SoundIoOutStream*)userdata;
|
||||||
outstream->underflow_callback(outstream);
|
outstream->underflow_callback(outstream);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void playback_stream_write_callback(pa_stream *stream, size_t nbytes, void *userdata) {
|
static void playback_stream_write_callback(pa_stream *stream, size_t nbytes, void *userdata) {
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate*)(userdata);
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate*)(userdata);
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
int frame_count = nbytes / outstream->bytes_per_frame;
|
int frame_count = nbytes / outstream->bytes_per_frame;
|
||||||
outstream->write_callback(outstream, 0, frame_count);
|
outstream->write_callback(outstream, 0, frame_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void outstream_destroy_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
static void outstream_destroy_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
||||||
|
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
pa_stream *stream = ospa->stream;
|
pa_stream *stream = ospa->stream;
|
||||||
if (stream) {
|
if (stream) {
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
pa_stream_set_write_callback(stream, nullptr, nullptr);
|
pa_stream_set_write_callback(stream, NULL, NULL);
|
||||||
pa_stream_set_state_callback(stream, nullptr, nullptr);
|
pa_stream_set_state_callback(stream, NULL, NULL);
|
||||||
pa_stream_set_underflow_callback(stream, nullptr, nullptr);
|
pa_stream_set_underflow_callback(stream, NULL, NULL);
|
||||||
pa_stream_set_overflow_callback(stream, nullptr, nullptr);
|
pa_stream_set_overflow_callback(stream, NULL, NULL);
|
||||||
pa_stream_disconnect(stream);
|
pa_stream_disconnect(stream);
|
||||||
|
|
||||||
pa_stream_unref(stream);
|
pa_stream_unref(stream);
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock(sipa->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
|
|
||||||
ospa->stream = nullptr;
|
ospa->stream = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void timing_update_callback(pa_stream *stream, int success, void *userdata) {
|
static void timing_update_callback(pa_stream *stream, int success, void *userdata) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)userdata;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)userdata;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
static int outstream_open_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
|
|
||||||
if ((unsigned)outstream->layout.channel_count > PA_CHANNELS_MAX)
|
if ((unsigned)outstream->layout.channel_count > PA_CHANNELS_MAX)
|
||||||
return SoundIoErrorIncompatibleBackend;
|
return SoundIoErrorIncompatibleBackend;
|
||||||
|
@ -661,9 +665,9 @@ static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
if (!outstream->name)
|
if (!outstream->name)
|
||||||
outstream->name = "SoundIoOutStream";
|
outstream->name = "SoundIoOutStream";
|
||||||
|
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
ospa->stream_ready.store(false);
|
SOUNDIO_ATOMIC_STORE(ospa->stream_ready, false);
|
||||||
ospa->clear_buffer_flag.test_and_set();
|
atomic_flag_test_and_set(&ospa->clear_buffer_flag);
|
||||||
|
|
||||||
assert(sipa->pulse_context);
|
assert(sipa->pulse_context);
|
||||||
|
|
||||||
|
@ -704,13 +708,13 @@ static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
|
|
||||||
int err = pa_stream_connect_playback(ospa->stream,
|
int err = pa_stream_connect_playback(ospa->stream,
|
||||||
outstream->device->id, &ospa->buffer_attr,
|
outstream->device->id, &ospa->buffer_attr,
|
||||||
flags, nullptr, nullptr);
|
flags, NULL, NULL);
|
||||||
if (err) {
|
if (err) {
|
||||||
pa_threaded_mainloop_unlock(sipa->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!ospa->stream_ready.load())
|
while (!SOUNDIO_ATOMIC_LOAD(ospa->stream_ready))
|
||||||
pa_threaded_mainloop_wait(sipa->main_loop);
|
pa_threaded_mainloop_wait(sipa->main_loop);
|
||||||
|
|
||||||
pa_operation *update_timing_info_op = pa_stream_update_timing_info(ospa->stream, timing_update_callback, si);
|
pa_operation *update_timing_info_op = pa_stream_update_timing_info(ospa->stream, timing_update_callback, si);
|
||||||
|
@ -727,10 +731,10 @@ static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_start_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
static int outstream_start_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
||||||
|
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
|
@ -738,7 +742,7 @@ static int outstream_start_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
int frame_count = ospa->write_byte_count / outstream->bytes_per_frame;
|
int frame_count = ospa->write_byte_count / outstream->bytes_per_frame;
|
||||||
outstream->write_callback(outstream, 0, frame_count);
|
outstream->write_callback(outstream, 0, frame_count);
|
||||||
|
|
||||||
pa_operation *op = pa_stream_cork(ospa->stream, false, nullptr, nullptr);
|
pa_operation *op = pa_stream_cork(ospa->stream, false, NULL, NULL);
|
||||||
if (!op) {
|
if (!op) {
|
||||||
pa_threaded_mainloop_unlock(sipa->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
return SoundIoErrorStreaming;
|
return SoundIoErrorStreaming;
|
||||||
|
@ -753,11 +757,11 @@ static int outstream_start_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_begin_write_pa(SoundIoPrivate *si,
|
static int outstream_begin_write_pa(struct SoundIoPrivate *si,
|
||||||
SoundIoOutStreamPrivate *os, SoundIoChannelArea **out_areas, int *frame_count)
|
struct SoundIoOutStreamPrivate *os, struct SoundIoChannelArea **out_areas, int *frame_count)
|
||||||
{
|
{
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
||||||
pa_stream *stream = ospa->stream;
|
pa_stream *stream = ospa->stream;
|
||||||
|
|
||||||
ospa->write_byte_count = *frame_count * outstream->bytes_per_frame;
|
ospa->write_byte_count = *frame_count * outstream->bytes_per_frame;
|
||||||
|
@ -775,28 +779,28 @@ static int outstream_begin_write_pa(SoundIoPrivate *si,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_end_write_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
static int outstream_end_write_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
||||||
pa_stream *stream = ospa->stream;
|
pa_stream *stream = ospa->stream;
|
||||||
|
|
||||||
pa_seek_mode_t seek_mode = ospa->clear_buffer_flag.test_and_set() ? PA_SEEK_RELATIVE : PA_SEEK_RELATIVE_ON_READ;
|
pa_seek_mode_t seek_mode = atomic_flag_test_and_set(&ospa->clear_buffer_flag) ? PA_SEEK_RELATIVE : PA_SEEK_RELATIVE_ON_READ;
|
||||||
if (pa_stream_write(stream, ospa->write_ptr, ospa->write_byte_count, nullptr, 0, seek_mode))
|
if (pa_stream_write(stream, ospa->write_ptr, ospa->write_byte_count, NULL, 0, seek_mode))
|
||||||
return SoundIoErrorStreaming;
|
return SoundIoErrorStreaming;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_clear_buffer_pa(SoundIoPrivate *si,
|
static int outstream_clear_buffer_pa(struct SoundIoPrivate *si,
|
||||||
SoundIoOutStreamPrivate *os)
|
struct SoundIoOutStreamPrivate *os)
|
||||||
{
|
{
|
||||||
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
||||||
ospa->clear_buffer_flag.clear();
|
atomic_flag_clear(&ospa->clear_buffer_flag);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_pause_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, bool pause) {
|
static int outstream_pause_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
|
||||||
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
|
|
||||||
if (!pa_threaded_mainloop_in_thread(sipa->main_loop)) {
|
if (!pa_threaded_mainloop_in_thread(sipa->main_loop)) {
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
@ -818,8 +822,8 @@ static int outstream_pause_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, b
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_get_latency_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, double *out_latency) {
|
static int outstream_get_latency_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, double *out_latency) {
|
||||||
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
pa_usec_t r_usec;
|
pa_usec_t r_usec;
|
||||||
|
@ -832,19 +836,19 @@ static int outstream_get_latency_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate
|
||||||
}
|
}
|
||||||
|
|
||||||
static void recording_stream_state_callback(pa_stream *stream, void *userdata) {
|
static void recording_stream_state_callback(pa_stream *stream, void *userdata) {
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate*)userdata;
|
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate*)userdata;
|
||||||
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
SoundIo *soundio = instream->device->soundio;
|
struct SoundIo *soundio = instream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
switch (pa_stream_get_state(stream)) {
|
switch (pa_stream_get_state(stream)) {
|
||||||
case PA_STREAM_UNCONNECTED:
|
case PA_STREAM_UNCONNECTED:
|
||||||
case PA_STREAM_CREATING:
|
case PA_STREAM_CREATING:
|
||||||
case PA_STREAM_TERMINATED:
|
case PA_STREAM_TERMINATED:
|
||||||
break;
|
break;
|
||||||
case PA_STREAM_READY:
|
case PA_STREAM_READY:
|
||||||
ispa->stream_ready = true;
|
SOUNDIO_ATOMIC_STORE(ispa->stream_ready, true);
|
||||||
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
break;
|
break;
|
||||||
case PA_STREAM_FAILED:
|
case PA_STREAM_FAILED:
|
||||||
|
@ -854,43 +858,43 @@ static void recording_stream_state_callback(pa_stream *stream, void *userdata) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void recording_stream_read_callback(pa_stream *stream, size_t nbytes, void *userdata) {
|
static void recording_stream_read_callback(pa_stream *stream, size_t nbytes, void *userdata) {
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate*)userdata;
|
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate*)userdata;
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
assert(nbytes % instream->bytes_per_frame == 0);
|
assert(nbytes % instream->bytes_per_frame == 0);
|
||||||
assert(nbytes > 0);
|
assert(nbytes > 0);
|
||||||
int available_frame_count = nbytes / instream->bytes_per_frame;
|
int available_frame_count = nbytes / instream->bytes_per_frame;
|
||||||
instream->read_callback(instream, 0, available_frame_count);
|
instream->read_callback(instream, 0, available_frame_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void instream_destroy_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
static void instream_destroy_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
pa_stream *stream = ispa->stream;
|
pa_stream *stream = ispa->stream;
|
||||||
if (stream) {
|
if (stream) {
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
pa_stream_set_state_callback(stream, nullptr, nullptr);
|
pa_stream_set_state_callback(stream, NULL, NULL);
|
||||||
pa_stream_set_read_callback(stream, nullptr, nullptr);
|
pa_stream_set_read_callback(stream, NULL, NULL);
|
||||||
pa_stream_disconnect(stream);
|
pa_stream_disconnect(stream);
|
||||||
pa_stream_unref(stream);
|
pa_stream_unref(stream);
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock(sipa->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
|
|
||||||
ispa->stream = nullptr;
|
ispa->stream = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_open_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
static int instream_open_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
|
|
||||||
if ((unsigned)instream->layout.channel_count > PA_CHANNELS_MAX)
|
if ((unsigned)instream->layout.channel_count > PA_CHANNELS_MAX)
|
||||||
return SoundIoErrorIncompatibleBackend;
|
return SoundIoErrorIncompatibleBackend;
|
||||||
if (!instream->name)
|
if (!instream->name)
|
||||||
instream->name = "SoundIoInStream";
|
instream->name = "SoundIoInStream";
|
||||||
|
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
ispa->stream_ready = false;
|
SOUNDIO_ATOMIC_STORE(ispa->stream_ready, false);
|
||||||
|
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
|
@ -931,10 +935,10 @@ static int instream_open_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_start_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
static int instream_start_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
pa_stream_flags_t flags = (pa_stream_flags_t)(PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING);
|
pa_stream_flags_t flags = (pa_stream_flags_t)(PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING);
|
||||||
|
@ -947,7 +951,7 @@ static int instream_start_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!ispa->stream_ready)
|
while (!SOUNDIO_ATOMIC_LOAD(ispa->stream_ready))
|
||||||
pa_threaded_mainloop_wait(sipa->main_loop);
|
pa_threaded_mainloop_wait(sipa->main_loop);
|
||||||
|
|
||||||
pa_operation *update_timing_info_op = pa_stream_update_timing_info(ispa->stream, timing_update_callback, si);
|
pa_operation *update_timing_info_op = pa_stream_update_timing_info(ispa->stream, timing_update_callback, si);
|
||||||
|
@ -961,14 +965,14 @@ static int instream_start_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_begin_read_pa(SoundIoPrivate *si,
|
static int instream_begin_read_pa(struct SoundIoPrivate *si,
|
||||||
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count)
|
struct SoundIoInStreamPrivate *is, struct SoundIoChannelArea **out_areas, int *frame_count)
|
||||||
{
|
{
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
||||||
pa_stream *stream = ispa->stream;
|
pa_stream *stream = ispa->stream;
|
||||||
|
|
||||||
assert(ispa->stream_ready);
|
assert(SOUNDIO_ATOMIC_LOAD(ispa->stream_ready));
|
||||||
|
|
||||||
if (!ispa->peek_buf) {
|
if (!ispa->peek_buf) {
|
||||||
if (pa_stream_peek(stream, (const void **)&ispa->peek_buf, &ispa->peek_buf_size))
|
if (pa_stream_peek(stream, (const void **)&ispa->peek_buf, &ispa->peek_buf_size))
|
||||||
|
@ -980,12 +984,12 @@ static int instream_begin_read_pa(SoundIoPrivate *si,
|
||||||
// hole
|
// hole
|
||||||
if (!ispa->peek_buf) {
|
if (!ispa->peek_buf) {
|
||||||
*frame_count = ispa->peek_buf_frames_left;
|
*frame_count = ispa->peek_buf_frames_left;
|
||||||
*out_areas = nullptr;
|
*out_areas = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ispa->read_frame_count = min(*frame_count, ispa->peek_buf_frames_left);
|
ispa->read_frame_count = soundio_int_min(*frame_count, ispa->peek_buf_frames_left);
|
||||||
*frame_count = ispa->read_frame_count;
|
*frame_count = ispa->read_frame_count;
|
||||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||||
ispa->areas[ch].ptr = ispa->peek_buf + ispa->peek_buf_index + instream->bytes_per_sample * ch;
|
ispa->areas[ch].ptr = ispa->peek_buf + ispa->peek_buf_index + instream->bytes_per_sample * ch;
|
||||||
|
@ -997,9 +1001,9 @@ static int instream_begin_read_pa(SoundIoPrivate *si,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_end_read_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
static int instream_end_read_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
||||||
pa_stream *stream = ispa->stream;
|
pa_stream *stream = ispa->stream;
|
||||||
|
|
||||||
// hole
|
// hole
|
||||||
|
@ -1016,15 +1020,15 @@ static int instream_end_read_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is)
|
||||||
if (ispa->peek_buf_index >= ispa->peek_buf_size) {
|
if (ispa->peek_buf_index >= ispa->peek_buf_size) {
|
||||||
if (pa_stream_drop(stream))
|
if (pa_stream_drop(stream))
|
||||||
return SoundIoErrorStreaming;
|
return SoundIoErrorStreaming;
|
||||||
ispa->peek_buf = nullptr;
|
ispa->peek_buf = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_pause_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is, bool pause) {
|
static int instream_pause_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
|
||||||
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
|
|
||||||
if (!pa_threaded_mainloop_in_thread(sipa->main_loop)) {
|
if (!pa_threaded_mainloop_in_thread(sipa->main_loop)) {
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
@ -1044,8 +1048,8 @@ static int instream_pause_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is, boo
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_get_latency_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is, double *out_latency) {
|
static int instream_get_latency_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, double *out_latency) {
|
||||||
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
pa_usec_t r_usec;
|
pa_usec_t r_usec;
|
||||||
|
@ -1057,9 +1061,9 @@ static int instream_get_latency_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *i
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_pulseaudio_init(SoundIoPrivate *si) {
|
int soundio_pulseaudio_init(struct SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
|
|
||||||
sipa->device_scan_queued = true;
|
sipa->device_scan_queued = true;
|
||||||
|
|
|
@ -5,17 +5,18 @@
|
||||||
* See http://opensource.org/licenses/MIT
|
* See http://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SOUNDIO_PULSEAUDIO_HPP
|
#ifndef SOUNDIO_PULSEAUDIO_H
|
||||||
#define SOUNDIO_PULSEAUDIO_HPP
|
#define SOUNDIO_PULSEAUDIO_H
|
||||||
|
|
||||||
#include "soundio_private.h"
|
#include "soundio_internal.h"
|
||||||
#include "atomics.hpp"
|
#include "atomics.h"
|
||||||
|
|
||||||
#include <pulse/pulseaudio.h>
|
#include <pulse/pulseaudio.h>
|
||||||
|
|
||||||
|
struct SoundIoPrivate;
|
||||||
int soundio_pulseaudio_init(struct SoundIoPrivate *si);
|
int soundio_pulseaudio_init(struct SoundIoPrivate *si);
|
||||||
|
|
||||||
struct SoundIoDevicePulseAudio { };
|
struct SoundIoDevicePulseAudio { int make_the_struct_not_empty; };
|
||||||
|
|
||||||
struct SoundIoPulseAudio {
|
struct SoundIoPulseAudio {
|
||||||
int device_query_err;
|
int device_query_err;
|
||||||
|
@ -41,24 +42,24 @@ struct SoundIoPulseAudio {
|
||||||
|
|
||||||
struct SoundIoOutStreamPulseAudio {
|
struct SoundIoOutStreamPulseAudio {
|
||||||
pa_stream *stream;
|
pa_stream *stream;
|
||||||
atomic_bool stream_ready;
|
struct SoundIoAtomicBool stream_ready;
|
||||||
pa_buffer_attr buffer_attr;
|
pa_buffer_attr buffer_attr;
|
||||||
char *write_ptr;
|
char *write_ptr;
|
||||||
size_t write_byte_count;
|
size_t write_byte_count;
|
||||||
atomic_flag clear_buffer_flag;
|
atomic_flag clear_buffer_flag;
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoInStreamPulseAudio {
|
struct SoundIoInStreamPulseAudio {
|
||||||
pa_stream *stream;
|
pa_stream *stream;
|
||||||
atomic_bool stream_ready;
|
struct SoundIoAtomicBool stream_ready;
|
||||||
pa_buffer_attr buffer_attr;
|
pa_buffer_attr buffer_attr;
|
||||||
char *peek_buf;
|
char *peek_buf;
|
||||||
size_t peek_buf_index;
|
size_t peek_buf_index;
|
||||||
size_t peek_buf_size;
|
size_t peek_buf_size;
|
||||||
int peek_buf_frames_left;
|
int peek_buf_frames_left;
|
||||||
int read_frame_count;
|
int read_frame_count;
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -5,25 +5,25 @@
|
||||||
* See http://opensource.org/licenses/MIT
|
* See http://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ring_buffer.hpp"
|
#include "ring_buffer.h"
|
||||||
#include "soundio.hpp"
|
#include "soundio_private.h"
|
||||||
#include "util.hpp"
|
#include "util.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
struct SoundIoRingBuffer *soundio_ring_buffer_create(struct SoundIo *soundio, int requested_capacity) {
|
struct SoundIoRingBuffer *soundio_ring_buffer_create(struct SoundIo *soundio, int requested_capacity) {
|
||||||
SoundIoRingBuffer *rb = allocate<SoundIoRingBuffer>(1);
|
struct SoundIoRingBuffer *rb = ALLOCATE(struct SoundIoRingBuffer, 1);
|
||||||
|
|
||||||
assert(requested_capacity > 0);
|
assert(requested_capacity > 0);
|
||||||
|
|
||||||
if (!rb) {
|
if (!rb) {
|
||||||
soundio_ring_buffer_destroy(rb);
|
soundio_ring_buffer_destroy(rb);
|
||||||
return nullptr;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (soundio_ring_buffer_init(rb, requested_capacity)) {
|
if (soundio_ring_buffer_init(rb, requested_capacity)) {
|
||||||
soundio_ring_buffer_destroy(rb);
|
soundio_ring_buffer_destroy(rb);
|
||||||
return nullptr;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rb;
|
return rb;
|
||||||
|
@ -43,25 +43,31 @@ int soundio_ring_buffer_capacity(struct SoundIoRingBuffer *rb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
char *soundio_ring_buffer_write_ptr(struct SoundIoRingBuffer *rb) {
|
char *soundio_ring_buffer_write_ptr(struct SoundIoRingBuffer *rb) {
|
||||||
return rb->mem.address + (rb->write_offset % rb->capacity);
|
long write_offset = SOUNDIO_ATOMIC_LOAD(rb->write_offset);
|
||||||
|
return rb->mem.address + (write_offset % rb->capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void soundio_ring_buffer_advance_write_ptr(struct SoundIoRingBuffer *rb, int count) {
|
void soundio_ring_buffer_advance_write_ptr(struct SoundIoRingBuffer *rb, int count) {
|
||||||
rb->write_offset += count;
|
SOUNDIO_ATOMIC_FETCH_ADD(rb->write_offset, count);
|
||||||
assert(soundio_ring_buffer_fill_count(rb) >= 0);
|
assert(soundio_ring_buffer_fill_count(rb) >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *soundio_ring_buffer_read_ptr(struct SoundIoRingBuffer *rb) {
|
char *soundio_ring_buffer_read_ptr(struct SoundIoRingBuffer *rb) {
|
||||||
return rb->mem.address + (rb->read_offset % rb->capacity);
|
long read_offset = SOUNDIO_ATOMIC_LOAD(rb->read_offset);
|
||||||
|
return rb->mem.address + (read_offset % rb->capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void soundio_ring_buffer_advance_read_ptr(struct SoundIoRingBuffer *rb, int count) {
|
void soundio_ring_buffer_advance_read_ptr(struct SoundIoRingBuffer *rb, int count) {
|
||||||
rb->read_offset += count;
|
SOUNDIO_ATOMIC_FETCH_ADD(rb->read_offset, count);
|
||||||
assert(soundio_ring_buffer_fill_count(rb) >= 0);
|
assert(soundio_ring_buffer_fill_count(rb) >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_ring_buffer_fill_count(struct SoundIoRingBuffer *rb) {
|
int soundio_ring_buffer_fill_count(struct SoundIoRingBuffer *rb) {
|
||||||
int count = rb->write_offset - rb->read_offset;
|
// Whichever offset we load first might have a smaller value. So we load
|
||||||
|
// the read_offset first.
|
||||||
|
long read_offset = SOUNDIO_ATOMIC_LOAD(rb->read_offset);
|
||||||
|
long write_offset = SOUNDIO_ATOMIC_LOAD(rb->write_offset);
|
||||||
|
int count = write_offset - read_offset;
|
||||||
assert(count >= 0);
|
assert(count >= 0);
|
||||||
assert(count <= rb->capacity);
|
assert(count <= rb->capacity);
|
||||||
return count;
|
return count;
|
||||||
|
@ -72,15 +78,16 @@ int soundio_ring_buffer_free_count(struct SoundIoRingBuffer *rb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void soundio_ring_buffer_clear(struct SoundIoRingBuffer *rb) {
|
void soundio_ring_buffer_clear(struct SoundIoRingBuffer *rb) {
|
||||||
return rb->write_offset.store(rb->read_offset.load());
|
long read_offset = SOUNDIO_ATOMIC_LOAD(rb->read_offset);
|
||||||
|
SOUNDIO_ATOMIC_STORE(rb->write_offset, read_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_ring_buffer_init(struct SoundIoRingBuffer *rb, int requested_capacity) {
|
int soundio_ring_buffer_init(struct SoundIoRingBuffer *rb, int requested_capacity) {
|
||||||
int err;
|
int err;
|
||||||
if ((err = soundio_os_init_mirrored_memory(&rb->mem, requested_capacity)))
|
if ((err = soundio_os_init_mirrored_memory(&rb->mem, requested_capacity)))
|
||||||
return err;
|
return err;
|
||||||
rb->write_offset = 0;
|
SOUNDIO_ATOMIC_STORE(rb->write_offset, 0);
|
||||||
rb->read_offset = 0;
|
SOUNDIO_ATOMIC_STORE(rb->read_offset, 0);
|
||||||
rb->capacity = rb->mem.capacity;
|
rb->capacity = rb->mem.capacity;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
|
@ -5,16 +5,16 @@
|
||||||
* See http://opensource.org/licenses/MIT
|
* See http://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SOUNDIO_RING_BUFFER_HPP
|
#ifndef SOUNDIO_RING_BUFFER_H
|
||||||
#define SOUNDIO_RING_BUFFER_HPP
|
#define SOUNDIO_RING_BUFFER_H
|
||||||
|
|
||||||
#include "atomics.hpp"
|
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
#include "atomics.h"
|
||||||
|
|
||||||
struct SoundIoRingBuffer {
|
struct SoundIoRingBuffer {
|
||||||
SoundIoOsMirroredMemory mem;
|
struct SoundIoOsMirroredMemory mem;
|
||||||
atomic_long write_offset;
|
struct SoundIoAtomicLong write_offset;
|
||||||
atomic_long read_offset;
|
struct SoundIoAtomicLong read_offset;
|
||||||
int capacity;
|
int capacity;
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
* See http://opensource.org/licenses/MIT
|
* See http://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "soundio.hpp"
|
#include "soundio_private.h"
|
||||||
#include "util.hpp"
|
#include "util.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
static const SoundIoBackend available_backends[] = {
|
static const enum SoundIoBackend available_backends[] = {
|
||||||
#ifdef SOUNDIO_HAVE_JACK
|
#ifdef SOUNDIO_HAVE_JACK
|
||||||
SoundIoBackendJack,
|
SoundIoBackendJack,
|
||||||
#endif
|
#endif
|
||||||
|
@ -33,36 +33,40 @@ static const SoundIoBackend available_backends[] = {
|
||||||
SoundIoBackendDummy,
|
SoundIoBackendDummy,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int (*backend_init_fns[])(SoundIoPrivate *) = {
|
static int (*backend_init_fns[])(struct SoundIoPrivate *) = {
|
||||||
[SoundIoBackendNone] = nullptr,
|
[SoundIoBackendNone] = NULL,
|
||||||
#ifdef SOUNDIO_HAVE_JACK
|
#ifdef SOUNDIO_HAVE_JACK
|
||||||
[SoundIoBackendJack] = soundio_jack_init,
|
[SoundIoBackendJack] = soundio_jack_init,
|
||||||
#else
|
#else
|
||||||
[SoundIoBackendJack] = nullptr,
|
[SoundIoBackendJack] = NULL,
|
||||||
#endif
|
#endif
|
||||||
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
||||||
[SoundIoBackendPulseAudio] = soundio_pulseaudio_init,
|
[SoundIoBackendPulseAudio] = soundio_pulseaudio_init,
|
||||||
#else
|
#else
|
||||||
[SoundIoBackendPulseAudio] = nullptr,
|
[SoundIoBackendPulseAudio] = NULL,
|
||||||
#endif
|
#endif
|
||||||
#ifdef SOUNDIO_HAVE_ALSA
|
#ifdef SOUNDIO_HAVE_ALSA
|
||||||
[SoundIoBackendAlsa] = soundio_alsa_init,
|
[SoundIoBackendAlsa] = soundio_alsa_init,
|
||||||
#else
|
#else
|
||||||
[SoundIoBackendAlsa] = nullptr,
|
[SoundIoBackendAlsa] = NULL,
|
||||||
#endif
|
#endif
|
||||||
#ifdef SOUNDIO_HAVE_COREAUDIO
|
#ifdef SOUNDIO_HAVE_COREAUDIO
|
||||||
[SoundIoBackendCoreAudio] = soundio_coreaudio_init,
|
[SoundIoBackendCoreAudio] = soundio_coreaudio_init,
|
||||||
#else
|
#else
|
||||||
[SoundIoBackendCoreAudio] = nullptr,
|
[SoundIoBackendCoreAudio] = NULL,
|
||||||
#endif
|
#endif
|
||||||
#ifdef SOUNDIO_HAVE_WASAPI
|
#ifdef SOUNDIO_HAVE_WASAPI
|
||||||
[SoundIoBackendWasapi] = soundio_wasapi_init,
|
[SoundIoBackendWasapi] = soundio_wasapi_init,
|
||||||
#else
|
#else
|
||||||
[SoundIoBackendWasapi] = nullptr,
|
[SoundIoBackendWasapi] = NULL,
|
||||||
#endif
|
#endif
|
||||||
[SoundIoBackendDummy] = soundio_dummy_init,
|
[SoundIoBackendDummy] = soundio_dummy_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
SOUNDIO_MAKE_LIST_DEF(struct SoundIoDevice*, SoundIoListDevicePtr, SOUNDIO_LIST_NOT_STATIC)
|
||||||
|
SOUNDIO_MAKE_LIST_DEF(struct SoundIoSampleRateRange, SoundIoListSampleRateRange, SOUNDIO_LIST_NOT_STATIC)
|
||||||
|
|
||||||
const char *soundio_strerror(int error) {
|
const char *soundio_strerror(int error) {
|
||||||
switch ((enum SoundIoError)error) {
|
switch ((enum SoundIoError)error) {
|
||||||
case SoundIoErrorNone: return "(no error)";
|
case SoundIoErrorNone: return "(no error)";
|
||||||
|
@ -153,23 +157,23 @@ const char *soundio_backend_name(enum SoundIoBackend backend) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void soundio_destroy(struct SoundIo *soundio) {
|
void soundio_destroy(struct SoundIo *soundio) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
|
|
||||||
soundio_disconnect(soundio);
|
soundio_disconnect(soundio);
|
||||||
|
|
||||||
free(si);
|
free(si);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_nothing_cb(struct SoundIo *) { }
|
static void do_nothing_cb(struct SoundIo *soundio) { }
|
||||||
static void default_msg_callback(const char *msg) { }
|
static void default_msg_callback(const char *msg) { }
|
||||||
|
|
||||||
static void default_backend_disconnect_cb(struct SoundIo *, int err) {
|
static void default_backend_disconnect_cb(struct SoundIo *soundio, int err) {
|
||||||
soundio_panic("libsoundio: backend disconnected: %s", soundio_strerror(err));
|
soundio_panic("libsoundio: backend disconnected: %s", soundio_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
static atomic_flag rtprio_seen = ATOMIC_FLAG_INIT;
|
static atomic_flag rtprio_seen = ATOMIC_FLAG_INIT;
|
||||||
static void default_emit_rtprio_warning(void) {
|
static void default_emit_rtprio_warning(void) {
|
||||||
if (!rtprio_seen.test_and_set()) {
|
if (!atomic_flag_test_and_set(&rtprio_seen)) {
|
||||||
fprintf(stderr, "warning: unable to set high priority thread: Operation not permitted\n");
|
fprintf(stderr, "warning: unable to set high priority thread: Operation not permitted\n");
|
||||||
fprintf(stderr, "See "
|
fprintf(stderr, "See "
|
||||||
"https://github.com/andrewrk/genesis/wiki/warning:-unable-to-set-high-priority-thread:-Operation-not-permitted\n");
|
"https://github.com/andrewrk/genesis/wiki/warning:-unable-to-set-high-priority-thread:-Operation-not-permitted\n");
|
||||||
|
@ -179,11 +183,11 @@ static void default_emit_rtprio_warning(void) {
|
||||||
struct SoundIo *soundio_create(void) {
|
struct SoundIo *soundio_create(void) {
|
||||||
int err;
|
int err;
|
||||||
if ((err = soundio_os_init()))
|
if ((err = soundio_os_init()))
|
||||||
return nullptr;
|
return NULL;
|
||||||
struct SoundIoPrivate *si = allocate<SoundIoPrivate>(1);
|
struct SoundIoPrivate *si = ALLOCATE(struct SoundIoPrivate, 1);
|
||||||
if (!si)
|
if (!si)
|
||||||
return nullptr;
|
return NULL;
|
||||||
SoundIo *soundio = &si->pub;
|
struct SoundIo *soundio = &si->pub;
|
||||||
soundio->on_devices_change = do_nothing_cb;
|
soundio->on_devices_change = do_nothing_cb;
|
||||||
soundio->on_backend_disconnect = default_backend_disconnect_cb;
|
soundio->on_backend_disconnect = default_backend_disconnect_cb;
|
||||||
soundio->on_events_signal = do_nothing_cb;
|
soundio->on_events_signal = do_nothing_cb;
|
||||||
|
@ -197,8 +201,8 @@ struct SoundIo *soundio_create(void) {
|
||||||
int soundio_connect(struct SoundIo *soundio) {
|
int soundio_connect(struct SoundIo *soundio) {
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
for (int i = 0; i < array_length(available_backends); i += 1) {
|
for (int i = 0; i < ARRAY_LENGTH(available_backends); i += 1) {
|
||||||
SoundIoBackend backend = available_backends[i];
|
enum SoundIoBackend backend = available_backends[i];
|
||||||
err = soundio_connect_backend(soundio, backend);
|
err = soundio_connect_backend(soundio, backend);
|
||||||
if (!err)
|
if (!err)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -209,8 +213,8 @@ int soundio_connect(struct SoundIo *soundio) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_connect_backend(SoundIo *soundio, SoundIoBackend backend) {
|
int soundio_connect_backend(struct SoundIo *soundio, enum SoundIoBackend backend) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
|
|
||||||
if (soundio->current_backend)
|
if (soundio->current_backend)
|
||||||
return SoundIoErrorInvalid;
|
return SoundIoErrorInvalid;
|
||||||
|
@ -218,7 +222,7 @@ int soundio_connect_backend(SoundIo *soundio, SoundIoBackend backend) {
|
||||||
if (backend <= 0 || backend > SoundIoBackendDummy)
|
if (backend <= 0 || backend > SoundIoBackendDummy)
|
||||||
return SoundIoErrorInvalid;
|
return SoundIoErrorInvalid;
|
||||||
|
|
||||||
int (*fn)(SoundIoPrivate *) = backend_init_fns[backend];
|
int (*fn)(struct SoundIoPrivate *) = backend_init_fns[backend];
|
||||||
|
|
||||||
if (!fn)
|
if (!fn)
|
||||||
return SoundIoErrorBackendUnavailable;
|
return SoundIoErrorBackendUnavailable;
|
||||||
|
@ -234,52 +238,52 @@ int soundio_connect_backend(SoundIo *soundio, SoundIoBackend backend) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void soundio_disconnect(struct SoundIo *soundio) {
|
void soundio_disconnect(struct SoundIo *soundio) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
|
|
||||||
if (!si)
|
if (!si)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (si->destroy)
|
if (si->destroy)
|
||||||
si->destroy(si);
|
si->destroy(si);
|
||||||
memset(&si->backend_data, 0, sizeof(SoundIoBackendData));
|
memset(&si->backend_data, 0, sizeof(union SoundIoBackendData));
|
||||||
|
|
||||||
soundio->current_backend = SoundIoBackendNone;
|
soundio->current_backend = SoundIoBackendNone;
|
||||||
|
|
||||||
soundio_destroy_devices_info(si->safe_devices_info);
|
soundio_destroy_devices_info(si->safe_devices_info);
|
||||||
si->safe_devices_info = nullptr;
|
si->safe_devices_info = NULL;
|
||||||
|
|
||||||
si->destroy = nullptr;
|
si->destroy = NULL;
|
||||||
si->flush_events = nullptr;
|
si->flush_events = NULL;
|
||||||
si->wait_events = nullptr;
|
si->wait_events = NULL;
|
||||||
si->wakeup = nullptr;
|
si->wakeup = NULL;
|
||||||
si->force_device_scan = nullptr;
|
si->force_device_scan = NULL;
|
||||||
|
|
||||||
si->outstream_open = nullptr;
|
si->outstream_open = NULL;
|
||||||
si->outstream_destroy = nullptr;
|
si->outstream_destroy = NULL;
|
||||||
si->outstream_start = nullptr;
|
si->outstream_start = NULL;
|
||||||
si->outstream_begin_write = nullptr;
|
si->outstream_begin_write = NULL;
|
||||||
si->outstream_end_write = nullptr;
|
si->outstream_end_write = NULL;
|
||||||
si->outstream_clear_buffer = nullptr;
|
si->outstream_clear_buffer = NULL;
|
||||||
si->outstream_pause = nullptr;
|
si->outstream_pause = NULL;
|
||||||
si->outstream_get_latency = nullptr;
|
si->outstream_get_latency = NULL;
|
||||||
|
|
||||||
si->instream_open = nullptr;
|
si->instream_open = NULL;
|
||||||
si->instream_destroy = nullptr;
|
si->instream_destroy = NULL;
|
||||||
si->instream_start = nullptr;
|
si->instream_start = NULL;
|
||||||
si->instream_begin_read = nullptr;
|
si->instream_begin_read = NULL;
|
||||||
si->instream_end_read = nullptr;
|
si->instream_end_read = NULL;
|
||||||
si->instream_pause = nullptr;
|
si->instream_pause = NULL;
|
||||||
si->instream_get_latency = nullptr;
|
si->instream_get_latency = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void soundio_flush_events(struct SoundIo *soundio) {
|
void soundio_flush_events(struct SoundIo *soundio) {
|
||||||
assert(soundio->current_backend != SoundIoBackendNone);
|
assert(soundio->current_backend != SoundIoBackendNone);
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
si->flush_events(si);
|
si->flush_events(si);
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_input_device_count(struct SoundIo *soundio) {
|
int soundio_input_device_count(struct SoundIo *soundio) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
|
|
||||||
assert(si->safe_devices_info);
|
assert(si->safe_devices_info);
|
||||||
if (!si->safe_devices_info)
|
if (!si->safe_devices_info)
|
||||||
|
@ -293,7 +297,7 @@ int soundio_input_device_count(struct SoundIo *soundio) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_output_device_count(struct SoundIo *soundio) {
|
int soundio_output_device_count(struct SoundIo *soundio) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
|
|
||||||
assert(si->safe_devices_info);
|
assert(si->safe_devices_info);
|
||||||
if (!si->safe_devices_info)
|
if (!si->safe_devices_info)
|
||||||
|
@ -307,7 +311,7 @@ int soundio_output_device_count(struct SoundIo *soundio) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_default_input_device_index(struct SoundIo *soundio) {
|
int soundio_default_input_device_index(struct SoundIo *soundio) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
|
|
||||||
assert(si->safe_devices_info);
|
assert(si->safe_devices_info);
|
||||||
if (!si->safe_devices_info)
|
if (!si->safe_devices_info)
|
||||||
|
@ -321,7 +325,7 @@ int soundio_default_input_device_index(struct SoundIo *soundio) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_default_output_device_index(struct SoundIo *soundio) {
|
int soundio_default_output_device_index(struct SoundIo *soundio) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
|
|
||||||
assert(si->safe_devices_info);
|
assert(si->safe_devices_info);
|
||||||
if (!si->safe_devices_info)
|
if (!si->safe_devices_info)
|
||||||
|
@ -335,43 +339,43 @@ int soundio_default_output_device_index(struct SoundIo *soundio) {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SoundIoDevice *soundio_get_input_device(struct SoundIo *soundio, int index) {
|
struct SoundIoDevice *soundio_get_input_device(struct SoundIo *soundio, int index) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
|
|
||||||
assert(soundio->current_backend != SoundIoBackendNone);
|
assert(soundio->current_backend != SoundIoBackendNone);
|
||||||
if (soundio->current_backend == SoundIoBackendNone)
|
if (soundio->current_backend == SoundIoBackendNone)
|
||||||
return nullptr;
|
return NULL;
|
||||||
|
|
||||||
assert(si->safe_devices_info);
|
assert(si->safe_devices_info);
|
||||||
if (!si->safe_devices_info)
|
if (!si->safe_devices_info)
|
||||||
return nullptr;
|
return NULL;
|
||||||
|
|
||||||
assert(index >= 0);
|
assert(index >= 0);
|
||||||
assert(index < si->safe_devices_info->input_devices.length);
|
assert(index < si->safe_devices_info->input_devices.length);
|
||||||
if (index < 0 || index >= si->safe_devices_info->input_devices.length)
|
if (index < 0 || index >= si->safe_devices_info->input_devices.length)
|
||||||
return nullptr;
|
return NULL;
|
||||||
|
|
||||||
SoundIoDevice *device = si->safe_devices_info->input_devices.at(index);
|
struct SoundIoDevice *device = SoundIoListDevicePtr_val_at(&si->safe_devices_info->input_devices, index);
|
||||||
soundio_device_ref(device);
|
soundio_device_ref(device);
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SoundIoDevice *soundio_get_output_device(struct SoundIo *soundio, int index) {
|
struct SoundIoDevice *soundio_get_output_device(struct SoundIo *soundio, int index) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
|
|
||||||
assert(soundio->current_backend != SoundIoBackendNone);
|
assert(soundio->current_backend != SoundIoBackendNone);
|
||||||
if (soundio->current_backend == SoundIoBackendNone)
|
if (soundio->current_backend == SoundIoBackendNone)
|
||||||
return nullptr;
|
return NULL;
|
||||||
|
|
||||||
assert(si->safe_devices_info);
|
assert(si->safe_devices_info);
|
||||||
if (!si->safe_devices_info)
|
if (!si->safe_devices_info)
|
||||||
return nullptr;
|
return NULL;
|
||||||
|
|
||||||
assert(index >= 0);
|
assert(index >= 0);
|
||||||
assert(index < si->safe_devices_info->output_devices.length);
|
assert(index < si->safe_devices_info->output_devices.length);
|
||||||
if (index < 0 || index >= si->safe_devices_info->output_devices.length)
|
if (index < 0 || index >= si->safe_devices_info->output_devices.length)
|
||||||
return nullptr;
|
return NULL;
|
||||||
|
|
||||||
SoundIoDevice *device = si->safe_devices_info->output_devices.at(index);
|
struct SoundIoDevice *device = SoundIoListDevicePtr_val_at(&si->safe_devices_info->output_devices, index);
|
||||||
soundio_device_ref(device);
|
soundio_device_ref(device);
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
@ -384,7 +388,7 @@ void soundio_device_unref(struct SoundIoDevice *device) {
|
||||||
assert(device->ref_count >= 0);
|
assert(device->ref_count >= 0);
|
||||||
|
|
||||||
if (device->ref_count == 0) {
|
if (device->ref_count == 0) {
|
||||||
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
|
||||||
if (dev->destruct)
|
if (dev->destruct)
|
||||||
dev->destruct(dev);
|
dev->destruct(dev);
|
||||||
|
|
||||||
|
@ -396,7 +400,7 @@ void soundio_device_unref(struct SoundIoDevice *device) {
|
||||||
{
|
{
|
||||||
free(device->sample_rates);
|
free(device->sample_rates);
|
||||||
}
|
}
|
||||||
dev->sample_rates.deinit();
|
SoundIoListSampleRateRange_deinit(&dev->sample_rates);
|
||||||
|
|
||||||
if (device->formats != &dev->prealloc_format)
|
if (device->formats != &dev->prealloc_format)
|
||||||
free(device->formats);
|
free(device->formats);
|
||||||
|
@ -414,35 +418,35 @@ void soundio_device_ref(struct SoundIoDevice *device) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void soundio_wait_events(struct SoundIo *soundio) {
|
void soundio_wait_events(struct SoundIo *soundio) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
si->wait_events(si);
|
si->wait_events(si);
|
||||||
}
|
}
|
||||||
|
|
||||||
void soundio_wakeup(struct SoundIo *soundio) {
|
void soundio_wakeup(struct SoundIo *soundio) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
si->wakeup(si);
|
si->wakeup(si);
|
||||||
}
|
}
|
||||||
|
|
||||||
void soundio_force_device_scan(struct SoundIo *soundio) {
|
void soundio_force_device_scan(struct SoundIo *soundio) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
si->force_device_scan(si);
|
si->force_device_scan(si);
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_outstream_begin_write(struct SoundIoOutStream *outstream,
|
int soundio_outstream_begin_write(struct SoundIoOutStream *outstream,
|
||||||
SoundIoChannelArea **areas, int *frame_count)
|
struct SoundIoChannelArea **areas, int *frame_count)
|
||||||
{
|
{
|
||||||
SoundIo *soundio = outstream->device->soundio;
|
struct SoundIo *soundio = outstream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
|
||||||
if (*frame_count <= 0)
|
if (*frame_count <= 0)
|
||||||
return SoundIoErrorInvalid;
|
return SoundIoErrorInvalid;
|
||||||
return si->outstream_begin_write(si, os, areas, frame_count);
|
return si->outstream_begin_write(si, os, areas, frame_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_outstream_end_write(struct SoundIoOutStream *outstream) {
|
int soundio_outstream_end_write(struct SoundIoOutStream *outstream) {
|
||||||
SoundIo *soundio = outstream->device->soundio;
|
struct SoundIo *soundio = outstream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
|
||||||
return si->outstream_end_write(si, os);
|
return si->outstream_end_write(si, os);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,13 +457,13 @@ static void default_outstream_error_callback(struct SoundIoOutStream *os, int er
|
||||||
static void default_underflow_callback(struct SoundIoOutStream *outstream) { }
|
static void default_underflow_callback(struct SoundIoOutStream *outstream) { }
|
||||||
|
|
||||||
struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device) {
|
struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device) {
|
||||||
SoundIoOutStreamPrivate *os = allocate<SoundIoOutStreamPrivate>(1);
|
struct SoundIoOutStreamPrivate *os = ALLOCATE(struct SoundIoOutStreamPrivate, 1);
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
struct SoundIoOutStream *outstream = &os->pub;
|
||||||
|
|
||||||
if (!os)
|
if (!os)
|
||||||
return nullptr;
|
return NULL;
|
||||||
if (!device)
|
if (!device)
|
||||||
return nullptr;
|
return NULL;
|
||||||
|
|
||||||
outstream->device = device;
|
outstream->device = device;
|
||||||
soundio_device_ref(device);
|
soundio_device_ref(device);
|
||||||
|
@ -471,7 +475,7 @@ struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device)
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_outstream_open(struct SoundIoOutStream *outstream) {
|
int soundio_outstream_open(struct SoundIoOutStream *outstream) {
|
||||||
SoundIoDevice *device = outstream->device;
|
struct SoundIoDevice *device = outstream->device;
|
||||||
|
|
||||||
if (device->aim != SoundIoDeviceAimOutput)
|
if (device->aim != SoundIoDeviceAimOutput)
|
||||||
return SoundIoErrorInvalid;
|
return SoundIoErrorInvalid;
|
||||||
|
@ -491,29 +495,29 @@ int soundio_outstream_open(struct SoundIoOutStream *outstream) {
|
||||||
return SoundIoErrorInvalid;
|
return SoundIoErrorInvalid;
|
||||||
|
|
||||||
if (!outstream->layout.channel_count) {
|
if (!outstream->layout.channel_count) {
|
||||||
const SoundIoChannelLayout *stereo = soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdStereo);
|
const struct SoundIoChannelLayout *stereo = soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdStereo);
|
||||||
outstream->layout = soundio_device_supports_layout(device, stereo) ? *stereo : device->layouts[0];
|
outstream->layout = soundio_device_supports_layout(device, stereo) ? *stereo : device->layouts[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!outstream->sample_rate)
|
if (!outstream->sample_rate)
|
||||||
outstream->sample_rate = soundio_device_nearest_sample_rate(device, 48000);
|
outstream->sample_rate = soundio_device_nearest_sample_rate(device, 48000);
|
||||||
|
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
|
||||||
outstream->bytes_per_frame = soundio_get_bytes_per_frame(outstream->format, outstream->layout.channel_count);
|
outstream->bytes_per_frame = soundio_get_bytes_per_frame(outstream->format, outstream->layout.channel_count);
|
||||||
outstream->bytes_per_sample = soundio_get_bytes_per_sample(outstream->format);
|
outstream->bytes_per_sample = soundio_get_bytes_per_sample(outstream->format);
|
||||||
|
|
||||||
SoundIo *soundio = device->soundio;
|
struct SoundIo *soundio = device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
return si->outstream_open(si, os);
|
return si->outstream_open(si, os);
|
||||||
}
|
}
|
||||||
|
|
||||||
void soundio_outstream_destroy(SoundIoOutStream *outstream) {
|
void soundio_outstream_destroy(struct SoundIoOutStream *outstream) {
|
||||||
if (!outstream)
|
if (!outstream)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
|
||||||
SoundIo *soundio = outstream->device->soundio;
|
struct SoundIo *soundio = outstream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
|
|
||||||
if (si->outstream_destroy)
|
if (si->outstream_destroy)
|
||||||
si->outstream_destroy(si, os);
|
si->outstream_destroy(si, os);
|
||||||
|
@ -523,30 +527,30 @@ void soundio_outstream_destroy(SoundIoOutStream *outstream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_outstream_start(struct SoundIoOutStream *outstream) {
|
int soundio_outstream_start(struct SoundIoOutStream *outstream) {
|
||||||
SoundIo *soundio = outstream->device->soundio;
|
struct SoundIo *soundio = outstream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
|
||||||
return si->outstream_start(si, os);
|
return si->outstream_start(si, os);
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_outstream_pause(struct SoundIoOutStream *outstream, bool pause) {
|
int soundio_outstream_pause(struct SoundIoOutStream *outstream, bool pause) {
|
||||||
SoundIo *soundio = outstream->device->soundio;
|
struct SoundIo *soundio = outstream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
|
||||||
return si->outstream_pause(si, os, pause);
|
return si->outstream_pause(si, os, pause);
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_outstream_clear_buffer(struct SoundIoOutStream *outstream) {
|
int soundio_outstream_clear_buffer(struct SoundIoOutStream *outstream) {
|
||||||
SoundIo *soundio = outstream->device->soundio;
|
struct SoundIo *soundio = outstream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
|
||||||
return si->outstream_clear_buffer(si, os);
|
return si->outstream_clear_buffer(si, os);
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_outstream_get_latency(struct SoundIoOutStream *outstream, double *out_latency) {
|
int soundio_outstream_get_latency(struct SoundIoOutStream *outstream, double *out_latency) {
|
||||||
SoundIo *soundio = outstream->device->soundio;
|
struct SoundIo *soundio = outstream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
|
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
|
||||||
return si->outstream_get_latency(si, os, out_latency);
|
return si->outstream_get_latency(si, os, out_latency);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,13 +561,13 @@ static void default_instream_error_callback(struct SoundIoInStream *is, int err)
|
||||||
static void default_overflow_callback(struct SoundIoInStream *instream) { }
|
static void default_overflow_callback(struct SoundIoInStream *instream) { }
|
||||||
|
|
||||||
struct SoundIoInStream *soundio_instream_create(struct SoundIoDevice *device) {
|
struct SoundIoInStream *soundio_instream_create(struct SoundIoDevice *device) {
|
||||||
SoundIoInStreamPrivate *is = allocate<SoundIoInStreamPrivate>(1);
|
struct SoundIoInStreamPrivate *is = ALLOCATE(struct SoundIoInStreamPrivate, 1);
|
||||||
SoundIoInStream *instream = &is->pub;
|
struct SoundIoInStream *instream = &is->pub;
|
||||||
|
|
||||||
if (!is)
|
if (!is)
|
||||||
return nullptr;
|
return NULL;
|
||||||
if (!device)
|
if (!device)
|
||||||
return nullptr;
|
return NULL;
|
||||||
|
|
||||||
instream->device = device;
|
instream->device = device;
|
||||||
soundio_device_ref(device);
|
soundio_device_ref(device);
|
||||||
|
@ -575,7 +579,7 @@ struct SoundIoInStream *soundio_instream_create(struct SoundIoDevice *device) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_instream_open(struct SoundIoInStream *instream) {
|
int soundio_instream_open(struct SoundIoInStream *instream) {
|
||||||
SoundIoDevice *device = instream->device;
|
struct SoundIoDevice *device = instream->device;
|
||||||
if (device->aim != SoundIoDeviceAimInput)
|
if (device->aim != SoundIoDeviceAimInput)
|
||||||
return SoundIoErrorInvalid;
|
return SoundIoErrorInvalid;
|
||||||
|
|
||||||
|
@ -594,7 +598,7 @@ int soundio_instream_open(struct SoundIoInStream *instream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!instream->layout.channel_count) {
|
if (!instream->layout.channel_count) {
|
||||||
const SoundIoChannelLayout *stereo = soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdStereo);
|
const struct SoundIoChannelLayout *stereo = soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdStereo);
|
||||||
instream->layout = soundio_device_supports_layout(device, stereo) ? *stereo : device->layouts[0];
|
instream->layout = soundio_device_supports_layout(device, stereo) ? *stereo : device->layouts[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,16 +608,16 @@ int soundio_instream_open(struct SoundIoInStream *instream) {
|
||||||
|
|
||||||
instream->bytes_per_frame = soundio_get_bytes_per_frame(instream->format, instream->layout.channel_count);
|
instream->bytes_per_frame = soundio_get_bytes_per_frame(instream->format, instream->layout.channel_count);
|
||||||
instream->bytes_per_sample = soundio_get_bytes_per_sample(instream->format);
|
instream->bytes_per_sample = soundio_get_bytes_per_sample(instream->format);
|
||||||
SoundIo *soundio = device->soundio;
|
struct SoundIo *soundio = device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream;
|
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
|
||||||
return si->instream_open(si, is);
|
return si->instream_open(si, is);
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_instream_start(struct SoundIoInStream *instream) {
|
int soundio_instream_start(struct SoundIoInStream *instream) {
|
||||||
SoundIo *soundio = instream->device->soundio;
|
struct SoundIo *soundio = instream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream;
|
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
|
||||||
return si->instream_start(si, is);
|
return si->instream_start(si, is);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -621,9 +625,9 @@ void soundio_instream_destroy(struct SoundIoInStream *instream) {
|
||||||
if (!instream)
|
if (!instream)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream;
|
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
|
||||||
SoundIo *soundio = instream->device->soundio;
|
struct SoundIo *soundio = instream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
|
|
||||||
if (si->instream_destroy)
|
if (si->instream_destroy)
|
||||||
si->instream_destroy(si, is);
|
si->instream_destroy(si, is);
|
||||||
|
@ -633,69 +637,69 @@ void soundio_instream_destroy(struct SoundIoInStream *instream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_instream_pause(struct SoundIoInStream *instream, bool pause) {
|
int soundio_instream_pause(struct SoundIoInStream *instream, bool pause) {
|
||||||
SoundIo *soundio = instream->device->soundio;
|
struct SoundIo *soundio = instream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream;
|
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
|
||||||
return si->instream_pause(si, is, pause);
|
return si->instream_pause(si, is, pause);
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_instream_begin_read(struct SoundIoInStream *instream,
|
int soundio_instream_begin_read(struct SoundIoInStream *instream,
|
||||||
struct SoundIoChannelArea **areas, int *frame_count)
|
struct SoundIoChannelArea **areas, int *frame_count)
|
||||||
{
|
{
|
||||||
SoundIo *soundio = instream->device->soundio;
|
struct SoundIo *soundio = instream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream;
|
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
|
||||||
return si->instream_begin_read(si, is, areas, frame_count);
|
return si->instream_begin_read(si, is, areas, frame_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_instream_end_read(struct SoundIoInStream *instream) {
|
int soundio_instream_end_read(struct SoundIoInStream *instream) {
|
||||||
SoundIo *soundio = instream->device->soundio;
|
struct SoundIo *soundio = instream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream;
|
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
|
||||||
return si->instream_end_read(si, is);
|
return si->instream_end_read(si, is);
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_instream_get_latency(struct SoundIoInStream *instream, double *out_latency) {
|
int soundio_instream_get_latency(struct SoundIoInStream *instream, double *out_latency) {
|
||||||
SoundIo *soundio = instream->device->soundio;
|
struct SoundIo *soundio = instream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream;
|
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
|
||||||
return si->instream_get_latency(si, is, out_latency);
|
return si->instream_get_latency(si, is, out_latency);
|
||||||
}
|
}
|
||||||
|
|
||||||
void soundio_destroy_devices_info(SoundIoDevicesInfo *devices_info) {
|
void soundio_destroy_devices_info(struct SoundIoDevicesInfo *devices_info) {
|
||||||
if (!devices_info)
|
if (!devices_info)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < devices_info->input_devices.length; i += 1)
|
for (int i = 0; i < devices_info->input_devices.length; i += 1)
|
||||||
soundio_device_unref(devices_info->input_devices.at(i));
|
soundio_device_unref(SoundIoListDevicePtr_val_at(&devices_info->input_devices, i));
|
||||||
for (int i = 0; i < devices_info->output_devices.length; i += 1)
|
for (int i = 0; i < devices_info->output_devices.length; i += 1)
|
||||||
soundio_device_unref(devices_info->output_devices.at(i));
|
soundio_device_unref(SoundIoListDevicePtr_val_at(&devices_info->output_devices, i));
|
||||||
|
|
||||||
devices_info->input_devices.deinit();
|
SoundIoListDevicePtr_deinit(&devices_info->input_devices);
|
||||||
devices_info->output_devices.deinit();
|
SoundIoListDevicePtr_deinit(&devices_info->output_devices);
|
||||||
|
|
||||||
free(devices_info);
|
free(devices_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool soundio_have_backend(SoundIoBackend backend) {
|
bool soundio_have_backend(enum SoundIoBackend backend) {
|
||||||
assert(backend > 0);
|
assert(backend > 0);
|
||||||
assert(backend <= SoundIoBackendDummy);
|
assert(backend <= SoundIoBackendDummy);
|
||||||
return backend_init_fns[backend];
|
return backend_init_fns[backend];
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_backend_count(struct SoundIo *soundio) {
|
int soundio_backend_count(struct SoundIo *soundio) {
|
||||||
return array_length(available_backends);
|
return ARRAY_LENGTH(available_backends);
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundIoBackend soundio_get_backend(struct SoundIo *soundio, int index) {
|
enum SoundIoBackend soundio_get_backend(struct SoundIo *soundio, int index) {
|
||||||
return available_backends[index];
|
return available_backends[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool layout_contains(const SoundIoChannelLayout *available_layouts, int available_layouts_count,
|
static bool layout_contains(const struct SoundIoChannelLayout *available_layouts, int available_layouts_count,
|
||||||
const SoundIoChannelLayout *target_layout)
|
const struct SoundIoChannelLayout *target_layout)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < available_layouts_count; i += 1) {
|
for (int i = 0; i < available_layouts_count; i += 1) {
|
||||||
const SoundIoChannelLayout *available_layout = &available_layouts[i];
|
const struct SoundIoChannelLayout *available_layout = &available_layouts[i];
|
||||||
if (soundio_channel_layout_equal(target_layout, available_layout))
|
if (soundio_channel_layout_equal(target_layout, available_layout))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -707,16 +711,16 @@ const struct SoundIoChannelLayout *soundio_best_matching_channel_layout(
|
||||||
const struct SoundIoChannelLayout *available_layouts, int available_layouts_count)
|
const struct SoundIoChannelLayout *available_layouts, int available_layouts_count)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < preferred_layouts_count; i += 1) {
|
for (int i = 0; i < preferred_layouts_count; i += 1) {
|
||||||
const SoundIoChannelLayout *preferred_layout = &preferred_layouts[i];
|
const struct SoundIoChannelLayout *preferred_layout = &preferred_layouts[i];
|
||||||
if (layout_contains(available_layouts, available_layouts_count, preferred_layout))
|
if (layout_contains(available_layouts, available_layouts_count, preferred_layout))
|
||||||
return preferred_layout;
|
return preferred_layout;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int compare_layouts(const void *a, const void *b) {
|
static int compare_layouts(const void *a, const void *b) {
|
||||||
const SoundIoChannelLayout *layout_a = *((SoundIoChannelLayout **)a);
|
const struct SoundIoChannelLayout *layout_a = *((struct SoundIoChannelLayout **)a);
|
||||||
const SoundIoChannelLayout *layout_b = *((SoundIoChannelLayout **)b);
|
const struct SoundIoChannelLayout *layout_b = *((struct SoundIoChannelLayout **)b);
|
||||||
if (layout_a->channel_count > layout_b->channel_count)
|
if (layout_a->channel_count > layout_b->channel_count)
|
||||||
return -1;
|
return -1;
|
||||||
else if (layout_a->channel_count < layout_b->channel_count)
|
else if (layout_a->channel_count < layout_b->channel_count)
|
||||||
|
@ -729,7 +733,7 @@ void soundio_sort_channel_layouts(struct SoundIoChannelLayout *layouts, int layo
|
||||||
if (!layouts)
|
if (!layouts)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qsort(layouts, layouts_count, sizeof(SoundIoChannelLayout), compare_layouts);
|
qsort(layouts, layouts_count, sizeof(struct SoundIoChannelLayout), compare_layouts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void soundio_device_sort_channel_layouts(struct SoundIoDevice *device) {
|
void soundio_device_sort_channel_layouts(struct SoundIoDevice *device) {
|
||||||
|
@ -756,7 +760,7 @@ bool soundio_device_supports_layout(struct SoundIoDevice *device,
|
||||||
|
|
||||||
bool soundio_device_supports_sample_rate(struct SoundIoDevice *device, int sample_rate) {
|
bool soundio_device_supports_sample_rate(struct SoundIoDevice *device, int sample_rate) {
|
||||||
for (int i = 0; i < device->sample_rate_count; i += 1) {
|
for (int i = 0; i < device->sample_rate_count; i += 1) {
|
||||||
SoundIoSampleRateRange *range = &device->sample_rates[i];
|
struct SoundIoSampleRateRange *range = &device->sample_rates[i];
|
||||||
if (sample_rate >= range->min && sample_rate <= range->max)
|
if (sample_rate >= range->min && sample_rate <= range->max)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -772,8 +776,8 @@ int soundio_device_nearest_sample_rate(struct SoundIoDevice *device, int sample_
|
||||||
int best_rate = -1;
|
int best_rate = -1;
|
||||||
int best_delta = -1;
|
int best_delta = -1;
|
||||||
for (int i = 0; i < device->sample_rate_count; i += 1) {
|
for (int i = 0; i < device->sample_rate_count; i += 1) {
|
||||||
SoundIoSampleRateRange *range = &device->sample_rates[i];
|
struct SoundIoSampleRateRange *range = &device->sample_rates[i];
|
||||||
int candidate_rate = clamp(range->min, sample_rate, range->max);
|
int candidate_rate = soundio_int_clamp(range->min, sample_rate, range->max);
|
||||||
if (candidate_rate == sample_rate)
|
if (candidate_rate == sample_rate)
|
||||||
return candidate_rate;
|
return candidate_rate;
|
||||||
|
|
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
|
#ifndef SOUNDIO_SOUNDIO_PRIVATE_H
|
||||||
#define SOUNDIO_SOUNDIO_PRIVATE_H
|
#define SOUNDIO_SOUNDIO_PRIVATE_H
|
||||||
|
|
||||||
// This exists for __declspec(dllexport) and __declspec(dllimport) to be
|
#include "soundio_internal.h"
|
||||||
// defined correctly without the library user having to do anything.
|
|
||||||
#define SOUNDIO_BUILDING_LIBRARY
|
#ifdef SOUNDIO_HAVE_JACK
|
||||||
#include "soundio/soundio.h"
|
#include "jack.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
||||||
|
#include "pulseaudio.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SOUNDIO_HAVE_ALSA
|
||||||
|
#include "alsa.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SOUNDIO_HAVE_COREAUDIO
|
||||||
|
#include "coreaudio.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SOUNDIO_HAVE_WASAPI
|
||||||
|
#include "wasapi.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "dummy.h"
|
||||||
|
|
||||||
|
union SoundIoBackendData {
|
||||||
|
#ifdef SOUNDIO_HAVE_JACK
|
||||||
|
struct SoundIoJack jack;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
||||||
|
struct SoundIoPulseAudio pulseaudio;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_ALSA
|
||||||
|
struct SoundIoAlsa alsa;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_COREAUDIO
|
||||||
|
struct SoundIoCoreAudio coreaudio;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_WASAPI
|
||||||
|
struct SoundIoWasapi wasapi;
|
||||||
|
#endif
|
||||||
|
struct SoundIoDummy dummy;
|
||||||
|
};
|
||||||
|
|
||||||
|
union SoundIoDeviceBackendData {
|
||||||
|
#ifdef SOUNDIO_HAVE_JACK
|
||||||
|
struct SoundIoDeviceJack jack;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
||||||
|
struct SoundIoDevicePulseAudio pulseaudio;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_ALSA
|
||||||
|
struct SoundIoDeviceAlsa alsa;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_COREAUDIO
|
||||||
|
struct SoundIoDeviceCoreAudio coreaudio;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_WASAPI
|
||||||
|
struct SoundIoDeviceWasapi wasapi;
|
||||||
|
#endif
|
||||||
|
struct SoundIoDeviceDummy dummy;
|
||||||
|
};
|
||||||
|
|
||||||
|
union SoundIoOutStreamBackendData {
|
||||||
|
#ifdef SOUNDIO_HAVE_JACK
|
||||||
|
struct SoundIoOutStreamJack jack;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
||||||
|
struct SoundIoOutStreamPulseAudio pulseaudio;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_ALSA
|
||||||
|
struct SoundIoOutStreamAlsa alsa;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_COREAUDIO
|
||||||
|
struct SoundIoOutStreamCoreAudio coreaudio;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_WASAPI
|
||||||
|
struct SoundIoOutStreamWasapi wasapi;
|
||||||
|
#endif
|
||||||
|
struct SoundIoOutStreamDummy dummy;
|
||||||
|
};
|
||||||
|
|
||||||
|
union SoundIoInStreamBackendData {
|
||||||
|
#ifdef SOUNDIO_HAVE_JACK
|
||||||
|
struct SoundIoInStreamJack jack;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
||||||
|
struct SoundIoInStreamPulseAudio pulseaudio;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_ALSA
|
||||||
|
struct SoundIoInStreamAlsa alsa;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_COREAUDIO
|
||||||
|
struct SoundIoInStreamCoreAudio coreaudio;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_WASAPI
|
||||||
|
struct SoundIoInStreamWasapi wasapi;
|
||||||
|
#endif
|
||||||
|
struct SoundIoInStreamDummy dummy;
|
||||||
|
};
|
||||||
|
|
||||||
|
SOUNDIO_MAKE_LIST_STRUCT(struct SoundIoDevice*, SoundIoListDevicePtr, SOUNDIO_LIST_NOT_STATIC)
|
||||||
|
SOUNDIO_MAKE_LIST_PROTO(struct SoundIoDevice*, SoundIoListDevicePtr, SOUNDIO_LIST_NOT_STATIC)
|
||||||
|
|
||||||
|
struct SoundIoDevicesInfo {
|
||||||
|
struct SoundIoListDevicePtr input_devices;
|
||||||
|
struct SoundIoListDevicePtr output_devices;
|
||||||
|
// can be -1 when default device is unknown
|
||||||
|
int default_output_index;
|
||||||
|
int default_input_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SoundIoOutStreamPrivate {
|
||||||
|
struct SoundIoOutStream pub;
|
||||||
|
union SoundIoOutStreamBackendData backend_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SoundIoInStreamPrivate {
|
||||||
|
struct SoundIoInStream pub;
|
||||||
|
union SoundIoInStreamBackendData backend_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SoundIoPrivate {
|
||||||
|
struct SoundIo pub;
|
||||||
|
|
||||||
|
// Safe to read from a single thread without a mutex.
|
||||||
|
struct SoundIoDevicesInfo *safe_devices_info;
|
||||||
|
|
||||||
|
void (*destroy)(struct SoundIoPrivate *);
|
||||||
|
void (*flush_events)(struct SoundIoPrivate *);
|
||||||
|
void (*wait_events)(struct SoundIoPrivate *);
|
||||||
|
void (*wakeup)(struct SoundIoPrivate *);
|
||||||
|
void (*force_device_scan)(struct SoundIoPrivate *);
|
||||||
|
|
||||||
|
int (*outstream_open)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||||
|
void (*outstream_destroy)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||||
|
int (*outstream_start)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||||
|
int (*outstream_begin_write)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *,
|
||||||
|
struct SoundIoChannelArea **out_areas, int *out_frame_count);
|
||||||
|
int (*outstream_end_write)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||||
|
int (*outstream_clear_buffer)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||||
|
int (*outstream_pause)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, bool pause);
|
||||||
|
int (*outstream_get_latency)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, double *out_latency);
|
||||||
|
|
||||||
|
|
||||||
|
int (*instream_open)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
|
||||||
|
void (*instream_destroy)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
|
||||||
|
int (*instream_start)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
|
||||||
|
int (*instream_begin_read)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *,
|
||||||
|
struct SoundIoChannelArea **out_areas, int *out_frame_count);
|
||||||
|
int (*instream_end_read)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
|
||||||
|
int (*instream_pause)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *, bool pause);
|
||||||
|
int (*instream_get_latency)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *, double *out_latency);
|
||||||
|
|
||||||
|
union SoundIoBackendData backend_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
SOUNDIO_MAKE_LIST_STRUCT(struct SoundIoSampleRateRange, SoundIoListSampleRateRange, SOUNDIO_LIST_NOT_STATIC)
|
||||||
|
SOUNDIO_MAKE_LIST_PROTO(struct SoundIoSampleRateRange, SoundIoListSampleRateRange, SOUNDIO_LIST_NOT_STATIC)
|
||||||
|
|
||||||
|
struct SoundIoDevicePrivate {
|
||||||
|
struct SoundIoDevice pub;
|
||||||
|
union SoundIoDeviceBackendData backend_data;
|
||||||
|
void (*destruct)(struct SoundIoDevicePrivate *);
|
||||||
|
struct SoundIoSampleRateRange prealloc_sample_rate_range;
|
||||||
|
struct SoundIoListSampleRateRange sample_rates;
|
||||||
|
enum SoundIoFormat prealloc_format;
|
||||||
|
};
|
||||||
|
|
||||||
|
void soundio_destroy_devices_info(struct SoundIoDevicesInfo *devices_info);
|
||||||
|
|
||||||
|
static const int SOUNDIO_MIN_SAMPLE_RATE = 8000;
|
||||||
|
static const int SOUNDIO_MAX_SAMPLE_RATE = 5644800;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
#include "util.hpp"
|
#include "util.h"
|
||||||
|
|
||||||
void soundio_panic(const char *format, ...) {
|
void soundio_panic(const char *format, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
@ -25,13 +25,13 @@ char *soundio_alloc_sprintf(int *len, const char *format, ...) {
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
va_copy(ap2, ap);
|
va_copy(ap2, ap);
|
||||||
|
|
||||||
int len1 = vsnprintf(nullptr, 0, format, ap);
|
int len1 = vsnprintf(NULL, 0, format, ap);
|
||||||
assert(len1 >= 0);
|
assert(len1 >= 0);
|
||||||
|
|
||||||
size_t required_size = len1 + 1;
|
size_t required_size = len1 + 1;
|
||||||
char *mem = allocate<char>(required_size);
|
char *mem = ALLOCATE(char, required_size);
|
||||||
if (!mem)
|
if (!mem)
|
||||||
return nullptr;
|
return NULL;
|
||||||
|
|
||||||
int len2 = vsnprintf(mem, required_size, format, ap2);
|
int len2 = vsnprintf(mem, required_size, format, ap2);
|
||||||
assert(len2 == len1);
|
assert(len2 == len1);
|
|
@ -5,26 +5,44 @@
|
||||||
* See http://opensource.org/licenses/MIT
|
* See http://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SOUNDIO_UTIL_HPP
|
#ifndef SOUNDIO_UTIL_H
|
||||||
#define SOUNDIO_UTIL_HPP
|
#define SOUNDIO_UTIL_H
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
template<typename T>
|
#define ALLOCATE_NONZERO(Type, count) malloc((count) * sizeof(Type))
|
||||||
__attribute__((malloc)) static inline T *allocate_nonzero(size_t count) {
|
|
||||||
return reinterpret_cast<T*>(malloc(count * sizeof(T)));
|
#define ALLOCATE(Type, count) calloc(count, sizeof(Type))
|
||||||
|
|
||||||
|
#define REALLOCATE_NONZERO(Type, old, new_count) realloc(old, (new_count) * sizeof(Type))
|
||||||
|
|
||||||
|
#define ARRAY_LENGTH(array) (sizeof(array)/sizeof((array)[0]))
|
||||||
|
|
||||||
|
static inline int soundio_int_min(int a, int b) {
|
||||||
|
return (a <= b) ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
static inline int soundio_int_max(int a, int b) {
|
||||||
__attribute__((malloc)) static inline T *allocate(size_t count) {
|
return (a >= b) ? a : b;
|
||||||
return reinterpret_cast<T*>(calloc(count, sizeof(T)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
static inline int soundio_int_clamp(int min_value, int value, int max_value) {
|
||||||
static inline T *reallocate_nonzero(T * old, size_t new_count) {
|
return soundio_int_max(soundio_int_min(value, max_value), min_value);
|
||||||
return reinterpret_cast<T*>(realloc(old, new_count * sizeof(T)));
|
}
|
||||||
|
|
||||||
|
static inline double soundio_double_min(double a, double b) {
|
||||||
|
return (a <= b) ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double soundio_double_max(double a, double b) {
|
||||||
|
return (a >= b) ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double soundio_double_clamp(double min_value, double value, double max_value) {
|
||||||
|
return soundio_double_max(soundio_double_min(value, max_value), min_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void soundio_panic(const char *format, ...)
|
void soundio_panic(const char *format, ...)
|
||||||
|
@ -36,9 +54,9 @@ char *soundio_alloc_sprintf(int *len, const char *format, ...)
|
||||||
__attribute__ ((format (printf, 2, 3)));
|
__attribute__ ((format (printf, 2, 3)));
|
||||||
|
|
||||||
static inline char *soundio_str_dupe(const char *str, int str_len) {
|
static inline char *soundio_str_dupe(const char *str, int str_len) {
|
||||||
char *out = allocate_nonzero<char>(str_len + 1);
|
char *out = ALLOCATE_NONZERO(char, str_len + 1);
|
||||||
if (!out)
|
if (!out)
|
||||||
return nullptr;
|
return NULL;
|
||||||
memcpy(out, str, str_len);
|
memcpy(out, str, str_len);
|
||||||
out[str_len] = 0;
|
out[str_len] = 0;
|
||||||
return out;
|
return out;
|
||||||
|
@ -61,24 +79,4 @@ static inline double ceil_dbl(double x) {
|
||||||
return ceiling;
|
return ceiling;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T, long n>
|
|
||||||
static constexpr long array_length(const T (&)[n]) {
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static inline T max(T a, T b) {
|
|
||||||
return (a >= b) ? a : b;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static inline T min(T a, T b) {
|
|
||||||
return (a <= b) ? a : b;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static inline T clamp(T min_value, T value, T max_value) {
|
|
||||||
return max(min(value, max_value), min_value);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -5,13 +5,13 @@
|
||||||
* See http://opensource.org/licenses/MIT
|
* See http://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SOUNDIO_WASAPI_HPP
|
#ifndef SOUNDIO_WASAPI_H
|
||||||
#define SOUNDIO_WASAPI_HPP
|
#define SOUNDIO_WASAPI_H
|
||||||
|
|
||||||
#include "soundio_private.h"
|
#include "soundio_internal.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "atomics.hpp"
|
#include "list.h"
|
||||||
#include "list.hpp"
|
#include "atomics.h"
|
||||||
|
|
||||||
#define INITGUID
|
#define INITGUID
|
||||||
#define CINTERFACE
|
#define CINTERFACE
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
#include <audiosessiontypes.h>
|
#include <audiosessiontypes.h>
|
||||||
#include <audiopolicy.h>
|
#include <audiopolicy.h>
|
||||||
|
|
||||||
|
struct SoundIoPrivate;
|
||||||
int soundio_wasapi_init(struct SoundIoPrivate *si);
|
int soundio_wasapi_init(struct SoundIoPrivate *si);
|
||||||
|
|
||||||
struct SoundIoDeviceWasapi {
|
struct SoundIoDeviceWasapi {
|
||||||
|
@ -33,10 +34,10 @@ struct SoundIoDeviceWasapi {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoWasapi {
|
struct SoundIoWasapi {
|
||||||
SoundIoOsMutex *mutex;
|
struct SoundIoOsMutex *mutex;
|
||||||
SoundIoOsCond *cond;
|
struct SoundIoOsCond *cond;
|
||||||
SoundIoOsCond *scan_devices_cond;
|
struct SoundIoOsCond *scan_devices_cond;
|
||||||
SoundIoOsMutex *scan_devices_mutex;
|
struct SoundIoOsMutex *scan_devices_mutex;
|
||||||
struct SoundIoOsThread *thread;
|
struct SoundIoOsThread *thread;
|
||||||
bool abort_flag;
|
bool abort_flag;
|
||||||
// this one is ready to be read with flush_events. protected by mutex
|
// this one is ready to be read with flush_events. protected by mutex
|
||||||
|
@ -58,17 +59,17 @@ struct SoundIoOutStreamWasapi {
|
||||||
IAudioSessionControl *audio_session_control;
|
IAudioSessionControl *audio_session_control;
|
||||||
LPWSTR stream_name;
|
LPWSTR stream_name;
|
||||||
bool need_resample;
|
bool need_resample;
|
||||||
SoundIoOsThread *thread;
|
struct SoundIoOsThread *thread;
|
||||||
SoundIoOsMutex *mutex;
|
struct SoundIoOsMutex *mutex;
|
||||||
SoundIoOsCond *cond;
|
struct SoundIoOsCond *cond;
|
||||||
SoundIoOsCond *start_cond;
|
struct SoundIoOsCond *start_cond;
|
||||||
atomic_flag thread_exit_flag;
|
atomic_flag thread_exit_flag;
|
||||||
bool is_raw;
|
bool is_raw;
|
||||||
int writable_frame_count;
|
int writable_frame_count;
|
||||||
UINT32 buffer_frame_count;
|
UINT32 buffer_frame_count;
|
||||||
int write_frame_count;
|
int write_frame_count;
|
||||||
HANDLE h_event;
|
HANDLE h_event;
|
||||||
atomic_bool desired_pause_state;
|
struct SoundIoAtomicBool desired_pause_state;
|
||||||
atomic_flag pause_resume_flag;
|
atomic_flag pause_resume_flag;
|
||||||
atomic_flag clear_buffer_flag;
|
atomic_flag clear_buffer_flag;
|
||||||
bool is_paused;
|
bool is_paused;
|
||||||
|
@ -76,7 +77,7 @@ struct SoundIoOutStreamWasapi {
|
||||||
int open_err;
|
int open_err;
|
||||||
bool started;
|
bool started;
|
||||||
UINT32 min_padding_frames;
|
UINT32 min_padding_frames;
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoInStreamWasapi {
|
struct SoundIoInStreamWasapi {
|
||||||
|
@ -84,10 +85,10 @@ struct SoundIoInStreamWasapi {
|
||||||
IAudioCaptureClient *audio_capture_client;
|
IAudioCaptureClient *audio_capture_client;
|
||||||
IAudioSessionControl *audio_session_control;
|
IAudioSessionControl *audio_session_control;
|
||||||
LPWSTR stream_name;
|
LPWSTR stream_name;
|
||||||
SoundIoOsThread *thread;
|
struct SoundIoOsThread *thread;
|
||||||
SoundIoOsMutex *mutex;
|
struct SoundIoOsMutex *mutex;
|
||||||
SoundIoOsCond *cond;
|
struct SoundIoOsCond *cond;
|
||||||
SoundIoOsCond *start_cond;
|
struct SoundIoOsCond *start_cond;
|
||||||
atomic_flag thread_exit_flag;
|
atomic_flag thread_exit_flag;
|
||||||
bool is_raw;
|
bool is_raw;
|
||||||
int readable_frame_count;
|
int readable_frame_count;
|
||||||
|
@ -100,7 +101,7 @@ struct SoundIoInStreamWasapi {
|
||||||
bool started;
|
bool started;
|
||||||
char *read_buf;
|
char *read_buf;
|
||||||
int read_buf_frames_left;
|
int read_buf_frames_left;
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -5,15 +5,15 @@
|
||||||
* See http://opensource.org/licenses/MIT
|
* See http://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "soundio.hpp"
|
#include "soundio_private.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "util.hpp"
|
#include "util.h"
|
||||||
#include "atomics.hpp"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
static int usage(char *exe) {
|
static int usage(char *exe) {
|
||||||
fprintf(stderr, "Usage: %s [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi] [--latency seconds]\n", exe);
|
fprintf(stderr, "Usage: %s [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi] [--latency seconds]\n", exe);
|
||||||
|
@ -51,9 +51,9 @@ static int pulse_frames_left = -1;
|
||||||
static const double PI = 3.14159265358979323846264338328;
|
static const double PI = 3.14159265358979323846264338328;
|
||||||
static double seconds_offset = 0.0;
|
static double seconds_offset = 0.0;
|
||||||
|
|
||||||
static SoundIoRingBuffer pulse_rb;
|
static struct SoundIoRingBuffer pulse_rb;
|
||||||
|
|
||||||
static void write_time(SoundIoOutStream *outstream, double extra) {
|
static void write_time(struct SoundIoOutStream *outstream, double extra) {
|
||||||
double latency;
|
double latency;
|
||||||
int err;
|
int err;
|
||||||
if ((err = soundio_outstream_get_latency(outstream, &latency))) {
|
if ((err = soundio_outstream_get_latency(outstream, &latency))) {
|
|
@ -1,9 +1,9 @@
|
||||||
#undef NDEBUG
|
#undef NDEBUG
|
||||||
|
|
||||||
#include "soundio.hpp"
|
#include "soundio_private.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "util.hpp"
|
#include "util.h"
|
||||||
#include "atomics.hpp"
|
#include "atomics.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -58,7 +58,7 @@ static void test_create_outstream(void) {
|
||||||
static void test_ring_buffer_basic(void) {
|
static void test_ring_buffer_basic(void) {
|
||||||
struct SoundIo *soundio = soundio_create();
|
struct SoundIo *soundio = soundio_create();
|
||||||
assert(soundio);
|
assert(soundio);
|
||||||
SoundIoRingBuffer *rb = soundio_ring_buffer_create(soundio, 10);
|
struct SoundIoRingBuffer *rb = soundio_ring_buffer_create(soundio, 10);
|
||||||
assert(rb);
|
assert(rb);
|
||||||
|
|
||||||
int page_size = soundio_os_page_size();
|
int page_size = soundio_os_page_size();
|
||||||
|
@ -98,41 +98,41 @@ static void test_ring_buffer_basic(void) {
|
||||||
soundio_destroy(soundio);
|
soundio_destroy(soundio);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SoundIoRingBuffer *rb = nullptr;
|
static struct SoundIoRingBuffer *rb = NULL;
|
||||||
static const int rb_size = 3528;
|
static const int rb_size = 3528;
|
||||||
static long expected_write_head;
|
static long expected_write_head;
|
||||||
static long expected_read_head;
|
static long expected_read_head;
|
||||||
static atomic_bool rb_done;
|
static struct SoundIoAtomicBool rb_done;
|
||||||
static atomic_int rb_write_it;
|
static struct SoundIoAtomicInt rb_write_it;
|
||||||
static atomic_int rb_read_it;
|
static struct SoundIoAtomicInt rb_read_it;
|
||||||
|
|
||||||
// just for testing purposes; does not need to be high quality random
|
// just for testing purposes; does not need to be high quality random
|
||||||
static double random_double(void) {
|
static double random_double(void) {
|
||||||
return ((double)rand() / (double)RAND_MAX);
|
return ((double)rand() / (double)RAND_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reader_thread_run(void *) {
|
static void reader_thread_run(void *arg) {
|
||||||
while (!rb_done) {
|
while (!SOUNDIO_ATOMIC_LOAD(rb_done)) {
|
||||||
rb_read_it += 1;
|
SOUNDIO_ATOMIC_FETCH_ADD(rb_read_it, 1);
|
||||||
int fill_count = soundio_ring_buffer_fill_count(rb);
|
int fill_count = soundio_ring_buffer_fill_count(rb);
|
||||||
assert(fill_count >= 0);
|
assert(fill_count >= 0);
|
||||||
assert(fill_count <= rb_size);
|
assert(fill_count <= rb_size);
|
||||||
int amount_to_read = min((int)(random_double() * 2.0 * fill_count), fill_count);
|
int amount_to_read = soundio_int_min(random_double() * 2.0 * fill_count, fill_count);
|
||||||
soundio_ring_buffer_advance_read_ptr(rb, amount_to_read);
|
soundio_ring_buffer_advance_read_ptr(rb, amount_to_read);
|
||||||
expected_read_head += amount_to_read;
|
expected_read_head += amount_to_read;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void writer_thread_run(void *) {
|
static void writer_thread_run(void *arg) {
|
||||||
while (!rb_done) {
|
while (!SOUNDIO_ATOMIC_LOAD(rb_done)) {
|
||||||
rb_write_it += 1;
|
SOUNDIO_ATOMIC_FETCH_ADD(rb_write_it, 1);
|
||||||
int fill_count = soundio_ring_buffer_fill_count(rb);
|
int fill_count = soundio_ring_buffer_fill_count(rb);
|
||||||
assert(fill_count >= 0);
|
assert(fill_count >= 0);
|
||||||
assert(fill_count <= rb_size);
|
assert(fill_count <= rb_size);
|
||||||
int free_count = rb_size - fill_count;
|
int free_count = rb_size - fill_count;
|
||||||
assert(free_count >= 0);
|
assert(free_count >= 0);
|
||||||
assert(free_count <= rb_size);
|
assert(free_count <= rb_size);
|
||||||
int value = min((int)(random_double() * 2.0 * free_count), free_count);
|
int value = soundio_int_min(random_double() * 2.0 * free_count, free_count);
|
||||||
soundio_ring_buffer_advance_write_ptr(rb, value);
|
soundio_ring_buffer_advance_write_ptr(rb, value);
|
||||||
expected_write_head += value;
|
expected_write_head += value;
|
||||||
}
|
}
|
||||||
|
@ -144,18 +144,18 @@ static void test_ring_buffer_threaded(void) {
|
||||||
rb = soundio_ring_buffer_create(soundio, rb_size);
|
rb = soundio_ring_buffer_create(soundio, rb_size);
|
||||||
expected_write_head = 0;
|
expected_write_head = 0;
|
||||||
expected_read_head = 0;
|
expected_read_head = 0;
|
||||||
rb_read_it = 0;
|
SOUNDIO_ATOMIC_STORE(rb_read_it, 0);
|
||||||
rb_write_it = 0;
|
SOUNDIO_ATOMIC_STORE(rb_write_it, 0);
|
||||||
rb_done = false;
|
SOUNDIO_ATOMIC_STORE(rb_done, false);
|
||||||
|
|
||||||
SoundIoOsThread *reader_thread;
|
struct SoundIoOsThread *reader_thread;
|
||||||
ok_or_panic(soundio_os_thread_create(reader_thread_run, nullptr, nullptr, &reader_thread));
|
ok_or_panic(soundio_os_thread_create(reader_thread_run, NULL, NULL, &reader_thread));
|
||||||
|
|
||||||
SoundIoOsThread *writer_thread;
|
struct SoundIoOsThread *writer_thread;
|
||||||
ok_or_panic(soundio_os_thread_create(writer_thread_run, nullptr, nullptr, &writer_thread));
|
ok_or_panic(soundio_os_thread_create(writer_thread_run, NULL, NULL, &writer_thread));
|
||||||
|
|
||||||
while (rb_read_it < 100000 || rb_write_it < 100000) {}
|
while (SOUNDIO_ATOMIC_LOAD(rb_read_it) < 100000 || SOUNDIO_ATOMIC_LOAD(rb_write_it) < 100000) {}
|
||||||
rb_done = true;
|
SOUNDIO_ATOMIC_STORE(rb_done, true);
|
||||||
|
|
||||||
soundio_os_thread_destroy(reader_thread);
|
soundio_os_thread_destroy(reader_thread);
|
||||||
soundio_os_thread_destroy(writer_thread);
|
soundio_os_thread_destroy(writer_thread);
|
||||||
|
@ -219,10 +219,10 @@ struct Test {
|
||||||
static struct Test tests[] = {
|
static struct Test tests[] = {
|
||||||
{"os_get_time", test_os_get_time},
|
{"os_get_time", test_os_get_time},
|
||||||
{"create output stream", test_create_outstream},
|
{"create output stream", test_create_outstream},
|
||||||
{"ring buffer basic", test_ring_buffer_basic},
|
|
||||||
{"ring buffer threaded", test_ring_buffer_threaded},
|
|
||||||
{"mirrored memory", test_mirrored_memory},
|
{"mirrored memory", test_mirrored_memory},
|
||||||
{"soundio_device_nearest_sample_rate", test_nearest_sample_rate},
|
{"soundio_device_nearest_sample_rate", test_nearest_sample_rate},
|
||||||
|
{"ring buffer basic", test_ring_buffer_basic},
|
||||||
|
{"ring buffer threaded", test_ring_buffer_threaded},
|
||||||
{NULL, NULL},
|
{NULL, NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -233,7 +233,7 @@ static void exec_test(struct Test *test) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
const char *match = nullptr;
|
const char *match = NULL;
|
||||||
|
|
||||||
if (argc == 2)
|
if (argc == 2)
|
||||||
match = argv[1];
|
match = argv[1];
|
Loading…
Reference in a new issue