|
|
|
@ -132,18 +132,30 @@
|
|
|
|
|
a good balance between low-latency and glitch-free playback
|
|
|
|
|
on all audio backends.
|
|
|
|
|
|
|
|
|
|
You should always provide a logging callback to be aware of any
|
|
|
|
|
warnings and errors. The easiest way is to use sokol_log.h for this:
|
|
|
|
|
|
|
|
|
|
#include "sokol_log.h"
|
|
|
|
|
// ...
|
|
|
|
|
saudio_setup(&(saudio_desc){
|
|
|
|
|
.logger = {
|
|
|
|
|
.func = slog_func,
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
If you want to use the callback-model, you need to provide a stream
|
|
|
|
|
callback function either in saudio_desc.stream_cb or saudio_desc.stream_userdata_cb,
|
|
|
|
|
otherwise keep both function pointers zero-initialized.
|
|
|
|
|
|
|
|
|
|
Use push model and default playback parameters:
|
|
|
|
|
|
|
|
|
|
saudio_setup(&(saudio_desc){0});
|
|
|
|
|
saudio_setup(&(saudio_desc){ .logger.func = slog_func });
|
|
|
|
|
|
|
|
|
|
Use stream callback model and default playback parameters:
|
|
|
|
|
|
|
|
|
|
saudio_setup(&(saudio_desc){
|
|
|
|
|
.stream_cb = my_stream_callback
|
|
|
|
|
.logger.func = slog_func,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
The standard stream callback doesn't have a user data argument, if you want
|
|
|
|
@ -152,6 +164,7 @@
|
|
|
|
|
saudio_setup(&(saudio_desc){
|
|
|
|
|
.stream_userdata_cb = my_stream_callback,
|
|
|
|
|
.user_data = &my_data
|
|
|
|
|
.logger.func = slog_func,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
The following playback parameters can be provided through the
|
|
|
|
@ -400,27 +413,43 @@
|
|
|
|
|
was called, so you don't need to worry about thread-safety.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LOG FUNCTION OVERRIDE
|
|
|
|
|
=====================
|
|
|
|
|
You can override the log function at initialization time like this:
|
|
|
|
|
ERROR REPORTING AND LOGGING
|
|
|
|
|
===========================
|
|
|
|
|
To get any logging information at all you need to provide a logging callback in the setup call
|
|
|
|
|
the easiest way is to use sokol_log.h:
|
|
|
|
|
|
|
|
|
|
void my_log(const char* message, void* user_data) {
|
|
|
|
|
printf("saudio says: \s\n", message);
|
|
|
|
|
}
|
|
|
|
|
#include "sokol_log.h"
|
|
|
|
|
|
|
|
|
|
saudio_setup(&(saudio_desc){ .logger.func = slog_func });
|
|
|
|
|
|
|
|
|
|
To override logging with your own callback, first write a logging function like this:
|
|
|
|
|
|
|
|
|
|
void my_log(const char* tag, // e.g. 'saudio'
|
|
|
|
|
uint32_t log_level, // 0=panic, 1=error, 2=warn, 3=info
|
|
|
|
|
uint32_t log_item_id, // SAUDIO_LOGITEM_*
|
|
|
|
|
const char* message_or_null, // a message string, may be nullptr in release mode
|
|
|
|
|
uint32_t line_nr, // line number in sokol_audio.h
|
|
|
|
|
const char* filename_or_null, // source filename, may be nullptr in release mode
|
|
|
|
|
void* user_data)
|
|
|
|
|
{
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
...and then setup sokol-audio like this:
|
|
|
|
|
|
|
|
|
|
saudio_setup(&(saudio_desc){
|
|
|
|
|
// ...
|
|
|
|
|
.logger = {
|
|
|
|
|
.log_cb = my_log,
|
|
|
|
|
.user_data = ...,
|
|
|
|
|
.func = my_log,
|
|
|
|
|
.user_data = my_user_data,
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
If no overrides are provided, puts will be used on most platforms.
|
|
|
|
|
On Android, __android_log_write will be used instead.
|
|
|
|
|
The provided logging function must be reentrant (e.g. be callable from
|
|
|
|
|
different threads).
|
|
|
|
|
|
|
|
|
|
If you don't want to provide your own custom logger it is highly recommended to use
|
|
|
|
|
the standard logger in sokol_log.h instead, otherwise you won't see any warnings or
|
|
|
|
|
errors.
|
|
|
|
|
|
|
|
|
|
LICENSE
|
|
|
|
|
=======
|
|
|
|
@ -470,6 +499,77 @@
|
|
|
|
|
extern "C" {
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
saudio_log_item
|
|
|
|
|
|
|
|
|
|
Log items are defined via X-Macros, and expanded to an
|
|
|
|
|
enum 'saudio_log_item', and in debug mode only,
|
|
|
|
|
corresponding strings.
|
|
|
|
|
|
|
|
|
|
Used as parameter in the logging callback.
|
|
|
|
|
*/
|
|
|
|
|
#define _SAUDIO_LOG_ITEMS \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(OK, "Ok") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(MALLOC_FAILED, "memory allocation failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(ALSA_SND_PCM_OPEN_FAILED, "snd_pcm_open() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(ALSA_FLOAT_SAMPLES_NOT_SUPPORTED, "floating point sample format not supported") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(ALSA_REQUESTED_BUFFER_SIZE_NOT_SUPPORTED, "requested buffer size not supported") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(ALSA_REQUESTED_CHANNEL_COUNT_NOT_SUPPORTED, "requested channel count not supported") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(ALSA_SND_PCM_HW_PARAMS_SET_RATE_NEAR_FAILED, "snd_pcm_hw_params_set_rate_near() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(ALSA_SND_PCM_HW_PARAMS_FAILED, "snd_pcm_hw_params() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(ALSA_PTHREAD_CREATE_FAILED, "pthread_create() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(WASAPI_CREATE_EVENT_FAILED, "CreateEvent() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(WASAPI_CREATE_DEVICE_ENUMERATOR_FAILED, "CoCreateInstance() for IMMDeviceEnumerator failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(WASAPI_GET_DEFAULT_AUDIO_ENDPOINT_FAILED, "IMMDeviceEnumerator.GetDefaultAudioEndpoint() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(WASAPI_DEVICE_ACTIVATE_FAILED, "IMMDevice.Activate() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(WASAPI_AUDIO_CLIENT_INITIALIZE_FAILED, "IAudioClient.Initialize() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(WASAPI_AUDIO_CLIENT_GET_BUFFER_SIZE_FAILED, "IAudioClient.GetBufferSize() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(WASAPI_AUDIO_CLIENT_GET_SERVICE_FAILED, "IAudioClient.GetService() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(WASAPI_AUDIO_CLIENT_SET_EVENT_HANDLE_FAILED, "IAudioClient.SetEventHandle() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(WASAPI_CREATE_THREAD_FAILED, "CreateThread() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(AAUDIO_STREAMBUILDER_OPEN_STREAM_FAILED, "AAudioStreamBuilder_openStream() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(AAUDIO_PTHREAD_CREATE_FAILED, "pthread_create() failed after AAUDIO_ERROR_DISCONNECTED") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(AAUDIO_RESTARTING_STREAM_AFTER_ERROR, "restarting AAudio stream after error") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(USING_AAUDIO_BACKEND, "using AAudio backend") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(AAUDIO_CREATE_STREAMBUILDER_FAILED, "AAudio_createStreamBuilder() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(USING_SLES_BACKEND, "using OpenSLES backend") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(SLES_CREATE_ENGINE_FAILED, "slCreateEngine() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(SLES_ENGINE_GET_ENGINE_INTERFACE_FAILED, "GetInterface() for SL_IID_ENGINE failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(SLES_CREATE_OUTPUT_MIX_FAILED, "CreateOutputMix() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(SLES_MIXER_GET_VOLUME_INTERFACE_FAILED, "GetInterface() for SL_IID_VOLUME failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(SLES_ENGINE_CREATE_AUDIO_PLAYER_FAILED, "CreateAudioPlayer() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(SLES_PLAYER_GET_PLAY_INTERFACE_FAILED, "GetInterface() for SL_IID_PLAY failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(SLES_PLAYER_GET_VOLUME_INTERFACE_FAILED, "GetInterface() for SL_IID_VOLUME failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(SLES_PLAYER_GET_BUFFERQUEUE_INTERFACE_FAILED, "GetInterface() for SL_IID_ANDROIDSIMPLEBUFFERQUEUE failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(COREAUDIO_NEW_OUTPUT_FAILED, "AudioQueueNewOutput() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(COREAUDIO_ALLOCATE_BUFFER_FAILED, "AudioQueueAllocateBuffer() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(COREAUDIO_START_FAILED, "AudioQueueStart() failed") \
|
|
|
|
|
_SAUDIO_LOGITEM_XMACRO(BACKEND_BUFFER_SIZE_ISNT_MULTIPLE_OF_PACKET_SIZE, "backend buffer size isn't multiple of packet size") \
|
|
|
|
|
|
|
|
|
|
#define _SAUDIO_LOGITEM_XMACRO(item,msg) SAUDIO_LOGITEM_##item,
|
|
|
|
|
typedef enum saudio_log_item {
|
|
|
|
|
_SAUDIO_LOG_ITEMS
|
|
|
|
|
} saudio_log_item;
|
|
|
|
|
#undef _SAUDIO_LOGITEM_XMACRO
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
saudio_logger
|
|
|
|
|
|
|
|
|
|
Used in saudio_desc to provide a custom logging and error reporting
|
|
|
|
|
callback to sokol-audio.
|
|
|
|
|
*/
|
|
|
|
|
typedef struct saudio_logger {
|
|
|
|
|
void (*func)(
|
|
|
|
|
const char* tag, // always "saudio"
|
|
|
|
|
uint32_t log_level, // 0=panic, 1=error, 2=warning, 3=info
|
|
|
|
|
uint32_t log_item_id, // SAUDIO_LOGITEM_*
|
|
|
|
|
const char* message_or_null, // a message string, may be nullptr in release mode
|
|
|
|
|
uint32_t line_nr, // line number in sokol_audio.h
|
|
|
|
|
const char* filename_or_null, // source filename, may be nullptr in release mode
|
|
|
|
|
void* user_data);
|
|
|
|
|
void* user_data;
|
|
|
|
|
} saudio_logger;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
saudio_allocator
|
|
|
|
|
|
|
|
|
@ -484,17 +584,6 @@ typedef struct saudio_allocator {
|
|
|
|
|
void* user_data;
|
|
|
|
|
} saudio_allocator;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
saudio_logger
|
|
|
|
|
|
|
|
|
|
Used in saudio_desc to provide custom log callbacks to sokol_audio.h.
|
|
|
|
|
Default behavior is SOKOL_LOG(message).
|
|
|
|
|
*/
|
|
|
|
|
typedef struct saudio_logger {
|
|
|
|
|
void (*log_cb)(const char* message, void* user_data);
|
|
|
|
|
void* user_data;
|
|
|
|
|
} saudio_logger;
|
|
|
|
|
|
|
|
|
|
typedef struct saudio_desc {
|
|
|
|
|
int sample_rate; // requested sample rate
|
|
|
|
|
int num_channels; // number of channels, default: 1 (mono)
|
|
|
|
@ -505,7 +594,7 @@ typedef struct saudio_desc {
|
|
|
|
|
void (*stream_userdata_cb)(float* buffer, int num_frames, int num_channels, void* user_data); //... and with user data
|
|
|
|
|
void* user_data; // optional user data argument for stream_userdata_cb
|
|
|
|
|
saudio_allocator allocator; // optional allocation override functions
|
|
|
|
|
saudio_logger logger; // optional log override functions
|
|
|
|
|
saudio_logger logger; // optional logging function (default: NO LOGGING!)
|
|
|
|
|
} saudio_desc;
|
|
|
|
|
|
|
|
|
|
/* setup sokol-audio */
|
|
|
|
@ -540,12 +629,11 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc);
|
|
|
|
|
#endif
|
|
|
|
|
#endif // SOKOL_AUDIO_INCLUDED
|
|
|
|
|
|
|
|
|
|
// ██╗███╗ ███╗██████╗ ██╗ ███████╗███╗ ███╗███████╗███╗ ██╗████████╗ █████╗ ████████╗██╗ ██████╗ ███╗ ██╗
|
|
|
|
|
// ██║████╗ ████║██╔══██╗██║ ██╔════╝████╗ ████║██╔════╝████╗ ██║╚══██╔══╝██╔══██╗╚══██╔══╝██║██╔═══██╗████╗ ██║
|
|
|
|
|
// ██║██╔████╔██║██████╔╝██║ █████╗ ██╔████╔██║█████╗ ██╔██╗ ██║ ██║ ███████║ ██║ ██║██║ ██║██╔██╗ ██║
|
|
|
|
|
// ██║██║╚██╔╝██║██╔═══╝ ██║ ██╔══╝ ██║╚██╔╝██║██╔══╝ ██║╚██╗██║ ██║ ██╔══██║ ██║ ██║██║ ██║██║╚██╗██║
|
|
|
|
|
// ██║██║ ╚═╝ ██║██║ ███████╗███████╗██║ ╚═╝ ██║███████╗██║ ╚████║ ██║ ██║ ██║ ██║ ██║╚██████╔╝██║ ╚████║
|
|
|
|
|
// ╚═╝╚═╝ ╚═╝╚═╝ ╚══════╝╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
|
|
|
|
|
// ██ ███ ███ ██████ ██ ███████ ███ ███ ███████ ███ ██ ████████ █████ ████████ ██ ██████ ███ ██
|
|
|
|
|
// ██ ████ ████ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██
|
|
|
|
|
// ██ ██ ████ ██ ██████ ██ █████ ██ ████ ██ █████ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██ ██ ██ ██ ███████ ███████ ██ ██ ███████ ██ ████ ██ ██ ██ ██ ██ ██████ ██ ████
|
|
|
|
|
//
|
|
|
|
|
// >>implementation
|
|
|
|
|
#ifdef SOKOL_AUDIO_IMPL
|
|
|
|
@ -572,21 +660,6 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc);
|
|
|
|
|
#define SOKOL_ASSERT(c) assert(c)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if !defined(SOKOL_DEBUG)
|
|
|
|
|
#define SAUDIO_LOG(s)
|
|
|
|
|
#else
|
|
|
|
|
#define SAUDIO_LOG(s) _saudio_log(s)
|
|
|
|
|
#ifndef SOKOL_LOG
|
|
|
|
|
#if defined(__ANDROID__)
|
|
|
|
|
#include <android/log.h>
|
|
|
|
|
#define SOKOL_LOG(s) __android_log_write(ANDROID_LOG_INFO, "SOKOL_AUDIO", s)
|
|
|
|
|
#else
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#define SOKOL_LOG(s) puts(s)
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef _SOKOL_PRIVATE
|
|
|
|
|
#if defined(__GNUC__) || defined(__clang__)
|
|
|
|
|
#define _SOKOL_PRIVATE __attribute__((unused)) static
|
|
|
|
@ -611,14 +684,12 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc);
|
|
|
|
|
#define _SAUDIO_MACOS (1)
|
|
|
|
|
#endif
|
|
|
|
|
#elif defined(__EMSCRIPTEN__)
|
|
|
|
|
#define _SAUDIO_EMSCRIPTEN
|
|
|
|
|
#define _SAUDIO_EMSCRIPTEN (1)
|
|
|
|
|
#elif defined(_WIN32)
|
|
|
|
|
#define _SAUDIO_WINDOWS (1)
|
|
|
|
|
#include <winapifamily.h>
|
|
|
|
|
#if (defined(WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP))
|
|
|
|
|
#define _SAUDIO_UWP (1)
|
|
|
|
|
#else
|
|
|
|
|
#define _SAUDIO_WIN32 (1)
|
|
|
|
|
#error "sokol_audio.h no longer supports UWP"
|
|
|
|
|
#endif
|
|
|
|
|
#elif defined(__ANDROID__)
|
|
|
|
|
#define _SAUDIO_ANDROID (1)
|
|
|
|
@ -644,12 +715,8 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc);
|
|
|
|
|
#endif
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
#include <synchapi.h>
|
|
|
|
|
#if defined(_SAUDIO_UWP)
|
|
|
|
|
#pragma comment (lib, "WindowsApp")
|
|
|
|
|
#else
|
|
|
|
|
#pragma comment (lib, "kernel32")
|
|
|
|
|
#pragma comment (lib, "ole32")
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef CINTERFACE
|
|
|
|
|
#define CINTERFACE
|
|
|
|
|
#endif
|
|
|
|
@ -713,6 +780,7 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc);
|
|
|
|
|
#include "aaudio/AAudio.h"
|
|
|
|
|
#endif
|
|
|
|
|
#elif defined(_SAUDIO_LINUX)
|
|
|
|
|
#include <alloca.h>
|
|
|
|
|
#define _SAUDIO_PTHREADS (1)
|
|
|
|
|
#include <pthread.h>
|
|
|
|
|
#define ALSA_PCM_NEW_HW_PARAMS_API
|
|
|
|
@ -734,12 +802,11 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc);
|
|
|
|
|
#define SAUDIO_RING_MAX_SLOTS (1024)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// ███████╗████████╗██████╗ ██╗ ██╗ ██████╗████████╗███████╗
|
|
|
|
|
// ██╔════╝╚══██╔══╝██╔══██╗██║ ██║██╔════╝╚══██╔══╝██╔════╝
|
|
|
|
|
// ███████╗ ██║ ██████╔╝██║ ██║██║ ██║ ███████╗
|
|
|
|
|
// ╚════██║ ██║ ██╔══██╗██║ ██║██║ ██║ ╚════██║
|
|
|
|
|
// ███████║ ██║ ██║ ██║╚██████╔╝╚██████╗ ██║ ███████║
|
|
|
|
|
// ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
|
|
|
|
|
// ███████ ████████ ██████ ██ ██ ██████ ████████ ███████
|
|
|
|
|
// ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ███████ ██ ██████ ██ ██ ██ ██ ███████
|
|
|
|
|
// ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ███████ ██ ██ ██ ██████ ██████ ██ ███████
|
|
|
|
|
//
|
|
|
|
|
// >>structs
|
|
|
|
|
#if defined(_SAUDIO_PTHREADS)
|
|
|
|
@ -939,15 +1006,8 @@ typedef struct {
|
|
|
|
|
} _saudio_wasapi_thread_data_t;
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
#if defined(_SAUDIO_UWP)
|
|
|
|
|
LPOLESTR interface_activation_audio_interface_uid_string;
|
|
|
|
|
IActivateAudioInterfaceAsyncOperation* interface_activation_operation;
|
|
|
|
|
BOOL interface_activation_success;
|
|
|
|
|
HANDLE interface_activation_mutex;
|
|
|
|
|
#else
|
|
|
|
|
IMMDeviceEnumerator* device_enumerator;
|
|
|
|
|
IMMDevice* device;
|
|
|
|
|
#endif
|
|
|
|
|
IAudioClient* audio_client;
|
|
|
|
|
IAudioRenderClient* render_client;
|
|
|
|
|
_saudio_wasapi_thread_data_t thread;
|
|
|
|
@ -1032,12 +1092,50 @@ _SOKOL_PRIVATE void _saudio_stream_callback(float* buffer, int num_frames, int n
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ███╗ ███╗███████╗███╗ ███╗ ██████╗ ██████╗ ██╗ ██╗
|
|
|
|
|
// ████╗ ████║██╔════╝████╗ ████║██╔═══██╗██╔══██╗╚██╗ ██╔╝
|
|
|
|
|
// ██╔████╔██║█████╗ ██╔████╔██║██║ ██║██████╔╝ ╚████╔╝
|
|
|
|
|
// ██║╚██╔╝██║██╔══╝ ██║╚██╔╝██║██║ ██║██╔══██╗ ╚██╔╝
|
|
|
|
|
// ██║ ╚═╝ ██║███████╗██║ ╚═╝ ██║╚██████╔╝██║ ██║ ██║
|
|
|
|
|
// ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝
|
|
|
|
|
// ██ ██████ ██████ ██████ ██ ███ ██ ██████
|
|
|
|
|
// ██ ██ ██ ██ ██ ██ ████ ██ ██
|
|
|
|
|
// ██ ██ ██ ██ ███ ██ ███ ██ ██ ██ ██ ██ ███
|
|
|
|
|
// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ███████ ██████ ██████ ██████ ██ ██ ████ ██████
|
|
|
|
|
//
|
|
|
|
|
// >>logging
|
|
|
|
|
#if defined(SOKOL_DEBUG)
|
|
|
|
|
#define _SAUDIO_LOGITEM_XMACRO(item,msg) #item ": " msg,
|
|
|
|
|
static const char* _saudio_log_messages[] = {
|
|
|
|
|
_SAUDIO_LOG_ITEMS
|
|
|
|
|
};
|
|
|
|
|
#undef _SAUDIO_LOGITEM_XMACRO
|
|
|
|
|
#endif // SOKOL_DEBUG
|
|
|
|
|
|
|
|
|
|
#define _SAUDIO_PANIC(code) _saudio_log(SAUDIO_LOGITEM_ ##code, 0, __LINE__)
|
|
|
|
|
#define _SAUDIO_ERROR(code) _saudio_log(SAUDIO_LOGITEM_ ##code, 1, __LINE__)
|
|
|
|
|
#define _SAUDIO_WARN(code) _saudio_log(SAUDIO_LOGITEM_ ##code, 2, __LINE__)
|
|
|
|
|
#define _SAUDIO_INFO(code) _saudio_log(SAUDIO_LOGITEM_ ##code, 3, __LINE__)
|
|
|
|
|
|
|
|
|
|
static void _saudio_log(saudio_log_item log_item, uint32_t log_level, uint32_t line_nr) {
|
|
|
|
|
if (_saudio.desc.logger.func) {
|
|
|
|
|
#if defined(SOKOL_DEBUG)
|
|
|
|
|
const char* filename = __FILE__;
|
|
|
|
|
const char* message = _saudio_log_messages[log_item];
|
|
|
|
|
#else
|
|
|
|
|
const char* filename = 0;
|
|
|
|
|
const char* message = 0;
|
|
|
|
|
#endif
|
|
|
|
|
_saudio.desc.logger.func("saudio", log_level, log_item, message, line_nr, filename, _saudio.desc.logger.user_data);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// for log level PANIC it would be 'undefined behaviour' to continue
|
|
|
|
|
if (log_level == 0) {
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ███ ███ ███████ ███ ███ ██████ ██████ ██ ██
|
|
|
|
|
// ████ ████ ██ ████ ████ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██ ████ ██ █████ ██ ████ ██ ██ ██ ██████ ████
|
|
|
|
|
// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██ ██ ███████ ██ ██ ██████ ██ ██ ██
|
|
|
|
|
//
|
|
|
|
|
// >>memory
|
|
|
|
|
_SOKOL_PRIVATE void _saudio_clear(void* ptr, size_t size) {
|
|
|
|
@ -1054,7 +1152,9 @@ _SOKOL_PRIVATE void* _saudio_malloc(size_t size) {
|
|
|
|
|
else {
|
|
|
|
|
ptr = malloc(size);
|
|
|
|
|
}
|
|
|
|
|
SOKOL_ASSERT(ptr);
|
|
|
|
|
if (0 == ptr) {
|
|
|
|
|
_SAUDIO_PANIC(MALLOC_FAILED);
|
|
|
|
|
}
|
|
|
|
|
return ptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1073,23 +1173,11 @@ _SOKOL_PRIVATE void _saudio_free(void* ptr) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined(SOKOL_DEBUG)
|
|
|
|
|
_SOKOL_PRIVATE void _saudio_log(const char* msg) {
|
|
|
|
|
SOKOL_ASSERT(msg);
|
|
|
|
|
if (_saudio.desc.logger.log_cb) {
|
|
|
|
|
_saudio.desc.logger.log_cb(msg, _saudio.desc.logger.user_data);
|
|
|
|
|
} else {
|
|
|
|
|
SOKOL_LOG(msg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// ███╗ ███╗██╗ ██╗████████╗███████╗██╗ ██╗
|
|
|
|
|
// ████╗ ████║██║ ██║╚══██╔══╝██╔════╝╚██╗██╔╝
|
|
|
|
|
// ██╔████╔██║██║ ██║ ██║ █████╗ ╚███╔╝
|
|
|
|
|
// ██║╚██╔╝██║██║ ██║ ██║ ██╔══╝ ██╔██╗
|
|
|
|
|
// ██║ ╚═╝ ██║╚██████╔╝ ██║ ███████╗██╔╝ ██╗
|
|
|
|
|
// ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝
|
|
|
|
|
// ███ ███ ██ ██ ████████ ███████ ██ ██
|
|
|
|
|
// ████ ████ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██ ████ ██ ██ ██ ██ █████ ███
|
|
|
|
|
// ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██ ██ ██████ ██ ███████ ██ ██
|
|
|
|
|
//
|
|
|
|
|
// >>mutex
|
|
|
|
|
#if defined(_SAUDIO_NOTHREADS)
|
|
|
|
@ -1140,12 +1228,11 @@ _SOKOL_PRIVATE void _saudio_mutex_unlock(_saudio_mutex_t* m) {
|
|
|
|
|
#error "sokol_audio.h: unknown platform!"
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// ██████╗ ██╗███╗ ██╗ ██████╗ ██████╗ ██╗ ██╗███████╗███████╗███████╗██████╗
|
|
|
|
|
// ██╔══██╗██║████╗ ██║██╔════╝ ██╔══██╗██║ ██║██╔════╝██╔════╝██╔════╝██╔══██╗
|
|
|
|
|
// ██████╔╝██║██╔██╗ ██║██║ ███╗██████╔╝██║ ██║█████╗ █████╗ █████╗ ██████╔╝
|
|
|
|
|
// ██╔══██╗██║██║╚██╗██║██║ ██║██╔══██╗██║ ██║██╔══╝ ██╔══╝ ██╔══╝ ██╔══██╗
|
|
|
|
|
// ██║ ██║██║██║ ╚████║╚██████╔╝██████╔╝╚██████╔╝██║ ██║ ███████╗██║ ██║
|
|
|
|
|
// ╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝
|
|
|
|
|
// ██████ ██ ███ ██ ██████ ██████ ██ ██ ███████ ███████ ███████ ██████
|
|
|
|
|
// ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██████ ██ ██ ██ ██ ██ ███ ██████ ██ ██ █████ █████ █████ ██████
|
|
|
|
|
// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██ ██ ██ ██ ████ ██████ ██████ ██████ ██ ██ ███████ ██ ██
|
|
|
|
|
//
|
|
|
|
|
// >>ringbuffer
|
|
|
|
|
_SOKOL_PRIVATE int _saudio_ring_idx(_saudio_ring_t* ring, int i) {
|
|
|
|
@ -1193,12 +1280,11 @@ _SOKOL_PRIVATE int _saudio_ring_dequeue(_saudio_ring_t* ring) {
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ███████╗██╗███████╗ ██████╗
|
|
|
|
|
// ██╔════╝██║██╔════╝██╔═══██╗
|
|
|
|
|
// █████╗ ██║█████╗ ██║ ██║
|
|
|
|
|
// ██╔══╝ ██║██╔══╝ ██║ ██║
|
|
|
|
|
// ██║ ██║██║ ╚██████╔╝
|
|
|
|
|
// ╚═╝ ╚═╝╚═╝ ╚═════╝
|
|
|
|
|
// ███████ ██ ███████ ██████
|
|
|
|
|
// ██ ██ ██ ██ ██
|
|
|
|
|
// █████ ██ █████ ██ ██
|
|
|
|
|
// ██ ██ ██ ██ ██
|
|
|
|
|
// ██ ██ ██ ██████
|
|
|
|
|
//
|
|
|
|
|
// >>fifo
|
|
|
|
|
_SOKOL_PRIVATE void _saudio_fifo_init_mutex(_saudio_fifo_t* fifo) {
|
|
|
|
@ -1330,12 +1416,11 @@ _SOKOL_PRIVATE int _saudio_fifo_read(_saudio_fifo_t* fifo, uint8_t* ptr, int num
|
|
|
|
|
return num_bytes_copied;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ██████╗ ██╗ ██╗███╗ ███╗███╗ ███╗██╗ ██╗
|
|
|
|
|
// ██╔══██╗██║ ██║████╗ ████║████╗ ████║╚██╗ ██╔╝
|
|
|
|
|
// ██║ ██║██║ ██║██╔████╔██║██╔████╔██║ ╚████╔╝
|
|
|
|
|
// ██║ ██║██║ ██║██║╚██╔╝██║██║╚██╔╝██║ ╚██╔╝
|
|
|
|
|
// ██████╔╝╚██████╔╝██║ ╚═╝ ██║██║ ╚═╝ ██║ ██║
|
|
|
|
|
// ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝
|
|
|
|
|
// ██████ ██ ██ ███ ███ ███ ███ ██ ██
|
|
|
|
|
// ██ ██ ██ ██ ████ ████ ████ ████ ██ ██
|
|
|
|
|
// ██ ██ ██ ██ ██ ████ ██ ██ ████ ██ ████
|
|
|
|
|
// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██████ ██████ ██ ██ ██ ██ ██
|
|
|
|
|
//
|
|
|
|
|
// >>dummy
|
|
|
|
|
#if defined(SOKOL_DUMMY_BACKEND)
|
|
|
|
@ -1345,12 +1430,11 @@ _SOKOL_PRIVATE bool _saudio_dummy_backend_init(void) {
|
|
|
|
|
};
|
|
|
|
|
_SOKOL_PRIVATE void _saudio_dummy_backend_shutdown(void) { };
|
|
|
|
|
|
|
|
|
|
// █████╗ ██╗ ███████╗ █████╗
|
|
|
|
|
// ██╔══██╗██║ ██╔════╝██╔══██╗
|
|
|
|
|
// ███████║██║ ███████╗███████║
|
|
|
|
|
// ██╔══██║██║ ╚════██║██╔══██║
|
|
|
|
|
// ██║ ██║███████╗███████║██║ ██║
|
|
|
|
|
// ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝
|
|
|
|
|
// █████ ██ ███████ █████
|
|
|
|
|
// ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ███████ ██ ███████ ███████
|
|
|
|
|
// ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██ ██ ███████ ███████ ██ ██
|
|
|
|
|
//
|
|
|
|
|
// >>alsa
|
|
|
|
|
#elif defined(_SAUDIO_LINUX)
|
|
|
|
@ -1385,7 +1469,7 @@ _SOKOL_PRIVATE bool _saudio_alsa_backend_init(void) {
|
|
|
|
|
int dir; uint32_t rate;
|
|
|
|
|
int rc = snd_pcm_open(&_saudio.backend.device, "default", SND_PCM_STREAM_PLAYBACK, 0);
|
|
|
|
|
if (rc < 0) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio.h: snd_pcm_open() failed");
|
|
|
|
|
_SAUDIO_ERROR(ALSA_SND_PCM_OPEN_FAILED);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1398,26 +1482,26 @@ _SOKOL_PRIVATE bool _saudio_alsa_backend_init(void) {
|
|
|
|
|
snd_pcm_hw_params_any(_saudio.backend.device, params);
|
|
|
|
|
snd_pcm_hw_params_set_access(_saudio.backend.device, params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
|
|
|
|
if (0 > snd_pcm_hw_params_set_format(_saudio.backend.device, params, SND_PCM_FORMAT_FLOAT_LE)) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio.h: float samples not supported");
|
|
|
|
|
_SAUDIO_ERROR(ALSA_FLOAT_SAMPLES_NOT_SUPPORTED);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
if (0 > snd_pcm_hw_params_set_buffer_size(_saudio.backend.device, params, (snd_pcm_uframes_t)_saudio.buffer_frames)) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio.h: requested buffer size not supported");
|
|
|
|
|
_SAUDIO_ERROR(ALSA_REQUESTED_BUFFER_SIZE_NOT_SUPPORTED);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
if (0 > snd_pcm_hw_params_set_channels(_saudio.backend.device, params, (uint32_t)_saudio.num_channels)) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio.h: requested channel count not supported");
|
|
|
|
|
_SAUDIO_ERROR(ALSA_REQUESTED_CHANNEL_COUNT_NOT_SUPPORTED);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
/* let ALSA pick a nearby sampling rate */
|
|
|
|
|
rate = (uint32_t) _saudio.sample_rate;
|
|
|
|
|
dir = 0;
|
|
|
|
|
if (0 > snd_pcm_hw_params_set_rate_near(_saudio.backend.device, params, &rate, &dir)) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio.h: snd_pcm_hw_params_set_rate_near() failed");
|
|
|
|
|
_SAUDIO_ERROR(ALSA_SND_PCM_HW_PARAMS_SET_RATE_NEAR_FAILED);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
if (0 > snd_pcm_hw_params(_saudio.backend.device, params)) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio.h: snd_pcm_hw_params() failed");
|
|
|
|
|
_SAUDIO_ERROR(ALSA_SND_PCM_HW_PARAMS_FAILED);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1432,7 +1516,7 @@ _SOKOL_PRIVATE bool _saudio_alsa_backend_init(void) {
|
|
|
|
|
|
|
|
|
|
/* create the buffer-streaming start thread */
|
|
|
|
|
if (0 != pthread_create(&_saudio.backend.thread, 0, _saudio_alsa_cb, 0)) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio.h: pthread_create() failed");
|
|
|
|
|
_SAUDIO_ERROR(ALSA_PTHREAD_CREATE_FAILED);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1454,58 +1538,15 @@ _SOKOL_PRIVATE void _saudio_alsa_backend_shutdown(void) {
|
|
|
|
|
_saudio_free(_saudio.backend.buffer);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ██╗ ██╗ █████╗ ███████╗ █████╗ ██████╗ ██╗
|
|
|
|
|
// ██║ ██║██╔══██╗██╔════╝██╔══██╗██╔══██╗██║
|
|
|
|
|
// ██║ █╗ ██║███████║███████╗███████║██████╔╝██║
|
|
|
|
|
// ██║███╗██║██╔══██║╚════██║██╔══██║██╔═══╝ ██║
|
|
|
|
|
// ╚███╔███╔╝██║ ██║███████║██║ ██║██║ ██║
|
|
|
|
|
// ╚══╝╚══╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝
|
|
|
|
|
// ██ ██ █████ ███████ █████ ██████ ██
|
|
|
|
|
// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██ █ ██ ███████ ███████ ███████ ██████ ██
|
|
|
|
|
// ██ ███ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ███ ███ ██ ██ ███████ ██ ██ ██ ██
|
|
|
|
|
//
|
|
|
|
|
// >>wasapi
|
|
|
|
|
#elif defined(_SAUDIO_WINDOWS)
|
|
|
|
|
|
|
|
|
|
#if defined(_SAUDIO_UWP)
|
|
|
|
|
/* Minimal implementation of an IActivateAudioInterfaceCompletionHandler COM object in plain C.
|
|
|
|
|
Meant to be a static singleton (always one reference when add/remove reference)
|
|
|
|
|
and implements IUnknown and IActivateAudioInterfaceCompletionHandler when queryinterface'd
|
|
|
|
|
|
|
|
|
|
Do not know why but IActivateAudioInterfaceCompletionHandler's GUID is not the one system queries for,
|
|
|
|
|
so I'm advertising the one actually requested.
|
|
|
|
|
*/
|
|
|
|
|
_SOKOL_PRIVATE HRESULT STDMETHODCALLTYPE _saudio_interface_completion_handler_queryinterface(IActivateAudioInterfaceCompletionHandler* instance, REFIID riid, void** ppvObject) {
|
|
|
|
|
if (!ppvObject) {
|
|
|
|
|
return E_POINTER;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsEqualIID(riid, _SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IActivateAudioInterface_Completion_Handler)) || IsEqualIID(riid, _SOKOL_AUDIO_WIN32COM_ID(IID_IUnknown)))
|
|
|
|
|
{
|
|
|
|
|
*ppvObject = (void*)instance;
|
|
|
|
|
return S_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*ppvObject = NULL;
|
|
|
|
|
return E_NOINTERFACE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_SOKOL_PRIVATE ULONG STDMETHODCALLTYPE _saudio_interface_completion_handler_addref_release(IActivateAudioInterfaceCompletionHandler* instance) {
|
|
|
|
|
_SOKOL_UNUSED(instance);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_SOKOL_PRIVATE HRESULT STDMETHODCALLTYPE _saudio_backend_activate_audio_interface_cb(IActivateAudioInterfaceCompletionHandler* instance, IActivateAudioInterfaceAsyncOperation* activateOperation) {
|
|
|
|
|
_SOKOL_UNUSED(instance);
|
|
|
|
|
WaitForSingleObject(_saudio.backend.interface_activation_mutex, INFINITE);
|
|
|
|
|
_saudio.backend.interface_activation_success = TRUE;
|
|
|
|
|
HRESULT activation_result;
|
|
|
|
|
if (FAILED(activateOperation->lpVtbl->GetActivateResult(activateOperation, &activation_result, (IUnknown**)(&_saudio.backend.audio_client))) || FAILED(activation_result)) {
|
|
|
|
|
_saudio.backend.interface_activation_success = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ReleaseMutex(_saudio.backend.interface_activation_mutex);
|
|
|
|
|
return S_OK;
|
|
|
|
|
}
|
|
|
|
|
#endif // _SAUDIO_UWP
|
|
|
|
|
|
|
|
|
|
/* fill intermediate buffer with new data and reset buffer_pos */
|
|
|
|
|
_SOKOL_PRIVATE void _saudio_wasapi_fill_buffer(void) {
|
|
|
|
|
if (_saudio_has_callback()) {
|
|
|
|
@ -1593,16 +1634,6 @@ _SOKOL_PRIVATE void _saudio_wasapi_release(void) {
|
|
|
|
|
IAudioClient_Release(_saudio.backend.audio_client);
|
|
|
|
|
_saudio.backend.audio_client = 0;
|
|
|
|
|
}
|
|
|
|
|
#if defined(_SAUDIO_UWP)
|
|
|
|
|
if (_saudio.backend.interface_activation_audio_interface_uid_string) {
|
|
|
|
|
CoTaskMemFree(_saudio.backend.interface_activation_audio_interface_uid_string);
|
|
|
|
|
_saudio.backend.interface_activation_audio_interface_uid_string = 0;
|
|
|
|
|
}
|
|
|
|
|
if (_saudio.backend.interface_activation_operation) {
|
|
|
|
|
IActivateAudioInterfaceAsyncOperation_Release(_saudio.backend.interface_activation_operation);
|
|
|
|
|
_saudio.backend.interface_activation_operation = 0;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
if (_saudio.backend.device) {
|
|
|
|
|
IMMDevice_Release(_saudio.backend.device);
|
|
|
|
|
_saudio.backend.device = 0;
|
|
|
|
@ -1611,7 +1642,6 @@ _SOKOL_PRIVATE void _saudio_wasapi_release(void) {
|
|
|
|
|
IMMDeviceEnumerator_Release(_saudio.backend.device_enumerator);
|
|
|
|
|
_saudio.backend.device_enumerator = 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
if (0 != _saudio.backend.thread.buffer_end_event) {
|
|
|
|
|
CloseHandle(_saudio.backend.thread.buffer_end_event);
|
|
|
|
|
_saudio.backend.thread.buffer_end_event = 0;
|
|
|
|
@ -1620,70 +1650,30 @@ _SOKOL_PRIVATE void _saudio_wasapi_release(void) {
|
|
|
|
|
|
|
|
|
|
_SOKOL_PRIVATE bool _saudio_wasapi_backend_init(void) {
|
|
|
|
|
REFERENCE_TIME dur;
|
|
|
|
|
/* UWP Threads are CoInitialized by default with a different threading model, and this call fails
|
|
|
|
|
See https://github.com/Microsoft/cppwinrt/issues/6#issuecomment-253930637 */
|
|
|
|
|
#if defined(_SAUDIO_WIN32)
|
|
|
|
|
/* CoInitializeEx could have been called elsewhere already, in which
|
|
|
|
|
case the function returns with S_FALSE (thus it does not make much
|
|
|
|
|
sense to check the result)
|
|
|
|
|
*/
|
|
|
|
|
HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED);
|
|
|
|
|
_SOKOL_UNUSED(hr);
|
|
|
|
|
#endif
|
|
|
|
|
_saudio.backend.thread.buffer_end_event = CreateEvent(0, FALSE, FALSE, 0);
|
|
|
|
|
if (0 == _saudio.backend.thread.buffer_end_event) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio wasapi: failed to create buffer_end_event");
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
#if defined(_SAUDIO_UWP)
|
|
|
|
|
_saudio.backend.interface_activation_mutex = CreateMutexA(NULL, FALSE, "interface_activation_mutex");
|
|
|
|
|
if (_saudio.backend.interface_activation_mutex == NULL) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio wasapi: failed to create interface activation mutex");
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
if (FAILED(StringFromIID(_SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_Devinterface_Audio_Render), &_saudio.backend.interface_activation_audio_interface_uid_string))) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio wasapi: failed to get default audio device ID string");
|
|
|
|
|
_SAUDIO_ERROR(WASAPI_CREATE_EVENT_FAILED);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* static instance of the fake COM object */
|
|
|
|
|
static IActivateAudioInterfaceCompletionHandlerVtbl completion_handler_interface_vtable = {
|
|
|
|
|
_saudio_interface_completion_handler_queryinterface,
|
|
|
|
|
_saudio_interface_completion_handler_addref_release,
|
|
|
|
|
_saudio_interface_completion_handler_addref_release,
|
|
|
|
|
_saudio_backend_activate_audio_interface_cb
|
|
|
|
|
};
|
|
|
|
|
static IActivateAudioInterfaceCompletionHandler completion_handler_interface = { &completion_handler_interface_vtable };
|
|
|
|
|
|
|
|
|
|
if (FAILED(ActivateAudioInterfaceAsync(_saudio.backend.interface_activation_audio_interface_uid_string, _SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IAudioClient), NULL, &completion_handler_interface, &_saudio.backend.interface_activation_operation))) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio wasapi: failed to get default audio device ID string");
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
while (!(_saudio.backend.audio_client)) {
|
|
|
|
|
if (WaitForSingleObject(_saudio.backend.interface_activation_mutex, 10) != WAIT_TIMEOUT) {
|
|
|
|
|
ReleaseMutex(_saudio.backend.interface_activation_mutex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(_saudio.backend.interface_activation_success)) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio wasapi: interface activation failed. Unable to get audio client");
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
if (FAILED(CoCreateInstance(_SOKOL_AUDIO_WIN32COM_ID(_saudio_CLSID_IMMDeviceEnumerator),
|
|
|
|
|
0, CLSCTX_ALL,
|
|
|
|
|
_SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IMMDeviceEnumerator),
|
|
|
|
|
(void**)&_saudio.backend.device_enumerator)))
|
|
|
|
|
{
|
|
|
|
|
SAUDIO_LOG("sokol_audio wasapi: failed to create device enumerator");
|
|
|
|
|
_SAUDIO_ERROR(WASAPI_CREATE_DEVICE_ENUMERATOR_FAILED);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
if (FAILED(IMMDeviceEnumerator_GetDefaultAudioEndpoint(_saudio.backend.device_enumerator,
|
|
|
|
|
eRender, eConsole,
|
|
|
|
|
&_saudio.backend.device)))
|
|
|
|
|
{
|
|
|
|
|
SAUDIO_LOG("sokol_audio wasapi: GetDefaultAudioEndPoint failed");
|
|
|
|
|
_SAUDIO_ERROR(WASAPI_GET_DEFAULT_AUDIO_ENDPOINT_FAILED);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
if (FAILED(IMMDevice_Activate(_saudio.backend.device,
|
|
|
|
@ -1691,10 +1681,9 @@ _SOKOL_PRIVATE bool _saudio_wasapi_backend_init(void) {
|
|
|
|
|
CLSCTX_ALL, 0,
|
|
|
|
|
(void**)&_saudio.backend.audio_client)))
|
|
|
|
|
{
|
|
|
|
|
SAUDIO_LOG("sokol_audio wasapi: device activate failed");
|
|
|
|
|
_SAUDIO_ERROR(WASAPI_DEVICE_ACTIVATE_FAILED);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
WAVEFORMATEXTENSIBLE fmtex;
|
|
|
|
|
_saudio_clear(&fmtex, sizeof(fmtex));
|
|
|
|
@ -1720,22 +1709,22 @@ _SOKOL_PRIVATE bool _saudio_wasapi_backend_init(void) {
|
|
|
|
|
AUDCLNT_STREAMFLAGS_EVENTCALLBACK|AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM|AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY,
|
|
|
|
|
dur, 0, (WAVEFORMATEX*)&fmtex, 0)))
|
|
|
|
|
{
|
|
|
|
|
SAUDIO_LOG("sokol_audio wasapi: audio client initialize failed");
|
|
|
|
|
_SAUDIO_ERROR(WASAPI_AUDIO_CLIENT_INITIALIZE_FAILED);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
if (FAILED(IAudioClient_GetBufferSize(_saudio.backend.audio_client, &_saudio.backend.thread.dst_buffer_frames))) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio wasapi: audio client get buffer size failed");
|
|
|
|
|
_SAUDIO_ERROR(WASAPI_AUDIO_CLIENT_GET_BUFFER_SIZE_FAILED);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
if (FAILED(IAudioClient_GetService(_saudio.backend.audio_client,
|
|
|
|
|
_SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IAudioRenderClient),
|
|
|
|
|
(void**)&_saudio.backend.render_client)))
|
|
|
|
|
{
|
|
|
|
|
SAUDIO_LOG("sokol_audio wasapi: audio client GetService failed");
|
|
|
|
|
_SAUDIO_ERROR(WASAPI_AUDIO_CLIENT_GET_SERVICE_FAILED);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
if (FAILED(IAudioClient_SetEventHandle(_saudio.backend.audio_client, _saudio.backend.thread.buffer_end_event))) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio wasapi: audio client SetEventHandle failed");
|
|
|
|
|
_SAUDIO_ERROR(WASAPI_AUDIO_CLIENT_SET_EVENT_HANDLE_FAILED);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
_saudio.bytes_per_frame = _saudio.num_channels * (int)sizeof(float);
|
|
|
|
@ -1748,7 +1737,7 @@ _SOKOL_PRIVATE bool _saudio_wasapi_backend_init(void) {
|
|
|
|
|
/* create streaming thread */
|
|
|
|
|
_saudio.backend.thread.thread_handle = CreateThread(NULL, 0, _saudio_wasapi_thread_fn, 0, 0, 0);
|
|
|
|
|
if (0 == _saudio.backend.thread.thread_handle) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio wasapi: CreateThread failed");
|
|
|
|
|
_SAUDIO_ERROR(WASAPI_CREATE_THREAD_FAILED);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
@ -1769,18 +1758,14 @@ _SOKOL_PRIVATE void _saudio_wasapi_backend_shutdown(void) {
|
|
|
|
|
IAudioClient_Stop(_saudio.backend.audio_client);
|
|
|
|
|
}
|
|
|
|
|
_saudio_wasapi_release();
|
|
|
|
|
|
|
|
|
|
#if defined(_SAUDIO_WIN32)
|
|
|
|
|
CoUninitialize();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ██╗ ██╗███████╗██████╗ █████╗ ██╗ ██╗██████╗ ██╗ ██████╗
|
|
|
|
|
// ██║ ██║██╔════╝██╔══██╗██╔══██╗██║ ██║██╔══██╗██║██╔═══██╗
|
|
|
|
|
// ██║ █╗ ██║█████╗ ██████╔╝███████║██║ ██║██║ ██║██║██║ ██║
|
|
|
|
|
// ██║███╗██║██╔══╝ ██╔══██╗██╔══██║██║ ██║██║ ██║██║██║ ██║
|
|
|
|
|
// ╚███╔███╔╝███████╗██████╔╝██║ ██║╚██████╔╝██████╔╝██║╚██████╔╝
|
|
|
|
|
// ╚══╝╚══╝ ╚══════╝╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝
|
|
|
|
|
// ██ ██ ███████ ██████ █████ ██ ██ ██████ ██ ██████
|
|
|
|
|
// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██ █ ██ █████ ██████ ███████ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ███ ███ ███████ ██████ ██ ██ ██████ ██████ ██ ██████
|
|
|
|
|
//
|
|
|
|
|
// >>webaudio
|
|
|
|
|
#elif defined(_SAUDIO_EMSCRIPTEN)
|
|
|
|
@ -1932,12 +1917,11 @@ _SOKOL_PRIVATE void _saudio_webaudio_backend_shutdown(void) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// █████╗ █████╗ ██╗ ██╗██████╗ ██╗ ██████╗
|
|
|
|
|
// ██╔══██╗██╔══██╗██║ ██║██╔══██╗██║██╔═══██╗
|
|
|
|
|
// ███████║███████║██║ ██║██║ ██║██║██║ ██║
|
|
|
|
|
// ██╔══██║██╔══██║██║ ██║██║ ██║██║██║ ██║
|
|
|
|
|
// ██║ ██║██║ ██║╚██████╔╝██████╔╝██║╚██████╔╝
|
|
|
|
|
// ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝
|
|
|
|
|
// █████ █████ ██ ██ ██████ ██ ██████
|
|
|
|
|
// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ███████ ███████ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██ ██ ██ ██ ██████ ██████ ██ ██████
|
|
|
|
|
//
|
|
|
|
|
// >>aaudio
|
|
|
|
|
#elif defined(SAUDIO_ANDROID_AAUDIO)
|
|
|
|
@ -1961,7 +1945,7 @@ _SOKOL_PRIVATE aaudio_data_callback_result_t _saudio_aaudio_data_callback(AAudio
|
|
|
|
|
|
|
|
|
|
_SOKOL_PRIVATE bool _saudio_aaudio_start_stream(void) {
|
|
|
|
|
if (AAudioStreamBuilder_openStream(_saudio.backend.builder, &_saudio.backend.stream) != AAUDIO_OK) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio.h aaudio: AAudioStreamBuilder_openStream failed");
|
|
|
|
|
_SAUDIO_ERROR(AAUDIO_STREAMBUILDER_OPEN_STREAM_FAILED);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
AAudioStream_requestStart(_saudio.backend.stream);
|
|
|
|
@ -1978,7 +1962,7 @@ _SOKOL_PRIVATE void _saudio_aaudio_stop_stream(void) {
|
|
|
|
|
|
|
|
|
|
_SOKOL_PRIVATE void* _saudio_aaudio_restart_stream_thread_fn(void* param) {
|
|
|
|
|
_SOKOL_UNUSED(param);
|
|
|
|
|
SAUDIO_LOG("sokol_audio.h aaudio: restarting stream after error");
|
|
|
|
|
_SAUDIO_WARN(AAUDIO_RESTARTING_STREAM_AFTER_ERROR);
|
|
|
|
|
pthread_mutex_lock(&_saudio.backend.mutex);
|
|
|
|
|
_saudio_aaudio_stop_stream();
|
|
|
|
|
_saudio_aaudio_start_stream();
|
|
|
|
@ -1991,7 +1975,7 @@ _SOKOL_PRIVATE void _saudio_aaudio_error_callback(AAudioStream* stream, void* us
|
|
|
|
|
_SOKOL_UNUSED(user_data);
|
|
|
|
|
if (error == AAUDIO_ERROR_DISCONNECTED) {
|
|
|
|
|
if (0 != pthread_create(&_saudio.backend.thread, 0, _saudio_aaudio_restart_stream_thread_fn, 0)) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio.h aaudio: pthread_create failed in _saudio_audio_error_callback");
|
|
|
|
|
_SAUDIO_ERROR(AAUDIO_PTHREAD_CREATE_FAILED);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -2008,7 +1992,7 @@ _SOKOL_PRIVATE void _saudio_aaudio_backend_shutdown(void) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_SOKOL_PRIVATE bool _saudio_aaudio_backend_init(void) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio.h: using AAudio backend");
|
|
|
|
|
_SAUDIO_INFO(USING_AAUDIO_BACKEND);
|
|
|
|
|
|
|
|
|
|
_saudio.bytes_per_frame = _saudio.num_channels * (int)sizeof(float);
|
|
|
|
|
|
|
|
|
@ -2017,7 +2001,7 @@ _SOKOL_PRIVATE bool _saudio_aaudio_backend_init(void) {
|
|
|
|
|
pthread_mutex_init(&_saudio.backend.mutex, &attr);
|
|
|
|
|
|
|
|
|
|
if (AAudio_createStreamBuilder(&_saudio.backend.builder) != AAUDIO_OK) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio.h aaudio: AAudio_createStreamBuilder() failed!");
|
|
|
|
|
_SAUDIO_ERROR(AAUDIO_CREATE_STREAMBUILDER_FAILED);
|
|
|
|
|
_saudio_aaudio_backend_shutdown();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
@ -2038,12 +2022,11 @@ _SOKOL_PRIVATE bool _saudio_aaudio_backend_init(void) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ██████╗ ██████╗ ███████╗███╗ ██╗███████╗██╗ ███████╗███████╗
|
|
|
|
|
// ██╔═══██╗██╔══██╗██╔════╝████╗ ██║██╔════╝██║ ██╔════╝██╔════╝
|
|
|
|
|
// ██║ ██║██████╔╝█████╗ ██╔██╗ ██║███████╗██║ █████╗ ███████╗
|
|
|
|
|
// ██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║╚════██║██║ ██╔══╝ ╚════██║
|
|
|
|
|
// ╚██████╔╝██║ ███████╗██║ ╚████║███████║███████╗███████╗███████║
|
|
|
|
|
// ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝╚══════╝╚══════╝╚══════╝╚══════╝
|
|
|
|
|
// ██████ ██████ ███████ ███ ██ ███████ ██ ███████ ███████
|
|
|
|
|
// ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██
|
|
|
|
|
// ██ ██ ██████ █████ ██ ██ ██ ███████ ██ █████ ███████
|
|
|
|
|
// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██████ ██ ███████ ██ ████ ███████ ███████ ███████ ███████
|
|
|
|
|
//
|
|
|
|
|
// >>opensles
|
|
|
|
|
// >>sles
|
|
|
|
@ -2107,9 +2090,8 @@ _SOKOL_PRIVATE void _saudio_sles_fill_buffer(void) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_SOKOL_PRIVATE void SLAPIENTRY _saudio_sles_play_cb(SLPlayItf player, void *context, SLuint32 event) {
|
|
|
|
|
(void)(context);
|
|
|
|
|
(void)(player);
|
|
|
|
|
|
|
|
|
|
_SOKOL_UNUSED(context);
|
|
|
|
|
_SOKOL_UNUSED(player);
|
|
|
|
|
if (event & SL_PLAYEVENT_HEADATEND) {
|
|
|
|
|
_saudio_sles_semaphore_post(&_saudio.backend.buffer_sem, 1);
|
|
|
|
|
}
|
|
|
|
@ -2163,7 +2145,7 @@ _SOKOL_PRIVATE void _saudio_sles_backend_shutdown(void) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_SOKOL_PRIVATE bool _saudio_sles_backend_init(void) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio.h: using OpenSLES backend");
|
|
|
|
|
_SAUDIO_INFO(USING_SLES_BACKEND);
|
|
|
|
|
|
|
|
|
|
_saudio.bytes_per_frame = (int)sizeof(float) * _saudio.num_channels;
|
|
|
|
|
|
|
|
|
@ -2180,14 +2162,14 @@ _SOKOL_PRIVATE bool _saudio_sles_backend_init(void) {
|
|
|
|
|
/* Create engine */
|
|
|
|
|
const SLEngineOption opts[] = { { SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE } };
|
|
|
|
|
if (slCreateEngine(&_saudio.backend.engine_obj, 1, opts, 0, NULL, NULL ) != SL_RESULT_SUCCESS) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio opensles: slCreateEngine failed");
|
|
|
|
|
_SAUDIO_ERROR(SLES_CREATE_ENGINE_FAILED);
|
|
|
|
|
_saudio_sles_backend_shutdown();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(*_saudio.backend.engine_obj)->Realize(_saudio.backend.engine_obj, SL_BOOLEAN_FALSE);
|
|
|
|
|
if ((*_saudio.backend.engine_obj)->GetInterface(_saudio.backend.engine_obj, SL_IID_ENGINE, &_saudio.backend.engine) != SL_RESULT_SUCCESS) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio opensles: GetInterface->Engine failed");
|
|
|
|
|
_SAUDIO_ERROR(SLES_ENGINE_GET_ENGINE_INTERFACE_FAILED);
|
|
|
|
|
_saudio_sles_backend_shutdown();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
@ -2197,16 +2179,15 @@ _SOKOL_PRIVATE bool _saudio_sles_backend_init(void) {
|
|
|
|
|
const SLInterfaceID ids[] = { SL_IID_VOLUME };
|
|
|
|
|
const SLboolean req[] = { SL_BOOLEAN_FALSE };
|
|
|
|
|
|
|
|
|
|
if( (*_saudio.backend.engine)->CreateOutputMix(_saudio.backend.engine, &_saudio.backend.output_mix_obj, 1, ids, req) != SL_RESULT_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
SAUDIO_LOG("sokol_audio opensles: CreateOutputMix failed");
|
|
|
|
|
if ((*_saudio.backend.engine)->CreateOutputMix(_saudio.backend.engine, &_saudio.backend.output_mix_obj, 1, ids, req) != SL_RESULT_SUCCESS) {
|
|
|
|
|
_SAUDIO_ERROR(SLES_CREATE_OUTPUT_MIX_FAILED);
|
|
|
|
|
_saudio_sles_backend_shutdown();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
(*_saudio.backend.output_mix_obj)->Realize(_saudio.backend.output_mix_obj, SL_BOOLEAN_FALSE);
|
|
|
|
|
|
|
|
|
|
if((*_saudio.backend.output_mix_obj)->GetInterface(_saudio.backend.output_mix_obj, SL_IID_VOLUME, &_saudio.backend.output_mix_vol) != SL_RESULT_SUCCESS) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio opensles: GetInterface->OutputMixVol failed");
|
|
|
|
|
if ((*_saudio.backend.output_mix_obj)->GetInterface(_saudio.backend.output_mix_obj, SL_IID_VOLUME, &_saudio.backend.output_mix_vol) != SL_RESULT_SUCCESS) {
|
|
|
|
|
_SAUDIO_WARN(SLES_MIXER_GET_VOLUME_INTERFACE_FAILED);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2245,24 +2226,24 @@ _SOKOL_PRIVATE bool _saudio_sles_backend_init(void) {
|
|
|
|
|
const SLInterfaceID ids[] = { SL_IID_VOLUME, SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
|
|
|
|
|
const SLboolean req[] = { SL_BOOLEAN_FALSE, SL_BOOLEAN_TRUE };
|
|
|
|
|
|
|
|
|
|
if( (*_saudio.backend.engine)->CreateAudioPlayer(_saudio.backend.engine, &_saudio.backend.player_obj, &src, &_saudio.backend.dst_data_sink, sizeof(ids) / sizeof(ids[0]), ids, req) != SL_RESULT_SUCCESS)
|
|
|
|
|
if ((*_saudio.backend.engine)->CreateAudioPlayer(_saudio.backend.engine, &_saudio.backend.player_obj, &src, &_saudio.backend.dst_data_sink, sizeof(ids) / sizeof(ids[0]), ids, req) != SL_RESULT_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
SAUDIO_LOG("sokol_audio opensles: CreateAudioPlayer failed");
|
|
|
|
|
_SAUDIO_ERROR(SLES_ENGINE_CREATE_AUDIO_PLAYER_FAILED);
|
|
|
|
|
_saudio_sles_backend_shutdown();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
(*_saudio.backend.player_obj)->Realize(_saudio.backend.player_obj, SL_BOOLEAN_FALSE);
|
|
|
|
|
|
|
|
|
|
if((*_saudio.backend.player_obj)->GetInterface(_saudio.backend.player_obj, SL_IID_PLAY, &_saudio.backend.player) != SL_RESULT_SUCCESS) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio opensles: GetInterface->Play failed");
|
|
|
|
|
if ((*_saudio.backend.player_obj)->GetInterface(_saudio.backend.player_obj, SL_IID_PLAY, &_saudio.backend.player) != SL_RESULT_SUCCESS) {
|
|
|
|
|
_SAUDIO_ERROR(SLES_PLAYER_GET_PLAY_INTERFACE_FAILED);
|
|
|
|
|
_saudio_sles_backend_shutdown();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if((*_saudio.backend.player_obj)->GetInterface(_saudio.backend.player_obj, SL_IID_VOLUME, &_saudio.backend.player_vol) != SL_RESULT_SUCCESS) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio opensles: GetInterface->PlayerVol failed");
|
|
|
|
|
if ((*_saudio.backend.player_obj)->GetInterface(_saudio.backend.player_obj, SL_IID_VOLUME, &_saudio.backend.player_vol) != SL_RESULT_SUCCESS) {
|
|
|
|
|
_SAUDIO_ERROR(SLES_PLAYER_GET_VOLUME_INTERFACE_FAILED);
|
|
|
|
|
}
|
|
|
|
|
if((*_saudio.backend.player_obj)->GetInterface(_saudio.backend.player_obj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &_saudio.backend.player_buffer_queue) != SL_RESULT_SUCCESS) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio opensles: GetInterface->BufferQ failed");
|
|
|
|
|
if ((*_saudio.backend.player_obj)->GetInterface(_saudio.backend.player_obj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &_saudio.backend.player_buffer_queue) != SL_RESULT_SUCCESS) {
|
|
|
|
|
_SAUDIO_ERROR(SLES_PLAYER_GET_BUFFERQUEUE_INTERFACE_FAILED);
|
|
|
|
|
_saudio_sles_backend_shutdown();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
@ -2288,12 +2269,11 @@ _SOKOL_PRIVATE bool _saudio_sles_backend_init(void) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ██████╗ ██████╗ ██████╗ ███████╗ █████╗ ██╗ ██╗██████╗ ██╗ ██████╗
|
|
|
|
|
// ██╔════╝██╔═══██╗██╔══██╗██╔════╝██╔══██╗██║ ██║██╔══██╗██║██╔═══██╗
|
|
|
|
|
// ██║ ██║ ██║██████╔╝█████╗ ███████║██║ ██║██║ ██║██║██║ ██║
|
|
|
|
|
// ██║ ██║ ██║██╔══██╗██╔══╝ ██╔══██║██║ ██║██║ ██║██║██║ ██║
|
|
|
|
|
// ╚██████╗╚██████╔╝██║ ██║███████╗██║ ██║╚██████╔╝██████╔╝██║╚██████╔╝
|
|
|
|
|
// ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝
|
|
|
|
|
// ██████ ██████ ██████ ███████ █████ ██ ██ ██████ ██ ██████
|
|
|
|
|
// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██ ██ ██ ██████ █████ ███████ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██████ ██████ ██ ██ ███████ ██ ██ ██████ ██████ ██ ██████
|
|
|
|
|
//
|
|
|
|
|
// >>coreaudio
|
|
|
|
|
#elif defined(_SAUDIO_APPLE)
|
|
|
|
@ -2418,7 +2398,7 @@ _SOKOL_PRIVATE bool _saudio_coreaudio_backend_init(void) {
|
|
|
|
|
fmt.mBitsPerChannel = 32;
|
|
|
|
|
_saudio_OSStatus res = AudioQueueNewOutput(&fmt, _saudio_coreaudio_callback, 0, NULL, NULL, 0, &_saudio.backend.ca_audio_queue);
|
|
|
|
|
if (0 != res) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio.h: AudioQueueNewOutput() failed!\n");
|
|
|
|
|
_SAUDIO_ERROR(COREAUDIO_NEW_OUTPUT_FAILED);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
SOKOL_ASSERT(_saudio.backend.ca_audio_queue);
|
|
|
|
@ -2429,7 +2409,7 @@ _SOKOL_PRIVATE bool _saudio_coreaudio_backend_init(void) {
|
|
|
|
|
const uint32_t buf_byte_size = (uint32_t)_saudio.buffer_frames * fmt.mBytesPerFrame;
|
|
|
|
|
res = AudioQueueAllocateBuffer(_saudio.backend.ca_audio_queue, buf_byte_size, &buf);
|
|
|
|
|
if (0 != res) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio.h: AudioQueueAllocateBuffer() failed!\n");
|
|
|
|
|
_SAUDIO_ERROR(COREAUDIO_ALLOCATE_BUFFER_FAILED);
|
|
|
|
|
_saudio_coreaudio_backend_shutdown();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
@ -2444,7 +2424,7 @@ _SOKOL_PRIVATE bool _saudio_coreaudio_backend_init(void) {
|
|
|
|
|
/* ...and start playback */
|
|
|
|
|
res = AudioQueueStart(_saudio.backend.ca_audio_queue, NULL);
|
|
|
|
|
if (0 != res) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio.h: AudioQueueStart() failed!\n");
|
|
|
|
|
_SAUDIO_ERROR(COREAUDIO_START_FAILED);
|
|
|
|
|
_saudio_coreaudio_backend_shutdown();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
@ -2495,12 +2475,11 @@ void _saudio_backend_shutdown(void) {
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ██████╗ ██╗ ██╗██████╗ ██╗ ██╗ ██████╗
|
|
|
|
|
// ██╔══██╗██║ ██║██╔══██╗██║ ██║██╔════╝
|
|
|
|
|
// ██████╔╝██║ ██║██████╔╝██║ ██║██║
|
|
|
|
|
// ██╔═══╝ ██║ ██║██╔══██╗██║ ██║██║
|
|
|
|
|
// ██║ ╚██████╔╝██████╔╝███████╗██║╚██████╗
|
|
|
|
|
// ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═════╝
|
|
|
|
|
// ██████ ██ ██ ██████ ██ ██ ██████
|
|
|
|
|
// ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██████ ██ ██ ██████ ██ ██ ██
|
|
|
|
|
// ██ ██ ██ ██ ██ ██ ██ ██
|
|
|
|
|
// ██ ██████ ██████ ███████ ██ ██████
|
|
|
|
|
//
|
|
|
|
|
// >>public
|
|
|
|
|
SOKOL_API_IMPL void saudio_setup(const saudio_desc* desc) {
|
|
|
|
@ -2524,7 +2503,7 @@ SOKOL_API_IMPL void saudio_setup(const saudio_desc* desc) {
|
|
|
|
|
the requested packet size
|
|
|
|
|
*/
|
|
|
|
|
if (0 != (_saudio.buffer_frames % _saudio.packet_frames)) {
|
|
|
|
|
SAUDIO_LOG("sokol_audio.h: actual backend buffer size isn't multiple of requested packet size");
|
|
|
|
|
_SAUDIO_ERROR(BACKEND_BUFFER_SIZE_ISNT_MULTIPLE_OF_PACKET_SIZE);
|
|
|
|
|
_saudio_backend_shutdown();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|