mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-12-23 06:29:38 +00:00
Remove libsoundio library.
This commit is contained in:
parent
c7f21040ae
commit
281aaa1902
3
thirdparty/libsoundio/.gitignore
vendored
3
thirdparty/libsoundio/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
build/
|
||||
build-win32/
|
||||
build-win64/
|
78
thirdparty/libsoundio/CHANGELOG.md
vendored
78
thirdparty/libsoundio/CHANGELOG.md
vendored
@ -1,78 +0,0 @@
|
||||
### Version 1.1.0 (2016-01-31)
|
||||
|
||||
* JACK: delete broken pause implementation. Previously, calling
|
||||
`soundio_outstream_pause` or `soundio_instream_pause` during the
|
||||
`write_callback` or `read_callback` would cause a deadlock. Now, attempting
|
||||
to pause always results in `SoundIoErrorBackendIncompatible`.
|
||||
* PulseAudio: improve latency handling code. It now passes the latency test
|
||||
along with all the other backends.
|
||||
* PulseAudio: fix incorrect outstream `software_latency`.
|
||||
* libsoundio source code is now pure C, no C++ mixed in.
|
||||
* ALSA: better device detection.
|
||||
- No longer suppress sysdefault.
|
||||
- If default and sysdefault are missing, use the first device as the default
|
||||
device.
|
||||
* Workaround for Raspberry Pi driver that incorrectly reports itself as Output
|
||||
when it is actually Input.
|
||||
* ALSA: let alsa lib choose period settings. Fixes behavior with many ALSA
|
||||
devices.
|
||||
* ALSA: fix potential cleanup deadlock.
|
||||
* ALSA: fix crash for devices with null description, thanks to Charles Lehner.
|
||||
* CoreAudio: drop support for MacOS 10.9. There was a bug for this system that
|
||||
was never resolved, so it didn't work in the first place.
|
||||
* Record example handles device not found and probe errors gracefully.
|
||||
* Fix typo in microphone example, thanks to James Dyson.
|
||||
* Improve documentation.
|
||||
* New functions available: `soundio_version_string`, `soundio_version_major`,
|
||||
`soundio_version_minor`, `soundio_version_patch`.
|
||||
* libsoundio source code now builds with MSVC, thanks to Raphaël Londeix.
|
||||
|
||||
### Version 1.0.3 (2015-10-20)
|
||||
|
||||
* Architecture independent header files.
|
||||
* Add --latency and --sample-rate to sine example.
|
||||
* ALSA: fix deadlock under some circumstances.
|
||||
* dummy: fix deadlock when pause called from `write_callback`.
|
||||
* Fix double clean-up corruption when opening stream fails.
|
||||
* Add --device and --raw to underflow test.
|
||||
* ALSA: use period size to calculate buffer size, fixes opening output stream
|
||||
sometimes resulting in an error.
|
||||
|
||||
### Version 1.0.2 (2015-09-24)
|
||||
|
||||
* build: fix GNUInstallDirs not working.
|
||||
* docs: fix incorrect docs for `soundio_instream_pause`.
|
||||
* PulseAudio: fix `soundio_outstream_pause` triggering assertion when called
|
||||
from within `write_callback`.
|
||||
* fix mirrored memory not working on Linux (fixes corrupted data in ring
|
||||
buffer).
|
||||
* os: fix crash when creating non high priority thread fails.
|
||||
* docs: fix typos and cleanup.
|
||||
* fix and add test for `soundio_device_nearest_sample_rate`.
|
||||
|
||||
### Version 1.0.1 (2015-09-11)
|
||||
|
||||
* libsoundio no longer depends on or links against libm.
|
||||
* ALSA: treat ALSA as unavailable when /dev/snd does not exist.
|
||||
* ALSA: remove duplicate assert.
|
||||
* ALSA: remove stray print statement.
|
||||
* ALSA: pausing returns error code when state is invalid instead of reaching
|
||||
assertion failure in pcm.c.
|
||||
* JACK: fix infinite loop when refreshing devices.
|
||||
* PulseAudio: better clear buffer implementation.
|
||||
* dummy backend: fix sometimes calling `write_callback` with
|
||||
`frame_count_max` equal to 0.
|
||||
* os: fix some variables accidentally not declared static.
|
||||
* macos: fix not cleaning up condition variables.
|
||||
* macos: avoid allocation when getting time.
|
||||
* docs: note that `read_callback` and `write_callback` must be real time safe.
|
||||
* docs: record example demonstrates proper real time safety by not calling
|
||||
fwrite in `read_callback`.
|
||||
* docs: add note to record example about shutting down.
|
||||
* docs: make microphone example latency a command line argument.
|
||||
* build: fix build on linux with clang.
|
||||
* build: static libs, examples, and tests are optional.
|
||||
|
||||
### Version 1.0.0 (2015-09-03)
|
||||
|
||||
* Initial public release.
|
388
thirdparty/libsoundio/CMakeLists.txt
vendored
388
thirdparty/libsoundio/CMakeLists.txt
vendored
@ -1,388 +0,0 @@
|
||||
cmake_minimum_required(VERSION 2.8.5)
|
||||
project(libsoundio C)
|
||||
set(CMAKE_MODULE_PATH ${libsoundio_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS 3.0.0)
|
||||
set(CMAKE_INSTALL_LIBDIR "lib" CACHE PATH "library install dir (lib)")
|
||||
set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "header base install dir (include)")
|
||||
set(CMAKE_INSTALL_BINDIR "bin" CACHE PATH "user executables (bin)")
|
||||
else()
|
||||
cmake_policy(SET CMP0042 NEW)
|
||||
cmake_policy(SET CMP0046 NEW)
|
||||
include(GNUInstallDirs)
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING
|
||||
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
|
||||
endif()
|
||||
|
||||
set(LIBSOUNDIO_VERSION_MAJOR 2)
|
||||
set(LIBSOUNDIO_VERSION_MINOR 0)
|
||||
set(LIBSOUNDIO_VERSION_PATCH 0)
|
||||
set(LIBSOUNDIO_VERSION "${LIBSOUNDIO_VERSION_MAJOR}.${LIBSOUNDIO_VERSION_MINOR}.${LIBSOUNDIO_VERSION_PATCH}")
|
||||
message("Configuring libsoundio version ${LIBSOUNDIO_VERSION}")
|
||||
|
||||
if(NOT SOUNDIO_STATIC_LIBNAME)
|
||||
set(SOUNDIO_STATIC_LIBNAME soundio)
|
||||
endif()
|
||||
|
||||
option(BUILD_STATIC_LIBS "Build static libraries" ON)
|
||||
option(BUILD_DYNAMIC_LIBS "Build dynamic libraries" ON)
|
||||
option(BUILD_EXAMPLE_PROGRAMS "Build example programs" ON)
|
||||
option(BUILD_TESTS "Build tests" ON)
|
||||
option(ENABLE_JACK "Enable JACK backend" ON)
|
||||
option(ENABLE_PULSEAUDIO "Enable PulseAudio backend" ON)
|
||||
option(ENABLE_ALSA "Enable ALSA backend" ON)
|
||||
option(ENABLE_COREAUDIO "Enable CoreAudio backend" ON)
|
||||
option(ENABLE_WASAPI "Enable WASAPI backend" ON)
|
||||
|
||||
find_package(Threads)
|
||||
if(Threads_FOUND)
|
||||
set(STATUS_THREADS "OK")
|
||||
else(Threads_FOUND)
|
||||
set(STATUS_THREADS "not found")
|
||||
endif(Threads_FOUND)
|
||||
|
||||
if(ENABLE_JACK)
|
||||
find_package(JACK)
|
||||
if(JACK_FOUND)
|
||||
set(STATUS_JACK "OK")
|
||||
set(SOUNDIO_HAVE_JACK true)
|
||||
include_directories(${JACK_INCLUDE_DIR})
|
||||
else()
|
||||
set(STATUS_JACK "not found")
|
||||
set(SOUNDIO_HAVE_JACK false)
|
||||
set(JACK_LIBRARY "")
|
||||
endif()
|
||||
else()
|
||||
set(STATUS_JACK "disabled")
|
||||
set(SOUNDIO_HAVE_JACK false)
|
||||
set(JACK_LIBRARY "")
|
||||
endif()
|
||||
|
||||
if(ENABLE_PULSEAUDIO)
|
||||
find_package(PulseAudio)
|
||||
if(PULSEAUDIO_FOUND)
|
||||
set(STATUS_PULSEAUDIO "OK")
|
||||
set(SOUNDIO_HAVE_PULSEAUDIO true)
|
||||
include_directories(${PULSEAUDIO_INCLUDE_DIR})
|
||||
else()
|
||||
set(STATUS_PULSEAUDIO "not found")
|
||||
set(SOUNDIO_HAVE_PULSEAUDIO false)
|
||||
set(PULSEAUDIO_LIBRARY "")
|
||||
endif()
|
||||
else()
|
||||
set(STATUS_PULSEAUDIO "disabled")
|
||||
set(SOUNDIO_HAVE_PULSEAUDIO false)
|
||||
set(PULSEAUDIO_LIBRARY "")
|
||||
endif()
|
||||
|
||||
if(ENABLE_ALSA)
|
||||
find_package(ALSA)
|
||||
if(ALSA_FOUND)
|
||||
set(STATUS_ALSA "OK")
|
||||
set(SOUNDIO_HAVE_ALSA true)
|
||||
include_directories(${ALSA_INCLUDE_DIRS})
|
||||
else()
|
||||
set(STATUS_ALSA "not found")
|
||||
set(SOUNDIO_HAVE_ALSA false)
|
||||
set(ALSA_LIBRARIES "")
|
||||
endif()
|
||||
else()
|
||||
set(STATUS_ALSA "disabled")
|
||||
set(SOUNDIO_HAVE_ALSA false)
|
||||
set(ALSA_LIBRARIES "")
|
||||
endif()
|
||||
|
||||
if(ENABLE_COREAUDIO)
|
||||
find_package(CoreAudio)
|
||||
if(COREAUDIO_FOUND)
|
||||
set(STATUS_COREAUDIO "OK")
|
||||
set(SOUNDIO_HAVE_COREAUDIO true)
|
||||
include_directories(${COREAUDIO_INCLUDE_DIR})
|
||||
|
||||
find_path(COREFOUNDATION_INCLUDE_DIR NAMES CoreFoundation.h)
|
||||
find_library(COREFOUNDATION_LIBRARY NAMES CoreFoundation)
|
||||
include_directories(${COREFOUNDATION_INCLUDE_DIR})
|
||||
|
||||
find_path(AUDIOUNIT_INCLUDE_DIR NAMES AudioUnit.h)
|
||||
find_library(AUDIOUNIT_LIBRARY NAMES AudioUnit)
|
||||
include_directories(${AUDIOUNIT_INCLUDE_DIR})
|
||||
else()
|
||||
set(STATUS_COREAUDIO "not found")
|
||||
set(SOUNDIO_HAVE_COREAUDIO false)
|
||||
set(COREAUDIO_LIBRARY "")
|
||||
set(COREFOUNDATION_LIBRARY "")
|
||||
set(AUDIOUNIT_LIBRARY "")
|
||||
endif()
|
||||
else()
|
||||
set(STATUS_COREAUDIO "disabled")
|
||||
set(SOUNDIO_HAVE_COREAUDIO false)
|
||||
set(COREAUDIO_LIBRARY "")
|
||||
set(COREFOUNDATION_LIBRARY "")
|
||||
set(AUDIOUNIT_LIBRARY "")
|
||||
endif()
|
||||
|
||||
if(ENABLE_WASAPI)
|
||||
find_package(WASAPI)
|
||||
if(WASAPI_FOUND)
|
||||
set(STATUS_WASAPI "OK")
|
||||
set(SOUNDIO_HAVE_WASAPI true)
|
||||
else()
|
||||
set(STATUS_WASAPI "not found")
|
||||
set(SOUNDIO_HAVE_WASAPI false)
|
||||
endif()
|
||||
else()
|
||||
set(STATUS_WASAPI "disabled")
|
||||
set(SOUNDIO_HAVE_WASAPI false)
|
||||
endif()
|
||||
|
||||
|
||||
set(LIBSOUNDIO_SOURCES
|
||||
"${libsoundio_SOURCE_DIR}/src/soundio.c"
|
||||
"${libsoundio_SOURCE_DIR}/src/util.c"
|
||||
"${libsoundio_SOURCE_DIR}/src/os.c"
|
||||
"${libsoundio_SOURCE_DIR}/src/dummy.c"
|
||||
"${libsoundio_SOURCE_DIR}/src/channel_layout.c"
|
||||
"${libsoundio_SOURCE_DIR}/src/ring_buffer.c"
|
||||
)
|
||||
|
||||
set(CONFIGURE_OUT_FILE "${libsoundio_BINARY_DIR}/config.h")
|
||||
set(LIBSOUNDIO_HEADERS
|
||||
"${libsoundio_SOURCE_DIR}/soundio/soundio.h"
|
||||
"${libsoundio_SOURCE_DIR}/soundio/endian.h"
|
||||
)
|
||||
|
||||
if(SOUNDIO_HAVE_JACK)
|
||||
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
|
||||
"${libsoundio_SOURCE_DIR}/src/jack.c"
|
||||
)
|
||||
endif()
|
||||
if(SOUNDIO_HAVE_PULSEAUDIO)
|
||||
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
|
||||
"${libsoundio_SOURCE_DIR}/src/pulseaudio.c"
|
||||
)
|
||||
endif()
|
||||
if(SOUNDIO_HAVE_ALSA)
|
||||
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
|
||||
"${libsoundio_SOURCE_DIR}/src/alsa.c"
|
||||
)
|
||||
endif()
|
||||
if(SOUNDIO_HAVE_COREAUDIO)
|
||||
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
|
||||
"${libsoundio_SOURCE_DIR}/src/coreaudio.c"
|
||||
)
|
||||
endif()
|
||||
if(SOUNDIO_HAVE_WASAPI)
|
||||
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
|
||||
"${libsoundio_SOURCE_DIR}/src/wasapi.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
${libsoundio_SOURCE_DIR}
|
||||
${libsoundio_BINARY_DIR}
|
||||
"${libsoundio_SOURCE_DIR}/test"
|
||||
"${libsoundio_SOURCE_DIR}/src"
|
||||
)
|
||||
|
||||
set(LIBSOUNDIO_LIBS
|
||||
${JACK_LIBRARY}
|
||||
${PULSEAUDIO_LIBRARY}
|
||||
${ALSA_LIBRARIES}
|
||||
${COREAUDIO_LIBRARY}
|
||||
${COREFOUNDATION_LIBRARY}
|
||||
${AUDIOUNIT_LIBRARY}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Wall")
|
||||
set(LIB_CFLAGS "/TP /W4")
|
||||
set(EXAMPLE_CFLAGS "/W4")
|
||||
set(TEST_CFLAGS "${LIB_CFLAGS}")
|
||||
set(TEST_LDFLAGS " ")
|
||||
set(LIBM " ")
|
||||
else()
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Werror -pedantic")
|
||||
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 -Wno-missing-braces")
|
||||
set(EXAMPLE_CFLAGS "-std=c99 -Wall")
|
||||
set(TEST_CFLAGS "${LIB_CFLAGS} -fprofile-arcs -ftest-coverage")
|
||||
set(TEST_LDFLAGS "-fprofile-arcs -ftest-coverage")
|
||||
set(LIBM "m")
|
||||
endif()
|
||||
|
||||
configure_file(
|
||||
"${libsoundio_SOURCE_DIR}/src/config.h.in"
|
||||
${CONFIGURE_OUT_FILE}
|
||||
)
|
||||
set(DOXYGEN_CONF_FILE "${libsoundio_BINARY_DIR}/doxygen.conf")
|
||||
configure_file(
|
||||
"${libsoundio_SOURCE_DIR}/doc/doxygen.conf.in"
|
||||
${DOXYGEN_CONF_FILE}
|
||||
)
|
||||
|
||||
if(BUILD_DYNAMIC_LIBS)
|
||||
add_library(libsoundio_shared SHARED ${LIBSOUNDIO_SOURCES})
|
||||
set_target_properties(libsoundio_shared PROPERTIES
|
||||
OUTPUT_NAME soundio
|
||||
SOVERSION ${LIBSOUNDIO_VERSION_MAJOR}
|
||||
VERSION ${LIBSOUNDIO_VERSION}
|
||||
COMPILE_FLAGS ${LIB_CFLAGS}
|
||||
LINKER_LANGUAGE C
|
||||
)
|
||||
target_link_libraries(libsoundio_shared LINK_PUBLIC ${LIBSOUNDIO_LIBS})
|
||||
install(TARGETS libsoundio_shared DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
||||
|
||||
if(BUILD_STATIC_LIBS)
|
||||
add_library(libsoundio_static STATIC ${LIBSOUNDIO_SOURCES})
|
||||
set_target_properties(libsoundio_static PROPERTIES
|
||||
OUTPUT_NAME ${SOUNDIO_STATIC_LIBNAME}
|
||||
COMPILE_FLAGS ${LIB_CFLAGS}
|
||||
LINKER_LANGUAGE C
|
||||
)
|
||||
install(TARGETS libsoundio_static DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
||||
|
||||
install(FILES
|
||||
${LIBSOUNDIO_HEADERS}
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/soundio")
|
||||
|
||||
# Example Programs
|
||||
|
||||
if(BUILD_EXAMPLE_PROGRAMS)
|
||||
add_executable(sio_sine example/sio_sine.c)
|
||||
set_target_properties(sio_sine PROPERTIES
|
||||
LINKER_LANGUAGE C
|
||||
COMPILE_FLAGS ${EXAMPLE_CFLAGS})
|
||||
if(BUILD_DYNAMIC_LIBS)
|
||||
target_link_libraries(sio_sine libsoundio_shared ${LIBM})
|
||||
else()
|
||||
target_link_libraries(sio_sine libsoundio_static ${LIBSOUNDIO_LIBS} ${LIBM})
|
||||
endif()
|
||||
install(TARGETS sio_sine DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
add_executable(sio_list_devices example/sio_list_devices.c)
|
||||
set_target_properties(sio_list_devices PROPERTIES
|
||||
LINKER_LANGUAGE C
|
||||
COMPILE_FLAGS ${EXAMPLE_CFLAGS})
|
||||
if(BUILD_DYNAMIC_LIBS)
|
||||
target_link_libraries(sio_list_devices libsoundio_shared)
|
||||
else()
|
||||
target_link_libraries(sio_list_devices libsoundio_static ${LIBSOUNDIO_LIBS})
|
||||
endif()
|
||||
install(TARGETS sio_list_devices DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
add_executable(sio_microphone example/sio_microphone.c)
|
||||
set_target_properties(sio_microphone PROPERTIES
|
||||
LINKER_LANGUAGE C
|
||||
COMPILE_FLAGS ${EXAMPLE_CFLAGS})
|
||||
if(BUILD_DYNAMIC_LIBS)
|
||||
target_link_libraries(sio_microphone libsoundio_shared)
|
||||
else()
|
||||
target_link_libraries(sio_microphone libsoundio_static ${LIBSOUNDIO_LIBS})
|
||||
endif()
|
||||
install(TARGETS sio_microphone DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
add_executable(sio_record example/sio_record.c)
|
||||
set_target_properties(sio_record PROPERTIES
|
||||
LINKER_LANGUAGE C
|
||||
COMPILE_FLAGS ${EXAMPLE_CFLAGS})
|
||||
if(BUILD_DYNAMIC_LIBS)
|
||||
target_link_libraries(sio_record libsoundio_shared)
|
||||
else()
|
||||
target_link_libraries(sio_record libsoundio_static ${LIBSOUNDIO_LIBS})
|
||||
endif()
|
||||
install(TARGETS sio_record DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTS)
|
||||
add_executable(unit_tests "${libsoundio_SOURCE_DIR}/test/unit_tests.c" ${LIBSOUNDIO_SOURCES})
|
||||
target_link_libraries(unit_tests LINK_PUBLIC ${LIBSOUNDIO_LIBS})
|
||||
set_target_properties(unit_tests PROPERTIES
|
||||
LINKER_LANGUAGE C
|
||||
COMPILE_FLAGS ${TEST_CFLAGS}
|
||||
LINK_FLAGS ${TEST_LDFLAGS}
|
||||
)
|
||||
|
||||
add_executable(latency "${libsoundio_SOURCE_DIR}/test/latency.c" ${LIBSOUNDIO_SOURCES})
|
||||
target_link_libraries(latency LINK_PUBLIC ${LIBSOUNDIO_LIBS} ${LIBM})
|
||||
set_target_properties(latency PROPERTIES
|
||||
LINKER_LANGUAGE C
|
||||
COMPILE_FLAGS ${LIB_CFLAGS}
|
||||
)
|
||||
|
||||
add_executable(underflow test/underflow.c)
|
||||
set_target_properties(underflow PROPERTIES
|
||||
LINKER_LANGUAGE C
|
||||
COMPILE_FLAGS ${EXAMPLE_CFLAGS})
|
||||
if(BUILD_DYNAMIC_LIBS)
|
||||
target_link_libraries(underflow libsoundio_shared ${LIBM})
|
||||
else()
|
||||
target_link_libraries(underflow libsoundio_static ${LIBSOUNDIO_LIBS} ${LIBM})
|
||||
endif()
|
||||
|
||||
add_executable(backend_disconnect_recover test/backend_disconnect_recover.c)
|
||||
set_target_properties(backend_disconnect_recover PROPERTIES
|
||||
LINKER_LANGUAGE C
|
||||
COMPILE_FLAGS ${EXAMPLE_CFLAGS})
|
||||
if(BUILD_DYNAMIC_LIBS)
|
||||
target_link_libraries(backend_disconnect_recover libsoundio_shared)
|
||||
else()
|
||||
target_link_libraries(backend_disconnect_recover libsoundio_static ${LIBSOUNDIO_LIBS})
|
||||
endif()
|
||||
|
||||
add_executable(overflow test/overflow.c)
|
||||
set_target_properties(overflow PROPERTIES
|
||||
LINKER_LANGUAGE C
|
||||
COMPILE_FLAGS ${EXAMPLE_CFLAGS})
|
||||
if(BUILD_DYNAMIC_LIBS)
|
||||
target_link_libraries(overflow libsoundio_shared)
|
||||
else()
|
||||
target_link_libraries(overflow libsoundio_static ${LIBSOUNDIO_LIBS})
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
add_custom_target(coverage
|
||||
DEPENDS unit_tests
|
||||
WORKING_DIRECTORY ${libsoundio_BINARY_DIR}
|
||||
COMMAND lcov --directory . --zerocounters --rc lcov_branch_coverage=1
|
||||
COMMAND ./unit_tests
|
||||
COMMAND lcov --directory . --capture --output-file coverage.info --rc lcov_branch_coverage=1
|
||||
COMMAND lcov --remove coverage.info '/usr/*' --output-file coverage.info.cleaned --rc lcov_branch_coverage=1
|
||||
COMMAND genhtml -o coverage coverage.info.cleaned --rc lcov_branch_coverage=1
|
||||
COMMAND rm coverage.info coverage.info.cleaned
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
add_custom_target(doc
|
||||
WORKING_DIRECTORY ${libsoundio_BINARY_DIR}
|
||||
COMMAND doxygen ${DOXYGEN_CONF_FILE}
|
||||
)
|
||||
|
||||
|
||||
|
||||
message("\n"
|
||||
"Installation Summary\n"
|
||||
"--------------------\n"
|
||||
"* Install Directory : ${CMAKE_INSTALL_PREFIX}\n"
|
||||
"* Build Type : ${CMAKE_BUILD_TYPE}\n"
|
||||
"* Build static libs : ${BUILD_STATIC_LIBS}\n"
|
||||
"* Build examples : ${BUILD_EXAMPLE_PROGRAMS}\n"
|
||||
"* Build tests : ${BUILD_TESTS}\n"
|
||||
)
|
||||
|
||||
message(
|
||||
"System Dependencies\n"
|
||||
"-------------------\n"
|
||||
"* threads : ${STATUS_THREADS}\n"
|
||||
"* JACK (optional) : ${STATUS_JACK}\n"
|
||||
"* PulseAudio (optional) : ${STATUS_PULSEAUDIO}\n"
|
||||
"* ALSA (optional) : ${STATUS_ALSA}\n"
|
||||
"* CoreAudio (optional) : ${STATUS_COREAUDIO}\n"
|
||||
"* WASAPI (optional) : ${STATUS_WASAPI}\n"
|
||||
)
|
21
thirdparty/libsoundio/LICENSE
vendored
21
thirdparty/libsoundio/LICENSE
vendored
@ -1,21 +0,0 @@
|
||||
The MIT License (Expat)
|
||||
|
||||
Copyright (c) 2015 Andrew Kelley
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
266
thirdparty/libsoundio/README.md
vendored
266
thirdparty/libsoundio/README.md
vendored
@ -1,266 +0,0 @@
|
||||
# libsoundio
|
||||
|
||||
C library providing cross-platform audio input and output. The API is
|
||||
suitable for real-time software such as digital audio workstations as well
|
||||
as consumer software such as music players.
|
||||
|
||||
This library is an abstraction; however in the delicate balance between
|
||||
performance and power, and API convenience, the scale is tipped closer to
|
||||
the former. Features that only exist in some sound backends are exposed.
|
||||
|
||||
## Features and Limitations
|
||||
|
||||
* Supported operating systems:
|
||||
- Windows 7+
|
||||
- MacOS 10.10+
|
||||
- Linux 3.7+
|
||||
* Supported backends:
|
||||
- [JACK](http://jackaudio.org/)
|
||||
- [PulseAudio](http://www.freedesktop.org/wiki/Software/PulseAudio/)
|
||||
- [ALSA](http://www.alsa-project.org/)
|
||||
- [CoreAudio](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/CoreAudioOverview/Introduction/Introduction.html)
|
||||
- [WASAPI](https://msdn.microsoft.com/en-us/library/windows/desktop/dd371455%28v=vs.85%29.aspx)
|
||||
- Dummy (silence)
|
||||
* Exposes both raw devices and shared devices. Raw devices give you the best
|
||||
performance but prevent other applications from using them. Shared devices
|
||||
are default and usually provide sample rate conversion and format
|
||||
conversion.
|
||||
* Exposes both device id and friendly name. id you could save in a config file
|
||||
because it persists between devices becoming plugged and unplugged, while
|
||||
friendly name is suitable for exposing to users.
|
||||
* Supports optimal usage of each supported backend. The same API does the
|
||||
right thing whether the backend has a fixed buffer size, such as on JACK and
|
||||
CoreAudio, or whether it allows directly managing the buffer, such as on
|
||||
ALSA, PulseAudio, and WASAPI.
|
||||
* C library. Depends only on the respective backend API libraries and libc.
|
||||
Does *not* depend on libstdc++, and does *not* have exceptions, run-time type
|
||||
information, or [setjmp](http://latentcontent.net/2007/12/05/libpng-worst-api-ever/).
|
||||
* Errors are communicated via return codes, not logging to stdio.
|
||||
* Supports channel layouts (also known as channel maps), important for
|
||||
surround sound applications.
|
||||
* Ability to monitor devices and get an event when available devices change.
|
||||
* Ability to get an event when the backend is disconnected, for example when
|
||||
the JACK server or PulseAudio server shuts down.
|
||||
* Detects which input device is default and which output device is default.
|
||||
* Ability to connect to multiple backends at once. For example you could have
|
||||
an ALSA device open and a JACK device open at the same time.
|
||||
* Meticulously checks all return codes and memory allocations and uses
|
||||
meaningful error codes.
|
||||
* Exposes extra API that is only available on some backends. For example you
|
||||
can provide application name and stream names which is used by JACK and
|
||||
PulseAudio.
|
||||
|
||||
## Synopsis
|
||||
|
||||
Complete program to emit a sine wave over the default device using the best
|
||||
backend:
|
||||
|
||||
```c
|
||||
#include <soundio/soundio.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
static const float PI = 3.1415926535f;
|
||||
static float seconds_offset = 0.0f;
|
||||
static void write_callback(struct SoundIoOutStream *outstream,
|
||||
int frame_count_min, int frame_count_max)
|
||||
{
|
||||
const struct SoundIoChannelLayout *layout = &outstream->layout;
|
||||
float float_sample_rate = outstream->sample_rate;
|
||||
float seconds_per_frame = 1.0f / float_sample_rate;
|
||||
struct SoundIoChannelArea *areas;
|
||||
int frames_left = frame_count_max;
|
||||
int err;
|
||||
|
||||
while (frames_left > 0) {
|
||||
int frame_count = frames_left;
|
||||
|
||||
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count))) {
|
||||
fprintf(stderr, "%s\n", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!frame_count)
|
||||
break;
|
||||
|
||||
float pitch = 440.0f;
|
||||
float radians_per_second = pitch * 2.0f * PI;
|
||||
for (int frame = 0; frame < frame_count; frame += 1) {
|
||||
float sample = sinf((seconds_offset + frame * seconds_per_frame) * radians_per_second);
|
||||
for (int channel = 0; channel < layout->channel_count; channel += 1) {
|
||||
float *ptr = (float*)(areas[channel].ptr + areas[channel].step * frame);
|
||||
*ptr = sample;
|
||||
}
|
||||
}
|
||||
seconds_offset = fmodf(seconds_offset +
|
||||
seconds_per_frame * frame_count, 1.0f);
|
||||
|
||||
if ((err = soundio_outstream_end_write(outstream))) {
|
||||
fprintf(stderr, "%s\n", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
frames_left -= frame_count;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int err;
|
||||
struct SoundIo *soundio = soundio_create();
|
||||
if (!soundio) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((err = soundio_connect(soundio))) {
|
||||
fprintf(stderr, "error connecting: %s", soundio_strerror(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
soundio_flush_events(soundio);
|
||||
|
||||
int default_out_device_index = soundio_default_output_device_index(soundio);
|
||||
if (default_out_device_index < 0) {
|
||||
fprintf(stderr, "no output device found");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct SoundIoDevice *device = soundio_get_output_device(soundio, default_out_device_index);
|
||||
if (!device) {
|
||||
fprintf(stderr, "out of memory");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Output device: %s\n", device->name);
|
||||
|
||||
struct SoundIoOutStream *outstream = soundio_outstream_create(device);
|
||||
outstream->format = SoundIoFormatFloat32NE;
|
||||
outstream->write_callback = write_callback;
|
||||
|
||||
if ((err = soundio_outstream_open(outstream))) {
|
||||
fprintf(stderr, "unable to open device: %s", soundio_strerror(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (outstream->layout_error)
|
||||
fprintf(stderr, "unable to set channel layout: %s\n", soundio_strerror(outstream->layout_error));
|
||||
|
||||
if ((err = soundio_outstream_start(outstream))) {
|
||||
fprintf(stderr, "unable to start device: %s", soundio_strerror(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
soundio_wait_events(soundio);
|
||||
|
||||
soundio_outstream_destroy(outstream);
|
||||
soundio_device_unref(device);
|
||||
soundio_destroy(soundio);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Backend Priority
|
||||
|
||||
When you use `soundio_connect`, libsoundio tries these backends in order.
|
||||
If unable to connect to that backend, due to the backend not being installed,
|
||||
or the server not running, or the platform is wrong, the next backend is tried.
|
||||
|
||||
0. JACK
|
||||
0. PulseAudio
|
||||
0. ALSA (Linux)
|
||||
0. CoreAudio (OSX)
|
||||
0. WASAPI (Windows)
|
||||
0. Dummy
|
||||
|
||||
If you don't like this order, you can use `soundio_connect_backend` to
|
||||
explicitly choose a backend to connect to. You can use `soundio_backend_count`
|
||||
and `soundio_get_backend` to get the list of available backends.
|
||||
|
||||
[API Documentation](http://libsound.io/doc)
|
||||
|
||||
### Building
|
||||
|
||||
Install the dependencies:
|
||||
|
||||
* cmake
|
||||
* ALSA library (optional)
|
||||
* libjack2 (optional)
|
||||
* libpulseaudio (optional)
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
### Building for Windows
|
||||
|
||||
You can build libsoundio with [mxe](http://mxe.cc/). Follow the
|
||||
[requirements](http://mxe.cc/#requirements) section to install the
|
||||
packages necessary on your system. Then somewhere on your file system:
|
||||
|
||||
```
|
||||
git clone https://github.com/mxe/mxe
|
||||
cd mxe
|
||||
make MXE_TARGETS='x86_64-w64-mingw32.static i686-w64-mingw32.static' gcc
|
||||
```
|
||||
|
||||
Then in the libsoundio source directory (replace "/path/to/mxe" with the
|
||||
appropriate path):
|
||||
|
||||
```
|
||||
mkdir build-win32
|
||||
cd build-win32
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=/path/to/mxe/usr/i686-w64-mingw32.static/share/cmake/mxe-conf.cmake
|
||||
make
|
||||
```
|
||||
|
||||
```
|
||||
mkdir build-win64
|
||||
cd build-win64
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=/path/to/mxe/usr/x86_64-w64-mingw32.static/share/cmake/mxe-conf.cmake
|
||||
make
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
For each backend, do the following:
|
||||
|
||||
0. Run the unit tests: `./unit_tests`. To see test coverage, install lcov, run
|
||||
`make coverage`, and then view `coverage/index.html` in a browser.
|
||||
0. Run the example `./sio_list_devices` and make sure it does not crash, and
|
||||
the output looks good. If valgrind is available, use it.
|
||||
0. Run `./sio_list_devices --watch` and make sure it detects when you plug and
|
||||
unplug a USB microphone.
|
||||
0. Run `./sio_sine` and make sure you hear a sine wave. For backends with raw
|
||||
devices, run `./sio_sine --device id --raw` (where 'id' is a device id you
|
||||
got from `sio_list_devices` and make sure you hear a sine wave.
|
||||
- Use 'p' to test pausing, 'u' to test unpausing, 'q' to test cleanup.
|
||||
- 'c' for clear buffer. Clear buffer should not pause the stream and it
|
||||
should also not cause an underflow.
|
||||
- Use 'P' to test pausing from the callback, and then 'u' to unpause.
|
||||
0. Run `./underflow` and read the testing instructions that it prints.
|
||||
0. Run `./sio_microphone` and ensure that it is both recording and playing
|
||||
back correctly. If possible use the `--in-device` and `--out-device`
|
||||
parameters to test a USB microphone in raw mode.
|
||||
0. Run `./backend_disconnect_recover` and read the testing instructions that
|
||||
it prints.
|
||||
0. Run `./latency` and make sure the printed beeps line up with the beeps that
|
||||
you hear.
|
||||
|
||||
### Building the Documentation
|
||||
|
||||
Ensure that [doxygen](http://www.stack.nl/~dimitri/doxygen/) is installed,
|
||||
then:
|
||||
|
||||
```
|
||||
make doc
|
||||
```
|
||||
|
||||
Then look at `html/index.html` in a browser.
|
16
thirdparty/libsoundio/cmake/FindCoreAudio.cmake
vendored
16
thirdparty/libsoundio/cmake/FindCoreAudio.cmake
vendored
@ -1,16 +0,0 @@
|
||||
# Copyright (c) 2015 Andrew Kelley
|
||||
# This file is MIT licensed.
|
||||
# See http://opensource.org/licenses/MIT
|
||||
|
||||
# COREAUDIO_FOUND
|
||||
# COREAUDIO_INCLUDE_DIR
|
||||
# COREAUDIO_LIBRARY
|
||||
|
||||
find_path(COREAUDIO_INCLUDE_DIR NAMES CoreAudio/CoreAudio.h)
|
||||
|
||||
find_library(COREAUDIO_LIBRARY NAMES CoreAudio)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(COREAUDIO DEFAULT_MSG COREAUDIO_LIBRARY COREAUDIO_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(COREAUDIO_INCLUDE_DIR COREAUDIO_LIBRARY)
|
19
thirdparty/libsoundio/cmake/FindJACK.cmake
vendored
19
thirdparty/libsoundio/cmake/FindJACK.cmake
vendored
@ -1,19 +0,0 @@
|
||||
# Copyright (c) 2015 Andrew Kelley
|
||||
# This file is MIT licensed.
|
||||
# See http://opensource.org/licenses/MIT
|
||||
|
||||
# JACK_FOUND
|
||||
# JACK_INCLUDE_DIR
|
||||
# JACK_LIBRARY
|
||||
|
||||
find_path(JACK_INCLUDE_DIR NAMES jack/jack.h)
|
||||
|
||||
find_library(JACK_LIBRARY NAMES jack)
|
||||
|
||||
include(CheckLibraryExists)
|
||||
check_library_exists(jack "jack_set_port_rename_callback" "${JACK_LIBRARY}" HAVE_jack_set_port_rename_callback)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(JACK DEFAULT_MSG JACK_LIBRARY JACK_INCLUDE_DIR HAVE_jack_set_port_rename_callback)
|
||||
|
||||
mark_as_advanced(JACK_INCLUDE_DIR JACK_LIBRARY)
|
16
thirdparty/libsoundio/cmake/FindPulseAudio.cmake
vendored
16
thirdparty/libsoundio/cmake/FindPulseAudio.cmake
vendored
@ -1,16 +0,0 @@
|
||||
# Copyright (c) 2015 Andrew Kelley
|
||||
# This file is MIT licensed.
|
||||
# See http://opensource.org/licenses/MIT
|
||||
|
||||
# PULSEAUDIO_FOUND
|
||||
# PULSEAUDIO_INCLUDE_DIR
|
||||
# PULSEAUDIO_LIBRARY
|
||||
|
||||
find_path(PULSEAUDIO_INCLUDE_DIR NAMES pulse/pulseaudio.h)
|
||||
|
||||
find_library(PULSEAUDIO_LIBRARY NAMES pulse)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(PULSEAUDIO DEFAULT_MSG PULSEAUDIO_LIBRARY PULSEAUDIO_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(PULSEAUDIO_INCLUDE_DIR PULSEAUDIO_LIBRARY)
|
14
thirdparty/libsoundio/cmake/FindWASAPI.cmake
vendored
14
thirdparty/libsoundio/cmake/FindWASAPI.cmake
vendored
@ -1,14 +0,0 @@
|
||||
# Copyright (c) 2015 Andrew Kelley
|
||||
# This file is MIT licensed.
|
||||
# See http://opensource.org/licenses/MIT
|
||||
|
||||
# WASAPI_FOUND
|
||||
# AUDIOCLIENT_H
|
||||
|
||||
if(WIN32)
|
||||
include(CheckIncludeFile)
|
||||
check_include_file(audioclient.h AUDIOCLIENT_H)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(WASAPI DEFAULT_MSG AUDIOCLIENT_H)
|
16
thirdparty/libsoundio/doc/FindSoundIo.cmake
vendored
16
thirdparty/libsoundio/doc/FindSoundIo.cmake
vendored
@ -1,16 +0,0 @@
|
||||
# Copyright (c) 2015 Andrew Kelley
|
||||
# This file is MIT licensed.
|
||||
# See http://opensource.org/licenses/MIT
|
||||
|
||||
# SOUNDIO_FOUND
|
||||
# SOUNDIO_INCLUDE_DIR
|
||||
# SOUNDIO_LIBRARY
|
||||
|
||||
find_path(SOUNDIO_INCLUDE_DIR NAMES soundio/soundio.h)
|
||||
|
||||
find_library(SOUNDIO_LIBRARY NAMES soundio)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(SOUNDIO DEFAULT_MSG SOUNDIO_LIBRARY SOUNDIO_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(SOUNDIO_INCLUDE_DIR SOUNDIO_LIBRARY)
|
2036
thirdparty/libsoundio/doc/doxygen.conf.in
vendored
2036
thirdparty/libsoundio/doc/doxygen.conf.in
vendored
File diff suppressed because it is too large
Load Diff
2
thirdparty/libsoundio/doc/footer.html
vendored
2
thirdparty/libsoundio/doc/footer.html
vendored
@ -1,2 +0,0 @@
|
||||
</body>
|
||||
</html>
|
181
thirdparty/libsoundio/example/sio_list_devices.c
vendored
181
thirdparty/libsoundio/example/sio_list_devices.c
vendored
@ -1,181 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Andrew Kelley
|
||||
*
|
||||
* This file is part of libsoundio, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include <soundio/soundio.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// list or keep a watch on audio devices
|
||||
|
||||
static int usage(char *exe) {
|
||||
fprintf(stderr, "Usage: %s [options]\n"
|
||||
"Options:\n"
|
||||
" [--watch]\n"
|
||||
" [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi]\n"
|
||||
" [--short]\n", exe);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void print_channel_layout(const struct SoundIoChannelLayout *layout) {
|
||||
if (layout->name) {
|
||||
fprintf(stderr, "%s", layout->name);
|
||||
} else {
|
||||
fprintf(stderr, "%s", soundio_get_channel_name(layout->channels[0]));
|
||||
for (int i = 1; i < layout->channel_count; i += 1) {
|
||||
fprintf(stderr, ", %s", soundio_get_channel_name(layout->channels[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool short_output = false;
|
||||
|
||||
static void print_device(struct SoundIoDevice *device, bool is_default) {
|
||||
const char *default_str = is_default ? " (default)" : "";
|
||||
const char *raw_str = device->is_raw ? " (raw)" : "";
|
||||
fprintf(stderr, "%s%s%s\n", device->name, default_str, raw_str);
|
||||
if (short_output)
|
||||
return;
|
||||
fprintf(stderr, " id: %s\n", device->id);
|
||||
|
||||
if (device->probe_error) {
|
||||
fprintf(stderr, " probe error: %s\n", soundio_strerror(device->probe_error));
|
||||
} else {
|
||||
fprintf(stderr, " channel layouts:\n");
|
||||
for (int i = 0; i < device->layout_count; i += 1) {
|
||||
fprintf(stderr, " ");
|
||||
print_channel_layout(&device->layouts[i]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
if (device->current_layout.channel_count > 0) {
|
||||
fprintf(stderr, " current layout: ");
|
||||
print_channel_layout(&device->current_layout);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
fprintf(stderr, " sample rates:\n");
|
||||
for (int i = 0; i < device->sample_rate_count; i += 1) {
|
||||
struct SoundIoSampleRateRange *range = &device->sample_rates[i];
|
||||
fprintf(stderr, " %d - %d\n", range->min, range->max);
|
||||
|
||||
}
|
||||
if (device->sample_rate_current)
|
||||
fprintf(stderr, " current sample rate: %d\n", device->sample_rate_current);
|
||||
fprintf(stderr, " formats: ");
|
||||
for (int i = 0; i < device->format_count; i += 1) {
|
||||
const char *comma = (i == device->format_count - 1) ? "" : ", ";
|
||||
fprintf(stderr, "%s%s", soundio_format_string(device->formats[i]), comma);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
if (device->current_format != SoundIoFormatInvalid)
|
||||
fprintf(stderr, " current format: %s\n", soundio_format_string(device->current_format));
|
||||
|
||||
fprintf(stderr, " min software latency: %0.8f sec\n", device->software_latency_min);
|
||||
fprintf(stderr, " max software latency: %0.8f sec\n", device->software_latency_max);
|
||||
if (device->software_latency_current != 0.0)
|
||||
fprintf(stderr, " current software latency: %0.8f sec\n", device->software_latency_current);
|
||||
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
static int list_devices(struct SoundIo *soundio) {
|
||||
int output_count = soundio_output_device_count(soundio);
|
||||
int input_count = soundio_input_device_count(soundio);
|
||||
|
||||
int default_output = soundio_default_output_device_index(soundio);
|
||||
int default_input = soundio_default_input_device_index(soundio);
|
||||
|
||||
fprintf(stderr, "--------Input Devices--------\n\n");
|
||||
for (int i = 0; i < input_count; i += 1) {
|
||||
struct SoundIoDevice *device = soundio_get_input_device(soundio, i);
|
||||
print_device(device, default_input == i);
|
||||
soundio_device_unref(device);
|
||||
}
|
||||
fprintf(stderr, "\n--------Output Devices--------\n\n");
|
||||
for (int i = 0; i < output_count; i += 1) {
|
||||
struct SoundIoDevice *device = soundio_get_output_device(soundio, i);
|
||||
print_device(device, default_output == i);
|
||||
soundio_device_unref(device);
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n%d devices found\n", input_count + output_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void on_devices_change(struct SoundIo *soundio) {
|
||||
fprintf(stderr, "devices changed\n");
|
||||
list_devices(soundio);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char *exe = argv[0];
|
||||
bool watch = false;
|
||||
enum SoundIoBackend backend = SoundIoBackendNone;
|
||||
|
||||
for (int i = 1; i < argc; i += 1) {
|
||||
char *arg = argv[i];
|
||||
if (strcmp("--watch", arg) == 0) {
|
||||
watch = true;
|
||||
} else if (strcmp("--short", arg) == 0) {
|
||||
short_output = true;
|
||||
} else if (arg[0] == '-' && arg[1] == '-') {
|
||||
i += 1;
|
||||
if (i >= argc) {
|
||||
return usage(exe);
|
||||
} else if (strcmp(arg, "--backend") == 0) {
|
||||
if (strcmp("dummy", argv[i]) == 0) {
|
||||
backend = SoundIoBackendDummy;
|
||||
} else if (strcmp("alsa", argv[i]) == 0) {
|
||||
backend = SoundIoBackendAlsa;
|
||||
} else if (strcmp("pulseaudio", argv[i]) == 0) {
|
||||
backend = SoundIoBackendPulseAudio;
|
||||
} else if (strcmp("jack", argv[i]) == 0) {
|
||||
backend = SoundIoBackendJack;
|
||||
} else if (strcmp("coreaudio", argv[i]) == 0) {
|
||||
backend = SoundIoBackendCoreAudio;
|
||||
} else if (strcmp("wasapi", argv[i]) == 0) {
|
||||
backend = SoundIoBackendWasapi;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid backend: %s\n", argv[i]);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
return usage(exe);
|
||||
}
|
||||
} else {
|
||||
return usage(exe);
|
||||
}
|
||||
}
|
||||
|
||||
struct SoundIo *soundio = soundio_create();
|
||||
if (!soundio) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int err = (backend == SoundIoBackendNone) ?
|
||||
soundio_connect(soundio) : soundio_connect_backend(soundio, backend);
|
||||
|
||||
if (err) {
|
||||
fprintf(stderr, "%s\n", soundio_strerror(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
if (watch) {
|
||||
soundio->on_devices_change = on_devices_change;
|
||||
for (;;) {
|
||||
soundio_wait_events(soundio);
|
||||
}
|
||||
} else {
|
||||
soundio_flush_events(soundio);
|
||||
int err = list_devices(soundio);
|
||||
soundio_destroy(soundio);
|
||||
return err;
|
||||
}
|
||||
}
|
390
thirdparty/libsoundio/example/sio_microphone.c
vendored
390
thirdparty/libsoundio/example/sio_microphone.c
vendored
@ -1,390 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Andrew Kelley
|
||||
*
|
||||
* This file is part of libsoundio, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include <soundio/soundio.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
struct SoundIoRingBuffer *ring_buffer = NULL;
|
||||
|
||||
static enum SoundIoFormat prioritized_formats[] = {
|
||||
SoundIoFormatFloat32NE,
|
||||
SoundIoFormatFloat32FE,
|
||||
SoundIoFormatS32NE,
|
||||
SoundIoFormatS32FE,
|
||||
SoundIoFormatS24NE,
|
||||
SoundIoFormatS24FE,
|
||||
SoundIoFormatS16NE,
|
||||
SoundIoFormatS16FE,
|
||||
SoundIoFormatFloat64NE,
|
||||
SoundIoFormatFloat64FE,
|
||||
SoundIoFormatU32NE,
|
||||
SoundIoFormatU32FE,
|
||||
SoundIoFormatU24NE,
|
||||
SoundIoFormatU24FE,
|
||||
SoundIoFormatU16NE,
|
||||
SoundIoFormatU16FE,
|
||||
SoundIoFormatS8,
|
||||
SoundIoFormatU8,
|
||||
SoundIoFormatInvalid,
|
||||
};
|
||||
|
||||
static int prioritized_sample_rates[] = {
|
||||
48000,
|
||||
44100,
|
||||
96000,
|
||||
24000,
|
||||
0,
|
||||
};
|
||||
|
||||
|
||||
__attribute__ ((cold))
|
||||
__attribute__ ((noreturn))
|
||||
__attribute__ ((format (printf, 1, 2)))
|
||||
static void panic(const char *format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
abort();
|
||||
}
|
||||
|
||||
static int min_int(int a, int b) {
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
static void read_callback(struct SoundIoInStream *instream, int frame_count_min, int frame_count_max) {
|
||||
struct SoundIoChannelArea *areas;
|
||||
int err;
|
||||
char *write_ptr = soundio_ring_buffer_write_ptr(ring_buffer);
|
||||
int free_bytes = soundio_ring_buffer_free_count(ring_buffer);
|
||||
int free_count = free_bytes / instream->bytes_per_frame;
|
||||
|
||||
if (frame_count_min > free_count)
|
||||
panic("ring buffer overflow");
|
||||
|
||||
int write_frames = min_int(free_count, frame_count_max);
|
||||
int frames_left = write_frames;
|
||||
|
||||
for (;;) {
|
||||
int frame_count = frames_left;
|
||||
|
||||
if ((err = soundio_instream_begin_read(instream, &areas, &frame_count)))
|
||||
panic("begin read error: %s", soundio_strerror(err));
|
||||
|
||||
if (!frame_count)
|
||||
break;
|
||||
|
||||
if (!areas) {
|
||||
// Due to an overflow there is a hole. Fill the ring buffer with
|
||||
// silence for the size of the hole.
|
||||
memset(write_ptr, 0, frame_count * instream->bytes_per_frame);
|
||||
fprintf(stderr, "Dropped %d frames due to internal overflow\n", frame_count);
|
||||
} else {
|
||||
for (int frame = 0; frame < frame_count; frame += 1) {
|
||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||
memcpy(write_ptr, areas[ch].ptr, instream->bytes_per_sample);
|
||||
areas[ch].ptr += areas[ch].step;
|
||||
write_ptr += instream->bytes_per_sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((err = soundio_instream_end_read(instream)))
|
||||
panic("end read error: %s", soundio_strerror(err));
|
||||
|
||||
frames_left -= frame_count;
|
||||
if (frames_left <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
int advance_bytes = write_frames * instream->bytes_per_frame;
|
||||
soundio_ring_buffer_advance_write_ptr(ring_buffer, advance_bytes);
|
||||
}
|
||||
|
||||
static void write_callback(struct SoundIoOutStream *outstream, int frame_count_min, int frame_count_max) {
|
||||
struct SoundIoChannelArea *areas;
|
||||
int frames_left;
|
||||
int frame_count;
|
||||
int err;
|
||||
|
||||
char *read_ptr = soundio_ring_buffer_read_ptr(ring_buffer);
|
||||
int fill_bytes = soundio_ring_buffer_fill_count(ring_buffer);
|
||||
int fill_count = fill_bytes / outstream->bytes_per_frame;
|
||||
|
||||
if (frame_count_min > fill_count) {
|
||||
// Ring buffer does not have enough data, fill with zeroes.
|
||||
frames_left = frame_count_min;
|
||||
for (;;) {
|
||||
frame_count = frames_left;
|
||||
if (frame_count <= 0)
|
||||
return;
|
||||
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count)))
|
||||
panic("begin write error: %s", soundio_strerror(err));
|
||||
if (frame_count <= 0)
|
||||
return;
|
||||
for (int frame = 0; frame < frame_count; frame += 1) {
|
||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||
memset(areas[ch].ptr, 0, outstream->bytes_per_sample);
|
||||
areas[ch].ptr += areas[ch].step;
|
||||
}
|
||||
}
|
||||
if ((err = soundio_outstream_end_write(outstream)))
|
||||
panic("end write error: %s", soundio_strerror(err));
|
||||
frames_left -= frame_count;
|
||||
}
|
||||
}
|
||||
|
||||
int read_count = min_int(frame_count_max, fill_count);
|
||||
frames_left = read_count;
|
||||
|
||||
while (frames_left > 0) {
|
||||
int frame_count = frames_left;
|
||||
|
||||
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count)))
|
||||
panic("begin write error: %s", soundio_strerror(err));
|
||||
|
||||
if (frame_count <= 0)
|
||||
break;
|
||||
|
||||
for (int frame = 0; frame < frame_count; frame += 1) {
|
||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||
memcpy(areas[ch].ptr, read_ptr, outstream->bytes_per_sample);
|
||||
areas[ch].ptr += areas[ch].step;
|
||||
read_ptr += outstream->bytes_per_sample;
|
||||
}
|
||||
}
|
||||
|
||||
if ((err = soundio_outstream_end_write(outstream)))
|
||||
panic("end write error: %s", soundio_strerror(err));
|
||||
|
||||
frames_left -= frame_count;
|
||||
}
|
||||
|
||||
soundio_ring_buffer_advance_read_ptr(ring_buffer, read_count * outstream->bytes_per_frame);
|
||||
}
|
||||
|
||||
static void underflow_callback(struct SoundIoOutStream *outstream) {
|
||||
static int count = 0;
|
||||
fprintf(stderr, "underflow %d\n", ++count);
|
||||
}
|
||||
|
||||
static int usage(char *exe) {
|
||||
fprintf(stderr, "Usage: %s [options]\n"
|
||||
"Options:\n"
|
||||
" [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi]\n"
|
||||
" [--in-device id]\n"
|
||||
" [--in-raw]\n"
|
||||
" [--out-device id]\n"
|
||||
" [--out-raw]\n"
|
||||
" [--latency seconds]\n"
|
||||
, exe);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char *exe = argv[0];
|
||||
enum SoundIoBackend backend = SoundIoBackendNone;
|
||||
char *in_device_id = NULL;
|
||||
char *out_device_id = NULL;
|
||||
bool in_raw = false;
|
||||
bool out_raw = false;
|
||||
|
||||
double microphone_latency = 0.2; // seconds
|
||||
|
||||
for (int i = 1; i < argc; i += 1) {
|
||||
char *arg = argv[i];
|
||||
if (arg[0] == '-' && arg[1] == '-') {
|
||||
if (strcmp(arg, "--in-raw") == 0) {
|
||||
in_raw = true;
|
||||
} else if (strcmp(arg, "--out-raw") == 0) {
|
||||
out_raw = true;
|
||||
} else if (++i >= argc) {
|
||||
return usage(exe);
|
||||
} else if (strcmp(arg, "--backend") == 0) {
|
||||
if (strcmp("dummy", argv[i]) == 0) {
|
||||
backend = SoundIoBackendDummy;
|
||||
} else if (strcmp("alsa", argv[i]) == 0) {
|
||||
backend = SoundIoBackendAlsa;
|
||||
} else if (strcmp("pulseaudio", argv[i]) == 0) {
|
||||
backend = SoundIoBackendPulseAudio;
|
||||
} else if (strcmp("jack", argv[i]) == 0) {
|
||||
backend = SoundIoBackendJack;
|
||||
} else if (strcmp("coreaudio", argv[i]) == 0) {
|
||||
backend = SoundIoBackendCoreAudio;
|
||||
} else if (strcmp("wasapi", argv[i]) == 0) {
|
||||
backend = SoundIoBackendWasapi;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid backend: %s\n", argv[i]);
|
||||
return 1;
|
||||
}
|
||||
} else if (strcmp(arg, "--in-device") == 0) {
|
||||
in_device_id = argv[i];
|
||||
} else if (strcmp(arg, "--out-device") == 0) {
|
||||
out_device_id = argv[i];
|
||||
} else if (strcmp(arg, "--latency") == 0) {
|
||||
microphone_latency = atof(argv[i]);
|
||||
} else {
|
||||
return usage(exe);
|
||||
}
|
||||
} else {
|
||||
return usage(exe);
|
||||
}
|
||||
}
|
||||
struct SoundIo *soundio = soundio_create();
|
||||
if (!soundio)
|
||||
panic("out of memory");
|
||||
|
||||
int err = (backend == SoundIoBackendNone) ?
|
||||
soundio_connect(soundio) : soundio_connect_backend(soundio, backend);
|
||||
if (err)
|
||||
panic("error connecting: %s", soundio_strerror(err));
|
||||
|
||||
soundio_flush_events(soundio);
|
||||
|
||||
int default_out_device_index = soundio_default_output_device_index(soundio);
|
||||
if (default_out_device_index < 0)
|
||||
panic("no output device found");
|
||||
|
||||
int default_in_device_index = soundio_default_input_device_index(soundio);
|
||||
if (default_in_device_index < 0)
|
||||
panic("no input device found");
|
||||
|
||||
int in_device_index = default_in_device_index;
|
||||
if (in_device_id) {
|
||||
bool found = false;
|
||||
for (int i = 0; i < soundio_input_device_count(soundio); i += 1) {
|
||||
struct SoundIoDevice *device = soundio_get_input_device(soundio, i);
|
||||
if (device->is_raw == in_raw && strcmp(device->id, in_device_id) == 0) {
|
||||
in_device_index = i;
|
||||
found = true;
|
||||
soundio_device_unref(device);
|
||||
break;
|
||||
}
|
||||
soundio_device_unref(device);
|
||||
}
|
||||
if (!found)
|
||||
panic("invalid input device id: %s", in_device_id);
|
||||
}
|
||||
|
||||
int out_device_index = default_out_device_index;
|
||||
if (out_device_id) {
|
||||
bool found = false;
|
||||
for (int i = 0; i < soundio_output_device_count(soundio); i += 1) {
|
||||
struct SoundIoDevice *device = soundio_get_output_device(soundio, i);
|
||||
if (device->is_raw == out_raw && strcmp(device->id, out_device_id) == 0) {
|
||||
out_device_index = i;
|
||||
found = true;
|
||||
soundio_device_unref(device);
|
||||
break;
|
||||
}
|
||||
soundio_device_unref(device);
|
||||
}
|
||||
if (!found)
|
||||
panic("invalid output device id: %s", out_device_id);
|
||||
}
|
||||
|
||||
struct SoundIoDevice *out_device = soundio_get_output_device(soundio, out_device_index);
|
||||
if (!out_device)
|
||||
panic("could not get output device: out of memory");
|
||||
|
||||
struct SoundIoDevice *in_device = soundio_get_input_device(soundio, in_device_index);
|
||||
if (!in_device)
|
||||
panic("could not get input device: out of memory");
|
||||
|
||||
fprintf(stderr, "Input device: %s\n", in_device->name);
|
||||
fprintf(stderr, "Output device: %s\n", out_device->name);
|
||||
|
||||
soundio_device_sort_channel_layouts(out_device);
|
||||
const struct SoundIoChannelLayout *layout = soundio_best_matching_channel_layout(
|
||||
out_device->layouts, out_device->layout_count,
|
||||
in_device->layouts, in_device->layout_count);
|
||||
|
||||
if (!layout)
|
||||
panic("channel layouts not compatible");
|
||||
|
||||
int *sample_rate;
|
||||
for (sample_rate = prioritized_sample_rates; *sample_rate; sample_rate += 1) {
|
||||
if (soundio_device_supports_sample_rate(in_device, *sample_rate) &&
|
||||
soundio_device_supports_sample_rate(out_device, *sample_rate))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!*sample_rate)
|
||||
panic("incompatible sample rates");
|
||||
|
||||
enum SoundIoFormat *fmt;
|
||||
for (fmt = prioritized_formats; *fmt != SoundIoFormatInvalid; fmt += 1) {
|
||||
if (soundio_device_supports_format(in_device, *fmt) &&
|
||||
soundio_device_supports_format(out_device, *fmt))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*fmt == SoundIoFormatInvalid)
|
||||
panic("incompatible sample formats");
|
||||
|
||||
struct SoundIoInStream *instream = soundio_instream_create(in_device);
|
||||
if (!instream)
|
||||
panic("out of memory");
|
||||
instream->format = *fmt;
|
||||
instream->sample_rate = *sample_rate;
|
||||
instream->layout = *layout;
|
||||
instream->software_latency = microphone_latency;
|
||||
instream->read_callback = read_callback;
|
||||
|
||||
if ((err = soundio_instream_open(instream))) {
|
||||
fprintf(stderr, "unable to open input stream: %s", soundio_strerror(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct SoundIoOutStream *outstream = soundio_outstream_create(out_device);
|
||||
if (!outstream)
|
||||
panic("out of memory");
|
||||
outstream->format = *fmt;
|
||||
outstream->sample_rate = *sample_rate;
|
||||
outstream->layout = *layout;
|
||||
outstream->software_latency = microphone_latency;
|
||||
outstream->write_callback = write_callback;
|
||||
outstream->underflow_callback = underflow_callback;
|
||||
|
||||
if ((err = soundio_outstream_open(outstream))) {
|
||||
fprintf(stderr, "unable to open output stream: %s", soundio_strerror(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int capacity = microphone_latency * 2 * instream->sample_rate * instream->bytes_per_frame;
|
||||
ring_buffer = soundio_ring_buffer_create(soundio, capacity);
|
||||
if (!ring_buffer)
|
||||
panic("unable to create ring buffer: out of memory");
|
||||
char *buf = soundio_ring_buffer_write_ptr(ring_buffer);
|
||||
int fill_count = microphone_latency * outstream->sample_rate * outstream->bytes_per_frame;
|
||||
memset(buf, 0, fill_count);
|
||||
soundio_ring_buffer_advance_write_ptr(ring_buffer, fill_count);
|
||||
|
||||
if ((err = soundio_instream_start(instream)))
|
||||
panic("unable to start input device: %s", soundio_strerror(err));
|
||||
|
||||
if ((err = soundio_outstream_start(outstream)))
|
||||
panic("unable to start output device: %s", soundio_strerror(err));
|
||||
|
||||
for (;;)
|
||||
soundio_wait_events(soundio);
|
||||
|
||||
soundio_outstream_destroy(outstream);
|
||||
soundio_instream_destroy(instream);
|
||||
soundio_device_unref(in_device);
|
||||
soundio_device_unref(out_device);
|
||||
soundio_destroy(soundio);
|
||||
return 0;
|
||||
}
|
300
thirdparty/libsoundio/example/sio_record.c
vendored
300
thirdparty/libsoundio/example/sio_record.c
vendored
@ -1,300 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Andrew Kelley
|
||||
*
|
||||
* This file is part of libsoundio, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include <soundio/soundio.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct RecordContext {
|
||||
struct SoundIoRingBuffer *ring_buffer;
|
||||
};
|
||||
|
||||
static enum SoundIoFormat prioritized_formats[] = {
|
||||
SoundIoFormatFloat32NE,
|
||||
SoundIoFormatFloat32FE,
|
||||
SoundIoFormatS32NE,
|
||||
SoundIoFormatS32FE,
|
||||
SoundIoFormatS24NE,
|
||||
SoundIoFormatS24FE,
|
||||
SoundIoFormatS16NE,
|
||||
SoundIoFormatS16FE,
|
||||
SoundIoFormatFloat64NE,
|
||||
SoundIoFormatFloat64FE,
|
||||
SoundIoFormatU32NE,
|
||||
SoundIoFormatU32FE,
|
||||
SoundIoFormatU24NE,
|
||||
SoundIoFormatU24FE,
|
||||
SoundIoFormatU16NE,
|
||||
SoundIoFormatU16FE,
|
||||
SoundIoFormatS8,
|
||||
SoundIoFormatU8,
|
||||
SoundIoFormatInvalid,
|
||||
};
|
||||
|
||||
static int prioritized_sample_rates[] = {
|
||||
48000,
|
||||
44100,
|
||||
96000,
|
||||
24000,
|
||||
0,
|
||||
};
|
||||
|
||||
static int min_int(int a, int b) {
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
static void read_callback(struct SoundIoInStream *instream, int frame_count_min, int frame_count_max) {
|
||||
struct RecordContext *rc = instream->userdata;
|
||||
struct SoundIoChannelArea *areas;
|
||||
int err;
|
||||
|
||||
char *write_ptr = soundio_ring_buffer_write_ptr(rc->ring_buffer);
|
||||
int free_bytes = soundio_ring_buffer_free_count(rc->ring_buffer);
|
||||
int free_count = free_bytes / instream->bytes_per_frame;
|
||||
|
||||
if (free_count < frame_count_min) {
|
||||
fprintf(stderr, "ring buffer overflow\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int write_frames = min_int(free_count, frame_count_max);
|
||||
int frames_left = write_frames;
|
||||
|
||||
for (;;) {
|
||||
int frame_count = frames_left;
|
||||
|
||||
if ((err = soundio_instream_begin_read(instream, &areas, &frame_count))) {
|
||||
fprintf(stderr, "begin read error: %s", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!frame_count)
|
||||
break;
|
||||
|
||||
if (!areas) {
|
||||
// Due to an overflow there is a hole. Fill the ring buffer with
|
||||
// silence for the size of the hole.
|
||||
memset(write_ptr, 0, frame_count * instream->bytes_per_frame);
|
||||
} else {
|
||||
for (int frame = 0; frame < frame_count; frame += 1) {
|
||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||
memcpy(write_ptr, areas[ch].ptr, instream->bytes_per_sample);
|
||||
areas[ch].ptr += areas[ch].step;
|
||||
write_ptr += instream->bytes_per_sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((err = soundio_instream_end_read(instream))) {
|
||||
fprintf(stderr, "end read error: %s", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
frames_left -= frame_count;
|
||||
if (frames_left <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
int advance_bytes = write_frames * instream->bytes_per_frame;
|
||||
soundio_ring_buffer_advance_write_ptr(rc->ring_buffer, advance_bytes);
|
||||
}
|
||||
|
||||
static void overflow_callback(struct SoundIoInStream *instream) {
|
||||
static int count = 0;
|
||||
fprintf(stderr, "overflow %d\n", ++count);
|
||||
}
|
||||
|
||||
static int usage(char *exe) {
|
||||
fprintf(stderr, "Usage: %s [options] outfile\n"
|
||||
"Options:\n"
|
||||
" [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi]\n"
|
||||
" [--device id]\n"
|
||||
" [--raw]\n"
|
||||
, exe);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char *exe = argv[0];
|
||||
enum SoundIoBackend backend = SoundIoBackendNone;
|
||||
char *device_id = NULL;
|
||||
bool is_raw = false;
|
||||
char *outfile = NULL;
|
||||
for (int i = 1; i < argc; i += 1) {
|
||||
char *arg = argv[i];
|
||||
if (arg[0] == '-' && arg[1] == '-') {
|
||||
if (strcmp(arg, "--raw") == 0) {
|
||||
is_raw = true;
|
||||
} else if (++i >= argc) {
|
||||
return usage(exe);
|
||||
} else if (strcmp(arg, "--backend") == 0) {
|
||||
if (strcmp("dummy", argv[i]) == 0) {
|
||||
backend = SoundIoBackendDummy;
|
||||
} else if (strcmp("alsa", argv[i]) == 0) {
|
||||
backend = SoundIoBackendAlsa;
|
||||
} else if (strcmp("pulseaudio", argv[i]) == 0) {
|
||||
backend = SoundIoBackendPulseAudio;
|
||||
} else if (strcmp("jack", argv[i]) == 0) {
|
||||
backend = SoundIoBackendJack;
|
||||
} else if (strcmp("coreaudio", argv[i]) == 0) {
|
||||
backend = SoundIoBackendCoreAudio;
|
||||
} else if (strcmp("wasapi", argv[i]) == 0) {
|
||||
backend = SoundIoBackendWasapi;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid backend: %s\n", argv[i]);
|
||||
return 1;
|
||||
}
|
||||
} else if (strcmp(arg, "--device") == 0) {
|
||||
device_id = argv[i];
|
||||
} else {
|
||||
return usage(exe);
|
||||
}
|
||||
} else if (!outfile) {
|
||||
outfile = argv[i];
|
||||
} else {
|
||||
return usage(exe);
|
||||
}
|
||||
}
|
||||
|
||||
if (!outfile)
|
||||
return usage(exe);
|
||||
|
||||
struct RecordContext rc;
|
||||
|
||||
struct SoundIo *soundio = soundio_create();
|
||||
if (!soundio) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int err = (backend == SoundIoBackendNone) ?
|
||||
soundio_connect(soundio) : soundio_connect_backend(soundio, backend);
|
||||
if (err) {
|
||||
fprintf(stderr, "error connecting: %s", soundio_strerror(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
soundio_flush_events(soundio);
|
||||
|
||||
struct SoundIoDevice *selected_device = NULL;
|
||||
|
||||
if (device_id) {
|
||||
for (int i = 0; i < soundio_input_device_count(soundio); i += 1) {
|
||||
struct SoundIoDevice *device = soundio_get_input_device(soundio, i);
|
||||
if (device->is_raw == is_raw && strcmp(device->id, device_id) == 0) {
|
||||
selected_device = device;
|
||||
break;
|
||||
}
|
||||
soundio_device_unref(device);
|
||||
}
|
||||
if (!selected_device) {
|
||||
fprintf(stderr, "Invalid device id: %s\n", device_id);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
int device_index = soundio_default_input_device_index(soundio);
|
||||
selected_device = soundio_get_input_device(soundio, device_index);
|
||||
if (!selected_device) {
|
||||
fprintf(stderr, "No input devices available.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "Device: %s\n", selected_device->name);
|
||||
|
||||
if (selected_device->probe_error) {
|
||||
fprintf(stderr, "Unable to probe device: %s\n", soundio_strerror(selected_device->probe_error));
|
||||
return 1;
|
||||
}
|
||||
|
||||
soundio_device_sort_channel_layouts(selected_device);
|
||||
|
||||
int sample_rate = 0;
|
||||
int *sample_rate_ptr;
|
||||
for (sample_rate_ptr = prioritized_sample_rates; *sample_rate_ptr; sample_rate_ptr += 1) {
|
||||
if (soundio_device_supports_sample_rate(selected_device, *sample_rate_ptr)) {
|
||||
sample_rate = *sample_rate_ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!sample_rate)
|
||||
sample_rate = selected_device->sample_rates[0].max;
|
||||
|
||||
enum SoundIoFormat fmt = SoundIoFormatInvalid;
|
||||
enum SoundIoFormat *fmt_ptr;
|
||||
for (fmt_ptr = prioritized_formats; *fmt_ptr != SoundIoFormatInvalid; fmt_ptr += 1) {
|
||||
if (soundio_device_supports_format(selected_device, *fmt_ptr)) {
|
||||
fmt = *fmt_ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fmt == SoundIoFormatInvalid)
|
||||
fmt = selected_device->formats[0];
|
||||
|
||||
FILE *out_f = fopen(outfile, "wb");
|
||||
if (!out_f) {
|
||||
fprintf(stderr, "unable to open %s: %s\n", outfile, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
struct SoundIoInStream *instream = soundio_instream_create(selected_device);
|
||||
if (!instream) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
return 1;
|
||||
}
|
||||
instream->format = fmt;
|
||||
instream->sample_rate = sample_rate;
|
||||
instream->read_callback = read_callback;
|
||||
instream->overflow_callback = overflow_callback;
|
||||
instream->userdata = &rc;
|
||||
|
||||
if ((err = soundio_instream_open(instream))) {
|
||||
fprintf(stderr, "unable to open input stream: %s", soundio_strerror(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s %dHz %s interleaved\n",
|
||||
instream->layout.name, sample_rate, soundio_format_string(fmt));
|
||||
|
||||
const int ring_buffer_duration_seconds = 30;
|
||||
int capacity = ring_buffer_duration_seconds * instream->sample_rate * instream->bytes_per_frame;
|
||||
rc.ring_buffer = soundio_ring_buffer_create(soundio, capacity);
|
||||
if (!rc.ring_buffer) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((err = soundio_instream_start(instream))) {
|
||||
fprintf(stderr, "unable to start input device: %s", soundio_strerror(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Note: in this example, if you send SIGINT (by pressing Ctrl+C for example)
|
||||
// you will lose up to 1 second of recorded audio data. In non-example code,
|
||||
// consider a better shutdown strategy.
|
||||
for (;;) {
|
||||
soundio_flush_events(soundio);
|
||||
sleep(1);
|
||||
int fill_bytes = soundio_ring_buffer_fill_count(rc.ring_buffer);
|
||||
char *read_buf = soundio_ring_buffer_read_ptr(rc.ring_buffer);
|
||||
size_t amt = fwrite(read_buf, 1, fill_bytes, out_f);
|
||||
if ((int)amt != fill_bytes) {
|
||||
fprintf(stderr, "write error: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
soundio_ring_buffer_advance_read_ptr(rc.ring_buffer, fill_bytes);
|
||||
}
|
||||
|
||||
soundio_instream_destroy(instream);
|
||||
soundio_device_unref(selected_device);
|
||||
soundio_destroy(soundio);
|
||||
return 0;
|
||||
}
|
289
thirdparty/libsoundio/example/sio_sine.c
vendored
289
thirdparty/libsoundio/example/sio_sine.c
vendored
@ -1,289 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Andrew Kelley
|
||||
*
|
||||
* This file is part of libsoundio, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include <soundio/soundio.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
|
||||
static int usage(char *exe) {
|
||||
fprintf(stderr, "Usage: %s [options]\n"
|
||||
"Options:\n"
|
||||
" [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi]\n"
|
||||
" [--device id]\n"
|
||||
" [--raw]\n"
|
||||
" [--name stream_name]\n"
|
||||
" [--latency seconds]\n"
|
||||
" [--sample-rate hz]\n"
|
||||
, exe);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void write_sample_s16ne(char *ptr, double sample) {
|
||||
int16_t *buf = (int16_t *)ptr;
|
||||
double range = (double)INT16_MAX - (double)INT16_MIN;
|
||||
double val = sample * range / 2.0;
|
||||
*buf = val;
|
||||
}
|
||||
|
||||
static void write_sample_s32ne(char *ptr, double sample) {
|
||||
int32_t *buf = (int32_t *)ptr;
|
||||
double range = (double)INT32_MAX - (double)INT32_MIN;
|
||||
double val = sample * range / 2.0;
|
||||
*buf = val;
|
||||
}
|
||||
|
||||
static void write_sample_float32ne(char *ptr, double sample) {
|
||||
float *buf = (float *)ptr;
|
||||
*buf = sample;
|
||||
}
|
||||
|
||||
static void write_sample_float64ne(char *ptr, double sample) {
|
||||
double *buf = (double *)ptr;
|
||||
*buf = sample;
|
||||
}
|
||||
|
||||
static void (*write_sample)(char *ptr, double sample);
|
||||
static const double PI = 3.14159265358979323846264338328;
|
||||
static double seconds_offset = 0.0;
|
||||
static volatile bool want_pause = false;
|
||||
static void write_callback(struct SoundIoOutStream *outstream, int frame_count_min, int frame_count_max) {
|
||||
double float_sample_rate = outstream->sample_rate;
|
||||
double seconds_per_frame = 1.0 / float_sample_rate;
|
||||
struct SoundIoChannelArea *areas;
|
||||
int err;
|
||||
|
||||
int frames_left = frame_count_max;
|
||||
|
||||
for (;;) {
|
||||
int frame_count = frames_left;
|
||||
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count))) {
|
||||
fprintf(stderr, "unrecoverable stream error: %s\n", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!frame_count)
|
||||
break;
|
||||
|
||||
const struct SoundIoChannelLayout *layout = &outstream->layout;
|
||||
|
||||
double pitch = 440.0;
|
||||
double radians_per_second = pitch * 2.0 * PI;
|
||||
for (int frame = 0; frame < frame_count; frame += 1) {
|
||||
double sample = sin((seconds_offset + frame * seconds_per_frame) * radians_per_second);
|
||||
for (int channel = 0; channel < layout->channel_count; channel += 1) {
|
||||
write_sample(areas[channel].ptr, sample);
|
||||
areas[channel].ptr += areas[channel].step;
|
||||
}
|
||||
}
|
||||
seconds_offset = fmod(seconds_offset + seconds_per_frame * frame_count, 1.0);
|
||||
|
||||
if ((err = soundio_outstream_end_write(outstream))) {
|
||||
if (err == SoundIoErrorUnderflow)
|
||||
return;
|
||||
fprintf(stderr, "unrecoverable stream error: %s\n", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
frames_left -= frame_count;
|
||||
if (frames_left <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
soundio_outstream_pause(outstream, want_pause);
|
||||
}
|
||||
|
||||
static void underflow_callback(struct SoundIoOutStream *outstream) {
|
||||
static int count = 0;
|
||||
fprintf(stderr, "underflow %d\n", count++);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char *exe = argv[0];
|
||||
enum SoundIoBackend backend = SoundIoBackendNone;
|
||||
char *device_id = NULL;
|
||||
bool raw = false;
|
||||
char *stream_name = NULL;
|
||||
double latency = 0.0;
|
||||
int sample_rate = 0;
|
||||
for (int i = 1; i < argc; i += 1) {
|
||||
char *arg = argv[i];
|
||||
if (arg[0] == '-' && arg[1] == '-') {
|
||||
if (strcmp(arg, "--raw") == 0) {
|
||||
raw = true;
|
||||
} else {
|
||||
i += 1;
|
||||
if (i >= argc) {
|
||||
return usage(exe);
|
||||
} else if (strcmp(arg, "--backend") == 0) {
|
||||
if (strcmp(argv[i], "dummy") == 0) {
|
||||
backend = SoundIoBackendDummy;
|
||||
} else if (strcmp(argv[i], "alsa") == 0) {
|
||||
backend = SoundIoBackendAlsa;
|
||||
} else if (strcmp(argv[i], "pulseaudio") == 0) {
|
||||
backend = SoundIoBackendPulseAudio;
|
||||
} else if (strcmp(argv[i], "jack") == 0) {
|
||||
backend = SoundIoBackendJack;
|
||||
} else if (strcmp(argv[i], "coreaudio") == 0) {
|
||||
backend = SoundIoBackendCoreAudio;
|
||||
} else if (strcmp(argv[i], "wasapi") == 0) {
|
||||
backend = SoundIoBackendWasapi;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid backend: %s\n", argv[i]);
|
||||
return 1;
|
||||
}
|
||||
} else if (strcmp(arg, "--device") == 0) {
|
||||
device_id = argv[i];
|
||||
} else if (strcmp(arg, "--name") == 0) {
|
||||
stream_name = argv[i];
|
||||
} else if (strcmp(arg, "--latency") == 0) {
|
||||
latency = atof(argv[i]);
|
||||
} else if (strcmp(arg, "--sample-rate") == 0) {
|
||||
sample_rate = atoi(argv[i]);
|
||||
} else {
|
||||
return usage(exe);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return usage(exe);
|
||||
}
|
||||
}
|
||||
|
||||
struct SoundIo *soundio = soundio_create();
|
||||
if (!soundio) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int err = (backend == SoundIoBackendNone) ?
|
||||
soundio_connect(soundio) : soundio_connect_backend(soundio, backend);
|
||||
|
||||
if (err) {
|
||||
fprintf(stderr, "Unable to connect to backend: %s\n", soundio_strerror(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Backend: %s\n", soundio_backend_name(soundio->current_backend));
|
||||
|
||||
soundio_flush_events(soundio);
|
||||
|
||||
int selected_device_index = -1;
|
||||
if (device_id) {
|
||||
int device_count = soundio_output_device_count(soundio);
|
||||
for (int i = 0; i < device_count; i += 1) {
|
||||
struct SoundIoDevice *device = soundio_get_output_device(soundio, i);
|
||||
bool select_this_one = strcmp(device->id, device_id) == 0 && device->is_raw == raw;
|
||||
soundio_device_unref(device);
|
||||
if (select_this_one) {
|
||||
selected_device_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
selected_device_index = soundio_default_output_device_index(soundio);
|
||||
}
|
||||
|
||||
if (selected_device_index < 0) {
|
||||
fprintf(stderr, "Output device not found\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct SoundIoDevice *device = soundio_get_output_device(soundio, selected_device_index);
|
||||
if (!device) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Output device: %s\n", device->name);
|
||||
|
||||
if (device->probe_error) {
|
||||
fprintf(stderr, "Cannot probe device: %s\n", soundio_strerror(device->probe_error));
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct SoundIoOutStream *outstream = soundio_outstream_create(device);
|
||||
if (!outstream) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
outstream->write_callback = write_callback;
|
||||
outstream->underflow_callback = underflow_callback;
|
||||
outstream->name = stream_name;
|
||||
outstream->software_latency = latency;
|
||||
outstream->sample_rate = sample_rate;
|
||||
|
||||
if (soundio_device_supports_format(device, SoundIoFormatFloat32NE)) {
|
||||
outstream->format = SoundIoFormatFloat32NE;
|
||||
write_sample = write_sample_float32ne;
|
||||
} else if (soundio_device_supports_format(device, SoundIoFormatFloat64NE)) {
|
||||
outstream->format = SoundIoFormatFloat64NE;
|
||||
write_sample = write_sample_float64ne;
|
||||
} else if (soundio_device_supports_format(device, SoundIoFormatS32NE)) {
|
||||
outstream->format = SoundIoFormatS32NE;
|
||||
write_sample = write_sample_s32ne;
|
||||
} else if (soundio_device_supports_format(device, SoundIoFormatS16NE)) {
|
||||
outstream->format = SoundIoFormatS16NE;
|
||||
write_sample = write_sample_s16ne;
|
||||
} else {
|
||||
fprintf(stderr, "No suitable device format available.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((err = soundio_outstream_open(outstream))) {
|
||||
fprintf(stderr, "unable to open device: %s", soundio_strerror(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Software latency: %f\n", outstream->software_latency);
|
||||
fprintf(stderr,
|
||||
"'p\\n' - pause\n"
|
||||
"'u\\n' - unpause\n"
|
||||
"'P\\n' - pause from within callback\n"
|
||||
"'c\\n' - clear buffer\n"
|
||||
"'q\\n' - quit\n");
|
||||
|
||||
if (outstream->layout_error)
|
||||
fprintf(stderr, "unable to set channel layout: %s\n", soundio_strerror(outstream->layout_error));
|
||||
|
||||
if ((err = soundio_outstream_start(outstream))) {
|
||||
fprintf(stderr, "unable to start device: %s\n", soundio_strerror(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
soundio_flush_events(soundio);
|
||||
int c = getc(stdin);
|
||||
if (c == 'p') {
|
||||
fprintf(stderr, "pausing result: %s\n",
|
||||
soundio_strerror(soundio_outstream_pause(outstream, true)));
|
||||
} else if (c == 'P') {
|
||||
want_pause = true;
|
||||
} else if (c == 'u') {
|
||||
want_pause = false;
|
||||
fprintf(stderr, "unpausing result: %s\n",
|
||||
soundio_strerror(soundio_outstream_pause(outstream, false)));
|
||||
} else if (c == 'c') {
|
||||
fprintf(stderr, "clear buffer result: %s\n",
|
||||
soundio_strerror(soundio_outstream_clear_buffer(outstream)));
|
||||
} else if (c == 'q') {
|
||||
break;
|
||||
} else if (c == '\r' || c == '\n') {
|
||||
// ignore
|
||||
} else {
|
||||
fprintf(stderr, "Unrecognized command: %c\n", c);
|
||||
}
|
||||
}
|
||||
|
||||
soundio_outstream_destroy(outstream);
|
||||
soundio_device_unref(device);
|
||||
soundio_destroy(soundio);
|
||||
return 0;
|
||||
}
|
97
thirdparty/libsoundio/soundio/endian.h
vendored
97
thirdparty/libsoundio/soundio/endian.h
vendored
@ -1,97 +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_ENDIAN_H
|
||||
#define SOUNDIO_ENDIAN_H
|
||||
|
||||
#if defined(__BIG_ENDIAN__)
|
||||
#define SOUNDIO_OS_BIG_ENDIAN
|
||||
#elif defined(__ARMEB__)
|
||||
#define SOUNDIO_OS_BIG_ENDIAN
|
||||
#elif defined(__THUMBEB__)
|
||||
#define SOUNDIO_OS_BIG_ENDIAN
|
||||
#elif defined(__AARCH64EB__)
|
||||
#define SOUNDIO_OS_BIG_ENDIAN
|
||||
#elif defined(_MIPSEB)
|
||||
#define SOUNDIO_OS_BIG_ENDIAN
|
||||
#elif defined(__MIPSEB)
|
||||
#define SOUNDIO_OS_BIG_ENDIAN
|
||||
#elif defined(__MIPSEB__)
|
||||
#define SOUNDIO_OS_BIG_ENDIAN
|
||||
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#define SOUNDIO_OS_BIG_ENDIAN
|
||||
#elif defined(_BIG_ENDIAN)
|
||||
#define SOUNDIO_OS_BIG_ENDIAN
|
||||
#elif defined(__sparc)
|
||||
#define SOUNDIO_OS_BIG_ENDIAN
|
||||
#elif defined(__sparc__)
|
||||
#define SOUNDIO_OS_BIG_ENDIAN
|
||||
#elif defined(_POWER)
|
||||
#define SOUNDIO_OS_BIG_ENDIAN
|
||||
#elif defined(__powerpc__)
|
||||
#define SOUNDIO_OS_BIG_ENDIAN
|
||||
#elif defined(__ppc__)
|
||||
#define SOUNDIO_OS_BIG_ENDIAN
|
||||
#elif defined(__hpux)
|
||||
#define SOUNDIO_OS_BIG_ENDIAN
|
||||
#elif defined(__hppa)
|
||||
#define SOUNDIO_OS_BIG_ENDIAN
|
||||
#elif defined(_POWER)
|
||||
#define SOUNDIO_OS_BIG_ENDIAN
|
||||
#elif defined(__s390__)
|
||||
#define SOUNDIO_OS_BIG_ENDIAN
|
||||
#elif defined(__LITTLE_ENDIAN__)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(__ARMEL__)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(__THUMBEL__)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(__AARCH64EL__)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(_MIPSEL)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(__MIPSEL)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(__MIPSEL__)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(_LITTLE_ENDIAN)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(__i386__)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(__alpha__)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(__ia64)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(__ia64__)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(_M_IX86)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(_M_IA64)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(_M_ALPHA)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(__amd64)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(__amd64__)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(_M_AMD64)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(__x86_64)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(__x86_64__)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(_M_X64)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#elif defined(__bfin__)
|
||||
#define SOUNDIO_OS_LITTLE_ENDIAN
|
||||
#else
|
||||
#error unable to detect endianness
|
||||
#endif
|
||||
|
||||
#endif
|
1207
thirdparty/libsoundio/soundio/soundio.h
vendored
1207
thirdparty/libsoundio/soundio/soundio.h
vendored
File diff suppressed because it is too large
Load Diff
1958
thirdparty/libsoundio/src/alsa.c
vendored
1958
thirdparty/libsoundio/src/alsa.c
vendored
File diff suppressed because it is too large
Load Diff
89
thirdparty/libsoundio/src/alsa.h
vendored
89
thirdparty/libsoundio/src/alsa.h
vendored
@ -1,89 +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_ALSA_H
|
||||
#define SOUNDIO_ALSA_H
|
||||
|
||||
#include "soundio_internal.h"
|
||||
#include "os.h"
|
||||
#include "list.h"
|
||||
#include "atomics.h"
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
struct SoundIoPrivate;
|
||||
int soundio_alsa_init(struct SoundIoPrivate *si);
|
||||
|
||||
struct SoundIoDeviceAlsa { int make_the_struct_not_empty; };
|
||||
|
||||
#define SOUNDIO_MAX_ALSA_SND_FILE_LEN 16
|
||||
struct SoundIoAlsaPendingFile {
|
||||
char name[SOUNDIO_MAX_ALSA_SND_FILE_LEN];
|
||||
};
|
||||
|
||||
SOUNDIO_MAKE_LIST_STRUCT(struct SoundIoAlsaPendingFile, SoundIoListAlsaPendingFile, SOUNDIO_LIST_STATIC)
|
||||
|
||||
struct SoundIoAlsa {
|
||||
struct SoundIoOsMutex *mutex;
|
||||
struct SoundIoOsCond *cond;
|
||||
|
||||
struct SoundIoOsThread *thread;
|
||||
struct SoundIoAtomicFlag abort_flag;
|
||||
int notify_fd;
|
||||
int notify_wd;
|
||||
bool have_devices_flag;
|
||||
int notify_pipe_fd[2];
|
||||
struct SoundIoListAlsaPendingFile pending_files;
|
||||
|
||||
// this one is ready to be read with flush_events. protected by mutex
|
||||
struct SoundIoDevicesInfo *ready_devices_info;
|
||||
|
||||
int shutdown_err;
|
||||
bool emitted_shutdown_cb;
|
||||
};
|
||||
|
||||
struct SoundIoOutStreamAlsa {
|
||||
snd_pcm_t *handle;
|
||||
snd_pcm_chmap_t *chmap;
|
||||
int chmap_size;
|
||||
snd_pcm_uframes_t offset;
|
||||
snd_pcm_access_t access;
|
||||
snd_pcm_uframes_t buffer_size_frames;
|
||||
int sample_buffer_size;
|
||||
char *sample_buffer;
|
||||
int poll_fd_count;
|
||||
int poll_fd_count_with_extra;
|
||||
struct pollfd *poll_fds;
|
||||
int poll_exit_pipe_fd[2];
|
||||
struct SoundIoOsThread *thread;
|
||||
struct SoundIoAtomicFlag thread_exit_flag;
|
||||
snd_pcm_uframes_t period_size;
|
||||
int write_frame_count;
|
||||
bool is_paused;
|
||||
struct SoundIoAtomicFlag clear_buffer_flag;
|
||||
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct SoundIoInStreamAlsa {
|
||||
snd_pcm_t *handle;
|
||||
snd_pcm_chmap_t *chmap;
|
||||
int chmap_size;
|
||||
snd_pcm_uframes_t offset;
|
||||
snd_pcm_access_t access;
|
||||
int sample_buffer_size;
|
||||
char *sample_buffer;
|
||||
int poll_fd_count;
|
||||
struct pollfd *poll_fds;
|
||||
struct SoundIoOsThread *thread;
|
||||
struct SoundIoAtomicFlag thread_exit_flag;
|
||||
int period_size;
|
||||
int read_frame_count;
|
||||
bool is_paused;
|
||||
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
#endif
|
80
thirdparty/libsoundio/src/atomics.h
vendored
80
thirdparty/libsoundio/src/atomics.h
vendored
@ -1,80 +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_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.
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <atomic>
|
||||
|
||||
struct SoundIoAtomicLong {
|
||||
std::atomic<long> x;
|
||||
};
|
||||
|
||||
struct SoundIoAtomicInt {
|
||||
std::atomic<int> x;
|
||||
};
|
||||
|
||||
struct SoundIoAtomicBool {
|
||||
std::atomic<bool> x;
|
||||
};
|
||||
|
||||
struct SoundIoAtomicFlag {
|
||||
std::atomic_flag x;
|
||||
};
|
||||
|
||||
struct SoundIoAtomicULong {
|
||||
std::atomic<unsigned long> x;
|
||||
};
|
||||
|
||||
#define SOUNDIO_ATOMIC_LOAD(a) (a.x.load())
|
||||
#define SOUNDIO_ATOMIC_FETCH_ADD(a, delta) (a.x.fetch_add(delta))
|
||||
#define SOUNDIO_ATOMIC_STORE(a, value) (a.x.store(value))
|
||||
#define SOUNDIO_ATOMIC_EXCHANGE(a, value) (a.x.exchange(value))
|
||||
#define SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(a) (a.x.test_and_set())
|
||||
#define SOUNDIO_ATOMIC_FLAG_CLEAR(a) (a.x.clear())
|
||||
#define SOUNDIO_ATOMIC_FLAG_INIT ATOMIC_FLAG_INIT
|
||||
|
||||
#else
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
struct SoundIoAtomicLong {
|
||||
atomic_long x;
|
||||
};
|
||||
|
||||
struct SoundIoAtomicInt {
|
||||
atomic_int x;
|
||||
};
|
||||
|
||||
struct SoundIoAtomicBool {
|
||||
atomic_bool x;
|
||||
};
|
||||
|
||||
struct SoundIoAtomicFlag {
|
||||
atomic_flag x;
|
||||
};
|
||||
|
||||
struct SoundIoAtomicULong {
|
||||
atomic_ulong 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)
|
||||
#define SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(a) atomic_flag_test_and_set(&a.x)
|
||||
#define SOUNDIO_ATOMIC_FLAG_CLEAR(a) atomic_flag_clear(&a.x)
|
||||
#define SOUNDIO_ATOMIC_FLAG_INIT ATOMIC_FLAG_INIT
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
465
thirdparty/libsoundio/src/channel_layout.c
vendored
465
thirdparty/libsoundio/src/channel_layout.c
vendored
@ -1,465 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Andrew Kelley
|
||||
*
|
||||
* This file is part of libsoundio, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "soundio_private.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static struct SoundIoChannelLayout builtin_channel_layouts[] = {
|
||||
{
|
||||
"Mono",
|
||||
1,
|
||||
{
|
||||
SoundIoChannelIdFrontCenter,
|
||||
},
|
||||
},
|
||||
{
|
||||
"Stereo",
|
||||
2,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2.1",
|
||||
3,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdLfe,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3.0",
|
||||
3,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdFrontCenter,
|
||||
}
|
||||
},
|
||||
{
|
||||
"3.0 (back)",
|
||||
3,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdBackCenter,
|
||||
}
|
||||
},
|
||||
{
|
||||
"3.1",
|
||||
4,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdFrontCenter,
|
||||
SoundIoChannelIdLfe,
|
||||
}
|
||||
},
|
||||
{
|
||||
"4.0",
|
||||
4,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdFrontCenter,
|
||||
SoundIoChannelIdBackCenter,
|
||||
}
|
||||
},
|
||||
{
|
||||
"Quad",
|
||||
4,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdBackLeft,
|
||||
SoundIoChannelIdBackRight,
|
||||
},
|
||||
},
|
||||
{
|
||||
"Quad (side)",
|
||||
4,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdSideLeft,
|
||||
SoundIoChannelIdSideRight,
|
||||
}
|
||||
},
|
||||
{
|
||||
"4.1",
|
||||
5,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdFrontCenter,
|
||||
SoundIoChannelIdBackCenter,
|
||||
SoundIoChannelIdLfe,
|
||||
}
|
||||
},
|
||||
{
|
||||
"5.0 (back)",
|
||||
5,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdFrontCenter,
|
||||
SoundIoChannelIdBackLeft,
|
||||
SoundIoChannelIdBackRight,
|
||||
}
|
||||
},
|
||||
{
|
||||
"5.0 (side)",
|
||||
5,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdFrontCenter,
|
||||
SoundIoChannelIdSideLeft,
|
||||
SoundIoChannelIdSideRight,
|
||||
}
|
||||
},
|
||||
{
|
||||
"5.1",
|
||||
6,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdFrontCenter,
|
||||
SoundIoChannelIdSideLeft,
|
||||
SoundIoChannelIdSideRight,
|
||||
SoundIoChannelIdLfe,
|
||||
}
|
||||
},
|
||||
{
|
||||
"5.1 (back)",
|
||||
6,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdFrontCenter,
|
||||
SoundIoChannelIdBackLeft,
|
||||
SoundIoChannelIdBackRight,
|
||||
SoundIoChannelIdLfe,
|
||||
}
|
||||
},
|
||||
{
|
||||
"6.0 (side)",
|
||||
6,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdFrontCenter,
|
||||
SoundIoChannelIdSideLeft,
|
||||
SoundIoChannelIdSideRight,
|
||||
SoundIoChannelIdBackCenter,
|
||||
}
|
||||
},
|
||||
{
|
||||
"6.0 (front)",
|
||||
6,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdSideLeft,
|
||||
SoundIoChannelIdSideRight,
|
||||
SoundIoChannelIdFrontLeftCenter,
|
||||
SoundIoChannelIdFrontRightCenter,
|
||||
}
|
||||
},
|
||||
{
|
||||
"Hexagonal",
|
||||
6,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdFrontCenter,
|
||||
SoundIoChannelIdBackLeft,
|
||||
SoundIoChannelIdBackRight,
|
||||
SoundIoChannelIdBackCenter,
|
||||
}
|
||||
},
|
||||
{
|
||||
"6.1",
|
||||
7,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdFrontCenter,
|
||||
SoundIoChannelIdSideLeft,
|
||||
SoundIoChannelIdSideRight,
|
||||
SoundIoChannelIdBackCenter,
|
||||
SoundIoChannelIdLfe,
|
||||
}
|
||||
},
|
||||
{
|
||||
"6.1 (back)",
|
||||
7,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdFrontCenter,
|
||||
SoundIoChannelIdBackLeft,
|
||||
SoundIoChannelIdBackRight,
|
||||
SoundIoChannelIdBackCenter,
|
||||
SoundIoChannelIdLfe,
|
||||
}
|
||||
},
|
||||
{
|
||||
"6.1 (front)",
|
||||
7,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdSideLeft,
|
||||
SoundIoChannelIdSideRight,
|
||||
SoundIoChannelIdFrontLeftCenter,
|
||||
SoundIoChannelIdFrontRightCenter,
|
||||
SoundIoChannelIdLfe,
|
||||
}
|
||||
},
|
||||
{
|
||||
"7.0",
|
||||
7,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdFrontCenter,
|
||||
SoundIoChannelIdSideLeft,
|
||||
SoundIoChannelIdSideRight,
|
||||
SoundIoChannelIdBackLeft,
|
||||
SoundIoChannelIdBackRight,
|
||||
}
|
||||
},
|
||||
{
|
||||
"7.0 (front)",
|
||||
7,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdFrontCenter,
|
||||
SoundIoChannelIdSideLeft,
|
||||
SoundIoChannelIdSideRight,
|
||||
SoundIoChannelIdFrontLeftCenter,
|
||||
SoundIoChannelIdFrontRightCenter,
|
||||
}
|
||||
},
|
||||
{
|
||||
"7.1",
|
||||
8,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdFrontCenter,
|
||||
SoundIoChannelIdSideLeft,
|
||||
SoundIoChannelIdSideRight,
|
||||
SoundIoChannelIdBackLeft,
|
||||
SoundIoChannelIdBackRight,
|
||||
SoundIoChannelIdLfe,
|
||||
}
|
||||
},
|
||||
{
|
||||
"7.1 (wide)",
|
||||
8,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdFrontCenter,
|
||||
SoundIoChannelIdSideLeft,
|
||||
SoundIoChannelIdSideRight,
|
||||
SoundIoChannelIdFrontLeftCenter,
|
||||
SoundIoChannelIdFrontRightCenter,
|
||||
SoundIoChannelIdLfe,
|
||||
}
|
||||
},
|
||||
{
|
||||
"7.1 (wide) (back)",
|
||||
8,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdFrontCenter,
|
||||
SoundIoChannelIdBackLeft,
|
||||
SoundIoChannelIdBackRight,
|
||||
SoundIoChannelIdFrontLeftCenter,
|
||||
SoundIoChannelIdFrontRightCenter,
|
||||
SoundIoChannelIdLfe,
|
||||
}
|
||||
},
|
||||
{
|
||||
"Octagonal",
|
||||
8,
|
||||
{
|
||||
SoundIoChannelIdFrontLeft,
|
||||
SoundIoChannelIdFrontRight,
|
||||
SoundIoChannelIdFrontCenter,
|
||||
SoundIoChannelIdSideLeft,
|
||||
SoundIoChannelIdSideRight,
|
||||
SoundIoChannelIdBackLeft,
|
||||
SoundIoChannelIdBackRight,
|
||||
SoundIoChannelIdBackCenter,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
#define CHANNEL_NAME_ALIAS_COUNT 3
|
||||
typedef const char *channel_names_t[CHANNEL_NAME_ALIAS_COUNT];
|
||||
static channel_names_t channel_names[] = {
|
||||
{"(Invalid Channel)", NULL, NULL},
|
||||
{"Front Left", "FL", "front-left"},
|
||||
{"Front Right", "FR", "front-right"},
|
||||
{"Front Center", "FC", "front-center"},
|
||||
{"LFE", "LFE", "lfe"},
|
||||
{"Back Left", "BL", "rear-left"},
|
||||
{"Back Right", "BR", "rear-right"},
|
||||
{"Front Left Center", "FLC", "front-left-of-center"},
|
||||
{"Front Right Center", "FRC", "front-right-of-center"},
|
||||
{"Back Center", "BC", "rear-center"},
|
||||
{"Side Left", "SL", "side-left"},
|
||||
{"Side Right", "SR", "side-right"},
|
||||
{"Top Center", "TC", "top-center"},
|
||||
{"Top Front Left", "TFL", "top-front-left"},
|
||||
{"Top Front Center", "TFC", "top-front-center"},
|
||||
{"Top Front Right", "TFR", "top-front-right"},
|
||||
{"Top Back Left", "TBL", "top-rear-left"},
|
||||
{"Top Back Center", "TBC", "top-rear-center"},
|
||||
{"Top Back Right", "TBR", "top-rear-right"},
|
||||
{"Back Left Center", NULL, NULL},
|
||||
{"Back Right Center", NULL, NULL},
|
||||
{"Front Left Wide", NULL, NULL},
|
||||
{"Front Right Wide", NULL, NULL},
|
||||
{"Front Left High", NULL, NULL},
|
||||
{"Front Center High", NULL, NULL},
|
||||
{"Front Right High", NULL, NULL},
|
||||
{"Top Front Left Center", NULL, NULL},
|
||||
{"Top Front Right Center", NULL, NULL},
|
||||
{"Top Side Left", NULL, NULL},
|
||||
{"Top Side Right", NULL, NULL},
|
||||
{"Left LFE", NULL, NULL},
|
||||
{"Right LFE", NULL, NULL},
|
||||
{"LFE 2", NULL, NULL},
|
||||
{"Bottom Center", NULL, NULL},
|
||||
{"Bottom Left Center", NULL, NULL},
|
||||
{"Bottom Right Center", NULL, NULL},
|
||||
{"Mid/Side Mid", NULL, NULL},
|
||||
{"Mid/Side Side", NULL, NULL},
|
||||
{"Ambisonic W", NULL, NULL},
|
||||
{"Ambisonic X", NULL, NULL},
|
||||
{"Ambisonic Y", NULL, NULL},
|
||||
{"Ambisonic Z", NULL, NULL},
|
||||
{"X-Y X", NULL, NULL},
|
||||
{"X-Y Y", NULL, NULL},
|
||||
{"Headphones Left", NULL, NULL},
|
||||
{"Headphones Right", NULL, NULL},
|
||||
{"Click Track", NULL, NULL},
|
||||
{"Foreign Language", NULL, NULL},
|
||||
{"Hearing Impaired", NULL, NULL},
|
||||
{"Narration", NULL, NULL},
|
||||
{"Haptic", NULL, NULL},
|
||||
{"Dialog Centric Mix", NULL, NULL},
|
||||
{"Aux", NULL, NULL},
|
||||
{"Aux 0", NULL, NULL},
|
||||
{"Aux 1", NULL, NULL},
|
||||
{"Aux 2", NULL, NULL},
|
||||
{"Aux 3", NULL, NULL},
|
||||
{"Aux 4", NULL, NULL},
|
||||
{"Aux 5", NULL, NULL},
|
||||
{"Aux 6", NULL, NULL},
|
||||
{"Aux 7", NULL, NULL},
|
||||
{"Aux 8", NULL, NULL},
|
||||
{"Aux 9", NULL, NULL},
|
||||
{"Aux 10", NULL, NULL},
|
||||
{"Aux 11", NULL, NULL},
|
||||
{"Aux 12", NULL, NULL},
|
||||
{"Aux 13", NULL, NULL},
|
||||
{"Aux 14", NULL, NULL},
|
||||
{"Aux 15", NULL, NULL},
|
||||
};
|
||||
|
||||
const char *soundio_get_channel_name(enum SoundIoChannelId id) {
|
||||
if (id >= ARRAY_LENGTH(channel_names))
|
||||
return "(Invalid Channel)";
|
||||
else
|
||||
return channel_names[id][0];
|
||||
}
|
||||
|
||||
bool soundio_channel_layout_equal(
|
||||
const struct SoundIoChannelLayout *a,
|
||||
const struct SoundIoChannelLayout *b)
|
||||
{
|
||||
if (a->channel_count != b->channel_count)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < a->channel_count; i += 1) {
|
||||
if (a->channels[i] != b->channels[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int soundio_channel_layout_builtin_count(void) {
|
||||
return ARRAY_LENGTH(builtin_channel_layouts);
|
||||
}
|
||||
|
||||
const struct SoundIoChannelLayout *soundio_channel_layout_get_builtin(int index) {
|
||||
assert(index >= 0);
|
||||
assert(index <= ARRAY_LENGTH(builtin_channel_layouts));
|
||||
return &builtin_channel_layouts[index];
|
||||
}
|
||||
|
||||
int soundio_channel_layout_find_channel(
|
||||
const struct SoundIoChannelLayout *layout, enum SoundIoChannelId channel)
|
||||
{
|
||||
for (int i = 0; i < layout->channel_count; i += 1) {
|
||||
if (layout->channels[i] == channel)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool soundio_channel_layout_detect_builtin(struct SoundIoChannelLayout *layout) {
|
||||
for (int i = 0; i < ARRAY_LENGTH(builtin_channel_layouts); i += 1) {
|
||||
const struct SoundIoChannelLayout *builtin_layout = &builtin_channel_layouts[i];
|
||||
if (soundio_channel_layout_equal(builtin_layout, layout)) {
|
||||
layout->name = builtin_layout->name;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
layout->name = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
const struct SoundIoChannelLayout *soundio_channel_layout_get_default(int channel_count) {
|
||||
switch (channel_count) {
|
||||
case 1: return soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdMono);
|
||||
case 2: return soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdStereo);
|
||||
case 3: return soundio_channel_layout_get_builtin(SoundIoChannelLayoutId3Point0);
|
||||
case 4: return soundio_channel_layout_get_builtin(SoundIoChannelLayoutId4Point0);
|
||||
case 5: return soundio_channel_layout_get_builtin(SoundIoChannelLayoutId5Point0Back);
|
||||
case 6: return soundio_channel_layout_get_builtin(SoundIoChannelLayoutId5Point1Back);
|
||||
case 7: return soundio_channel_layout_get_builtin(SoundIoChannelLayoutId6Point1);
|
||||
case 8: return soundio_channel_layout_get_builtin(SoundIoChannelLayoutId7Point1);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
enum SoundIoChannelId soundio_parse_channel_id(const char *str, int str_len) {
|
||||
for (int id = 0; id < ARRAY_LENGTH(channel_names); id += 1) {
|
||||
for (int i = 0; i < CHANNEL_NAME_ALIAS_COUNT; i += 1) {
|
||||
const char *alias = channel_names[id][i];
|
||||
if (!alias)
|
||||
break;
|
||||
int alias_len = strlen(alias);
|
||||
if (soundio_streql(alias, alias_len, str, str_len))
|
||||
return (enum SoundIoChannelId)id;
|
||||
}
|
||||
}
|
||||
return SoundIoChannelIdInvalid;
|
||||
}
|
22
thirdparty/libsoundio/src/config.h.in
vendored
22
thirdparty/libsoundio/src/config.h.in
vendored
@ -1,22 +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_CONFIG_H
|
||||
#define SOUNDIO_CONFIG_H
|
||||
|
||||
#define SOUNDIO_VERSION_MAJOR @LIBSOUNDIO_VERSION_MAJOR@
|
||||
#define SOUNDIO_VERSION_MINOR @LIBSOUNDIO_VERSION_MINOR@
|
||||
#define SOUNDIO_VERSION_PATCH @LIBSOUNDIO_VERSION_PATCH@
|
||||
#define SOUNDIO_VERSION_STRING "@LIBSOUNDIO_VERSION@"
|
||||
|
||||
#cmakedefine SOUNDIO_HAVE_JACK
|
||||
#cmakedefine SOUNDIO_HAVE_PULSEAUDIO
|
||||
#cmakedefine SOUNDIO_HAVE_ALSA
|
||||
#cmakedefine SOUNDIO_HAVE_COREAUDIO
|
||||
#cmakedefine SOUNDIO_HAVE_WASAPI
|
||||
|
||||
#endif
|
1487
thirdparty/libsoundio/src/coreaudio.c
vendored
1487
thirdparty/libsoundio/src/coreaudio.c
vendored
File diff suppressed because it is too large
Load Diff
67
thirdparty/libsoundio/src/coreaudio.h
vendored
67
thirdparty/libsoundio/src/coreaudio.h
vendored
@ -1,67 +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_COREAUDIO_H
|
||||
#define SOUNDIO_COREAUDIO_H
|
||||
|
||||
#include "soundio_internal.h"
|
||||
#include "os.h"
|
||||
#include "list.h"
|
||||
#include "atomics.h"
|
||||
|
||||
#include <CoreAudio/CoreAudio.h>
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
|
||||
struct SoundIoPrivate;
|
||||
int soundio_coreaudio_init(struct SoundIoPrivate *si);
|
||||
|
||||
struct SoundIoDeviceCoreAudio {
|
||||
AudioDeviceID device_id;
|
||||
UInt32 latency_frames;
|
||||
};
|
||||
|
||||
SOUNDIO_MAKE_LIST_STRUCT(AudioDeviceID, SoundIoListAudioDeviceID, SOUNDIO_LIST_STATIC)
|
||||
|
||||
struct SoundIoCoreAudio {
|
||||
struct SoundIoOsMutex *mutex;
|
||||
struct SoundIoOsCond *cond;
|
||||
struct SoundIoOsThread *thread;
|
||||
struct SoundIoAtomicFlag abort_flag;
|
||||
|
||||
// this one is ready to be read with flush_events. protected by mutex
|
||||
struct SoundIoDevicesInfo *ready_devices_info;
|
||||
struct SoundIoAtomicBool have_devices_flag;
|
||||
struct SoundIoOsCond *have_devices_cond;
|
||||
struct SoundIoOsCond *scan_devices_cond;
|
||||
struct SoundIoListAudioDeviceID registered_listeners;
|
||||
|
||||
struct SoundIoAtomicBool device_scan_queued;
|
||||
struct SoundIoAtomicBool service_restarted;
|
||||
int shutdown_err;
|
||||
bool emitted_shutdown_cb;
|
||||
};
|
||||
|
||||
struct SoundIoOutStreamCoreAudio {
|
||||
AudioComponentInstance instance;
|
||||
AudioBufferList *io_data;
|
||||
int buffer_index;
|
||||
int frames_left;
|
||||
int write_frame_count;
|
||||
double hardware_latency;
|
||||
float volume;
|
||||
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct SoundIoInStreamCoreAudio {
|
||||
AudioComponentInstance instance;
|
||||
AudioBufferList *buffer_list;
|
||||
int frames_left;
|
||||
double hardware_latency;
|
||||
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
#endif
|
570
thirdparty/libsoundio/src/dummy.c
vendored
570
thirdparty/libsoundio/src/dummy.c
vendored
@ -1,570 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Andrew Kelley
|
||||
*
|
||||
* This file is part of libsoundio, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "dummy.h"
|
||||
#include "soundio_private.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static void playback_thread_run(void *arg) {
|
||||
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
|
||||
struct SoundIoOutStream *outstream = &os->pub;
|
||||
struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||
|
||||
int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer);
|
||||
int free_bytes = soundio_ring_buffer_capacity(&osd->ring_buffer) - fill_bytes;
|
||||
int free_frames = free_bytes / outstream->bytes_per_frame;
|
||||
osd->frames_left = free_frames;
|
||||
if (free_frames > 0)
|
||||
outstream->write_callback(outstream, 0, free_frames);
|
||||
double start_time = soundio_os_get_time();
|
||||
long frames_consumed = 0;
|
||||
|
||||
while (SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(osd->abort_flag)) {
|
||||
double now = soundio_os_get_time();
|
||||
double time_passed = now - start_time;
|
||||
double next_period = start_time +
|
||||
ceil_dbl(time_passed / osd->period_duration) * osd->period_duration;
|
||||
double relative_time = next_period - now;
|
||||
soundio_os_cond_timed_wait(osd->cond, NULL, relative_time);
|
||||
if (!SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(osd->clear_buffer_flag)) {
|
||||
soundio_ring_buffer_clear(&osd->ring_buffer);
|
||||
int free_bytes = soundio_ring_buffer_capacity(&osd->ring_buffer);
|
||||
int free_frames = free_bytes / outstream->bytes_per_frame;
|
||||
osd->frames_left = free_frames;
|
||||
if (free_frames > 0)
|
||||
outstream->write_callback(outstream, 0, free_frames);
|
||||
frames_consumed = 0;
|
||||
start_time = soundio_os_get_time();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (SOUNDIO_ATOMIC_LOAD(osd->pause_requested)) {
|
||||
start_time = now;
|
||||
frames_consumed = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer);
|
||||
int fill_frames = fill_bytes / outstream->bytes_per_frame;
|
||||
int free_bytes = soundio_ring_buffer_capacity(&osd->ring_buffer) - fill_bytes;
|
||||
int free_frames = free_bytes / outstream->bytes_per_frame;
|
||||
|
||||
double total_time = soundio_os_get_time() - start_time;
|
||||
long total_frames = total_time * outstream->sample_rate;
|
||||
int frames_to_kill = total_frames - frames_consumed;
|
||||
int read_count = soundio_int_min(frames_to_kill, fill_frames);
|
||||
int byte_count = read_count * outstream->bytes_per_frame;
|
||||
soundio_ring_buffer_advance_read_ptr(&osd->ring_buffer, byte_count);
|
||||
frames_consumed += read_count;
|
||||
|
||||
if (frames_to_kill > fill_frames) {
|
||||
outstream->underflow_callback(outstream);
|
||||
osd->frames_left = free_frames;
|
||||
if (free_frames > 0)
|
||||
outstream->write_callback(outstream, 0, free_frames);
|
||||
frames_consumed = 0;
|
||||
start_time = soundio_os_get_time();
|
||||
} else if (free_frames > 0) {
|
||||
osd->frames_left = free_frames;
|
||||
outstream->write_callback(outstream, 0, free_frames);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void capture_thread_run(void *arg) {
|
||||
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
|
||||
struct SoundIoInStream *instream = &is->pub;
|
||||
struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||
|
||||
long frames_consumed = 0;
|
||||
double start_time = soundio_os_get_time();
|
||||
while (SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(isd->abort_flag)) {
|
||||
double now = soundio_os_get_time();
|
||||
double time_passed = now - start_time;
|
||||
double next_period = start_time +
|
||||
ceil_dbl(time_passed / isd->period_duration) * isd->period_duration;
|
||||
double relative_time = next_period - now;
|
||||
soundio_os_cond_timed_wait(isd->cond, NULL, relative_time);
|
||||
|
||||
if (SOUNDIO_ATOMIC_LOAD(isd->pause_requested)) {
|
||||
start_time = now;
|
||||
frames_consumed = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
int fill_bytes = soundio_ring_buffer_fill_count(&isd->ring_buffer);
|
||||
int free_bytes = soundio_ring_buffer_capacity(&isd->ring_buffer) - fill_bytes;
|
||||
int fill_frames = fill_bytes / instream->bytes_per_frame;
|
||||
int free_frames = free_bytes / instream->bytes_per_frame;
|
||||
|
||||
double total_time = soundio_os_get_time() - start_time;
|
||||
long total_frames = total_time * instream->sample_rate;
|
||||
int frames_to_kill = total_frames - frames_consumed;
|
||||
int write_count = soundio_int_min(frames_to_kill, free_frames);
|
||||
int byte_count = write_count * instream->bytes_per_frame;
|
||||
soundio_ring_buffer_advance_write_ptr(&isd->ring_buffer, byte_count);
|
||||
frames_consumed += write_count;
|
||||
|
||||
if (frames_to_kill > free_frames) {
|
||||
instream->overflow_callback(instream);
|
||||
frames_consumed = 0;
|
||||
start_time = soundio_os_get_time();
|
||||
}
|
||||
if (fill_frames > 0) {
|
||||
isd->frames_left = fill_frames;
|
||||
instream->read_callback(instream, 0, fill_frames);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void destroy_dummy(struct SoundIoPrivate *si) {
|
||||
struct SoundIoDummy *sid = &si->backend_data.dummy;
|
||||
|
||||
if (sid->cond)
|
||||
soundio_os_cond_destroy(sid->cond);
|
||||
|
||||
if (sid->mutex)
|
||||
soundio_os_mutex_destroy(sid->mutex);
|
||||
}
|
||||
|
||||
static void flush_events_dummy(struct SoundIoPrivate *si) {
|
||||
struct SoundIo *soundio = &si->pub;
|
||||
struct SoundIoDummy *sid = &si->backend_data.dummy;
|
||||
if (sid->devices_emitted)
|
||||
return;
|
||||
sid->devices_emitted = true;
|
||||
soundio->on_devices_change(soundio);
|
||||
}
|
||||
|
||||
static void wait_events_dummy(struct SoundIoPrivate *si) {
|
||||
struct SoundIoDummy *sid = &si->backend_data.dummy;
|
||||
flush_events_dummy(si);
|
||||
soundio_os_cond_wait(sid->cond, NULL);
|
||||
}
|
||||
|
||||
static void wakeup_dummy(struct SoundIoPrivate *si) {
|
||||
struct SoundIoDummy *sid = &si->backend_data.dummy;
|
||||
soundio_os_cond_signal(sid->cond, NULL);
|
||||
}
|
||||
|
||||
static void force_device_scan_dummy(struct SoundIoPrivate *si) {
|
||||
// nothing to do; dummy devices never change
|
||||
}
|
||||
|
||||
static void outstream_destroy_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||
struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||
|
||||
if (osd->thread) {
|
||||
SOUNDIO_ATOMIC_FLAG_CLEAR(osd->abort_flag);
|
||||
soundio_os_cond_signal(osd->cond, NULL);
|
||||
soundio_os_thread_destroy(osd->thread);
|
||||
osd->thread = NULL;
|
||||
}
|
||||
soundio_os_cond_destroy(osd->cond);
|
||||
osd->cond = NULL;
|
||||
|
||||
soundio_ring_buffer_deinit(&osd->ring_buffer);
|
||||
}
|
||||
|
||||
static int outstream_open_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||
struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||
struct SoundIoOutStream *outstream = &os->pub;
|
||||
struct SoundIoDevice *device = outstream->device;
|
||||
|
||||
SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(osd->clear_buffer_flag);
|
||||
SOUNDIO_ATOMIC_STORE(osd->pause_requested, false);
|
||||
|
||||
if (outstream->software_latency == 0.0) {
|
||||
outstream->software_latency = soundio_double_clamp(
|
||||
device->software_latency_min, 1.0, device->software_latency_max);
|
||||
}
|
||||
|
||||
osd->period_duration = outstream->software_latency / 2.0;
|
||||
|
||||
int err;
|
||||
int buffer_size = outstream->bytes_per_frame * outstream->sample_rate * outstream->software_latency;
|
||||
if ((err = soundio_ring_buffer_init(&osd->ring_buffer, buffer_size))) {
|
||||
outstream_destroy_dummy(si, os);
|
||||
return err;
|
||||
}
|
||||
int actual_capacity = soundio_ring_buffer_capacity(&osd->ring_buffer);
|
||||
osd->buffer_frame_count = actual_capacity / outstream->bytes_per_frame;
|
||||
outstream->software_latency = osd->buffer_frame_count / (double) outstream->sample_rate;
|
||||
|
||||
osd->cond = soundio_os_cond_create();
|
||||
if (!osd->cond) {
|
||||
outstream_destroy_dummy(si, os);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outstream_pause_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
|
||||
struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||
SOUNDIO_ATOMIC_STORE(osd->pause_requested, pause);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outstream_start_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||
struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||
struct SoundIo *soundio = &si->pub;
|
||||
assert(!osd->thread);
|
||||
SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(osd->abort_flag);
|
||||
int err;
|
||||
if ((err = soundio_os_thread_create(playback_thread_run, os,
|
||||
soundio->emit_rtprio_warning, &osd->thread)))
|
||||
{
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outstream_begin_write_dummy(struct SoundIoPrivate *si,
|
||||
struct SoundIoOutStreamPrivate *os, struct SoundIoChannelArea **out_areas, int *frame_count)
|
||||
{
|
||||
struct SoundIoOutStream *outstream = &os->pub;
|
||||
struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||
|
||||
if (*frame_count > osd->frames_left)
|
||||
return SoundIoErrorInvalid;
|
||||
|
||||
char *write_ptr = soundio_ring_buffer_write_ptr(&osd->ring_buffer);
|
||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||
osd->areas[ch].ptr = write_ptr + outstream->bytes_per_sample * ch;
|
||||
osd->areas[ch].step = outstream->bytes_per_frame;
|
||||
}
|
||||
|
||||
osd->write_frame_count = *frame_count;
|
||||
*out_areas = osd->areas;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outstream_end_write_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||
struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||
struct SoundIoOutStream *outstream = &os->pub;
|
||||
int byte_count = osd->write_frame_count * outstream->bytes_per_frame;
|
||||
soundio_ring_buffer_advance_write_ptr(&osd->ring_buffer, byte_count);
|
||||
osd->frames_left -= osd->write_frame_count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outstream_clear_buffer_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||
struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||
SOUNDIO_ATOMIC_FLAG_CLEAR(osd->clear_buffer_flag);
|
||||
soundio_os_cond_signal(osd->cond, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outstream_get_latency_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, double *out_latency) {
|
||||
struct SoundIoOutStream *outstream = &os->pub;
|
||||
struct SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||
int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer);
|
||||
|
||||
*out_latency = (fill_bytes / outstream->bytes_per_frame) / (double)outstream->sample_rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void instream_destroy_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||
struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||
|
||||
if (isd->thread) {
|
||||
SOUNDIO_ATOMIC_FLAG_CLEAR(isd->abort_flag);
|
||||
soundio_os_cond_signal(isd->cond, NULL);
|
||||
soundio_os_thread_destroy(isd->thread);
|
||||
isd->thread = NULL;
|
||||
}
|
||||
soundio_os_cond_destroy(isd->cond);
|
||||
isd->cond = NULL;
|
||||
|
||||
soundio_ring_buffer_deinit(&isd->ring_buffer);
|
||||
}
|
||||
|
||||
static int instream_open_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||
struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||
struct SoundIoInStream *instream = &is->pub;
|
||||
struct SoundIoDevice *device = instream->device;
|
||||
|
||||
SOUNDIO_ATOMIC_STORE(isd->pause_requested, false);
|
||||
|
||||
if (instream->software_latency == 0.0) {
|
||||
instream->software_latency = soundio_double_clamp(
|
||||
device->software_latency_min, 1.0, device->software_latency_max);
|
||||
}
|
||||
|
||||
isd->period_duration = instream->software_latency;
|
||||
|
||||
double target_buffer_duration = isd->period_duration * 4.0;
|
||||
|
||||
int err;
|
||||
int buffer_size = instream->bytes_per_frame * instream->sample_rate * target_buffer_duration;
|
||||
if ((err = soundio_ring_buffer_init(&isd->ring_buffer, buffer_size))) {
|
||||
instream_destroy_dummy(si, is);
|
||||
return err;
|
||||
}
|
||||
|
||||
int actual_capacity = soundio_ring_buffer_capacity(&isd->ring_buffer);
|
||||
isd->buffer_frame_count = actual_capacity / instream->bytes_per_frame;
|
||||
|
||||
isd->cond = soundio_os_cond_create();
|
||||
if (!isd->cond) {
|
||||
instream_destroy_dummy(si, is);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int instream_pause_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
|
||||
struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||
SOUNDIO_ATOMIC_STORE(isd->pause_requested, pause);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int instream_start_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||
struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||
struct SoundIo *soundio = &si->pub;
|
||||
assert(!isd->thread);
|
||||
SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(isd->abort_flag);
|
||||
int err;
|
||||
if ((err = soundio_os_thread_create(capture_thread_run, is,
|
||||
soundio->emit_rtprio_warning, &isd->thread)))
|
||||
{
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int instream_begin_read_dummy(struct SoundIoPrivate *si,
|
||||
struct SoundIoInStreamPrivate *is, struct SoundIoChannelArea **out_areas, int *frame_count)
|
||||
{
|
||||
struct SoundIoInStream *instream = &is->pub;
|
||||
struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||
|
||||
assert(*frame_count <= isd->frames_left);
|
||||
|
||||
char *read_ptr = soundio_ring_buffer_read_ptr(&isd->ring_buffer);
|
||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||
isd->areas[ch].ptr = read_ptr + instream->bytes_per_sample * ch;
|
||||
isd->areas[ch].step = instream->bytes_per_frame;
|
||||
}
|
||||
|
||||
isd->read_frame_count = *frame_count;
|
||||
*out_areas = isd->areas;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int instream_end_read_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||
struct SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||
struct SoundIoInStream *instream = &is->pub;
|
||||
int byte_count = isd->read_frame_count * instream->bytes_per_frame;
|
||||
soundio_ring_buffer_advance_read_ptr(&isd->ring_buffer, byte_count);
|
||||
isd->frames_left -= isd->read_frame_count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int instream_get_latency_dummy(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, double *out_latency) {
|
||||
struct SoundIoInStream *instream = &is->pub;
|
||||
struct SoundIoInStreamDummy *osd = &is->backend_data.dummy;
|
||||
int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer);
|
||||
|
||||
*out_latency = (fill_bytes / instream->bytes_per_frame) / (double)instream->sample_rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_all_device_formats(struct SoundIoDevice *device) {
|
||||
device->format_count = 18;
|
||||
device->formats = ALLOCATE(enum SoundIoFormat, device->format_count);
|
||||
if (!device->formats)
|
||||
return SoundIoErrorNoMem;
|
||||
|
||||
device->formats[0] = SoundIoFormatFloat32NE;
|
||||
device->formats[1] = SoundIoFormatFloat32FE;
|
||||
device->formats[2] = SoundIoFormatS32NE;
|
||||
device->formats[3] = SoundIoFormatS32FE;
|
||||
device->formats[4] = SoundIoFormatU32NE;
|
||||
device->formats[5] = SoundIoFormatU32FE;
|
||||
device->formats[6] = SoundIoFormatS24NE;
|
||||
device->formats[7] = SoundIoFormatS24FE;
|
||||
device->formats[8] = SoundIoFormatU24NE;
|
||||
device->formats[9] = SoundIoFormatU24FE;
|
||||
device->formats[10] = SoundIoFormatFloat64NE;
|
||||
device->formats[11] = SoundIoFormatFloat64FE;
|
||||
device->formats[12] = SoundIoFormatS16NE;
|
||||
device->formats[13] = SoundIoFormatS16FE;
|
||||
device->formats[14] = SoundIoFormatU16NE;
|
||||
device->formats[15] = SoundIoFormatU16FE;
|
||||
device->formats[16] = SoundIoFormatS8;
|
||||
device->formats[17] = SoundIoFormatU8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_all_device_sample_rates(struct SoundIoDevice *device) {
|
||||
struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
|
||||
device->sample_rate_count = 1;
|
||||
device->sample_rates = &dev->prealloc_sample_rate_range;
|
||||
device->sample_rates[0].min = SOUNDIO_MIN_SAMPLE_RATE;
|
||||
device->sample_rates[0].max = SOUNDIO_MAX_SAMPLE_RATE;
|
||||
}
|
||||
|
||||
static int set_all_device_channel_layouts(struct SoundIoDevice *device) {
|
||||
device->layout_count = soundio_channel_layout_builtin_count();
|
||||
device->layouts = ALLOCATE(struct SoundIoChannelLayout, device->layout_count);
|
||||
if (!device->layouts)
|
||||
return SoundIoErrorNoMem;
|
||||
for (int i = 0; i < device->layout_count; i += 1)
|
||||
device->layouts[i] = *soundio_channel_layout_get_builtin(i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int soundio_dummy_init(struct SoundIoPrivate *si) {
|
||||
struct SoundIo *soundio = &si->pub;
|
||||
struct SoundIoDummy *sid = &si->backend_data.dummy;
|
||||
|
||||
sid->mutex = soundio_os_mutex_create();
|
||||
if (!sid->mutex) {
|
||||
destroy_dummy(si);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
sid->cond = soundio_os_cond_create();
|
||||
if (!sid->cond) {
|
||||
destroy_dummy(si);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
assert(!si->safe_devices_info);
|
||||
si->safe_devices_info = ALLOCATE(struct SoundIoDevicesInfo, 1);
|
||||
if (!si->safe_devices_info) {
|
||||
destroy_dummy(si);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
si->safe_devices_info->default_input_index = 0;
|
||||
si->safe_devices_info->default_output_index = 0;
|
||||
|
||||
// create output device
|
||||
{
|
||||
struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
|
||||
if (!dev) {
|
||||
destroy_dummy(si);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
struct SoundIoDevice *device = &dev->pub;
|
||||
|
||||
device->ref_count = 1;
|
||||
device->soundio = soundio;
|
||||
device->id = strdup("dummy-out");
|
||||
device->name = strdup("Dummy Output Device");
|
||||
if (!device->id || !device->name) {
|
||||
soundio_device_unref(device);
|
||||
destroy_dummy(si);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
int err;
|
||||
if ((err = set_all_device_channel_layouts(device))) {
|
||||
soundio_device_unref(device);
|
||||
destroy_dummy(si);
|
||||
return err;
|
||||
}
|
||||
if ((err = set_all_device_formats(device))) {
|
||||
soundio_device_unref(device);
|
||||
destroy_dummy(si);
|
||||
return err;
|
||||
}
|
||||
set_all_device_sample_rates(device);
|
||||
|
||||
device->software_latency_current = 0.1;
|
||||
device->software_latency_min = 0.01;
|
||||
device->software_latency_max = 4.0;
|
||||
|
||||
device->sample_rate_current = 48000;
|
||||
device->aim = SoundIoDeviceAimOutput;
|
||||
|
||||
if (SoundIoListDevicePtr_append(&si->safe_devices_info->output_devices, device)) {
|
||||
soundio_device_unref(device);
|
||||
destroy_dummy(si);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
}
|
||||
|
||||
// create input device
|
||||
{
|
||||
struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
|
||||
if (!dev) {
|
||||
destroy_dummy(si);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
struct SoundIoDevice *device = &dev->pub;
|
||||
|
||||
device->ref_count = 1;
|
||||
device->soundio = soundio;
|
||||
device->id = strdup("dummy-in");
|
||||
device->name = strdup("Dummy Input Device");
|
||||
if (!device->id || !device->name) {
|
||||
soundio_device_unref(device);
|
||||
destroy_dummy(si);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
int err;
|
||||
if ((err = set_all_device_channel_layouts(device))) {
|
||||
soundio_device_unref(device);
|
||||
destroy_dummy(si);
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = set_all_device_formats(device))) {
|
||||
soundio_device_unref(device);
|
||||
destroy_dummy(si);
|
||||
return err;
|
||||
}
|
||||
set_all_device_sample_rates(device);
|
||||
device->software_latency_current = 0.1;
|
||||
device->software_latency_min = 0.01;
|
||||
device->software_latency_max = 4.0;
|
||||
device->sample_rate_current = 48000;
|
||||
device->aim = SoundIoDeviceAimInput;
|
||||
|
||||
if (SoundIoListDevicePtr_append(&si->safe_devices_info->input_devices, device)) {
|
||||
soundio_device_unref(device);
|
||||
destroy_dummy(si);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
si->destroy = destroy_dummy;
|
||||
si->flush_events = flush_events_dummy;
|
||||
si->wait_events = wait_events_dummy;
|
||||
si->wakeup = wakeup_dummy;
|
||||
si->force_device_scan = force_device_scan_dummy;
|
||||
|
||||
si->outstream_open = outstream_open_dummy;
|
||||
si->outstream_destroy = outstream_destroy_dummy;
|
||||
si->outstream_start = outstream_start_dummy;
|
||||
si->outstream_begin_write = outstream_begin_write_dummy;
|
||||
si->outstream_end_write = outstream_end_write_dummy;
|
||||
si->outstream_clear_buffer = outstream_clear_buffer_dummy;
|
||||
si->outstream_pause = outstream_pause_dummy;
|
||||
si->outstream_get_latency = outstream_get_latency_dummy;
|
||||
|
||||
si->instream_open = instream_open_dummy;
|
||||
si->instream_destroy = instream_destroy_dummy;
|
||||
si->instream_start = instream_start_dummy;
|
||||
si->instream_begin_read = instream_begin_read_dummy;
|
||||
si->instream_end_read = instream_end_read_dummy;
|
||||
si->instream_pause = instream_pause_dummy;
|
||||
si->instream_get_latency = instream_get_latency_dummy;
|
||||
|
||||
return 0;
|
||||
}
|
55
thirdparty/libsoundio/src/dummy.h
vendored
55
thirdparty/libsoundio/src/dummy.h
vendored
@ -1,55 +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_DUMMY_H
|
||||
#define SOUNDIO_DUMMY_H
|
||||
|
||||
#include "soundio_internal.h"
|
||||
#include "os.h"
|
||||
#include "ring_buffer.h"
|
||||
#include "atomics.h"
|
||||
|
||||
struct SoundIoPrivate;
|
||||
int soundio_dummy_init(struct SoundIoPrivate *si);
|
||||
|
||||
struct SoundIoDummy {
|
||||
struct SoundIoOsMutex *mutex;
|
||||
struct SoundIoOsCond *cond;
|
||||
bool devices_emitted;
|
||||
};
|
||||
|
||||
struct SoundIoDeviceDummy { int make_the_struct_not_empty; };
|
||||
|
||||
struct SoundIoOutStreamDummy {
|
||||
struct SoundIoOsThread *thread;
|
||||
struct SoundIoOsCond *cond;
|
||||
struct SoundIoAtomicFlag abort_flag;
|
||||
double period_duration;
|
||||
int buffer_frame_count;
|
||||
int frames_left;
|
||||
int write_frame_count;
|
||||
struct SoundIoRingBuffer ring_buffer;
|
||||
double playback_start_time;
|
||||
struct SoundIoAtomicFlag clear_buffer_flag;
|
||||
struct SoundIoAtomicBool pause_requested;
|
||||
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct SoundIoInStreamDummy {
|
||||
struct SoundIoOsThread *thread;
|
||||
struct SoundIoOsCond *cond;
|
||||
struct SoundIoAtomicFlag abort_flag;
|
||||
double period_duration;
|
||||
int frames_left;
|
||||
int read_frame_count;
|
||||
int buffer_frame_count;
|
||||
struct SoundIoRingBuffer ring_buffer;
|
||||
struct SoundIoAtomicBool pause_requested;
|
||||
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
#endif
|
964
thirdparty/libsoundio/src/jack.c
vendored
964
thirdparty/libsoundio/src/jack.c
vendored
@ -1,964 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Andrew Kelley
|
||||
*
|
||||
* This file is part of libsoundio, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "jack.h"
|
||||
#include "soundio_private.h"
|
||||
#include "list.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static struct SoundIoAtomicFlag global_msg_callback_flag = SOUNDIO_ATOMIC_FLAG_INIT;
|
||||
|
||||
struct SoundIoJackPort {
|
||||
const char *full_name;
|
||||
int full_name_len;
|
||||
const char *name;
|
||||
int name_len;
|
||||
enum SoundIoChannelId channel_id;
|
||||
jack_latency_range_t latency_range;
|
||||
};
|
||||
|
||||
struct SoundIoJackClient {
|
||||
const char *name;
|
||||
int name_len;
|
||||
bool is_physical;
|
||||
enum SoundIoDeviceAim aim;
|
||||
int port_count;
|
||||
struct SoundIoJackPort ports[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
SOUNDIO_MAKE_LIST_STRUCT(struct SoundIoJackClient, SoundIoListJackClient, SOUNDIO_LIST_STATIC)
|
||||
SOUNDIO_MAKE_LIST_DEF(struct SoundIoJackClient, SoundIoListJackClient, SOUNDIO_LIST_STATIC)
|
||||
|
||||
static void split_str(const char *input_str, int input_str_len, char c,
|
||||
const char **out_1, int *out_len_1, const char **out_2, int *out_len_2)
|
||||
{
|
||||
*out_1 = input_str;
|
||||
while (*input_str) {
|
||||
if (*input_str == c) {
|
||||
*out_len_1 = input_str - *out_1;
|
||||
*out_2 = input_str + 1;
|
||||
*out_len_2 = input_str_len - 1 - *out_len_1;
|
||||
return;
|
||||
}
|
||||
input_str += 1;
|
||||
}
|
||||
}
|
||||
|
||||
static struct SoundIoJackClient *find_or_create_client(struct SoundIoListJackClient *clients,
|
||||
enum SoundIoDeviceAim aim, bool is_physical, const char *client_name, int client_name_len)
|
||||
{
|
||||
for (int i = 0; i < clients->length; i += 1) {
|
||||
struct SoundIoJackClient *client = SoundIoListJackClient_ptr_at(clients, i);
|
||||
if (client->is_physical == is_physical &&
|
||||
client->aim == aim &&
|
||||
soundio_streql(client->name, client->name_len, client_name, client_name_len))
|
||||
{
|
||||
return client;
|
||||
}
|
||||
}
|
||||
int err;
|
||||
if ((err = SoundIoListJackClient_add_one(clients)))
|
||||
return NULL;
|
||||
struct SoundIoJackClient *client = SoundIoListJackClient_last_ptr(clients);
|
||||
client->is_physical = is_physical;
|
||||
client->aim = aim;
|
||||
client->name = client_name;
|
||||
client->name_len = client_name_len;
|
||||
client->port_count = 0;
|
||||
return client;
|
||||
}
|
||||
|
||||
static void destruct_device(struct SoundIoDevicePrivate *dp) {
|
||||
struct SoundIoDeviceJack *dj = &dp->backend_data.jack;
|
||||
for (int i = 0; i < dj->port_count; i += 1) {
|
||||
struct SoundIoDeviceJackPort *djp = &dj->ports[i];
|
||||
free(djp->full_name);
|
||||
}
|
||||
free(dj->ports);
|
||||
}
|
||||
|
||||
static int refresh_devices_bare(struct SoundIoPrivate *si) {
|
||||
struct SoundIo *soundio = &si->pub;
|
||||
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||
|
||||
if (sij->is_shutdown)
|
||||
return SoundIoErrorBackendDisconnected;
|
||||
|
||||
|
||||
struct SoundIoDevicesInfo *devices_info = ALLOCATE(struct SoundIoDevicesInfo, 1);
|
||||
if (!devices_info)
|
||||
return SoundIoErrorNoMem;
|
||||
|
||||
devices_info->default_output_index = -1;
|
||||
devices_info->default_input_index = -1;
|
||||
const char **port_names = jack_get_ports(sij->client, NULL, NULL, 0);
|
||||
if (!port_names) {
|
||||
soundio_destroy_devices_info(devices_info);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
struct SoundIoListJackClient clients = {0};
|
||||
const char **port_name_ptr = port_names;
|
||||
for (; *port_name_ptr; port_name_ptr += 1) {
|
||||
const char *client_and_port_name = *port_name_ptr;
|
||||
int client_and_port_name_len = strlen(client_and_port_name);
|
||||
jack_port_t *jport = jack_port_by_name(sij->client, client_and_port_name);
|
||||
if (!jport) {
|
||||
// This refresh devices scan is already outdated. Just give up and
|
||||
// let refresh_devices be called again.
|
||||
jack_free(port_names);
|
||||
soundio_destroy_devices_info(devices_info);
|
||||
return SoundIoErrorInterrupted;
|
||||
}
|
||||
|
||||
int flags = jack_port_flags(jport);
|
||||
const char *port_type = jack_port_type(jport);
|
||||
if (strcmp(port_type, JACK_DEFAULT_AUDIO_TYPE) != 0) {
|
||||
// we don't know how to support such a port
|
||||
continue;
|
||||
}
|
||||
|
||||
enum SoundIoDeviceAim aim = (flags & JackPortIsInput) ?
|
||||
SoundIoDeviceAimOutput : SoundIoDeviceAimInput;
|
||||
bool is_physical = flags & JackPortIsPhysical;
|
||||
|
||||
const char *client_name = NULL;
|
||||
const char *port_name = NULL;
|
||||
int client_name_len;
|
||||
int port_name_len;
|
||||
split_str(client_and_port_name, client_and_port_name_len, ':',
|
||||
&client_name, &client_name_len, &port_name, &port_name_len);
|
||||
if (!client_name || !port_name) {
|
||||
// device does not have colon, skip it
|
||||
continue;
|
||||
}
|
||||
struct SoundIoJackClient *client = find_or_create_client(&clients, aim, is_physical,
|
||||
client_name, client_name_len);
|
||||
if (!client) {
|
||||
jack_free(port_names);
|
||||
soundio_destroy_devices_info(devices_info);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
if (client->port_count >= SOUNDIO_MAX_CHANNELS) {
|
||||
// we hit the channel limit, skip the leftovers
|
||||
continue;
|
||||
}
|
||||
struct SoundIoJackPort *port = &client->ports[client->port_count++];
|
||||
port->full_name = client_and_port_name;
|
||||
port->full_name_len = client_and_port_name_len;
|
||||
port->name = port_name;
|
||||
port->name_len = port_name_len;
|
||||
port->channel_id = soundio_parse_channel_id(port_name, port_name_len);
|
||||
|
||||
jack_latency_callback_mode_t latency_mode = (aim == SoundIoDeviceAimOutput) ?
|
||||
JackPlaybackLatency : JackCaptureLatency;
|
||||
jack_port_get_latency_range(jport, latency_mode, &port->latency_range);
|
||||
}
|
||||
|
||||
for (int i = 0; i < clients.length; i += 1) {
|
||||
struct SoundIoJackClient *client = SoundIoListJackClient_ptr_at(&clients, i);
|
||||
if (client->port_count <= 0)
|
||||
continue;
|
||||
|
||||
struct SoundIoDevicePrivate *dev = ALLOCATE(struct SoundIoDevicePrivate, 1);
|
||||
if (!dev) {
|
||||
jack_free(port_names);
|
||||
soundio_destroy_devices_info(devices_info);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
struct SoundIoDevice *device = &dev->pub;
|
||||
struct SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
||||
int description_len = client->name_len + 3 + 2 * client->port_count;
|
||||
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
||||
struct SoundIoJackPort *port = &client->ports[port_index];
|
||||
|
||||
description_len += port->name_len;
|
||||
}
|
||||
|
||||
dev->destruct = destruct_device;
|
||||
|
||||
device->ref_count = 1;
|
||||
device->soundio = soundio;
|
||||
device->is_raw = false;
|
||||
device->aim = client->aim;
|
||||
device->id = soundio_str_dupe(client->name, client->name_len);
|
||||
device->name = ALLOCATE(char, description_len);
|
||||
device->current_format = SoundIoFormatFloat32NE;
|
||||
device->sample_rate_count = 1;
|
||||
device->sample_rates = &dev->prealloc_sample_rate_range;
|
||||
device->sample_rates[0].min = sij->sample_rate;
|
||||
device->sample_rates[0].max = sij->sample_rate;
|
||||
device->sample_rate_current = sij->sample_rate;
|
||||
|
||||
device->software_latency_current = sij->period_size / (double) sij->sample_rate;
|
||||
device->software_latency_min = 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->ports = ALLOCATE(struct SoundIoDeviceJackPort, dj->port_count);
|
||||
|
||||
if (!device->id || !device->name || !dj->ports) {
|
||||
jack_free(port_names);
|
||||
soundio_device_unref(device);
|
||||
soundio_destroy_devices_info(devices_info);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
||||
struct SoundIoJackPort *port = &client->ports[port_index];
|
||||
struct SoundIoDeviceJackPort *djp = &dj->ports[port_index];
|
||||
djp->full_name = soundio_str_dupe(port->full_name, port->full_name_len);
|
||||
djp->full_name_len = port->full_name_len;
|
||||
djp->channel_id = port->channel_id;
|
||||
djp->latency_range = port->latency_range;
|
||||
|
||||
if (!djp->full_name) {
|
||||
jack_free(port_names);
|
||||
soundio_device_unref(device);
|
||||
soundio_destroy_devices_info(devices_info);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(device->name, client->name, client->name_len);
|
||||
memcpy(&device->name[client->name_len], ": ", 2);
|
||||
int index = client->name_len + 2;
|
||||
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
||||
struct SoundIoJackPort *port = &client->ports[port_index];
|
||||
memcpy(&device->name[index], port->name, port->name_len);
|
||||
index += port->name_len;
|
||||
if (port_index + 1 < client->port_count) {
|
||||
memcpy(&device->name[index], ", ", 2);
|
||||
index += 2;
|
||||
}
|
||||
}
|
||||
|
||||
device->current_layout.channel_count = client->port_count;
|
||||
bool any_invalid = false;
|
||||
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
||||
struct SoundIoJackPort *port = &client->ports[port_index];
|
||||
device->current_layout.channels[port_index] = port->channel_id;
|
||||
any_invalid = any_invalid || (port->channel_id == SoundIoChannelIdInvalid);
|
||||
}
|
||||
if (any_invalid) {
|
||||
const struct SoundIoChannelLayout *layout = soundio_channel_layout_get_default(client->port_count);
|
||||
if (layout)
|
||||
device->current_layout = *layout;
|
||||
} else {
|
||||
soundio_channel_layout_detect_builtin(&device->current_layout);
|
||||
}
|
||||
|
||||
device->layout_count = 1;
|
||||
device->layouts = &device->current_layout;
|
||||
device->format_count = 1;
|
||||
device->formats = &dev->prealloc_format;
|
||||
device->formats[0] = device->current_format;
|
||||
|
||||
struct SoundIoListDevicePtr *device_list;
|
||||
if (device->aim == SoundIoDeviceAimOutput) {
|
||||
device_list = &devices_info->output_devices;
|
||||
if (devices_info->default_output_index < 0 && client->is_physical)
|
||||
devices_info->default_output_index = device_list->length;
|
||||
} else {
|
||||
assert(device->aim == SoundIoDeviceAimInput);
|
||||
device_list = &devices_info->input_devices;
|
||||
if (devices_info->default_input_index < 0 && client->is_physical)
|
||||
devices_info->default_input_index = device_list->length;
|
||||
}
|
||||
|
||||
if (SoundIoListDevicePtr_append(device_list, device)) {
|
||||
soundio_device_unref(device);
|
||||
soundio_destroy_devices_info(devices_info);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
}
|
||||
jack_free(port_names);
|
||||
|
||||
soundio_destroy_devices_info(si->safe_devices_info);
|
||||
si->safe_devices_info = devices_info;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int refresh_devices(struct SoundIoPrivate *si) {
|
||||
int err = SoundIoErrorInterrupted;
|
||||
while (err == SoundIoErrorInterrupted)
|
||||
err = refresh_devices_bare(si);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void my_flush_events(struct SoundIoPrivate *si, bool wait) {
|
||||
struct SoundIo *soundio = &si->pub;
|
||||
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||
int err;
|
||||
|
||||
bool cb_shutdown = false;
|
||||
|
||||
soundio_os_mutex_lock(sij->mutex);
|
||||
|
||||
if (wait)
|
||||
soundio_os_cond_wait(sij->cond, sij->mutex);
|
||||
|
||||
if (sij->is_shutdown && !sij->emitted_shutdown_cb) {
|
||||
sij->emitted_shutdown_cb = true;
|
||||
cb_shutdown = true;
|
||||
}
|
||||
|
||||
soundio_os_mutex_unlock(sij->mutex);
|
||||
|
||||
if (cb_shutdown) {
|
||||
soundio->on_backend_disconnect(soundio, SoundIoErrorBackendDisconnected);
|
||||
} else {
|
||||
if (!SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(sij->refresh_devices_flag)) {
|
||||
if ((err = refresh_devices(si))) {
|
||||
SOUNDIO_ATOMIC_FLAG_CLEAR(sij->refresh_devices_flag);
|
||||
} else {
|
||||
soundio->on_devices_change(soundio);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void flush_events_jack(struct SoundIoPrivate *si) {
|
||||
my_flush_events(si, false);
|
||||
}
|
||||
|
||||
static void wait_events_jack(struct SoundIoPrivate *si) {
|
||||
my_flush_events(si, false);
|
||||
my_flush_events(si, true);
|
||||
}
|
||||
|
||||
static void wakeup_jack(struct SoundIoPrivate *si) {
|
||||
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||
soundio_os_mutex_lock(sij->mutex);
|
||||
soundio_os_cond_signal(sij->cond, sij->mutex);
|
||||
soundio_os_mutex_unlock(sij->mutex);
|
||||
}
|
||||
|
||||
static void force_device_scan_jack(struct SoundIoPrivate *si) {
|
||||
struct SoundIo *soundio = &si->pub;
|
||||
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||
SOUNDIO_ATOMIC_FLAG_CLEAR(sij->refresh_devices_flag);
|
||||
soundio_os_mutex_lock(sij->mutex);
|
||||
soundio_os_cond_signal(sij->cond, sij->mutex);
|
||||
soundio->on_events_signal(soundio);
|
||||
soundio_os_mutex_unlock(sij->mutex);
|
||||
}
|
||||
|
||||
static int outstream_process_callback(jack_nframes_t nframes, void *arg) {
|
||||
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
|
||||
struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||
struct SoundIoOutStream *outstream = &os->pub;
|
||||
osj->frames_left = nframes;
|
||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||
struct SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
||||
osj->areas[ch].ptr = (char*)jack_port_get_buffer(osjp->source_port, nframes);
|
||||
osj->areas[ch].step = outstream->bytes_per_sample;
|
||||
}
|
||||
outstream->write_callback(outstream, osj->frames_left, osj->frames_left);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void outstream_destroy_jack(struct SoundIoPrivate *is, struct SoundIoOutStreamPrivate *os) {
|
||||
struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||
|
||||
jack_client_close(osj->client);
|
||||
osj->client = NULL;
|
||||
}
|
||||
|
||||
static struct SoundIoDeviceJackPort *find_port_matching_channel(struct SoundIoDevice *device, enum SoundIoChannelId id) {
|
||||
struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
|
||||
struct SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
||||
|
||||
for (int ch = 0; ch < device->current_layout.channel_count; ch += 1) {
|
||||
enum SoundIoChannelId chan_id = device->current_layout.channels[ch];
|
||||
if (chan_id == id)
|
||||
return &dj->ports[ch];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int outstream_xrun_callback(void *arg) {
|
||||
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
|
||||
struct SoundIoOutStream *outstream = &os->pub;
|
||||
outstream->underflow_callback(outstream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outstream_buffer_size_callback(jack_nframes_t nframes, void *arg) {
|
||||
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
|
||||
struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||
struct SoundIoOutStream *outstream = &os->pub;
|
||||
if ((jack_nframes_t)osj->period_size == nframes) {
|
||||
return 0;
|
||||
} else {
|
||||
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int outstream_sample_rate_callback(jack_nframes_t nframes, void *arg) {
|
||||
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
|
||||
struct SoundIoOutStream *outstream = &os->pub;
|
||||
if (nframes == (jack_nframes_t)outstream->sample_rate) {
|
||||
return 0;
|
||||
} else {
|
||||
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void outstream_shutdown_callback(void *arg) {
|
||||
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)arg;
|
||||
struct SoundIoOutStream *outstream = &os->pub;
|
||||
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||
}
|
||||
|
||||
static inline jack_nframes_t nframes_max(jack_nframes_t a, jack_nframes_t b) {
|
||||
return (a >= b) ? a : b;
|
||||
}
|
||||
|
||||
static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||
struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||
struct SoundIoOutStream *outstream = &os->pub;
|
||||
struct SoundIoDevice *device = outstream->device;
|
||||
struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
|
||||
struct SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
||||
|
||||
if (sij->is_shutdown)
|
||||
return SoundIoErrorBackendDisconnected;
|
||||
|
||||
if (!outstream->name)
|
||||
outstream->name = "SoundIoOutStream";
|
||||
|
||||
outstream->software_latency = device->software_latency_current;
|
||||
osj->period_size = sij->period_size;
|
||||
|
||||
jack_status_t status;
|
||||
osj->client = jack_client_open(outstream->name, JackNoStartServer, &status);
|
||||
if (!osj->client) {
|
||||
outstream_destroy_jack(si, os);
|
||||
assert(!(status & JackInvalidOption));
|
||||
if (status & JackShmFailure)
|
||||
return SoundIoErrorSystemResources;
|
||||
if (status & JackNoSuchClient)
|
||||
return SoundIoErrorNoSuchClient;
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
int err;
|
||||
if ((err = jack_set_process_callback(osj->client, outstream_process_callback, os))) {
|
||||
outstream_destroy_jack(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
if ((err = jack_set_buffer_size_callback(osj->client, outstream_buffer_size_callback, os))) {
|
||||
outstream_destroy_jack(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
if ((err = jack_set_sample_rate_callback(osj->client, outstream_sample_rate_callback, os))) {
|
||||
outstream_destroy_jack(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
if ((err = jack_set_xrun_callback(osj->client, outstream_xrun_callback, os))) {
|
||||
outstream_destroy_jack(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
jack_on_shutdown(osj->client, outstream_shutdown_callback, os);
|
||||
|
||||
|
||||
jack_nframes_t max_port_latency = 0;
|
||||
|
||||
// register ports and map channels
|
||||
int connected_count = 0;
|
||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||
enum SoundIoChannelId my_channel_id = outstream->layout.channels[ch];
|
||||
const char *channel_name = soundio_get_channel_name(my_channel_id);
|
||||
unsigned long flags = JackPortIsOutput;
|
||||
if (!outstream->non_terminal_hint)
|
||||
flags |= JackPortIsTerminal;
|
||||
jack_port_t *jport = jack_port_register(osj->client, channel_name, JACK_DEFAULT_AUDIO_TYPE, flags, 0);
|
||||
if (!jport) {
|
||||
outstream_destroy_jack(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
struct SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
||||
osjp->source_port = jport;
|
||||
// figure out which dest port this connects to
|
||||
struct SoundIoDeviceJackPort *djp = find_port_matching_channel(device, my_channel_id);
|
||||
if (djp) {
|
||||
osjp->dest_port_name = djp->full_name;
|
||||
osjp->dest_port_name_len = djp->full_name_len;
|
||||
connected_count += 1;
|
||||
max_port_latency = nframes_max(max_port_latency, djp->latency_range.max);
|
||||
}
|
||||
}
|
||||
// If nothing got connected, channel layouts aren't working. Just send the
|
||||
// data in the order of the ports.
|
||||
if (connected_count == 0) {
|
||||
max_port_latency = 0;
|
||||
outstream->layout_error = SoundIoErrorIncompatibleDevice;
|
||||
|
||||
int ch_count = soundio_int_min(outstream->layout.channel_count, dj->port_count);
|
||||
for (int ch = 0; ch < ch_count; ch += 1) {
|
||||
struct SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
||||
struct SoundIoDeviceJackPort *djp = &dj->ports[ch];
|
||||
osjp->dest_port_name = djp->full_name;
|
||||
osjp->dest_port_name_len = djp->full_name_len;
|
||||
max_port_latency = nframes_max(max_port_latency, djp->latency_range.max);
|
||||
}
|
||||
}
|
||||
|
||||
osj->hardware_latency = max_port_latency / (double)outstream->sample_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outstream_pause_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
|
||||
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||
|
||||
if (sij->is_shutdown)
|
||||
return SoundIoErrorBackendDisconnected;
|
||||
|
||||
return SoundIoErrorIncompatibleBackend;
|
||||
}
|
||||
|
||||
static int outstream_start_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||
struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||
struct SoundIoOutStream *outstream = &os->pub;
|
||||
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||
int err;
|
||||
|
||||
if (sij->is_shutdown)
|
||||
return SoundIoErrorBackendDisconnected;
|
||||
|
||||
if ((err = jack_activate(osj->client)))
|
||||
return SoundIoErrorStreaming;
|
||||
|
||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||
struct SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
||||
const char *dest_port_name = osjp->dest_port_name;
|
||||
// allow unconnected ports
|
||||
if (!dest_port_name)
|
||||
continue;
|
||||
const char *source_port_name = jack_port_name(osjp->source_port);
|
||||
if ((err = jack_connect(osj->client, source_port_name, dest_port_name)))
|
||||
return SoundIoErrorStreaming;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outstream_begin_write_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
||||
struct SoundIoChannelArea **out_areas, int *frame_count)
|
||||
{
|
||||
struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||
|
||||
if (*frame_count != osj->frames_left)
|
||||
return SoundIoErrorInvalid;
|
||||
|
||||
*out_areas = osj->areas;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outstream_end_write_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||
struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||
osj->frames_left = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outstream_clear_buffer_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||
return SoundIoErrorIncompatibleBackend;
|
||||
}
|
||||
|
||||
static int outstream_get_latency_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
||||
double *out_latency)
|
||||
{
|
||||
struct SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||
*out_latency = osj->hardware_latency;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void instream_destroy_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||
struct SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||
|
||||
jack_client_close(isj->client);
|
||||
isj->client = NULL;
|
||||
}
|
||||
|
||||
static int instream_xrun_callback(void *arg) {
|
||||
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
|
||||
struct SoundIoInStream *instream = &is->pub;
|
||||
instream->overflow_callback(instream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int instream_buffer_size_callback(jack_nframes_t nframes, void *arg) {
|
||||
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
|
||||
struct SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||
struct SoundIoInStream *instream = &is->pub;
|
||||
|
||||
if ((jack_nframes_t)isj->period_size == nframes) {
|
||||
return 0;
|
||||
} else {
|
||||
instream->error_callback(instream, SoundIoErrorStreaming);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int instream_sample_rate_callback(jack_nframes_t nframes, void *arg) {
|
||||
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
|
||||
struct SoundIoInStream *instream = &is->pub;
|
||||
if (nframes == (jack_nframes_t)instream->sample_rate) {
|
||||
return 0;
|
||||
} else {
|
||||
instream->error_callback(instream, SoundIoErrorStreaming);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void instream_shutdown_callback(void *arg) {
|
||||
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
|
||||
struct SoundIoInStream *instream = &is->pub;
|
||||
instream->error_callback(instream, SoundIoErrorStreaming);
|
||||
}
|
||||
|
||||
static int instream_process_callback(jack_nframes_t nframes, void *arg) {
|
||||
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)arg;
|
||||
struct SoundIoInStream *instream = &is->pub;
|
||||
struct SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||
isj->frames_left = nframes;
|
||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||
struct SoundIoInStreamJackPort *isjp = &isj->ports[ch];
|
||||
isj->areas[ch].ptr = (char*)jack_port_get_buffer(isjp->dest_port, nframes);
|
||||
isj->areas[ch].step = instream->bytes_per_sample;
|
||||
}
|
||||
instream->read_callback(instream, isj->frames_left, isj->frames_left);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||
struct SoundIoInStream *instream = &is->pub;
|
||||
struct SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||
struct SoundIoDevice *device = instream->device;
|
||||
struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
|
||||
struct SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
||||
|
||||
if (sij->is_shutdown)
|
||||
return SoundIoErrorBackendDisconnected;
|
||||
|
||||
if (!instream->name)
|
||||
instream->name = "SoundIoInStream";
|
||||
|
||||
instream->software_latency = device->software_latency_current;
|
||||
isj->period_size = sij->period_size;
|
||||
|
||||
jack_status_t status;
|
||||
isj->client = jack_client_open(instream->name, JackNoStartServer, &status);
|
||||
if (!isj->client) {
|
||||
instream_destroy_jack(si, is);
|
||||
assert(!(status & JackInvalidOption));
|
||||
if (status & JackShmFailure)
|
||||
return SoundIoErrorSystemResources;
|
||||
if (status & JackNoSuchClient)
|
||||
return SoundIoErrorNoSuchClient;
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
int err;
|
||||
if ((err = jack_set_process_callback(isj->client, instream_process_callback, is))) {
|
||||
instream_destroy_jack(si, is);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
if ((err = jack_set_buffer_size_callback(isj->client, instream_buffer_size_callback, is))) {
|
||||
instream_destroy_jack(si, is);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
if ((err = jack_set_sample_rate_callback(isj->client, instream_sample_rate_callback, is))) {
|
||||
instream_destroy_jack(si, is);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
if ((err = jack_set_xrun_callback(isj->client, instream_xrun_callback, is))) {
|
||||
instream_destroy_jack(si, is);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
jack_on_shutdown(isj->client, instream_shutdown_callback, is);
|
||||
|
||||
jack_nframes_t max_port_latency = 0;
|
||||
|
||||
// register ports and map channels
|
||||
int connected_count = 0;
|
||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||
enum SoundIoChannelId my_channel_id = instream->layout.channels[ch];
|
||||
const char *channel_name = soundio_get_channel_name(my_channel_id);
|
||||
unsigned long flags = JackPortIsInput;
|
||||
if (!instream->non_terminal_hint)
|
||||
flags |= JackPortIsTerminal;
|
||||
jack_port_t *jport = jack_port_register(isj->client, channel_name, JACK_DEFAULT_AUDIO_TYPE, flags, 0);
|
||||
if (!jport) {
|
||||
instream_destroy_jack(si, is);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
struct SoundIoInStreamJackPort *isjp = &isj->ports[ch];
|
||||
isjp->dest_port = jport;
|
||||
// figure out which source port this connects to
|
||||
struct SoundIoDeviceJackPort *djp = find_port_matching_channel(device, my_channel_id);
|
||||
if (djp) {
|
||||
isjp->source_port_name = djp->full_name;
|
||||
isjp->source_port_name_len = djp->full_name_len;
|
||||
connected_count += 1;
|
||||
max_port_latency = nframes_max(max_port_latency, djp->latency_range.max);
|
||||
}
|
||||
}
|
||||
// If nothing got connected, channel layouts aren't working. Just send the
|
||||
// data in the order of the ports.
|
||||
if (connected_count == 0) {
|
||||
max_port_latency = 0;
|
||||
instream->layout_error = SoundIoErrorIncompatibleDevice;
|
||||
|
||||
int ch_count = soundio_int_min(instream->layout.channel_count, dj->port_count);
|
||||
for (int ch = 0; ch < ch_count; ch += 1) {
|
||||
struct SoundIoInStreamJackPort *isjp = &isj->ports[ch];
|
||||
struct SoundIoDeviceJackPort *djp = &dj->ports[ch];
|
||||
isjp->source_port_name = djp->full_name;
|
||||
isjp->source_port_name_len = djp->full_name_len;
|
||||
max_port_latency = nframes_max(max_port_latency, djp->latency_range.max);
|
||||
}
|
||||
}
|
||||
|
||||
isj->hardware_latency = max_port_latency / (double)instream->sample_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int instream_pause_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
|
||||
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||
|
||||
if (sij->is_shutdown)
|
||||
return SoundIoErrorBackendDisconnected;
|
||||
|
||||
return SoundIoErrorIncompatibleBackend;
|
||||
}
|
||||
|
||||
static int instream_start_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||
struct SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||
struct SoundIoInStream *instream = &is->pub;
|
||||
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||
int err;
|
||||
|
||||
if (sij->is_shutdown)
|
||||
return SoundIoErrorBackendDisconnected;
|
||||
|
||||
if ((err = jack_activate(isj->client)))
|
||||
return SoundIoErrorStreaming;
|
||||
|
||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||
struct SoundIoInStreamJackPort *isjp = &isj->ports[ch];
|
||||
const char *source_port_name = isjp->source_port_name;
|
||||
// allow unconnected ports
|
||||
if (!source_port_name)
|
||||
continue;
|
||||
const char *dest_port_name = jack_port_name(isjp->dest_port);
|
||||
if ((err = jack_connect(isj->client, source_port_name, dest_port_name)))
|
||||
return SoundIoErrorStreaming;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int instream_begin_read_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
|
||||
struct SoundIoChannelArea **out_areas, int *frame_count)
|
||||
{
|
||||
struct SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||
|
||||
if (*frame_count != isj->frames_left)
|
||||
return SoundIoErrorInvalid;
|
||||
|
||||
*out_areas = isj->areas;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int instream_end_read_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||
struct SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||
isj->frames_left = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int instream_get_latency_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
|
||||
double *out_latency)
|
||||
{
|
||||
struct SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||
*out_latency = isj->hardware_latency;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void notify_devices_change(struct SoundIoPrivate *si) {
|
||||
struct SoundIo *soundio = &si->pub;
|
||||
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||
SOUNDIO_ATOMIC_FLAG_CLEAR(sij->refresh_devices_flag);
|
||||
soundio_os_mutex_lock(sij->mutex);
|
||||
soundio_os_cond_signal(sij->cond, sij->mutex);
|
||||
soundio->on_events_signal(soundio);
|
||||
soundio_os_mutex_unlock(sij->mutex);
|
||||
}
|
||||
|
||||
static int buffer_size_callback(jack_nframes_t nframes, void *arg) {
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
|
||||
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||
sij->period_size = nframes;
|
||||
notify_devices_change(si);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sample_rate_callback(jack_nframes_t nframes, void *arg) {
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
|
||||
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||
sij->sample_rate = nframes;
|
||||
notify_devices_change(si);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void port_registration_callback(jack_port_id_t port_id, int reg, void *arg) {
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
|
||||
notify_devices_change(si);
|
||||
}
|
||||
|
||||
static void port_rename_calllback(jack_port_id_t port_id,
|
||||
const char *old_name, const char *new_name, void *arg)
|
||||
{
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
|
||||
notify_devices_change(si);
|
||||
}
|
||||
|
||||
static void shutdown_callback(void *arg) {
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)arg;
|
||||
struct SoundIo *soundio = &si->pub;
|
||||
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||
soundio_os_mutex_lock(sij->mutex);
|
||||
sij->is_shutdown = true;
|
||||
soundio_os_cond_signal(sij->cond, sij->mutex);
|
||||
soundio->on_events_signal(soundio);
|
||||
soundio_os_mutex_unlock(sij->mutex);
|
||||
}
|
||||
|
||||
static void destroy_jack(struct SoundIoPrivate *si) {
|
||||
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||
|
||||
if (sij->client)
|
||||
jack_client_close(sij->client);
|
||||
|
||||
if (sij->cond)
|
||||
soundio_os_cond_destroy(sij->cond);
|
||||
|
||||
if (sij->mutex)
|
||||
soundio_os_mutex_destroy(sij->mutex);
|
||||
}
|
||||
|
||||
int soundio_jack_init(struct SoundIoPrivate *si) {
|
||||
struct SoundIoJack *sij = &si->backend_data.jack;
|
||||
struct SoundIo *soundio = &si->pub;
|
||||
|
||||
if (!SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(global_msg_callback_flag)) {
|
||||
if (soundio->jack_error_callback)
|
||||
jack_set_error_function(soundio->jack_error_callback);
|
||||
if (soundio->jack_info_callback)
|
||||
jack_set_info_function(soundio->jack_info_callback);
|
||||
SOUNDIO_ATOMIC_FLAG_CLEAR(global_msg_callback_flag);
|
||||
}
|
||||
|
||||
sij->mutex = soundio_os_mutex_create();
|
||||
if (!sij->mutex) {
|
||||
destroy_jack(si);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
sij->cond = soundio_os_cond_create();
|
||||
if (!sij->cond) {
|
||||
destroy_jack(si);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
// We pass JackNoStartServer due to
|
||||
// https://github.com/jackaudio/jack2/issues/138
|
||||
jack_status_t status;
|
||||
sij->client = jack_client_open(soundio->app_name, JackNoStartServer, &status);
|
||||
if (!sij->client) {
|
||||
destroy_jack(si);
|
||||
assert(!(status & JackInvalidOption));
|
||||
if (status & JackShmFailure)
|
||||
return SoundIoErrorSystemResources;
|
||||
if (status & JackNoSuchClient)
|
||||
return SoundIoErrorNoSuchClient;
|
||||
|
||||
return SoundIoErrorInitAudioBackend;
|
||||
}
|
||||
|
||||
int err;
|
||||
if ((err = jack_set_buffer_size_callback(sij->client, buffer_size_callback, si))) {
|
||||
destroy_jack(si);
|
||||
return SoundIoErrorInitAudioBackend;
|
||||
}
|
||||
if ((err = jack_set_sample_rate_callback(sij->client, sample_rate_callback, si))) {
|
||||
destroy_jack(si);
|
||||
return SoundIoErrorInitAudioBackend;
|
||||
}
|
||||
if ((err = jack_set_port_registration_callback(sij->client, port_registration_callback, si))) {
|
||||
destroy_jack(si);
|
||||
return SoundIoErrorInitAudioBackend;
|
||||
}
|
||||
if ((err = jack_set_port_rename_callback(sij->client, port_rename_calllback, si))) {
|
||||
destroy_jack(si);
|
||||
return SoundIoErrorInitAudioBackend;
|
||||
}
|
||||
jack_on_shutdown(sij->client, shutdown_callback, si);
|
||||
|
||||
SOUNDIO_ATOMIC_FLAG_CLEAR(sij->refresh_devices_flag);
|
||||
sij->period_size = jack_get_buffer_size(sij->client);
|
||||
sij->sample_rate = jack_get_sample_rate(sij->client);
|
||||
|
||||
if ((err = jack_activate(sij->client))) {
|
||||
destroy_jack(si);
|
||||
return SoundIoErrorInitAudioBackend;
|
||||
}
|
||||
|
||||
if ((err = refresh_devices(si))) {
|
||||
destroy_jack(si);
|
||||
return err;
|
||||
}
|
||||
|
||||
si->destroy = destroy_jack;
|
||||
si->flush_events = flush_events_jack;
|
||||
si->wait_events = wait_events_jack;
|
||||
si->wakeup = wakeup_jack;
|
||||
si->force_device_scan = force_device_scan_jack;
|
||||
|
||||
si->outstream_open = outstream_open_jack;
|
||||
si->outstream_destroy = outstream_destroy_jack;
|
||||
si->outstream_start = outstream_start_jack;
|
||||
si->outstream_begin_write = outstream_begin_write_jack;
|
||||
si->outstream_end_write = outstream_end_write_jack;
|
||||
si->outstream_clear_buffer = outstream_clear_buffer_jack;
|
||||
si->outstream_pause = outstream_pause_jack;
|
||||
si->outstream_get_latency = outstream_get_latency_jack;
|
||||
|
||||
si->instream_open = instream_open_jack;
|
||||
si->instream_destroy = instream_destroy_jack;
|
||||
si->instream_start = instream_start_jack;
|
||||
si->instream_begin_read = instream_begin_read_jack;
|
||||
si->instream_end_read = instream_end_read_jack;
|
||||
si->instream_pause = instream_pause_jack;
|
||||
si->instream_get_latency = instream_get_latency_jack;
|
||||
|
||||
return 0;
|
||||
}
|
79
thirdparty/libsoundio/src/jack.h
vendored
79
thirdparty/libsoundio/src/jack.h
vendored
@ -1,79 +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_JACK_H
|
||||
#define SOUNDIO_JACK_H
|
||||
|
||||
#include "soundio_internal.h"
|
||||
#include "os.h"
|
||||
#include "atomics.h"
|
||||
|
||||
// jack.h does not properly put `void` in function prototypes with no
|
||||
// arguments, so we're forced to temporarily disable -Werror=strict-prototypes
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
|
||||
#include <jack/jack.h>
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
struct SoundIoPrivate;
|
||||
int soundio_jack_init(struct SoundIoPrivate *si);
|
||||
|
||||
struct SoundIoDeviceJackPort {
|
||||
char *full_name;
|
||||
int full_name_len;
|
||||
enum SoundIoChannelId channel_id;
|
||||
jack_latency_range_t latency_range;
|
||||
};
|
||||
|
||||
struct SoundIoDeviceJack {
|
||||
int port_count;
|
||||
struct SoundIoDeviceJackPort *ports;
|
||||
};
|
||||
|
||||
struct SoundIoJack {
|
||||
jack_client_t *client;
|
||||
struct SoundIoOsMutex *mutex;
|
||||
struct SoundIoOsCond *cond;
|
||||
struct SoundIoAtomicFlag refresh_devices_flag;
|
||||
int sample_rate;
|
||||
int period_size;
|
||||
bool is_shutdown;
|
||||
bool emitted_shutdown_cb;
|
||||
};
|
||||
|
||||
struct SoundIoOutStreamJackPort {
|
||||
jack_port_t *source_port;
|
||||
const char *dest_port_name;
|
||||
int dest_port_name_len;
|
||||
};
|
||||
|
||||
struct SoundIoOutStreamJack {
|
||||
jack_client_t *client;
|
||||
int period_size;
|
||||
int frames_left;
|
||||
double hardware_latency;
|
||||
struct SoundIoOutStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
|
||||
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct SoundIoInStreamJackPort {
|
||||
jack_port_t *dest_port;
|
||||
const char *source_port_name;
|
||||
int source_port_name_len;
|
||||
};
|
||||
|
||||
struct SoundIoInStreamJack {
|
||||
jack_client_t *client;
|
||||
int period_size;
|
||||
int frames_left;
|
||||
double hardware_latency;
|
||||
struct SoundIoInStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
|
||||
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||
char *buf_ptrs[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
#endif
|
145
thirdparty/libsoundio/src/list.h
vendored
145
thirdparty/libsoundio/src/list.h
vendored
@ -1,145 +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_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 SOUNDIO_ATTR_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 SOUNDIO_ATTR_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 SOUNDIO_ATTR_WARN_UNUSED_RESULT Name##_resize(struct Name *s, int new_length); \
|
||||
static_kw void Name##_clear(struct Name *s); \
|
||||
static_kw int SOUNDIO_ATTR_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) \
|
||||
SOUNDIO_ATTR_UNUSED \
|
||||
static_kw void Name##_deinit(struct Name *s) { \
|
||||
free(s->items); \
|
||||
} \
|
||||
\
|
||||
SOUNDIO_ATTR_UNUSED \
|
||||
SOUNDIO_ATTR_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; \
|
||||
} \
|
||||
\
|
||||
SOUNDIO_ATTR_UNUSED \
|
||||
SOUNDIO_ATTR_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; \
|
||||
} \
|
||||
\
|
||||
SOUNDIO_ATTR_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 \
|
||||
*/ \
|
||||
SOUNDIO_ATTR_UNUSED \
|
||||
static_kw Type * Name##_ptr_at(struct Name *s, int index) { \
|
||||
assert(index >= 0); \
|
||||
assert(index < s->length); \
|
||||
return &s->items[index]; \
|
||||
} \
|
||||
\
|
||||
SOUNDIO_ATTR_UNUSED \
|
||||
static_kw Type Name##_pop(struct Name *s) { \
|
||||
assert(s->length >= 1); \
|
||||
s->length -= 1; \
|
||||
return s->items[s->length]; \
|
||||
} \
|
||||
\
|
||||
SOUNDIO_ATTR_UNUSED \
|
||||
SOUNDIO_ATTR_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; \
|
||||
} \
|
||||
\
|
||||
SOUNDIO_ATTR_UNUSED \
|
||||
SOUNDIO_ATTR_WARN_UNUSED_RESULT \
|
||||
static_kw int Name##_add_one(struct Name *s) { \
|
||||
return Name##_resize(s, s->length + 1); \
|
||||
} \
|
||||
\
|
||||
SOUNDIO_ATTR_UNUSED \
|
||||
static_kw Type Name##_last_val(struct Name *s) { \
|
||||
assert(s->length >= 1); \
|
||||
return s->items[s->length - 1]; \
|
||||
} \
|
||||
\
|
||||
SOUNDIO_ATTR_UNUSED \
|
||||
static_kw Type *Name##_last_ptr(struct Name *s) { \
|
||||
assert(s->length >= 1); \
|
||||
return &s->items[s->length - 1]; \
|
||||
} \
|
||||
\
|
||||
SOUNDIO_ATTR_UNUSED \
|
||||
static_kw void Name##_clear(struct Name *s) { \
|
||||
s->length = 0; \
|
||||
} \
|
||||
\
|
||||
SOUNDIO_ATTR_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
|
747
thirdparty/libsoundio/src/os.c
vendored
747
thirdparty/libsoundio/src/os.c
vendored
@ -1,747 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Andrew Kelley
|
||||
*
|
||||
* This file is part of libsoundio, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define _DARWIN_C_SOURCE
|
||||
#undef _POSIX_C_SOURCE
|
||||
#else
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include "os.h"
|
||||
#include "soundio_internal.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define SOUNDIO_OS_WINDOWS
|
||||
|
||||
#if !defined(NOMINMAX)
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#if !defined(VC_EXTRALEAN)
|
||||
#define VC_EXTRALEAN
|
||||
#endif
|
||||
|
||||
#if !defined(WIN32_LEAN_AND_MEAN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#if !defined(UNICODE)
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
// require Windows 7 or later
|
||||
#if WINVER < 0x0601
|
||||
#undef WINVER
|
||||
#define WINVER 0x0601
|
||||
#endif
|
||||
#if _WIN32_WINNT < 0x0601
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0601
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <objbase.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__MACH__)
|
||||
#define SOUNDIO_OS_KQUEUE
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#if defined(__MACH__)
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
struct SoundIoOsThread {
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
HANDLE handle;
|
||||
DWORD id;
|
||||
#else
|
||||
pthread_attr_t attr;
|
||||
bool attr_init;
|
||||
|
||||
pthread_t id;
|
||||
bool running;
|
||||
#endif
|
||||
void *arg;
|
||||
void (*run)(void *arg);
|
||||
};
|
||||
|
||||
struct SoundIoOsMutex {
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
CRITICAL_SECTION id;
|
||||
#else
|
||||
pthread_mutex_t id;
|
||||
bool id_init;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(SOUNDIO_OS_KQUEUE)
|
||||
static const uintptr_t notify_ident = 1;
|
||||
struct SoundIoOsCond {
|
||||
int kq_id;
|
||||
};
|
||||
#elif defined(SOUNDIO_OS_WINDOWS)
|
||||
struct SoundIoOsCond {
|
||||
CONDITION_VARIABLE id;
|
||||
CRITICAL_SECTION default_cs_id;
|
||||
};
|
||||
#else
|
||||
struct SoundIoOsCond {
|
||||
pthread_cond_t id;
|
||||
bool id_init;
|
||||
|
||||
pthread_condattr_t attr;
|
||||
bool attr_init;
|
||||
|
||||
pthread_mutex_t default_mutex_id;
|
||||
bool default_mutex_init;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
static INIT_ONCE win32_init_once = INIT_ONCE_STATIC_INIT;
|
||||
static double win32_time_resolution;
|
||||
static SYSTEM_INFO win32_system_info;
|
||||
#else
|
||||
static bool initialized = false;
|
||||
static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#if defined(__MACH__)
|
||||
static clock_serv_t cclock;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static int page_size;
|
||||
|
||||
double soundio_os_get_time(void) {
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
unsigned __int64 time;
|
||||
QueryPerformanceCounter((LARGE_INTEGER*) &time);
|
||||
return time * win32_time_resolution;
|
||||
#elif defined(__MACH__)
|
||||
mach_timespec_t mts;
|
||||
|
||||
kern_return_t err = clock_get_time(cclock, &mts);
|
||||
assert(!err);
|
||||
|
||||
double seconds = (double)mts.tv_sec;
|
||||
seconds += ((double)mts.tv_nsec) / 1000000000.0;
|
||||
|
||||
return seconds;
|
||||
#else
|
||||
struct timespec tms;
|
||||
clock_gettime(CLOCK_MONOTONIC, &tms);
|
||||
double seconds = (double)tms.tv_sec;
|
||||
seconds += ((double)tms.tv_nsec) / 1000000000.0;
|
||||
return seconds;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
static DWORD WINAPI run_win32_thread(LPVOID userdata) {
|
||||
struct SoundIoOsThread *thread = (struct SoundIoOsThread *)userdata;
|
||||
HRESULT err = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
assert(err == S_OK);
|
||||
thread->run(thread->arg);
|
||||
CoUninitialize();
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static void assert_no_err(int err) {
|
||||
assert(!err);
|
||||
}
|
||||
|
||||
static void *run_pthread(void *userdata) {
|
||||
struct SoundIoOsThread *thread = (struct SoundIoOsThread *)userdata;
|
||||
thread->run(thread->arg);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
int soundio_os_thread_create(
|
||||
void (*run)(void *arg), void *arg,
|
||||
void (*emit_rtprio_warning)(void),
|
||||
struct SoundIoOsThread ** out_thread)
|
||||
{
|
||||
*out_thread = NULL;
|
||||
|
||||
struct SoundIoOsThread *thread = ALLOCATE(struct SoundIoOsThread, 1);
|
||||
if (!thread) {
|
||||
soundio_os_thread_destroy(thread);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
thread->run = run;
|
||||
thread->arg = arg;
|
||||
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
thread->handle = CreateThread(NULL, 0, run_win32_thread, thread, 0, &thread->id);
|
||||
if (!thread->handle) {
|
||||
soundio_os_thread_destroy(thread);
|
||||
return SoundIoErrorSystemResources;
|
||||
}
|
||||
if (emit_rtprio_warning) {
|
||||
if (!SetThreadPriority(thread->handle, THREAD_PRIORITY_TIME_CRITICAL)) {
|
||||
emit_rtprio_warning();
|
||||
}
|
||||
}
|
||||
#else
|
||||
int err;
|
||||
if ((err = pthread_attr_init(&thread->attr))) {
|
||||
soundio_os_thread_destroy(thread);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
thread->attr_init = true;
|
||||
|
||||
if (emit_rtprio_warning) {
|
||||
int max_priority = sched_get_priority_max(SCHED_FIFO);
|
||||
if (max_priority == -1) {
|
||||
soundio_os_thread_destroy(thread);
|
||||
return SoundIoErrorSystemResources;
|
||||
}
|
||||
|
||||
if ((err = pthread_attr_setschedpolicy(&thread->attr, SCHED_FIFO))) {
|
||||
soundio_os_thread_destroy(thread);
|
||||
return SoundIoErrorSystemResources;
|
||||
}
|
||||
|
||||
struct sched_param param;
|
||||
param.sched_priority = max_priority;
|
||||
if ((err = pthread_attr_setschedparam(&thread->attr, ¶m))) {
|
||||
soundio_os_thread_destroy(thread);
|
||||
return SoundIoErrorSystemResources;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ((err = pthread_create(&thread->id, &thread->attr, run_pthread, thread))) {
|
||||
if (err == EPERM && emit_rtprio_warning) {
|
||||
emit_rtprio_warning();
|
||||
err = pthread_create(&thread->id, NULL, run_pthread, thread);
|
||||
}
|
||||
if (err) {
|
||||
soundio_os_thread_destroy(thread);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
}
|
||||
thread->running = true;
|
||||
#endif
|
||||
|
||||
*out_thread = thread;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void soundio_os_thread_destroy(struct SoundIoOsThread *thread) {
|
||||
if (!thread)
|
||||
return;
|
||||
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
if (thread->handle) {
|
||||
DWORD err = WaitForSingleObject(thread->handle, INFINITE);
|
||||
assert(err != WAIT_FAILED);
|
||||
BOOL ok = CloseHandle(thread->handle);
|
||||
assert(ok);
|
||||
}
|
||||
#else
|
||||
|
||||
if (thread->running) {
|
||||
assert_no_err(pthread_join(thread->id, NULL));
|
||||
}
|
||||
|
||||
if (thread->attr_init) {
|
||||
assert_no_err(pthread_attr_destroy(&thread->attr));
|
||||
}
|
||||
#endif
|
||||
|
||||
free(thread);
|
||||
}
|
||||
|
||||
struct SoundIoOsMutex *soundio_os_mutex_create(void) {
|
||||
struct SoundIoOsMutex *mutex = ALLOCATE(struct SoundIoOsMutex, 1);
|
||||
if (!mutex) {
|
||||
soundio_os_mutex_destroy(mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
InitializeCriticalSection(&mutex->id);
|
||||
#else
|
||||
int err;
|
||||
if ((err = pthread_mutex_init(&mutex->id, NULL))) {
|
||||
soundio_os_mutex_destroy(mutex);
|
||||
return NULL;
|
||||
}
|
||||
mutex->id_init = true;
|
||||
#endif
|
||||
|
||||
return mutex;
|
||||
}
|
||||
|
||||
void soundio_os_mutex_destroy(struct SoundIoOsMutex *mutex) {
|
||||
if (!mutex)
|
||||
return;
|
||||
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
DeleteCriticalSection(&mutex->id);
|
||||
#else
|
||||
if (mutex->id_init) {
|
||||
assert_no_err(pthread_mutex_destroy(&mutex->id));
|
||||
}
|
||||
#endif
|
||||
|
||||
free(mutex);
|
||||
}
|
||||
|
||||
void soundio_os_mutex_lock(struct SoundIoOsMutex *mutex) {
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
EnterCriticalSection(&mutex->id);
|
||||
#else
|
||||
assert_no_err(pthread_mutex_lock(&mutex->id));
|
||||
#endif
|
||||
}
|
||||
|
||||
void soundio_os_mutex_unlock(struct SoundIoOsMutex *mutex) {
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
LeaveCriticalSection(&mutex->id);
|
||||
#else
|
||||
assert_no_err(pthread_mutex_unlock(&mutex->id));
|
||||
#endif
|
||||
}
|
||||
|
||||
struct SoundIoOsCond * soundio_os_cond_create(void) {
|
||||
struct SoundIoOsCond *cond = ALLOCATE(struct SoundIoOsCond, 1);
|
||||
|
||||
if (!cond) {
|
||||
soundio_os_cond_destroy(cond);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
InitializeConditionVariable(&cond->id);
|
||||
InitializeCriticalSection(&cond->default_cs_id);
|
||||
#elif defined(SOUNDIO_OS_KQUEUE)
|
||||
cond->kq_id = kqueue();
|
||||
if (cond->kq_id == -1)
|
||||
return NULL;
|
||||
#else
|
||||
if (pthread_condattr_init(&cond->attr)) {
|
||||
soundio_os_cond_destroy(cond);
|
||||
return NULL;
|
||||
}
|
||||
cond->attr_init = true;
|
||||
|
||||
if (pthread_condattr_setclock(&cond->attr, CLOCK_MONOTONIC)) {
|
||||
soundio_os_cond_destroy(cond);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pthread_cond_init(&cond->id, &cond->attr)) {
|
||||
soundio_os_cond_destroy(cond);
|
||||
return NULL;
|
||||
}
|
||||
cond->id_init = true;
|
||||
|
||||
if ((pthread_mutex_init(&cond->default_mutex_id, NULL))) {
|
||||
soundio_os_cond_destroy(cond);
|
||||
return NULL;
|
||||
}
|
||||
cond->default_mutex_init = true;
|
||||
#endif
|
||||
|
||||
return cond;
|
||||
}
|
||||
|
||||
void soundio_os_cond_destroy(struct SoundIoOsCond *cond) {
|
||||
if (!cond)
|
||||
return;
|
||||
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
DeleteCriticalSection(&cond->default_cs_id);
|
||||
#elif defined(SOUNDIO_OS_KQUEUE)
|
||||
close(cond->kq_id);
|
||||
#else
|
||||
if (cond->id_init) {
|
||||
assert_no_err(pthread_cond_destroy(&cond->id));
|
||||
}
|
||||
|
||||
if (cond->attr_init) {
|
||||
assert_no_err(pthread_condattr_destroy(&cond->attr));
|
||||
}
|
||||
if (cond->default_mutex_init) {
|
||||
assert_no_err(pthread_mutex_destroy(&cond->default_mutex_id));
|
||||
}
|
||||
#endif
|
||||
|
||||
free(cond);
|
||||
}
|
||||
|
||||
void soundio_os_cond_signal(struct SoundIoOsCond *cond,
|
||||
struct SoundIoOsMutex *locked_mutex)
|
||||
{
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
if (locked_mutex) {
|
||||
WakeConditionVariable(&cond->id);
|
||||
} else {
|
||||
EnterCriticalSection(&cond->default_cs_id);
|
||||
WakeConditionVariable(&cond->id);
|
||||
LeaveCriticalSection(&cond->default_cs_id);
|
||||
}
|
||||
#elif defined(SOUNDIO_OS_KQUEUE)
|
||||
struct kevent kev;
|
||||
struct timespec timeout = { 0, 0 };
|
||||
|
||||
memset(&kev, 0, sizeof(kev));
|
||||
kev.ident = notify_ident;
|
||||
kev.filter = EVFILT_USER;
|
||||
kev.fflags = NOTE_TRIGGER;
|
||||
|
||||
if (kevent(cond->kq_id, &kev, 1, NULL, 0, &timeout) == -1) {
|
||||
if (errno == EINTR)
|
||||
return;
|
||||
if (errno == ENOENT)
|
||||
return;
|
||||
assert(0); // kevent signal error
|
||||
}
|
||||
#else
|
||||
if (locked_mutex) {
|
||||
assert_no_err(pthread_cond_signal(&cond->id));
|
||||
} else {
|
||||
assert_no_err(pthread_mutex_lock(&cond->default_mutex_id));
|
||||
assert_no_err(pthread_cond_signal(&cond->id));
|
||||
assert_no_err(pthread_mutex_unlock(&cond->default_mutex_id));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void soundio_os_cond_timed_wait(struct SoundIoOsCond *cond,
|
||||
struct SoundIoOsMutex *locked_mutex, double seconds)
|
||||
{
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
CRITICAL_SECTION *target_cs;
|
||||
if (locked_mutex) {
|
||||
target_cs = &locked_mutex->id;
|
||||
} else {
|
||||
target_cs = &cond->default_cs_id;
|
||||
EnterCriticalSection(&cond->default_cs_id);
|
||||
}
|
||||
DWORD ms = seconds * 1000.0;
|
||||
SleepConditionVariableCS(&cond->id, target_cs, ms);
|
||||
if (!locked_mutex)
|
||||
LeaveCriticalSection(&cond->default_cs_id);
|
||||
#elif defined(SOUNDIO_OS_KQUEUE)
|
||||
struct kevent kev;
|
||||
struct kevent out_kev;
|
||||
|
||||
if (locked_mutex)
|
||||
assert_no_err(pthread_mutex_unlock(&locked_mutex->id));
|
||||
|
||||
memset(&kev, 0, sizeof(kev));
|
||||
kev.ident = notify_ident;
|
||||
kev.filter = EVFILT_USER;
|
||||
kev.flags = EV_ADD | EV_CLEAR;
|
||||
|
||||
// this time is relative
|
||||
struct timespec timeout;
|
||||
timeout.tv_nsec = (seconds * 1000000000L);
|
||||
timeout.tv_sec = timeout.tv_nsec / 1000000000L;
|
||||
timeout.tv_nsec = timeout.tv_nsec % 1000000000L;
|
||||
|
||||
if (kevent(cond->kq_id, &kev, 1, &out_kev, 1, &timeout) == -1) {
|
||||
if (errno == EINTR)
|
||||
return;
|
||||
assert(0); // kevent wait error
|
||||
}
|
||||
if (locked_mutex)
|
||||
assert_no_err(pthread_mutex_lock(&locked_mutex->id));
|
||||
#else
|
||||
pthread_mutex_t *target_mutex;
|
||||
if (locked_mutex) {
|
||||
target_mutex = &locked_mutex->id;
|
||||
} else {
|
||||
target_mutex = &cond->default_mutex_id;
|
||||
assert_no_err(pthread_mutex_lock(target_mutex));
|
||||
}
|
||||
// this time is absolute
|
||||
struct timespec tms;
|
||||
clock_gettime(CLOCK_MONOTONIC, &tms);
|
||||
tms.tv_nsec += (seconds * 1000000000L);
|
||||
tms.tv_sec += tms.tv_nsec / 1000000000L;
|
||||
tms.tv_nsec = tms.tv_nsec % 1000000000L;
|
||||
int err;
|
||||
if ((err = pthread_cond_timedwait(&cond->id, target_mutex, &tms))) {
|
||||
assert(err != EPERM);
|
||||
assert(err != EINVAL);
|
||||
}
|
||||
if (!locked_mutex)
|
||||
assert_no_err(pthread_mutex_unlock(target_mutex));
|
||||
#endif
|
||||
}
|
||||
|
||||
void soundio_os_cond_wait(struct SoundIoOsCond *cond,
|
||||
struct SoundIoOsMutex *locked_mutex)
|
||||
{
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
CRITICAL_SECTION *target_cs;
|
||||
if (locked_mutex) {
|
||||
target_cs = &locked_mutex->id;
|
||||
} else {
|
||||
target_cs = &cond->default_cs_id;
|
||||
EnterCriticalSection(&cond->default_cs_id);
|
||||
}
|
||||
SleepConditionVariableCS(&cond->id, target_cs, INFINITE);
|
||||
if (!locked_mutex)
|
||||
LeaveCriticalSection(&cond->default_cs_id);
|
||||
#elif defined(SOUNDIO_OS_KQUEUE)
|
||||
struct kevent kev;
|
||||
struct kevent out_kev;
|
||||
|
||||
if (locked_mutex)
|
||||
assert_no_err(pthread_mutex_unlock(&locked_mutex->id));
|
||||
|
||||
memset(&kev, 0, sizeof(kev));
|
||||
kev.ident = notify_ident;
|
||||
kev.filter = EVFILT_USER;
|
||||
kev.flags = EV_ADD | EV_CLEAR;
|
||||
|
||||
if (kevent(cond->kq_id, &kev, 1, &out_kev, 1, NULL) == -1) {
|
||||
if (errno == EINTR)
|
||||
return;
|
||||
assert(0); // kevent wait error
|
||||
}
|
||||
if (locked_mutex)
|
||||
assert_no_err(pthread_mutex_lock(&locked_mutex->id));
|
||||
#else
|
||||
pthread_mutex_t *target_mutex;
|
||||
if (locked_mutex) {
|
||||
target_mutex = &locked_mutex->id;
|
||||
} else {
|
||||
target_mutex = &cond->default_mutex_id;
|
||||
assert_no_err(pthread_mutex_lock(&cond->default_mutex_id));
|
||||
}
|
||||
int err;
|
||||
if ((err = pthread_cond_wait(&cond->id, target_mutex))) {
|
||||
assert(err != EPERM);
|
||||
assert(err != EINVAL);
|
||||
}
|
||||
if (!locked_mutex)
|
||||
assert_no_err(pthread_mutex_unlock(&cond->default_mutex_id));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int internal_init(void) {
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
unsigned __int64 frequency;
|
||||
if (QueryPerformanceFrequency((LARGE_INTEGER*) &frequency)) {
|
||||
win32_time_resolution = 1.0 / (double) frequency;
|
||||
} else {
|
||||
return SoundIoErrorSystemResources;
|
||||
}
|
||||
GetSystemInfo(&win32_system_info);
|
||||
page_size = win32_system_info.dwAllocationGranularity;
|
||||
#else
|
||||
page_size = sysconf(_SC_PAGESIZE);
|
||||
#if defined(__MACH__)
|
||||
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
|
||||
#endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int soundio_os_init(void) {
|
||||
int err;
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
PVOID lpContext;
|
||||
BOOL pending;
|
||||
|
||||
if (!InitOnceBeginInitialize(&win32_init_once, INIT_ONCE_ASYNC, &pending, &lpContext))
|
||||
return SoundIoErrorSystemResources;
|
||||
|
||||
if (!pending)
|
||||
return 0;
|
||||
|
||||
if ((err = internal_init()))
|
||||
return err;
|
||||
|
||||
if (!InitOnceComplete(&win32_init_once, INIT_ONCE_ASYNC, NULL))
|
||||
return SoundIoErrorSystemResources;
|
||||
#else
|
||||
assert_no_err(pthread_mutex_lock(&init_mutex));
|
||||
if (initialized) {
|
||||
assert_no_err(pthread_mutex_unlock(&init_mutex));
|
||||
return 0;
|
||||
}
|
||||
initialized = true;
|
||||
if ((err = internal_init()))
|
||||
return err;
|
||||
assert_no_err(pthread_mutex_unlock(&init_mutex));
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int soundio_os_page_size(void) {
|
||||
return page_size;
|
||||
}
|
||||
|
||||
static inline size_t ceil_dbl_to_size_t(double x) {
|
||||
const double truncation = (size_t)x;
|
||||
return truncation + (truncation < x);
|
||||
}
|
||||
|
||||
int soundio_os_init_mirrored_memory(struct SoundIoOsMirroredMemory *mem, size_t requested_capacity) {
|
||||
size_t actual_capacity = ceil_dbl_to_size_t(requested_capacity / (double)page_size) * page_size;
|
||||
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
BOOL ok;
|
||||
HANDLE hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, actual_capacity * 2, NULL);
|
||||
if (!hMapFile)
|
||||
return SoundIoErrorNoMem;
|
||||
|
||||
for (;;) {
|
||||
// find a free address space with the correct size
|
||||
char *address = (char*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, actual_capacity * 2);
|
||||
if (!address) {
|
||||
ok = CloseHandle(hMapFile);
|
||||
assert(ok);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
// found a big enough address space. hopefully it will remain free
|
||||
// while we map to it. if not, we'll try again.
|
||||
ok = UnmapViewOfFile(address);
|
||||
assert(ok);
|
||||
|
||||
char *addr1 = (char*)MapViewOfFileEx(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, actual_capacity, address);
|
||||
if (addr1 != address) {
|
||||
DWORD err = GetLastError();
|
||||
if (err == ERROR_INVALID_ADDRESS) {
|
||||
continue;
|
||||
} else {
|
||||
ok = CloseHandle(hMapFile);
|
||||
assert(ok);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
}
|
||||
|
||||
char *addr2 = (char*)MapViewOfFileEx(hMapFile, FILE_MAP_WRITE, 0, 0,
|
||||
actual_capacity, address + actual_capacity);
|
||||
if (addr2 != address + actual_capacity) {
|
||||
ok = UnmapViewOfFile(addr1);
|
||||
assert(ok);
|
||||
|
||||
DWORD err = GetLastError();
|
||||
if (err == ERROR_INVALID_ADDRESS) {
|
||||
continue;
|
||||
} else {
|
||||
ok = CloseHandle(hMapFile);
|
||||
assert(ok);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
}
|
||||
|
||||
mem->priv = hMapFile;
|
||||
mem->address = address;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
char shm_path[] = "/dev/shm/soundio-XXXXXX";
|
||||
char tmp_path[] = "/tmp/soundio-XXXXXX";
|
||||
char *chosen_path;
|
||||
|
||||
int fd = mkstemp(shm_path);
|
||||
if (fd < 0) {
|
||||
fd = mkstemp(tmp_path);
|
||||
if (fd < 0) {
|
||||
return SoundIoErrorSystemResources;
|
||||
} else {
|
||||
chosen_path = tmp_path;
|
||||
}
|
||||
} else {
|
||||
chosen_path = shm_path;
|
||||
}
|
||||
|
||||
if (unlink(chosen_path)) {
|
||||
close(fd);
|
||||
return SoundIoErrorSystemResources;
|
||||
}
|
||||
|
||||
if (ftruncate(fd, actual_capacity)) {
|
||||
close(fd);
|
||||
return SoundIoErrorSystemResources;
|
||||
}
|
||||
|
||||
char *address = (char*)mmap(NULL, actual_capacity * 2, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
if (address == MAP_FAILED) {
|
||||
close(fd);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
char *other_address = (char*)mmap(address, actual_capacity, PROT_READ|PROT_WRITE,
|
||||
MAP_FIXED|MAP_SHARED, fd, 0);
|
||||
if (other_address != address) {
|
||||
munmap(address, 2 * actual_capacity);
|
||||
close(fd);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
other_address = (char*)mmap(address + actual_capacity, actual_capacity,
|
||||
PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, fd, 0);
|
||||
if (other_address != address + actual_capacity) {
|
||||
munmap(address, 2 * actual_capacity);
|
||||
close(fd);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
mem->address = address;
|
||||
|
||||
if (close(fd))
|
||||
return SoundIoErrorSystemResources;
|
||||
#endif
|
||||
|
||||
mem->capacity = actual_capacity;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void soundio_os_deinit_mirrored_memory(struct SoundIoOsMirroredMemory *mem) {
|
||||
if (!mem->address)
|
||||
return;
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
BOOL ok;
|
||||
ok = UnmapViewOfFile(mem->address);
|
||||
assert(ok);
|
||||
ok = UnmapViewOfFile(mem->address + mem->capacity);
|
||||
assert(ok);
|
||||
ok = CloseHandle((HANDLE)mem->priv);
|
||||
assert(ok);
|
||||
#else
|
||||
int err = munmap(mem->address, 2 * mem->capacity);
|
||||
assert(!err);
|
||||
#endif
|
||||
mem->address = NULL;
|
||||
}
|
67
thirdparty/libsoundio/src/os.h
vendored
67
thirdparty/libsoundio/src/os.h
vendored
@ -1,67 +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_OS_H
|
||||
#define SOUNDIO_OS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// safe to call from any thread(s) multiple times, but
|
||||
// must be called at least once before calling any other os functions
|
||||
// soundio_create calls this function.
|
||||
int soundio_os_init(void);
|
||||
|
||||
double soundio_os_get_time(void);
|
||||
|
||||
struct SoundIoOsThread;
|
||||
int soundio_os_thread_create(
|
||||
void (*run)(void *arg), void *arg,
|
||||
void (*emit_rtprio_warning)(void),
|
||||
struct SoundIoOsThread ** out_thread);
|
||||
|
||||
void soundio_os_thread_destroy(struct SoundIoOsThread *thread);
|
||||
|
||||
|
||||
struct SoundIoOsMutex;
|
||||
struct SoundIoOsMutex *soundio_os_mutex_create(void);
|
||||
void soundio_os_mutex_destroy(struct SoundIoOsMutex *mutex);
|
||||
void soundio_os_mutex_lock(struct SoundIoOsMutex *mutex);
|
||||
void soundio_os_mutex_unlock(struct SoundIoOsMutex *mutex);
|
||||
|
||||
struct SoundIoOsCond;
|
||||
struct SoundIoOsCond *soundio_os_cond_create(void);
|
||||
void soundio_os_cond_destroy(struct SoundIoOsCond *cond);
|
||||
|
||||
// locked_mutex is optional. On systems that use mutexes for conditions, if you
|
||||
// pass NULL, a mutex will be created and locked/unlocked for you. On systems
|
||||
// that do not use mutexes for conditions, no mutex handling is necessary. If
|
||||
// you already have a locked mutex available, pass it; this will be better on
|
||||
// systems that use mutexes for conditions.
|
||||
void soundio_os_cond_signal(struct SoundIoOsCond *cond,
|
||||
struct SoundIoOsMutex *locked_mutex);
|
||||
void soundio_os_cond_timed_wait(struct SoundIoOsCond *cond,
|
||||
struct SoundIoOsMutex *locked_mutex, double seconds);
|
||||
void soundio_os_cond_wait(struct SoundIoOsCond *cond,
|
||||
struct SoundIoOsMutex *locked_mutex);
|
||||
|
||||
|
||||
int soundio_os_page_size(void);
|
||||
|
||||
// You may rely on the size of this struct as part of the API and ABI.
|
||||
struct SoundIoOsMirroredMemory {
|
||||
size_t capacity;
|
||||
char *address;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
// returned capacity might be increased from capacity to be a multiple of the
|
||||
// system page size
|
||||
int soundio_os_init_mirrored_memory(struct SoundIoOsMirroredMemory *mem, size_t capacity);
|
||||
void soundio_os_deinit_mirrored_memory(struct SoundIoOsMirroredMemory *mem);
|
||||
|
||||
#endif
|
1148
thirdparty/libsoundio/src/pulseaudio.c
vendored
1148
thirdparty/libsoundio/src/pulseaudio.c
vendored
File diff suppressed because it is too large
Load Diff
65
thirdparty/libsoundio/src/pulseaudio.h
vendored
65
thirdparty/libsoundio/src/pulseaudio.h
vendored
@ -1,65 +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_PULSEAUDIO_H
|
||||
#define SOUNDIO_PULSEAUDIO_H
|
||||
|
||||
#include "soundio_internal.h"
|
||||
#include "atomics.h"
|
||||
|
||||
#include <pulse/pulseaudio.h>
|
||||
|
||||
struct SoundIoPrivate;
|
||||
int soundio_pulseaudio_init(struct SoundIoPrivate *si);
|
||||
|
||||
struct SoundIoDevicePulseAudio { int make_the_struct_not_empty; };
|
||||
|
||||
struct SoundIoPulseAudio {
|
||||
int device_query_err;
|
||||
int connection_err;
|
||||
bool emitted_shutdown_cb;
|
||||
|
||||
pa_context *pulse_context;
|
||||
bool device_scan_queued;
|
||||
|
||||
// the one that we're working on building
|
||||
struct SoundIoDevicesInfo *current_devices_info;
|
||||
char *default_sink_name;
|
||||
char *default_source_name;
|
||||
|
||||
// this one is ready to be read with flush_events. protected by mutex
|
||||
struct SoundIoDevicesInfo *ready_devices_info;
|
||||
|
||||
bool ready_flag;
|
||||
|
||||
pa_threaded_mainloop *main_loop;
|
||||
pa_proplist *props;
|
||||
};
|
||||
|
||||
struct SoundIoOutStreamPulseAudio {
|
||||
pa_stream *stream;
|
||||
struct SoundIoAtomicBool stream_ready;
|
||||
pa_buffer_attr buffer_attr;
|
||||
char *write_ptr;
|
||||
size_t write_byte_count;
|
||||
struct SoundIoAtomicFlag clear_buffer_flag;
|
||||
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct SoundIoInStreamPulseAudio {
|
||||
pa_stream *stream;
|
||||
struct SoundIoAtomicBool stream_ready;
|
||||
pa_buffer_attr buffer_attr;
|
||||
char *peek_buf;
|
||||
size_t peek_buf_index;
|
||||
size_t peek_buf_size;
|
||||
int peek_buf_frames_left;
|
||||
int read_frame_count;
|
||||
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
#endif
|
98
thirdparty/libsoundio/src/ring_buffer.c
vendored
98
thirdparty/libsoundio/src/ring_buffer.c
vendored
@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Andrew Kelley
|
||||
*
|
||||
* This file is part of libsoundio, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "ring_buffer.h"
|
||||
#include "soundio_private.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
struct SoundIoRingBuffer *soundio_ring_buffer_create(struct SoundIo *soundio, int requested_capacity) {
|
||||
struct SoundIoRingBuffer *rb = ALLOCATE(struct SoundIoRingBuffer, 1);
|
||||
|
||||
assert(requested_capacity > 0);
|
||||
|
||||
if (!rb) {
|
||||
soundio_ring_buffer_destroy(rb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (soundio_ring_buffer_init(rb, requested_capacity)) {
|
||||
soundio_ring_buffer_destroy(rb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rb;
|
||||
}
|
||||
|
||||
void soundio_ring_buffer_destroy(struct SoundIoRingBuffer *rb) {
|
||||
if (!rb)
|
||||
return;
|
||||
|
||||
soundio_ring_buffer_deinit(rb);
|
||||
|
||||
free(rb);
|
||||
}
|
||||
|
||||
int soundio_ring_buffer_capacity(struct SoundIoRingBuffer *rb) {
|
||||
return rb->capacity;
|
||||
}
|
||||
|
||||
char *soundio_ring_buffer_write_ptr(struct SoundIoRingBuffer *rb) {
|
||||
unsigned 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) {
|
||||
SOUNDIO_ATOMIC_FETCH_ADD(rb->write_offset, count);
|
||||
assert(soundio_ring_buffer_fill_count(rb) >= 0);
|
||||
}
|
||||
|
||||
char *soundio_ring_buffer_read_ptr(struct SoundIoRingBuffer *rb) {
|
||||
unsigned 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) {
|
||||
SOUNDIO_ATOMIC_FETCH_ADD(rb->read_offset, count);
|
||||
assert(soundio_ring_buffer_fill_count(rb) >= 0);
|
||||
}
|
||||
|
||||
int soundio_ring_buffer_fill_count(struct SoundIoRingBuffer *rb) {
|
||||
// Whichever offset we load first might have a smaller value. So we load
|
||||
// the read_offset first.
|
||||
unsigned long read_offset = SOUNDIO_ATOMIC_LOAD(rb->read_offset);
|
||||
unsigned long write_offset = SOUNDIO_ATOMIC_LOAD(rb->write_offset);
|
||||
int count = write_offset - read_offset;
|
||||
assert(count >= 0);
|
||||
assert(count <= rb->capacity);
|
||||
return count;
|
||||
}
|
||||
|
||||
int soundio_ring_buffer_free_count(struct SoundIoRingBuffer *rb) {
|
||||
return rb->capacity - soundio_ring_buffer_fill_count(rb);
|
||||
}
|
||||
|
||||
void soundio_ring_buffer_clear(struct SoundIoRingBuffer *rb) {
|
||||
unsigned long read_offset = SOUNDIO_ATOMIC_LOAD(rb->read_offset);
|
||||
SOUNDIO_ATOMIC_STORE(rb->write_offset, read_offset);
|
||||
}
|
||||
|
||||
int soundio_ring_buffer_init(struct SoundIoRingBuffer *rb, int requested_capacity) {
|
||||
int err;
|
||||
if ((err = soundio_os_init_mirrored_memory(&rb->mem, requested_capacity)))
|
||||
return err;
|
||||
SOUNDIO_ATOMIC_STORE(rb->write_offset, 0);
|
||||
SOUNDIO_ATOMIC_STORE(rb->read_offset, 0);
|
||||
rb->capacity = rb->mem.capacity;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void soundio_ring_buffer_deinit(struct SoundIoRingBuffer *rb) {
|
||||
soundio_os_deinit_mirrored_memory(&rb->mem);
|
||||
}
|
24
thirdparty/libsoundio/src/ring_buffer.h
vendored
24
thirdparty/libsoundio/src/ring_buffer.h
vendored
@ -1,24 +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_RING_BUFFER_H
|
||||
#define SOUNDIO_RING_BUFFER_H
|
||||
|
||||
#include "os.h"
|
||||
#include "atomics.h"
|
||||
|
||||
struct SoundIoRingBuffer {
|
||||
struct SoundIoOsMirroredMemory mem;
|
||||
struct SoundIoAtomicULong write_offset;
|
||||
struct SoundIoAtomicULong read_offset;
|
||||
int capacity;
|
||||
};
|
||||
|
||||
int soundio_ring_buffer_init(struct SoundIoRingBuffer *rb, int requested_capacity);
|
||||
void soundio_ring_buffer_deinit(struct SoundIoRingBuffer *rb);
|
||||
|
||||
#endif
|
833
thirdparty/libsoundio/src/soundio.c
vendored
833
thirdparty/libsoundio/src/soundio.c
vendored
@ -1,833 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Andrew Kelley
|
||||
*
|
||||
* This file is part of libsoundio, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "soundio_private.h"
|
||||
#include "util.h"
|
||||
#include "os.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static const enum SoundIoBackend available_backends[] = {
|
||||
#ifdef SOUNDIO_HAVE_JACK
|
||||
SoundIoBackendJack,
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
||||
SoundIoBackendPulseAudio,
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_ALSA
|
||||
SoundIoBackendAlsa,
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_COREAUDIO
|
||||
SoundIoBackendCoreAudio,
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_WASAPI
|
||||
SoundIoBackendWasapi,
|
||||
#endif
|
||||
SoundIoBackendDummy,
|
||||
};
|
||||
|
||||
typedef int (*backend_init_t)(struct SoundIoPrivate *);
|
||||
static backend_init_t backend_init_fns[] = {
|
||||
NULL, // None backend
|
||||
|
||||
#ifdef SOUNDIO_HAVE_JACK
|
||||
&soundio_jack_init,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
|
||||
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
||||
&soundio_pulseaudio_init,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
|
||||
#ifdef SOUNDIO_HAVE_ALSA
|
||||
&soundio_alsa_init,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
|
||||
#ifdef SOUNDIO_HAVE_COREAUDIO
|
||||
&soundio_coreaudio_init,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
|
||||
#ifdef SOUNDIO_HAVE_WASAPI
|
||||
soundio_wasapi_init,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
|
||||
&soundio_dummy_init,
|
||||
};
|
||||
|
||||
SOUNDIO_MAKE_LIST_DEF(struct SoundIoDevice*, SoundIoListDevicePtr, SOUNDIO_LIST_NOT_STATIC)
|
||||
SOUNDIO_MAKE_LIST_DEF(struct SoundIoSampleRateRange, SoundIoListSampleRateRange, SOUNDIO_LIST_NOT_STATIC)
|
||||
|
||||
const char *soundio_strerror(int error) {
|
||||
switch ((enum SoundIoError)error) {
|
||||
case SoundIoErrorNone: return "(no error)";
|
||||
case SoundIoErrorNoMem: return "out of memory";
|
||||
case SoundIoErrorInitAudioBackend: return "unable to initialize audio backend";
|
||||
case SoundIoErrorSystemResources: return "system resource not available";
|
||||
case SoundIoErrorOpeningDevice: return "unable to open device";
|
||||
case SoundIoErrorNoSuchDevice: return "no such device";
|
||||
case SoundIoErrorInvalid: return "invalid value";
|
||||
case SoundIoErrorBackendUnavailable: return "backend unavailable";
|
||||
case SoundIoErrorStreaming: return "unrecoverable streaming failure";
|
||||
case SoundIoErrorIncompatibleDevice: return "incompatible device";
|
||||
case SoundIoErrorNoSuchClient: return "no such client";
|
||||
case SoundIoErrorIncompatibleBackend: return "incompatible backend";
|
||||
case SoundIoErrorBackendDisconnected: return "backend disconnected";
|
||||
case SoundIoErrorInterrupted: return "interrupted; try again";
|
||||
case SoundIoErrorUnderflow: return "buffer underflow";
|
||||
case SoundIoErrorEncodingString: return "failed to encode string";
|
||||
}
|
||||
return "(invalid error)";
|
||||
}
|
||||
|
||||
int soundio_get_bytes_per_sample(enum SoundIoFormat format) {
|
||||
switch (format) {
|
||||
case SoundIoFormatU8: return 1;
|
||||
case SoundIoFormatS8: return 1;
|
||||
case SoundIoFormatS16LE: return 2;
|
||||
case SoundIoFormatS16BE: return 2;
|
||||
case SoundIoFormatU16LE: return 2;
|
||||
case SoundIoFormatU16BE: return 2;
|
||||
case SoundIoFormatS24LE: return 4;
|
||||
case SoundIoFormatS24BE: return 4;
|
||||
case SoundIoFormatU24LE: return 4;
|
||||
case SoundIoFormatU24BE: return 4;
|
||||
case SoundIoFormatS32LE: return 4;
|
||||
case SoundIoFormatS32BE: return 4;
|
||||
case SoundIoFormatU32LE: return 4;
|
||||
case SoundIoFormatU32BE: return 4;
|
||||
case SoundIoFormatFloat32LE: return 4;
|
||||
case SoundIoFormatFloat32BE: return 4;
|
||||
case SoundIoFormatFloat64LE: return 8;
|
||||
case SoundIoFormatFloat64BE: return 8;
|
||||
|
||||
case SoundIoFormatInvalid: return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char * soundio_format_string(enum SoundIoFormat format) {
|
||||
switch (format) {
|
||||
case SoundIoFormatS8: return "signed 8-bit";
|
||||
case SoundIoFormatU8: return "unsigned 8-bit";
|
||||
case SoundIoFormatS16LE: return "signed 16-bit LE";
|
||||
case SoundIoFormatS16BE: return "signed 16-bit BE";
|
||||
case SoundIoFormatU16LE: return "unsigned 16-bit LE";
|
||||
case SoundIoFormatU16BE: return "unsigned 16-bit LE";
|
||||
case SoundIoFormatS24LE: return "signed 24-bit LE";
|
||||
case SoundIoFormatS24BE: return "signed 24-bit BE";
|
||||
case SoundIoFormatU24LE: return "unsigned 24-bit LE";
|
||||
case SoundIoFormatU24BE: return "unsigned 24-bit BE";
|
||||
case SoundIoFormatS32LE: return "signed 32-bit LE";
|
||||
case SoundIoFormatS32BE: return "signed 32-bit BE";
|
||||
case SoundIoFormatU32LE: return "unsigned 32-bit LE";
|
||||
case SoundIoFormatU32BE: return "unsigned 32-bit BE";
|
||||
case SoundIoFormatFloat32LE: return "float 32-bit LE";
|
||||
case SoundIoFormatFloat32BE: return "float 32-bit BE";
|
||||
case SoundIoFormatFloat64LE: return "float 64-bit LE";
|
||||
case SoundIoFormatFloat64BE: return "float 64-bit BE";
|
||||
|
||||
case SoundIoFormatInvalid:
|
||||
return "(invalid sample format)";
|
||||
}
|
||||
return "(invalid sample format)";
|
||||
}
|
||||
|
||||
|
||||
const char *soundio_backend_name(enum SoundIoBackend backend) {
|
||||
switch (backend) {
|
||||
case SoundIoBackendNone: return "(none)";
|
||||
case SoundIoBackendJack: return "JACK";
|
||||
case SoundIoBackendPulseAudio: return "PulseAudio";
|
||||
case SoundIoBackendAlsa: return "ALSA";
|
||||
case SoundIoBackendCoreAudio: return "CoreAudio";
|
||||
case SoundIoBackendWasapi: return "WASAPI";
|
||||
case SoundIoBackendDummy: return "Dummy";
|
||||
}
|
||||
return "(invalid backend)";
|
||||
}
|
||||
|
||||
void soundio_destroy(struct SoundIo *soundio) {
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
|
||||
soundio_disconnect(soundio);
|
||||
|
||||
free(si);
|
||||
}
|
||||
|
||||
static void do_nothing_cb(struct SoundIo *soundio) { }
|
||||
static void default_msg_callback(const char *msg) { }
|
||||
|
||||
static void default_backend_disconnect_cb(struct SoundIo *soundio, int err) {
|
||||
soundio_panic("libsoundio: backend disconnected: %s", soundio_strerror(err));
|
||||
}
|
||||
|
||||
static struct SoundIoAtomicFlag rtprio_seen = SOUNDIO_ATOMIC_FLAG_INIT;
|
||||
static void default_emit_rtprio_warning(void) {
|
||||
if (!SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(rtprio_seen)) {
|
||||
fprintf(stderr, "warning: unable to set high priority thread: Operation not permitted\n");
|
||||
fprintf(stderr, "See "
|
||||
"https://github.com/andrewrk/genesis/wiki/warning:-unable-to-set-high-priority-thread:-Operation-not-permitted\n");
|
||||
}
|
||||
}
|
||||
|
||||
struct SoundIo *soundio_create(void) {
|
||||
int err;
|
||||
if ((err = soundio_os_init()))
|
||||
return NULL;
|
||||
struct SoundIoPrivate *si = ALLOCATE(struct SoundIoPrivate, 1);
|
||||
if (!si)
|
||||
return NULL;
|
||||
struct SoundIo *soundio = &si->pub;
|
||||
soundio->on_devices_change = do_nothing_cb;
|
||||
soundio->on_backend_disconnect = default_backend_disconnect_cb;
|
||||
soundio->on_events_signal = do_nothing_cb;
|
||||
soundio->app_name = "SoundIo";
|
||||
soundio->emit_rtprio_warning = default_emit_rtprio_warning;
|
||||
soundio->jack_info_callback = default_msg_callback;
|
||||
soundio->jack_error_callback = default_msg_callback;
|
||||
return soundio;
|
||||
}
|
||||
|
||||
int soundio_connect(struct SoundIo *soundio) {
|
||||
int err = 0;
|
||||
|
||||
for (int i = 0; i < ARRAY_LENGTH(available_backends); i += 1) {
|
||||
enum SoundIoBackend backend = available_backends[i];
|
||||
err = soundio_connect_backend(soundio, backend);
|
||||
if (!err)
|
||||
return 0;
|
||||
if (err != SoundIoErrorInitAudioBackend)
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int soundio_connect_backend(struct SoundIo *soundio, enum SoundIoBackend backend) {
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
|
||||
if (soundio->current_backend)
|
||||
return SoundIoErrorInvalid;
|
||||
|
||||
if (backend <= 0 || backend > SoundIoBackendDummy)
|
||||
return SoundIoErrorInvalid;
|
||||
|
||||
int (*fn)(struct SoundIoPrivate *) = backend_init_fns[backend];
|
||||
|
||||
if (!fn)
|
||||
return SoundIoErrorBackendUnavailable;
|
||||
|
||||
int err;
|
||||
if ((err = backend_init_fns[backend](si))) {
|
||||
soundio_disconnect(soundio);
|
||||
return err;
|
||||
}
|
||||
soundio->current_backend = backend;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void soundio_disconnect(struct SoundIo *soundio) {
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
|
||||
if (!si)
|
||||
return;
|
||||
|
||||
if (si->destroy)
|
||||
si->destroy(si);
|
||||
memset(&si->backend_data, 0, sizeof(union SoundIoBackendData));
|
||||
|
||||
soundio->current_backend = SoundIoBackendNone;
|
||||
|
||||
soundio_destroy_devices_info(si->safe_devices_info);
|
||||
si->safe_devices_info = NULL;
|
||||
|
||||
si->destroy = NULL;
|
||||
si->flush_events = NULL;
|
||||
si->wait_events = NULL;
|
||||
si->wakeup = NULL;
|
||||
si->force_device_scan = NULL;
|
||||
|
||||
si->outstream_open = NULL;
|
||||
si->outstream_destroy = NULL;
|
||||
si->outstream_start = NULL;
|
||||
si->outstream_begin_write = NULL;
|
||||
si->outstream_end_write = NULL;
|
||||
si->outstream_clear_buffer = NULL;
|
||||
si->outstream_pause = NULL;
|
||||
si->outstream_get_latency = NULL;
|
||||
si->outstream_set_volume = NULL;
|
||||
|
||||
si->instream_open = NULL;
|
||||
si->instream_destroy = NULL;
|
||||
si->instream_start = NULL;
|
||||
si->instream_begin_read = NULL;
|
||||
si->instream_end_read = NULL;
|
||||
si->instream_pause = NULL;
|
||||
si->instream_get_latency = NULL;
|
||||
}
|
||||
|
||||
void soundio_flush_events(struct SoundIo *soundio) {
|
||||
assert(soundio->current_backend != SoundIoBackendNone);
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
si->flush_events(si);
|
||||
}
|
||||
|
||||
int soundio_input_device_count(struct SoundIo *soundio) {
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
|
||||
assert(si->safe_devices_info);
|
||||
if (!si->safe_devices_info)
|
||||
return -1;
|
||||
|
||||
assert(soundio->current_backend != SoundIoBackendNone);
|
||||
if (soundio->current_backend == SoundIoBackendNone)
|
||||
return -1;
|
||||
|
||||
return si->safe_devices_info->input_devices.length;
|
||||
}
|
||||
|
||||
int soundio_output_device_count(struct SoundIo *soundio) {
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
|
||||
assert(si->safe_devices_info);
|
||||
if (!si->safe_devices_info)
|
||||
return -1;
|
||||
|
||||
assert(soundio->current_backend != SoundIoBackendNone);
|
||||
if (soundio->current_backend == SoundIoBackendNone)
|
||||
return -1;
|
||||
|
||||
return si->safe_devices_info->output_devices.length;
|
||||
}
|
||||
|
||||
int soundio_default_input_device_index(struct SoundIo *soundio) {
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
|
||||
assert(si->safe_devices_info);
|
||||
if (!si->safe_devices_info)
|
||||
return -1;
|
||||
|
||||
assert(soundio->current_backend != SoundIoBackendNone);
|
||||
if (soundio->current_backend == SoundIoBackendNone)
|
||||
return -1;
|
||||
|
||||
return si->safe_devices_info->default_input_index;
|
||||
}
|
||||
|
||||
int soundio_default_output_device_index(struct SoundIo *soundio) {
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
|
||||
assert(si->safe_devices_info);
|
||||
if (!si->safe_devices_info)
|
||||
return -1;
|
||||
|
||||
assert(soundio->current_backend != SoundIoBackendNone);
|
||||
if (soundio->current_backend == SoundIoBackendNone)
|
||||
return -1;
|
||||
|
||||
return si->safe_devices_info->default_output_index;
|
||||
}
|
||||
|
||||
struct SoundIoDevice *soundio_get_input_device(struct SoundIo *soundio, int index) {
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
|
||||
assert(soundio->current_backend != SoundIoBackendNone);
|
||||
if (soundio->current_backend == SoundIoBackendNone)
|
||||
return NULL;
|
||||
|
||||
assert(si->safe_devices_info);
|
||||
if (!si->safe_devices_info)
|
||||
return NULL;
|
||||
|
||||
assert(index >= 0);
|
||||
assert(index < si->safe_devices_info->input_devices.length);
|
||||
if (index < 0 || index >= si->safe_devices_info->input_devices.length)
|
||||
return NULL;
|
||||
|
||||
struct SoundIoDevice *device = SoundIoListDevicePtr_val_at(&si->safe_devices_info->input_devices, index);
|
||||
soundio_device_ref(device);
|
||||
return device;
|
||||
}
|
||||
|
||||
struct SoundIoDevice *soundio_get_output_device(struct SoundIo *soundio, int index) {
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
|
||||
assert(soundio->current_backend != SoundIoBackendNone);
|
||||
if (soundio->current_backend == SoundIoBackendNone)
|
||||
return NULL;
|
||||
|
||||
assert(si->safe_devices_info);
|
||||
if (!si->safe_devices_info)
|
||||
return NULL;
|
||||
|
||||
assert(index >= 0);
|
||||
assert(index < si->safe_devices_info->output_devices.length);
|
||||
if (index < 0 || index >= si->safe_devices_info->output_devices.length)
|
||||
return NULL;
|
||||
|
||||
struct SoundIoDevice *device = SoundIoListDevicePtr_val_at(&si->safe_devices_info->output_devices, index);
|
||||
soundio_device_ref(device);
|
||||
return device;
|
||||
}
|
||||
|
||||
void soundio_device_unref(struct SoundIoDevice *device) {
|
||||
if (!device)
|
||||
return;
|
||||
|
||||
device->ref_count -= 1;
|
||||
assert(device->ref_count >= 0);
|
||||
|
||||
if (device->ref_count == 0) {
|
||||
struct SoundIoDevicePrivate *dev = (struct SoundIoDevicePrivate *)device;
|
||||
if (dev->destruct)
|
||||
dev->destruct(dev);
|
||||
|
||||
free(device->id);
|
||||
free(device->name);
|
||||
|
||||
if (device->sample_rates != &dev->prealloc_sample_rate_range &&
|
||||
device->sample_rates != dev->sample_rates.items)
|
||||
{
|
||||
free(device->sample_rates);
|
||||
}
|
||||
SoundIoListSampleRateRange_deinit(&dev->sample_rates);
|
||||
|
||||
if (device->formats != &dev->prealloc_format)
|
||||
free(device->formats);
|
||||
|
||||
if (device->layouts != &device->current_layout)
|
||||
free(device->layouts);
|
||||
|
||||
free(dev);
|
||||
}
|
||||
}
|
||||
|
||||
void soundio_device_ref(struct SoundIoDevice *device) {
|
||||
assert(device);
|
||||
device->ref_count += 1;
|
||||
}
|
||||
|
||||
void soundio_wait_events(struct SoundIo *soundio) {
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
si->wait_events(si);
|
||||
}
|
||||
|
||||
void soundio_wakeup(struct SoundIo *soundio) {
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
si->wakeup(si);
|
||||
}
|
||||
|
||||
void soundio_force_device_scan(struct SoundIo *soundio) {
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
si->force_device_scan(si);
|
||||
}
|
||||
|
||||
int soundio_outstream_begin_write(struct SoundIoOutStream *outstream,
|
||||
struct SoundIoChannelArea **areas, int *frame_count)
|
||||
{
|
||||
struct SoundIo *soundio = outstream->device->soundio;
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
|
||||
if (*frame_count <= 0)
|
||||
return SoundIoErrorInvalid;
|
||||
return si->outstream_begin_write(si, os, areas, frame_count);
|
||||
}
|
||||
|
||||
int soundio_outstream_end_write(struct SoundIoOutStream *outstream) {
|
||||
struct SoundIo *soundio = outstream->device->soundio;
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
|
||||
return si->outstream_end_write(si, os);
|
||||
}
|
||||
|
||||
static void default_outstream_error_callback(struct SoundIoOutStream *os, int err) {
|
||||
soundio_panic("libsoundio: %s", soundio_strerror(err));
|
||||
}
|
||||
|
||||
static void default_underflow_callback(struct SoundIoOutStream *outstream) { }
|
||||
|
||||
struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device) {
|
||||
struct SoundIoOutStreamPrivate *os = ALLOCATE(struct SoundIoOutStreamPrivate, 1);
|
||||
struct SoundIoOutStream *outstream = &os->pub;
|
||||
|
||||
if (!os)
|
||||
return NULL;
|
||||
if (!device)
|
||||
return NULL;
|
||||
|
||||
outstream->device = device;
|
||||
soundio_device_ref(device);
|
||||
|
||||
outstream->error_callback = default_outstream_error_callback;
|
||||
outstream->underflow_callback = default_underflow_callback;
|
||||
|
||||
return outstream;
|
||||
}
|
||||
|
||||
int soundio_outstream_open(struct SoundIoOutStream *outstream) {
|
||||
struct SoundIoDevice *device = outstream->device;
|
||||
|
||||
if (device->aim != SoundIoDeviceAimOutput)
|
||||
return SoundIoErrorInvalid;
|
||||
|
||||
if (device->probe_error)
|
||||
return device->probe_error;
|
||||
|
||||
if (outstream->layout.channel_count > SOUNDIO_MAX_CHANNELS)
|
||||
return SoundIoErrorInvalid;
|
||||
|
||||
if (outstream->format == SoundIoFormatInvalid) {
|
||||
outstream->format = soundio_device_supports_format(device, SoundIoFormatFloat32NE) ?
|
||||
SoundIoFormatFloat32NE : device->formats[0];
|
||||
}
|
||||
|
||||
if (outstream->format <= SoundIoFormatInvalid)
|
||||
return SoundIoErrorInvalid;
|
||||
|
||||
if (!outstream->layout.channel_count) {
|
||||
const struct SoundIoChannelLayout *stereo = soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdStereo);
|
||||
outstream->layout = soundio_device_supports_layout(device, stereo) ? *stereo : device->layouts[0];
|
||||
}
|
||||
|
||||
if (!outstream->sample_rate)
|
||||
outstream->sample_rate = soundio_device_nearest_sample_rate(device, 48000);
|
||||
|
||||
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
|
||||
outstream->bytes_per_frame = soundio_get_bytes_per_frame(outstream->format, outstream->layout.channel_count);
|
||||
outstream->bytes_per_sample = soundio_get_bytes_per_sample(outstream->format);
|
||||
|
||||
struct SoundIo *soundio = device->soundio;
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
return si->outstream_open(si, os);
|
||||
}
|
||||
|
||||
void soundio_outstream_destroy(struct SoundIoOutStream *outstream) {
|
||||
if (!outstream)
|
||||
return;
|
||||
|
||||
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
|
||||
struct SoundIo *soundio = outstream->device->soundio;
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
|
||||
if (si->outstream_destroy)
|
||||
si->outstream_destroy(si, os);
|
||||
|
||||
soundio_device_unref(outstream->device);
|
||||
free(os);
|
||||
}
|
||||
|
||||
int soundio_outstream_start(struct SoundIoOutStream *outstream) {
|
||||
struct SoundIo *soundio = outstream->device->soundio;
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
|
||||
return si->outstream_start(si, os);
|
||||
}
|
||||
|
||||
int soundio_outstream_pause(struct SoundIoOutStream *outstream, bool pause) {
|
||||
struct SoundIo *soundio = outstream->device->soundio;
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
|
||||
return si->outstream_pause(si, os, pause);
|
||||
}
|
||||
|
||||
int soundio_outstream_clear_buffer(struct SoundIoOutStream *outstream) {
|
||||
struct SoundIo *soundio = outstream->device->soundio;
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
|
||||
return si->outstream_clear_buffer(si, os);
|
||||
}
|
||||
|
||||
int soundio_outstream_get_latency(struct SoundIoOutStream *outstream, double *out_latency) {
|
||||
struct SoundIo *soundio = outstream->device->soundio;
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
|
||||
return si->outstream_get_latency(si, os, out_latency);
|
||||
}
|
||||
|
||||
int soundio_outstream_set_volume(struct SoundIoOutStream *outstream, double volume) {
|
||||
struct SoundIo *soundio = outstream->device->soundio;
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
|
||||
return si->outstream_set_volume(si, os, volume);
|
||||
}
|
||||
|
||||
static void default_instream_error_callback(struct SoundIoInStream *is, int err) {
|
||||
soundio_panic("libsoundio: %s", soundio_strerror(err));
|
||||
}
|
||||
|
||||
static void default_overflow_callback(struct SoundIoInStream *instream) { }
|
||||
|
||||
struct SoundIoInStream *soundio_instream_create(struct SoundIoDevice *device) {
|
||||
struct SoundIoInStreamPrivate *is = ALLOCATE(struct SoundIoInStreamPrivate, 1);
|
||||
struct SoundIoInStream *instream = &is->pub;
|
||||
|
||||
if (!is)
|
||||
return NULL;
|
||||
if (!device)
|
||||
return NULL;
|
||||
|
||||
instream->device = device;
|
||||
soundio_device_ref(device);
|
||||
|
||||
instream->error_callback = default_instream_error_callback;
|
||||
instream->overflow_callback = default_overflow_callback;
|
||||
|
||||
return instream;
|
||||
}
|
||||
|
||||
int soundio_instream_open(struct SoundIoInStream *instream) {
|
||||
struct SoundIoDevice *device = instream->device;
|
||||
if (device->aim != SoundIoDeviceAimInput)
|
||||
return SoundIoErrorInvalid;
|
||||
|
||||
if (instream->format <= SoundIoFormatInvalid)
|
||||
return SoundIoErrorInvalid;
|
||||
|
||||
if (instream->layout.channel_count > SOUNDIO_MAX_CHANNELS)
|
||||
return SoundIoErrorInvalid;
|
||||
|
||||
if (device->probe_error)
|
||||
return device->probe_error;
|
||||
|
||||
if (instream->format == SoundIoFormatInvalid) {
|
||||
instream->format = soundio_device_supports_format(device, SoundIoFormatFloat32NE) ?
|
||||
SoundIoFormatFloat32NE : device->formats[0];
|
||||
}
|
||||
|
||||
if (!instream->layout.channel_count) {
|
||||
const struct SoundIoChannelLayout *stereo = soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdStereo);
|
||||
instream->layout = soundio_device_supports_layout(device, stereo) ? *stereo : device->layouts[0];
|
||||
}
|
||||
|
||||
if (!instream->sample_rate)
|
||||
instream->sample_rate = soundio_device_nearest_sample_rate(device, 48000);
|
||||
|
||||
|
||||
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);
|
||||
struct SoundIo *soundio = device->soundio;
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
|
||||
return si->instream_open(si, is);
|
||||
}
|
||||
|
||||
int soundio_instream_start(struct SoundIoInStream *instream) {
|
||||
struct SoundIo *soundio = instream->device->soundio;
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
|
||||
return si->instream_start(si, is);
|
||||
}
|
||||
|
||||
void soundio_instream_destroy(struct SoundIoInStream *instream) {
|
||||
if (!instream)
|
||||
return;
|
||||
|
||||
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
|
||||
struct SoundIo *soundio = instream->device->soundio;
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
|
||||
if (si->instream_destroy)
|
||||
si->instream_destroy(si, is);
|
||||
|
||||
soundio_device_unref(instream->device);
|
||||
free(is);
|
||||
}
|
||||
|
||||
int soundio_instream_pause(struct SoundIoInStream *instream, bool pause) {
|
||||
struct SoundIo *soundio = instream->device->soundio;
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
|
||||
return si->instream_pause(si, is, pause);
|
||||
}
|
||||
|
||||
int soundio_instream_begin_read(struct SoundIoInStream *instream,
|
||||
struct SoundIoChannelArea **areas, int *frame_count)
|
||||
{
|
||||
struct SoundIo *soundio = instream->device->soundio;
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
|
||||
return si->instream_begin_read(si, is, areas, frame_count);
|
||||
}
|
||||
|
||||
int soundio_instream_end_read(struct SoundIoInStream *instream) {
|
||||
struct SoundIo *soundio = instream->device->soundio;
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
|
||||
return si->instream_end_read(si, is);
|
||||
}
|
||||
|
||||
int soundio_instream_get_latency(struct SoundIoInStream *instream, double *out_latency) {
|
||||
struct SoundIo *soundio = instream->device->soundio;
|
||||
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
|
||||
struct SoundIoInStreamPrivate *is = (struct SoundIoInStreamPrivate *)instream;
|
||||
return si->instream_get_latency(si, is, out_latency);
|
||||
}
|
||||
|
||||
void soundio_destroy_devices_info(struct SoundIoDevicesInfo *devices_info) {
|
||||
if (!devices_info)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < devices_info->input_devices.length; i += 1)
|
||||
soundio_device_unref(SoundIoListDevicePtr_val_at(&devices_info->input_devices, i));
|
||||
for (int i = 0; i < devices_info->output_devices.length; i += 1)
|
||||
soundio_device_unref(SoundIoListDevicePtr_val_at(&devices_info->output_devices, i));
|
||||
|
||||
SoundIoListDevicePtr_deinit(&devices_info->input_devices);
|
||||
SoundIoListDevicePtr_deinit(&devices_info->output_devices);
|
||||
|
||||
free(devices_info);
|
||||
}
|
||||
|
||||
bool soundio_have_backend(enum SoundIoBackend backend) {
|
||||
assert(backend > 0);
|
||||
assert(backend <= SoundIoBackendDummy);
|
||||
return backend_init_fns[backend];
|
||||
}
|
||||
|
||||
int soundio_backend_count(struct SoundIo *soundio) {
|
||||
return ARRAY_LENGTH(available_backends);
|
||||
}
|
||||
|
||||
enum SoundIoBackend soundio_get_backend(struct SoundIo *soundio, int index) {
|
||||
return available_backends[index];
|
||||
}
|
||||
|
||||
static bool layout_contains(const struct SoundIoChannelLayout *available_layouts, int available_layouts_count,
|
||||
const struct SoundIoChannelLayout *target_layout)
|
||||
{
|
||||
for (int i = 0; i < available_layouts_count; i += 1) {
|
||||
const struct SoundIoChannelLayout *available_layout = &available_layouts[i];
|
||||
if (soundio_channel_layout_equal(target_layout, available_layout))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const struct SoundIoChannelLayout *soundio_best_matching_channel_layout(
|
||||
const struct SoundIoChannelLayout *preferred_layouts, int preferred_layouts_count,
|
||||
const struct SoundIoChannelLayout *available_layouts, int available_layouts_count)
|
||||
{
|
||||
for (int i = 0; i < preferred_layouts_count; i += 1) {
|
||||
const struct SoundIoChannelLayout *preferred_layout = &preferred_layouts[i];
|
||||
if (layout_contains(available_layouts, available_layouts_count, preferred_layout))
|
||||
return preferred_layout;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int compare_layouts(const void *a, const void *b) {
|
||||
const struct SoundIoChannelLayout *layout_a = (const struct SoundIoChannelLayout *)a;
|
||||
const struct SoundIoChannelLayout *layout_b = (const struct SoundIoChannelLayout *)b;
|
||||
if (layout_a->channel_count > layout_b->channel_count)
|
||||
return -1;
|
||||
else if (layout_a->channel_count < layout_b->channel_count)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void soundio_sort_channel_layouts(struct SoundIoChannelLayout *layouts, int layouts_count) {
|
||||
if (!layouts)
|
||||
return;
|
||||
|
||||
qsort(layouts, layouts_count, sizeof(struct SoundIoChannelLayout), compare_layouts);
|
||||
}
|
||||
|
||||
void soundio_device_sort_channel_layouts(struct SoundIoDevice *device) {
|
||||
soundio_sort_channel_layouts(device->layouts, device->layout_count);
|
||||
}
|
||||
|
||||
bool soundio_device_supports_format(struct SoundIoDevice *device, enum SoundIoFormat format) {
|
||||
for (int i = 0; i < device->format_count; i += 1) {
|
||||
if (device->formats[i] == format)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool soundio_device_supports_layout(struct SoundIoDevice *device,
|
||||
const struct SoundIoChannelLayout *layout)
|
||||
{
|
||||
for (int i = 0; i < device->layout_count; i += 1) {
|
||||
if (soundio_channel_layout_equal(&device->layouts[i], layout))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool soundio_device_supports_sample_rate(struct SoundIoDevice *device, int sample_rate) {
|
||||
for (int i = 0; i < device->sample_rate_count; i += 1) {
|
||||
struct SoundIoSampleRateRange *range = &device->sample_rates[i];
|
||||
if (sample_rate >= range->min && sample_rate <= range->max)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int abs_diff_int(int a, int b) {
|
||||
int x = a - b;
|
||||
return (x >= 0) ? x : -x;
|
||||
}
|
||||
|
||||
int soundio_device_nearest_sample_rate(struct SoundIoDevice *device, int sample_rate) {
|
||||
int best_rate = -1;
|
||||
int best_delta = -1;
|
||||
for (int i = 0; i < device->sample_rate_count; i += 1) {
|
||||
struct SoundIoSampleRateRange *range = &device->sample_rates[i];
|
||||
int candidate_rate = soundio_int_clamp(range->min, sample_rate, range->max);
|
||||
if (candidate_rate == sample_rate)
|
||||
return candidate_rate;
|
||||
|
||||
int delta = abs_diff_int(candidate_rate, sample_rate);
|
||||
bool best_rate_too_small = best_rate < sample_rate;
|
||||
bool candidate_rate_too_small = candidate_rate < sample_rate;
|
||||
if (best_rate == -1 ||
|
||||
(best_rate_too_small && !candidate_rate_too_small) ||
|
||||
((best_rate_too_small || !candidate_rate_too_small) && delta < best_delta))
|
||||
{
|
||||
best_rate = candidate_rate;
|
||||
best_delta = delta;
|
||||
}
|
||||
}
|
||||
return best_rate;
|
||||
}
|
||||
|
||||
bool soundio_device_equal(
|
||||
const struct SoundIoDevice *a,
|
||||
const struct SoundIoDevice *b)
|
||||
{
|
||||
return a->is_raw == b->is_raw && a->aim == b->aim && strcmp(a->id, b->id) == 0;
|
||||
}
|
||||
|
||||
const char *soundio_version_string(void) {
|
||||
return SOUNDIO_VERSION_STRING;
|
||||
}
|
||||
|
||||
int soundio_version_major(void) {
|
||||
return SOUNDIO_VERSION_MAJOR;
|
||||
}
|
||||
|
||||
int soundio_version_minor(void) {
|
||||
return SOUNDIO_VERSION_MINOR;
|
||||
}
|
||||
|
||||
int soundio_version_patch(void) {
|
||||
return SOUNDIO_VERSION_PATCH;
|
||||
}
|
16
thirdparty/libsoundio/src/soundio_internal.h
vendored
16
thirdparty/libsoundio/src/soundio_internal.h
vendored
@ -1,16 +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_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
|
186
thirdparty/libsoundio/src/soundio_private.h
vendored
186
thirdparty/libsoundio/src/soundio_private.h
vendored
@ -1,186 +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_PRIVATE_H
|
||||
#define SOUNDIO_SOUNDIO_PRIVATE_H
|
||||
|
||||
#include "soundio_internal.h"
|
||||
#include "config.h"
|
||||
#include "list.h"
|
||||
|
||||
#ifdef SOUNDIO_HAVE_JACK
|
||||
#include "jack.h"
|
||||
#endif
|
||||
|
||||
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
||||
#include "pulseaudio.h"
|
||||
#endif
|
||||
|
||||
#ifdef SOUNDIO_HAVE_ALSA
|
||||
#include "alsa.h"
|
||||
#endif
|
||||
|
||||
#ifdef SOUNDIO_HAVE_COREAUDIO
|
||||
#include "coreaudio.h"
|
||||
#endif
|
||||
|
||||
#ifdef SOUNDIO_HAVE_WASAPI
|
||||
#include "wasapi.h"
|
||||
#endif
|
||||
|
||||
#include "dummy.h"
|
||||
|
||||
union SoundIoBackendData {
|
||||
#ifdef SOUNDIO_HAVE_JACK
|
||||
struct SoundIoJack jack;
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
||||
struct SoundIoPulseAudio pulseaudio;
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_ALSA
|
||||
struct SoundIoAlsa alsa;
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_COREAUDIO
|
||||
struct SoundIoCoreAudio coreaudio;
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_WASAPI
|
||||
struct SoundIoWasapi wasapi;
|
||||
#endif
|
||||
struct SoundIoDummy dummy;
|
||||
};
|
||||
|
||||
union SoundIoDeviceBackendData {
|
||||
#ifdef SOUNDIO_HAVE_JACK
|
||||
struct SoundIoDeviceJack jack;
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
||||
struct SoundIoDevicePulseAudio pulseaudio;
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_ALSA
|
||||
struct SoundIoDeviceAlsa alsa;
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_COREAUDIO
|
||||
struct SoundIoDeviceCoreAudio coreaudio;
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_WASAPI
|
||||
struct SoundIoDeviceWasapi wasapi;
|
||||
#endif
|
||||
struct SoundIoDeviceDummy dummy;
|
||||
};
|
||||
|
||||
union SoundIoOutStreamBackendData {
|
||||
#ifdef SOUNDIO_HAVE_JACK
|
||||
struct SoundIoOutStreamJack jack;
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
||||
struct SoundIoOutStreamPulseAudio pulseaudio;
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_ALSA
|
||||
struct SoundIoOutStreamAlsa alsa;
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_COREAUDIO
|
||||
struct SoundIoOutStreamCoreAudio coreaudio;
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_WASAPI
|
||||
struct SoundIoOutStreamWasapi wasapi;
|
||||
#endif
|
||||
struct SoundIoOutStreamDummy dummy;
|
||||
};
|
||||
|
||||
union SoundIoInStreamBackendData {
|
||||
#ifdef SOUNDIO_HAVE_JACK
|
||||
struct SoundIoInStreamJack jack;
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
||||
struct SoundIoInStreamPulseAudio pulseaudio;
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_ALSA
|
||||
struct SoundIoInStreamAlsa alsa;
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_COREAUDIO
|
||||
struct SoundIoInStreamCoreAudio coreaudio;
|
||||
#endif
|
||||
#ifdef SOUNDIO_HAVE_WASAPI
|
||||
struct SoundIoInStreamWasapi wasapi;
|
||||
#endif
|
||||
struct SoundIoInStreamDummy dummy;
|
||||
};
|
||||
|
||||
SOUNDIO_MAKE_LIST_STRUCT(struct SoundIoDevice*, SoundIoListDevicePtr, SOUNDIO_LIST_NOT_STATIC)
|
||||
SOUNDIO_MAKE_LIST_PROTO(struct SoundIoDevice*, SoundIoListDevicePtr, SOUNDIO_LIST_NOT_STATIC)
|
||||
|
||||
struct SoundIoDevicesInfo {
|
||||
struct SoundIoListDevicePtr input_devices;
|
||||
struct SoundIoListDevicePtr output_devices;
|
||||
// can be -1 when default device is unknown
|
||||
int default_output_index;
|
||||
int default_input_index;
|
||||
};
|
||||
|
||||
struct SoundIoOutStreamPrivate {
|
||||
struct SoundIoOutStream pub;
|
||||
union SoundIoOutStreamBackendData backend_data;
|
||||
};
|
||||
|
||||
struct SoundIoInStreamPrivate {
|
||||
struct SoundIoInStream pub;
|
||||
union SoundIoInStreamBackendData backend_data;
|
||||
};
|
||||
|
||||
struct SoundIoPrivate {
|
||||
struct SoundIo pub;
|
||||
|
||||
// Safe to read from a single thread without a mutex.
|
||||
struct SoundIoDevicesInfo *safe_devices_info;
|
||||
|
||||
void (*destroy)(struct SoundIoPrivate *);
|
||||
void (*flush_events)(struct SoundIoPrivate *);
|
||||
void (*wait_events)(struct SoundIoPrivate *);
|
||||
void (*wakeup)(struct SoundIoPrivate *);
|
||||
void (*force_device_scan)(struct SoundIoPrivate *);
|
||||
|
||||
int (*outstream_open)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||
void (*outstream_destroy)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||
int (*outstream_start)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||
int (*outstream_begin_write)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *,
|
||||
struct SoundIoChannelArea **out_areas, int *out_frame_count);
|
||||
int (*outstream_end_write)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||
int (*outstream_clear_buffer)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||
int (*outstream_pause)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, bool pause);
|
||||
int (*outstream_get_latency)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, double *out_latency);
|
||||
int (*outstream_set_volume)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, float volume);
|
||||
|
||||
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
|
45
thirdparty/libsoundio/src/util.c
vendored
45
thirdparty/libsoundio/src/util.c
vendored
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Andrew Kelley
|
||||
*
|
||||
* This file is part of libsoundio, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
void soundio_panic(const char *format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
abort();
|
||||
}
|
||||
|
||||
char *soundio_alloc_sprintf(int *len, const char *format, ...) {
|
||||
va_list ap, ap2;
|
||||
va_start(ap, format);
|
||||
va_copy(ap2, ap);
|
||||
|
||||
int len1 = vsnprintf(NULL, 0, format, ap);
|
||||
assert(len1 >= 0);
|
||||
|
||||
size_t required_size = len1 + 1;
|
||||
char *mem = ALLOCATE(char, required_size);
|
||||
if (!mem)
|
||||
return NULL;
|
||||
|
||||
int len2 = vsnprintf(mem, required_size, format, ap2);
|
||||
assert(len2 == len1);
|
||||
|
||||
va_end(ap2);
|
||||
va_end(ap);
|
||||
|
||||
if (len)
|
||||
*len = len1;
|
||||
return mem;
|
||||
}
|
98
thirdparty/libsoundio/src/util.h
vendored
98
thirdparty/libsoundio/src/util.h
vendored
@ -1,98 +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_UTIL_H
|
||||
#define SOUNDIO_UTIL_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define ALLOCATE_NONZERO(Type, count) ((Type*)malloc((count) * sizeof(Type)))
|
||||
|
||||
#define ALLOCATE(Type, count) ((Type*)calloc(count, sizeof(Type)))
|
||||
|
||||
#define REALLOCATE_NONZERO(Type, old, new_count) ((Type*)realloc(old, (new_count) * sizeof(Type)))
|
||||
|
||||
#define ARRAY_LENGTH(array) (sizeof(array)/sizeof((array)[0]))
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define SOUNDIO_ATTR_COLD
|
||||
#define SOUNDIO_ATTR_NORETURN __declspec(noreturn)
|
||||
#define SOUNDIO_ATTR_FORMAT(...)
|
||||
#define SOUNDIO_ATTR_UNUSED __pragma(warning(suppress:4100))
|
||||
#define SOUNDIO_ATTR_WARN_UNUSED_RESULT _Check_return_
|
||||
#else
|
||||
#define SOUNDIO_ATTR_COLD __attribute__((cold))
|
||||
#define SOUNDIO_ATTR_NORETURN __attribute__((noreturn))
|
||||
#define SOUNDIO_ATTR_FORMAT(...) __attribute__((format(__VA_ARGS__)))
|
||||
#define SOUNDIO_ATTR_UNUSED __attribute__((unused))
|
||||
#define SOUNDIO_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
#endif
|
||||
|
||||
|
||||
static inline int soundio_int_min(int a, int b) {
|
||||
return (a <= b) ? a : b;
|
||||
}
|
||||
|
||||
static inline int soundio_int_max(int a, int b) {
|
||||
return (a >= b) ? a : b;
|
||||
}
|
||||
|
||||
static inline int soundio_int_clamp(int min_value, int value, int max_value) {
|
||||
return soundio_int_max(soundio_int_min(value, max_value), min_value);
|
||||
}
|
||||
|
||||
static inline double soundio_double_min(double a, double b) {
|
||||
return (a <= b) ? a : b;
|
||||
}
|
||||
|
||||
static inline double soundio_double_max(double a, double b) {
|
||||
return (a >= b) ? a : b;
|
||||
}
|
||||
|
||||
static inline double soundio_double_clamp(double min_value, double value, double max_value) {
|
||||
return soundio_double_max(soundio_double_min(value, max_value), min_value);
|
||||
}
|
||||
|
||||
SOUNDIO_ATTR_NORETURN
|
||||
void soundio_panic(const char *format, ...)
|
||||
SOUNDIO_ATTR_COLD
|
||||
SOUNDIO_ATTR_FORMAT(printf, 1, 2)
|
||||
;
|
||||
|
||||
char *soundio_alloc_sprintf(int *len, const char *format, ...)
|
||||
SOUNDIO_ATTR_FORMAT(printf, 2, 3);
|
||||
|
||||
static inline char *soundio_str_dupe(const char *str, int str_len) {
|
||||
char *out = ALLOCATE_NONZERO(char, str_len + 1);
|
||||
if (!out)
|
||||
return NULL;
|
||||
memcpy(out, str, str_len);
|
||||
out[str_len] = 0;
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline bool soundio_streql(const char *str1, int str1_len, const char *str2, int str2_len) {
|
||||
if (str1_len != str2_len)
|
||||
return false;
|
||||
return memcmp(str1, str2, str1_len) == 0;
|
||||
}
|
||||
|
||||
static inline int ceil_dbl_to_int(double x) {
|
||||
const double truncation = (int)x;
|
||||
return truncation + (truncation < x);
|
||||
}
|
||||
|
||||
static inline double ceil_dbl(double x) {
|
||||
const double truncation = (long long) x;
|
||||
const double ceiling = truncation + (truncation < x);
|
||||
return ceiling;
|
||||
}
|
||||
|
||||
#endif
|
2332
thirdparty/libsoundio/src/wasapi.c
vendored
2332
thirdparty/libsoundio/src/wasapi.c
vendored
File diff suppressed because it is too large
Load Diff
117
thirdparty/libsoundio/src/wasapi.h
vendored
117
thirdparty/libsoundio/src/wasapi.h
vendored
@ -1,117 +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_WASAPI_H
|
||||
#define SOUNDIO_WASAPI_H
|
||||
|
||||
#include "soundio_internal.h"
|
||||
#include "os.h"
|
||||
#include "list.h"
|
||||
#include "atomics.h"
|
||||
|
||||
#define CINTERFACE
|
||||
#define COBJMACROS
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <mmdeviceapi.h>
|
||||
#include <audioclient.h>
|
||||
#include <audiosessiontypes.h>
|
||||
#include <audiopolicy.h>
|
||||
|
||||
#ifndef AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM
|
||||
#define AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 0x80000000
|
||||
#endif
|
||||
|
||||
#ifndef AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
|
||||
#define AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY 0x08000000
|
||||
#endif
|
||||
|
||||
struct SoundIoPrivate;
|
||||
int soundio_wasapi_init(struct SoundIoPrivate *si);
|
||||
|
||||
struct SoundIoDeviceWasapi {
|
||||
double period_duration;
|
||||
IMMDevice *mm_device;
|
||||
};
|
||||
|
||||
struct SoundIoWasapi {
|
||||
struct SoundIoOsMutex *mutex;
|
||||
struct SoundIoOsCond *cond;
|
||||
struct SoundIoOsCond *scan_devices_cond;
|
||||
struct SoundIoOsMutex *scan_devices_mutex;
|
||||
struct SoundIoOsThread *thread;
|
||||
bool abort_flag;
|
||||
// this one is ready to be read with flush_events. protected by mutex
|
||||
struct SoundIoDevicesInfo *ready_devices_info;
|
||||
bool have_devices_flag;
|
||||
bool device_scan_queued;
|
||||
int shutdown_err;
|
||||
bool emitted_shutdown_cb;
|
||||
|
||||
IMMDeviceEnumerator* device_enumerator;
|
||||
IMMNotificationClient device_events;
|
||||
LONG device_events_refs;
|
||||
};
|
||||
|
||||
struct SoundIoOutStreamWasapi {
|
||||
IAudioClient *audio_client;
|
||||
IAudioClockAdjustment *audio_clock_adjustment;
|
||||
IAudioRenderClient *audio_render_client;
|
||||
IAudioSessionControl *audio_session_control;
|
||||
ISimpleAudioVolume *audio_volume_control;
|
||||
LPWSTR stream_name;
|
||||
bool need_resample;
|
||||
struct SoundIoOsThread *thread;
|
||||
struct SoundIoOsMutex *mutex;
|
||||
struct SoundIoOsCond *cond;
|
||||
struct SoundIoOsCond *start_cond;
|
||||
struct SoundIoAtomicFlag thread_exit_flag;
|
||||
bool is_raw;
|
||||
int writable_frame_count;
|
||||
UINT32 buffer_frame_count;
|
||||
int write_frame_count;
|
||||
HANDLE h_event;
|
||||
struct SoundIoAtomicBool desired_pause_state;
|
||||
struct SoundIoAtomicFlag pause_resume_flag;
|
||||
struct SoundIoAtomicFlag clear_buffer_flag;
|
||||
bool is_paused;
|
||||
bool open_complete;
|
||||
int open_err;
|
||||
bool started;
|
||||
UINT32 min_padding_frames;
|
||||
float volume;
|
||||
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct SoundIoInStreamWasapi {
|
||||
IAudioClient *audio_client;
|
||||
IAudioCaptureClient *audio_capture_client;
|
||||
IAudioSessionControl *audio_session_control;
|
||||
LPWSTR stream_name;
|
||||
struct SoundIoOsThread *thread;
|
||||
struct SoundIoOsMutex *mutex;
|
||||
struct SoundIoOsCond *cond;
|
||||
struct SoundIoOsCond *start_cond;
|
||||
struct SoundIoAtomicFlag thread_exit_flag;
|
||||
bool is_raw;
|
||||
int readable_frame_count;
|
||||
UINT32 buffer_frame_count;
|
||||
int read_frame_count;
|
||||
HANDLE h_event;
|
||||
bool is_paused;
|
||||
bool open_complete;
|
||||
int open_err;
|
||||
bool started;
|
||||
char *read_buf;
|
||||
int read_buf_frames_left;
|
||||
int opened_buf_frames;
|
||||
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
#endif
|
@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Andrew Kelley
|
||||
*
|
||||
* This file is part of libsoundio, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include <soundio/soundio.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
|
||||
__attribute__ ((cold))
|
||||
__attribute__ ((noreturn))
|
||||
__attribute__ ((format (printf, 1, 2)))
|
||||
static void panic(const char *format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
abort();
|
||||
}
|
||||
|
||||
static int usage(char *exe) {
|
||||
fprintf(stderr, "Usage: %s [options]\n"
|
||||
"Options:\n"
|
||||
" [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi]\n"
|
||||
" [--timeout seconds]\n", exe);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static enum SoundIoBackend backend = SoundIoBackendNone;
|
||||
|
||||
static bool severed = false;
|
||||
|
||||
static void on_backend_disconnect(struct SoundIo *soundio, int err) {
|
||||
fprintf(stderr, "OK backend disconnected with '%s'.\n", soundio_strerror(err));
|
||||
severed = true;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char *exe = argv[0];
|
||||
int timeout = 0;
|
||||
for (int i = 1; i < argc; i += 1) {
|
||||
char *arg = argv[i];
|
||||
if (arg[0] == '-' && arg[1] == '-') {
|
||||
i += 1;
|
||||
if (i >= argc) {
|
||||
return usage(exe);
|
||||
} else if (strcmp(arg, "--timeout") == 0) {
|
||||
timeout = atoi(argv[i]);
|
||||
} else if (strcmp(arg, "--backend") == 0) {
|
||||
if (strcmp("-dummy", argv[i]) == 0) {
|
||||
backend = SoundIoBackendDummy;
|
||||
} else if (strcmp("alsa", argv[i]) == 0) {
|
||||
backend = SoundIoBackendAlsa;
|
||||
} else if (strcmp("pulseaudio", argv[i]) == 0) {
|
||||
backend = SoundIoBackendPulseAudio;
|
||||
} else if (strcmp("jack", argv[i]) == 0) {
|
||||
backend = SoundIoBackendJack;
|
||||
} else if (strcmp("coreaudio", argv[i]) == 0) {
|
||||
backend = SoundIoBackendCoreAudio;
|
||||
} else if (strcmp("wasapi", argv[i]) == 0) {
|
||||
backend = SoundIoBackendWasapi;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid backend: %s\n", argv[i]);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
return usage(exe);
|
||||
}
|
||||
} else {
|
||||
return usage(exe);
|
||||
}
|
||||
}
|
||||
|
||||
struct SoundIo *soundio;
|
||||
if (!(soundio = soundio_create()))
|
||||
panic("out of memory");
|
||||
|
||||
int err = (backend == SoundIoBackendNone) ?
|
||||
soundio_connect(soundio) : soundio_connect_backend(soundio, backend);
|
||||
|
||||
if (err)
|
||||
panic("error connecting: %s", soundio_strerror(err));
|
||||
|
||||
soundio->on_backend_disconnect = on_backend_disconnect;
|
||||
|
||||
fprintf(stderr, "OK connected to %s. Now cause the backend to disconnect.\n",
|
||||
soundio_backend_name(soundio->current_backend));
|
||||
|
||||
while (!severed)
|
||||
soundio_wait_events(soundio);
|
||||
|
||||
soundio_disconnect(soundio);
|
||||
|
||||
if (timeout > 0) {
|
||||
fprintf(stderr, "OK sleeping for %d seconds\n", timeout);
|
||||
sleep(timeout);
|
||||
}
|
||||
|
||||
fprintf(stderr, "OK cleaned up. Reconnecting...\n");
|
||||
|
||||
err = (backend == SoundIoBackendNone) ?
|
||||
soundio_connect(soundio) : soundio_connect_backend(soundio, backend);
|
||||
|
||||
if (err)
|
||||
panic("error reconnecting: %s", soundio_strerror(err));
|
||||
|
||||
fprintf(stderr, "OK reconnected successfully to %s\n", soundio_backend_name(soundio->current_backend));
|
||||
|
||||
soundio_flush_events(soundio);
|
||||
|
||||
fprintf(stderr, "OK test passed\n");
|
||||
|
||||
return 0;
|
||||
}
|
251
thirdparty/libsoundio/test/latency.c
vendored
251
thirdparty/libsoundio/test/latency.c
vendored
@ -1,251 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Andrew Kelley
|
||||
*
|
||||
* This file is part of libsoundio, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "soundio_private.h"
|
||||
#include "os.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static int usage(char *exe) {
|
||||
fprintf(stderr, "Usage: %s [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi] [--latency seconds]\n", exe);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void write_sample_s16ne(char *ptr, double sample) {
|
||||
int16_t *buf = (int16_t *)ptr;
|
||||
double range = (double)INT16_MAX - (double)INT16_MIN;
|
||||
double val = sample * range / 2.0;
|
||||
*buf = val;
|
||||
}
|
||||
|
||||
static void write_sample_s32ne(char *ptr, double sample) {
|
||||
int32_t *buf = (int32_t *)ptr;
|
||||
double range = (double)INT32_MAX - (double)INT32_MIN;
|
||||
double val = sample * range / 2.0;
|
||||
*buf = val;
|
||||
}
|
||||
|
||||
static void write_sample_float32ne(char *ptr, double sample) {
|
||||
float *buf = (float *)ptr;
|
||||
*buf = sample;
|
||||
}
|
||||
|
||||
static void write_sample_float64ne(char *ptr, double sample) {
|
||||
double *buf = (double *)ptr;
|
||||
*buf = sample;
|
||||
}
|
||||
|
||||
static void (*write_sample)(char *ptr, double sample);
|
||||
|
||||
static int frames_until_pulse = 0;
|
||||
static int pulse_frames_left = -1;
|
||||
static const double PI = 3.14159265358979323846264338328;
|
||||
static double seconds_offset = 0.0;
|
||||
|
||||
static struct SoundIoRingBuffer pulse_rb;
|
||||
|
||||
static void write_time(struct SoundIoOutStream *outstream, double extra) {
|
||||
double latency;
|
||||
int err;
|
||||
if ((err = soundio_outstream_get_latency(outstream, &latency))) {
|
||||
soundio_panic("getting latency: %s", soundio_strerror(err));
|
||||
}
|
||||
double now = soundio_os_get_time();
|
||||
double audible_time = now + latency + extra;
|
||||
double *write_ptr = (double *)soundio_ring_buffer_write_ptr(&pulse_rb);
|
||||
*write_ptr = audible_time;
|
||||
soundio_ring_buffer_advance_write_ptr(&pulse_rb, sizeof(double));
|
||||
}
|
||||
|
||||
static void write_callback(struct SoundIoOutStream *outstream, int frame_count_min, int frame_count_max) {
|
||||
double float_sample_rate = outstream->sample_rate;
|
||||
double seconds_per_frame = 1.0f / float_sample_rate;
|
||||
struct SoundIoChannelArea *areas;
|
||||
int err;
|
||||
|
||||
int frames_left = frame_count_max;
|
||||
|
||||
while (frames_left > 0) {
|
||||
int frame_count = frames_left;
|
||||
|
||||
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count)))
|
||||
soundio_panic("begin write: %s", soundio_strerror(err));
|
||||
|
||||
if (!frame_count)
|
||||
break;
|
||||
|
||||
const struct SoundIoChannelLayout *layout = &outstream->layout;
|
||||
|
||||
double pitch = 440.0;
|
||||
double radians_per_second = pitch * 2.0 * PI;
|
||||
for (int frame = 0; frame < frame_count; frame += 1) {
|
||||
double sample;
|
||||
if (frames_until_pulse <= 0) {
|
||||
if (pulse_frames_left == -1) {
|
||||
pulse_frames_left = 0.25 * float_sample_rate;
|
||||
write_time(outstream, seconds_per_frame * frame); // announce beep start
|
||||
}
|
||||
if (pulse_frames_left > 0) {
|
||||
pulse_frames_left -= 1;
|
||||
sample = sinf((seconds_offset + frame * seconds_per_frame) * radians_per_second);
|
||||
} else {
|
||||
frames_until_pulse = (0.5 + (rand() / (double)RAND_MAX) * 2.0) * float_sample_rate;
|
||||
pulse_frames_left = -1;
|
||||
sample = 0.0;
|
||||
write_time(outstream, seconds_per_frame * frame); // announce beep end
|
||||
}
|
||||
} else {
|
||||
frames_until_pulse -= 1;
|
||||
sample = 0.0;
|
||||
}
|
||||
for (int channel = 0; channel < layout->channel_count; channel += 1) {
|
||||
write_sample(areas[channel].ptr, sample);
|
||||
areas[channel].ptr += areas[channel].step;
|
||||
}
|
||||
}
|
||||
|
||||
seconds_offset += seconds_per_frame * frame_count;
|
||||
|
||||
if ((err = soundio_outstream_end_write(outstream)))
|
||||
soundio_panic("end write: %s", soundio_strerror(err));
|
||||
|
||||
frames_left -= frame_count;
|
||||
}
|
||||
}
|
||||
|
||||
static void underflow_callback(struct SoundIoOutStream *outstream) {
|
||||
soundio_panic("underflow\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char *exe = argv[0];
|
||||
enum SoundIoBackend backend = SoundIoBackendNone;
|
||||
double software_latency = 0.0;
|
||||
for (int i = 1; i < argc; i += 1) {
|
||||
char *arg = argv[i];
|
||||
if (arg[0] == '-' && arg[1] == '-') {
|
||||
i += 1;
|
||||
if (i >= argc) {
|
||||
return usage(exe);
|
||||
} else if (strcmp(arg, "--backend") == 0) {
|
||||
if (strcmp("dummy", argv[i]) == 0) {
|
||||
backend = SoundIoBackendDummy;
|
||||
} else if (strcmp("alsa", argv[i]) == 0) {
|
||||
backend = SoundIoBackendAlsa;
|
||||
} else if (strcmp("pulseaudio", argv[i]) == 0) {
|
||||
backend = SoundIoBackendPulseAudio;
|
||||
} else if (strcmp("jack", argv[i]) == 0) {
|
||||
backend = SoundIoBackendJack;
|
||||
} else if (strcmp("coreaudio", argv[i]) == 0) {
|
||||
backend = SoundIoBackendCoreAudio;
|
||||
} else if (strcmp("wasapi", argv[i]) == 0) {
|
||||
backend = SoundIoBackendWasapi;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid backend: %s\n", argv[i]);
|
||||
return 1;
|
||||
}
|
||||
} else if (strcmp(arg, "--latency") == 0) {
|
||||
software_latency = atof(argv[i]);
|
||||
} else {
|
||||
return usage(exe);
|
||||
}
|
||||
} else {
|
||||
return usage(exe);
|
||||
}
|
||||
}
|
||||
|
||||
struct SoundIo *soundio;
|
||||
if (!(soundio = soundio_create()))
|
||||
soundio_panic("out of memory");
|
||||
|
||||
int err = (backend == SoundIoBackendNone) ?
|
||||
soundio_connect(soundio) : soundio_connect_backend(soundio, backend);
|
||||
|
||||
if (err)
|
||||
soundio_panic("error connecting: %s", soundio_strerror(err));
|
||||
|
||||
soundio_flush_events(soundio);
|
||||
|
||||
int default_out_device_index = soundio_default_output_device_index(soundio);
|
||||
if (default_out_device_index < 0)
|
||||
soundio_panic("no output device found");
|
||||
|
||||
struct SoundIoDevice *device = soundio_get_output_device(soundio, default_out_device_index);
|
||||
if (!device)
|
||||
soundio_panic("out of memory");
|
||||
|
||||
fprintf(stderr, "Output device: %s\n", device->name);
|
||||
|
||||
struct SoundIoOutStream *outstream = soundio_outstream_create(device);
|
||||
outstream->format = SoundIoFormatFloat32NE;
|
||||
outstream->write_callback = write_callback;
|
||||
outstream->underflow_callback = underflow_callback;
|
||||
outstream->software_latency = software_latency;
|
||||
|
||||
if (soundio_device_supports_format(device, SoundIoFormatFloat32NE)) {
|
||||
outstream->format = SoundIoFormatFloat32NE;
|
||||
write_sample = write_sample_float32ne;
|
||||
} else if (soundio_device_supports_format(device, SoundIoFormatFloat64NE)) {
|
||||
outstream->format = SoundIoFormatFloat64NE;
|
||||
write_sample = write_sample_float64ne;
|
||||
} else if (soundio_device_supports_format(device, SoundIoFormatS32NE)) {
|
||||
outstream->format = SoundIoFormatS32NE;
|
||||
write_sample = write_sample_s32ne;
|
||||
} else if (soundio_device_supports_format(device, SoundIoFormatS16NE)) {
|
||||
outstream->format = SoundIoFormatS16NE;
|
||||
write_sample = write_sample_s16ne;
|
||||
} else {
|
||||
soundio_panic("No suitable device format available.\n");
|
||||
}
|
||||
|
||||
if ((err = soundio_ring_buffer_init(&pulse_rb, 1024)))
|
||||
soundio_panic("ring buffer init: %s", soundio_strerror(err));
|
||||
|
||||
if ((err = soundio_outstream_open(outstream)))
|
||||
soundio_panic("unable to open device: %s", soundio_strerror(err));
|
||||
|
||||
if (outstream->layout_error)
|
||||
fprintf(stderr, "unable to set channel layout: %s\n", soundio_strerror(outstream->layout_error));
|
||||
|
||||
if ((err = soundio_outstream_start(outstream)))
|
||||
soundio_panic("unable to start device: %s", soundio_strerror(err));
|
||||
|
||||
bool beep_on = true;
|
||||
int count = 0;
|
||||
for (;;) {
|
||||
int fill_count = soundio_ring_buffer_fill_count(&pulse_rb);
|
||||
if (fill_count >= (int)sizeof(double)) {
|
||||
double *read_ptr = (double *)soundio_ring_buffer_read_ptr(&pulse_rb);
|
||||
double audible_time = *read_ptr;
|
||||
while (audible_time > soundio_os_get_time()) {
|
||||
// Burn the CPU while we wait for our precisely timed event.
|
||||
}
|
||||
if (beep_on) {
|
||||
fprintf(stderr, "BEEP %d start\n", count);
|
||||
} else {
|
||||
fprintf(stderr, "BEEP %d end\n", count++);
|
||||
}
|
||||
fflush(stderr);
|
||||
double off_by = soundio_os_get_time() - audible_time;
|
||||
if (off_by > 0.0001)
|
||||
fprintf(stderr, "off by %f\n", off_by);
|
||||
beep_on = !beep_on;
|
||||
soundio_ring_buffer_advance_read_ptr(&pulse_rb, sizeof(double));
|
||||
}
|
||||
}
|
||||
|
||||
soundio_outstream_destroy(outstream);
|
||||
soundio_device_unref(device);
|
||||
soundio_destroy(soundio);
|
||||
return 0;
|
||||
}
|
||||
|
230
thirdparty/libsoundio/test/overflow.c
vendored
230
thirdparty/libsoundio/test/overflow.c
vendored
@ -1,230 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Andrew Kelley
|
||||
*
|
||||
* This file is part of libsoundio, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include <soundio/soundio.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static enum SoundIoFormat prioritized_formats[] = {
|
||||
SoundIoFormatFloat32NE,
|
||||
SoundIoFormatFloat32FE,
|
||||
SoundIoFormatS32NE,
|
||||
SoundIoFormatS32FE,
|
||||
SoundIoFormatS24NE,
|
||||
SoundIoFormatS24FE,
|
||||
SoundIoFormatS16NE,
|
||||
SoundIoFormatS16FE,
|
||||
SoundIoFormatFloat64NE,
|
||||
SoundIoFormatFloat64FE,
|
||||
SoundIoFormatU32NE,
|
||||
SoundIoFormatU32FE,
|
||||
SoundIoFormatU24NE,
|
||||
SoundIoFormatU24FE,
|
||||
SoundIoFormatU16NE,
|
||||
SoundIoFormatU16FE,
|
||||
SoundIoFormatS8,
|
||||
SoundIoFormatU8,
|
||||
SoundIoFormatInvalid,
|
||||
};
|
||||
|
||||
__attribute__ ((cold))
|
||||
__attribute__ ((noreturn))
|
||||
__attribute__ ((format (printf, 1, 2)))
|
||||
static void panic(const char *format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
abort();
|
||||
}
|
||||
|
||||
static int usage(char *exe) {
|
||||
fprintf(stderr, "Usage: %s [options]\n"
|
||||
"Options:\n"
|
||||
" [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi]\n"
|
||||
" [--device id]\n"
|
||||
" [--raw]\n", exe);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct SoundIo *soundio = NULL;
|
||||
static float seconds_offset = 0.0f;
|
||||
static float seconds_end = 9.0f;
|
||||
static bool caused_underflow = false;
|
||||
static int overflow_count = 0;
|
||||
|
||||
static void read_callback(struct SoundIoInStream *instream, int frame_count_min, int frame_count_max) {
|
||||
struct SoundIoChannelArea *areas;
|
||||
float float_sample_rate = instream->sample_rate;
|
||||
float seconds_per_frame = 1.0f / float_sample_rate;
|
||||
int err;
|
||||
|
||||
if (!caused_underflow && seconds_offset >= 3.0f) {
|
||||
fprintf(stderr, "OK sleeping...\n");
|
||||
caused_underflow = true;
|
||||
sleep(3);
|
||||
}
|
||||
|
||||
if (seconds_offset >= seconds_end) {
|
||||
soundio_wakeup(soundio);
|
||||
return;
|
||||
}
|
||||
|
||||
int frames_left = frame_count_max;
|
||||
|
||||
for (;;) {
|
||||
int frame_count = frames_left;
|
||||
|
||||
if ((err = soundio_instream_begin_read(instream, &areas, &frame_count)))
|
||||
panic("begin read error: %s", soundio_strerror(err));
|
||||
|
||||
if (!frame_count)
|
||||
break;
|
||||
|
||||
seconds_offset += seconds_per_frame * frame_count;
|
||||
|
||||
if ((err = soundio_instream_end_read(instream)))
|
||||
panic("end read error: %s", soundio_strerror(err));
|
||||
|
||||
frames_left -= frame_count;
|
||||
if (frames_left <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stderr, "OK received %d frames\n", frame_count_max);
|
||||
}
|
||||
|
||||
static void overflow_callback(struct SoundIoInStream *instream) {
|
||||
fprintf(stderr, "OK overflow %d\n", overflow_count++);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char *exe = argv[0];
|
||||
enum SoundIoBackend backend = SoundIoBackendNone;
|
||||
bool is_raw = false;
|
||||
char *device_id = NULL;
|
||||
for (int i = 1; i < argc; i += 1) {
|
||||
char *arg = argv[i];
|
||||
if (arg[0] == '-' && arg[1] == '-') {
|
||||
if (strcmp(arg, "--raw") == 0) {
|
||||
is_raw = true;
|
||||
} else if (++i >= argc) {
|
||||
return usage(exe);
|
||||
} else if (strcmp(arg, "--device") == 0) {
|
||||
device_id = argv[i];
|
||||
} else if (strcmp(arg, "--backend") == 0) {
|
||||
if (strcmp("dummy", argv[i]) == 0) {
|
||||
backend = SoundIoBackendDummy;
|
||||
} else if (strcmp("alsa", argv[i]) == 0) {
|
||||
backend = SoundIoBackendAlsa;
|
||||
} else if (strcmp("pulseaudio", argv[i]) == 0) {
|
||||
backend = SoundIoBackendPulseAudio;
|
||||
} else if (strcmp("jack", argv[i]) == 0) {
|
||||
backend = SoundIoBackendJack;
|
||||
} else if (strcmp("coreaudio", argv[i]) == 0) {
|
||||
backend = SoundIoBackendCoreAudio;
|
||||
} else if (strcmp("wasapi", argv[i]) == 0) {
|
||||
backend = SoundIoBackendWasapi;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid backend: %s\n", argv[i]);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
return usage(exe);
|
||||
}
|
||||
} else {
|
||||
return usage(exe);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"Records for 3 seconds, sleeps for 3 seconds, then you should see at least\n"
|
||||
"one buffer overflow message, then records for 3 seconds.\n"
|
||||
"PulseAudio is not expected to pass this test.\n"
|
||||
"CoreAudio is not expected to pass this test.\n"
|
||||
"WASAPI is not expected to pass this test.\n");
|
||||
|
||||
if (!(soundio = soundio_create()))
|
||||
panic("out of memory");
|
||||
|
||||
int err = (backend == SoundIoBackendNone) ?
|
||||
soundio_connect(soundio) : soundio_connect_backend(soundio, backend);
|
||||
|
||||
if (err)
|
||||
panic("error connecting: %s", soundio_strerror(err));
|
||||
|
||||
soundio_flush_events(soundio);
|
||||
|
||||
int selected_device_index = -1;
|
||||
if (device_id) {
|
||||
int device_count = soundio_input_device_count(soundio);
|
||||
for (int i = 0; i < device_count; i += 1) {
|
||||
struct SoundIoDevice *device = soundio_get_input_device(soundio, i);
|
||||
if (strcmp(device->id, device_id) == 0 && device->is_raw == is_raw) {
|
||||
selected_device_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
selected_device_index = soundio_default_input_device_index(soundio);
|
||||
}
|
||||
|
||||
if (selected_device_index < 0) {
|
||||
fprintf(stderr, "input device not found\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct SoundIoDevice *device = soundio_get_input_device(soundio, selected_device_index);
|
||||
if (!device) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Input device: %s\n", device->name);
|
||||
|
||||
enum SoundIoFormat *fmt;
|
||||
for (fmt = prioritized_formats; *fmt != SoundIoFormatInvalid; fmt += 1) {
|
||||
if (soundio_device_supports_format(device, *fmt))
|
||||
break;
|
||||
}
|
||||
if (*fmt == SoundIoFormatInvalid)
|
||||
panic("incompatible sample format");
|
||||
|
||||
struct SoundIoInStream *instream = soundio_instream_create(device);
|
||||
instream->format = *fmt;
|
||||
instream->read_callback = read_callback;
|
||||
instream->overflow_callback = overflow_callback;
|
||||
|
||||
if ((err = soundio_instream_open(instream)))
|
||||
panic("unable to open device: %s", soundio_strerror(err));
|
||||
|
||||
fprintf(stderr, "OK format: %s\n", soundio_format_string(instream->format));
|
||||
|
||||
if ((err = soundio_instream_start(instream)))
|
||||
panic("unable to start device: %s", soundio_strerror(err));
|
||||
|
||||
while (seconds_offset < seconds_end)
|
||||
soundio_wait_events(soundio);
|
||||
|
||||
soundio_instream_destroy(instream);
|
||||
soundio_device_unref(device);
|
||||
soundio_destroy(soundio);
|
||||
|
||||
if (overflow_count > 0) {
|
||||
fprintf(stderr, "OK test passed with %d overflow callbacks\n", overflow_count);
|
||||
return 0;
|
||||
} else {
|
||||
fprintf(stderr, "FAIL no overflow callbacks received\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
251
thirdparty/libsoundio/test/underflow.c
vendored
251
thirdparty/libsoundio/test/underflow.c
vendored
@ -1,251 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Andrew Kelley
|
||||
*
|
||||
* This file is part of libsoundio, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include <soundio/soundio.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
__attribute__ ((cold))
|
||||
__attribute__ ((noreturn))
|
||||
__attribute__ ((format (printf, 1, 2)))
|
||||
static void panic(const char *format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
abort();
|
||||
}
|
||||
|
||||
static int usage(char *exe) {
|
||||
fprintf(stderr, "Usage: %s [options]\n"
|
||||
"Options:\n"
|
||||
" [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi]\n"
|
||||
" [--device id]\n"
|
||||
" [--raw]\n"
|
||||
" [--sample-rate hz]\n"
|
||||
, exe);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void write_sample_s16ne(char *ptr, double sample) {
|
||||
int16_t *buf = (int16_t *)ptr;
|
||||
double range = (double)INT16_MAX - (double)INT16_MIN;
|
||||
double val = sample * range / 2.0;
|
||||
*buf = val;
|
||||
}
|
||||
|
||||
static void write_sample_s32ne(char *ptr, double sample) {
|
||||
int32_t *buf = (int32_t *)ptr;
|
||||
double range = (double)INT32_MAX - (double)INT32_MIN;
|
||||
double val = sample * range / 2.0;
|
||||
*buf = val;
|
||||
}
|
||||
|
||||
static void write_sample_float32ne(char *ptr, double sample) {
|
||||
float *buf = (float *)ptr;
|
||||
*buf = sample;
|
||||
}
|
||||
|
||||
static void write_sample_float64ne(char *ptr, double sample) {
|
||||
double *buf = (double *)ptr;
|
||||
*buf = sample;
|
||||
}
|
||||
|
||||
static void (*write_sample)(char *ptr, double sample);
|
||||
static const double PI = 3.14159265358979323846264338328;
|
||||
static double seconds_offset = 0.0;
|
||||
static bool caused_underflow = false;
|
||||
static struct SoundIo *soundio = NULL;
|
||||
static double seconds_end = 9.0f;
|
||||
|
||||
static void write_callback(struct SoundIoOutStream *outstream, int frame_count_min, int frame_count_max) {
|
||||
double float_sample_rate = outstream->sample_rate;
|
||||
double seconds_per_frame = 1.0 / float_sample_rate;
|
||||
struct SoundIoChannelArea *areas;
|
||||
int err;
|
||||
|
||||
if (!caused_underflow && seconds_offset >= 3.0) {
|
||||
caused_underflow = true;
|
||||
sleep(3);
|
||||
}
|
||||
|
||||
if (seconds_offset >= seconds_end) {
|
||||
soundio_wakeup(soundio);
|
||||
return;
|
||||
}
|
||||
|
||||
int frames_left = frame_count_max;
|
||||
|
||||
for (;;) {
|
||||
int frame_count = frames_left;
|
||||
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count)))
|
||||
panic("%s", soundio_strerror(err));
|
||||
|
||||
if (!frame_count)
|
||||
break;
|
||||
|
||||
const struct SoundIoChannelLayout *layout = &outstream->layout;
|
||||
|
||||
double pitch = 440.0;
|
||||
double radians_per_second = pitch * 2.0 * PI;
|
||||
for (int frame = 0; frame < frame_count; frame += 1) {
|
||||
double sample = sinf((seconds_offset + frame * seconds_per_frame) * radians_per_second);
|
||||
for (int channel = 0; channel < layout->channel_count; channel += 1) {
|
||||
write_sample(areas[channel].ptr, sample);
|
||||
areas[channel].ptr += areas[channel].step;
|
||||
}
|
||||
}
|
||||
seconds_offset += seconds_per_frame * frame_count;
|
||||
|
||||
if ((err = soundio_outstream_end_write(outstream))) {
|
||||
if (err == SoundIoErrorUnderflow)
|
||||
return;
|
||||
panic("%s", soundio_strerror(err));
|
||||
}
|
||||
|
||||
frames_left -= frame_count;
|
||||
if (frames_left <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void underflow_callback(struct SoundIoOutStream *outstream) {
|
||||
static int count = 0;
|
||||
fprintf(stderr, "underflow %d\n", count++);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char *exe = argv[0];
|
||||
enum SoundIoBackend backend = SoundIoBackendNone;
|
||||
char *device_id = NULL;
|
||||
bool raw = false;
|
||||
int sample_rate = 0;
|
||||
for (int i = 1; i < argc; i += 1) {
|
||||
char *arg = argv[i];
|
||||
if (arg[0] == '-' && arg[1] == '-') {
|
||||
if (strcmp(arg, "--raw") == 0) {
|
||||
raw = true;
|
||||
} else {
|
||||
i += 1;
|
||||
if (i >= argc) {
|
||||
return usage(exe);
|
||||
} else if (strcmp(arg, "--backend") == 0) {
|
||||
if (strcmp(argv[i], "dummy") == 0) {
|
||||
backend = SoundIoBackendDummy;
|
||||
} else if (strcmp(argv[i], "alsa") == 0) {
|
||||
backend = SoundIoBackendAlsa;
|
||||
} else if (strcmp(argv[i], "pulseaudio") == 0) {
|
||||
backend = SoundIoBackendPulseAudio;
|
||||
} else if (strcmp(argv[i], "jack") == 0) {
|
||||
backend = SoundIoBackendJack;
|
||||
} else if (strcmp(argv[i], "coreaudio") == 0) {
|
||||
backend = SoundIoBackendCoreAudio;
|
||||
} else if (strcmp(argv[i], "wasapi") == 0) {
|
||||
backend = SoundIoBackendWasapi;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid backend: %s\n", argv[i]);
|
||||
return 1;
|
||||
}
|
||||
} else if (strcmp(arg, "--device") == 0) {
|
||||
device_id = argv[i];
|
||||
} else if (strcmp(arg, "--sample-rate") == 0) {
|
||||
sample_rate = atoi(argv[i]);
|
||||
} else {
|
||||
return usage(exe);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return usage(exe);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "You should hear a sine wave for 3 seconds, then some period of silence or glitches,\n"
|
||||
"then you should see at least one buffer underflow message, then hear a sine\n"
|
||||
"wave for 3 seconds, then the program should exit successfully.\n"
|
||||
"WASAPI does not report buffer underflows.\n");
|
||||
|
||||
if (!(soundio = soundio_create()))
|
||||
panic("out of memory");
|
||||
|
||||
int err = (backend == SoundIoBackendNone) ?
|
||||
soundio_connect(soundio) : soundio_connect_backend(soundio, backend);
|
||||
|
||||
if (err)
|
||||
panic("error connecting: %s", soundio_strerror(err));
|
||||
|
||||
soundio_flush_events(soundio);
|
||||
|
||||
int selected_device_index = -1;
|
||||
if (device_id) {
|
||||
int device_count = soundio_output_device_count(soundio);
|
||||
for (int i = 0; i < device_count; i += 1) {
|
||||
struct SoundIoDevice *device = soundio_get_output_device(soundio, i);
|
||||
if (strcmp(device->id, device_id) == 0 && device->is_raw == raw) {
|
||||
selected_device_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
selected_device_index = soundio_default_output_device_index(soundio);
|
||||
}
|
||||
|
||||
if (selected_device_index < 0)
|
||||
panic("Output device not found");
|
||||
|
||||
struct SoundIoDevice *device = soundio_get_output_device(soundio, selected_device_index);
|
||||
if (!device)
|
||||
panic("out of memory");
|
||||
|
||||
fprintf(stderr, "Output device: %s\n", device->name);
|
||||
|
||||
struct SoundIoOutStream *outstream = soundio_outstream_create(device);
|
||||
outstream->format = SoundIoFormatFloat32NE;
|
||||
outstream->write_callback = write_callback;
|
||||
outstream->underflow_callback = underflow_callback;
|
||||
outstream->sample_rate = sample_rate;
|
||||
|
||||
if (soundio_device_supports_format(device, SoundIoFormatFloat32NE)) {
|
||||
outstream->format = SoundIoFormatFloat32NE;
|
||||
write_sample = write_sample_float32ne;
|
||||
} else if (soundio_device_supports_format(device, SoundIoFormatFloat64NE)) {
|
||||
outstream->format = SoundIoFormatFloat64NE;
|
||||
write_sample = write_sample_float64ne;
|
||||
} else if (soundio_device_supports_format(device, SoundIoFormatS32NE)) {
|
||||
outstream->format = SoundIoFormatS32NE;
|
||||
write_sample = write_sample_s32ne;
|
||||
} else if (soundio_device_supports_format(device, SoundIoFormatS16NE)) {
|
||||
outstream->format = SoundIoFormatS16NE;
|
||||
write_sample = write_sample_s16ne;
|
||||
} else {
|
||||
fprintf(stderr, "No suitable device format available.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((err = soundio_outstream_open(outstream)))
|
||||
panic("unable to open device: %s", soundio_strerror(err));
|
||||
|
||||
if (outstream->layout_error)
|
||||
fprintf(stderr, "unable to set channel layout: %s\n", soundio_strerror(outstream->layout_error));
|
||||
|
||||
if ((err = soundio_outstream_start(outstream)))
|
||||
panic("unable to start device: %s", soundio_strerror(err));
|
||||
|
||||
while (seconds_offset < seconds_end)
|
||||
soundio_wait_events(soundio);
|
||||
|
||||
soundio_outstream_destroy(outstream);
|
||||
soundio_device_unref(device);
|
||||
soundio_destroy(soundio);
|
||||
return 0;
|
||||
}
|
250
thirdparty/libsoundio/test/unit_tests.c
vendored
250
thirdparty/libsoundio/test/unit_tests.c
vendored
@ -1,250 +0,0 @@
|
||||
#undef NDEBUG
|
||||
|
||||
#include "soundio_private.h"
|
||||
#include "os.h"
|
||||
#include "util.h"
|
||||
#include "atomics.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
static inline void ok_or_panic(int err) {
|
||||
if (err)
|
||||
soundio_panic("%s", soundio_strerror(err));
|
||||
}
|
||||
|
||||
static void test_os_get_time(void) {
|
||||
ok_or_panic(soundio_os_init());
|
||||
double prev_time = soundio_os_get_time();
|
||||
for (int i = 0; i < 1000; i += 1) {
|
||||
double time = soundio_os_get_time();
|
||||
assert(time >= prev_time);
|
||||
prev_time = time;
|
||||
}
|
||||
}
|
||||
|
||||
static void write_callback(struct SoundIoOutStream *device, int frame_count_min, int frame_count_max) { }
|
||||
static void error_callback(struct SoundIoOutStream *device, int err) { }
|
||||
|
||||
static void test_create_outstream(void) {
|
||||
struct SoundIo *soundio = soundio_create();
|
||||
assert(soundio);
|
||||
ok_or_panic(soundio_connect(soundio));
|
||||
soundio_flush_events(soundio);
|
||||
int default_out_device_index = soundio_default_output_device_index(soundio);
|
||||
assert(default_out_device_index >= 0);
|
||||
struct SoundIoDevice *device = soundio_get_output_device(soundio, default_out_device_index);
|
||||
assert(device);
|
||||
struct SoundIoOutStream *outstream = soundio_outstream_create(device);
|
||||
outstream->format = SoundIoFormatFloat32NE;
|
||||
outstream->sample_rate = 48000;
|
||||
outstream->layout = device->layouts[0];
|
||||
outstream->software_latency = 0.1;
|
||||
outstream->write_callback = write_callback;
|
||||
outstream->error_callback = error_callback;
|
||||
|
||||
ok_or_panic(soundio_outstream_open(outstream));
|
||||
|
||||
soundio_outstream_destroy(outstream);
|
||||
soundio_device_unref(device);
|
||||
soundio_destroy(soundio);
|
||||
soundio = NULL;
|
||||
soundio_destroy(soundio);
|
||||
}
|
||||
|
||||
|
||||
static void test_ring_buffer_basic(void) {
|
||||
struct SoundIo *soundio = soundio_create();
|
||||
assert(soundio);
|
||||
struct SoundIoRingBuffer *rb = soundio_ring_buffer_create(soundio, 10);
|
||||
assert(rb);
|
||||
|
||||
int page_size = soundio_os_page_size();
|
||||
|
||||
assert(soundio_ring_buffer_capacity(rb) == page_size);
|
||||
|
||||
char *write_ptr = soundio_ring_buffer_write_ptr(rb);
|
||||
int amt = sprintf(write_ptr, "hello") + 1;
|
||||
soundio_ring_buffer_advance_write_ptr(rb, amt);
|
||||
|
||||
assert(soundio_ring_buffer_fill_count(rb) == amt);
|
||||
assert(soundio_ring_buffer_free_count(rb) == page_size - amt);
|
||||
|
||||
char *read_ptr = soundio_ring_buffer_read_ptr(rb);
|
||||
|
||||
assert(strcmp(read_ptr, "hello") == 0);
|
||||
|
||||
soundio_ring_buffer_advance_read_ptr(rb, amt);
|
||||
|
||||
assert(soundio_ring_buffer_fill_count(rb) == 0);
|
||||
assert(soundio_ring_buffer_free_count(rb) == soundio_ring_buffer_capacity(rb));
|
||||
|
||||
soundio_ring_buffer_advance_write_ptr(rb, page_size - 2);
|
||||
soundio_ring_buffer_advance_read_ptr(rb, page_size - 2);
|
||||
amt = sprintf(soundio_ring_buffer_write_ptr(rb), "writing past the end") + 1;
|
||||
soundio_ring_buffer_advance_write_ptr(rb, amt);
|
||||
|
||||
assert(soundio_ring_buffer_fill_count(rb) == amt);
|
||||
|
||||
assert(strcmp(soundio_ring_buffer_read_ptr(rb), "writing past the end") == 0);
|
||||
|
||||
soundio_ring_buffer_advance_read_ptr(rb, amt);
|
||||
|
||||
assert(soundio_ring_buffer_fill_count(rb) == 0);
|
||||
assert(soundio_ring_buffer_free_count(rb) == soundio_ring_buffer_capacity(rb));
|
||||
soundio_ring_buffer_destroy(rb);
|
||||
soundio_destroy(soundio);
|
||||
}
|
||||
|
||||
static struct SoundIoRingBuffer *rb = NULL;
|
||||
static const int rb_size = 3528;
|
||||
static long expected_write_head;
|
||||
static long expected_read_head;
|
||||
static struct SoundIoAtomicBool rb_done;
|
||||
static struct SoundIoAtomicInt rb_write_it;
|
||||
static struct SoundIoAtomicInt rb_read_it;
|
||||
|
||||
// just for testing purposes; does not need to be high quality random
|
||||
static double random_double(void) {
|
||||
return ((double)rand() / (double)RAND_MAX);
|
||||
}
|
||||
|
||||
static void reader_thread_run(void *arg) {
|
||||
while (!SOUNDIO_ATOMIC_LOAD(rb_done)) {
|
||||
SOUNDIO_ATOMIC_FETCH_ADD(rb_read_it, 1);
|
||||
int fill_count = soundio_ring_buffer_fill_count(rb);
|
||||
assert(fill_count >= 0);
|
||||
assert(fill_count <= rb_size);
|
||||
int amount_to_read = soundio_int_min(random_double() * 2.0 * fill_count, fill_count);
|
||||
soundio_ring_buffer_advance_read_ptr(rb, amount_to_read);
|
||||
expected_read_head += amount_to_read;
|
||||
}
|
||||
}
|
||||
|
||||
static void writer_thread_run(void *arg) {
|
||||
while (!SOUNDIO_ATOMIC_LOAD(rb_done)) {
|
||||
SOUNDIO_ATOMIC_FETCH_ADD(rb_write_it, 1);
|
||||
int fill_count = soundio_ring_buffer_fill_count(rb);
|
||||
assert(fill_count >= 0);
|
||||
assert(fill_count <= rb_size);
|
||||
int free_count = rb_size - fill_count;
|
||||
assert(free_count >= 0);
|
||||
assert(free_count <= rb_size);
|
||||
int value = soundio_int_min(random_double() * 2.0 * free_count, free_count);
|
||||
soundio_ring_buffer_advance_write_ptr(rb, value);
|
||||
expected_write_head += value;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_ring_buffer_threaded(void) {
|
||||
struct SoundIo *soundio = soundio_create();
|
||||
assert(soundio);
|
||||
rb = soundio_ring_buffer_create(soundio, rb_size);
|
||||
expected_write_head = 0;
|
||||
expected_read_head = 0;
|
||||
SOUNDIO_ATOMIC_STORE(rb_read_it, 0);
|
||||
SOUNDIO_ATOMIC_STORE(rb_write_it, 0);
|
||||
SOUNDIO_ATOMIC_STORE(rb_done, false);
|
||||
|
||||
struct SoundIoOsThread *reader_thread;
|
||||
ok_or_panic(soundio_os_thread_create(reader_thread_run, NULL, NULL, &reader_thread));
|
||||
|
||||
struct SoundIoOsThread *writer_thread;
|
||||
ok_or_panic(soundio_os_thread_create(writer_thread_run, NULL, NULL, &writer_thread));
|
||||
|
||||
while (SOUNDIO_ATOMIC_LOAD(rb_read_it) < 100000 || SOUNDIO_ATOMIC_LOAD(rb_write_it) < 100000) {}
|
||||
SOUNDIO_ATOMIC_STORE(rb_done, true);
|
||||
|
||||
soundio_os_thread_destroy(reader_thread);
|
||||
soundio_os_thread_destroy(writer_thread);
|
||||
|
||||
int fill_count = soundio_ring_buffer_fill_count(rb);
|
||||
int expected_fill_count = expected_write_head - expected_read_head;
|
||||
assert(fill_count == expected_fill_count);
|
||||
soundio_destroy(soundio);
|
||||
}
|
||||
|
||||
static void test_mirrored_memory(void) {
|
||||
struct SoundIoOsMirroredMemory mem;
|
||||
ok_or_panic(soundio_os_init());
|
||||
|
||||
static const int requested_bytes = 1024;
|
||||
ok_or_panic(soundio_os_init_mirrored_memory(&mem, requested_bytes));
|
||||
const int size_bytes = mem.capacity;
|
||||
|
||||
for (int i = 0; i < size_bytes; i += 1) {
|
||||
mem.address[i] = rand() % CHAR_MAX;
|
||||
}
|
||||
for (int i = 0; i < size_bytes; i += 1) {
|
||||
assert(mem.address[i] == mem.address[size_bytes+i]);
|
||||
}
|
||||
|
||||
soundio_os_deinit_mirrored_memory(&mem);
|
||||
}
|
||||
|
||||
static void test_nearest_sample_rate(void) {
|
||||
struct SoundIoDevice device;
|
||||
struct SoundIoSampleRateRange sample_rates[2] = {
|
||||
{
|
||||
44100,
|
||||
48000
|
||||
},
|
||||
{
|
||||
96000,
|
||||
96000,
|
||||
},
|
||||
};
|
||||
|
||||
device.sample_rate_count = 2;
|
||||
device.sample_rates = sample_rates;
|
||||
|
||||
assert(soundio_device_nearest_sample_rate(&device, 100) == 44100);
|
||||
assert(soundio_device_nearest_sample_rate(&device, 44099) == 44100);
|
||||
assert(soundio_device_nearest_sample_rate(&device, 44100) == 44100);
|
||||
assert(soundio_device_nearest_sample_rate(&device, 45000) == 45000);
|
||||
assert(soundio_device_nearest_sample_rate(&device, 48000) == 48000);
|
||||
assert(soundio_device_nearest_sample_rate(&device, 48001) == 96000);
|
||||
assert(soundio_device_nearest_sample_rate(&device, 90000) == 96000);
|
||||
assert(soundio_device_nearest_sample_rate(&device, 96001) == 96000);
|
||||
assert(soundio_device_nearest_sample_rate(&device, 9999999) == 96000);
|
||||
}
|
||||
|
||||
struct Test {
|
||||
const char *name;
|
||||
void (*fn)(void);
|
||||
};
|
||||
|
||||
static struct Test tests[] = {
|
||||
{"os_get_time", test_os_get_time},
|
||||
{"create output stream", test_create_outstream},
|
||||
{"mirrored memory", test_mirrored_memory},
|
||||
{"soundio_device_nearest_sample_rate", test_nearest_sample_rate},
|
||||
{"ring buffer basic", test_ring_buffer_basic},
|
||||
{"ring buffer threaded", test_ring_buffer_threaded},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
static void exec_test(struct Test *test) {
|
||||
fprintf(stderr, "testing %s...", test->name);
|
||||
test->fn();
|
||||
fprintf(stderr, "OK\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *match = NULL;
|
||||
|
||||
if (argc == 2)
|
||||
match = argv[1];
|
||||
|
||||
struct Test *test = &tests[0];
|
||||
|
||||
while (test->name) {
|
||||
if (!match || strstr(test->name, match))
|
||||
exec_test(test);
|
||||
test += 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
124
thirdparty/libsoundio/test/valgrind.supp
vendored
124
thirdparty/libsoundio/test/valgrind.supp
vendored
@ -1,124 +0,0 @@
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: possible
|
||||
fun:malloc
|
||||
...
|
||||
obj:*/libasound.so.2.0.0
|
||||
fun:snd_config_hook_load
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: possible
|
||||
fun:calloc
|
||||
...
|
||||
obj:*/libasound.so.2.0.0
|
||||
fun:snd_config_hook_load
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: possible
|
||||
fun:malloc
|
||||
...
|
||||
obj:*/libasound.so.2.0.0
|
||||
fun:snd_config_update_r
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: possible
|
||||
fun:calloc
|
||||
...
|
||||
obj:*/libasound.so.2.0.0
|
||||
fun:snd_config_update_r
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: possible
|
||||
fun:malloc
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: possible
|
||||
fun:calloc
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
obj:*/libasound.so.2.0.0
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: possible
|
||||
fun:malloc
|
||||
...
|
||||
obj:*/libasound.so.2.0.0
|
||||
fun:snd_config_load
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: possible
|
||||
fun:malloc
|
||||
...
|
||||
obj:*/libasound.so.2.0.0
|
||||
fun:parse_array_defs
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: possible
|
||||
fun:malloc
|
||||
...
|
||||
fun:snd1_dlobj_cache_get
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: definite
|
||||
fun:malloc
|
||||
fun:snd_pcm_hw_get_chmap
|
||||
fun:snd_pcm_get_chmap
|
||||
fun:snd1_pcm_direct_get_chmap
|
||||
fun:snd_pcm_get_chmap
|
||||
fun:snd1_pcm_generic_get_chmap
|
||||
fun:snd_pcm_get_chmap
|
||||
fun:snd1_pcm_generic_get_chmap
|
||||
fun:snd_pcm_get_chmap
|
||||
fun:snd1_pcm_generic_get_chmap
|
||||
fun:snd_pcm_get_chmap
|
||||
fun:snd_pcm_set_chmap
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Cond
|
||||
fun:snd_interval_floor
|
||||
fun:snd_pcm_plug_hw_refine_cchange
|
||||
fun:snd1_pcm_hw_refine_slave
|
||||
fun:snd_pcm_plug_hw_refine
|
||||
fun:snd_pcm_hw_refine
|
||||
fun:snd1_pcm_hw_param_set_last
|
||||
...
|
||||
}
|
Loading…
Reference in New Issue
Block a user