view release on metacpan or search on metacpan
lib/App/MHFS.pm view on Meta::CPAN
use feature 'say';
use Exporter 'import';
use File::Find;
use File::Basename;
use POSIX ();
use Cwd qw(abs_path getcwd);
use Encode qw(decode encode);
use URI::Escape qw(uri_escape uri_escape_utf8);
use MIME::Base64 qw(encode_base64url decode_base64url);
our @EXPORT = ('LOCK_GET_LOCKDATA', 'LOCK_WRITE', 'UNLOCK_WRITE', 'write_file', 'read_file', 'shellcmd_unlock', 'ASYNC', 'FindFile', 'space2us', 'escape_html', 'function_exists', 'shell_escape', 'pid_running', 'escape_html_noquote', 'output_dir_v...
# single threaded locks
sub LOCK_GET_LOCKDATA {
my ($filename) = @_;
my $lockname = "$filename.lock";
my $bytes = read_file($lockname);
if(! defined $bytes) {
return undef;
}
return $bytes;
}
lib/App/MHFS.pm view on Meta::CPAN
use constant {
RECV_SIZE => 65536,
CT_YIELD => 1,
CT_DONE => undef,
#CT_READ => 1,
#CT_PROCESS = 2,
#CT_WRITE => 3
};
# The "client_thread" consists of 5 states, CT_READ, CT_PROCESS, CT_WRITE, CT_YIELD, and CT_DONE
# CT_READ reads input data from the socket
## on data read transitions to CT_PROCESS
## on error transitions to CT_DONE
## otherwise CT_YIELD
# CT_PROCESS processes the input data
## on processing done, switches to CT_WRITE or CT_READ to read more data to process
## on error transitions to CT_DONE
## otherwise CT_YIELD
# CT_WRITE outputs data to the socket
## on all data written transitions to CT_PROCESS unless Connection: close is set.
## on error transitions to CT_DONE
## otherwise CT_YIELD
# CT_YIELD just returns control to the poll loop to wait for IO or allow another client thread to run
# CT_DONE also returns control to the poll loop, it is called on error or when the client connection should be closed or is closed
sub CT_READ {
my ($self) = @_;
my $tempdata;
if(!defined($self->{'sock'}->recv($tempdata, RECV_SIZE))) {
if(! ($!{EAGAIN} || $!{EWOULDBLOCK})) {
print ("CT_READ RECV errno: $!\n");
return CT_DONE;
share/public_html/static/hls.js view on Meta::CPAN
// see https://stackoverflow.com/a/11237259/589493
var global = Object(get_self_scope["a" /* getSelfScope */])(); // safeguard for code that might run both on worker and main thread
var decrypter_Decrypter = function () {
function Decrypter(observer, config) {
var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
_ref$removePKCS7Paddi = _ref.removePKCS7Padding,
removePKCS7Padding = _ref$removePKCS7Paddi === undefined ? true : _ref$removePKCS7Paddi;
decrypter__classCallCheck(this, Decrypter);
this.logEnabled = true;
share/public_html/static/hls.js view on Meta::CPAN
// see https://stackoverflow.com/a/11237259/589493
var global = Object(get_self_scope["a" /* getSelfScope */])(); // safeguard for code that might run both on worker and main thread
var performance = global;
var demuxer_inline_DemuxerInline = function () {
function DemuxerInline(observer, typeSupported, config, vendor) {
demuxer_inline__classCallCheck(this, DemuxerInline);
this.observer = observer;
this.typeSupported = typeSupported;
this.config = config;
this.vendor = vendor;
share/public_html/static/hls.js view on Meta::CPAN
// see https://stackoverflow.com/a/11237259/589493
var global = Object(get_self_scope["a" /* getSelfScope */])(); // safeguard for code that might run both on worker and main thread
var MediaSource = getMediaSource();
var demuxer_Demuxer = function () {
function Demuxer(hls, id) {
demuxer__classCallCheck(this, Demuxer);
this.hls = hls;
this.id = id;
// observer setup
var observer = this.observer = new events_default.a();
share/public_html/static/hls.js view on Meta::CPAN
observer.removeListener.apply(observer, [event].concat(data));
};
var forwardMessage = function (ev, data) {
data = data || {};
data.frag = this.frag;
data.id = this.id;
hls.trigger(ev, data);
}.bind(this);
// forward events to main thread
observer.on(events["a" /* default */].FRAG_DECRYPTED, forwardMessage);
observer.on(events["a" /* default */].FRAG_PARSING_INIT_SEGMENT, forwardMessage);
observer.on(events["a" /* default */].FRAG_PARSING_DATA, forwardMessage);
observer.on(events["a" /* default */].FRAG_PARSED, forwardMessage);
observer.on(events["a" /* default */].ERROR, forwardMessage);
observer.on(events["a" /* default */].FRAG_PARSING_METADATA, forwardMessage);
observer.on(events["a" /* default */].FRAG_PARSING_USERDATA, forwardMessage);
observer.on(events["a" /* default */].INIT_PTS_FOUND, forwardMessage);
var typeSupported = {
share/public_html/static/hls.js view on Meta::CPAN
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__demux_demuxer_inline__ = __webpack_require__(9);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__events__ = __webpack_require__(1);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__utils_logger__ = __webpack_require__(0);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_events__ = __webpack_require__(6);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_events___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3_events__);
/* demuxer web worker.
* - listen to worker message, and trigger DemuxerInline upon reception of Fragments.
* - provides MP4 Boxes back to main thread using [transferable objects](https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast) in order to minimize message passing overhead.
*/
var DemuxerWorker = function DemuxerWorker(self) {
// observer setup
var observer = new __WEBPACK_IMPORTED_MODULE_3_events___default.a();
share/public_html/static/hls.js view on Meta::CPAN
forwardMessage('init', null);
break;
case 'demux':
self.demuxer.push(data.data, data.decryptdata, data.initSegment, data.audioCodec, data.videoCodec, data.timeOffset, data.discontinuity, data.trackSwitch, data.contiguous, data.duration, data.accurateTimeOffset, data.defaultInitPTS);
break;
default:
break;
}
});
// forward events to main thread
observer.on(__WEBPACK_IMPORTED_MODULE_1__events__["a" /* default */].FRAG_DECRYPTED, forwardMessage);
observer.on(__WEBPACK_IMPORTED_MODULE_1__events__["a" /* default */].FRAG_PARSING_INIT_SEGMENT, forwardMessage);
observer.on(__WEBPACK_IMPORTED_MODULE_1__events__["a" /* default */].FRAG_PARSED, forwardMessage);
observer.on(__WEBPACK_IMPORTED_MODULE_1__events__["a" /* default */].ERROR, forwardMessage);
observer.on(__WEBPACK_IMPORTED_MODULE_1__events__["a" /* default */].FRAG_PARSING_METADATA, forwardMessage);
observer.on(__WEBPACK_IMPORTED_MODULE_1__events__["a" /* default */].FRAG_PARSING_USERDATA, forwardMessage);
observer.on(__WEBPACK_IMPORTED_MODULE_1__events__["a" /* default */].INIT_PTS_FOUND, forwardMessage);
// special case for FRAG_PARSING_DATA: pass data1/data2 as transferable object (no copy)
observer.on(__WEBPACK_IMPORTED_MODULE_1__events__["a" /* default */].FRAG_PARSING_DATA, function (ev, data) {
share/public_html/static/music_inc/drflac.js view on Meta::CPAN
var Module = (() => {
var _scriptName = import.meta.url;
return (
async function(moduleArg = {}) {
var moduleRtn;
var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;var readyPromise=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});["_network_drflac_open_mem","_network_drflac_read_pcm_frames_f32_mem","_network_dr...
return moduleRtn;
}
);
})();
export default Module;
share/public_html/static/music_inc/src/dr_flac.h view on Meta::CPAN
be used if available. Otherwise the seek will be performed using brute force.
#define DR_FLAC_NO_SIMD
Disables SIMD optimizations (SSE on x86/x64 architectures, NEON on ARM architectures). Use this if you are having compatibility issues with your compiler.
Notes
=====
- dr_flac does not support changing the sample rate nor channel count mid stream.
- dr_flac is not thread-safe, but its APIs can be called from any thread so long as you do your own synchronization.
- When using Ogg encapsulation, a corrupted metadata block will result in `drflac_open_with_metadata()` and `drflac_open()` returning inconsistent samples due
to differences in corrupted stream recorvery logic between the two APIs.
*/
#ifndef dr_flac_h
#define dr_flac_h
#ifdef __cplusplus
extern "C" {
#endif
share/public_html/static/music_inc/src/dr_flac.h view on Meta::CPAN
}
DRFLAC_API const char* drflac_version_string(void)
{
return DRFLAC_VERSION_STRING;
}
/* CPU caps. */
#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
#define DRFLAC_NO_THREAD_SANITIZE __attribute__((no_sanitize("thread")))
#else
#define DRFLAC_NO_THREAD_SANITIZE
#endif
#else
#define DRFLAC_NO_THREAD_SANITIZE
#endif
#if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE;
#endif
share/public_html/static/music_inc/src/dr_flac.h view on Meta::CPAN
*ppFile = _wfopen(pFilePath, pOpenMode);
if (*ppFile == NULL) {
return drflac_result_from_errno(errno);
}
#endif
(void)pAllocationCallbacks;
}
#else
/*
Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can
think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility.
*/
{
mbstate_t mbs;
size_t lenMB;
const wchar_t* pFilePathTemp = pFilePath;
char* pFilePathMB = NULL;
char pOpenModeMB[32] = {0};
/* Get the length first. */
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
which is useful if you want to avoid the overhead of miniaudio's automatic data conversion.
In addition to the sample format, channel count and sample rate, the data callback and user data pointer are also set via the config. The user data pointer is
not passed into the callback as a parameter, but is instead set to the `pUserData` member of `ma_device` which you can access directly since all miniaudio
structures are transparent.
Initializing the device is done with `ma_device_init()`. This will return a result code telling you what went wrong, if anything. On success it will return
`MA_SUCCESS`. After initialization is complete the device will be in a stopped state. To start it, use `ma_device_start()`. Uninitializing the device will stop
it, which is what the example above does, but you can also stop the device with `ma_device_stop()`. To resume the device simply call `ma_device_start()` again.
Note that it's important to never stop or start the device from inside the callback. This will result in a deadlock. Instead you set a variable or signal an
event indicating that the device needs to stop and handle it in a different thread. The following APIs must never be called inside the callback:
```c
ma_device_init()
ma_device_init_ex()
ma_device_uninit()
ma_device_start()
ma_device_stop()
```
You must never try uninitializing and reinitializing a device inside the callback. You must also never try to stop and start it from inside the callback. There
are a few other things you shouldn't do in the callback depending on your requirements, however this isn't so much a thread-safety thing, but rather a
real-time processing thing which is beyond the scope of this introduction.
The example above demonstrates the initialization of a playback device, but it works exactly the same for capture. All you need to do is change the device type
from `ma_device_type_playback` to `ma_device_type_capture` when setting up the config, like so:
```c
ma_device_config config = ma_device_config_init(ma_device_type_capture);
config.capture.format = MY_FORMAT;
config.capture.channels = MY_CHANNEL_COUNT;
```
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
2.1. Windows
------------
The Windows build should compile cleanly on all popular compilers without the need to configure any include paths nor link to any libraries.
2.2. macOS and iOS
------------------
The macOS build should compile cleanly without the need to download any dependencies nor link to any libraries or frameworks. The iOS build needs to be
compiled as Objective-C and will need to link the relevant frameworks but should compile cleanly out of the box with Xcode. Compiling through the command line
requires linking to `-lpthread` and `-lm`.
Due to the way miniaudio links to frameworks at runtime, your application may not pass Apple's notarization process. To fix this there are two options. The
first is to use the `MA_NO_RUNTIME_LINKING` option, like so:
```c
#ifdef __APPLE__
#define MA_NO_RUNTIME_LINKING
#endif
#define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
```
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
```
2.3. Linux
----------
The Linux build only requires linking to `-ldl`, `-lpthread` and `-lm`. You do not need any development packages.
2.4. BSD
--------
The BSD build only requires linking to `-lpthread` and `-lm`. NetBSD uses audio(4), OpenBSD uses sndio and FreeBSD uses OSS.
2.5. Android
------------
AAudio is the highest priority backend on Android. This should work out of the box without needing any kind of compiler configuration. Support for AAudio
starts with Android 8 which means older versions will fall back to OpenSL|ES which requires API level 16+.
2.6. Emscripten
---------------
The Emscripten build emits Web Audio JavaScript directly and should compile cleanly out of the box. You cannot use -std=c* compiler flags, nor -ansi.
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_WAV | Disables the built-in WAV decoder and encoder. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_FLAC | Disables the built-in FLAC decoder. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_MP3 | Disables the built-in MP3 decoder. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_DEVICE_IO | Disables playback and recording. This will disable ma_context and ma_device APIs. This is useful if you only want to use |
| | miniaudio's data conversion and/or decoding APIs. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_THREADING | Disables the ma_thread, ma_mutex, ma_semaphore and ma_event APIs. This option is useful if you only need to use miniaudio for |
| | data conversion, decoding and/or encoding. Some families of APIs require threading which means the following options must also |
| | be set: |
| | |
| | ``` |
| | MA_NO_DEVICE_IO |
| | ``` |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_GENERATION | Disables generation APIs such a ma_waveform and ma_noise. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_SSE2 | Disables SSE2 optimizations. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
need, and on output it will set to what was actually acquired. If the read or write pointer is positioned such that the number of frames requested will require
a loop, it will be clamped to the end of the buffer. Therefore, the number of frames you're given may be less than the number you requested.
After calling `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()`, you do your work on the buffer and then "commit" it with `ma_pcm_rb_commit_read()` or
`ma_pcm_rb_commit_write()`. This is where the read/write pointers are updated. When you commit you need to pass in the buffer that was returned by the earlier
call to `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()` and is only used for validation. The number of frames passed to `ma_pcm_rb_commit_read()` and
`ma_pcm_rb_commit_write()` is what's used to increment the pointers.
If you want to correct for drift between the write pointer and the read pointer you can use a combination of `ma_pcm_rb_pointer_distance()`,
`ma_pcm_rb_seek_read()` and `ma_pcm_rb_seek_write()`. Note that you can only move the pointers forward, and you should only move the read pointer forward via
the consumer thread, and the write pointer forward by the producer thread. If there is too much space between the pointers, move the read pointer forward. If
there is too little space between the pointers, move the write pointer forward.
You can use a ring buffer at the byte level instead of the PCM frame level by using the `ma_rb` API. This is exactly the same, only you will use the `ma_rb`
functions instead of `ma_pcm_rb` and instead of frame counts you will pass around byte counts.
The maximum size of the buffer in bytes is `0x7FFFFFFF-(MA_SIMD_ALIGNMENT-1)` due to the most significant bit being used to encode a loop flag and the internally
managed buffers always being aligned to MA_SIMD_ALIGNMENT.
Note that the ring buffer is only thread safe when used by a single consumer thread and single producer thread.
11. Backends
============
The following backends are supported by miniaudio.
+-------------+-----------------------+--------------------------------------------------------+
| Name | Enum Name | Supported Operating Systems |
+-------------+-----------------------+--------------------------------------------------------+
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
/* Platform/backend detection. */
#ifdef _WIN32
#define MA_WIN32
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
#define MA_WIN32_UWP
#else
#define MA_WIN32_DESKTOP
#endif
#else
#define MA_POSIX
#include <pthread.h> /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */
#ifdef __unix__
#define MA_UNIX
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#define MA_BSD
#endif
#endif
#ifdef __linux__
#define MA_LINUX
#endif
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
void (* onFree)(void* p, void* pUserData);
} ma_allocation_callbacks;
typedef struct
{
ma_int32 state;
} ma_lcg;
#ifndef MA_NO_THREADING
/* Thread priorties should be ordered such that the default priority of the worker thread is 0. */
typedef enum
{
ma_thread_priority_idle = -5,
ma_thread_priority_lowest = -4,
ma_thread_priority_low = -3,
ma_thread_priority_normal = -2,
ma_thread_priority_high = -1,
ma_thread_priority_highest = 0,
ma_thread_priority_realtime = 1,
ma_thread_priority_default = 0
} ma_thread_priority;
typedef unsigned char ma_spinlock;
#if defined(MA_WIN32)
typedef ma_handle ma_thread;
#endif
#if defined(MA_POSIX)
typedef pthread_t ma_thread;
#endif
#if defined(MA_WIN32)
typedef ma_handle ma_mutex;
#endif
#if defined(MA_POSIX)
typedef pthread_mutex_t ma_mutex;
#endif
#if defined(MA_WIN32)
typedef ma_handle ma_event;
#endif
#if defined(MA_POSIX)
typedef struct
{
ma_uint32 value;
pthread_mutex_t lock;
pthread_cond_t cond;
} ma_event;
#endif /* MA_POSIX */
#if defined(MA_WIN32)
typedef ma_handle ma_semaphore;
#endif
#if defined(MA_POSIX)
typedef struct
{
int value;
pthread_mutex_t lock;
pthread_cond_t cond;
} ma_semaphore;
#endif /* MA_POSIX */
#else
/* MA_NO_THREADING is set which means threading is disabled. Threading is required by some API families. If any of these are enabled we need to throw an error. */
#ifndef MA_NO_DEVICE_IO
#error "MA_NO_THREADING cannot be used without MA_NO_DEVICE_IO";
#endif
#endif /* MA_NO_THREADING */
/*
Retrieves the version of miniaudio as separated integers. Each component can be NULL if it's not required.
*/
MA_API void ma_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* pRevision);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#define MA_SUPPORT_OSS /* Only support OSS on specific platforms with known support. */
#endif
#endif
#if defined(MA_APPLE)
#define MA_SUPPORT_COREAUDIO
#endif
#if defined(MA_EMSCRIPTEN)
#define MA_SUPPORT_WEBAUDIO
#endif
/* Explicitly disable the Null backend for Emscripten because it uses a background thread which is not properly supported right now. */
#if !defined(MA_EMSCRIPTEN)
#define MA_SUPPORT_NULL
#endif
#if !defined(MA_NO_WASAPI) && defined(MA_SUPPORT_WASAPI)
#define MA_ENABLE_WASAPI
#endif
#if !defined(MA_NO_DSOUND) && defined(MA_SUPPORT_DSOUND)
#define MA_ENABLE_DSOUND
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
-------
You cannot stop and start the device from inside the callback or else you'll get a deadlock. You must also not uninitialize the device from inside the
callback. The following APIs cannot be called from inside the callback:
ma_device_init()
ma_device_init_ex()
ma_device_uninit()
ma_device_start()
ma_device_stop()
The proper way to stop the device is to call `ma_device_stop()` from a different thread, normally the main application thread.
*/
typedef void (* ma_device_callback_proc)(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
/*
The callback for when the device has been stopped.
This will be called when the device is stopped explicitly with `ma_device_stop()` and also called implicitly when the device is stopped through external forces
such as being unplugged or an internal error occuring.
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
struct
{
const char* pStreamNamePlayback;
const char* pStreamNameCapture;
} pulse;
} ma_device_config;
typedef struct
{
ma_log_proc logCallback;
ma_thread_priority threadPriority;
size_t threadStackSize;
void* pUserData;
ma_allocation_callbacks allocationCallbacks;
struct
{
ma_bool32 useVerboseDeviceEnumeration;
} alsa;
struct
{
const char* pApplicationName;
const char* pServerName;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
pUserData (in)
The user data pointer passed into `ma_context_enumerate_devices()`.
*/
typedef ma_bool32 (* ma_enum_devices_callback_proc)(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData);
struct ma_context
{
ma_backend backend; /* DirectSound, ALSA, etc. */
ma_log_proc logCallback;
ma_thread_priority threadPriority;
size_t threadStackSize;
void* pUserData;
ma_allocation_callbacks allocationCallbacks;
ma_mutex deviceEnumLock; /* Used to make ma_context_get_devices() thread safe. */
ma_mutex deviceInfoLock; /* Used to make ma_context_get_device_info() thread safe. */
ma_uint32 deviceInfoCapacity; /* Total capacity of pDeviceInfos. */
ma_uint32 playbackDeviceInfoCount;
ma_uint32 captureDeviceInfoCount;
ma_device_info* pDeviceInfos; /* Playback devices first, then capture. */
ma_bool32 isBackendAsynchronous : 1; /* Set when the context is initialized. Set to 1 for asynchronous backends such as Core Audio and JACK. Do not modify. */
ma_result (* onUninit )(ma_context* pContext);
ma_bool32 (* onDeviceIDEqual )(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1);
ma_result (* onEnumDevices )(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData); /* Return false from the callback to stop enumeration. */
ma_result (* onGetDeviceInfo )(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
/*HMODULE*/ ma_handle hAdvapi32DLL;
ma_proc RegOpenKeyExA;
ma_proc RegCloseKey;
ma_proc RegQueryValueExA;
} win32;
#endif
#ifdef MA_POSIX
struct
{
ma_handle pthreadSO;
ma_proc pthread_create;
ma_proc pthread_join;
ma_proc pthread_mutex_init;
ma_proc pthread_mutex_destroy;
ma_proc pthread_mutex_lock;
ma_proc pthread_mutex_unlock;
ma_proc pthread_cond_init;
ma_proc pthread_cond_destroy;
ma_proc pthread_cond_wait;
ma_proc pthread_cond_signal;
ma_proc pthread_attr_init;
ma_proc pthread_attr_destroy;
ma_proc pthread_attr_setschedpolicy;
ma_proc pthread_attr_getschedparam;
ma_proc pthread_attr_setschedparam;
} posix;
#endif
int _unused;
};
};
struct ma_device
{
ma_context* pContext;
ma_device_type type;
ma_uint32 sampleRate;
volatile ma_uint32 state; /* The state of the device is variable and can change at any time on any thread, so tell the compiler as such with `volatile`. */
ma_device_callback_proc onData; /* Set once at initialization time and should not be changed after. */
ma_stop_proc onStop; /* Set once at initialization time and should not be changed after. */
void* pUserData; /* Application defined data. */
ma_mutex lock;
ma_event wakeupEvent;
ma_event startEvent;
ma_event stopEvent;
ma_thread thread;
ma_result workResult; /* This is set by the worker thread after it's finished doing a job. */
ma_bool32 usingDefaultSampleRate : 1;
ma_bool32 usingDefaultBufferSize : 1;
ma_bool32 usingDefaultPeriods : 1;
ma_bool32 isOwnerOfContext : 1; /* When set to true, uninitializing the device will also uninitialize the context. Set to true when NULL is passed into ma_device_init(). */
ma_bool32 noPreZeroedOutputBuffer : 1;
ma_bool32 noClip : 1;
volatile float masterVolumeFactor; /* Volatile so we can use some thread safety when applying volume to periods. */
struct
{
ma_resample_algorithm algorithm;
struct
{
ma_uint32 lpfOrder;
} linear;
struct
{
int quality;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
struct
{
int indexPlayback; /* We use a factory on the JavaScript side to manage devices and use an index for JS/C interop. */
int indexCapture;
ma_pcm_rb duplexRB; /* In external capture format. */
} webaudio;
#endif
#ifdef MA_SUPPORT_NULL
struct
{
ma_thread deviceThread;
ma_event operationEvent;
ma_event operationCompletionEvent;
ma_uint32 operation;
ma_result operationResult;
ma_timer timer;
double priorRunTime;
ma_uint32 currentPeriodFramesRemainingPlayback;
ma_uint32 currentPeriodFramesRemainingCapture;
ma_uint64 lastProcessedFramePlayback;
ma_uint64 lastProcessedFrameCapture;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
A pointer to the context object being initialized.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Unsafe. Do not call this function across multiple threads as some backends read and write to global state.
Remarks
-------
When `backends` is NULL, the default priority order will be used. Below is a list of backends in priority order:
|-------------|-----------------------|--------------------------------------------------------|
| Name | Enum Name | Supported Operating Systems |
|-------------|-----------------------|--------------------------------------------------------|
| WASAPI | ma_backend_wasapi | Windows Vista+ |
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
| Web Audio | ma_backend_webaudio | Web (via Emscripten) |
| Null | ma_backend_null | Cross Platform (not used on Web) |
|-------------|-----------------------|--------------------------------------------------------|
The context can be configured via the `pConfig` argument. The config object is initialized with `ma_context_config_init()`. Individual configuration settings
can then be set directly on the structure. Below are the members of the `ma_context_config` object.
logCallback
Callback for handling log messages from miniaudio.
threadPriority
The desired priority to use for the audio thread. Allowable values include the following:
|--------------------------------------|
| Thread Priority |
|--------------------------------------|
| ma_thread_priority_idle |
| ma_thread_priority_lowest |
| ma_thread_priority_low |
| ma_thread_priority_normal |
| ma_thread_priority_high |
| ma_thread_priority_highest (default) |
| ma_thread_priority_realtime |
| ma_thread_priority_default |
|--------------------------------------|
pUserData
A pointer to application-defined data. This can be accessed from the context object directly such as `context.pUserData`.
allocationCallbacks
Structure containing custom allocation callbacks. Leaving this at defaults will cause it to use MA_MALLOC, MA_REALLOC and MA_FREE. These allocation
callbacks will be used for anything tied to the context, including devices.
alsa.useVerboseDeviceEnumeration
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
Uninitializes a context.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Unsafe. Do not call this function across multiple threads as some backends read and write to global state.
Remarks
-------
Results are undefined if you call this while any device created by this context is still active.
See Also
--------
ma_context_init()
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Unsafe. Since each call to this function invalidates the pointers from the previous call, you should not be calling this simultaneously across multiple
threads. Instead, you need to make a copy of the returned data with your own higher level synchronization.
Remarks
-------
It is _not_ safe to assume the first device in the list is the default device.
You can pass in NULL for the playback or capture lists in which case they'll be ignored.
The returned pointers will become invalid upon the next call this this function, or when the context is uninitialized. Do not free the returned pointers.
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
in exclusive mode, and then fall back to shared mode if required. Alternatively you can just request shared mode (the default if you leave it unset in the
config) which is the most reliable option. Some backends do not have a practical way of choosing whether or not the device should be exclusive or not (ALSA,
for example) in which case it just acts as a hint. Unless you have special requirements you should try avoiding exclusive mode as it's intrusive to the user.
Starting with Windows 10, miniaudio will use low-latency shared mode where possible which may make exclusive mode unnecessary.
When sending or receiving data to/from a device, miniaudio will internally perform a format conversion to convert between the format specified by the config
and the format used internally by the backend. If you pass in 0 for the sample format, channel count, sample rate _and_ channel map, data transmission will run
on an optimized pass-through fast path. You can retrieve the format, channel count and sample rate by inspecting the `playback/capture.format`,
`playback/capture.channels` and `sampleRate` members of the device object.
When compiling for UWP you must ensure you call this function on the main UI thread because the operating system may need to present the user with a message
asking for permissions. Please refer to the official documentation for ActivateAudioInterfaceAsync() for more information.
ALSA Specific: When initializing the default device, requesting shared mode will try using the "dmix" device for playback and the "dsnoop" device for capture.
If these fail it will try falling back to the "hw" device.
Example 1 - Simple Initialization
---------------------------------
This example shows how to initialize a simple playback device using a standard configuration. If you are just needing to do simple playback from the default
playback device this is usually all you need.
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
A pointer to the device to start.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Safe. It's safe to call this from any thread with the exception of the callback thread.
Callback Safety
---------------
Unsafe. It is not safe to call this inside any callback.
Remarks
-------
For a playback device, this will retrieve an initial chunk of audio data from the client before returning. The reason for this is to ensure there is valid
audio data in the buffer, which needs to be done before the device begins playback.
This API waits until the backend device has been started for real by the worker thread. It also waits on a mutex for thread-safety.
Do not call this in any callback.
See Also
--------
ma_device_stop()
*/
MA_API ma_result ma_device_start(ma_device* pDevice);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
A pointer to the device to stop.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Safe. It's safe to call this from any thread with the exception of the callback thread.
Callback Safety
---------------
Unsafe. It is not safe to call this inside any callback. Doing this will result in a deadlock.
Remarks
-------
This API needs to wait on the worker thread to stop the backend device properly before returning. It also waits on a mutex for thread-safety. In addition, some
backends need to wait for the device to finish playback/recording of the current fragment which can take some time (usually proportionate to the buffer size
that was specified at initialization time).
Backends are required to either pause the stream in-place or drain the buffer if pausing is not possible. The reason for this is that stopping the device and
the resuming it with ma_device_start() (which you might do when your program loses focus) may result in a situation where those samples are never output to the
speakers or received from the microphone which can in turn result in de-syncs.
Do not call this in any callback.
This will be called implicitly by `ma_device_uninit()`.
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
A pointer to the device whose start state is being retrieved.
Return Value
------------
True if the device is started, false otherwise.
Thread Safety
-------------
Safe. If another thread calls `ma_device_start()` or `ma_device_stop()` at this same time as this function is called, there's a very small chance the return
value will be out of sync.
Callback Safety
---------------
Safe. This is implemented as a simple accessor.
See Also
--------
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
{
ma_resource_format_wav
} ma_resource_format;
#endif
/************************************************************************************************************************************************************
Decoding
========
Decoders are independent of the main device API. Decoding APIs can be called freely inside the device's data callback, but they are not thread safe unless
you do your own synchronization.
************************************************************************************************************************************************************/
#ifndef MA_NO_DECODING
typedef struct ma_decoder ma_decoder;
typedef size_t (* ma_decoder_read_proc) (ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead); /* Returns the number of bytes read. */
typedef ma_bool32 (* ma_decoder_seek_proc) (ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin); /* Origin will never be ma_seek_origin_end. */
typedef ma_uint64 (* ma_decoder_read_pcm_frames_proc) (ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount); /* Returns the number of frames read. Output data is in internal format. */
typedef ma_result (* ma_decoder_seek_to_pcm_frame_proc) (ma_decoder* pDecoder, ma_uint64 frameIndex);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
Do not call this on streams of an undefined length, such as internet radio.
If the length is unknown or an error occurs, 0 will be returned.
This will always return 0 for Vorbis decoders. This is due to a limitation with stb_vorbis in push mode which is what miniaudio
uses internally.
For MP3's, this will decode the entire file. Do not call this in time critical scenarios.
This function is not thread safe without your own synchronization.
*/
MA_API ma_uint64 ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder);
/*
Reads PCM frames from the given decoder.
This is not thread safe without your own synchronization.
*/
MA_API ma_uint64 ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount);
/*
Seeks to a PCM frame based on it's absolute index.
This is not thread safe without your own synchronization.
*/
MA_API ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex);
/*
Retrieves the number of frames that can be read before reaching the end.
This calls `ma_decoder_get_length_in_pcm_frames()` so you need to be aware of the rules for that function, in
particular ensuring you do not call it on streams of an undefined length, such as internet radio.
If the total length of the decoder cannot be retrieved, such as with Vorbis decoders, `MA_NOT_IMPLEMENTED` will be
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
*ppFile = _wfopen(pFilePath, pOpenMode);
if (*ppFile == NULL) {
return ma_result_from_errno(errno);
}
#endif
(void)pAllocationCallbacks;
}
#else
/*
Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can
think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility.
*/
{
mbstate_t mbs;
size_t lenMB;
const wchar_t* pFilePathTemp = pFilePath;
char* pFilePathMB = NULL;
char pOpenModeMB[32] = {0};
/* Get the length first. */
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
return a;
}
/*
Random Number Generation
miniaudio uses the LCG random number generation algorithm. This is good enough for audio.
Note that miniaudio's global LCG implementation uses global state which is _not_ thread-local. When this is called across
multiple threads, results will be unpredictable. However, it won't crash and results will still be random enough for
miniaudio's purposes.
*/
#ifndef MA_DEFAULT_LCG_SEED
#define MA_DEFAULT_LCG_SEED 4321
#endif
#define MA_LCG_M 2147483647
#define MA_LCG_A 48271
#define MA_LCG_C 0
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#define c89atomic_fetch_add_explicit_16(dst, src, order) (c89atomic_uint16)_InterlockedExchangeAdd16((volatile short*)dst, (short)src)
#define c89atomic_fetch_add_explicit_32(dst, src, order) (c89atomic_uint32)_InterlockedExchangeAdd ((volatile long* )dst, (long )src)
#if defined(C89ATOMIC_64BIT)
#define c89atomic_fetch_add_explicit_64(dst, src, order) (c89atomic_uint64)_InterlockedExchangeAdd64((volatile long long*)dst, (long long)src)
#endif
#define c89atomic_compare_and_swap_8( dst, expected, desired) (c89atomic_uint8 )_InterlockedCompareExchange8 ((volatile char* )dst, (char )desired, (char )expected)
#define c89atomic_compare_and_swap_16(dst, expected, desired) (c89atomic_uint16)_InterlockedCompareExchange16((volatile short* )dst, (short )desired, (short )expected)
#define c89atomic_compare_and_swap_32(dst, expected, desired) (c89atomic_uint32)_InterlockedCompareExchange ((volatile long* )dst, (long )desired, (long )expected)
#define c89atomic_compare_and_swap_64(dst, expected, desired) (c89atomic_uint64)_InterlockedCompareExchange64((volatile long long*)dst, (long long)desired, (long long)expected)
#if defined(C89ATOMIC_X64)
#define c89atomic_thread_fence(order) __faststorefence()
#else
static C89ATOMIC_INLINE void c89atomic_thread_fence(c89atomic_memory_order order)
{
volatile c89atomic_uint32 barrier = 0;
(void)order;
c89atomic_fetch_add_explicit_32(&barrier, 0, order);
}
#endif
#else
#if defined(__i386) || defined(_M_IX86)
static C89ATOMIC_INLINE void __stdcall c89atomic_thread_fence(int order)
{
volatile c89atomic_uint32 barrier;
(void)order;
__asm {
xchg barrier, eax
}
}
static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, int order)
{
(void)order;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
mov edx, dword ptr expected + 4
mov ebx, dword ptr desired
mov ecx, dword ptr desired + 4
lock cmpxchg8b qword ptr [esi]
}
}
#else
error "Unsupported architecture."
#endif
#endif
#define c89atomic_compiler_fence() c89atomic_thread_fence(c89atomic_memory_order_seq_cst)
#define c89atomic_signal_fence(order) c89atomic_thread_fence(order)
#define c89atomic_load_explicit_8( ptr, order) c89atomic_compare_and_swap_8 (ptr, 0, 0)
#define c89atomic_load_explicit_16(ptr, order) c89atomic_compare_and_swap_16(ptr, 0, 0)
#define c89atomic_load_explicit_32(ptr, order) c89atomic_compare_and_swap_32(ptr, 0, 0)
#define c89atomic_load_explicit_64(ptr, order) c89atomic_compare_and_swap_64(ptr, 0, 0)
#define c89atomic_store_explicit_8( dst, src, order) (void)c89atomic_exchange_explicit_8 (dst, src, order)
#define c89atomic_store_explicit_16(dst, src, order) (void)c89atomic_exchange_explicit_16(dst, src, order)
#define c89atomic_store_explicit_32(dst, src, order) (void)c89atomic_exchange_explicit_32(dst, src, order)
#define c89atomic_store_explicit_64(dst, src, order) (void)c89atomic_exchange_explicit_64(dst, src, order)
#if defined(C89ATOMIC_32BIT)
static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, int order)
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC__ >= 7)))
#define C89ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE
#define C89ATOMIC_HAS_NATIVE_IS_LOCK_FREE
#define c89atomic_memory_order_relaxed __ATOMIC_RELAXED
#define c89atomic_memory_order_consume __ATOMIC_CONSUME
#define c89atomic_memory_order_acquire __ATOMIC_ACQUIRE
#define c89atomic_memory_order_release __ATOMIC_RELEASE
#define c89atomic_memory_order_acq_rel __ATOMIC_ACQ_REL
#define c89atomic_memory_order_seq_cst __ATOMIC_SEQ_CST
#define c89atomic_compiler_fence() __asm__ __volatile__("":::"memory")
#define c89atomic_thread_fence(order) __atomic_thread_fence(order)
#define c89atomic_signal_fence(order) __atomic_signal_fence(order)
#define c89atomic_is_lock_free_8(ptr) __atomic_is_lock_free(1, ptr)
#define c89atomic_is_lock_free_16(ptr) __atomic_is_lock_free(2, ptr)
#define c89atomic_is_lock_free_32(ptr) __atomic_is_lock_free(4, ptr)
#define c89atomic_is_lock_free_64(ptr) __atomic_is_lock_free(8, ptr)
#define c89atomic_flag_test_and_set_explicit(dst, order) (c89atomic_flag)__atomic_test_and_set(dst, order)
#define c89atomic_flag_clear_explicit(dst, order) __atomic_clear(dst, order)
#define c89atomic_test_and_set_explicit_8( dst, order) __atomic_exchange_n(dst, 1, order)
#define c89atomic_test_and_set_explicit_16(dst, order) __atomic_exchange_n(dst, 1, order)
#define c89atomic_test_and_set_explicit_32(dst, order) __atomic_exchange_n(dst, 1, order)
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#define c89atomic_compare_and_swap_32(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired)
#define c89atomic_compare_and_swap_64(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired)
#else
#define c89atomic_memory_order_relaxed 1
#define c89atomic_memory_order_consume 2
#define c89atomic_memory_order_acquire 3
#define c89atomic_memory_order_release 4
#define c89atomic_memory_order_acq_rel 5
#define c89atomic_memory_order_seq_cst 6
#define c89atomic_compiler_fence() __asm__ __volatile__("":::"memory")
#define c89atomic_thread_fence(order) __sync_synchronize()
#define c89atomic_signal_fence(order) c89atomic_thread_fence(order)
static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
{
if (order > c89atomic_memory_order_acquire) {
__sync_synchronize();
}
return __sync_lock_test_and_set(dst, src);
}
static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
{
volatile c89atomic_uint16 oldValue;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
/*******************************************************************************
Threading
*******************************************************************************/
#ifndef MA_NO_THREADING
#ifdef MA_WIN32
#define MA_THREADCALL WINAPI
typedef unsigned long ma_thread_result;
#else
#define MA_THREADCALL
typedef void* ma_thread_result;
#endif
typedef ma_thread_result (MA_THREADCALL * ma_thread_entry_proc)(void* pData);
static MA_INLINE ma_result ma_spinlock_lock_ex(ma_spinlock* pSpinlock, ma_bool32 yield)
{
if (pSpinlock == NULL) {
return MA_INVALID_ARGS;
}
for (;;) {
if (c89atomic_flag_test_and_set_explicit(pSpinlock, c89atomic_memory_order_acquire) == 0) {
break;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
{
if (pSpinlock == NULL) {
return MA_INVALID_ARGS;
}
c89atomic_flag_clear_explicit(pSpinlock, c89atomic_memory_order_release);
return MA_SUCCESS;
}
#ifdef MA_WIN32
static int ma_thread_priority_to_win32(ma_thread_priority priority)
{
switch (priority) {
case ma_thread_priority_idle: return THREAD_PRIORITY_IDLE;
case ma_thread_priority_lowest: return THREAD_PRIORITY_LOWEST;
case ma_thread_priority_low: return THREAD_PRIORITY_BELOW_NORMAL;
case ma_thread_priority_normal: return THREAD_PRIORITY_NORMAL;
case ma_thread_priority_high: return THREAD_PRIORITY_ABOVE_NORMAL;
case ma_thread_priority_highest: return THREAD_PRIORITY_HIGHEST;
case ma_thread_priority_realtime: return THREAD_PRIORITY_TIME_CRITICAL;
default: return THREAD_PRIORITY_NORMAL;
}
}
static ma_result ma_thread_create__win32(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData)
{
*pThread = CreateThread(NULL, stackSize, entryProc, pData, 0, NULL);
if (*pThread == NULL) {
return ma_result_from_GetLastError(GetLastError());
}
SetThreadPriority((HANDLE)*pThread, ma_thread_priority_to_win32(priority));
return MA_SUCCESS;
}
static void ma_thread_wait__win32(ma_thread* pThread)
{
WaitForSingleObject((HANDLE)*pThread, INFINITE);
}
static ma_result ma_mutex_init__win32(ma_mutex* pMutex)
{
*pMutex = CreateEventW(NULL, FALSE, TRUE, NULL);
if (*pMutex == NULL) {
return ma_result_from_GetLastError(GetLastError());
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
if (result == 0) {
return ma_result_from_GetLastError(GetLastError());
}
return MA_SUCCESS;
}
#endif
#ifdef MA_POSIX
static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData)
{
int result;
pthread_attr_t* pAttr = NULL;
#if !defined(__EMSCRIPTEN__)
/* Try setting the thread priority. It's not critical if anything fails here. */
pthread_attr_t attr;
if (pthread_attr_init(&attr) == 0) {
int scheduler = -1;
if (priority == ma_thread_priority_idle) {
#ifdef SCHED_IDLE
if (pthread_attr_setschedpolicy(&attr, SCHED_IDLE) == 0) {
scheduler = SCHED_IDLE;
}
#endif
} else if (priority == ma_thread_priority_realtime) {
#ifdef SCHED_FIFO
if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) == 0) {
scheduler = SCHED_FIFO;
}
#endif
#ifdef MA_LINUX
} else {
scheduler = sched_getscheduler(0);
#endif
}
if (stackSize > 0) {
pthread_attr_setstacksize(&attr, stackSize);
}
if (scheduler != -1) {
int priorityMin = sched_get_priority_min(scheduler);
int priorityMax = sched_get_priority_max(scheduler);
int priorityStep = (priorityMax - priorityMin) / 7; /* 7 = number of priorities supported by miniaudio. */
struct sched_param sched;
if (pthread_attr_getschedparam(&attr, &sched) == 0) {
if (priority == ma_thread_priority_idle) {
sched.sched_priority = priorityMin;
} else if (priority == ma_thread_priority_realtime) {
sched.sched_priority = priorityMax;
} else {
sched.sched_priority += ((int)priority + 5) * priorityStep; /* +5 because the lowest priority is -5. */
if (sched.sched_priority < priorityMin) {
sched.sched_priority = priorityMin;
}
if (sched.sched_priority > priorityMax) {
sched.sched_priority = priorityMax;
}
}
if (pthread_attr_setschedparam(&attr, &sched) == 0) {
pAttr = &attr;
}
}
}
pthread_attr_destroy(&attr);
}
#else
/* It's the emscripten build. We'll have a few unused parameters. */
(void)priority;
(void)stackSize;
#endif
result = pthread_create(pThread, pAttr, entryProc, pData);
if (result != 0) {
return ma_result_from_errno(result);
}
return MA_SUCCESS;
}
static void ma_thread_wait__posix(ma_thread* pThread)
{
pthread_join(*pThread, NULL);
}
static ma_result ma_mutex_init__posix(ma_mutex* pMutex)
{
int result = pthread_mutex_init((pthread_mutex_t*)pMutex, NULL);
if (result != 0) {
return ma_result_from_errno(result);
}
return MA_SUCCESS;
}
static void ma_mutex_uninit__posix(ma_mutex* pMutex)
{
pthread_mutex_destroy((pthread_mutex_t*)pMutex);
}
static void ma_mutex_lock__posix(ma_mutex* pMutex)
{
pthread_mutex_lock((pthread_mutex_t*)pMutex);
}
static void ma_mutex_unlock__posix(ma_mutex* pMutex)
{
pthread_mutex_unlock((pthread_mutex_t*)pMutex);
}
static ma_result ma_event_init__posix(ma_event* pEvent)
{
int result;
result = pthread_mutex_init(&pEvent->lock, NULL);
if (result != 0) {
return ma_result_from_errno(result);
}
result = pthread_cond_init(&pEvent->cond, NULL);
if (result != 0) {
pthread_mutex_destroy(&pEvent->lock);
return ma_result_from_errno(result);
}
pEvent->value = 0;
return MA_SUCCESS;
}
static void ma_event_uninit__posix(ma_event* pEvent)
{
pthread_cond_destroy(&pEvent->cond);
pthread_mutex_destroy(&pEvent->lock);
}
static ma_result ma_event_wait__posix(ma_event* pEvent)
{
pthread_mutex_lock(&pEvent->lock);
{
while (pEvent->value == 0) {
pthread_cond_wait(&pEvent->cond, &pEvent->lock);
}
pEvent->value = 0; /* Auto-reset. */
}
pthread_mutex_unlock(&pEvent->lock);
return MA_SUCCESS;
}
static ma_result ma_event_signal__posix(ma_event* pEvent)
{
pthread_mutex_lock(&pEvent->lock);
{
pEvent->value = 1;
pthread_cond_signal(&pEvent->cond);
}
pthread_mutex_unlock(&pEvent->lock);
return MA_SUCCESS;
}
static ma_result ma_semaphore_init__posix(int initialValue, ma_semaphore* pSemaphore)
{
int result;
if (pSemaphore == NULL) {
return MA_INVALID_ARGS;
}
pSemaphore->value = initialValue;
result = pthread_mutex_init(&pSemaphore->lock, NULL);
if (result != 0) {
return ma_result_from_errno(result); /* Failed to create mutex. */
}
result = pthread_cond_init(&pSemaphore->cond, NULL);
if (result != 0) {
pthread_mutex_destroy(&pSemaphore->lock);
return ma_result_from_errno(result); /* Failed to create condition variable. */
}
return MA_SUCCESS;
}
static void ma_semaphore_uninit__posix(ma_semaphore* pSemaphore)
{
if (pSemaphore == NULL) {
return;
}
pthread_cond_destroy(&pSemaphore->cond);
pthread_mutex_destroy(&pSemaphore->lock);
}
static ma_result ma_semaphore_wait__posix(ma_semaphore* pSemaphore)
{
if (pSemaphore == NULL) {
return MA_INVALID_ARGS;
}
pthread_mutex_lock(&pSemaphore->lock);
{
/* We need to wait on a condition variable before escaping. We can't return from this function until the semaphore has been signaled. */
while (pSemaphore->value == 0) {
pthread_cond_wait(&pSemaphore->cond, &pSemaphore->lock);
}
pSemaphore->value -= 1;
}
pthread_mutex_unlock(&pSemaphore->lock);
return MA_SUCCESS;
}
static ma_result ma_semaphore_release__posix(ma_semaphore* pSemaphore)
{
if (pSemaphore == NULL) {
return MA_INVALID_ARGS;
}
pthread_mutex_lock(&pSemaphore->lock);
{
pSemaphore->value += 1;
pthread_cond_signal(&pSemaphore->cond);
}
pthread_mutex_unlock(&pSemaphore->lock);
return MA_SUCCESS;
}
#endif
static ma_result ma_thread_create(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData)
{
if (pThread == NULL || entryProc == NULL) {
return MA_FALSE;
}
#ifdef MA_WIN32
return ma_thread_create__win32(pThread, priority, stackSize, entryProc, pData);
#endif
#ifdef MA_POSIX
return ma_thread_create__posix(pThread, priority, stackSize, entryProc, pData);
#endif
}
static void ma_thread_wait(ma_thread* pThread)
{
if (pThread == NULL) {
return;
}
#ifdef MA_WIN32
ma_thread_wait__win32(pThread);
#endif
#ifdef MA_POSIX
ma_thread_wait__posix(pThread);
#endif
}
MA_API ma_result ma_mutex_init(ma_mutex* pMutex)
{
if (pMutex == NULL) {
MA_ASSERT(MA_FALSE); /* Fire an assert to the caller is aware of this bug. */
return MA_INVALID_ARGS;
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
}
#ifdef MA_WIN32
return ma_semaphore_release__win32(pSemaphore);
#endif
#ifdef MA_POSIX
return ma_semaphore_release__posix(pSemaphore);
#endif
}
#else
/* MA_NO_THREADING is set which means threading is disabled. Threading is required by some API families. If any of these are enabled we need to throw an error. */
#ifndef MA_NO_DEVICE_IO
#error "MA_NO_THREADING cannot be used without MA_NO_DEVICE_IO";
#endif
#endif /* MA_NO_THREADING */
/************************************************************************************************************************************************************
*************************************************************************************************************************************************************
DEVICE I/O
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#include <mach/mach_time.h> /* For mach_absolute_time() */
#endif
#ifdef MA_POSIX
#include <sys/types.h>
#include <unistd.h>
#include <dlfcn.h>
#endif
/*
Unfortunately using runtime linking for pthreads causes problems. This has occurred for me when testing on FreeBSD. When
using runtime linking, deadlocks can occur (for me it happens when loading data from fread()). It turns out that doing
compile-time linking fixes this. I'm not sure why this happens, but the safest way I can think of to fix this is to simply
disable runtime linking by default. To enable runtime linking, #define this before the implementation of this file. I am
not officially supporting this, but I'm leaving it here in case it's useful for somebody, somewhere.
*/
/*#define MA_USE_RUNTIME_LINKING_FOR_PTHREAD*/
/* Disable run-time linking on certain backends. */
#ifndef MA_NO_RUNTIME_LINKING
#if defined(MA_ANDROID) || defined(MA_EMSCRIPTEN)
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
/* Microsoft documents these APIs as returning LSTATUS, but the Win32 API shipping with some compilers do not define it. It's just a LONG. */
typedef LONG (WINAPI * MA_PFN_RegOpenKeyExA)(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
typedef LONG (WINAPI * MA_PFN_RegCloseKey)(HKEY hKey);
typedef LONG (WINAPI * MA_PFN_RegQueryValueExA)(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);
#endif
#define MA_STATE_UNINITIALIZED 0
#define MA_STATE_STOPPED 1 /* The device's default state after initialization. */
#define MA_STATE_STARTED 2 /* The worker thread is in it's main loop waiting for the driver to request or deliver audio data. */
#define MA_STATE_STARTING 3 /* Transitioning from a stopped state to started. */
#define MA_STATE_STOPPING 4 /* Transitioning from a started state to stopped. */
#define MA_DEFAULT_PLAYBACK_DEVICE_NAME "Default Playback Device"
#define MA_DEFAULT_CAPTURE_DEVICE_NAME "Default Capture Device"
MA_API const char* ma_log_level_to_string(ma_uint32 logLevel)
{
switch (logLevel)
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
Null Backend
*******************************************************************************/
#ifdef MA_HAS_NULL
#define MA_DEVICE_OP_NONE__NULL 0
#define MA_DEVICE_OP_START__NULL 1
#define MA_DEVICE_OP_SUSPEND__NULL 2
#define MA_DEVICE_OP_KILL__NULL 3
static ma_thread_result MA_THREADCALL ma_device_thread__null(void* pData)
{
ma_device* pDevice = (ma_device*)pData;
MA_ASSERT(pDevice != NULL);
for (;;) { /* Keep the thread alive until the device is uninitialized. */
/* Wait for an operation to be requested. */
ma_event_wait(&pDevice->null_device.operationEvent);
/* At this point an event should have been triggered. */
/* Starting the device needs to put the thread into a loop. */
if (pDevice->null_device.operation == MA_DEVICE_OP_START__NULL) {
c89atomic_exchange_32(&pDevice->null_device.operation, MA_DEVICE_OP_NONE__NULL);
/* Reset the timer just in case. */
ma_timer_init(&pDevice->null_device.timer);
/* Keep looping until an operation has been requested. */
while (pDevice->null_device.operation != MA_DEVICE_OP_NONE__NULL && pDevice->null_device.operation != MA_DEVICE_OP_START__NULL) {
ma_sleep(10); /* Don't hog the CPU. */
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
/* We need to add the current run time to the prior run time, then reset the timer. */
pDevice->null_device.priorRunTime += ma_timer_get_time_in_seconds(&pDevice->null_device.timer);
ma_timer_init(&pDevice->null_device.timer);
/* We're done. */
c89atomic_exchange_32((c89atomic_uint32*)&pDevice->null_device.operationResult, MA_SUCCESS);
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
continue;
}
/* Killing the device means we need to get out of this loop so that this thread can terminate. */
if (pDevice->null_device.operation == MA_DEVICE_OP_KILL__NULL) {
c89atomic_exchange_32(&pDevice->null_device.operation, MA_DEVICE_OP_NONE__NULL);
c89atomic_exchange_32((c89atomic_uint32*)&pDevice->null_device.operationResult, MA_SUCCESS);
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
break;
}
/* Getting a signal on a "none" operation probably means an error. Return invalid operation. */
if (pDevice->null_device.operation == MA_DEVICE_OP_NONE__NULL) {
MA_ASSERT(MA_FALSE); /* <-- Trigger this in debug mode to ensure developers are aware they're doing something wrong (or there's a bug in a miniaudio). */
c89atomic_exchange_32((c89atomic_uint32*)&pDevice->null_device.operationResult, (c89atomic_uint32)MA_INVALID_OPERATION);
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
continue; /* Continue the loop. Don't terminate. */
}
}
return (ma_thread_result)0;
}
static ma_result ma_device_do_operation__null(ma_device* pDevice, ma_uint32 operation)
{
c89atomic_exchange_32(&pDevice->null_device.operation, operation);
if (ma_event_signal(&pDevice->null_device.operationEvent) != MA_SUCCESS) {
return MA_ERROR;
}
if (ma_event_wait(&pDevice->null_device.operationCompletionEvent) != MA_SUCCESS) {
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
(void)pContext;
(void)shareMode;
return MA_SUCCESS;
}
static void ma_device_uninit__null(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
/* Keep it clean and wait for the device thread to finish before returning. */
ma_device_do_operation__null(pDevice, MA_DEVICE_OP_KILL__NULL);
/* At this point the loop in the device thread is as good as terminated so we can uninitialize our events. */
ma_event_uninit(&pDevice->null_device.operationCompletionEvent);
ma_event_uninit(&pDevice->null_device.operationEvent);
}
static ma_result ma_device_init__null(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
{
ma_result result;
ma_uint32 periodSizeInFrames;
MA_ASSERT(pDevice != NULL);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), "NULL Playback Device", (size_t)-1);
pDevice->playback.internalFormat = pConfig->playback.format;
pDevice->playback.internalChannels = pConfig->playback.channels;
ma_channel_map_copy(pDevice->playback.internalChannelMap, pConfig->playback.channelMap, ma_min(pConfig->playback.channels, MA_MAX_CHANNELS));
pDevice->playback.internalPeriodSizeInFrames = periodSizeInFrames;
pDevice->playback.internalPeriods = pConfig->periods;
}
/*
In order to get timing right, we need to create a thread that does nothing but keeps track of the timer. This timer is started when the
first period is "written" to it, and then stopped in ma_device_stop__null().
*/
result = ma_event_init(&pDevice->null_device.operationEvent);
if (result != MA_SUCCESS) {
return result;
}
result = ma_event_init(&pDevice->null_device.operationCompletionEvent);
if (result != MA_SUCCESS) {
return result;
}
result = ma_thread_create(&pDevice->thread, pContext->threadPriority, 0, ma_device_thread__null, pDevice);
if (result != MA_SUCCESS) {
return result;
}
return MA_SUCCESS;
}
static ma_result ma_device_start__null(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
struct ma_completion_handler_uwp
{
ma_completion_handler_uwp_vtbl* lpVtbl;
ma_uint32 counter;
HANDLE hEvent;
};
static HRESULT STDMETHODCALLTYPE ma_completion_handler_uwp_QueryInterface(ma_completion_handler_uwp* pThis, const IID* const riid, void** ppObject)
{
/*
We need to "implement" IAgileObject which is just an indicator that's used internally by WASAPI for some multithreading management. To
"implement" this, we just make sure we return pThis when the IAgileObject is requested.
*/
if (!ma_is_guid_equal(riid, &MA_IID_IUnknown) && !ma_is_guid_equal(riid, &MA_IID_IActivateAudioInterfaceCompletionHandler) && !ma_is_guid_equal(riid, &MA_IID_IAgileObject)) {
*ppObject = NULL;
return E_NOINTERFACE;
}
/* Getting here means the IID is IUnknown or IMMNotificationClient. */
*ppObject = (void*)pThis;
((ma_completion_handler_uwp_vtbl*)pThis->lpVtbl)->AddRef(pThis);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
Not currently supporting automatic stream routing in exclusive mode. This is not working correctly on my machine due to
AUDCLNT_E_DEVICE_IN_USE errors when reinitializing the device. If this is a bug in miniaudio, we can try re-enabling this once
it's fixed.
*/
if ((dataFlow == ma_eRender && pThis->pDevice->playback.shareMode == ma_share_mode_exclusive) ||
(dataFlow == ma_eCapture && pThis->pDevice->capture.shareMode == ma_share_mode_exclusive)) {
return S_OK;
}
/*
We don't change the device here - we change it in the worker thread to keep synchronization simple. To do this I'm just setting a flag to
indicate that the default device has changed. Loopback devices are treated as capture devices so we need to do a bit of a dance to handle
that properly.
*/
if (dataFlow == ma_eRender && pThis->pDevice->type != ma_device_type_loopback) {
c89atomic_exchange_32(&pThis->pDevice->wasapi.hasDefaultPlaybackDeviceChanged, MA_TRUE);
}
if (dataFlow == ma_eCapture || pThis->pDevice->type == ma_device_type_loopback) {
c89atomic_exchange_32(&pThis->pDevice->wasapi.hasDefaultCaptureDeviceChanged, MA_TRUE);
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
ma_device__track__coreaudio(pDevice);
}
#endif
}
pDevice->coreaudio.originalPeriodSizeInFrames = pConfig->periodSizeInFrames;
pDevice->coreaudio.originalPeriodSizeInMilliseconds = pConfig->periodSizeInMilliseconds;
pDevice->coreaudio.originalPeriods = pConfig->periods;
/*
When stopping the device, a callback is called on another thread. We need to wait for this callback
before returning from ma_device_stop(). This event is used for this.
*/
ma_event_init(&pDevice->coreaudio.stopEvent);
/* Need a ring buffer for duplex mode. */
if (pConfig->deviceType == ma_device_type_duplex) {
ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods);
ma_result result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->pContext->allocationCallbacks, &pDevice->coreaudio.duplexRB);
if (result != MA_SUCCESS) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[Core Audio] Failed to initialize ring buffer.", result);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
return MA_SUCCESS;
}
static ma_result ma_device_stop__oss(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
/*
We want to use SNDCTL_DSP_HALT. From the documentation:
In multithreaded applications SNDCTL_DSP_HALT (SNDCTL_DSP_RESET) must only be called by the thread
that actually reads/writes the audio device. It must not be called by some master thread to kill the
audio thread. The audio thread will not stop or get any kind of notification that the device was
stopped by the master thread. The device gets stopped but the next read or write call will silently
restart the device.
This is actually safe in our case, because this function is only ever called from within our worker
thread anyway. Just keep this in mind, though...
*/
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
int result = ioctl(pDevice->oss.fdCapture, SNDCTL_DSP_HALT, 0);
if (result == -1) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to stop device. SNDCTL_DSP_HALT failed.", ma_result_from_errno(errno));
}
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
MA_ASSERT(pDevice != NULL);
(void)error;
#if defined(MA_DEBUG_OUTPUT)
printf("[AAudio] ERROR CALLBACK: error=%d, AAudioStream_getState()=%d\n", error, ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream));
#endif
/*
From the documentation for AAudio, when a device is disconnected all we can do is stop it. However, we cannot stop it from the callback - we need
to do it from another thread. Therefore we are going to use an event thread for the AAudio backend to do this cleanly and safely.
*/
if (((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream) == MA_AAUDIO_STREAM_STATE_DISCONNECTED) {
#if defined(MA_DEBUG_OUTPUT)
printf("[AAudio] Device Disconnected.\n");
#endif
}
}
static ma_aaudio_data_callback_result_t ma_stream_data_callback_capture__aaudio(ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t frameCount)
{
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
result = ma_data_converter_init(&converterConfig, &pDevice->playback.converter);
if (result != MA_SUCCESS) {
return result;
}
}
return MA_SUCCESS;
}
static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData)
{
ma_device* pDevice = (ma_device*)pData;
MA_ASSERT(pDevice != NULL);
#ifdef MA_WIN32
ma_CoInitializeEx(pDevice->pContext, NULL, MA_COINIT_VALUE);
#endif
/*
When the device is being initialized it's initial state is set to MA_STATE_UNINITIALIZED. Before returning from
ma_device_init(), the state needs to be set to something valid. In miniaudio the device's default state immediately
after initialization is stopped, so therefore we need to mark the device as such. miniaudio will wait on the worker
thread to signal an event to know when the worker thread is ready for action.
*/
ma_device__set_state(pDevice, MA_STATE_STOPPED);
ma_event_signal(&pDevice->stopEvent);
for (;;) { /* <-- This loop just keeps the thread alive. The main audio loop is inside. */
ma_stop_proc onStop;
/* We wait on an event to know when something has requested that the device be started and the main loop entered. */
ma_event_wait(&pDevice->wakeupEvent);
/* Default result code. */
pDevice->workResult = MA_SUCCESS;
/* If the reason for the wake up is that we are terminating, just break from the loop. */
if (ma_device__get_state(pDevice) == MA_STATE_UNINITIALIZED) {
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
}
}
/* Make sure we aren't continuously waiting on a stop event. */
ma_event_signal(&pDevice->stopEvent); /* <-- Is this still needed? */
#ifdef MA_WIN32
ma_CoUninitialize(pDevice->pContext);
#endif
return (ma_thread_result)0;
}
/* Helper for determining whether or not the given device is initialized. */
static ma_bool32 ma_device__is_initialized(ma_device* pDevice)
{
if (pDevice == NULL) {
return MA_FALSE;
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegQueryValueExA");
#endif
ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE);
return MA_SUCCESS;
}
#else
static ma_result ma_context_uninit_backend_apis__nix(ma_context* pContext)
{
#if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING)
ma_dlclose(pContext, pContext->posix.pthreadSO);
#else
(void)pContext;
#endif
return MA_SUCCESS;
}
static ma_result ma_context_init_backend_apis__nix(ma_context* pContext)
{
/* pthread */
#if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING)
const char* libpthreadFileNames[] = {
"libpthread.so",
"libpthread.so.0",
"libpthread.dylib"
};
size_t i;
for (i = 0; i < sizeof(libpthreadFileNames) / sizeof(libpthreadFileNames[0]); ++i) {
pContext->posix.pthreadSO = ma_dlopen(pContext, libpthreadFileNames[i]);
if (pContext->posix.pthreadSO != NULL) {
break;
}
}
if (pContext->posix.pthreadSO == NULL) {
return MA_FAILED_TO_INIT_BACKEND;
}
pContext->posix.pthread_create = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_create");
pContext->posix.pthread_join = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_join");
pContext->posix.pthread_mutex_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_init");
pContext->posix.pthread_mutex_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_destroy");
pContext->posix.pthread_mutex_lock = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_lock");
pContext->posix.pthread_mutex_unlock = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_unlock");
pContext->posix.pthread_cond_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_init");
pContext->posix.pthread_cond_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_destroy");
pContext->posix.pthread_cond_wait = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_wait");
pContext->posix.pthread_cond_signal = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_signal");
pContext->posix.pthread_attr_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_init");
pContext->posix.pthread_attr_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_destroy");
pContext->posix.pthread_attr_setschedpolicy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedpolicy");
pContext->posix.pthread_attr_getschedparam = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_getschedparam");
pContext->posix.pthread_attr_setschedparam = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedparam");
#else
pContext->posix.pthread_create = (ma_proc)pthread_create;
pContext->posix.pthread_join = (ma_proc)pthread_join;
pContext->posix.pthread_mutex_init = (ma_proc)pthread_mutex_init;
pContext->posix.pthread_mutex_destroy = (ma_proc)pthread_mutex_destroy;
pContext->posix.pthread_mutex_lock = (ma_proc)pthread_mutex_lock;
pContext->posix.pthread_mutex_unlock = (ma_proc)pthread_mutex_unlock;
pContext->posix.pthread_cond_init = (ma_proc)pthread_cond_init;
pContext->posix.pthread_cond_destroy = (ma_proc)pthread_cond_destroy;
pContext->posix.pthread_cond_wait = (ma_proc)pthread_cond_wait;
pContext->posix.pthread_cond_signal = (ma_proc)pthread_cond_signal;
pContext->posix.pthread_attr_init = (ma_proc)pthread_attr_init;
pContext->posix.pthread_attr_destroy = (ma_proc)pthread_attr_destroy;
#if !defined(__EMSCRIPTEN__)
pContext->posix.pthread_attr_setschedpolicy = (ma_proc)pthread_attr_setschedpolicy;
pContext->posix.pthread_attr_getschedparam = (ma_proc)pthread_attr_getschedparam;
pContext->posix.pthread_attr_setschedparam = (ma_proc)pthread_attr_setschedparam;
#endif
#endif
return MA_SUCCESS;
}
#endif
static ma_result ma_context_init_backend_apis(ma_context* pContext)
{
ma_result result;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
MA_ZERO_OBJECT(pContext);
/* Always make sure the config is set first to ensure properties are available as soon as possible. */
if (pConfig != NULL) {
config = *pConfig;
} else {
config = ma_context_config_init();
}
pContext->logCallback = config.logCallback;
pContext->threadPriority = config.threadPriority;
pContext->threadStackSize = config.threadStackSize;
pContext->pUserData = config.pUserData;
result = ma_allocation_callbacks_init_copy(&pContext->allocationCallbacks, &config.allocationCallbacks);
if (result != MA_SUCCESS) {
return result;
}
/* Backend APIs need to be initialized first. This is where external libraries will be loaded and linked. */
result = ma_context_init_backend_apis(pContext);
if (result != MA_SUCCESS) {
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
} break;
#endif
default: break;
}
/* If this iteration was successful, return. */
if (result == MA_SUCCESS) {
result = ma_mutex_init(&pContext->deviceEnumLock);
if (result != MA_SUCCESS) {
ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device enumeration. ma_context_get_devices() is not thread safe.", result);
}
result = ma_mutex_init(&pContext->deviceInfoLock);
if (result != MA_SUCCESS) {
ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device info retrieval. ma_context_get_device_info() is not thread safe.", result);
}
#ifdef MA_DEBUG_OUTPUT
printf("[miniaudio] Endian: %s\n", ma_is_little_endian() ? "LE" : "BE");
printf("[miniaudio] SSE2: %s\n", ma_has_sse2() ? "YES" : "NO");
printf("[miniaudio] AVX2: %s\n", ma_has_avx2() ? "YES" : "NO");
printf("[miniaudio] AVX512F: %s\n", ma_has_avx512f() ? "YES" : "NO");
printf("[miniaudio] NEON: %s\n", ma_has_neon() ? "YES" : "NO");
#endif
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
pDevice->playback.internalChannels = pDevice->playback.channels;
pDevice->playback.internalSampleRate = pDevice->sampleRate;
ma_channel_map_copy(pDevice->playback.internalChannelMap, pDevice->playback.channelMap, pDevice->playback.channels);
result = ma_mutex_init(&pDevice->lock);
if (result != MA_SUCCESS) {
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create mutex.", result);
}
/*
When the device is started, the worker thread is the one that does the actual startup of the backend device. We
use a semaphore to wait for the background thread to finish the work. The same applies for stopping the device.
Each of these semaphores is released internally by the worker thread when the work is completed. The start
semaphore is also used to wake up the worker thread.
*/
result = ma_event_init(&pDevice->wakeupEvent);
if (result != MA_SUCCESS) {
ma_mutex_uninit(&pDevice->lock);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread wakeup event.", result);
}
result = ma_event_init(&pDevice->startEvent);
if (result != MA_SUCCESS) {
ma_event_uninit(&pDevice->wakeupEvent);
ma_mutex_uninit(&pDevice->lock);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread start event.", result);
}
result = ma_event_init(&pDevice->stopEvent);
if (result != MA_SUCCESS) {
ma_event_uninit(&pDevice->startEvent);
ma_event_uninit(&pDevice->wakeupEvent);
ma_mutex_uninit(&pDevice->lock);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread stop event.", result);
}
result = pContext->onDeviceInit(pContext, &config, pDevice);
if (result != MA_SUCCESS) {
return result;
}
ma_device__post_init_setup(pDevice, pConfig->deviceType);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
if (pDevice->playback.name[0] == '\0') {
if (ma_context__try_get_device_name_by_id(pContext, ma_device_type_playback, config.playback.pDeviceID, pDevice->playback.name, sizeof(pDevice->playback.name)) != MA_SUCCESS) {
ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), (config.playback.pDeviceID == NULL) ? MA_DEFAULT_PLAYBACK_DEVICE_NAME : "Playback Device", (size_t)-1);
}
}
}
/* Some backends don't require the worker thread. */
if (!ma_context_is_backend_asynchronous(pContext)) {
/* The worker thread. */
result = ma_thread_create(&pDevice->thread, pContext->threadPriority, pContext->threadStackSize, ma_worker_thread, pDevice);
if (result != MA_SUCCESS) {
ma_device_uninit(pDevice);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread.", result);
}
/* Wait for the worker thread to put the device into it's stopped state for real. */
ma_event_wait(&pDevice->stopEvent);
} else {
ma_device__set_state(pDevice, MA_STATE_STOPPED);
}
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "[%s]", ma_get_backend_name(pDevice->pContext->backend));
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " %s (%s)", pDevice->capture.name, "Capture");
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Format: %s -> %s", ma_get_format_name(pDevice->capture.format), ma_get_format_name(pDevice->capture.internalFormat));
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
{
if (!ma_device__is_initialized(pDevice)) {
return;
}
/* Make sure the device is stopped first. The backends will probably handle this naturally, but I like to do it explicitly for my own sanity. */
if (ma_device_is_started(pDevice)) {
ma_device_stop(pDevice);
}
/* Putting the device into an uninitialized state will make the worker thread return. */
ma_device__set_state(pDevice, MA_STATE_UNINITIALIZED);
/* Wake up the worker thread and wait for it to properly terminate. */
if (!ma_context_is_backend_asynchronous(pDevice->pContext)) {
ma_event_signal(&pDevice->wakeupEvent);
ma_thread_wait(&pDevice->thread);
}
pDevice->pContext->onDeviceUninit(pDevice);
ma_event_uninit(&pDevice->stopEvent);
ma_event_uninit(&pDevice->startEvent);
ma_event_uninit(&pDevice->wakeupEvent);
ma_mutex_uninit(&pDevice->lock);
if (pDevice->isOwnerOfContext) {
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
ma_device__set_state(pDevice, MA_STATE_STARTING);
/* Asynchronous backends need to be handled differently. */
if (ma_context_is_backend_asynchronous(pDevice->pContext)) {
result = pDevice->pContext->onDeviceStart(pDevice);
if (result == MA_SUCCESS) {
ma_device__set_state(pDevice, MA_STATE_STARTED);
}
} else {
/*
Synchronous backends are started by signaling an event that's being waited on in the worker thread. We first wake up the
thread and then wait for the start event.
*/
ma_event_signal(&pDevice->wakeupEvent);
/*
Wait for the worker thread to finish starting the device. Note that the worker thread will be the one who puts the device
into the started state. Don't call ma_device__set_state() here.
*/
ma_event_wait(&pDevice->startEvent);
result = pDevice->workResult;
}
}
ma_mutex_unlock(&pDevice->lock);
return result;
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
}
result = MA_ERROR;
ma_mutex_lock(&pDevice->lock);
{
/* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a started or paused state. */
MA_ASSERT(ma_device__get_state(pDevice) == MA_STATE_STARTED);
ma_device__set_state(pDevice, MA_STATE_STOPPING);
/* There's no need to wake up the thread like we do when starting. */
if (pDevice->pContext->onDeviceStop) {
result = pDevice->pContext->onDeviceStop(pDevice);
} else {
result = MA_SUCCESS;
}
/* Asynchronous backends need to be handled differently. */
if (ma_context_is_backend_asynchronous(pDevice->pContext)) {
ma_device__set_state(pDevice, MA_STATE_STOPPED);
} else {
/* Synchronous backends. */
/*
We need to wait for the worker thread to become available for work before returning. Note that the worker thread will be
the one who puts the device into the stopped state. Don't call ma_device__set_state() here.
*/
ma_event_wait(&pDevice->stopEvent);
result = MA_SUCCESS;
}
}
ma_mutex_unlock(&pDevice->lock);
return result;
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
}
if (pRevision) {
*pRevision = DRFLAC_VERSION_REVISION;
}
}
DRFLAC_API const char* drflac_version_string(void)
{
return DRFLAC_VERSION_STRING;
}
#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
#define DRFLAC_NO_THREAD_SANITIZE __attribute__((no_sanitize("thread")))
#else
#define DRFLAC_NO_THREAD_SANITIZE
#endif
#else
#define DRFLAC_NO_THREAD_SANITIZE
#endif
#if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE;
#endif
#ifndef DRFLAC_NO_CPUID
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
- Fix an error where the WAV codec is incorrectly excluded from the build depending on which compile time options are set.
- Fix a bug in ma_audio_buffer_read_pcm_frames() where it isn't returning the correct number of frames processed.
- Fix compilation error on Android.
- Core Audio: Fix a bug with full-duplex mode.
- Add ma_decoder_get_cursor_in_pcm_frames().
- Update WAV codec.
v0.10.16 - 2020-08-14
- WASAPI: Fix a potential crash due to using an uninitialized variable.
- OpenSL: Enable runtime linking.
- OpenSL: Fix a multithreading bug when initializing and uninitializing multiple contexts at the same time.
- iOS: Improvements to device enumeration.
- Fix a crash in ma_data_source_read_pcm_frames() when the output frame count parameter is NULL.
- Fix a bug in ma_data_source_read_pcm_frames() where looping doesn't work.
- Fix some compilation warnings on Windows when both DirectSound and WinMM are disabled.
- Fix some compilation warnings when no decoders are enabled.
- Add ma_audio_buffer_get_available_frames().
- Add ma_decoder_get_available_frames().
- Add sample rate to ma_data_source_get_data_format().
- Change volume APIs to take 64-bit frame counts.
- Updates to documentation.
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
- Mark some APIs as deprecated:
- mal_src_set_input_sample_rate() and mal_src_set_output_sample_rate() are replaced with mal_src_set_sample_rate().
- mal_dsp_set_input_sample_rate() and mal_dsp_set_output_sample_rate() are replaced with mal_dsp_set_sample_rate().
- Fix a bug when capturing using the WASAPI backend.
- Fix some aliasing issues with resampling, specifically when increasing the sample rate.
- Fix warnings.
v0.8.3 - 2018-07-15
- Fix a crackling bug when resampling in capture mode.
- Core Audio: Fix a bug where capture does not work.
- ALSA: Fix a bug where the worker thread can get stuck in an infinite loop.
- PulseAudio: Fix a bug where mal_context_init() succeeds when PulseAudio is unusable.
- JACK: Fix a bug where mal_context_init() succeeds when JACK is unusable.
v0.8.2 - 2018-07-07
- Fix a bug on macOS with Core Audio where the internal callback is not called.
v0.8.1 - 2018-07-06
- Fix compilation errors and warnings.
v0.8 - 2018-07-05
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
is extremely common), it's better to just use PulseAudio directly rather than going through the
"pulse" ALSA plugin (which is what the "default" ALSA device is likely set to).
- Add support for JACK.
- Remove dependency on asound.h for the ALSA backend. This means the ALSA development packages are no
longer required to build miniaudio.
- Remove dependency on dsound.h for the DirectSound backend. This fixes build issues with some
distributions of MinGW.
- Remove dependency on audioclient.h for the WASAPI backend. This fixes build issues with some
distributions of MinGW.
- Add support for dithering to format conversion.
- Add support for configuring the priority of the worker thread.
- Add a sine wave generator.
- Improve efficiency of sample rate conversion.
- Introduce the notion of standard channel maps. Use mal_get_standard_channel_map().
- Introduce the notion of default device configurations. A default config uses the same configuration
as the backend's internal device, and as such results in a pass-through data transmission pipeline.
- Add support for passing in NULL for the device config in mal_device_init(), which uses a default
config. This requires manually calling mal_device_set_send/recv_callback().
- Add support for decoding from raw PCM data (mal_decoder_init_raw(), etc.)
- Make mal_device_init_ex() more robust.
- Make some APIs more const-correct.
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
v0.6a - 2018-01-26
- Fix errors with channel mixing when increasing the channel count.
- Improvements to the build system for the OpenAL backend.
- Documentation fixes.
v0.6 - 2017-12-08
- API CHANGE: Expose and improve mutex APIs. If you were using the mutex APIs before this version you'll
need to update.
- API CHANGE: SRC and DSP callbacks now take a pointer to a mal_src and mal_dsp object respectively.
- API CHANGE: Improvements to event and thread APIs. These changes make these APIs more consistent.
- Add support for SDL and Emscripten.
- Simplify the build system further for when development packages for various backends are not installed.
With this change, when the compiler supports __has_include, backends without the relevant development
packages installed will be ignored. This fixes the build for old versions of MinGW.
- Fixes to the Android build.
- Add mal_convert_frames(). This is a high-level helper API for performing a one-time, bulk conversion of
audio data to a different format.
- Improvements to f32 -> u8/s16/s24/s32 conversion routines.
- Fix a bug where the wrong value is returned from mal_device_start() for the OpenSL backend.
- Fixes and improvements for Raspberry Pi.
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
v0.4 - 2017-11-05
- API CHANGE: The log callback is now per-context rather than per-device and as is thus now passed to
mal_context_init(). The rationale for this change is that it allows applications to capture diagnostic
messages at the context level. Previously this was only available at the device level.
- API CHANGE: The device config passed to mal_device_init() is now const.
- Added support for OSS which enables support on BSD platforms.
- Added support for WinMM (waveOut/waveIn).
- Added support for UWP (Universal Windows Platform) applications. Currently C++ only.
- Added support for exclusive mode for selected backends. Currently supported on WASAPI.
- POSIX builds no longer require explicit linking to libpthread (-lpthread).
- ALSA: Explicit linking to libasound (-lasound) is no longer required.
- ALSA: Latency improvements.
- ALSA: Use MMAP mode where available. This can be disabled with the alsa.noMMap config.
- ALSA: Use "hw" devices instead of "plughw" devices by default. This can be disabled with the
alsa.preferPlugHW config.
- WASAPI is now the highest priority backend on Windows platforms.
- Fixed an error with sample rate conversion which was causing crackling when capturing.
- Improved error handling.
- Improved compiler support.
- Miscellaneous bug fixes.
share/public_html/static/music_worklet_inprogress/decoder/bin/_mhfscl.js view on Meta::CPAN
var Module = (() => {
var _scriptName = import.meta.url;
return (
async function(moduleArg = {}) {
var moduleRtn;
var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;var readyPromise=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof im...
return moduleRtn;
}
);
})();
export default Module;
share/public_html/static/music_worklet_inprogress/decoder/deps/dr_libs/dr_flac.h view on Meta::CPAN
be used if available. Otherwise the seek will be performed using brute force.
#define DR_FLAC_NO_SIMD
Disables SIMD optimizations (SSE on x86/x64 architectures, NEON on ARM architectures). Use this if you are having compatibility issues with your compiler.
Notes
=====
- dr_flac does not support changing the sample rate nor channel count mid stream.
- dr_flac is not thread-safe, but its APIs can be called from any thread so long as you do your own synchronization.
- When using Ogg encapsulation, a corrupted metadata block will result in `drflac_open_with_metadata()` and `drflac_open()` returning inconsistent samples due
to differences in corrupted stream recorvery logic between the two APIs.
*/
#ifndef dr_flac_h
#define dr_flac_h
#ifdef __cplusplus
extern "C" {
#endif
share/public_html/static/music_worklet_inprogress/decoder/deps/dr_libs/dr_flac.h view on Meta::CPAN
}
DRFLAC_API const char* drflac_version_string(void)
{
return DRFLAC_VERSION_STRING;
}
/* CPU caps. */
#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
#define DRFLAC_NO_THREAD_SANITIZE __attribute__((no_sanitize("thread")))
#else
#define DRFLAC_NO_THREAD_SANITIZE
#endif
#else
#define DRFLAC_NO_THREAD_SANITIZE
#endif
#if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE;
#endif
share/public_html/static/music_worklet_inprogress/decoder/deps/dr_libs/dr_flac.h view on Meta::CPAN
*ppFile = _wfopen(pFilePath, pOpenMode);
if (*ppFile == NULL) {
return drflac_result_from_errno(errno);
}
#endif
(void)pAllocationCallbacks;
}
#else
/*
Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can
think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility.
*/
{
mbstate_t mbs;
size_t lenMB;
const wchar_t* pFilePathTemp = pFilePath;
char* pFilePathMB = NULL;
char pOpenModeMB[32] = {0};
/* Get the length first. */
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
parameter, but is instead set to the `pUserData` member of `ma_device` which you can access
directly since all miniaudio structures are transparent.
Initializing the device is done with `ma_device_init()`. This will return a result code telling you
what went wrong, if anything. On success it will return `MA_SUCCESS`. After initialization is
complete the device will be in a stopped state. To start it, use `ma_device_start()`.
Uninitializing the device will stop it, which is what the example above does, but you can also stop
the device with `ma_device_stop()`. To resume the device simply call `ma_device_start()` again.
Note that it's important to never stop or start the device from inside the callback. This will
result in a deadlock. Instead you set a variable or signal an event indicating that the device
needs to stop and handle it in a different thread. The following APIs must never be called inside
the callback:
```c
ma_device_init()
ma_device_init_ex()
ma_device_uninit()
ma_device_start()
ma_device_stop()
```
You must never try uninitializing and reinitializing a device inside the callback. You must also
never try to stop and start it from inside the callback. There are a few other things you shouldn't
do in the callback depending on your requirements, however this isn't so much a thread-safety
thing, but rather a real-time processing thing which is beyond the scope of this introduction.
The example above demonstrates the initialization of a playback device, but it works exactly the
same for capture. All you need to do is change the device type from `ma_device_type_playback` to
`ma_device_type_capture` when setting up the config, like so:
```c
ma_device_config config = ma_device_config_init(ma_device_type_capture);
config.capture.format = MY_FORMAT;
config.capture.channels = MY_CHANNEL_COUNT;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_sound_set_start_time_in_pcm_frames(&sound, ma_engine_get_time(&engine) + (ma_engine_get_sample_rate(&engine) * 2);
ma_sound_start(&sound);
```
The third parameter of `ma_sound_init_from_file()` is a set of flags that control how the sound be
loaded and a few options on which features should be enabled for that sound. By default, the sound
is synchronously loaded fully into memory straight from the file system without any kind of
decoding. If you want to decode the sound before storing it in memory, you need to specify the
`MA_SOUND_FLAG_DECODE` flag. This is useful if you want to incur the cost of decoding at an earlier
stage, such as a loading stage. Without this option, decoding will happen dynamically at mixing
time which might be too expensive on the audio thread.
If you want to load the sound asynchronously, you can specify the `MA_SOUND_FLAG_ASYNC` flag. This
will result in `ma_sound_init_from_file()` returning quickly, but the sound will not start playing
until the sound has had some audio decoded.
The fourth parameter is a pointer to sound group. A sound group is used as a mechanism to organise
sounds into groups which have their own effect processing and volume control. An example is a game
which might have separate groups for sfx, voice and music. Each of these groups have their own
independent volume control. Use `ma_sound_group_init()` or `ma_sound_group_init_ex()` to initialize
a sound group.
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
The UWP build may require linking to mmdevapi.lib if you get errors about an unresolved external
symbol for `ActivateAudioInterfaceAsync()`.
2.2. macOS and iOS
------------------
The macOS build should compile cleanly without the need to download any dependencies nor link to
any libraries or frameworks. The iOS build needs to be compiled as Objective-C and will need to
link the relevant frameworks but should compile cleanly out of the box with Xcode. Compiling
through the command line requires linking to `-lpthread` and `-lm`.
Due to the way miniaudio links to frameworks at runtime, your application may not pass Apple's
notarization process. To fix this there are two options. The first is to use the
`MA_NO_RUNTIME_LINKING` option, like so:
```c
#ifdef __APPLE__
#define MA_NO_RUNTIME_LINKING
#endif
#define MINIAUDIO_IMPLEMENTATION
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
```
See this discussion for more info: https://github.com/mackron/miniaudio/issues/203.
2.3. Linux
----------
The Linux build only requires linking to `-ldl`, `-lpthread` and `-lm`. You do not need any
development packages. You may need to link with `-latomic` if you're compiling for 32-bit ARM.
2.4. BSD
--------
The BSD build only requires linking to `-lpthread` and `-lm`. NetBSD uses audio(4), OpenBSD uses
sndio and FreeBSD uses OSS. You may need to link with `-latomic` if you're compiling for 32-bit
ARM.
2.5. Android
------------
AAudio is the highest priority backend on Android. This should work out of the box without needing
any kind of compiler configuration. Support for AAudio starts with Android 8 which means older
versions will fall back to OpenSL|ES which requires API level 16+.
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
| MA_NO_WAV | Disables the built-in WAV decoder and encoder. |
+----------------------------------+--------------------------------------------------------------------+
| MA_NO_FLAC | Disables the built-in FLAC decoder. |
+----------------------------------+--------------------------------------------------------------------+
| MA_NO_MP3 | Disables the built-in MP3 decoder. |
+----------------------------------+--------------------------------------------------------------------+
| MA_NO_DEVICE_IO | Disables playback and recording. This will disable `ma_context` |
| | and `ma_device` APIs. This is useful if you only want to use |
| | miniaudio's data conversion and/or decoding APIs. |
+----------------------------------+--------------------------------------------------------------------+
| MA_NO_THREADING | Disables the `ma_thread`, `ma_mutex`, `ma_semaphore` and |
| | `ma_event` APIs. This option is useful if you only need to use |
| | miniaudio for data conversion, decoding and/or encoding. Some |
| | families of APIsrequire threading which means the following |
| | options must also be set: |
| | |
| | ``` |
| | MA_NO_DEVICE_IO |
| | ``` |
+----------------------------------+--------------------------------------------------------------------+
| MA_NO_GENERATION | Disables generation APIs such a `ma_waveform` and `ma_noise`. |
+----------------------------------+--------------------------------------------------------------------+
| MA_NO_SSE2 | Disables SSE2 optimizations. |
+----------------------------------+--------------------------------------------------------------------+
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
gaps.
Note that the `loop` parameter is set to false in the example above. When this is set to true, only
the current data source will be looped. You can loop the entire chain by linking in a loop like so:
```c
ma_data_source_set_next(&decoder1, &decoder2); // decoder1 -> decoder2
ma_data_source_set_next(&decoder2, &decoder1); // decoder2 -> decoder1 (loop back to the start).
```
Note that setting up chaining is not thread safe, so care needs to be taken if you're dynamically
changing links while the audio thread is in the middle of reading.
Do not use `ma_decoder_seek_to_pcm_frame()` as a means to reuse a data source to play multiple
instances of the same sound simultaneously. Instead, initialize multiple data sources for each
instance. This can be extremely inefficient depending on the data source and can result in
glitching due to subtle changes to the state of internal filters.
4.1. Custom Data Sources
------------------------
You can implement a custom data source by implementing the functions in `ma_data_source_vtable`.
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
In the example above, the sound is being initialized without a file nor a data source. This is
valid, in which case the sound acts as a node in the middle of the node graph. This means you can
connect other sounds to this sound and allow it to act like a sound group. Indeed, this is exactly
what a `ma_sound_group` is.
When loading a sound, you specify a set of flags that control how the sound is loaded and what
features are enabled for that sound. When no flags are set, the sound will be fully loaded into
memory in exactly the same format as how it's stored on the file system. The resource manager will
allocate a block of memory and then load the file directly into it. When reading audio data, it
will be decoded dynamically on the fly. In order to save processing time on the audio thread, it
might be beneficial to pre-decode the sound. You can do this with the `MA_SOUND_FLAG_DECODE` flag:
```c
ma_sound_init_from_file(&engine, "my_sound.wav", MA_SOUND_FLAG_DECODE, pGroup, NULL, &sound);
```
By default, sounds will be loaded synchronously, meaning `ma_sound_init_*()` will not return until
the sound has been fully loaded. If this is prohibitive you can instead load sounds asynchronously
by specificying the `MA_SOUND_FLAG_ASYNC` flag:
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
resourceManagerConfig.ppCustomDecodingBackendVTables = pCustomBackendVTables;
resourceManagerConfig.customDecodingBackendCount = sizeof(pCustomBackendVTables) / sizeof(pCustomBackendVTables[0]);
resourceManagerConfig.pCustomDecodingBackendUserData = NULL;
```
This system can allow you to support any kind of file format. See the "Decoding" section for
details on how to implement custom decoders. The miniaudio repository includes examples for Opus
via libopus and libopusfile and Vorbis via libvorbis and libvorbisfile.
Asynchronicity is achieved via a job system. When an operation needs to be performed, such as the
decoding of a page, a job will be posted to a queue which will then be processed by a job thread.
By default there will be only one job thread running, but this can be configured, like so:
```c
config = ma_resource_manager_config_init();
config.jobThreadCount = MY_JOB_THREAD_COUNT;
```
By default job threads are managed internally by the resource manager, however you can also self
manage your job threads if, for example, you want to integrate the job processing into your
existing job infrastructure, or if you simply don't like the way the resource manager does it. To
do this, just set the job thread count to 0 and process jobs manually. To process jobs, you first
need to retrieve a job using `ma_resource_manager_next_job()` and then process it using
`ma_job_process()`:
```c
config = ma_resource_manager_config_init();
config.jobThreadCount = 0; // Don't manage any job threads internally.
config.flags = MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING; // Optional. Makes `ma_resource_manager_next_job()` non-blocking.
// ... Initialize your custom job threads ...
void my_custom_job_thread(...)
{
for (;;) {
ma_job job;
ma_result result = ma_resource_manager_next_job(pMyResourceManager, &job);
if (result != MA_SUCCESS) {
if (result == MA_NOT_DATA_AVAILABLE) {
// No jobs are available. Keep going. Will only get this if the resource manager was initialized
// with MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING.
continue;
} else if (result == MA_CANCELLED) {
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
break;
}
}
ma_job_process(&job);
}
}
```
In the example above, the `MA_JOB_TYPE_QUIT` event is the used as the termination
indicator, but you can use whatever you would like to terminate the thread. The call to
`ma_resource_manager_next_job()` is blocking by default, but can be configured to be non-blocking
by initializing the resource manager with the `MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING` configuration
flag. Note that the `MA_JOB_TYPE_QUIT` will never be removed from the job queue. This
is to give every thread the opportunity to catch the event and terminate naturally.
When loading a file, it's sometimes convenient to be able to customize how files are opened and
read instead of using standard `fopen()`, `fclose()`, etc. which is what miniaudio will use by
default. This can be done by setting `pVFS` member of the resource manager's config:
```c
// Initialize your custom VFS object. See documentation for VFS for information on how to do this.
my_custom_vfs vfs = my_custom_vfs_init();
config = ma_resource_manager_config_init();
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
can instead load the sound asynchronously using the `MA_RESOURCE_MANAGER_DATA_SOURCE_ASYNC` flag.
This will result in `ma_resource_manager_data_source_init()` returning quickly, but no data will be
returned by `ma_data_source_read_pcm_frames()` until some data is available. When no data is
available because the asynchronous decoding hasn't caught up, `MA_BUSY` will be returned by
`ma_data_source_read_pcm_frames()`.
For large sounds, it's often prohibitive to store the entire file in memory. To mitigate this, you
can instead stream audio data which you can do by specifying the
`MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag. When streaming, data will be decoded in 1
second pages. When a new page needs to be decoded, a job will be posted to the job queue and then
subsequently processed in a job thread.
For in-memory sounds, reference counting is used to ensure the data is loaded only once. This means
multiple calls to `ma_resource_manager_data_source_init()` with the same file path will result in
the file data only being loaded once. Each call to `ma_resource_manager_data_source_init()` must be
matched up with a call to `ma_resource_manager_data_source_uninit()`. Sometimes it can be useful
for a program to register self-managed raw audio data and associate it with a file path. Use the
`ma_resource_manager_register_*()` and `ma_resource_manager_unregister_*()` APIs to do this.
`ma_resource_manager_register_decoded_data()` is used to associate a pointer to raw, self-managed
decoded audio data in the specified data format with the specified name. Likewise,
`ma_resource_manager_register_encoded_data()` is used to associate a pointer to raw self-managed
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
* By streaming audio data on the fly (referred to as a data stream)
A resource managed data source (`ma_resource_manager_data_source`) encapsulates a data buffer or
data stream, depending on whether or not the data source was initialized with the
`MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag. If so, it will make use of a
`ma_resource_manager_data_stream` object. Otherwise it will use a `ma_resource_manager_data_buffer`
object. Both of these objects are data sources which means they can be used with any
`ma_data_source_*()` API.
Another major feature of the resource manager is the ability to asynchronously decode audio files.
This relieves the audio thread of time-consuming decoding which can negatively affect scalability
due to the audio thread needing to complete it's work extremely quickly to avoid glitching.
Asynchronous decoding is achieved through a job system. There is a central multi-producer,
multi-consumer, fixed-capacity job queue. When some asynchronous work needs to be done, a job is
posted to the queue which is then read by a job thread. The number of job threads can be
configured for improved scalability, and job threads can all run in parallel without needing to
worry about the order of execution (how this is achieved is explained below).
When a sound is being loaded asynchronously, playback can begin before the sound has been fully
decoded. This enables the application to start playback of the sound quickly, while at the same
time allowing to resource manager to keep loading in the background. Since there may be less
threads than the number of sounds being loaded at a given time, a simple scheduling system is used
to keep decoding time balanced and fair. The resource manager solves this by splitting decoding
into chunks called pages. By default, each page is 1 second long. When a page has been decoded, a
new job will be posted to start decoding the next page. By dividing up decoding into pages, an
individual sound shouldn't ever delay every other sound from having their first page decoded. Of
course, when loading many sounds at the same time, there will always be an amount of time required
to process jobs in the queue so in heavy load situations there will still be some delay. To
determine if a data source is ready to have some frames read, use
`ma_resource_manager_data_source_get_available_frames()`. This will return the number of frames
available starting from the current position.
6.2.1. Job Queue
----------------
The resource manager uses a job queue which is multi-producer, multi-consumer, and fixed-capacity.
This job queue is not currently lock-free, and instead uses a spinlock to achieve thread-safety.
Only a fixed number of jobs can be allocated and inserted into the queue which is done through a
lock-free data structure for allocating an index into a fixed sized array, with reference counting
for mitigation of the ABA problem. The reference count is 32-bit.
For many types of jobs it's important that they execute in a specific order. In these cases, jobs
are executed serially. For the resource manager, serial execution of jobs is only required on a
per-object basis (per data buffer or per data stream). Each of these objects stores an execution
counter. When a job is posted it is associated with an execution counter. When the job is
processed, it checks if the execution counter of the job equals the execution counter of the
owning object and if so, processes the job. If the counters are not equal, the job will be posted
back onto the job queue for later processing. When the job finishes processing the execution order
of the main object is incremented. This system means the no matter how many job threads are
executing, decoding of an individual sound will always get processed serially. The advantage to
having multiple threads comes into play when loading multiple sounds at the same time.
The resource manager's job queue is not 100% lock-free and will use a spinlock to achieve
thread-safety for a very small section of code. This is only relevant when the resource manager
uses more than one job thread. If only using a single job thread, which is the default, the
lock should never actually wait in practice. The amount of time spent locking should be quite
short, but it's something to be aware of for those who have pedantic lock-free requirements and
need to use more than one job thread. There are plans to remove this lock in a future version.
In addition, posting a job will release a semaphore, which on Win32 is implemented with
`ReleaseSemaphore` and on POSIX platforms via a condition variable:
```c
pthread_mutex_lock(&pSemaphore->lock);
{
pSemaphore->value += 1;
pthread_cond_signal(&pSemaphore->cond);
}
pthread_mutex_unlock(&pSemaphore->lock);
```
Again, this is relevant for those with strict lock-free requirements in the audio thread. To avoid
this, you can use non-blocking mode (via the `MA_JOB_QUEUE_FLAG_NON_BLOCKING`
flag) and implement your own job processing routine (see the "Resource Manager" section above for
details on how to do this).
6.2.2. Data Buffers
-------------------
When the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag is excluded at initialization time, the
resource manager will try to load the data into an in-memory data buffer. Before doing so, however,
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
A binary search tree (BST) is used for storing data buffers as it has good balance between
efficiency and simplicity. The key of the BST is a 64-bit hash of the file path that was passed
into `ma_resource_manager_data_source_init()`. The advantage of using a hash is that it saves
memory over storing the entire path, has faster comparisons, and results in a mostly balanced BST
due to the random nature of the hash. The disadvantage is that file names are case-sensitive. If
this is an issue, you should normalize your file names to upper- or lower-case before initializing
your data sources.
When a sound file has not already been loaded and the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC`
flag is excluded, the file will be decoded synchronously by the calling thread. There are two
options for controlling how the audio is stored in the data buffer - encoded or decoded. When the
`MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE` option is excluded, the raw file data will be stored
in memory. Otherwise the sound will be decoded before storing it in memory. Synchronous loading is
a very simple and standard process of simply adding an item to the BST, allocating a block of
memory and then decoding (if `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE` is specified).
When the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC` flag is specified, loading of the data buffer
is done asynchronously. In this case, a job is posted to the queue to start loading and then the
function immediately returns, setting an internal result code to `MA_BUSY`. This result code is
returned when the program calls `ma_resource_manager_data_source_result()`. When decoding has fully
completed `MA_SUCCESS` will be returned. This can be used to know if loading has fully completed.
When loading asynchronously, a single job is posted to the queue of the type
`MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE`. This involves making a copy of the file path and
associating it with job. When the job is processed by the job thread, it will first load the file
using the VFS associated with the resource manager. When using a custom VFS, it's important that it
be completely thread-safe because it will be used from one or more job threads at the same time.
Individual files should only ever be accessed by one thread at a time, however. After opening the
file via the VFS, the job will determine whether or not the file is being decoded. If not, it
simply allocates a block of memory and loads the raw file contents into it and returns. On the
other hand, when the file is being decoded, it will first allocate a decoder on the heap and
initialize it. Then it will check if the length of the file is known. If so it will allocate a
block of memory to store the decoded output and initialize it to silence. If the size is unknown,
it will allocate room for one page. After memory has been allocated, the first page will be
decoded. If the sound is shorter than a page, the result code will be set to `MA_SUCCESS` and the
completion event will be signalled and loading is now complete. If, however, there is more to
decode, a job with the code `MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE` is posted. This job
will decode the next page and perform the same process if it reaches the end. If there is more to
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
it will return immediately.
When frames are read from a data stream using `ma_resource_manager_data_source_read_pcm_frames()`,
`MA_BUSY` will be returned if there are no frames available. If there are some frames available,
but less than the number requested, `MA_SUCCESS` will be returned, but the actual number of frames
read will be less than the number requested. Due to the asynchronous nature of data streams,
seeking is also asynchronous. If the data stream is in the middle of a seek, `MA_BUSY` will be
returned when trying to read frames.
When `ma_resource_manager_data_source_read_pcm_frames()` results in a page getting fully consumed
a job is posted to load the next page. This will be posted from the same thread that called
`ma_resource_manager_data_source_read_pcm_frames()`.
Data streams are uninitialized by posting a job to the queue, but the function won't return until
that job has been processed. The reason for this is that the caller owns the data stream object and
therefore miniaudio needs to ensure everything completes before handing back control to the caller.
Also, if the data stream is uninitialized while pages are in the middle of decoding, they must
complete before destroying any underlying object and the job system handles this cleanly.
Note that when a new page needs to be loaded, a job will be posted to the resource manager's job
thread from the audio thread. You must keep in mind the details mentioned in the "Job Queue"
section above regarding locking when posting an event if you require a strictly lock-free audio
thread.
7. Node Graph
=============
miniaudio's routing infrastructure follows a node graph paradigm. The idea is that you create a
node whose outputs are attached to inputs of another node, thereby creating a graph. There are
different types of nodes, with each node in the graph processing input data to produce output,
which is then fed through the chain. Each node in the graph can apply their own custom effects. At
the start of the graph will usually be one or more data source nodes which have no inputs, but
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
Each input bus must be configured to accept the same number of channels, but the number of channels
used by input buses can be different to the number of channels for output buses in which case
miniaudio will automatically convert the input data to the output channel count before processing.
The number of channels of an output bus of one node must match the channel count of the input bus
it's attached to. The channel counts cannot be changed after the node has been initialized. If you
attempt to attach an output bus to an input bus with a different channel count, attachment will
fail.
To use a node graph, you first need to initialize a `ma_node_graph` object. This is essentially a
container around the entire graph. The `ma_node_graph` object is required for some thread-safety
issues which will be explained later. A `ma_node_graph` object is initialized using miniaudio's
standard config/init system:
```c
ma_node_graph_config nodeGraphConfig = ma_node_graph_config_init(myChannelCount);
result = ma_node_graph_init(&nodeGraphConfig, NULL, &nodeGraph); // Second parameter is a pointer to allocation callbacks.
if (result != MA_SUCCESS) {
// Failed to initialize node graph.
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
A local clock is per-node, whereas the global clock is per graph. Scheduling starts and stops can
only be done based on the global clock because the local clock will not be running while the node
is stopped. The global clocks advances whenever `ma_node_graph_read_pcm_frames()` is called. On the
other hand, the local clock only advances when the node's processing callback is fired, and is
advanced based on the output frame count.
To retrieve the global time, use `ma_node_graph_get_time()`. The global time can be set with
`ma_node_graph_set_time()` which might be useful if you want to do seeking on a global timeline.
Getting and setting the local time is similar. Use `ma_node_get_time()` to retrieve the local time,
and `ma_node_set_time()` to set the local time. The global and local times will be advanced by the
audio thread, so care should be taken to avoid data races. Ideally you should avoid calling these
outside of the node processing callbacks which are always run on the audio thread.
There is basic support for scheduling the starting and stopping of nodes. You can only schedule one
start and one stop at a time. This is mainly intended for putting nodes into a started or stopped
state in a frame-exact manner. Without this mechanism, starting and stopping of a node is limited
to the resolution of a call to `ma_node_graph_read_pcm_frames()` which would typically be in blocks
of several milliseconds. The following APIs can be used for scheduling node states:
```c
ma_node_set_state_time()
ma_node_get_state_time()
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_node_set_state_time(&myNode, ma_node_state_stopped, sampleRate*5); // Delay stopping to 5 seconds.
```
An example for changing the state using a relative time.
```c
ma_node_set_state_time(&myNode, ma_node_state_started, sampleRate*1 + ma_node_graph_get_time(&myNodeGraph));
ma_node_set_state_time(&myNode, ma_node_state_stopped, sampleRate*5 + ma_node_graph_get_time(&myNodeGraph));
```
Note that due to the nature of multi-threading the times may not be 100% exact. If this is an
issue, consider scheduling state changes from within a processing callback. An idea might be to
have some kind of passthrough trigger node that is used specifically for tracking time and handling
events.
7.2. Thread Safety and Locking
------------------------------
When processing audio, it's ideal not to have any kind of locking in the audio thread. Since it's
expected that `ma_node_graph_read_pcm_frames()` would be run on the audio thread, it does so
without the use of any locks. This section discusses the implementation used by miniaudio and goes
over some of the compromises employed by miniaudio to achieve this goal. Note that the current
implementation may not be ideal - feedback and critiques are most welcome.
The node graph API is not *entirely* lock-free. Only `ma_node_graph_read_pcm_frames()` is expected
to be lock-free. Attachment, detachment and uninitialization of nodes use locks to simplify the
implementation, but are crafted in a way such that such locking is not required when reading audio
data from the graph. Locking in these areas are achieved by means of spinlocks.
The main complication with keeping `ma_node_graph_read_pcm_frames()` lock-free stems from the fact
that a node can be uninitialized, and it's memory potentially freed, while in the middle of being
processed on the audio thread. There are times when the audio thread will be referencing a node,
which means the uninitialization process of a node needs to make sure it delays returning until the
audio thread is finished so that control is not handed back to the caller thereby giving them a
chance to free the node's memory.
When the audio thread is processing a node, it does so by reading from each of the output buses of
the node. In order for a node to process data for one of it's output buses, it needs to read from
each of it's input buses, and so on an so forth. It follows that once all output buses of a node
are detached, the node as a whole will be disconnected and no further processing will occur unless
it's output buses are reattached, which won't be happening when the node is being uninitialized.
By having `ma_node_detach_output_bus()` wait until the audio thread is finished with it, we can
simplify a few things, at the expense of making `ma_node_detach_output_bus()` a bit slower. By
doing this, the implementation of `ma_node_uninit()` becomes trivial - just detach all output
nodes, followed by each of the attachments to each of it's input nodes, and then do any final clean
up.
With the above design, the worst-case scenario is `ma_node_detach_output_bus()` taking as long as
it takes to process the output bus being detached. This will happen if it's called at just the
wrong moment where the audio thread has just iterated it and has just started processing. The
caller of `ma_node_detach_output_bus()` will stall until the audio thread is finished, which
includes the cost of recursively processing it's inputs. This is the biggest compromise made with
the approach taken by miniaudio for it's lock-free processing system. The cost of detaching nodes
earlier in the pipeline (data sources, for example) will be cheaper than the cost of detaching
higher level nodes, such as some kind of final post-processing endpoint. If you need to do mass
detachments, detach starting from the lowest level nodes and work your way towards the final
endpoint node (but don't try detaching the node graph's endpoint). If the audio thread is not
running, detachment will be fast and detachment in any order will be the same. The reason nodes
need to wait for their input attachments to complete is due to the potential for desyncs between
data sources. If the node was to terminate processing mid way through processing it's inputs,
there's a chance that some of the underlying data sources will have been read, but then others not.
That will then result in a potential desynchronization when detaching and reattaching higher-level
nodes. A possible solution to this is to have an option when detaching to terminate processing
before processing all input attachments which should be fairly simple.
Another compromise, albeit less significant, is locking when attaching and detaching nodes. This
locking is achieved by means of a spinlock in order to reduce memory overhead. A lock is present
for each input bus and output bus. When an output bus is connected to an input bus, both the output
bus and input bus is locked. This locking is specifically for attaching and detaching across
different threads and does not affect `ma_node_graph_read_pcm_frames()` in any way. The locking and
unlocking is mostly self-explanatory, but a slightly less intuitive aspect comes into it when
considering that iterating over attachments must not break as a result of attaching or detaching a
node while iteration is occuring.
Attaching and detaching are both quite simple. When an output bus of a node is attached to an input
bus of another node, it's added to a linked list. Basically, an input bus is a linked list, where
each item in the list is and output bus. We have some intentional (and convenient) restrictions on
what can done with the linked list in order to simplify the implementation. First of all, whenever
something needs to iterate over the list, it must do so in a forward direction. Backwards iteration
is not supported. Also, items can only be added to the start of the list.
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
buffer and then "commit" it with `ma_pcm_rb_commit_read()` or `ma_pcm_rb_commit_write()`. This is
where the read/write pointers are updated. When you commit you need to pass in the buffer that was
returned by the earlier call to `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()` and is
only used for validation. The number of frames passed to `ma_pcm_rb_commit_read()` and
`ma_pcm_rb_commit_write()` is what's used to increment the pointers, and can be less that what was
originally requested.
If you want to correct for drift between the write pointer and the read pointer you can use a
combination of `ma_pcm_rb_pointer_distance()`, `ma_pcm_rb_seek_read()` and
`ma_pcm_rb_seek_write()`. Note that you can only move the pointers forward, and you should only
move the read pointer forward via the consumer thread, and the write pointer forward by the
producer thread. If there is too much space between the pointers, move the read pointer forward. If
there is too little space between the pointers, move the write pointer forward.
You can use a ring buffer at the byte level instead of the PCM frame level by using the `ma_rb`
API. This is exactly the same, only you will use the `ma_rb` functions instead of `ma_pcm_rb` and
instead of frame counts you will pass around byte counts.
The maximum size of the buffer in bytes is `0x7FFFFFFF-(MA_SIMD_ALIGNMENT-1)` due to the most
significant bit being used to encode a loop flag and the internally managed buffers always being
aligned to `MA_SIMD_ALIGNMENT`.
Note that the ring buffer is only thread safe when used by a single consumer thread and single
producer thread.
15. Backends
============
The following backends are supported by miniaudio.
+-------------+-----------------------+--------------------------------------------------------+
| Name | Enum Name | Supported Operating Systems |
+-------------+-----------------------+--------------------------------------------------------+
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
#elif defined(WINAPI_FAMILY) && (defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES)
#define MA_WIN32_GDK
#else
#define MA_WIN32_DESKTOP
#endif
#else
#define MA_POSIX
/*
Use the MA_NO_PTHREAD_IN_HEADER option at your own risk. This is intentionally undocumented.
You can use this to avoid including pthread.h in the header section. The downside is that it
results in some fixed sized structures being declared for the various types that are used in
miniaudio. The risk here is that these types might be too small for a given platform. This
risk is yours to take and no support will be offered if you enable this option.
*/
#ifndef MA_NO_PTHREAD_IN_HEADER
#include <pthread.h> /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */
typedef pthread_t ma_pthread_t;
typedef pthread_mutex_t ma_pthread_mutex_t;
typedef pthread_cond_t ma_pthread_cond_t;
#else
typedef ma_uintptr ma_pthread_t;
typedef union ma_pthread_mutex_t { char __data[40]; ma_uint64 __alignment; } ma_pthread_mutex_t;
typedef union ma_pthread_cond_t { char __data[48]; ma_uint64 __alignment; } ma_pthread_cond_t;
#endif
#ifdef __unix__
#define MA_UNIX
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#define MA_BSD
#endif
#endif
#ifdef __linux__
#define MA_LINUX
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
typedef struct
{
ma_int32 state;
} ma_lcg;
/* Spinlocks are 32-bit for compatibility reasons. */
typedef ma_uint32 ma_spinlock;
#ifndef MA_NO_THREADING
/* Thread priorities should be ordered such that the default priority of the worker thread is 0. */
typedef enum
{
ma_thread_priority_idle = -5,
ma_thread_priority_lowest = -4,
ma_thread_priority_low = -3,
ma_thread_priority_normal = -2,
ma_thread_priority_high = -1,
ma_thread_priority_highest = 0,
ma_thread_priority_realtime = 1,
ma_thread_priority_default = 0
} ma_thread_priority;
#if defined(MA_WIN32)
typedef ma_handle ma_thread;
#endif
#if defined(MA_POSIX)
typedef ma_pthread_t ma_thread;
#endif
#if defined(MA_WIN32)
typedef ma_handle ma_mutex;
#endif
#if defined(MA_POSIX)
typedef ma_pthread_mutex_t ma_mutex;
#endif
#if defined(MA_WIN32)
typedef ma_handle ma_event;
#endif
#if defined(MA_POSIX)
typedef struct
{
ma_uint32 value;
ma_pthread_mutex_t lock;
ma_pthread_cond_t cond;
} ma_event;
#endif /* MA_POSIX */
#if defined(MA_WIN32)
typedef ma_handle ma_semaphore;
#endif
#if defined(MA_POSIX)
typedef struct
{
int value;
ma_pthread_mutex_t lock;
ma_pthread_cond_t cond;
} ma_semaphore;
#endif /* MA_POSIX */
#else
/* MA_NO_THREADING is set which means threading is disabled. Threading is required by some API families. If any of these are enabled we need to throw an error. */
#ifndef MA_NO_DEVICE_IO
#error "MA_NO_THREADING cannot be used without MA_NO_DEVICE_IO";
#endif
#endif /* MA_NO_THREADING */
/*
Retrieves the version of miniaudio as separated integers. Each component can be NULL if it's not required.
*/
MA_API void ma_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* pRevision);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
MA_API ma_log_callback ma_log_callback_init(ma_log_callback_proc onLog, void* pUserData);
typedef struct
{
ma_log_callback callbacks[MA_MAX_LOG_CALLBACKS];
ma_uint32 callbackCount;
ma_allocation_callbacks allocationCallbacks; /* Need to store these persistently because ma_log_postv() might need to allocate a buffer on the heap. */
#ifndef MA_NO_THREADING
ma_mutex lock; /* For thread safety just to make it easier and safer for the logging implementation. */
#endif
} ma_log;
MA_API ma_result ma_log_init(const ma_allocation_callbacks* pAllocationCallbacks, ma_log* pLog);
MA_API void ma_log_uninit(ma_log* pLog);
MA_API ma_result ma_log_register_callback(ma_log* pLog, ma_log_callback callback);
MA_API ma_result ma_log_unregister_callback(ma_log* pLog, ma_log_callback callback);
MA_API ma_result ma_log_post(ma_log* pLog, ma_uint32 level, const char* pMessage);
MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat, va_list args);
MA_API ma_result ma_log_postf(ma_log* pLog, ma_uint32 level, const char* pFormat, ...) MA_ATTRIBUTE_FORMAT(3, 4);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
Signals the specified auto-reset event.
*/
MA_API ma_result ma_event_signal(ma_event* pEvent);
#endif /* MA_NO_THREADING */
/*
Fence
=====
This locks while the counter is larger than 0. Counter can be incremented and decremented by any
thread, but care needs to be taken when waiting. It is possible for one thread to acquire the
fence just as another thread returns from ma_fence_wait().
The idea behind a fence is to allow you to wait for a group of operations to complete. When an
operation starts, the counter is incremented which locks the fence. When the operation completes,
the fence will be released which decrements the counter. ma_fence_wait() will block until the
counter hits zero.
If threading is disabled, ma_fence_wait() will spin on the counter.
*/
typedef struct
{
#ifndef MA_NO_THREADING
ma_event e;
#endif
ma_uint32 counter;
} ma_fence;
MA_API ma_result ma_fence_init(ma_fence* pFence);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_bool32 signalled;
} ma_async_notification_poll;
MA_API ma_result ma_async_notification_poll_init(ma_async_notification_poll* pNotificationPoll);
MA_API ma_bool32 ma_async_notification_poll_is_signalled(const ma_async_notification_poll* pNotificationPoll);
/*
Event Notification
This uses an ma_event. If threading is disabled (MA_NO_THREADING), initialization will fail.
*/
typedef struct
{
ma_async_notification_callbacks cb;
#ifndef MA_NO_THREADING
ma_event e;
#endif
} ma_async_notification_event;
MA_API ma_result ma_async_notification_event_init(ma_async_notification_event* pNotificationEvent);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
struct
{
/*ma_resource_manager_data_buffer**/ void* pDataBuffer;
ma_async_notification* pDoneNotification;
ma_fence* pDoneFence;
} freeDataBuffer;
struct
{
/*ma_resource_manager_data_stream**/ void* pDataStream;
char* pFilePath; /* Allocated when the job is posted, freed by the job thread after loading. */
wchar_t* pFilePathW; /* ^ As above ^. Only used if pFilePath is NULL. */
ma_uint64 initialSeekPoint;
ma_async_notification* pInitNotification; /* Signalled after the first two pages have been decoded and frames can be read from the stream. */
ma_fence* pInitFence;
} loadDataStream;
struct
{
/*ma_resource_manager_data_stream**/ void* pDataStream;
ma_async_notification* pDoneNotification;
ma_fence* pDoneFence;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
};
MA_API ma_job ma_job_init(ma_uint16 code);
MA_API ma_result ma_job_process(ma_job* pJob);
/*
When set, ma_job_queue_next() will not wait and no semaphore will be signaled in
ma_job_queue_post(). ma_job_queue_next() will return MA_NO_DATA_AVAILABLE if nothing is available.
This flag should always be used for platforms that do not support multithreading.
*/
typedef enum
{
MA_JOB_QUEUE_FLAG_NON_BLOCKING = 0x00000001
} ma_job_queue_flags;
typedef struct
{
ma_uint32 flags;
ma_uint32 capacity; /* The maximum number of jobs that can fit in the queue at a time. */
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
#if defined(MA_APPLE)
#define MA_SUPPORT_COREAUDIO
#endif
#if defined(MA_EMSCRIPTEN)
#define MA_SUPPORT_WEBAUDIO
#endif
/* All platforms should support custom backends. */
#define MA_SUPPORT_CUSTOM
/* Explicitly disable the Null backend for Emscripten because it uses a background thread which is not properly supported right now. */
#if !defined(MA_EMSCRIPTEN)
#define MA_SUPPORT_NULL
#endif
#if defined(MA_SUPPORT_WASAPI) && !defined(MA_NO_WASAPI) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_WASAPI))
#define MA_HAS_WASAPI
#endif
#if defined(MA_SUPPORT_DSOUND) && !defined(MA_NO_DSOUND) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_DSOUND))
#define MA_HAS_DSOUND
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_backend_opensl,
ma_backend_webaudio,
ma_backend_custom, /* <-- Custom backend, with callbacks defined by the context config. */
ma_backend_null /* <-- Must always be the last item. Lowest priority, and used as the terminator for backend enumeration. */
} ma_backend;
#define MA_BACKEND_COUNT (ma_backend_null+1)
/*
Device job thread. This is used by backends that require asynchronous processing of certain
operations. It is not used by all backends.
The device job thread is made up of a thread and a job queue. You can post a job to the thread with
ma_device_job_thread_post(). The thread will do the processing of the job.
*/
typedef struct
{
ma_bool32 noThread; /* Set this to true if you want to process jobs yourself. */
ma_uint32 jobQueueCapacity;
ma_uint32 jobQueueFlags;
} ma_device_job_thread_config;
MA_API ma_device_job_thread_config ma_device_job_thread_config_init(void);
typedef struct
{
ma_thread thread;
ma_job_queue jobQueue;
ma_bool32 _hasThread;
} ma_device_job_thread;
MA_API ma_result ma_device_job_thread_init(const ma_device_job_thread_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_device_job_thread* pJobThread);
MA_API void ma_device_job_thread_uninit(ma_device_job_thread* pJobThread, const ma_allocation_callbacks* pAllocationCallbacks);
MA_API ma_result ma_device_job_thread_post(ma_device_job_thread* pJobThread, const ma_job* pJob);
MA_API ma_result ma_device_job_thread_next(ma_device_job_thread* pJobThread, ma_job* pJob);
/* Device notification types. */
typedef enum
{
ma_device_notification_type_started,
ma_device_notification_type_stopped,
ma_device_notification_type_rerouted,
ma_device_notification_type_interruption_began,
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
-------
You cannot stop and start the device from inside the callback or else you'll get a deadlock. You must also not uninitialize the device from inside the
callback. The following APIs cannot be called from inside the callback:
ma_device_init()
ma_device_init_ex()
ma_device_uninit()
ma_device_start()
ma_device_stop()
The proper way to stop the device is to call `ma_device_stop()` from a different thread, normally the main application thread.
*/
typedef void (* ma_device_data_proc)(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
/*
DEPRECATED. Use ma_device_notification_proc instead.
The callback for when the device has been stopped.
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
Starting and stopping of the device is done with `onDeviceStart()` and `onDeviceStop()` and should be self-explanatory. If the backend uses
asynchronous reading and writing, `onDeviceStart()` and `onDeviceStop()` should always be implemented.
The handling of data delivery between the application and the device is the most complicated part of the process. To make this a bit
easier, some helper callbacks are available. If the backend uses a blocking read/write style of API, the `onDeviceRead()` and
`onDeviceWrite()` callbacks can optionally be implemented. These are blocking and work just like reading and writing from a file. If the
backend uses a callback for data delivery, that callback must call `ma_device_handle_backend_data_callback()` from within it's callback.
This allows miniaudio to then process any necessary data conversion and then pass it to the miniaudio data callback.
If the backend requires absolute flexibility with it's data delivery, it can optionally implement the `onDeviceDataLoop()` callback
which will allow it to implement the logic that will run on the audio thread. This is much more advanced and is completely optional.
The audio thread should run data delivery logic in a loop while `ma_device_get_state() == ma_device_state_started` and no errors have been
encounted. Do not start or stop the device here. That will be handled from outside the `onDeviceDataLoop()` callback.
The invocation of the `onDeviceDataLoop()` callback will be handled by miniaudio. When you start the device, miniaudio will fire this
callback. When the device is stopped, the `ma_device_get_state() == ma_device_state_started` condition will fail and the loop will be terminated
which will then fall through to the part that stops the device. For an example on how to implement the `onDeviceDataLoop()` callback,
look at `ma_device_audio_thread__default_read_write()`. Implement the `onDeviceDataLoopWakeup()` callback if you need a mechanism to
wake up the audio thread.
If the backend supports an optimized retrieval of device information from an initialized `ma_device` object, it should implement the
`onDeviceGetInfo()` callback. This is optional, in which case it will fall back to `onContextGetDeviceInfo()` which is less efficient.
*/
struct ma_backend_callbacks
{
ma_result (* onContextInit)(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks);
ma_result (* onContextUninit)(ma_context* pContext);
ma_result (* onContextEnumerateDevices)(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData);
ma_result (* onContextGetDeviceInfo)(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_result (* onDeviceRead)(ma_device* pDevice, void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesRead);
ma_result (* onDeviceWrite)(ma_device* pDevice, const void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten);
ma_result (* onDeviceDataLoop)(ma_device* pDevice);
ma_result (* onDeviceDataLoopWakeup)(ma_device* pDevice);
ma_result (* onDeviceGetInfo)(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo);
};
struct ma_context_config
{
ma_log* pLog;
ma_thread_priority threadPriority;
size_t threadStackSize;
void* pUserData;
ma_allocation_callbacks allocationCallbacks;
struct
{
ma_bool32 useVerboseDeviceEnumeration;
} alsa;
struct
{
const char* pApplicationName;
const char* pServerName;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_bool32 noAudioSessionDeactivate; /* iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:false] on uninitialization. */
} coreaudio;
struct
{
const char* pClientName;
ma_bool32 tryStartServer;
} jack;
ma_backend_callbacks custom;
};
/* WASAPI specific structure for some commands which must run on a common thread due to bugs in WASAPI. */
typedef struct
{
int code;
ma_event* pEvent; /* This will be signalled when the event is complete. */
union
{
struct
{
int _unused;
} quit;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
} releaseAudioClient;
} data;
} ma_context_command__wasapi;
struct ma_context
{
ma_backend_callbacks callbacks;
ma_backend backend; /* DirectSound, ALSA, etc. */
ma_log* pLog;
ma_log log; /* Only used if the log is owned by the context. The pLog member will be set to &log in this case. */
ma_thread_priority threadPriority;
size_t threadStackSize;
void* pUserData;
ma_allocation_callbacks allocationCallbacks;
ma_mutex deviceEnumLock; /* Used to make ma_context_get_devices() thread safe. */
ma_mutex deviceInfoLock; /* Used to make ma_context_get_device_info() thread safe. */
ma_uint32 deviceInfoCapacity; /* Total capacity of pDeviceInfos. */
ma_uint32 playbackDeviceInfoCount;
ma_uint32 captureDeviceInfoCount;
ma_device_info* pDeviceInfos; /* Playback devices first, then capture. */
union
{
#ifdef MA_SUPPORT_WASAPI
struct
{
ma_thread commandThread;
ma_mutex commandLock;
ma_semaphore commandSem;
ma_uint32 commandIndex;
ma_uint32 commandCount;
ma_context_command__wasapi commands[4];
} wasapi;
#endif
#ifdef MA_SUPPORT_DSOUND
struct
{
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
#ifdef MA_SUPPORT_PULSEAUDIO
struct
{
ma_handle pulseSO;
ma_proc pa_mainloop_new;
ma_proc pa_mainloop_free;
ma_proc pa_mainloop_quit;
ma_proc pa_mainloop_get_api;
ma_proc pa_mainloop_iterate;
ma_proc pa_mainloop_wakeup;
ma_proc pa_threaded_mainloop_new;
ma_proc pa_threaded_mainloop_free;
ma_proc pa_threaded_mainloop_start;
ma_proc pa_threaded_mainloop_stop;
ma_proc pa_threaded_mainloop_lock;
ma_proc pa_threaded_mainloop_unlock;
ma_proc pa_threaded_mainloop_wait;
ma_proc pa_threaded_mainloop_signal;
ma_proc pa_threaded_mainloop_accept;
ma_proc pa_threaded_mainloop_get_retval;
ma_proc pa_threaded_mainloop_get_api;
ma_proc pa_threaded_mainloop_in_thread;
ma_proc pa_threaded_mainloop_set_name;
ma_proc pa_context_new;
ma_proc pa_context_unref;
ma_proc pa_context_connect;
ma_proc pa_context_disconnect;
ma_proc pa_context_set_state_callback;
ma_proc pa_context_get_state;
ma_proc pa_context_get_sink_info_list;
ma_proc pa_context_get_source_info_list;
ma_proc pa_context_get_sink_info_by_name;
ma_proc pa_context_get_source_info_by_name;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_proc AAudioStream_getState;
ma_proc AAudioStream_waitForStateChange;
ma_proc AAudioStream_getFormat;
ma_proc AAudioStream_getChannelCount;
ma_proc AAudioStream_getSampleRate;
ma_proc AAudioStream_getBufferCapacityInFrames;
ma_proc AAudioStream_getFramesPerDataCallback;
ma_proc AAudioStream_getFramesPerBurst;
ma_proc AAudioStream_requestStart;
ma_proc AAudioStream_requestStop;
ma_device_job_thread jobThread; /* For processing operations outside of the error callback, specifically device disconnections and rerouting. */
} aaudio;
#endif
#ifdef MA_SUPPORT_OPENSL
struct
{
ma_handle libOpenSLES;
ma_handle SL_IID_ENGINE;
ma_handle SL_IID_AUDIOIODEVICECAPABILITIES;
ma_handle SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
ma_handle SL_IID_RECORD;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
/*HMODULE*/ ma_handle hAdvapi32DLL;
ma_proc RegOpenKeyExA;
ma_proc RegCloseKey;
ma_proc RegQueryValueExA;
} win32;
#endif
#ifdef MA_POSIX
struct
{
ma_handle pthreadSO;
ma_proc pthread_create;
ma_proc pthread_join;
ma_proc pthread_mutex_init;
ma_proc pthread_mutex_destroy;
ma_proc pthread_mutex_lock;
ma_proc pthread_mutex_unlock;
ma_proc pthread_cond_init;
ma_proc pthread_cond_destroy;
ma_proc pthread_cond_wait;
ma_proc pthread_cond_signal;
ma_proc pthread_attr_init;
ma_proc pthread_attr_destroy;
ma_proc pthread_attr_setschedpolicy;
ma_proc pthread_attr_getschedparam;
ma_proc pthread_attr_setschedparam;
} posix;
#endif
int _unused;
};
};
struct ma_device
{
ma_context* pContext;
ma_device_type type;
ma_uint32 sampleRate;
MA_ATOMIC(4, ma_device_state) state; /* The state of the device is variable and can change at any time on any thread. Must be used atomically. */
ma_device_data_proc onData; /* Set once at initialization time and should not be changed after. */
ma_device_notification_proc onNotification; /* Set once at initialization time and should not be changed after. */
ma_stop_proc onStop; /* DEPRECATED. Use the notification callback instead. Set once at initialization time and should not be changed after. */
void* pUserData; /* Application defined data. */
ma_mutex startStopLock;
ma_event wakeupEvent;
ma_event startEvent;
ma_event stopEvent;
ma_thread thread;
ma_result workResult; /* This is set by the worker thread after it's finished doing a job. */
ma_bool8 isOwnerOfContext; /* When set to true, uninitializing the device will also uninitialize the context. Set to true when NULL is passed into ma_device_init(). */
ma_bool8 noPreSilencedOutputBuffer;
ma_bool8 noClip;
ma_bool8 noDisableDenormals;
ma_bool8 noFixedSizedCallback;
MA_ATOMIC(4, float) masterVolumeFactor; /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */
ma_duplex_rb duplexRB; /* Intermediary buffer for duplex device on asynchronous backends. */
struct
{
ma_resample_algorithm algorithm;
ma_resampling_backend_vtable* pBackendVTable;
void* pBackendUserData;
struct
{
ma_uint32 lpfOrder;
} linear;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_uint32 originalPeriods;
ma_performance_profile originalPerformanceProfile;
ma_uint32 periodSizeInFramesPlayback;
ma_uint32 periodSizeInFramesCapture;
void* pMappedBufferCapture;
ma_uint32 mappedBufferCaptureCap;
ma_uint32 mappedBufferCaptureLen;
void* pMappedBufferPlayback;
ma_uint32 mappedBufferPlaybackCap;
ma_uint32 mappedBufferPlaybackLen;
MA_ATOMIC(4, ma_bool32) isStartedCapture; /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */
MA_ATOMIC(4, ma_bool32) isStartedPlayback; /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */
ma_bool8 noAutoConvertSRC; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM. */
ma_bool8 noDefaultQualitySRC; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY. */
ma_bool8 noHardwareOffloading;
ma_bool8 allowCaptureAutoStreamRouting;
ma_bool8 allowPlaybackAutoStreamRouting;
ma_bool8 isDetachedPlayback;
ma_bool8 isDetachedCapture;
} wasapi;
#endif
#ifdef MA_SUPPORT_DSOUND
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
#ifdef MA_SUPPORT_WEBAUDIO
struct
{
int indexPlayback; /* We use a factory on the JavaScript side to manage devices and use an index for JS/C interop. */
int indexCapture;
} webaudio;
#endif
#ifdef MA_SUPPORT_NULL
struct
{
ma_thread deviceThread;
ma_event operationEvent;
ma_event operationCompletionEvent;
ma_semaphore operationSemaphore;
ma_uint32 operation;
ma_result operationResult;
ma_timer timer;
double priorRunTime;
ma_uint32 currentPeriodFramesRemainingPlayback;
ma_uint32 currentPeriodFramesRemainingCapture;
ma_uint64 lastProcessedFramePlayback;
ma_uint64 lastProcessedFrameCapture;
MA_ATOMIC(4, ma_bool32) isStarted; /* Read and written by multiple threads. Must be used atomically, and must be 32-bit for compiler compatibility. */
} null_device;
#endif
};
};
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(pop)
#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))
#pragma GCC diagnostic pop /* For ISO C99 doesn't support unnamed structs/unions [-Wpedantic] */
#endif
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
A pointer to the context object being initialized.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Unsafe. Do not call this function across multiple threads as some backends read and write to global state.
Remarks
-------
When `backends` is NULL, the default priority order will be used. Below is a list of backends in priority order:
|-------------|-----------------------|--------------------------------------------------------|
| Name | Enum Name | Supported Operating Systems |
|-------------|-----------------------|--------------------------------------------------------|
| WASAPI | ma_backend_wasapi | Windows Vista+ |
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
| Null | ma_backend_null | Cross Platform (not used on Web) |
|-------------|-----------------------|--------------------------------------------------------|
The context can be configured via the `pConfig` argument. The config object is initialized with `ma_context_config_init()`. Individual configuration settings
can then be set directly on the structure. Below are the members of the `ma_context_config` object.
pLog
A pointer to the `ma_log` to post log messages to. Can be NULL if the application does not
require logging. See the `ma_log` API for details on how to use the logging system.
threadPriority
The desired priority to use for the audio thread. Allowable values include the following:
|--------------------------------------|
| Thread Priority |
|--------------------------------------|
| ma_thread_priority_idle |
| ma_thread_priority_lowest |
| ma_thread_priority_low |
| ma_thread_priority_normal |
| ma_thread_priority_high |
| ma_thread_priority_highest (default) |
| ma_thread_priority_realtime |
| ma_thread_priority_default |
|--------------------------------------|
threadStackSize
The desired size of the stack for the audio thread. Defaults to the operating system's default.
pUserData
A pointer to application-defined data. This can be accessed from the context object directly such as `context.pUserData`.
allocationCallbacks
Structure containing custom allocation callbacks. Leaving this at defaults will cause it to use MA_MALLOC, MA_REALLOC and MA_FREE. These allocation
callbacks will be used for anything tied to the context, including devices.
alsa.useVerboseDeviceEnumeration
ALSA will typically enumerate many different devices which can be intrusive and not user-friendly. To combat this, miniaudio will enumerate only unique
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
Uninitializes a context.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Unsafe. Do not call this function across multiple threads as some backends read and write to global state.
Remarks
-------
Results are undefined if you call this while any device created by this context is still active.
See Also
--------
ma_context_init()
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Unsafe. Since each call to this function invalidates the pointers from the previous call, you should not be calling this simultaneously across multiple
threads. Instead, you need to make a copy of the returned data with your own higher level synchronization.
Remarks
-------
It is _not_ safe to assume the first device in the list is the default device.
You can pass in NULL for the playback or capture lists in which case they'll be ignored.
The returned pointers will become invalid upon the next call this this function, or when the context is uninitialized. Do not free the returned pointers.
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
in exclusive mode, and then fall back to shared mode if required. Alternatively you can just request shared mode (the default if you leave it unset in the
config) which is the most reliable option. Some backends do not have a practical way of choosing whether or not the device should be exclusive or not (ALSA,
for example) in which case it just acts as a hint. Unless you have special requirements you should try avoiding exclusive mode as it's intrusive to the user.
Starting with Windows 10, miniaudio will use low-latency shared mode where possible which may make exclusive mode unnecessary.
When sending or receiving data to/from a device, miniaudio will internally perform a format conversion to convert between the format specified by the config
and the format used internally by the backend. If you pass in 0 for the sample format, channel count, sample rate _and_ channel map, data transmission will run
on an optimized pass-through fast path. You can retrieve the format, channel count and sample rate by inspecting the `playback/capture.format`,
`playback/capture.channels` and `sampleRate` members of the device object.
When compiling for UWP you must ensure you call this function on the main UI thread because the operating system may need to present the user with a message
asking for permissions. Please refer to the official documentation for ActivateAudioInterfaceAsync() for more information.
ALSA Specific: When initializing the default device, requesting shared mode will try using the "dmix" device for playback and the "dsnoop" device for capture.
If these fail it will try falling back to the "hw" device.
Example 1 - Simple Initialization
---------------------------------
This example shows how to initialize a simple playback device using a standard configuration. If you are just needing to do simple playback from the default
playback device this is usually all you need.
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
A pointer to the device to start.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Safe. It's safe to call this from any thread with the exception of the callback thread.
Callback Safety
---------------
Unsafe. It is not safe to call this inside any callback.
Remarks
-------
For a playback device, this will retrieve an initial chunk of audio data from the client before returning. The reason for this is to ensure there is valid
audio data in the buffer, which needs to be done before the device begins playback.
This API waits until the backend device has been started for real by the worker thread. It also waits on a mutex for thread-safety.
Do not call this in any callback.
See Also
--------
ma_device_stop()
*/
MA_API ma_result ma_device_start(ma_device* pDevice);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
A pointer to the device to stop.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Safe. It's safe to call this from any thread with the exception of the callback thread.
Callback Safety
---------------
Unsafe. It is not safe to call this inside any callback. Doing this will result in a deadlock.
Remarks
-------
This API needs to wait on the worker thread to stop the backend device properly before returning. It also waits on a mutex for thread-safety. In addition, some
backends need to wait for the device to finish playback/recording of the current fragment which can take some time (usually proportionate to the buffer size
that was specified at initialization time).
Backends are required to either pause the stream in-place or drain the buffer if pausing is not possible. The reason for this is that stopping the device and
the resuming it with ma_device_start() (which you might do when your program loses focus) may result in a situation where those samples are never output to the
speakers or received from the microphone which can in turn result in de-syncs.
Do not call this in any callback.
This will be called implicitly by `ma_device_uninit()`.
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
A pointer to the device whose start state is being retrieved.
Return Value
------------
True if the device is started, false otherwise.
Thread Safety
-------------
Safe. If another thread calls `ma_device_start()` or `ma_device_stop()` at this same time as this function is called, there's a very small chance the return
value will be out of sync.
Callback Safety
---------------
Safe. This is implemented as a simple accessor.
See Also
--------
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
The descriptor of the capture device containing the internal data format and buffer sizes.
Return Value
------------
MA_SUCCESS if successful; any other error otherwise.
Thread Safety
-------------
Unsafe. This will be reinitializing internal data converters which may be in use by another thread.
Callback Safety
---------------
Unsafe. This will be reinitializing internal data converters which may be in use by the callback.
Remarks
-------
For a duplex device, you can call this for only one side of the system. This is why the deviceType
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
Return Value
------------
The calculated buffer size in frames.
Thread Safety
-------------
This is safe so long as nothing modifies `pDescriptor` at the same time. However, this function
should only ever be called from within the backend's device initialization routine and therefore
shouldn't have any multithreading concerns.
Callback Safety
---------------
This is safe to call within the data callback, but there is no reason to ever do this.
Remarks
-------
If `nativeSampleRate` is zero, this function will fall back to `pDescriptor->sampleRate`. If that
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
MA_API ma_result ma_audio_buffer_get_available_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pAvailableFrames);
/*
Paged Audio Buffer
==================
A paged audio buffer is made up of a linked list of pages. It's expandable, but not shrinkable. It
can be used for cases where audio data is streamed in asynchronously while allowing data to be read
at the same time.
This is lock-free, but not 100% thread safe. You can append a page and read from the buffer across
simultaneously across different threads, however only one thread at a time can append, and only one
thread at a time can read and seek.
*/
typedef struct ma_paged_audio_buffer_page ma_paged_audio_buffer_page;
struct ma_paged_audio_buffer_page
{
MA_ATOMIC(MA_SIZEOF_PTR, ma_paged_audio_buffer_page*) pNext;
ma_uint64 sizeInFrames;
ma_uint8 pAudioData[1];
};
typedef struct
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_encoding_format_mp3,
ma_encoding_format_vorbis
} ma_encoding_format;
#endif
/************************************************************************************************************************************************************
Decoding
========
Decoders are independent of the main device API. Decoding APIs can be called freely inside the device's data callback, but they are not thread safe unless
you do your own synchronization.
************************************************************************************************************************************************************/
#ifndef MA_NO_DECODING
typedef struct ma_decoder ma_decoder;
typedef struct
{
ma_format preferredFormat;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
MA_API ma_result ma_decoder_init_file_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
/*
Uninitializes a decoder.
*/
MA_API ma_result ma_decoder_uninit(ma_decoder* pDecoder);
/*
Reads PCM frames from the given decoder.
This is not thread safe without your own synchronization.
*/
MA_API ma_result ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
/*
Seeks to a PCM frame based on it's absolute index.
This is not thread safe without your own synchronization.
*/
MA_API ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex);
/*
Retrieves the decoder's output data format.
*/
MA_API ma_result ma_decoder_get_data_format(ma_decoder* pDecoder, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
/*
Retrieves the current position of the read cursor in PCM frames.
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
Do not call this on streams of an undefined length, such as internet radio.
If the length is unknown or an error occurs, 0 will be returned.
This will always return 0 for Vorbis decoders. This is due to a limitation with stb_vorbis in push mode which is what miniaudio
uses internally.
For MP3's, this will decode the entire file. Do not call this in time critical scenarios.
This function is not thread safe without your own synchronization.
*/
MA_API ma_result ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder, ma_uint64* pLength);
/*
Retrieves the number of frames that can be read before reaching the end.
This calls `ma_decoder_get_length_in_pcm_frames()` so you need to be aware of the rules for that function, in
particular ensuring you do not call it on streams of an undefined length, such as internet radio.
If the total length of the decoder cannot be retrieved, such as with Vorbis decoders, `MA_NOT_IMPLEMENTED` will be
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
#ifndef MA_NO_RESOURCE_MANAGER
typedef struct ma_resource_manager ma_resource_manager;
typedef struct ma_resource_manager_data_buffer_node ma_resource_manager_data_buffer_node;
typedef struct ma_resource_manager_data_buffer ma_resource_manager_data_buffer;
typedef struct ma_resource_manager_data_stream ma_resource_manager_data_stream;
typedef struct ma_resource_manager_data_source ma_resource_manager_data_source;
typedef enum
{
MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM = 0x00000001, /* When set, does not load the entire data source in memory. Disk I/O will happen on job threads. */
MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE = 0x00000002, /* Decode data before storing in memory. When set, decoding is done at the resource manager level rather than the mixing thread. Results in faster mixing, but higher memory usage...
MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC = 0x00000004, /* When set, the resource manager will load the data source asynchronously. */
MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT = 0x00000008, /* When set, waits for initialization of the underlying data source before returning from ma_resource_manager_data_source_init(). */
MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_UNKNOWN_LENGTH = 0x00000010 /* Gives the resource manager a hint that the length of the data source is unknown and calling `ma_data_source_get_length_in_pcm_frames()` should be avoided. */
} ma_resource_manager_data_source_flags;
/*
Pipeline notifications used by the resource manager. Made up of both an async notification and a fence, both of which are optional.
*/
typedef struct
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
#define ma_resource_manager_job_queue_init ma_job_queue_init
#define ma_resource_manager_job_queue_uninit ma_job_queue_uninit
#define ma_resource_manager_job_queue_post ma_job_queue_post
#define ma_resource_manager_job_queue_next ma_job_queue_next
#endif
/* END BACKWARDS COMPATIBILITY */
/* Maximum job thread count will be restricted to this, but this may be removed later and replaced with a heap allocation thereby removing any limitation. */
#ifndef MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT
#define MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT 64
#endif
typedef enum
{
/* Indicates ma_resource_manager_next_job() should not block. Only valid when the job thread count is 0. */
MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING = 0x00000001,
/* Disables any kind of multithreading. Implicitly enables MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING. */
MA_RESOURCE_MANAGER_FLAG_NO_THREADING = 0x00000002
} ma_resource_manager_flags;
typedef struct
{
const char* pFilePath;
const wchar_t* pFilePathW;
const ma_resource_manager_pipeline_notifications* pNotifications;
ma_uint64 initialSeekPointInPCMFrames;
ma_uint64 rangeBegInPCMFrames;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
typedef enum
{
ma_resource_manager_data_supply_type_unknown = 0, /* Used for determining whether or the data supply has been initialized. */
ma_resource_manager_data_supply_type_encoded, /* Data supply is an encoded buffer. Connector is ma_decoder. */
ma_resource_manager_data_supply_type_decoded, /* Data supply is a decoded buffer. Connector is ma_audio_buffer. */
ma_resource_manager_data_supply_type_decoded_paged /* Data supply is a linked list of decoded buffers. Connector is ma_paged_audio_buffer. */
} ma_resource_manager_data_supply_type;
typedef struct
{
MA_ATOMIC(4, ma_resource_manager_data_supply_type) type; /* Read and written from different threads so needs to be accessed atomically. */
union
{
struct
{
const void* pData;
size_t sizeInBytes;
} encoded;
struct
{
const void* pData;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
};
struct ma_resource_manager_data_buffer
{
ma_data_source_base ds; /* Base data source. A data buffer is a data source. */
ma_resource_manager* pResourceManager; /* A pointer to the resource manager that owns this buffer. */
ma_resource_manager_data_buffer_node* pNode; /* The data node. This is reference counted and is what supplies the data. */
ma_uint32 flags; /* The flags that were passed used to initialize the buffer. */
MA_ATOMIC(4, ma_uint32) executionCounter; /* For allocating execution orders for jobs. */
MA_ATOMIC(4, ma_uint32) executionPointer; /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */
ma_uint64 seekTargetInPCMFrames; /* Only updated by the public API. Never written nor read from the job thread. */
ma_bool32 seekToCursorOnNextRead; /* On the next read we need to seek to the frame cursor. */
MA_ATOMIC(4, ma_result) result; /* Keeps track of a result of decoding. Set to MA_BUSY while the buffer is still loading. Set to MA_SUCCESS when loading is finished successfully. Otherwise set to some other code. */
MA_ATOMIC(4, ma_bool32) isLooping; /* Can be read and written by different threads at the same time. Must be used atomically. */
ma_bool32 isConnectorInitialized; /* Used for asynchronous loading to ensure we don't try to initialize the connector multiple times while waiting for the node to fully load. */
union
{
ma_decoder decoder; /* Supply type is ma_resource_manager_data_supply_type_encoded */
ma_audio_buffer buffer; /* Supply type is ma_resource_manager_data_supply_type_decoded */
ma_paged_audio_buffer pagedBuffer; /* Supply type is ma_resource_manager_data_supply_type_decoded_paged */
} connector; /* Connects this object to the node's data supply. */
};
struct ma_resource_manager_data_stream
{
ma_data_source_base ds; /* Base data source. A data stream is a data source. */
ma_resource_manager* pResourceManager; /* A pointer to the resource manager that owns this data stream. */
ma_uint32 flags; /* The flags that were passed used to initialize the stream. */
ma_decoder decoder; /* Used for filling pages with data. This is only ever accessed by the job thread. The public API should never touch this. */
ma_bool32 isDecoderInitialized; /* Required for determining whether or not the decoder should be uninitialized in MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_STREAM. */
ma_uint64 totalLengthInPCMFrames; /* This is calculated when first loaded by the MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_STREAM. */
ma_uint32 relativeCursor; /* The playback cursor, relative to the current page. Only ever accessed by the public API. Never accessed by the job thread. */
MA_ATOMIC(8, ma_uint64) absoluteCursor; /* The playback cursor, in absolute position starting from the start of the file. */
ma_uint32 currentPageIndex; /* Toggles between 0 and 1. Index 0 is the first half of pPageData. Index 1 is the second half. Only ever accessed by the public API. Never accessed by the job thread. */
MA_ATOMIC(4, ma_uint32) executionCounter; /* For allocating execution orders for jobs. */
MA_ATOMIC(4, ma_uint32) executionPointer; /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */
/* Written by the public API, read by the job thread. */
MA_ATOMIC(4, ma_bool32) isLooping; /* Whether or not the stream is looping. It's important to set the looping flag at the data stream level for smooth loop transitions. */
/* Written by the job thread, read by the public API. */
void* pPageData; /* Buffer containing the decoded data of each page. Allocated once at initialization time. */
MA_ATOMIC(4, ma_uint32) pageFrameCount[2]; /* The number of valid PCM frames in each page. Used to determine the last valid frame. */
/* Written and read by both the public API and the job thread. These must be atomic. */
MA_ATOMIC(4, ma_result) result; /* Result from asynchronous loading. When loading set to MA_BUSY. When initialized set to MA_SUCCESS. When deleting set to MA_UNAVAILABLE. If an error occurs when loading, set to an error code. */
MA_ATOMIC(4, ma_bool32) isDecoderAtEnd; /* Whether or not the decoder has reached the end. */
MA_ATOMIC(4, ma_bool32) isPageValid[2]; /* Booleans to indicate whether or not a page is valid. Set to false by the public API, set to true by the job thread. Set to false as the pages are consumed, true when they are filled. */
MA_ATOMIC(4, ma_bool32) seekCounter; /* When 0, no seeking is being performed. When > 0, a seek is being performed and reading should be delayed with MA_BUSY. */
};
struct ma_resource_manager_data_source
{
union
{
ma_resource_manager_data_buffer buffer;
ma_resource_manager_data_stream stream;
} backend; /* Must be the first item because we need the first item to be the data source callbacks for the buffer or stream. */
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
MA_ATOMIC(4, ma_uint32) executionPointer; /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */
};
typedef struct
{
ma_allocation_callbacks allocationCallbacks;
ma_log* pLog;
ma_format decodedFormat; /* The decoded format to use. Set to ma_format_unknown (default) to use the file's native format. */
ma_uint32 decodedChannels; /* The decoded channel count to use. Set to 0 (default) to use the file's native channel count. */
ma_uint32 decodedSampleRate; /* the decoded sample rate to use. Set to 0 (default) to use the file's native sample rate. */
ma_uint32 jobThreadCount; /* Set to 0 if you want to self-manage your job threads. Defaults to 1. */
ma_uint32 jobQueueCapacity; /* The maximum number of jobs that can fit in the queue at a time. Defaults to MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_CAPACITY. Cannot be zero. */
ma_uint32 flags;
ma_vfs* pVFS; /* Can be NULL in which case defaults will be used. */
ma_decoding_backend_vtable** ppCustomDecodingBackendVTables;
ma_uint32 customDecodingBackendCount;
void* pCustomDecodingBackendUserData;
} ma_resource_manager_config;
MA_API ma_resource_manager_config ma_resource_manager_config_init(void);
struct ma_resource_manager
{
ma_resource_manager_config config;
ma_resource_manager_data_buffer_node* pRootDataBufferNode; /* The root buffer in the binary tree. */
#ifndef MA_NO_THREADING
ma_mutex dataBufferBSTLock; /* For synchronizing access to the data buffer binary tree. */
ma_thread jobThreads[MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT]; /* The threads for executing jobs. */
#endif
ma_job_queue jobQueue; /* Multi-consumer, multi-producer job queue for managing jobs for asynchronous decoding and streaming. */
ma_default_vfs defaultVFS; /* Only used if a custom VFS is not specified. */
ma_log log; /* Only used if no log was specified in the config. */
};
/* Init. */
MA_API ma_result ma_resource_manager_init(const ma_resource_manager_config* pConfig, ma_resource_manager* pResourceManager);
MA_API void ma_resource_manager_uninit(ma_resource_manager* pResourceManager);
MA_API ma_log* ma_resource_manager_get_log(ma_resource_manager* pResourceManager);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
list. Think of the input bus as a linked list, with the output bus being an item in that list.
*/
typedef struct ma_node_output_bus ma_node_output_bus;
struct ma_node_output_bus
{
/* Immutable. */
ma_node* pNode; /* The node that owns this output bus. The input node. Will be null for dummy head and tail nodes. */
ma_uint8 outputBusIndex; /* The index of the output bus on pNode that this output bus represents. */
ma_uint8 channels; /* The number of channels in the audio stream for this bus. */
/* Mutable via multiple threads. Must be used atomically. The weird ordering here is for packing reasons. */
MA_ATOMIC(1, ma_uint8) inputNodeInputBusIndex; /* The index of the input bus on the input. Required for detaching. */
MA_ATOMIC(4, ma_uint32) flags; /* Some state flags for tracking the read state of the output buffer. A combination of MA_NODE_OUTPUT_BUS_FLAG_*. */
MA_ATOMIC(4, ma_uint32) refCount; /* Reference count for some thread-safety when detaching. */
MA_ATOMIC(4, ma_bool32) isAttached; /* This is used to prevent iteration of nodes that are in the middle of being detached. Used for thread safety. */
MA_ATOMIC(4, ma_spinlock) lock; /* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */
MA_ATOMIC(4, float) volume; /* Linear. */
MA_ATOMIC(MA_SIZEOF_PTR, ma_node_output_bus*) pNext; /* If null, it's the tail node or detached. */
MA_ATOMIC(MA_SIZEOF_PTR, ma_node_output_bus*) pPrev; /* If null, it's the head node or detached. */
MA_ATOMIC(MA_SIZEOF_PTR, ma_node*) pInputNode; /* The node that this output bus is attached to. Required for detaching. */
};
/*
A node has multiple input buses. The output buses of a node are connecting to the input busses of
another. An input bus is essentially just a linked list of output buses.
*/
typedef struct ma_node_input_bus ma_node_input_bus;
struct ma_node_input_bus
{
/* Mutable via multiple threads. */
ma_node_output_bus head; /* Dummy head node for simplifying some lock-free thread-safety stuff. */
MA_ATOMIC(4, ma_uint32) nextCounter; /* This is used to determine whether or not the input bus is finding the next node in the list. Used for thread safety when detaching output buses. */
MA_ATOMIC(4, ma_spinlock) lock; /* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */
/* Set once at startup. */
ma_uint8 channels; /* The number of channels in the audio stream for this bus. */
};
typedef struct ma_node_base ma_node_base;
struct ma_node_base
{
/* These variables are set once at startup. */
ma_node_graph* pNodeGraph; /* The graph this node belongs to. */
const ma_node_vtable* vtable;
float* pCachedData; /* Allocated on the heap. Fixed size. Needs to be stored on the heap because reading from output buses is done in separate function calls. */
ma_uint16 cachedDataCapInFramesPerBus; /* The capacity of the input data cache in frames, per bus. */
/* These variables are read and written only from the audio thread. */
ma_uint16 cachedFrameCountOut;
ma_uint16 cachedFrameCountIn;
ma_uint16 consumedFrameCountIn;
/* These variables are read and written between different threads. */
MA_ATOMIC(4, ma_node_state) state; /* When set to stopped, nothing will be read, regardless of the times in stateTimes. */
MA_ATOMIC(8, ma_uint64) stateTimes[2]; /* Indexed by ma_node_state. Specifies the time based on the global clock that a node should be considered to be in the relevant state. */
MA_ATOMIC(8, ma_uint64) localTime; /* The node's local clock. This is just a running sum of the number of output frames that have been processed. Can be modified by any thread with `ma_node_set_time()`. */
ma_uint32 inputBusCount;
ma_uint32 outputBusCount;
ma_node_input_bus* pInputBuses;
ma_node_output_bus* pOutputBuses;
/* Memory management. */
ma_node_input_bus _inputBuses[MA_MAX_NODE_LOCAL_BUS_COUNT];
ma_node_output_bus _outputBuses[MA_MAX_NODE_LOCAL_BUS_COUNT];
void* _pHeap; /* A heap allocation for internal use only. pInputBuses and/or pOutputBuses will point to this if the bus count exceeds MA_MAX_NODE_LOCAL_BUS_COUNT. */
ma_bool32 _ownsHeap; /* If set to true, the node owns the heap allocation and _pHeap will be freed in ma_node_uninit(). */
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
MA_API ma_node_graph_config ma_node_graph_config_init(ma_uint32 channels);
struct ma_node_graph
{
/* Immutable. */
ma_node_base base; /* The node graph itself is a node so it can be connected as an input to different node graph. This has zero inputs and calls ma_node_graph_read_pcm_frames() to generate it's output. */
ma_node_base endpoint; /* Special node that all nodes eventually connect to. Data is read from this node in ma_node_graph_read_pcm_frames(). */
ma_uint16 nodeCacheCapInFrames;
/* Read and written by multiple threads. */
MA_ATOMIC(4, ma_bool32) isReading;
};
MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node_graph* pNodeGraph);
MA_API void ma_node_graph_uninit(ma_node_graph* pNodeGraph, const ma_allocation_callbacks* pAllocationCallbacks);
MA_API ma_node* ma_node_graph_get_endpoint(ma_node_graph* pNodeGraph);
MA_API ma_result ma_node_graph_read_pcm_frames(ma_node_graph* pNodeGraph, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
MA_API ma_uint32 ma_node_graph_get_channels(const ma_node_graph* pNodeGraph);
MA_API ma_uint64 ma_node_graph_get_time(const ma_node_graph* pNodeGraph);
MA_API ma_result ma_node_graph_set_time(ma_node_graph* pNodeGraph, ma_uint64 globalTime);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
typedef struct
{
ma_node_base baseNode; /* Must be the first member for compatiblity with the ma_node API. */
ma_engine* pEngine; /* A pointer to the engine. Set based on the value from the config. */
ma_uint32 sampleRate; /* The sample rate of the input data. For sounds backed by a data source, this will be the data source's sample rate. Otherwise it'll be the engine's sample rate. */
ma_fader fader;
ma_linear_resampler resampler; /* For pitch shift. */
ma_spatializer spatializer;
ma_panner panner;
MA_ATOMIC(4, float) pitch;
float oldPitch; /* For determining whether or not the resampler needs to be updated to reflect the new pitch. The resampler will be updated on the mixing thread. */
float oldDopplerPitch; /* For determining whether or not the resampler needs to be updated to take a new doppler pitch into account. */
MA_ATOMIC(4, ma_bool32) isPitchDisabled; /* When set to true, pitching will be disabled which will allow the resampler to be bypassed to save some computation. */
MA_ATOMIC(4, ma_bool32) isSpatializationDisabled; /* Set to false by default. When set to false, will not have spatialisation applied. */
MA_ATOMIC(4, ma_uint32) pinnedListenerIndex; /* The index of the listener this node should always use for spatialization. If set to MA_LISTENER_INDEX_CLOSEST the engine will use the closest listener. */
/* Memory management. */
ma_bool8 _ownsHeap;
void* _pHeap;
} ma_engine_node;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_bool32 isLooping;
ma_fence* pDoneFence; /* Released when the resource manager has finished decoding the entire sound. Not used with streams. */
} ma_sound_config;
MA_API ma_sound_config ma_sound_config_init(void);
struct ma_sound
{
ma_engine_node engineNode; /* Must be the first member for compatibility with the ma_node API. */
ma_data_source* pDataSource;
MA_ATOMIC(8, ma_uint64) seekTarget; /* The PCM frame index to seek to in the mixing thread. Set to (~(ma_uint64)0) to not perform any seeking. */
MA_ATOMIC(4, ma_bool32) atEnd;
ma_bool8 ownsDataSource;
/*
We're declaring a resource manager data source object here to save us a malloc when loading a
sound via the resource manager, which I *think* will be the most common scenario.
*/
#ifndef MA_NO_RESOURCE_MANAGER
ma_resource_manager_data_source* pResourceManagerDataSource;
#endif
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
#include <float.h> /* For _controlfp_s constants */
#endif
#ifdef MA_WIN32
#include <windows.h>
#else
#include <stdlib.h> /* For malloc(), free(), wcstombs(). */
#include <string.h> /* For memset() */
#include <sched.h>
#include <sys/time.h> /* select() (used for ma_sleep()). */
#include <pthread.h>
#endif
#include <sys/stat.h> /* For fstat(), etc. */
#ifdef MA_EMSCRIPTEN
#include <emscripten/emscripten.h>
#endif
#if !defined(MA_64BIT) && !defined(MA_32BIT)
#ifdef _WIN32
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
*ppFile = _wfopen(pFilePath, pOpenMode);
if (*ppFile == NULL) {
return ma_result_from_errno(errno);
}
#endif
(void)pAllocationCallbacks;
}
#else
/*
Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can
think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility.
*/
{
mbstate_t mbs;
size_t lenMB;
const wchar_t* pFilePathTemp = pFilePath;
char* pFilePathMB = NULL;
char pOpenModeMB[32] = {0};
/* Get the length first. */
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
MA_API ma_result ma_log_init(const ma_allocation_callbacks* pAllocationCallbacks, ma_log* pLog)
{
if (pLog == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pLog);
ma_allocation_callbacks_init_copy(&pLog->allocationCallbacks, pAllocationCallbacks);
/* We need a mutex for thread safety. */
#ifndef MA_NO_THREADING
{
ma_result result = ma_mutex_init(&pLog->lock);
if (result != MA_SUCCESS) {
return result;
}
}
#endif
/* If we're using debug output, enable it. */
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
return (ma_int16)(x * (1 << 8));
}
/*
Random Number Generation
miniaudio uses the LCG random number generation algorithm. This is good enough for audio.
Note that miniaudio's global LCG implementation uses global state which is _not_ thread-local. When this is called across
multiple threads, results will be unpredictable. However, it won't crash and results will still be random enough for
miniaudio's purposes.
*/
#ifndef MA_DEFAULT_LCG_SEED
#define MA_DEFAULT_LCG_SEED 4321
#endif
#define MA_LCG_M 2147483647
#define MA_LCG_A 48271
#define MA_LCG_C 0
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
c89atomic_uint64 newValue;
do {
oldValue = *dst;
newValue = oldValue + src;
} while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
(void)order;
return oldValue;
}
#endif
#if defined(C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY)
static C89ATOMIC_INLINE void __stdcall c89atomic_thread_fence(c89atomic_memory_order order)
{
(void)order;
__asm {
lock add [esp], 0
}
}
#else
#if defined(C89ATOMIC_X64)
#define c89atomic_thread_fence(order) __faststorefence(), (void)order
#else
static C89ATOMIC_INLINE void c89atomic_thread_fence(c89atomic_memory_order order)
{
volatile c89atomic_uint32 barrier = 0;
c89atomic_fetch_add_explicit_32(&barrier, 0, order);
}
#endif
#endif
#define c89atomic_compiler_fence() c89atomic_thread_fence(c89atomic_memory_order_seq_cst)
#define c89atomic_signal_fence(order) c89atomic_thread_fence(order)
#if defined(C89ATOMIC_HAS_8)
static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* ptr, c89atomic_memory_order order)
{
(void)order;
return c89atomic_compare_and_swap_8((volatile c89atomic_uint8*)ptr, 0, 0);
}
#endif
#if defined(C89ATOMIC_HAS_16)
static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* ptr, c89atomic_memory_order order)
{
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)))
#define C89ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE
#define C89ATOMIC_HAS_NATIVE_IS_LOCK_FREE
#define c89atomic_memory_order_relaxed __ATOMIC_RELAXED
#define c89atomic_memory_order_consume __ATOMIC_CONSUME
#define c89atomic_memory_order_acquire __ATOMIC_ACQUIRE
#define c89atomic_memory_order_release __ATOMIC_RELEASE
#define c89atomic_memory_order_acq_rel __ATOMIC_ACQ_REL
#define c89atomic_memory_order_seq_cst __ATOMIC_SEQ_CST
#define c89atomic_compiler_fence() __asm__ __volatile__("":::"memory")
#define c89atomic_thread_fence(order) __atomic_thread_fence(order)
#define c89atomic_signal_fence(order) __atomic_signal_fence(order)
#define c89atomic_is_lock_free_8(ptr) __atomic_is_lock_free(1, ptr)
#define c89atomic_is_lock_free_16(ptr) __atomic_is_lock_free(2, ptr)
#define c89atomic_is_lock_free_32(ptr) __atomic_is_lock_free(4, ptr)
#define c89atomic_is_lock_free_64(ptr) __atomic_is_lock_free(8, ptr)
#define c89atomic_test_and_set_explicit_8( dst, order) __atomic_exchange_n(dst, 1, order)
#define c89atomic_test_and_set_explicit_16(dst, order) __atomic_exchange_n(dst, 1, order)
#define c89atomic_test_and_set_explicit_32(dst, order) __atomic_exchange_n(dst, 1, order)
#define c89atomic_test_and_set_explicit_64(dst, order) __atomic_exchange_n(dst, 1, order)
#define c89atomic_clear_explicit_8( dst, order) __atomic_store_n(dst, 0, order)
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
#define c89atoimc_flag_load_explicit(ptr, order) c89atomic_load_explicit_8(ptr, order)
#else
#define c89atomic_memory_order_relaxed 1
#define c89atomic_memory_order_consume 2
#define c89atomic_memory_order_acquire 3
#define c89atomic_memory_order_release 4
#define c89atomic_memory_order_acq_rel 5
#define c89atomic_memory_order_seq_cst 6
#define c89atomic_compiler_fence() __asm__ __volatile__("":::"memory")
#if defined(__GNUC__)
#define c89atomic_thread_fence(order) __sync_synchronize(), (void)order
static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
{
if (order > c89atomic_memory_order_acquire) {
__sync_synchronize();
}
return __sync_lock_test_and_set(dst, src);
}
static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
{
c89atomic_uint16 oldValue;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
{
(void)order;
return __sync_fetch_and_and(dst, src);
}
#define c89atomic_compare_and_swap_8( dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired)
#define c89atomic_compare_and_swap_16(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired)
#define c89atomic_compare_and_swap_32(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired)
#define c89atomic_compare_and_swap_64(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired)
#else
#if defined(C89ATOMIC_X86)
#define c89atomic_thread_fence(order) __asm__ __volatile__("lock; addl $0, (%%esp)" ::: "memory", "cc")
#elif defined(C89ATOMIC_X64)
#define c89atomic_thread_fence(order) __asm__ __volatile__("lock; addq $0, (%%rsp)" ::: "memory", "cc")
#else
#error Unsupported architecture. Please submit a feature request.
#endif
static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_compare_and_swap_8(volatile c89atomic_uint8* dst, c89atomic_uint8 expected, c89atomic_uint8 desired)
{
c89atomic_uint8 result;
#if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
__asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc");
#else
#error Unsupported architecture. Please submit a feature request.
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
c89atomic_uint64 oldValue;
c89atomic_uint64 newValue;
do {
oldValue = *dst;
newValue = oldValue | src;
} while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
(void)order;
return oldValue;
}
#endif
#define c89atomic_signal_fence(order) c89atomic_thread_fence(order)
static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* ptr, c89atomic_memory_order order)
{
(void)order;
return c89atomic_compare_and_swap_8((c89atomic_uint8*)ptr, 0, 0);
}
static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* ptr, c89atomic_memory_order order)
{
(void)order;
return c89atomic_compare_and_swap_16((c89atomic_uint16*)ptr, 0, 0);
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
c89atomic_store_explicit_32(pSpinlock, 0, c89atomic_memory_order_release);
return MA_SUCCESS;
}
#ifndef MA_NO_THREADING
#ifdef MA_WIN32
#define MA_THREADCALL WINAPI
typedef unsigned long ma_thread_result;
#else
#define MA_THREADCALL
typedef void* ma_thread_result;
#endif
typedef ma_thread_result (MA_THREADCALL * ma_thread_entry_proc)(void* pData);
#ifdef MA_WIN32
static int ma_thread_priority_to_win32(ma_thread_priority priority)
{
switch (priority) {
case ma_thread_priority_idle: return THREAD_PRIORITY_IDLE;
case ma_thread_priority_lowest: return THREAD_PRIORITY_LOWEST;
case ma_thread_priority_low: return THREAD_PRIORITY_BELOW_NORMAL;
case ma_thread_priority_normal: return THREAD_PRIORITY_NORMAL;
case ma_thread_priority_high: return THREAD_PRIORITY_ABOVE_NORMAL;
case ma_thread_priority_highest: return THREAD_PRIORITY_HIGHEST;
case ma_thread_priority_realtime: return THREAD_PRIORITY_TIME_CRITICAL;
default: return THREAD_PRIORITY_NORMAL;
}
}
static ma_result ma_thread_create__win32(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData)
{
*pThread = CreateThread(NULL, stackSize, entryProc, pData, 0, NULL);
if (*pThread == NULL) {
return ma_result_from_GetLastError(GetLastError());
}
SetThreadPriority((HANDLE)*pThread, ma_thread_priority_to_win32(priority));
return MA_SUCCESS;
}
static void ma_thread_wait__win32(ma_thread* pThread)
{
WaitForSingleObject((HANDLE)*pThread, INFINITE);
CloseHandle((HANDLE)*pThread);
}
static ma_result ma_mutex_init__win32(ma_mutex* pMutex)
{
*pMutex = CreateEventW(NULL, FALSE, TRUE, NULL);
if (*pMutex == NULL) {
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
if (result == 0) {
return ma_result_from_GetLastError(GetLastError());
}
return MA_SUCCESS;
}
#endif
#ifdef MA_POSIX
static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData)
{
int result;
pthread_attr_t* pAttr = NULL;
#if !defined(__EMSCRIPTEN__)
/* Try setting the thread priority. It's not critical if anything fails here. */
pthread_attr_t attr;
if (pthread_attr_init(&attr) == 0) {
int scheduler = -1;
if (priority == ma_thread_priority_idle) {
#ifdef SCHED_IDLE
if (pthread_attr_setschedpolicy(&attr, SCHED_IDLE) == 0) {
scheduler = SCHED_IDLE;
}
#endif
} else if (priority == ma_thread_priority_realtime) {
#ifdef SCHED_FIFO
if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) == 0) {
scheduler = SCHED_FIFO;
}
#endif
#ifdef MA_LINUX
} else {
scheduler = sched_getscheduler(0);
#endif
}
if (stackSize > 0) {
pthread_attr_setstacksize(&attr, stackSize);
}
if (scheduler != -1) {
int priorityMin = sched_get_priority_min(scheduler);
int priorityMax = sched_get_priority_max(scheduler);
int priorityStep = (priorityMax - priorityMin) / 7; /* 7 = number of priorities supported by miniaudio. */
struct sched_param sched;
if (pthread_attr_getschedparam(&attr, &sched) == 0) {
if (priority == ma_thread_priority_idle) {
sched.sched_priority = priorityMin;
} else if (priority == ma_thread_priority_realtime) {
sched.sched_priority = priorityMax;
} else {
sched.sched_priority += ((int)priority + 5) * priorityStep; /* +5 because the lowest priority is -5. */
if (sched.sched_priority < priorityMin) {
sched.sched_priority = priorityMin;
}
if (sched.sched_priority > priorityMax) {
sched.sched_priority = priorityMax;
}
}
if (pthread_attr_setschedparam(&attr, &sched) == 0) {
pAttr = &attr;
}
}
}
}
#else
/* It's the emscripten build. We'll have a few unused parameters. */
(void)priority;
(void)stackSize;
#endif
result = pthread_create((pthread_t*)pThread, pAttr, entryProc, pData);
/* The thread attributes object is no longer required. */
if (pAttr != NULL) {
pthread_attr_destroy(pAttr);
}
if (result != 0) {
return ma_result_from_errno(result);
}
return MA_SUCCESS;
}
static void ma_thread_wait__posix(ma_thread* pThread)
{
pthread_join((pthread_t)*pThread, NULL);
}
static ma_result ma_mutex_init__posix(ma_mutex* pMutex)
{
int result = pthread_mutex_init((pthread_mutex_t*)pMutex, NULL);
if (result != 0) {
return ma_result_from_errno(result);
}
return MA_SUCCESS;
}
static void ma_mutex_uninit__posix(ma_mutex* pMutex)
{
pthread_mutex_destroy((pthread_mutex_t*)pMutex);
}
static void ma_mutex_lock__posix(ma_mutex* pMutex)
{
pthread_mutex_lock((pthread_mutex_t*)pMutex);
}
static void ma_mutex_unlock__posix(ma_mutex* pMutex)
{
pthread_mutex_unlock((pthread_mutex_t*)pMutex);
}
static ma_result ma_event_init__posix(ma_event* pEvent)
{
int result;
result = pthread_mutex_init((pthread_mutex_t*)&pEvent->lock, NULL);
if (result != 0) {
return ma_result_from_errno(result);
}
result = pthread_cond_init((pthread_cond_t*)&pEvent->cond, NULL);
if (result != 0) {
pthread_mutex_destroy((pthread_mutex_t*)&pEvent->lock);
return ma_result_from_errno(result);
}
pEvent->value = 0;
return MA_SUCCESS;
}
static void ma_event_uninit__posix(ma_event* pEvent)
{
pthread_cond_destroy((pthread_cond_t*)&pEvent->cond);
pthread_mutex_destroy((pthread_mutex_t*)&pEvent->lock);
}
static ma_result ma_event_wait__posix(ma_event* pEvent)
{
pthread_mutex_lock((pthread_mutex_t*)&pEvent->lock);
{
while (pEvent->value == 0) {
pthread_cond_wait((pthread_cond_t*)&pEvent->cond, (pthread_mutex_t*)&pEvent->lock);
}
pEvent->value = 0; /* Auto-reset. */
}
pthread_mutex_unlock((pthread_mutex_t*)&pEvent->lock);
return MA_SUCCESS;
}
static ma_result ma_event_signal__posix(ma_event* pEvent)
{
pthread_mutex_lock((pthread_mutex_t*)&pEvent->lock);
{
pEvent->value = 1;
pthread_cond_signal((pthread_cond_t*)&pEvent->cond);
}
pthread_mutex_unlock((pthread_mutex_t*)&pEvent->lock);
return MA_SUCCESS;
}
static ma_result ma_semaphore_init__posix(int initialValue, ma_semaphore* pSemaphore)
{
int result;
if (pSemaphore == NULL) {
return MA_INVALID_ARGS;
}
pSemaphore->value = initialValue;
result = pthread_mutex_init((pthread_mutex_t*)&pSemaphore->lock, NULL);
if (result != 0) {
return ma_result_from_errno(result); /* Failed to create mutex. */
}
result = pthread_cond_init((pthread_cond_t*)&pSemaphore->cond, NULL);
if (result != 0) {
pthread_mutex_destroy((pthread_mutex_t*)&pSemaphore->lock);
return ma_result_from_errno(result); /* Failed to create condition variable. */
}
return MA_SUCCESS;
}
static void ma_semaphore_uninit__posix(ma_semaphore* pSemaphore)
{
if (pSemaphore == NULL) {
return;
}
pthread_cond_destroy((pthread_cond_t*)&pSemaphore->cond);
pthread_mutex_destroy((pthread_mutex_t*)&pSemaphore->lock);
}
static ma_result ma_semaphore_wait__posix(ma_semaphore* pSemaphore)
{
if (pSemaphore == NULL) {
return MA_INVALID_ARGS;
}
pthread_mutex_lock((pthread_mutex_t*)&pSemaphore->lock);
{
/* We need to wait on a condition variable before escaping. We can't return from this function until the semaphore has been signaled. */
while (pSemaphore->value == 0) {
pthread_cond_wait((pthread_cond_t*)&pSemaphore->cond, (pthread_mutex_t*)&pSemaphore->lock);
}
pSemaphore->value -= 1;
}
pthread_mutex_unlock((pthread_mutex_t*)&pSemaphore->lock);
return MA_SUCCESS;
}
static ma_result ma_semaphore_release__posix(ma_semaphore* pSemaphore)
{
if (pSemaphore == NULL) {
return MA_INVALID_ARGS;
}
pthread_mutex_lock((pthread_mutex_t*)&pSemaphore->lock);
{
pSemaphore->value += 1;
pthread_cond_signal((pthread_cond_t*)&pSemaphore->cond);
}
pthread_mutex_unlock((pthread_mutex_t*)&pSemaphore->lock);
return MA_SUCCESS;
}
#endif
typedef struct
{
ma_thread_entry_proc entryProc;
void* pData;
ma_allocation_callbacks allocationCallbacks;
} ma_thread_proxy_data;
static ma_thread_result MA_THREADCALL ma_thread_entry_proxy(void* pData)
{
ma_thread_proxy_data* pProxyData = (ma_thread_proxy_data*)pData;
ma_thread_entry_proc entryProc;
void* pEntryProcData;
ma_thread_result result;
#if defined(MA_ON_THREAD_ENTRY)
MA_ON_THREAD_ENTRY
#endif
entryProc = pProxyData->entryProc;
pEntryProcData = pProxyData->pData;
/* Free the proxy data before getting into the real thread entry proc. */
ma_free(pProxyData, &pProxyData->allocationCallbacks);
result = entryProc(pEntryProcData);
#if defined(MA_ON_THREAD_EXIT)
MA_ON_THREAD_EXIT
#endif
return result;
}
static ma_result ma_thread_create(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData, const ma_allocation_callbacks* pAllocationCallbacks)
{
ma_result result;
ma_thread_proxy_data* pProxyData;
if (pThread == NULL || entryProc == NULL) {
return MA_INVALID_ARGS;
}
pProxyData = (ma_thread_proxy_data*)ma_malloc(sizeof(*pProxyData), pAllocationCallbacks); /* Will be freed by the proxy entry proc. */
if (pProxyData == NULL) {
return MA_OUT_OF_MEMORY;
}
pProxyData->entryProc = entryProc;
pProxyData->pData = pData;
ma_allocation_callbacks_init_copy(&pProxyData->allocationCallbacks, pAllocationCallbacks);
#ifdef MA_WIN32
result = ma_thread_create__win32(pThread, priority, stackSize, ma_thread_entry_proxy, pProxyData);
#endif
#ifdef MA_POSIX
result = ma_thread_create__posix(pThread, priority, stackSize, ma_thread_entry_proxy, pProxyData);
#endif
if (result != MA_SUCCESS) {
ma_free(pProxyData, pAllocationCallbacks);
return result;
}
return MA_SUCCESS;
}
static void ma_thread_wait(ma_thread* pThread)
{
if (pThread == NULL) {
return;
}
#ifdef MA_WIN32
ma_thread_wait__win32(pThread);
#endif
#ifdef MA_POSIX
ma_thread_wait__posix(pThread);
#endif
}
MA_API ma_result ma_mutex_init(ma_mutex* pMutex)
{
if (pMutex == NULL) {
MA_ASSERT(MA_FALSE); /* Fire an assert so the caller is aware of this bug. */
return MA_INVALID_ARGS;
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
#ifdef MA_WIN32
return ma_semaphore_release__win32(pSemaphore);
#endif
#ifdef MA_POSIX
return ma_semaphore_release__posix(pSemaphore);
#endif
}
#else
/* MA_NO_THREADING is set which means threading is disabled. Threading is required by some API families. If any of these are enabled we need to throw an error. */
#ifndef MA_NO_DEVICE_IO
#error "MA_NO_THREADING cannot be used without MA_NO_DEVICE_IO";
#endif
#endif /* MA_NO_THREADING */
#define MA_FENCE_COUNTER_MAX 0x7FFFFFFF
MA_API ma_result ma_fence_init(ma_fence* pFence)
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
if (newCounter > MA_FENCE_COUNTER_MAX) {
MA_ASSERT(MA_FALSE);
return MA_OUT_OF_RANGE;
}
if (c89atomic_compare_exchange_weak_32(&pFence->counter, &oldCounter, newCounter)) {
return MA_SUCCESS;
} else {
if (oldCounter == MA_FENCE_COUNTER_MAX) {
MA_ASSERT(MA_FALSE);
return MA_OUT_OF_RANGE; /* The other thread took the last available slot. Abort. */
}
}
}
/* Should never get here. */
/*return MA_SUCCESS;*/
}
MA_API ma_result ma_fence_release(ma_fence* pFence)
{
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
if (newCounter == 0) {
ma_event_signal(&pFence->e); /* <-- ma_fence_wait() will be waiting on this. */
}
}
#endif
return MA_SUCCESS;
} else {
if (oldCounter == 0) {
MA_ASSERT(MA_FALSE);
return MA_INVALID_OPERATION; /* Another thread has taken the 0 slot. Acquire/release mismatch. */
}
}
}
/* Should never get here. */
/*return MA_SUCCESS;*/
}
MA_API ma_result ma_fence_wait(ma_fence* pFence)
{
if (pFence == NULL) {
return MA_INVALID_ARGS;
}
for (;;) {
ma_uint32 counter;
counter = c89atomic_load_32(&pFence->counter);
if (counter == 0) {
/*
Counter has hit zero. By the time we get here some other thread may have acquired the
fence again, but that is where the caller needs to take care with how they se the fence.
*/
return MA_SUCCESS;
}
/* Getting here means the counter is > 0. We'll need to wait for something to happen. */
#ifndef MA_NO_THREADING
{
ma_result result;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
bitOffset = ma_ffs_32(~oldBitfield);
MA_ASSERT(bitOffset < 32);
newBitfield = oldBitfield | (1 << bitOffset);
if (c89atomic_compare_and_swap_32(&pAllocator->pGroups[iGroup].bitfield, oldBitfield, newBitfield) == oldBitfield) {
ma_uint32 slotIndex;
/* Increment the counter as soon as possible to have other threads report out-of-memory sooner than later. */
c89atomic_fetch_add_32(&pAllocator->count, 1);
/* The slot index is required for constructing the output value. */
slotIndex = (iGroup << 5) + bitOffset; /* iGroup << 5 = iGroup * 32 */
if (slotIndex >= pAllocator->capacity) {
return MA_OUT_OF_MEMORY;
}
/* Increment the reference count before constructing the output value. */
pAllocator->pSlots[slotIndex] += 1;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
pQueue->flags = pConfig->flags;
pQueue->capacity = pConfig->capacity;
pQueue->pJobs = (ma_job*)ma_offset_ptr(pHeap, heapLayout.jobsOffset);
allocatorConfig = ma_slot_allocator_config_init(pConfig->capacity);
result = ma_slot_allocator_init_preallocated(&allocatorConfig, ma_offset_ptr(pHeap, heapLayout.allocatorOffset), &pQueue->allocator);
if (result != MA_SUCCESS) {
return result;
}
/* We need a semaphore if we're running in non-blocking mode. If threading is disabled we need to return an error. */
if ((pQueue->flags & MA_JOB_QUEUE_FLAG_NON_BLOCKING) == 0) {
#ifndef MA_NO_THREADING
{
ma_semaphore_init(0, &pQueue->sem);
}
#else
{
/* Threading is disabled and we've requested non-blocking mode. */
return MA_INVALID_OPERATION;
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
MA_ASSERT(MA_FALSE); /* Should never get here. Should have been checked at initialization time. */
}
#endif
}
#ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE
ma_spinlock_lock(&pQueue->lock);
#endif
{
/*
BUG: In lock-free mode, multiple threads can be in this section of code. The "head" variable in the loop below
is stored. One thread can fall through to the freeing of this item while another is still using "head" for the
retrieval of the "next" variable.
The slot allocator might need to make use of some reference counting to ensure it's only truely freed when
there are no more references to the item. This must be fixed before removing these locks.
*/
/* Now we need to remove the root item from the list. */
for (;;) {
head = c89atomic_load_64(&pQueue->head);
tail = c89atomic_load_64(&pQueue->tail);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
}
}
#ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE
ma_spinlock_unlock(&pQueue->lock);
#endif
ma_slot_allocator_free(&pQueue->allocator, head);
/*
If it's a quit job make sure it's put back on the queue to ensure other threads have an opportunity to detect it and terminate naturally. We
could instead just leave it on the queue, but that would involve fiddling with the lock-free code above and I want to keep that as simple as
possible.
*/
if (pJob->toc.breakup.code == MA_JOB_TYPE_QUIT) {
ma_job_queue_post(pQueue, pJob);
return MA_CANCELLED; /* Return a cancelled status just in case the thread is checking return codes and not properly checking for a quit job. */
}
return MA_SUCCESS;
}
/************************************************************************************************************************************************************
*************************************************************************************************************************************************************
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
#include <mach/mach_time.h> /* For mach_absolute_time() */
#endif
#ifdef MA_POSIX
#include <sys/types.h>
#include <unistd.h>
#include <dlfcn.h>
#endif
/*
Unfortunately using runtime linking for pthreads causes problems. This has occurred for me when testing on FreeBSD. When
using runtime linking, deadlocks can occur (for me it happens when loading data from fread()). It turns out that doing
compile-time linking fixes this. I'm not sure why this happens, but the safest way I can think of to fix this is to simply
disable runtime linking by default. To enable runtime linking, #define this before the implementation of this file. I am
not officially supporting this, but I'm leaving it here in case it's useful for somebody, somewhere.
*/
/*#define MA_USE_RUNTIME_LINKING_FOR_PTHREAD*/
/* Disable run-time linking on certain backends. */
#ifndef MA_NO_RUNTIME_LINKING
#if defined(MA_EMSCRIPTEN)
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
if (pDeviceDescriptor->sampleRate == 0) {
return MA_FALSE;
}
return MA_TRUE;
}
static ma_result ma_device_audio_thread__default_read_write(ma_device* pDevice)
{
ma_result result = MA_SUCCESS;
ma_bool32 exitLoop = MA_FALSE;
ma_uint8 capturedDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint8 playbackDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint32 capturedDeviceDataCapInFrames = 0;
ma_uint32 playbackDeviceDataCapInFrames = 0;
MA_ASSERT(pDevice != NULL);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
if (pDevice->pContext->callbacks.onDeviceWrite == NULL) {
return MA_NOT_IMPLEMENTED;
}
playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
}
/* NOTE: The device was started outside of this function, in the worker thread. */
while (ma_device_get_state(pDevice) == ma_device_state_started && !exitLoop) {
switch (pDevice->type) {
case ma_device_type_duplex:
{
/* The process is: onDeviceRead() -> convert -> callback -> convert -> onDeviceWrite() */
ma_uint32 totalCapturedDeviceFramesProcessed = 0;
ma_uint32 capturedDevicePeriodSizeInFrames = ma_min(pDevice->capture.internalPeriodSizeInFrames, pDevice->playback.internalPeriodSizeInFrames);
while (totalCapturedDeviceFramesProcessed < capturedDevicePeriodSizeInFrames) {
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
Null Backend
*******************************************************************************/
#ifdef MA_HAS_NULL
#define MA_DEVICE_OP_NONE__NULL 0
#define MA_DEVICE_OP_START__NULL 1
#define MA_DEVICE_OP_SUSPEND__NULL 2
#define MA_DEVICE_OP_KILL__NULL 3
static ma_thread_result MA_THREADCALL ma_device_thread__null(void* pData)
{
ma_device* pDevice = (ma_device*)pData;
MA_ASSERT(pDevice != NULL);
for (;;) { /* Keep the thread alive until the device is uninitialized. */
ma_uint32 operation;
/* Wait for an operation to be requested. */
ma_event_wait(&pDevice->null_device.operationEvent);
/* At this point an event should have been triggered. */
operation = pDevice->null_device.operation;
/* Starting the device needs to put the thread into a loop. */
if (operation == MA_DEVICE_OP_START__NULL) {
/* Reset the timer just in case. */
ma_timer_init(&pDevice->null_device.timer);
/* Getting here means a suspend or kill operation has been requested. */
pDevice->null_device.operationResult = MA_SUCCESS;
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
ma_semaphore_release(&pDevice->null_device.operationSemaphore);
continue;
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
pDevice->null_device.priorRunTime += ma_timer_get_time_in_seconds(&pDevice->null_device.timer);
ma_timer_init(&pDevice->null_device.timer);
/* We're done. */
pDevice->null_device.operationResult = MA_SUCCESS;
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
ma_semaphore_release(&pDevice->null_device.operationSemaphore);
continue;
}
/* Killing the device means we need to get out of this loop so that this thread can terminate. */
if (operation == MA_DEVICE_OP_KILL__NULL) {
pDevice->null_device.operationResult = MA_SUCCESS;
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
ma_semaphore_release(&pDevice->null_device.operationSemaphore);
break;
}
/* Getting a signal on a "none" operation probably means an error. Return invalid operation. */
if (operation == MA_DEVICE_OP_NONE__NULL) {
MA_ASSERT(MA_FALSE); /* <-- Trigger this in debug mode to ensure developers are aware they're doing something wrong (or there's a bug in a miniaudio). */
pDevice->null_device.operationResult = MA_INVALID_OPERATION;
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
ma_semaphore_release(&pDevice->null_device.operationSemaphore);
continue; /* Continue the loop. Don't terminate. */
}
}
return (ma_thread_result)0;
}
static ma_result ma_device_do_operation__null(ma_device* pDevice, ma_uint32 operation)
{
ma_result result;
/*
TODO: Need to review this and consider just using mutual exclusion. I think the original motivation
for this was to just post the event to a queue and return immediately, but that has since changed
and now this function is synchronous. I think this can be simplified to just use a mutex.
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
/*
The first thing to do is wait for an operation slot to become available. We only have a single slot for this, but we could extend this later
to support queing of operations.
*/
result = ma_semaphore_wait(&pDevice->null_device.operationSemaphore);
if (result != MA_SUCCESS) {
return result; /* Failed to wait for the event. */
}
/*
When we get here it means the background thread is not referencing the operation code and it can be changed. After changing this we need to
signal an event to the worker thread to let it know that it can start work.
*/
pDevice->null_device.operation = operation;
/* Once the operation code has been set, the worker thread can start work. */
if (ma_event_signal(&pDevice->null_device.operationEvent) != MA_SUCCESS) {
return MA_ERROR;
}
/* We want everything to be synchronous so we're going to wait for the worker thread to complete it's operation. */
if (ma_event_wait(&pDevice->null_device.operationCompletionEvent) != MA_SUCCESS) {
return MA_ERROR;
}
return pDevice->null_device.operationResult;
}
static ma_uint64 ma_device_get_total_run_time_in_frames__null(ma_device* pDevice)
{
ma_uint32 internalSampleRate;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
(void)pContext;
return MA_SUCCESS;
}
static ma_result ma_device_uninit__null(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
/* Keep it clean and wait for the device thread to finish before returning. */
ma_device_do_operation__null(pDevice, MA_DEVICE_OP_KILL__NULL);
/* Wait for the thread to finish before continuing. */
ma_thread_wait(&pDevice->null_device.deviceThread);
/* At this point the loop in the device thread is as good as terminated so we can uninitialize our events. */
ma_semaphore_uninit(&pDevice->null_device.operationSemaphore);
ma_event_uninit(&pDevice->null_device.operationCompletionEvent);
ma_event_uninit(&pDevice->null_device.operationEvent);
return MA_SUCCESS;
}
static ma_result ma_device_init__null(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
{
ma_result result;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
pDescriptorPlayback->sampleRate = (pDescriptorPlayback->sampleRate != 0) ? pDescriptorPlayback->sampleRate : MA_DEFAULT_SAMPLE_RATE;
if (pDescriptorPlayback->channelMap[0] == MA_CHANNEL_NONE) {
ma_channel_map_init_standard(ma_standard_channel_map_default, pDescriptorPlayback->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorPlayback->channels);
}
pDescriptorPlayback->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile);
}
/*
In order to get timing right, we need to create a thread that does nothing but keeps track of the timer. This timer is started when the
first period is "written" to it, and then stopped in ma_device_stop__null().
*/
result = ma_event_init(&pDevice->null_device.operationEvent);
if (result != MA_SUCCESS) {
return result;
}
result = ma_event_init(&pDevice->null_device.operationCompletionEvent);
if (result != MA_SUCCESS) {
return result;
}
result = ma_semaphore_init(1, &pDevice->null_device.operationSemaphore); /* <-- It's important that the initial value is set to 1. */
if (result != MA_SUCCESS) {
return result;
}
result = ma_thread_create(&pDevice->null_device.deviceThread, pDevice->pContext->threadPriority, 0, ma_device_thread__null, pDevice, &pDevice->pContext->allocationCallbacks);
if (result != MA_SUCCESS) {
return result;
}
return MA_SUCCESS;
}
static ma_result ma_device_start__null(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
pCallbacks->onContextInit = ma_context_init__null;
pCallbacks->onContextUninit = ma_context_uninit__null;
pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__null;
pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__null;
pCallbacks->onDeviceInit = ma_device_init__null;
pCallbacks->onDeviceUninit = ma_device_uninit__null;
pCallbacks->onDeviceStart = ma_device_start__null;
pCallbacks->onDeviceStop = ma_device_stop__null;
pCallbacks->onDeviceRead = ma_device_read__null;
pCallbacks->onDeviceWrite = ma_device_write__null;
pCallbacks->onDeviceDataLoop = NULL; /* Our backend is asynchronous with a blocking read-write API which means we can get miniaudio to deal with the audio thread. */
/* The null backend always works. */
return MA_SUCCESS;
}
#endif
/*******************************************************************************
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
struct ma_completion_handler_uwp
{
ma_completion_handler_uwp_vtbl* lpVtbl;
MA_ATOMIC(4, ma_uint32) counter;
HANDLE hEvent;
};
static HRESULT STDMETHODCALLTYPE ma_completion_handler_uwp_QueryInterface(ma_completion_handler_uwp* pThis, const IID* const riid, void** ppObject)
{
/*
We need to "implement" IAgileObject which is just an indicator that's used internally by WASAPI for some multithreading management. To
"implement" this, we just make sure we return pThis when the IAgileObject is requested.
*/
if (!ma_is_guid_equal(riid, &MA_IID_IUnknown) && !ma_is_guid_equal(riid, &MA_IID_IActivateAudioInterfaceCompletionHandler) && !ma_is_guid_equal(riid, &MA_IID_IAgileObject)) {
*ppObject = NULL;
return E_NOINTERFACE;
}
/* Getting here means the IID is IUnknown or IMMNotificationClient. */
*ppObject = (void*)pThis;
((ma_completion_handler_uwp_vtbl*)pThis->lpVtbl)->AddRef(pThis);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
*pCmd = pContext->wasapi.commands[pContext->wasapi.commandIndex];
pContext->wasapi.commandIndex = (pContext->wasapi.commandIndex + 1) % ma_countof(pContext->wasapi.commands);
pContext->wasapi.commandCount -= 1;
}
ma_mutex_unlock(&pContext->wasapi.commandLock);
}
return result;
}
static ma_thread_result MA_THREADCALL ma_context_command_thread__wasapi(void* pUserData)
{
ma_result result;
ma_context* pContext = (ma_context*)pUserData;
MA_ASSERT(pContext != NULL);
for (;;) {
ma_context_command__wasapi cmd;
result = ma_context_next_command__wasapi(pContext, &cmd);
if (result != MA_SUCCESS) {
break;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
if (cmd.pEvent != NULL) {
ma_event_signal(cmd.pEvent);
}
if (cmd.code == MA_CONTEXT_COMMAND_QUIT__WASAPI) {
break; /* Received a quit message. Get out of here. */
}
}
return (ma_thread_result)0;
}
static ma_result ma_device_create_IAudioClient_service__wasapi(ma_context* pContext, ma_device_type deviceType, ma_IAudioClient* pAudioClient, void** ppAudioClientService)
{
ma_result result;
ma_result cmdResult;
ma_context_command__wasapi cmd = ma_context_init_command__wasapi(MA_CONTEXT_COMMAND_CREATE_IAUDIOCLIENT__WASAPI);
cmd.data.createAudioClient.deviceType = deviceType;
cmd.data.createAudioClient.pAudioClient = (void*)pAudioClient;
cmd.data.createAudioClient.ppAudioClientService = ppAudioClientService;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
/*
Before reinitializing the device we need to free the previous audio clients.
There's a known memory leak here. We will be calling this from the routing change callback that
is fired by WASAPI. If we attempt to release the IAudioClient we will deadlock. In my opinion
this is a bug. I'm not sure what I need to do to handle this cleanly, but I think we'll probably
need some system where we post an event, but delay the execution of it until the callback has
returned. I'm not sure how to do this reliably, however. I have set up some infrastructure for
a command thread which might be useful for this.
*/
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
if (pDevice->wasapi.pCaptureClient) {
ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
pDevice->wasapi.pCaptureClient = NULL;
}
if (pDevice->wasapi.pAudioClientCapture) {
/*ma_device_release_IAudioClient_service__wasapi(pDevice, ma_device_type_capture);*/
pDevice->wasapi.pAudioClientCapture = NULL;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
static ma_result ma_context_uninit__wasapi(ma_context* pContext)
{
MA_ASSERT(pContext != NULL);
MA_ASSERT(pContext->backend == ma_backend_wasapi);
if (pContext->wasapi.commandThread != NULL) {
ma_context_command__wasapi cmd = ma_context_init_command__wasapi(MA_CONTEXT_COMMAND_QUIT__WASAPI);
ma_context_post_command__wasapi(pContext, &cmd);
ma_thread_wait(&pContext->wasapi.commandThread);
/* Only after the thread has been terminated can we uninitialize the sync objects for the command thread. */
ma_semaphore_uninit(&pContext->wasapi.commandSem);
ma_mutex_uninit(&pContext->wasapi.commandLock);
}
return MA_SUCCESS;
}
static ma_result ma_context_init__wasapi(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
{
ma_result result = MA_SUCCESS;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
#endif
if (result != MA_SUCCESS) {
return result;
}
MA_ZERO_OBJECT(&pContext->wasapi);
/*
Annoyingly, WASAPI does not allow you to release an IAudioClient object from a different thread
than the one that retrieved it with GetService(). This can result in a deadlock in two
situations:
1) When calling ma_device_uninit() from a different thread to ma_device_init(); and
2) When uninitializing and reinitializing the internal IAudioClient object in response to
automatic stream routing.
We could define ma_device_uninit() such that it must be called on the same thread as
ma_device_init(). We could also just not release the IAudioClient when performing automatic
stream routing to avoid the deadlock. Neither of these are acceptable solutions in my view so
we're going to have to work around this with a worker thread. This is not ideal, but I can't
think of a better way to do this.
More information about this can be found here:
https://docs.microsoft.com/en-us/windows/win32/api/audioclient/nn-audioclient-iaudiorenderclient
Note this section:
When releasing an IAudioRenderClient interface instance, the client must call the interface's
Release method from the same thread as the call to IAudioClient::GetService that created the
object.
*/
{
result = ma_mutex_init(&pContext->wasapi.commandLock);
if (result != MA_SUCCESS) {
return result;
}
result = ma_semaphore_init(0, &pContext->wasapi.commandSem);
if (result != MA_SUCCESS) {
ma_mutex_uninit(&pContext->wasapi.commandLock);
return result;
}
result = ma_thread_create(&pContext->wasapi.commandThread, ma_thread_priority_normal, 0, ma_context_command_thread__wasapi, pContext, &pContext->allocationCallbacks);
if (result != MA_SUCCESS) {
ma_semaphore_uninit(&pContext->wasapi.commandSem);
ma_mutex_uninit(&pContext->wasapi.commandLock);
return result;
}
}
pCallbacks->onContextInit = ma_context_init__wasapi;
pCallbacks->onContextUninit = ma_context_uninit__wasapi;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
pCallbacks->onContextInit = ma_context_init__winmm;
pCallbacks->onContextUninit = ma_context_uninit__winmm;
pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__winmm;
pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__winmm;
pCallbacks->onDeviceInit = ma_device_init__winmm;
pCallbacks->onDeviceUninit = ma_device_uninit__winmm;
pCallbacks->onDeviceStart = ma_device_start__winmm;
pCallbacks->onDeviceStop = ma_device_stop__winmm;
pCallbacks->onDeviceRead = ma_device_read__winmm;
pCallbacks->onDeviceWrite = ma_device_write__winmm;
pCallbacks->onDeviceDataLoop = NULL; /* This is a blocking read-write API, so this can be NULL since miniaudio will manage the audio thread for us. */
return MA_SUCCESS;
}
#endif
/******************************************************************************
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
Since we're not using the simple API, we're left with the asynchronous API as our only other option. And boy, is this where it starts to
get fun, and I don't mean that in a good way...
The problems start with the very name of the API - "asynchronous". Yes, this is an asynchronous oriented API which means your commands
don't immediately take effect. You instead need to issue your commands, and then wait for them to complete. The waiting mechanism is
enabled through the use of a "main loop". In the asychronous API you cannot get away from the main loop, and the main loop is where almost
all of PulseAudio's problems stem from.
When you first initialize PulseAudio you need an object referred to as "main loop". You can implement this yourself by defining your own
vtable, but it's much easier to just use one of the built-in main loop implementations. There's two generic implementations called
pa_mainloop and pa_threaded_mainloop, and another implementation specific to GLib called pa_glib_mainloop. We're using pa_threaded_mainloop
because it simplifies management of the worker thread. The idea of the main loop object is pretty self explanatory - you're supposed to use
it to implement a worker thread which runs in a loop. The main loop is where operations are actually executed.
To initialize the main loop, you just use `pa_threaded_mainloop_new()`. This is the first function you'll call. You can then get a pointer
to the vtable with `pa_threaded_mainloop_get_api()` (the main loop vtable is called `pa_mainloop_api`). Again, you can bypass the threaded
main loop object entirely and just implement `pa_mainloop_api` directly, but there's no need for it unless you're doing something extremely
specialized such as if you want to integrate it into your application's existing main loop infrastructure.
(EDIT 2021-01-26: miniaudio is no longer using `pa_threaded_mainloop` due to this issue: https://github.com/mackron/miniaudio/issues/262.
It is now using `pa_mainloop` which turns out to be a simpler solution anyway. The rest of this rant still applies, however.)
Once you have your main loop vtable (the `pa_mainloop_api` object) you can create the PulseAudio context. This is very similar to
miniaudio's context and they map to each other quite well. You have one context to many streams, which is basically the same as miniaudio's
one `ma_context` to many `ma_device`s. Here's where it starts to get annoying, however. When you first create the PulseAudio context, which
is done with `pa_context_new()`, it's not actually connected to anything. When you connect, you call `pa_context_connect()`. However, if
you remember, PulseAudio is an asynchronous API. That means you cannot just assume the context is connected after `pa_context_context()`
has returned. You instead need to wait for it to connect. To do this, you need to either wait for a callback to get fired, which you can
set with `pa_context_set_state_callback()`, or you can continuously poll the context's state. Either way, you need to run this in a loop.
All objects from here out are created from the context, and, I believe, you can't be creating these objects until the context is connected.
This waiting loop is therefore unavoidable. In order for the waiting to ever complete, however, the main loop needs to be running. Before
attempting to connect the context, the main loop needs to be started with `pa_threaded_mainloop_start()`.
The reason for this asynchronous design is to support cases where you're connecting to a remote server, say through a local network or an
internet connection. However, the *VAST* majority of cases don't involve this at all - they just connect to a local "server" running on the
host machine. The fact that this would be the default rather than making `pa_context_connect()` synchronous tends to boggle the mind.
Once the context has been created and connected you can start creating a stream. A PulseAudio stream is analogous to miniaudio's device.
The initialization of a stream is fairly standard - you configure some attributes (analogous to miniaudio's device config) and then call
`pa_stream_new()` to actually create it. Here is where we start to get into "operations". When configuring the stream, you can get
information about the source (such as sample format, sample rate, etc.), however it's not synchronous. Instead, a `pa_operation` object
is returned from `pa_context_get_source_info_by_name()` (capture) or `pa_context_get_sink_info_by_name()` (playback). Then, you need to
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
"corking" in PulseAudio. The analogy is corking a barrel. To start the stream, you uncork it, to stop it you cork it. Personally I think
it's silly - why would you not just call it "starting" and "stopping" like any other normal audio API? Anyway, the act of corking is, you
guessed it, asynchronous. This means you'll need our waiting loop as usual. Again, why this asynchronous design is the default is
absolutely beyond me. Would it really be that hard to just make it run synchronously?
Teardown is pretty simple (what?!). It's just a matter of calling the relevant `_unref()` function on each object in reverse order that
they were initialized in.
That's about it from the PulseAudio side. A bit ranty, I know, but they really need to fix that main loop and callback system. They're
embarrassingly unpractical. The main loop thing is an easy fix - have synchronous versions of all APIs. If an application wants these to
run asynchronously, they can execute them in a separate thread themselves. The desire to run these asynchronously is such a niche
requirement - it makes no sense to make it the default. The stream write callback needs to be change, or an alternative provided, that is
constantly fired, regardless of whether or not `pa_stream_write()` has been called, and it needs to take a pointer to a buffer as a
parameter which the program just writes to directly rather than having to call `pa_stream_writable_size()` and `pa_stream_write()`. These
changes alone will change PulseAudio from one of the worst audio APIs to one of the best.
*/
/*
It is assumed pulseaudio.h is available when linking at compile time. When linking at compile time, we use the declarations in the header
to check for type safety. We cannot do this when linking at run time because the header might not be available.
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
#define MA_PA_SAMPLE_FLOAT32LE PA_SAMPLE_FLOAT32LE
#define MA_PA_SAMPLE_FLOAT32BE PA_SAMPLE_FLOAT32BE
#define MA_PA_SAMPLE_S32LE PA_SAMPLE_S32LE
#define MA_PA_SAMPLE_S32BE PA_SAMPLE_S32BE
#define MA_PA_SAMPLE_S24LE PA_SAMPLE_S24LE
#define MA_PA_SAMPLE_S24BE PA_SAMPLE_S24BE
#define MA_PA_SAMPLE_S24_32LE PA_SAMPLE_S24_32LE
#define MA_PA_SAMPLE_S24_32BE PA_SAMPLE_S24_32BE
typedef pa_mainloop ma_pa_mainloop;
typedef pa_threaded_mainloop ma_pa_threaded_mainloop;
typedef pa_mainloop_api ma_pa_mainloop_api;
typedef pa_context ma_pa_context;
typedef pa_operation ma_pa_operation;
typedef pa_stream ma_pa_stream;
typedef pa_spawn_api ma_pa_spawn_api;
typedef pa_buffer_attr ma_pa_buffer_attr;
typedef pa_channel_map ma_pa_channel_map;
typedef pa_cvolume ma_pa_cvolume;
typedef pa_sample_spec ma_pa_sample_spec;
typedef pa_sink_info ma_pa_sink_info;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
#define MA_PA_SAMPLE_FLOAT32LE 5
#define MA_PA_SAMPLE_FLOAT32BE 6
#define MA_PA_SAMPLE_S32LE 7
#define MA_PA_SAMPLE_S32BE 8
#define MA_PA_SAMPLE_S24LE 9
#define MA_PA_SAMPLE_S24BE 10
#define MA_PA_SAMPLE_S24_32LE 11
#define MA_PA_SAMPLE_S24_32BE 12
typedef struct ma_pa_mainloop ma_pa_mainloop;
typedef struct ma_pa_threaded_mainloop ma_pa_threaded_mainloop;
typedef struct ma_pa_mainloop_api ma_pa_mainloop_api;
typedef struct ma_pa_context ma_pa_context;
typedef struct ma_pa_operation ma_pa_operation;
typedef struct ma_pa_stream ma_pa_stream;
typedef struct ma_pa_spawn_api ma_pa_spawn_api;
typedef struct
{
ma_uint32 maxlength;
ma_uint32 tlength;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
typedef void (* ma_pa_free_cb_t) (void* p);
#endif
typedef ma_pa_mainloop* (* ma_pa_mainloop_new_proc) (void);
typedef void (* ma_pa_mainloop_free_proc) (ma_pa_mainloop* m);
typedef void (* ma_pa_mainloop_quit_proc) (ma_pa_mainloop* m, int retval);
typedef ma_pa_mainloop_api* (* ma_pa_mainloop_get_api_proc) (ma_pa_mainloop* m);
typedef int (* ma_pa_mainloop_iterate_proc) (ma_pa_mainloop* m, int block, int* retval);
typedef void (* ma_pa_mainloop_wakeup_proc) (ma_pa_mainloop* m);
typedef ma_pa_threaded_mainloop* (* ma_pa_threaded_mainloop_new_proc) (void);
typedef void (* ma_pa_threaded_mainloop_free_proc) (ma_pa_threaded_mainloop* m);
typedef int (* ma_pa_threaded_mainloop_start_proc) (ma_pa_threaded_mainloop* m);
typedef void (* ma_pa_threaded_mainloop_stop_proc) (ma_pa_threaded_mainloop* m);
typedef void (* ma_pa_threaded_mainloop_lock_proc) (ma_pa_threaded_mainloop* m);
typedef void (* ma_pa_threaded_mainloop_unlock_proc) (ma_pa_threaded_mainloop* m);
typedef void (* ma_pa_threaded_mainloop_wait_proc) (ma_pa_threaded_mainloop* m);
typedef void (* ma_pa_threaded_mainloop_signal_proc) (ma_pa_threaded_mainloop* m, int wait_for_accept);
typedef void (* ma_pa_threaded_mainloop_accept_proc) (ma_pa_threaded_mainloop* m);
typedef int (* ma_pa_threaded_mainloop_get_retval_proc) (ma_pa_threaded_mainloop* m);
typedef ma_pa_mainloop_api* (* ma_pa_threaded_mainloop_get_api_proc) (ma_pa_threaded_mainloop* m);
typedef int (* ma_pa_threaded_mainloop_in_thread_proc) (ma_pa_threaded_mainloop* m);
typedef void (* ma_pa_threaded_mainloop_set_name_proc) (ma_pa_threaded_mainloop* m, const char* name);
typedef ma_pa_context* (* ma_pa_context_new_proc) (ma_pa_mainloop_api* mainloop, const char* name);
typedef void (* ma_pa_context_unref_proc) (ma_pa_context* c);
typedef int (* ma_pa_context_connect_proc) (ma_pa_context* c, const char* server, ma_pa_context_flags_t flags, const ma_pa_spawn_api* api);
typedef void (* ma_pa_context_disconnect_proc) (ma_pa_context* c);
typedef void (* ma_pa_context_set_state_callback_proc) (ma_pa_context* c, ma_pa_context_notify_cb_t cb, void* userdata);
typedef ma_pa_context_state_t (* ma_pa_context_get_state_proc) (ma_pa_context* c);
typedef ma_pa_operation* (* ma_pa_context_get_sink_info_list_proc) (ma_pa_context* c, ma_pa_sink_info_cb_t cb, void* userdata);
typedef ma_pa_operation* (* ma_pa_context_get_source_info_list_proc) (ma_pa_context* c, ma_pa_source_info_cb_t cb, void* userdata);
typedef ma_pa_operation* (* ma_pa_context_get_sink_info_by_name_proc) (ma_pa_context* c, const char* name, ma_pa_sink_info_cb_t cb, void* userdata);
typedef ma_pa_operation* (* ma_pa_context_get_source_info_by_name_proc)(ma_pa_context* c, const char* name, ma_pa_source_info_cb_t cb, void* userdata);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
if (pContext->pulse.pulseSO == NULL) {
return MA_NO_BACKEND;
}
pContext->pulse.pa_mainloop_new = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_new");
pContext->pulse.pa_mainloop_free = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_free");
pContext->pulse.pa_mainloop_quit = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_quit");
pContext->pulse.pa_mainloop_get_api = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_get_api");
pContext->pulse.pa_mainloop_iterate = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_iterate");
pContext->pulse.pa_mainloop_wakeup = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_wakeup");
pContext->pulse.pa_threaded_mainloop_new = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_new");
pContext->pulse.pa_threaded_mainloop_free = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_free");
pContext->pulse.pa_threaded_mainloop_start = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_start");
pContext->pulse.pa_threaded_mainloop_stop = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_stop");
pContext->pulse.pa_threaded_mainloop_lock = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_lock");
pContext->pulse.pa_threaded_mainloop_unlock = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_unlock");
pContext->pulse.pa_threaded_mainloop_wait = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_wait");
pContext->pulse.pa_threaded_mainloop_signal = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_signal");
pContext->pulse.pa_threaded_mainloop_accept = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_accept");
pContext->pulse.pa_threaded_mainloop_get_retval = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_get_retval");
pContext->pulse.pa_threaded_mainloop_get_api = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_get_api");
pContext->pulse.pa_threaded_mainloop_in_thread = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_in_thread");
pContext->pulse.pa_threaded_mainloop_set_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_set_name");
pContext->pulse.pa_context_new = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_new");
pContext->pulse.pa_context_unref = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_unref");
pContext->pulse.pa_context_connect = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_connect");
pContext->pulse.pa_context_disconnect = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_disconnect");
pContext->pulse.pa_context_set_state_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_set_state_callback");
pContext->pulse.pa_context_get_state = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_state");
pContext->pulse.pa_context_get_sink_info_list = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_sink_info_list");
pContext->pulse.pa_context_get_source_info_list = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_source_info_list");
pContext->pulse.pa_context_get_sink_info_by_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_sink_info_by_name");
pContext->pulse.pa_context_get_source_info_by_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_source_info_by_name");
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
pContext->pulse.pa_stream_writable_size = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_writable_size");
pContext->pulse.pa_stream_readable_size = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_readable_size");
#else
/* This strange assignment system is just for type safety. */
ma_pa_mainloop_new_proc _pa_mainloop_new = pa_mainloop_new;
ma_pa_mainloop_free_proc _pa_mainloop_free = pa_mainloop_free;
ma_pa_mainloop_quit_proc _pa_mainloop_quit = pa_mainloop_quit;
ma_pa_mainloop_get_api_proc _pa_mainloop_get_api = pa_mainloop_get_api;
ma_pa_mainloop_iterate_proc _pa_mainloop_iterate = pa_mainloop_iterate;
ma_pa_mainloop_wakeup_proc _pa_mainloop_wakeup = pa_mainloop_wakeup;
ma_pa_threaded_mainloop_new_proc _pa_threaded_mainloop_new = pa_threaded_mainloop_new;
ma_pa_threaded_mainloop_free_proc _pa_threaded_mainloop_free = pa_threaded_mainloop_free;
ma_pa_threaded_mainloop_start_proc _pa_threaded_mainloop_start = pa_threaded_mainloop_start;
ma_pa_threaded_mainloop_stop_proc _pa_threaded_mainloop_stop = pa_threaded_mainloop_stop;
ma_pa_threaded_mainloop_lock_proc _pa_threaded_mainloop_lock = pa_threaded_mainloop_lock;
ma_pa_threaded_mainloop_unlock_proc _pa_threaded_mainloop_unlock = pa_threaded_mainloop_unlock;
ma_pa_threaded_mainloop_wait_proc _pa_threaded_mainloop_wait = pa_threaded_mainloop_wait;
ma_pa_threaded_mainloop_signal_proc _pa_threaded_mainloop_signal = pa_threaded_mainloop_signal;
ma_pa_threaded_mainloop_accept_proc _pa_threaded_mainloop_accept = pa_threaded_mainloop_accept;
ma_pa_threaded_mainloop_get_retval_proc _pa_threaded_mainloop_get_retval = pa_threaded_mainloop_get_retval;
ma_pa_threaded_mainloop_get_api_proc _pa_threaded_mainloop_get_api = pa_threaded_mainloop_get_api;
ma_pa_threaded_mainloop_in_thread_proc _pa_threaded_mainloop_in_thread = pa_threaded_mainloop_in_thread;
ma_pa_threaded_mainloop_set_name_proc _pa_threaded_mainloop_set_name = pa_threaded_mainloop_set_name;
ma_pa_context_new_proc _pa_context_new = pa_context_new;
ma_pa_context_unref_proc _pa_context_unref = pa_context_unref;
ma_pa_context_connect_proc _pa_context_connect = pa_context_connect;
ma_pa_context_disconnect_proc _pa_context_disconnect = pa_context_disconnect;
ma_pa_context_set_state_callback_proc _pa_context_set_state_callback = pa_context_set_state_callback;
ma_pa_context_get_state_proc _pa_context_get_state = pa_context_get_state;
ma_pa_context_get_sink_info_list_proc _pa_context_get_sink_info_list = pa_context_get_sink_info_list;
ma_pa_context_get_source_info_list_proc _pa_context_get_source_info_list = pa_context_get_source_info_list;
ma_pa_context_get_sink_info_by_name_proc _pa_context_get_sink_info_by_name = pa_context_get_sink_info_by_name;
ma_pa_context_get_source_info_by_name_proc _pa_context_get_source_info_by_name= pa_context_get_source_info_by_name;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_pa_stream_drop_proc _pa_stream_drop = pa_stream_drop;
ma_pa_stream_writable_size_proc _pa_stream_writable_size = pa_stream_writable_size;
ma_pa_stream_readable_size_proc _pa_stream_readable_size = pa_stream_readable_size;
pContext->pulse.pa_mainloop_new = (ma_proc)_pa_mainloop_new;
pContext->pulse.pa_mainloop_free = (ma_proc)_pa_mainloop_free;
pContext->pulse.pa_mainloop_quit = (ma_proc)_pa_mainloop_quit;
pContext->pulse.pa_mainloop_get_api = (ma_proc)_pa_mainloop_get_api;
pContext->pulse.pa_mainloop_iterate = (ma_proc)_pa_mainloop_iterate;
pContext->pulse.pa_mainloop_wakeup = (ma_proc)_pa_mainloop_wakeup;
pContext->pulse.pa_threaded_mainloop_new = (ma_proc)_pa_threaded_mainloop_new;
pContext->pulse.pa_threaded_mainloop_free = (ma_proc)_pa_threaded_mainloop_free;
pContext->pulse.pa_threaded_mainloop_start = (ma_proc)_pa_threaded_mainloop_start;
pContext->pulse.pa_threaded_mainloop_stop = (ma_proc)_pa_threaded_mainloop_stop;
pContext->pulse.pa_threaded_mainloop_lock = (ma_proc)_pa_threaded_mainloop_lock;
pContext->pulse.pa_threaded_mainloop_unlock = (ma_proc)_pa_threaded_mainloop_unlock;
pContext->pulse.pa_threaded_mainloop_wait = (ma_proc)_pa_threaded_mainloop_wait;
pContext->pulse.pa_threaded_mainloop_signal = (ma_proc)_pa_threaded_mainloop_signal;
pContext->pulse.pa_threaded_mainloop_accept = (ma_proc)_pa_threaded_mainloop_accept;
pContext->pulse.pa_threaded_mainloop_get_retval = (ma_proc)_pa_threaded_mainloop_get_retval;
pContext->pulse.pa_threaded_mainloop_get_api = (ma_proc)_pa_threaded_mainloop_get_api;
pContext->pulse.pa_threaded_mainloop_in_thread = (ma_proc)_pa_threaded_mainloop_in_thread;
pContext->pulse.pa_threaded_mainloop_set_name = (ma_proc)_pa_threaded_mainloop_set_name;
pContext->pulse.pa_context_new = (ma_proc)_pa_context_new;
pContext->pulse.pa_context_unref = (ma_proc)_pa_context_unref;
pContext->pulse.pa_context_connect = (ma_proc)_pa_context_connect;
pContext->pulse.pa_context_disconnect = (ma_proc)_pa_context_disconnect;
pContext->pulse.pa_context_set_state_callback = (ma_proc)_pa_context_set_state_callback;
pContext->pulse.pa_context_get_state = (ma_proc)_pa_context_get_state;
pContext->pulse.pa_context_get_sink_info_list = (ma_proc)_pa_context_get_sink_info_list;
pContext->pulse.pa_context_get_source_info_list = (ma_proc)_pa_context_get_source_info_list;
pContext->pulse.pa_context_get_sink_info_by_name = (ma_proc)_pa_context_get_sink_info_by_name;
pContext->pulse.pa_context_get_source_info_by_name = (ma_proc)_pa_context_get_source_info_by_name;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
/*
Technical Note TN2091: Device input using the HAL Output Audio Unit
https://developer.apple.com/library/archive/technotes/tn2091/_index.html
This documentation says the following:
The internal AudioConverter can handle any *simple* conversion. Typically, this means that a client can specify ANY
variant of the PCM formats. Consequently, the device's sample rate should match the desired sample rate. If sample rate
conversion is needed, it can be accomplished by buffering the input and converting the data on a separate thread with
another AudioConverter.
The important part here is the mention that it can handle *simple* conversions, which does *not* include sample rate. We
therefore want to ensure the sample rate stays consistent. This document is specifically for input, but I'm going to play it
safe and apply the same rule to output as well.
I have tried going against the documentation by setting the sample rate anyway, but this just results in AudioUnitRender()
returning a result code of -10863. I have also tried changing the format directly on the input scope on the input bus, but
this just results in `ca_require: IsStreamFormatWritable(inScope, inElement) NotWritable` when trying to set the format.
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
*/
if (pDescriptorPlayback->pDeviceID == NULL && (pConfig->deviceType != ma_device_type_duplex || pDescriptorCapture->pDeviceID != NULL)) {
ma_device__track__coreaudio(pDevice);
}
#endif
}
/*
When stopping the device, a callback is called on another thread. We need to wait for this callback
before returning from ma_device_stop(). This event is used for this.
*/
ma_event_init(&pDevice->coreaudio.stopEvent);
/*
We need to detect when a route has changed so we can update the data conversion pipeline accordingly. This is done
differently on non-Desktop Apple platforms.
*/
#if defined(MA_APPLE_MOBILE)
pDevice->coreaudio.pNotificationHandler = (MA_BRIDGE_RETAINED void*)[[ma_ios_notification_handler alloc] init:pDevice];
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
{
ma_device* pDevice = (ma_device*)pUserData;
MA_ASSERT(pDevice != NULL);
(void)error;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] ERROR CALLBACK: error=%d, AAudioStream_getState()=%d\n", error, ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream));
/*
From the documentation for AAudio, when a device is disconnected all we can do is stop it. However, we cannot stop it from the callback - we need
to do it from another thread. Therefore we are going to use an event thread for the AAudio backend to do this cleanly and safely.
*/
if (((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream) == MA_AAUDIO_STREAM_STATE_DISCONNECTED) {
/* We need to post a job to the job thread for processing. This will reroute the device by reinitializing the stream. */
ma_result result;
ma_job job = ma_job_init(MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE);
job.data.device.aaudio.reroute.pDevice = pDevice;
if (pStream == pDevice->aaudio.pStreamCapture) {
job.data.device.aaudio.reroute.deviceType = ma_device_type_capture;
} else {
job.data.device.aaudio.reroute.deviceType = ma_device_type_playback;
}
result = ma_device_job_thread_post(&pDevice->pContext->aaudio.jobThread, &job);
if (result != MA_SUCCESS) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Device Disconnected. Failed to post job for rerouting.\n");
return;
}
}
}
static ma_aaudio_data_callback_result_t ma_stream_data_callback_capture__aaudio(ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t frameCount)
{
ma_device* pDevice = (ma_device*)pUserData;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
return MA_SUCCESS;
}
static ma_result ma_context_uninit__aaudio(ma_context* pContext)
{
MA_ASSERT(pContext != NULL);
MA_ASSERT(pContext->backend == ma_backend_aaudio);
ma_device_job_thread_uninit(&pContext->aaudio.jobThread, &pContext->allocationCallbacks);
ma_dlclose(pContext, pContext->aaudio.hAAudio);
pContext->aaudio.hAAudio = NULL;
return MA_SUCCESS;
}
static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
{
size_t i;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
pCallbacks->onDeviceInit = ma_device_init__aaudio;
pCallbacks->onDeviceUninit = ma_device_uninit__aaudio;
pCallbacks->onDeviceStart = ma_device_start__aaudio;
pCallbacks->onDeviceStop = ma_device_stop__aaudio;
pCallbacks->onDeviceRead = NULL; /* Not used because AAudio is asynchronous. */
pCallbacks->onDeviceWrite = NULL; /* Not used because AAudio is asynchronous. */
pCallbacks->onDeviceDataLoop = NULL; /* Not used because AAudio is asynchronous. */
pCallbacks->onDeviceGetInfo = ma_device_get_info__aaudio;
/* We need a job thread so we can deal with rerouting. */
{
ma_result result;
ma_device_job_thread_config jobThreadConfig;
jobThreadConfig = ma_device_job_thread_config_init();
result = ma_device_job_thread_init(&jobThreadConfig, &pContext->allocationCallbacks, &pContext->aaudio.jobThread);
if (result != MA_SUCCESS) {
ma_dlclose(pContext, pContext->aaudio.hAAudio);
pContext->aaudio.hAAudio = NULL;
return result;
}
}
(void)pConfig;
return MA_SUCCESS;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
}
}
}
/* Update data conversion. */
return ma_device__post_init_setup(pDevice, deviceType); /* TODO: Should probably rename ma_device__post_init_setup() to something better. */
}
static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData)
{
ma_device* pDevice = (ma_device*)pData;
MA_ASSERT(pDevice != NULL);
#ifdef MA_WIN32
ma_CoInitializeEx(pDevice->pContext, NULL, MA_COINIT_VALUE);
#endif
/*
When the device is being initialized it's initial state is set to ma_device_state_uninitialized. Before returning from
ma_device_init(), the state needs to be set to something valid. In miniaudio the device's default state immediately
after initialization is stopped, so therefore we need to mark the device as such. miniaudio will wait on the worker
thread to signal an event to know when the worker thread is ready for action.
*/
ma_device__set_state(pDevice, ma_device_state_stopped);
ma_event_signal(&pDevice->stopEvent);
for (;;) { /* <-- This loop just keeps the thread alive. The main audio loop is inside. */
ma_result startResult;
ma_result stopResult; /* <-- This will store the result from onDeviceStop(). If it returns an error, we don't fire the stopped notification callback. */
/* We wait on an event to know when something has requested that the device be started and the main loop entered. */
ma_event_wait(&pDevice->wakeupEvent);
/* Default result code. */
pDevice->workResult = MA_SUCCESS;
/* If the reason for the wake up is that we are terminating, just break from the loop. */
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
/* Make sure the state is set appropriately. */
ma_device__set_state(pDevice, ma_device_state_started); /* <-- Set this before signaling the event so that the state is always guaranteed to be good after ma_device_start() has returned. */
ma_event_signal(&pDevice->startEvent);
ma_device__on_notification_started(pDevice);
if (pDevice->pContext->callbacks.onDeviceDataLoop != NULL) {
pDevice->pContext->callbacks.onDeviceDataLoop(pDevice);
} else {
/* The backend is not using a custom main loop implementation, so now fall back to the blocking read-write implementation. */
ma_device_audio_thread__default_read_write(pDevice);
}
/* Getting here means we have broken from the main loop which happens the application has requested that device be stopped. */
if (pDevice->pContext->callbacks.onDeviceStop != NULL) {
stopResult = pDevice->pContext->callbacks.onDeviceStop(pDevice);
} else {
stopResult = MA_SUCCESS; /* No stop callback with the backend. Just assume successful. */
}
/*
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
/* A function somewhere is waiting for the device to have stopped for real so we need to signal an event to allow it to continue. */
ma_device__set_state(pDevice, ma_device_state_stopped);
ma_event_signal(&pDevice->stopEvent);
}
#ifdef MA_WIN32
ma_CoUninitialize(pDevice->pContext);
#endif
return (ma_thread_result)0;
}
/* Helper for determining whether or not the given device is initialized. */
static ma_bool32 ma_device__is_initialized(ma_device* pDevice)
{
if (pDevice == NULL) {
return MA_FALSE;
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegQueryValueExA");
#endif
ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE);
return MA_SUCCESS;
}
#else
static ma_result ma_context_uninit_backend_apis__nix(ma_context* pContext)
{
#if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING)
ma_dlclose(pContext, pContext->posix.pthreadSO);
#else
(void)pContext;
#endif
return MA_SUCCESS;
}
static ma_result ma_context_init_backend_apis__nix(ma_context* pContext)
{
/* pthread */
#if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING)
const char* libpthreadFileNames[] = {
"libpthread.so",
"libpthread.so.0",
"libpthread.dylib"
};
size_t i;
for (i = 0; i < sizeof(libpthreadFileNames) / sizeof(libpthreadFileNames[0]); ++i) {
pContext->posix.pthreadSO = ma_dlopen(pContext, libpthreadFileNames[i]);
if (pContext->posix.pthreadSO != NULL) {
break;
}
}
if (pContext->posix.pthreadSO == NULL) {
return MA_FAILED_TO_INIT_BACKEND;
}
pContext->posix.pthread_create = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_create");
pContext->posix.pthread_join = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_join");
pContext->posix.pthread_mutex_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_init");
pContext->posix.pthread_mutex_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_destroy");
pContext->posix.pthread_mutex_lock = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_lock");
pContext->posix.pthread_mutex_unlock = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_unlock");
pContext->posix.pthread_cond_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_init");
pContext->posix.pthread_cond_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_destroy");
pContext->posix.pthread_cond_wait = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_wait");
pContext->posix.pthread_cond_signal = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_signal");
pContext->posix.pthread_attr_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_init");
pContext->posix.pthread_attr_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_destroy");
pContext->posix.pthread_attr_setschedpolicy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedpolicy");
pContext->posix.pthread_attr_getschedparam = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_getschedparam");
pContext->posix.pthread_attr_setschedparam = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedparam");
#else
pContext->posix.pthread_create = (ma_proc)pthread_create;
pContext->posix.pthread_join = (ma_proc)pthread_join;
pContext->posix.pthread_mutex_init = (ma_proc)pthread_mutex_init;
pContext->posix.pthread_mutex_destroy = (ma_proc)pthread_mutex_destroy;
pContext->posix.pthread_mutex_lock = (ma_proc)pthread_mutex_lock;
pContext->posix.pthread_mutex_unlock = (ma_proc)pthread_mutex_unlock;
pContext->posix.pthread_cond_init = (ma_proc)pthread_cond_init;
pContext->posix.pthread_cond_destroy = (ma_proc)pthread_cond_destroy;
pContext->posix.pthread_cond_wait = (ma_proc)pthread_cond_wait;
pContext->posix.pthread_cond_signal = (ma_proc)pthread_cond_signal;
pContext->posix.pthread_attr_init = (ma_proc)pthread_attr_init;
pContext->posix.pthread_attr_destroy = (ma_proc)pthread_attr_destroy;
#if !defined(__EMSCRIPTEN__)
pContext->posix.pthread_attr_setschedpolicy = (ma_proc)pthread_attr_setschedpolicy;
pContext->posix.pthread_attr_getschedparam = (ma_proc)pthread_attr_getschedparam;
pContext->posix.pthread_attr_setschedparam = (ma_proc)pthread_attr_setschedparam;
#endif
#endif
return MA_SUCCESS;
}
#endif
static ma_result ma_context_init_backend_apis(ma_context* pContext)
{
ma_result result;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
return MA_FALSE;
}
}
/* The default capacity doesn't need to be too big. */
#ifndef MA_DEFAULT_DEVICE_JOB_QUEUE_CAPACITY
#define MA_DEFAULT_DEVICE_JOB_QUEUE_CAPACITY 32
#endif
MA_API ma_device_job_thread_config ma_device_job_thread_config_init(void)
{
ma_device_job_thread_config config;
MA_ZERO_OBJECT(&config);
config.noThread = MA_FALSE;
config.jobQueueCapacity = MA_DEFAULT_DEVICE_JOB_QUEUE_CAPACITY;
config.jobQueueFlags = 0;
return config;
}
static ma_thread_result MA_THREADCALL ma_device_job_thread_entry(void* pUserData)
{
ma_device_job_thread* pJobThread = (ma_device_job_thread*)pUserData;
MA_ASSERT(pJobThread != NULL);
for (;;) {
ma_result result;
ma_job job;
result = ma_device_job_thread_next(pJobThread, &job);
if (result != MA_SUCCESS) {
break;
}
if (job.toc.breakup.code == MA_JOB_TYPE_QUIT) {
break;
}
ma_job_process(&job);
}
return (ma_thread_result)0;
}
MA_API ma_result ma_device_job_thread_init(const ma_device_job_thread_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_device_job_thread* pJobThread)
{
ma_result result;
ma_job_queue_config jobQueueConfig;
if (pJobThread == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pJobThread);
if (pConfig == NULL) {
return MA_INVALID_ARGS;
}
/* Initialize the job queue before the thread to ensure it's in a valid state. */
jobQueueConfig = ma_job_queue_config_init(pConfig->jobQueueFlags, pConfig->jobQueueCapacity);
result = ma_job_queue_init(&jobQueueConfig, pAllocationCallbacks, &pJobThread->jobQueue);
if (result != MA_SUCCESS) {
return result; /* Failed to initialize job queue. */
}
/* The thread needs to be initialized after the job queue to ensure the thread doesn't try to access it prematurely. */
if (pConfig->noThread == MA_FALSE) {
result = ma_thread_create(&pJobThread->thread, ma_thread_priority_normal, 0, ma_device_job_thread_entry, pJobThread, pAllocationCallbacks);
if (result != MA_SUCCESS) {
ma_job_queue_uninit(&pJobThread->jobQueue, pAllocationCallbacks);
return result; /* Failed to create the job thread. */
}
pJobThread->_hasThread = MA_TRUE;
} else {
pJobThread->_hasThread = MA_FALSE;
}
return MA_SUCCESS;
}
MA_API void ma_device_job_thread_uninit(ma_device_job_thread* pJobThread, const ma_allocation_callbacks* pAllocationCallbacks)
{
if (pJobThread == NULL) {
return;
}
/* The first thing to do is post a quit message to the job queue. If we're using a thread we'll need to wait for it. */
{
ma_job job = ma_job_init(MA_JOB_TYPE_QUIT);
ma_device_job_thread_post(pJobThread, &job);
}
/* Wait for the thread to terminate naturally. */
if (pJobThread->_hasThread) {
ma_thread_wait(&pJobThread->thread);
}
/* At this point the thread should be terminated so we can safely uninitialize the job queue. */
ma_job_queue_uninit(&pJobThread->jobQueue, pAllocationCallbacks);
}
MA_API ma_result ma_device_job_thread_post(ma_device_job_thread* pJobThread, const ma_job* pJob)
{
if (pJobThread == NULL || pJob == NULL) {
return MA_INVALID_ARGS;
}
return ma_job_queue_post(&pJobThread->jobQueue, pJob);
}
MA_API ma_result ma_device_job_thread_next(ma_device_job_thread* pJobThread, ma_job* pJob)
{
if (pJob == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pJob);
if (pJobThread == NULL) {
return MA_INVALID_ARGS;
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
pContext->pLog = pConfig->pLog;
} else {
result = ma_log_init(&pContext->allocationCallbacks, &pContext->log);
if (result == MA_SUCCESS) {
pContext->pLog = &pContext->log;
} else {
pContext->pLog = NULL; /* Logging is not available. */
}
}
pContext->threadPriority = pConfig->threadPriority;
pContext->threadStackSize = pConfig->threadStackSize;
pContext->pUserData = pConfig->pUserData;
/* Backend APIs need to be initialized first. This is where external libraries will be loaded and linked. */
result = ma_context_init_backend_apis(pContext);
if (result != MA_SUCCESS) {
return result;
}
for (iBackend = 0; iBackend <= ma_backend_null; ++iBackend) {
defaultBackends[iBackend] = (ma_backend)iBackend;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Attempting to initialize %s backend...\n", ma_get_backend_name(backend));
result = pContext->callbacks.onContextInit(pContext, pConfig, &pContext->callbacks);
} else {
result = MA_NO_BACKEND;
}
/* If this iteration was successful, return. */
if (result == MA_SUCCESS) {
result = ma_mutex_init(&pContext->deviceEnumLock);
if (result != MA_SUCCESS) {
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device enumeration. ma_context_get_devices() is not thread safe.\n");
}
result = ma_mutex_init(&pContext->deviceInfoLock);
if (result != MA_SUCCESS) {
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device info retrieval. ma_context_get_device_info() is not thread safe.\n");
}
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "System Architecture:\n");
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " Endian: %s\n", ma_is_little_endian() ? "LE" : "BE");
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " SSE2: %s\n", ma_has_sse2() ? "YES" : "NO");
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " AVX2: %s\n", ma_has_avx2() ? "YES" : "NO");
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " NEON: %s\n", ma_has_neon() ? "YES" : "NO");
pContext->backend = backend;
return result;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_channel_map_copy_or_default(pDevice->playback.channelMap, ma_countof(pDevice->playback.channelMap), pConfig->playback.pChannelMap, pConfig->playback.channels);
pDevice->playback.channelMixMode = pConfig->playback.channelMixMode;
result = ma_mutex_init(&pDevice->startStopLock);
if (result != MA_SUCCESS) {
return result;
}
/*
When the device is started, the worker thread is the one that does the actual startup of the backend device. We
use a semaphore to wait for the background thread to finish the work. The same applies for stopping the device.
Each of these semaphores is released internally by the worker thread when the work is completed. The start
semaphore is also used to wake up the worker thread.
*/
result = ma_event_init(&pDevice->wakeupEvent);
if (result != MA_SUCCESS) {
ma_mutex_uninit(&pDevice->startStopLock);
return result;
}
result = ma_event_init(&pDevice->startEvent);
if (result != MA_SUCCESS) {
ma_event_uninit(&pDevice->wakeupEvent);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
/* Silence the buffer for safety. */
ma_silence_pcm_frames(pDevice->playback.pIntermediaryBuffer, pDevice->playback.intermediaryBufferCap, pDevice->playback.format, pDevice->playback.channels);
pDevice->playback.intermediaryBufferLen = 0;
}
} else {
/* Not using a fixed sized data callback so no need for an intermediary buffer. */
}
/* Some backends don't require the worker thread. */
if (!ma_context_is_backend_asynchronous(pContext)) {
/* The worker thread. */
result = ma_thread_create(&pDevice->thread, pContext->threadPriority, pContext->threadStackSize, ma_worker_thread, pDevice, &pContext->allocationCallbacks);
if (result != MA_SUCCESS) {
ma_device_uninit(pDevice);
return result;
}
/* Wait for the worker thread to put the device into it's stopped state for real. */
ma_event_wait(&pDevice->stopEvent);
MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_stopped);
} else {
/*
If the backend is asynchronous and the device is duplex, we'll need an intermediary ring buffer. Note that this needs to be done
after ma_device__post_init_setup().
*/
if (ma_context_is_backend_asynchronous(pContext)) {
if (pConfig->deviceType == ma_device_type_duplex) {
result = ma_duplex_rb_init(pDevice->capture.format, pDevice->capture.channels, pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames, &pDevice->pContext->allocationCallbacks, &pDevice->d...
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
{
if (!ma_device__is_initialized(pDevice)) {
return;
}
/* Make sure the device is stopped first. The backends will probably handle this naturally, but I like to do it explicitly for my own sanity. */
if (ma_device_is_started(pDevice)) {
ma_device_stop(pDevice);
}
/* Putting the device into an uninitialized state will make the worker thread return. */
ma_device__set_state(pDevice, ma_device_state_uninitialized);
/* Wake up the worker thread and wait for it to properly terminate. */
if (!ma_context_is_backend_asynchronous(pDevice->pContext)) {
ma_event_signal(&pDevice->wakeupEvent);
ma_thread_wait(&pDevice->thread);
}
if (pDevice->pContext->callbacks.onDeviceUninit != NULL) {
pDevice->pContext->callbacks.onDeviceUninit(pDevice);
}
ma_event_uninit(&pDevice->stopEvent);
ma_event_uninit(&pDevice->startEvent);
ma_event_uninit(&pDevice->wakeupEvent);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
} else {
result = MA_INVALID_OPERATION;
}
if (result == MA_SUCCESS) {
ma_device__set_state(pDevice, ma_device_state_started);
ma_device__on_notification_started(pDevice);
}
} else {
/*
Synchronous backends are started by signaling an event that's being waited on in the worker thread. We first wake up the
thread and then wait for the start event.
*/
ma_event_signal(&pDevice->wakeupEvent);
/*
Wait for the worker thread to finish starting the device. Note that the worker thread will be the one who puts the device
into the started state. Don't call ma_device__set_state() here.
*/
ma_event_wait(&pDevice->startEvent);
result = pDevice->workResult;
}
/* We changed the state from stopped to started, so if we failed, make sure we put the state back to stopped. */
if (result != MA_SUCCESS) {
ma_device__set_state(pDevice, ma_device_state_stopped);
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
/* Asynchronous backends must have a stop operation. */
if (pDevice->pContext->callbacks.onDeviceStop != NULL) {
result = pDevice->pContext->callbacks.onDeviceStop(pDevice);
} else {
result = MA_INVALID_OPERATION;
}
ma_device__set_state(pDevice, ma_device_state_stopped);
} else {
/*
Synchronous backends. The stop callback is always called from the worker thread. Do not call the stop callback here. If
the backend is implementing it's own audio thread loop we'll need to wake it up if required. Note that we need to make
sure the state of the device is *not* playing right now, which it shouldn't be since we set it above. This is super
important though, so I'm asserting it here as well for extra safety in case we accidentally change something later.
*/
MA_ASSERT(ma_device_get_state(pDevice) != ma_device_state_started);
if (pDevice->pContext->callbacks.onDeviceDataLoopWakeup != NULL) {
pDevice->pContext->callbacks.onDeviceDataLoopWakeup(pDevice);
}
/*
We need to wait for the worker thread to become available for work before returning. Note that the worker thread will be
the one who puts the device into the stopped state. Don't call ma_device__set_state() here.
*/
ma_event_wait(&pDevice->stopEvent);
result = MA_SUCCESS;
}
}
ma_mutex_unlock(&pDevice->startStopLock);
return result;
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
static ma_result ma_resource_manager_data_buffer_node_result(const ma_resource_manager_data_buffer_node* pDataBufferNode)
{
MA_ASSERT(pDataBufferNode != NULL);
return (ma_result)c89atomic_load_i32((ma_result*)&pDataBufferNode->result); /* Need a naughty const-cast here. */
}
static ma_bool32 ma_resource_manager_is_threading_enabled(const ma_resource_manager* pResourceManager)
{
MA_ASSERT(pResourceManager != NULL);
return (pResourceManager->config.flags & MA_RESOURCE_MANAGER_FLAG_NO_THREADING) == 0;
}
typedef struct
{
union
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_resource_manager* pResourceManager;
} ma_resource_manager_inline_notification;
static ma_result ma_resource_manager_inline_notification_init(ma_resource_manager* pResourceManager, ma_resource_manager_inline_notification* pNotification)
{
MA_ASSERT(pResourceManager != NULL);
MA_ASSERT(pNotification != NULL);
pNotification->pResourceManager = pResourceManager;
if (ma_resource_manager_is_threading_enabled(pResourceManager)) {
return ma_async_notification_event_init(&pNotification->backend.e);
} else {
return ma_async_notification_poll_init(&pNotification->backend.p);
}
}
static void ma_resource_manager_inline_notification_uninit(ma_resource_manager_inline_notification* pNotification)
{
MA_ASSERT(pNotification != NULL);
if (ma_resource_manager_is_threading_enabled(pNotification->pResourceManager)) {
ma_async_notification_event_uninit(&pNotification->backend.e);
} else {
/* No need to uninitialize a polling notification. */
}
}
static void ma_resource_manager_inline_notification_wait(ma_resource_manager_inline_notification* pNotification)
{
MA_ASSERT(pNotification != NULL);
if (ma_resource_manager_is_threading_enabled(pNotification->pResourceManager)) {
ma_async_notification_event_wait(&pNotification->backend.e);
} else {
while (ma_async_notification_poll_is_signalled(&pNotification->backend.p) == MA_FALSE) {
ma_result result = ma_resource_manager_process_next_job(pNotification->pResourceManager);
if (result == MA_NO_DATA_AVAILABLE || result == MA_CANCELLED) {
break;
}
}
}
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
{
ma_resource_manager_inline_notification_wait(pNotification);
ma_resource_manager_inline_notification_uninit(pNotification);
}
static void ma_resource_manager_data_buffer_bst_lock(ma_resource_manager* pResourceManager)
{
MA_ASSERT(pResourceManager != NULL);
if (ma_resource_manager_is_threading_enabled(pResourceManager)) {
#ifndef MA_NO_THREADING
{
ma_mutex_lock(&pResourceManager->dataBufferBSTLock);
}
#else
{
MA_ASSERT(MA_FALSE); /* Should never hit this. */
}
#endif
} else {
/* Threading not enabled. Do nothing. */
}
}
static void ma_resource_manager_data_buffer_bst_unlock(ma_resource_manager* pResourceManager)
{
MA_ASSERT(pResourceManager != NULL);
if (ma_resource_manager_is_threading_enabled(pResourceManager)) {
#ifndef MA_NO_THREADING
{
ma_mutex_unlock(&pResourceManager->dataBufferBSTLock);
}
#else
{
MA_ASSERT(MA_FALSE); /* Should never hit this. */
}
#endif
} else {
/* Threading not enabled. Do nothing. */
}
}
#ifndef MA_NO_THREADING
static ma_thread_result MA_THREADCALL ma_resource_manager_job_thread(void* pUserData)
{
ma_resource_manager* pResourceManager = (ma_resource_manager*)pUserData;
MA_ASSERT(pResourceManager != NULL);
for (;;) {
ma_result result;
ma_job job;
result = ma_resource_manager_next_job(pResourceManager, &job);
if (result != MA_SUCCESS) {
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
/* Terminate if we got a quit message. */
if (job.toc.breakup.code == MA_JOB_TYPE_QUIT) {
break;
}
ma_job_process(&job);
}
return (ma_thread_result)0;
}
#endif
MA_API ma_resource_manager_config ma_resource_manager_config_init(void)
{
ma_resource_manager_config config;
MA_ZERO_OBJECT(&config);
config.decodedFormat = ma_format_unknown;
config.decodedChannels = 0;
config.decodedSampleRate = 0;
config.jobThreadCount = 1; /* A single miniaudio-managed job thread by default. */
config.jobQueueCapacity = MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_CAPACITY;
/* Flags. */
config.flags = 0;
#ifdef MA_NO_THREADING
{
/* Threading is disabled at compile time so disable threading at runtime as well by default. */
config.flags |= MA_RESOURCE_MANAGER_FLAG_NO_THREADING;
config.jobThreadCount = 0;
}
#endif
return config;
}
MA_API ma_result ma_resource_manager_init(const ma_resource_manager_config* pConfig, ma_resource_manager* pResourceManager)
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
MA_ZERO_OBJECT(pResourceManager);
if (pConfig == NULL) {
return MA_INVALID_ARGS;
}
#ifndef MA_NO_THREADING
{
if (pConfig->jobThreadCount > ma_countof(pResourceManager->jobThreads)) {
return MA_INVALID_ARGS; /* Requesting too many job threads. */
}
}
#endif
pResourceManager->config = *pConfig;
ma_allocation_callbacks_init_copy(&pResourceManager->config.allocationCallbacks, &pConfig->allocationCallbacks);
/* Get the log set up early so we can start using it as soon as possible. */
if (pResourceManager->config.pLog == NULL) {
result = ma_log_init(&pResourceManager->config.allocationCallbacks, &pResourceManager->log);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
if (pResourceManager->config.pVFS == NULL) {
result = ma_default_vfs_init(&pResourceManager->defaultVFS, &pResourceManager->config.allocationCallbacks);
if (result != MA_SUCCESS) {
return result; /* Failed to initialize the default file system. */
}
pResourceManager->config.pVFS = &pResourceManager->defaultVFS;
}
/* If threading has been disabled at compile time, enfore it at run time as well. */
#ifdef MA_NO_THREADING
{
pResourceManager->config.flags |= MA_RESOURCE_MANAGER_FLAG_NO_THREADING;
}
#endif
/* We need to force MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING if MA_RESOURCE_MANAGER_FLAG_NO_THREADING is set. */
if ((pResourceManager->config.flags & MA_RESOURCE_MANAGER_FLAG_NO_THREADING) != 0) {
pResourceManager->config.flags |= MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING;
/* We cannot allow job threads when MA_RESOURCE_MANAGER_FLAG_NO_THREADING has been set. This is an invalid use case. */
if (pResourceManager->config.jobThreadCount > 0) {
return MA_INVALID_ARGS;
}
}
/* Job queue. */
jobQueueConfig.capacity = pResourceManager->config.jobQueueCapacity;
jobQueueConfig.flags = 0;
if ((pResourceManager->config.flags & MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING) != 0) {
if (pResourceManager->config.jobThreadCount > 0) {
return MA_INVALID_ARGS; /* Non-blocking mode is only valid for self-managed job threads. */
}
jobQueueConfig.flags |= MA_JOB_QUEUE_FLAG_NON_BLOCKING;
}
result = ma_job_queue_init(&jobQueueConfig, &pResourceManager->config.allocationCallbacks, &pResourceManager->jobQueue);
if (result != MA_SUCCESS) {
return result;
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
MA_COPY_MEMORY(pResourceManager->config.ppCustomDecodingBackendVTables, pConfig->ppCustomDecodingBackendVTables, sizeInBytes);
pResourceManager->config.customDecodingBackendCount = pConfig->customDecodingBackendCount;
pResourceManager->config.pCustomDecodingBackendUserData = pConfig->pCustomDecodingBackendUserData;
}
/* Here is where we initialize our threading stuff. We don't do this if we don't support threading. */
if (ma_resource_manager_is_threading_enabled(pResourceManager)) {
#ifndef MA_NO_THREADING
{
ma_uint32 iJobThread;
/* Data buffer lock. */
result = ma_mutex_init(&pResourceManager->dataBufferBSTLock);
if (result != MA_SUCCESS) {
ma_job_queue_uninit(&pResourceManager->jobQueue, &pResourceManager->config.allocationCallbacks);
return result;
}
/* Create the job threads last to ensure the threads has access to valid data. */
for (iJobThread = 0; iJobThread < pResourceManager->config.jobThreadCount; iJobThread += 1) {
result = ma_thread_create(&pResourceManager->jobThreads[iJobThread], ma_thread_priority_normal, 0, ma_resource_manager_job_thread, pResourceManager, &pResourceManager->config.allocationCallbacks);
if (result != MA_SUCCESS) {
ma_mutex_uninit(&pResourceManager->dataBufferBSTLock);
ma_job_queue_uninit(&pResourceManager->jobQueue, &pResourceManager->config.allocationCallbacks);
return result;
}
}
}
#else
{
/* Threading is disabled at compile time. We should never get here because validation checks should have already been performed. */
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
}
MA_API void ma_resource_manager_uninit(ma_resource_manager* pResourceManager)
{
if (pResourceManager == NULL) {
return;
}
/*
Job threads need to be killed first. To do this we need to post a quit message to the message queue and then wait for the thread. The quit message will never be removed from the
queue which means it will never not be returned after being encounted for the first time which means all threads will eventually receive it.
*/
ma_resource_manager_post_job_quit(pResourceManager);
/* Wait for every job to finish before continuing to ensure nothing is sill trying to access any of our objects below. */
if (ma_resource_manager_is_threading_enabled(pResourceManager)) {
#ifndef MA_NO_THREADING
{
ma_uint32 iJobThread;
for (iJobThread = 0; iJobThread < pResourceManager->config.jobThreadCount; iJobThread += 1) {
ma_thread_wait(&pResourceManager->jobThreads[iJobThread]);
}
}
#else
{
MA_ASSERT(MA_FALSE); /* Should never hit this. */
}
#endif
}
/* At this point the thread should have returned and no other thread should be accessing our data. We can now delete all data buffers. */
ma_resource_manager_delete_all_data_buffer_nodes(pResourceManager);
/* The job queue is no longer needed. */
ma_job_queue_uninit(&pResourceManager->jobQueue, &pResourceManager->config.allocationCallbacks);
/* We're no longer doing anything with data buffers so the lock can now be uninitialized. */
if (ma_resource_manager_is_threading_enabled(pResourceManager)) {
#ifndef MA_NO_THREADING
{
ma_mutex_uninit(&pResourceManager->dataBufferBSTLock);
}
#else
{
MA_ASSERT(MA_FALSE); /* Should never hit this. */
}
#endif
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
if (result != MA_SUCCESS) {
return result; /* Should never happen. Failed to increment the reference count. */
}
result = MA_ALREADY_EXISTS;
goto done;
} else {
/*
The node does not already exist. We need to post a LOAD_DATA_BUFFER_NODE job here. This
needs to be done inside the critical section to ensure an uninitialization of the node
does not occur before initialization on another thread.
*/
pDataBufferNode = (ma_resource_manager_data_buffer_node*)ma_malloc(sizeof(*pDataBufferNode), &pResourceManager->config.allocationCallbacks);
if (pDataBufferNode == NULL) {
return MA_OUT_OF_MEMORY;
}
MA_ZERO_OBJECT(pDataBufferNode);
pDataBufferNode->hashedName32 = hashedName32;
pDataBufferNode->refCount = 1; /* Always set to 1 by default (this is our first reference). */
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
if (pFilePathCopy == NULL && pFilePathWCopy == NULL) {
ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode);
ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks);
return MA_OUT_OF_MEMORY;
}
if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) {
ma_resource_manager_inline_notification_init(pResourceManager, pInitNotification);
}
/* Acquire init and done fences before posting the job. These will be unacquired by the job thread. */
if (pInitFence != NULL) { ma_fence_acquire(pInitFence); }
if (pDoneFence != NULL) { ma_fence_acquire(pDoneFence); }
/* We now have everything we need to post the job to the job thread. */
job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE);
job.order = ma_resource_manager_data_buffer_node_next_execution_order(pDataBufferNode);
job.data.resourceManager.loadDataBufferNode.pResourceManager = pResourceManager;
job.data.resourceManager.loadDataBufferNode.pDataBufferNode = pDataBufferNode;
job.data.resourceManager.loadDataBufferNode.pFilePath = pFilePathCopy;
job.data.resourceManager.loadDataBufferNode.pFilePathW = pFilePathWCopy;
job.data.resourceManager.loadDataBufferNode.flags = flags;
job.data.resourceManager.loadDataBufferNode.pInitNotification = ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) ? pInitNotification : NULL;
job.data.resourceManager.loadDataBufferNode.pDoneNotification = NULL;
job.data.resourceManager.loadDataBufferNode.pInitFence = pInitFence;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
if (pResourceManager == NULL || (pFilePath == NULL && pFilePathW == NULL && hashedName32 == 0)) {
return MA_INVALID_ARGS;
}
/* If we're specifying existing data, it must be valid. */
if (pExistingData != NULL && pExistingData->type == ma_resource_manager_data_supply_type_unknown) {
return MA_INVALID_ARGS;
}
/* If we don't support threading, remove the ASYNC flag to make the rest of this a bit simpler. */
if (ma_resource_manager_is_threading_enabled(pResourceManager) == MA_FALSE) {
flags &= ~MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC;
}
if (hashedName32 == 0) {
if (pFilePath != NULL) {
hashedName32 = ma_hash_string_32(pFilePath);
} else {
hashedName32 = ma_hash_string_w_32(pFilePathW);
}
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
} else {
if (result != MA_SUCCESS) {
return result;
}
}
/*
If we're loading synchronously, we'll need to load everything now. When loading asynchronously,
a job will have been posted inside the BST critical section so that an uninitialization can be
allocated an appropriate execution order thereby preventing it from being uninitialized before
the node is initialized by the decoding thread(s).
*/
if (nodeAlreadyExists == MA_FALSE) { /* Don't need to try loading anything if the node already exists. */
if (pFilePath == NULL && pFilePathW == NULL) {
/*
If this path is hit, it means a buffer is being copied (i.e. initialized from only the
hashed name), but that node has been freed in the meantime, probably from some other
thread. This is an invalid operation.
*/
ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Cloning data buffer node failed because the source node was released. The source node must remain valid until the cloning has completed.\n");
result = MA_INVALID_OPERATION;
goto done;
}
if (pDataBufferNode->isDataOwnedByResourceManager) {
if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) == 0) {
/* Loading synchronously. Load the sound in it's entirety here. */
if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE) == 0) {
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
ma_resource_manager_data_buffer_bst_unlock(pResourceManager);
stage2:
if (result != MA_SUCCESS) {
return result;
}
/*
Here is where we need to free the node. We don't want to do this inside the critical section
above because we want to keep that as small as possible for multi-threaded efficiency.
*/
if (refCount == 0) {
if (ma_resource_manager_data_buffer_node_result(pDataBufferNode) == MA_BUSY) {
/* The sound is still loading. We need to delay the freeing of the node to a safe time. */
ma_job job;
/* We need to mark the node as unavailable for the sake of the resource manager worker threads. */
c89atomic_exchange_i32(&pDataBufferNode->result, MA_UNAVAILABLE);
job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER_NODE);
job.order = ma_resource_manager_data_buffer_node_next_execution_order(pDataBufferNode);
job.data.resourceManager.freeDataBufferNode.pResourceManager = pResourceManager;
job.data.resourceManager.freeDataBufferNode.pDataBufferNode = pDataBufferNode;
result = ma_resource_manager_post_job(pResourceManager, &job);
if (result != MA_SUCCESS) {
ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER_NODE job. %s.\n", ma_result_description(result));
return result;
}
/* If we don't support threading, process the job queue here. */
if (ma_resource_manager_is_threading_enabled(pResourceManager) == MA_FALSE) {
while (ma_resource_manager_data_buffer_node_result(pDataBufferNode) == MA_BUSY) {
result = ma_resource_manager_process_next_job(pResourceManager);
if (result == MA_NO_DATA_AVAILABLE || result == MA_CANCELLED) {
result = MA_SUCCESS;
break;
}
}
} else {
/* Threading is enabled. The job queue will deal with the rest of the cleanup from here. */
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
if (pConfig == NULL) {
return MA_INVALID_ARGS;
}
if (pConfig->pNotifications != NULL) {
notifications = *pConfig->pNotifications; /* From here on out we should be referencing `notifications` instead of `pNotifications`. Set this to NULL to catch errors at testing time. */
} else {
MA_ZERO_OBJECT(¬ifications);
}
/* For safety, always remove the ASYNC flag if threading is disabled on the resource manager. */
flags = pConfig->flags;
if (ma_resource_manager_is_threading_enabled(pResourceManager) == MA_FALSE) {
flags &= ~MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC;
}
async = (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) != 0;
/*
Fences need to be acquired before doing anything. These must be aquired and released outside of
the node to ensure there's no holes where ma_fence_wait() could prematurely return before the
data buffer has completed initialization.
When loading asynchronously, the node acquisition routine below will acquire the fences on this
thread and then release them on the async thread when the operation is complete.
These fences are always released at the "done" tag at the end of this function. They'll be
acquired a second if loading asynchronously. This double acquisition system is just done to
simplify code maintanence.
*/
ma_resource_manager_pipeline_notifications_acquire_all_fences(¬ifications);
{
/* We first need to acquire a node. If ASYNC is not set, this will not return until the entire sound has been loaded. */
result = ma_resource_manager_data_buffer_node_acquire(pResourceManager, pConfig->pFilePath, pConfig->pFilePathW, hashedName32, flags, NULL, notifications.init.pFence, notifications.done.pFence, &pDataBufferNode);
if (result != MA_SUCCESS) {
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
/* The node's data supply isn't initialized yet. The caller has requested that we load asynchronously so we need to post a job to do this. */
ma_job job;
ma_resource_manager_inline_notification initNotification; /* Used when the WAIT_INIT flag is set. */
if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) {
ma_resource_manager_inline_notification_init(pResourceManager, &initNotification);
}
/*
The status of the data buffer needs to be set to MA_BUSY before posting the job so that the
worker thread is aware of it's busy state. If the LOAD_DATA_BUFFER job sees a status other
than MA_BUSY, it'll assume an error and fall through to an early exit.
*/
c89atomic_exchange_i32(&pDataBuffer->result, MA_BUSY);
/* Acquire fences a second time. These will be released by the async thread. */
ma_resource_manager_pipeline_notifications_acquire_all_fences(¬ifications);
job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER);
job.order = ma_resource_manager_data_buffer_next_execution_order(pDataBuffer);
job.data.resourceManager.loadDataBuffer.pDataBuffer = pDataBuffer;
job.data.resourceManager.loadDataBuffer.pInitNotification = ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) ? &initNotification : notifications.init.pNotification;
job.data.resourceManager.loadDataBuffer.pDoneNotification = notifications.done.pNotification;
job.data.resourceManager.loadDataBuffer.pInitFence = notifications.init.pFence;
job.data.resourceManager.loadDataBuffer.pDoneFence = notifications.done.pFence;
job.data.resourceManager.loadDataBuffer.rangeBegInPCMFrames = pConfig->rangeBegInPCMFrames;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
} else {
if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) {
ma_resource_manager_inline_notification_wait(&initNotification);
if (notifications.init.pNotification != NULL) {
ma_async_notification_signal(notifications.init.pNotification);
}
/* NOTE: Do not release the init fence here. It will have been done by the job. */
/* Make sure we return an error if initialization failed on the async thread. */
result = ma_resource_manager_data_buffer_result(pDataBuffer);
if (result == MA_BUSY) {
result = MA_SUCCESS;
}
}
}
if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) {
ma_resource_manager_inline_notification_uninit(&initNotification);
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
/*
The data buffer needs to be deleted asynchronously because it's still loading. With the status set to MA_UNAVAILABLE, no more pages will
be loaded and the uninitialization should happen fairly quickly. Since the caller owns the data buffer, we need to wait for this event
to get processed before returning.
*/
ma_resource_manager_inline_notification notification;
ma_job job;
/*
We need to mark the node as unavailable so we don't try reading from it anymore, but also to
let the loading thread know that it needs to abort it's loading procedure.
*/
c89atomic_exchange_i32(&pDataBuffer->result, MA_UNAVAILABLE);
result = ma_resource_manager_inline_notification_init(pDataBuffer->pResourceManager, ¬ification);
if (result != MA_SUCCESS) {
return result; /* Failed to create the notification. This should rarely, if ever, happen. */
}
job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER);
job.order = ma_resource_manager_data_buffer_next_execution_order(pDataBuffer);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_data_source_set_range_in_pcm_frames(pDataStream, pConfig->rangeBegInPCMFrames, pConfig->rangeEndInPCMFrames);
ma_data_source_set_loop_point_in_pcm_frames(pDataStream, pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames);
ma_data_source_set_looping(pDataStream, pConfig->isLooping);
if (pResourceManager == NULL || (pConfig->pFilePath == NULL && pConfig->pFilePathW == NULL)) {
ma_resource_manager_pipeline_notifications_signal_all_notifications(¬ifications);
return MA_INVALID_ARGS;
}
/* We want all access to the VFS and the internal decoder to happen on the job thread just to keep things easier to manage for the VFS. */
/* We need a copy of the file path. We should probably make this more efficient, but for now we'll do a transient memory allocation. */
if (pConfig->pFilePath != NULL) {
pFilePathCopy = ma_copy_string(pConfig->pFilePath, &pResourceManager->config.allocationCallbacks);
} else {
pFilePathWCopy = ma_copy_string_w(pConfig->pFilePathW, &pResourceManager->config.allocationCallbacks);
}
if (pFilePathCopy == NULL && pFilePathWCopy == NULL) {
ma_resource_manager_pipeline_notifications_signal_all_notifications(¬ifications);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
if ((pConfig->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) == 0 || (pConfig->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) {
waitBeforeReturning = MA_TRUE;
ma_resource_manager_inline_notification_init(pResourceManager, &waitNotification);
}
ma_resource_manager_pipeline_notifications_acquire_all_fences(¬ifications);
/* Set the absolute cursor to our initial seek position so retrieval of the cursor returns a good value. */
ma_resource_manager_data_stream_set_absolute_cursor(pDataStream, pConfig->initialSeekPointInPCMFrames);
/* We now have everything we need to post the job. This is the last thing we need to do from here. The rest will be done by the job thread. */
job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_STREAM);
job.order = ma_resource_manager_data_stream_next_execution_order(pDataStream);
job.data.resourceManager.loadDataStream.pDataStream = pDataStream;
job.data.resourceManager.loadDataStream.pFilePath = pFilePathCopy;
job.data.resourceManager.loadDataStream.pFilePathW = pFilePathWCopy;
job.data.resourceManager.loadDataStream.initialSeekPoint = pConfig->initialSeekPointInPCMFrames;
job.data.resourceManager.loadDataStream.pInitNotification = (waitBeforeReturning == MA_TRUE) ? &waitNotification : notifications.init.pNotification;
job.data.resourceManager.loadDataStream.pInitFence = notifications.init.pFence;
result = ma_resource_manager_post_job(pResourceManager, &job);
if (result != MA_SUCCESS) {
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS) {
return MA_INVALID_OPERATION;
}
/* Don't attempt to read while we're in the middle of seeking. Tell the caller that we're busy. */
if (ma_resource_manager_data_stream_seek_counter(pDataStream) > 0) {
return MA_BUSY;
}
/* If the page we're on is invalid it means we've caught up to the job thread. */
if (c89atomic_load_32(&pDataStream->isPageValid[pDataStream->currentPageIndex]) == MA_FALSE) {
framesAvailable = 0;
} else {
/*
The page we're on is valid so we must have some frames available. We need to make sure that we don't overflow into the next page, even if it's valid. The reason is
that the unmap process will only post an update for one page at a time. Keeping mapping tied to page boundaries makes this simpler.
*/
ma_uint32 currentPageFrameCount = c89atomic_load_32(&pDataStream->pageFrameCount[pDataStream->currentPageIndex]);
MA_ASSERT(currentPageFrameCount >= pDataStream->relativeCursor);
framesAvailable = currentPageFrameCount - pDataStream->relativeCursor;
}
/* If there's no frames available and the result is set to MA_AT_END we need to return MA_AT_END. */
if (framesAvailable == 0) {
if (ma_resource_manager_data_stream_is_decoder_at_end(pDataStream)) {
return MA_AT_END;
} else {
return MA_BUSY; /* There are no frames available, but we're not marked as EOF so we might have caught up to the job thread. Need to return MA_BUSY and wait for more data. */
}
}
MA_ASSERT(framesAvailable > 0);
if (frameCount > framesAvailable) {
frameCount = framesAvailable;
}
*ppFramesOut = ma_resource_manager_data_stream_get_page_data_pointer(pDataStream, pDataStream->currentPageIndex, pDataStream->relativeCursor);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
*/
pDataStream->relativeCursor = 0;
pDataStream->currentPageIndex = 0;
c89atomic_exchange_32(&pDataStream->isPageValid[0], MA_FALSE);
c89atomic_exchange_32(&pDataStream->isPageValid[1], MA_FALSE);
/* Make sure the data stream is not marked as at the end or else if we seek in response to hitting the end, we won't be able to read any more data. */
c89atomic_exchange_32(&pDataStream->isDecoderAtEnd, MA_FALSE);
/*
The public API is not allowed to touch the internal decoder so we need to use a job to perform the seek. When seeking, the job thread will assume both pages
are invalid and any content contained within them will be discarded and replaced with newly decoded data.
*/
job = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_SEEK_DATA_STREAM);
job.order = ma_resource_manager_data_stream_next_execution_order(pDataStream);
job.data.resourceManager.seekDataStream.pDataStream = pDataStream;
job.data.resourceManager.seekDataStream.frameIndex = frameIndex;
return ma_resource_manager_post_job(pDataStream->pResourceManager, &job);
}
MA_API ma_result ma_resource_manager_data_stream_get_data_format(ma_resource_manager_data_stream* pDataStream, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
if (pDataStream == NULL) {
return MA_INVALID_ARGS;
}
if (streamResult != MA_SUCCESS) {
return streamResult;
}
/*
We most definitely do not want to be calling ma_decoder_get_length_in_pcm_frames() directly. Instead we want to use a cached value that we
calculated when we initialized it on the job thread.
*/
*pLength = pDataStream->totalLengthInPCMFrames;
if (*pLength == 0) {
return MA_NOT_IMPLEMENTED; /* Some decoders may not have a known length. */
}
return MA_SUCCESS;
}
MA_API ma_result ma_resource_manager_data_stream_result(const ma_resource_manager_data_stream* pDataStream)
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
{
return ma_data_source_set_looping(pDataStream, isLooping);
}
MA_API ma_bool32 ma_resource_manager_data_stream_is_looping(const ma_resource_manager_data_stream* pDataStream)
{
if (pDataStream == NULL) {
return MA_FALSE;
}
return c89atomic_load_32((ma_bool32*)&pDataStream->isLooping); /* Naughty const-cast. Value won't change from here in practice (maybe from another thread). */
}
MA_API ma_result ma_resource_manager_data_stream_get_available_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pAvailableFrames)
{
ma_uint32 pageIndex0;
ma_uint32 pageIndex1;
ma_uint32 relativeCursor;
ma_uint64 availableFrames;
if (pAvailableFrames == NULL) {
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
if (ma_resource_manager_data_buffer_node_result(pDataBufferNode) != MA_BUSY) {
result = ma_resource_manager_data_buffer_node_result(pDataBufferNode); /* The data buffer may be getting deleted before it's even been loaded. */
goto done;
}
/*
We're ready to start loading. Essentially what we're doing here is initializing the data supply
of the node. Once this is complete, data buffers can have their connectors initialized which
will allow then to have audio data read from them.
Note that when the data supply type has been moved away from "unknown", that is when other threads
will determine that the node is available for data delivery and the data buffer connectors can be
initialized. Therefore, it's important that it is set after the data supply has been initialized.
*/
if ((pJob->data.resourceManager.loadDataBufferNode.flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE) != 0) {
/*
Decoding. This is the complex case because we're not going to be doing the entire decoding
process here. Instead it's going to be split of multiple jobs and loaded in pages. The
reason for this is to evenly distribute decoding time across multiple sounds, rather than
having one huge sound hog all the available processing resources.
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
} else {
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(_MSC_VER)
ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to initialize data supply for \"%ls\", %s.\n", pJob->data.resourceManager.loadDataBufferNode.pFilePathW, ma_result_description(result));
#endif
}
goto done;
}
/*
At this point the node's data supply is initialized and other threads can start initializing
their data buffer connectors. However, no data will actually be available until we start to
actually decode it. To do this, we need to post a paging job which is where the decoding
work is done.
Note that if an error occurred at an earlier point, this section will have been skipped.
*/
pageDataBufferNodeJob = ma_job_init(MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE);
pageDataBufferNodeJob.order = ma_resource_manager_data_buffer_node_next_execution_order(pDataBufferNode);
pageDataBufferNodeJob.data.resourceManager.pageDataBufferNode.pResourceManager = pResourceManager;
pageDataBufferNodeJob.data.resourceManager.pageDataBufferNode.pDataBufferNode = pDataBufferNode;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
result = ma_resource_manager_data_buffer_node_init_supply_encoded(pResourceManager, pDataBufferNode, pJob->data.resourceManager.loadDataBufferNode.pFilePath, pJob->data.resourceManager.loadDataBufferNode.pFilePathW);
}
done:
/* File paths are no longer needed. */
ma_free(pJob->data.resourceManager.loadDataBufferNode.pFilePath, &pResourceManager->config.allocationCallbacks);
ma_free(pJob->data.resourceManager.loadDataBufferNode.pFilePathW, &pResourceManager->config.allocationCallbacks);
/*
We need to set the result to at the very end to ensure no other threads try reading the data before we've fully initialized the object. Other threads
are going to be inspecting this variable to determine whether or not they're ready to read data. We can only change the result if it's set to MA_BUSY
because otherwise we may be changing away from an error code which would be bad. An example is if the application creates a data buffer, but then
immediately deletes it before we've got to this point. In this case, pDataBuffer->result will be MA_UNAVAILABLE, and setting it to MA_SUCCESS or any
other error code would cause the buffer to look like it's in a state that it's not.
*/
c89atomic_compare_and_swap_i32(&pDataBufferNode->result, MA_BUSY, result);
/* At this point initialization is complete and we can signal the notification if any. */
if (pJob->data.resourceManager.loadDataBufferNode.pInitNotification != NULL) {
ma_async_notification_signal(pJob->data.resourceManager.loadDataBufferNode.pInitNotification);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
*/
result = ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode);
if (result == MA_BUSY || (result == MA_SUCCESS && isConnectorInitialized == MA_FALSE && dataSupplyType == ma_resource_manager_data_supply_type_unknown)) {
return ma_resource_manager_post_job(pResourceManager, pJob);
}
done:
/* Only move away from a busy code so that we don't trash any existing error codes. */
c89atomic_compare_and_swap_i32(&pDataBuffer->result, MA_BUSY, result);
/* Only signal the other threads after the result has been set just for cleanliness sake. */
if (pJob->data.resourceManager.loadDataBuffer.pDoneNotification != NULL) {
ma_async_notification_signal(pJob->data.resourceManager.loadDataBuffer.pDoneNotification);
}
if (pJob->data.resourceManager.loadDataBuffer.pDoneFence != NULL) {
ma_fence_release(pJob->data.resourceManager.loadDataBuffer.pDoneFence);
}
/*
If at this point the data buffer has not had it's connector initialized, it means the
notification event was never signalled which means we need to signal it here.
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
result = ma_decoder_get_length_in_pcm_frames(&pDataStream->decoder, &pDataStream->totalLengthInPCMFrames);
if (result != MA_SUCCESS) {
goto done; /* Failed to retrieve the length. */
}
} else {
pDataStream->totalLengthInPCMFrames = 0;
}
/*
Only mark the decoder as initialized when the length of the decoder has been retrieved because that can possibly require a scan over the whole file
and we don't want to have another thread trying to access the decoder while it's scanning.
*/
pDataStream->isDecoderInitialized = MA_TRUE;
/* We have the decoder so we can now initialize our page buffer. */
pageBufferSizeInBytes = ma_resource_manager_data_stream_get_page_size_in_frames(pDataStream) * 2 * ma_get_bytes_per_frame(pDataStream->decoder.outputFormat, pDataStream->decoder.outputChannels);
pDataStream->pPageData = ma_malloc(pageBufferSizeInBytes, &pResourceManager->config.allocationCallbacks);
if (pDataStream->pPageData == NULL) {
ma_decoder_uninit(&pDataStream->decoder);
result = MA_OUT_OF_MEMORY;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
/* And now we're done. We want to make sure the result is MA_SUCCESS. */
result = MA_SUCCESS;
done:
ma_free(pJob->data.resourceManager.loadDataStream.pFilePath, &pResourceManager->config.allocationCallbacks);
ma_free(pJob->data.resourceManager.loadDataStream.pFilePathW, &pResourceManager->config.allocationCallbacks);
/* We can only change the status away from MA_BUSY. If it's set to anything else it means an error has occurred somewhere or the uninitialization process has started (most likely). */
c89atomic_compare_and_swap_i32(&pDataStream->result, MA_BUSY, result);
/* Only signal the other threads after the result has been set just for cleanliness sake. */
if (pJob->data.resourceManager.loadDataStream.pInitNotification != NULL) {
ma_async_notification_signal(pJob->data.resourceManager.loadDataStream.pInitNotification);
}
if (pJob->data.resourceManager.loadDataStream.pInitFence != NULL) {
ma_fence_release(pJob->data.resourceManager.loadDataStream.pInitFence);
}
c89atomic_fetch_add_32(&pDataStream->executionPointer, 1);
return result;
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
return pInputBus->channels;
}
static void ma_node_input_bus_detach__no_output_bus_lock(ma_node_input_bus* pInputBus, ma_node_output_bus* pOutputBus)
{
MA_ASSERT(pInputBus != NULL);
MA_ASSERT(pOutputBus != NULL);
/*
Mark the output bus as detached first. This will prevent future iterations on the audio thread
from iterating this output bus.
*/
ma_node_output_bus_set_is_attached(pOutputBus, MA_FALSE);
/*
We cannot use the output bus lock here since it'll be getting used at a higher level, but we do
still need to use the input bus lock since we'll be updating pointers on two different output
buses. The same rules apply here as the attaching case. Although we're using a lock here, we're
*not* using a lock when iterating over the list in the audio thread. We therefore need to craft
this in a way such that the iteration on the audio thread doesn't break.
The the first thing to do is swap out the "next" pointer of the previous output bus with the
new "next" output bus. This is the operation that matters for iteration on the audio thread.
After that, the previous pointer on the new "next" pointer needs to be updated, after which
point the linked list will be in a good state.
*/
ma_node_input_bus_lock(pInputBus);
{
ma_node_output_bus* pOldPrev = (ma_node_output_bus*)c89atomic_load_ptr(&pOutputBus->pPrev);
ma_node_output_bus* pOldNext = (ma_node_output_bus*)c89atomic_load_ptr(&pOutputBus->pNext);
if (pOldPrev != NULL) {
c89atomic_exchange_ptr(&pOldPrev->pNext, pOldNext); /* <-- This is where the output bus is detached from the list. */
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_node_input_bus_unlock(pInputBus);
/* At this point the output bus is detached and the linked list is completely unaware of it. Reset some data for safety. */
c89atomic_exchange_ptr(&pOutputBus->pNext, NULL); /* Using atomic exchanges here, mainly for the benefit of analysis tools which don't always recognize spinlocks. */
c89atomic_exchange_ptr(&pOutputBus->pPrev, NULL); /* As above. */
pOutputBus->pInputNode = NULL;
pOutputBus->inputNodeInputBusIndex = 0;
/*
For thread-safety reasons, we don't want to be returning from this straight away. We need to
wait for the audio thread to finish with the output bus. There's two things we need to wait
for. The first is the part that selects the next output bus in the list, and the other is the
part that reads from the output bus. Basically all we're doing is waiting for the input bus
to stop referencing the output bus.
We're doing this part last because we want the section above to run while the audio thread
is finishing up with the output bus, just for efficiency reasons. We marked the output bus as
detached right at the top of this function which is going to prevent the audio thread from
iterating the output bus again.
*/
/* Part 1: Wait for the current iteration to complete. */
while (ma_node_input_bus_get_next_counter(pInputBus) > 0) {
ma_yield();
}
/* Part 2: Wait for any reads to complete. */
while (c89atomic_load_32(&pOutputBus->refCount) > 0) {
ma_yield();
}
/*
At this point we're done detaching and we can be guaranteed that the audio thread is not going
to attempt to reference this output bus again (until attached again).
*/
}
#if 0 /* Not used at the moment, but leaving here in case I need it later. */
static void ma_node_input_bus_detach(ma_node_input_bus* pInputBus, ma_node_output_bus* pOutputBus)
{
MA_ASSERT(pInputBus != NULL);
MA_ASSERT(pOutputBus != NULL);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
*/
pOutputBus->pInputNode = pNewInputNode; /* No need for an atomic assignment here because modification of this variable always happens within a lock. */
pOutputBus->inputNodeInputBusIndex = (ma_uint8)inputNodeInputBusIndex; /* As above. */
/*
Now we need to attach the output bus to the linked list. This involves updating two pointers on
two different output buses so I'm going to go ahead and keep this simple and just use a lock.
There are ways to do this without a lock, but it's just too hard to maintain for it's value.
Although we're locking here, it's important to remember that we're *not* locking when iterating
and reading audio data since that'll be running on the audio thread. As a result we need to be
careful how we craft this so that we don't break iteration. What we're going to do is always
attach the new item so that it becomes the first item in the list. That way, as we're iterating
we won't break any links in the list and iteration will continue safely. The detaching case will
also be crafted in a way as to not break list iteration. It's important to remember to use
atomic exchanges here since no locking is happening on the audio thread during iteration.
*/
ma_node_input_bus_lock(pInputBus);
{
ma_node_output_bus* pNewPrev = &pInputBus->head;
ma_node_output_bus* pNewNext = (ma_node_output_bus*)c89atomic_load_ptr(&pInputBus->head.pNext);
/* Update the local output bus. */
c89atomic_exchange_ptr(&pOutputBus->pPrev, pNewPrev);
c89atomic_exchange_ptr(&pOutputBus->pNext, pNewNext);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
/* Do the previous pointer last. This is only used for detachment. */
if (pNewNext != NULL) {
c89atomic_exchange_ptr(&pNewNext->pPrev, pOutputBus);
}
}
ma_node_input_bus_unlock(pInputBus);
/*
Mark the node as attached last. This is used to controlling whether or the output bus will be
iterated on the audio thread. Mainly required for detachment purposes.
*/
ma_node_output_bus_set_is_attached(pOutputBus, MA_TRUE);
}
ma_node_output_bus_unlock(pOutputBus);
}
static ma_node_output_bus* ma_node_input_bus_next(ma_node_input_bus* pInputBus, ma_node_output_bus* pOutputBus)
{
ma_node_output_bus* pNext;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_input_bus* pInputBus, float* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead, ma_uint64 globalTime)
{
ma_result result = MA_SUCCESS;
ma_node_output_bus* pOutputBus;
ma_node_output_bus* pFirst;
ma_uint32 inputChannels;
ma_bool32 doesOutputBufferHaveContent = MA_FALSE;
/*
This will be called from the audio thread which means we can't be doing any locking. Basically,
this function will not perfom any locking, whereas attaching and detaching will, but crafted in
such a way that we don't need to perform any locking here. The important thing to remember is
to always iterate in a forward direction.
In order to process any data we need to first read from all input buses. That's where this
function comes in. This iterates over each of the attachments and accumulates/mixes them. We
also convert the channels to the nodes output channel count before mixing. We want to do this
channel conversion so that the caller of this function can invoke the processing callback
without having to do it themselves.
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
*/
MA_ASSERT(pInputNode != NULL);
MA_ASSERT(pFramesRead != NULL); /* pFramesRead is critical and must always be specified. On input it's undefined and on output it'll be set to the number of frames actually read. */
*pFramesRead = 0; /* Safety. */
inputChannels = ma_node_input_bus_get_channels(pInputBus);
/*
We need to be careful with how we call ma_node_input_bus_first() and ma_node_input_bus_next(). They
are both critical to our lock-free thread-safety system. We can only call ma_node_input_bus_first()
once per iteration, however we have an optimization to checks whether or not it's the first item in
the list. We therefore need to store a pointer to the first item rather than repeatedly calling
ma_node_input_bus_first(). It's safe to keep hold of this pointer, so long as we don't dereference it
after calling ma_node_input_bus_next(), which we won't be.
*/
pFirst = ma_node_input_bus_first(pInputBus);
if (pFirst == NULL) {
return MA_SUCCESS; /* No attachments. Read nothing. */
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
{
ma_node_base* pNodeBase = (ma_node_base*)pNode;
if (pNodeBase == NULL) {
return;
}
/*
The first thing we need to do is fully detach the node. This will detach all inputs and
outputs. We need to do this first because it will sever the connection with the node graph and
allow us to complete uninitialization without needing to worry about thread-safety with the
audio thread. The detachment process will wait for any local processing of the node to finish.
*/
ma_node_detach_full(pNode);
/*
At this point the node should be completely unreferenced by the node graph and we can finish up
the uninitialization process without needing to worry about thread-safety.
*/
if (pNodeBase->_ownsHeap) {
ma_free(pNodeBase->_pHeap, pAllocationCallbacks);
}
}
MA_API ma_node_graph* ma_node_get_node_graph(const ma_node* pNode)
{
if (pNode == NULL) {
return NULL;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
{
ma_node_base* pNodeBase = (ma_node_base*)pNode;
ma_uint32 iInputBus;
if (pNodeBase == NULL) {
return MA_INVALID_ARGS;
}
/*
Make sure the node is completely detached first. This will not return until the output bus is
guaranteed to no longer be referenced by the audio thread.
*/
ma_node_detach_all_output_buses(pNode);
/*
At this point all output buses will have been detached from the graph and we can be guaranteed
that none of it's input nodes will be getting processed by the graph. We can detach these
without needing to worry about the audio thread touching them.
*/
for (iInputBus = 0; iInputBus < ma_node_get_input_bus_count(pNode); iInputBus += 1) {
ma_node_input_bus* pInputBus;
ma_node_output_bus* pOutputBus;
pInputBus = &pNodeBase->pInputBuses[iInputBus];
/*
This is important. We cannot be using ma_node_input_bus_first() or ma_node_input_bus_next(). Those
functions are specifically for the audio thread. We'll instead just manually iterate using standard
linked list logic. We don't need to worry about the audio thread referencing these because the step
above severed the connection to the graph.
*/
for (pOutputBus = (ma_node_output_bus*)c89atomic_load_ptr(&pInputBus->head.pNext); pOutputBus != NULL; pOutputBus = (ma_node_output_bus*)c89atomic_load_ptr(&pOutputBus->pNext)) {
ma_node_detach_output_bus(pOutputBus->pNode, pOutputBus->outputBusIndex); /* This won't do any waiting in practice and should be efficient. */
}
}
return MA_SUCCESS;
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
*pFrameCountOut = totalFramesRead;
}
static void ma_engine_node_process_pcm_frames__group(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
{
/*
Make sure the pitch is updated before trying to read anything. It's important that this is done
only once and not in ma_engine_node_process_pcm_frames__general(). The reason for this is that
ma_engine_node_process_pcm_frames__general() will call ma_engine_node_get_required_input_frame_count(),
and if another thread modifies the pitch just after that call it can result in a glitch due to
the input rate changing.
*/
ma_engine_node_update_pitch_if_required((ma_engine_node*)pNode);
/* For groups, the input data has already been read and we just need to apply the effect. */
ma_engine_node_process_pcm_frames__general((ma_engine_node*)pNode, ppFramesIn, pFrameCountIn, ppFramesOut, pFrameCountOut);
}
static ma_result ma_engine_node_get_required_input_frame_count__group(ma_node* pNode, ma_uint32 outputFrameCount, ma_uint32* pInputFrameCount)
{
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
This serves two purposes:
1) It ensures jobs are actually processed at some point since we cannot guarantee that the
caller is doing the right thing and calling ma_resource_manager_process_next_job(); and
2) It's an attempt at working around an issue where processing jobs on the Emscripten main
loop doesn't work as well as it should. When trying to load sounds without the `DECODE`
flag or with the `ASYNC` flag, the sound data is just not able to be loaded in time
before the callback is processed. I think it's got something to do with the single-
threaded nature of Web, but I'm not entirely sure.
*/
#if !defined(MA_NO_RESOURCE_MANAGER) && defined(MA_EMSCRIPTEN)
{
if (pEngine->pResourceManager != NULL) {
if ((pEngine->pResourceManager->config.flags & MA_RESOURCE_MANAGER_FLAG_NO_THREADING) != 0) {
ma_resource_manager_process_next_job(pEngine->pResourceManager);
}
}
}
#endif
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
resourceManagerConfig = ma_resource_manager_config_init();
resourceManagerConfig.pLog = pEngine->pLog; /* Always use the engine's log for internally-managed resource managers. */
resourceManagerConfig.decodedFormat = ma_format_f32;
resourceManagerConfig.decodedChannels = 0; /* Leave the decoded channel count as 0 so we can get good spatialization. */
resourceManagerConfig.decodedSampleRate = ma_engine_get_sample_rate(pEngine);
ma_allocation_callbacks_init_copy(&resourceManagerConfig.allocationCallbacks, &pEngine->allocationCallbacks);
resourceManagerConfig.pVFS = engineConfig.pResourceManagerVFS;
/* The Emscripten build cannot use threads. */
#if defined(MA_EMSCRIPTEN)
{
resourceManagerConfig.jobThreadCount = 0;
resourceManagerConfig.flags |= MA_RESOURCE_MANAGER_FLAG_NO_THREADING;
}
#endif
result = ma_resource_manager_init(&resourceManagerConfig, pEngine->pResourceManager);
if (result != MA_SUCCESS) {
goto on_error_3;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
MA_API void ma_engine_uninit(ma_engine* pEngine)
{
ma_uint32 iListener;
if (pEngine == NULL) {
return;
}
/* The device must be uninitialized before the node graph to ensure the audio thread doesn't try accessing it. */
#if !defined(MA_NO_DEVICE_IO)
{
if (pEngine->ownsDevice) {
ma_device_uninit(pEngine->pDevice);
ma_free(pEngine->pDevice, &pEngine->allocationCallbacks);
} else {
if (pEngine->pDevice != NULL) {
ma_device_stop(pEngine->pDevice);
}
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_sound_uninit(&pSoundToDelete->sound);
ma_free(pSoundToDelete, &pEngine->allocationCallbacks);
}
}
ma_spinlock_unlock(&pEngine->inlinedSoundLock);
for (iListener = 0; iListener < pEngine->listenerCount; iListener += 1) {
ma_spatializer_listener_uninit(&pEngine->listeners[iListener], &pEngine->allocationCallbacks);
}
/* Make sure the node graph is uninitialized after the audio thread has been shutdown to prevent accessing of the node graph after being uninitialized. */
ma_node_graph_uninit(&pEngine->nodeGraph, &pEngine->allocationCallbacks);
/* Uninitialize the resource manager last to ensure we don't have a thread still trying to access it. */
#ifndef MA_NO_RESOURCE_MANAGER
if (pEngine->ownsResourceManager) {
ma_resource_manager_uninit(pEngine->pResourceManager);
ma_free(pEngine->pResourceManager, &pEngine->allocationCallbacks);
}
#endif
}
MA_API ma_result ma_engine_read_pcm_frames(ma_engine* pEngine, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
{
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
MA_API void ma_sound_uninit(ma_sound* pSound)
{
if (pSound == NULL) {
return;
}
/*
Always uninitialize the node first. This ensures it's detached from the graph and does not return until it has done
so which makes thread safety beyond this point trivial.
*/
ma_engine_node_uninit(&pSound->engineNode, &pSound->engineNode.pEngine->allocationCallbacks);
/* Once the sound is detached from the group we can guarantee that it won't be referenced by the mixer thread which means it's safe for us to destroy the data source. */
#ifndef MA_NO_RESOURCE_MANAGER
if (pSound->ownsDataSource) {
ma_resource_manager_data_source_uninit(pSound->pResourceManagerDataSource);
ma_free(pSound->pResourceManagerDataSource, &pSound->engineNode.pEngine->allocationCallbacks);
pSound->pDataSource = NULL;
}
#else
MA_ASSERT(pSound->ownsDataSource == MA_FALSE);
#endif
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
{
if (pSound == NULL) {
return MA_INVALID_ARGS;
}
/* Seeking is only valid for sounds that are backed by a data source. */
if (pSound->pDataSource == NULL) {
return MA_INVALID_OPERATION;
}
/* We can't be seeking while reading at the same time. We just set the seek target and get the mixing thread to do the actual seek. */
c89atomic_exchange_64(&pSound->seekTarget, frameIndex);
return MA_SUCCESS;
}
MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
{
if (pSound == NULL) {
return MA_INVALID_ARGS;
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
if (pRevision) {
*pRevision = DRFLAC_VERSION_REVISION;
}
}
DRFLAC_API const char* drflac_version_string(void)
{
return DRFLAC_VERSION_STRING;
}
#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
#define DRFLAC_NO_THREAD_SANITIZE __attribute__((no_sanitize("thread")))
#else
#define DRFLAC_NO_THREAD_SANITIZE
#endif
#else
#define DRFLAC_NO_THREAD_SANITIZE
#endif
#if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE;
#endif
#ifndef DRFLAC_NO_CPUID