Commit 35fd4fbf authored by David Reid's avatar David Reid

Version 0.10.23

parent 84f8acf4
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.10.21 - 2020-10-30
miniaudio - v0.10.23 - 2020-11-09
David Reid - mackron@gmail.com
......@@ -20,7 +20,7 @@ extern "C" {
#define MA_VERSION_MAJOR 0
#define MA_VERSION_MINOR 10
#define MA_VERSION_REVISION 21
#define MA_VERSION_REVISION 23
#define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION)
#if defined(_MSC_VER) && !defined(__clang__)
......@@ -28,7 +28,7 @@ extern "C" {
#pragma warning(disable:4201) /* nonstandard extension used: nameless struct/union */
#pragma warning(disable:4214) /* nonstandard extension used: bit field types other than int */
#pragma warning(disable:4324) /* structure was padded due to alignment specifier */
#else
#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic" /* For ISO C99 doesn't support unnamed structs/unions [-Wpedantic] */
#if defined(__clang__)
......@@ -81,7 +81,7 @@ typedef unsigned int ma_uint32;
typedef signed __int64 ma_int64;
typedef unsigned __int64 ma_uint64;
#else
#if defined(__GNUC__)
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlong-long"
#if defined(__clang__)
......@@ -90,7 +90,7 @@ typedef unsigned int ma_uint32;
#endif
typedef signed long long ma_int64;
typedef unsigned long long ma_uint64;
#if defined(__GNUC__)
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic pop
#endif
#endif
......@@ -1333,6 +1333,25 @@ MA_API ma_uint32 ma_pcm_rb_get_subbuffer_offset(ma_pcm_rb* pRB, ma_uint32 subbuf
MA_API void* ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb* pRB, ma_uint32 subbufferIndex, void* pBuffer);
/*
The idea of the duplex ring buffer is to act as the intermediary buffer when running two asynchronous devices in a duplex set up. The
capture device writes to it, and then a playback device reads from it.
At the moment this is just a simple naive implementation, but in the future I want to implement some dynamic resampling to seamlessly
handle desyncs. Note that the API is work in progress and may change at any time in any version.
The size of the buffer is based on the capture side since that's what'll be written to the buffer. It is based on the capture period size
in frames. The internal sample rate of the capture device is also needed in order to calculate the size.
*/
typedef struct
{
ma_pcm_rb rb;
} ma_duplex_rb;
MA_API ma_result ma_duplex_rb_init(ma_uint32 inputSampleRate, ma_format captureFormat, ma_uint32 captureChannels, ma_uint32 captureSampleRate, ma_uint32 capturePeriodSizeInFrames, const ma_allocation_callbacks* pAllocationCallbacks, ma_duplex_rb* pRB);
MA_API ma_result ma_duplex_rb_uninit(ma_duplex_rb* pRB);
/************************************************************************************************************************************************************
Miscellaneous Helpers
......@@ -1447,6 +1466,9 @@ This section contains the APIs for device playback and capture. Here is where yo
#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
......@@ -1492,10 +1514,19 @@ This section contains the APIs for device playback and capture. Here is where yo
#if !defined(MA_NO_WEBAUDIO) && defined(MA_SUPPORT_WEBAUDIO)
#define MA_ENABLE_WEBAUDIO
#endif
#if !defined(MA_NO_CUSTOM) && defined(MA_SUPPORT_CUSTOM)
#define MA_ENABLE_CUSTOM
#endif
#if !defined(MA_NO_NULL) && defined(MA_SUPPORT_NULL)
#define MA_ENABLE_NULL
#endif
#define MA_STATE_UNINITIALIZED 0
#define MA_STATE_STOPPED 1 /* The device's default state after initialization. */
#define MA_STATE_STARTED 2 /* The device is started and is requesting and/or delivering 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. */
#ifdef MA_SUPPORT_WASAPI
/* We need a IMMNotificationClient object for WASAPI. */
typedef struct
......@@ -1522,7 +1553,8 @@ typedef enum
ma_backend_aaudio,
ma_backend_opensl,
ma_backend_webaudio,
ma_backend_null /* <-- Must always be the last item. Lowest priority, and used as the terminator for backend enumeration. */
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)
......@@ -1604,14 +1636,14 @@ pDevice (in)
logLevel (in)
The log level. This can be one of the following:
|----------------------|
+----------------------+
| Log Level |
|----------------------|
+----------------------+
| MA_LOG_LEVEL_VERBOSE |
| MA_LOG_LEVEL_INFO |
| MA_LOG_LEVEL_WARNING |
| MA_LOG_LEVEL_ERROR |
|----------------------|
+----------------------+
message (in)
The log message.
......@@ -1662,6 +1694,74 @@ typedef enum
ma_ios_session_category_option_allow_air_play = 0x40, /* AVAudioSessionCategoryOptionAllowAirPlay */
} ma_ios_session_category_option;
/* OpenSL stream types. */
typedef enum
{
ma_opensl_stream_type_default = 0, /* Leaves the stream type unset. */
ma_opensl_stream_type_voice, /* SL_ANDROID_STREAM_VOICE */
ma_opensl_stream_type_system, /* SL_ANDROID_STREAM_SYSTEM */
ma_opensl_stream_type_ring, /* SL_ANDROID_STREAM_RING */
ma_opensl_stream_type_media, /* SL_ANDROID_STREAM_MEDIA */
ma_opensl_stream_type_alarm, /* SL_ANDROID_STREAM_ALARM */
ma_opensl_stream_type_notification /* SL_ANDROID_STREAM_NOTIFICATION */
} ma_opensl_stream_type;
/* OpenSL recording presets. */
typedef enum
{
ma_opensl_recording_preset_default = 0, /* Leaves the input preset unset. */
ma_opensl_recording_preset_generic, /* SL_ANDROID_RECORDING_PRESET_GENERIC */
ma_opensl_recording_preset_camcorder, /* SL_ANDROID_RECORDING_PRESET_CAMCORDER */
ma_opensl_recording_preset_voice_recognition, /* SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION */
ma_opensl_recording_preset_voice_communication, /* SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION */
ma_opensl_recording_preset_voice_unprocessed /* SL_ANDROID_RECORDING_PRESET_UNPROCESSED */
} ma_opensl_recording_preset;
/* AAudio usage types. */
typedef enum
{
ma_aaudio_usage_default = 0, /* Leaves the usage type unset. */
ma_aaudio_usage_announcement, /* AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT */
ma_aaudio_usage_emergency, /* AAUDIO_SYSTEM_USAGE_EMERGENCY */
ma_aaudio_usage_safety, /* AAUDIO_SYSTEM_USAGE_SAFETY */
ma_aaudio_usage_vehicle_status, /* AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS */
ma_aaudio_usage_alarm, /* AAUDIO_USAGE_ALARM */
ma_aaudio_usage_assistance_accessibility, /* AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY */
ma_aaudio_usage_assistance_navigation_guidance, /* AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE */
ma_aaudio_usage_assistance_sonification, /* AAUDIO_USAGE_ASSISTANCE_SONIFICATION */
ma_aaudio_usage_assitant, /* AAUDIO_USAGE_ASSISTANT */
ma_aaudio_usage_game, /* AAUDIO_USAGE_GAME */
ma_aaudio_usage_media, /* AAUDIO_USAGE_MEDIA */
ma_aaudio_usage_notification, /* AAUDIO_USAGE_NOTIFICATION */
ma_aaudio_usage_notification_event, /* AAUDIO_USAGE_NOTIFICATION_EVENT */
ma_aaudio_usage_notification_ringtone, /* AAUDIO_USAGE_NOTIFICATION_RINGTONE */
ma_aaudio_usage_voice_communication, /* AAUDIO_USAGE_VOICE_COMMUNICATION */
ma_aaudio_usage_voice_communication_signalling /* AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING */
} ma_aaudio_usage;
/* AAudio content types. */
typedef enum
{
ma_aaudio_content_type_default = 0, /* Leaves the content type unset. */
ma_aaudio_content_type_movie, /* AAUDIO_CONTENT_TYPE_MOVIE */
ma_aaudio_content_type_music, /* AAUDIO_CONTENT_TYPE_MUSIC */
ma_aaudio_content_type_sonification, /* AAUDIO_CONTENT_TYPE_SONIFICATION */
ma_aaudio_content_type_speech /* AAUDIO_CONTENT_TYPE_SPEECH */
} ma_aaudio_content_type;
/* AAudio input presets. */
typedef enum
{
ma_aaudio_input_preset_default = 0, /* Leaves the input preset unset. */
ma_aaudio_input_preset_generic, /* AAUDIO_INPUT_PRESET_GENERIC */
ma_aaudio_input_preset_camcorder, /* AAUDIO_INPUT_PRESET_CAMCORDER */
ma_aaudio_input_preset_unprocessed, /* AAUDIO_INPUT_PRESET_UNPROCESSED */
ma_aaudio_input_preset_voice_recognition, /* AAUDIO_INPUT_PRESET_VOICE_RECOGNITION */
ma_aaudio_input_preset_voice_communication, /* AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION */
ma_aaudio_input_preset_voice_performance /* AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE */
} ma_aaudio_input_preset;
typedef union
{
ma_int64 counter;
......@@ -1683,14 +1783,28 @@ typedef union
ma_int32 aaudio; /* AAudio uses a 32-bit integer for identification. */
ma_uint32 opensl; /* OpenSL|ES uses a 32-bit unsigned integer for identification. */
char webaudio[32]; /* Web Audio always uses default devices for now, but if this changes it'll be a GUID. */
union
{
int i;
char s[256];
void* p;
} custom; /* The custom backend could be anything. Give them a few options. */
int nullbackend; /* The null backend uses an integer for device IDs. */
} ma_device_id;
typedef struct ma_context_config ma_context_config;
typedef struct ma_device_config ma_device_config;
typedef struct ma_backend_callbacks ma_backend_callbacks;
#define MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE (1U << 1); /* If set, this is supported in exclusive mode. Otherwise not natively supported by exclusive mode. */
typedef struct
{
/* Basic info. This is the only information guaranteed to be filled in during device enumeration. */
ma_device_id id;
char name[256];
ma_bool32 isDefault;
/*
Detailed info. As much of this is filled as possible with ma_context_get_device_info(). Note that you are allowed to initialize
......@@ -1707,13 +1821,19 @@ typedef struct
ma_uint32 minSampleRate;
ma_uint32 maxSampleRate;
/* Experimental. Don't use these right now. */
ma_uint32 nativeDataFormatCount;
struct
{
ma_bool32 isDefault;
} _private;
ma_format format; /* Sample format. If set to ma_format_unknown, all sample formats are supported. */
ma_uint32 channels; /* If set to 0, all channels are supported. */
ma_uint32 sampleRate; /* If set to 0, all sample rates are supported. */
ma_uint32 flags;
} nativeDataFormats[64];
} ma_device_info;
typedef struct
struct ma_device_config
{
ma_device_type deviceType;
ma_uint32 sampleRate;
......@@ -1774,9 +1894,146 @@ typedef struct
const char* pStreamNamePlayback;
const char* pStreamNameCapture;
} pulse;
} ma_device_config;
struct
{
ma_bool32 allowNominalSampleRateChange; /* Desktop only. When enabled, allows changing of the sample rate at the operating system level. */
} coreaudio;
struct
{
ma_opensl_stream_type streamType;
ma_opensl_recording_preset recordingPreset;
} opensl;
struct
{
ma_aaudio_usage usage;
ma_aaudio_content_type contentType;
ma_aaudio_input_preset inputPreset;
} aaudio;
};
/*
The callback for handling device enumeration. This is fired from `ma_context_enumerated_devices()`.
Parameters
----------
pContext (in)
A pointer to the context performing the enumeration.
deviceType (in)
The type of the device being enumerated. This will always be either `ma_device_type_playback` or `ma_device_type_capture`.
pInfo (in)
A pointer to a `ma_device_info` containing the ID and name of the enumerated device. Note that this will not include detailed information about the device,
only basic information (ID and name). The reason for this is that it would otherwise require opening the backend device to probe for the information which
is too inefficient.
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);
/*
Describes some basic details about a playback or capture device.
*/
typedef struct
{
const ma_device_id* pDeviceID;
ma_share_mode shareMode;
ma_format format;
ma_uint32 channels;
ma_uint32 sampleRate;
ma_channel channelMap[MA_MAX_CHANNELS];
ma_uint32 periodSizeInFrames;
ma_uint32 periodSizeInMilliseconds;
ma_uint32 periodCount;
} ma_device_descriptor;
/*
These are the callbacks required to be implemented for a backend. These callbacks are grouped into two parts: context and device. There is one context
to many devices. A device is created from a context.
The general flow goes like this:
1) A context is created with `onContextInit()`
1a) Available devices can be enumerated with `onContextEnumerateDevices()` if required.
1b) Detailed information about a device can be queried with `onContextGetDeviceInfo()` if required.
2) A device is created from the context that was created in the first step using `onDeviceInit()`, and optionally a device ID that was
selected from device enumeration via `onContextEnumerateDevices()`.
3) A device is started or stopped with `onDeviceStart()` / `onDeviceStop()`
4) Data is delivered to and from the device by the backend. This is always done based on the native format returned by the prior call
to `onDeviceInit()`. Conversion between the device's native format and the format requested by the application will be handled by
miniaudio internally.
Initialization of the context is quite simple. You need to do any necessary initialization of internal objects and then output the
callbacks defined in this structure.
Once the context has been initialized you can initialize a device. Before doing so, however, the application may want to know which
physical devices are available. This is where `onContextEnumerateDevices()` comes in. This is fairly simple. For each device, fire the
given callback with, at a minimum, the basic information filled out in `ma_device_info`. When the callback returns `MA_FALSE`, enumeration
needs to stop and the `onContextEnumerateDevices()` function return with a success code.
Detailed device information can be retrieved from a device ID using `onContextGetDeviceInfo()`. This takes as input the device type and ID,
and on output returns detailed information about the device in `ma_device_info`. The `onContextGetDeviceInfo()` callback must handle the
case when the device ID is NULL, in which case information about the default device needs to be retrieved.
Once the context has been created and the device ID retrieved (if using anything other than the default device), the device can be created.
This is a little bit more complicated than initialization of the context due to it's more complicated configuration. When initializing a
device, a duplex device may be requested. This means a separate data format needs to be specified for both playback and capture. On input,
the data format is set to what the application wants. On output it's set to the native format which should match as closely as possible to
the requested format. The conversion between the format requested by the application and the device's native format will be handled
internally by miniaudio.
On input, if the sample format is set to `ma_format_unknown`, the backend is free to use whatever sample format it desires, so long as it's
supported by miniaudio. When the channel count is set to 0, the backend should use the device's native channel count. The same applies for
sample rate. For the channel map, the default should be used when `ma_channel_map_blank()` returns true (all channels set to
`MA_CHANNEL_NONE`). On input, the `periodSizeInFrames` or `periodSizeInMilliseconds` option should always be set. The backend should
inspect both of these variables. If `periodSizeInFrames` is set, it should take priority, otherwise it needs to be derived from the period
size in milliseconds (`periodSizeInMilliseconds`) and the sample rate, keeping in mind that the sample rate may be 0, in which case the
sample rate will need to be determined before calculating the period size in frames. On output, all members of the `ma_device_data_format`
object should be set to a valid value, except for `periodSizeInMilliseconds` which is optional (`periodSizeInFrames` *must* be set).
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()` is optional, so long as the device is automatically started in `onDeviceWrite()`.
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 `onDeviceWorkerThread()` 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 follows this general flow:
1) Start the device before entering the main loop.
2) Run data delivery logic in a loop while `ma_device_get_state() == MA_STATE_STARTED` and no errors have been encounted.
3) Stop thd device after leaving the main loop.
The invocation of the `onDeviceAudioThread()` 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_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 `onDeviceAudioThread()` callback,
look at `ma_device_audio_thread__default_read_write()`.
*/
struct ma_backend_callbacks
{
ma_result (* onContextInit)(ma_context* pContext, 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);
ma_result (* onDeviceInit)(ma_device* pDevice, ma_device_type deviceType, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture);
ma_result (* onDeviceUninit)(ma_device* pDevice);
ma_result (* onDeviceStart)(ma_device* pDevice);
ma_result (* onDeviceStop)(ma_device* pDevice);
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 (* onDeviceAudioThread)(ma_device* pDevice);
};
struct ma_context_config
{
ma_log_proc logCallback;
ma_thread_priority threadPriority;
......@@ -1805,29 +2062,8 @@ typedef struct
const char* pClientName;
ma_bool32 tryStartServer;
} jack;
} ma_context_config;
/*
The callback for handling device enumeration. This is fired from `ma_context_enumerated_devices()`.
Parameters
----------
pContext (in)
A pointer to the context performing the enumeration.
deviceType (in)
The type of the device being enumerated. This will always be either `ma_device_type_playback` or `ma_device_type_capture`.
pInfo (in)
A pointer to a `ma_device_info` containing the ID and name of the enumerated device. Note that this will not include detailed information about the device,
only basic information (ID and name). The reason for this is that it would otherwise require opening the backend device to probe for the information which
is too inefficient.
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);
ma_backend_callbacks custom;
};
struct ma_context
{
......@@ -1846,7 +2082,6 @@ struct ma_context
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);
ma_result (* onDeviceInit )(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice);
......@@ -1966,9 +2201,23 @@ struct ma_context
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;
......@@ -2009,9 +2258,8 @@ struct ma_context
ma_proc pa_stream_writable_size;
ma_proc pa_stream_readable_size;
char* pApplicationName;
char* pServerName;
ma_bool32 tryAutoSpawn;
/*pa_threaded_mainloop**/ ma_ptr pMainLoop;
/*pa_context**/ ma_ptr pPulseContext;
} pulse;
#endif
#ifdef MA_SUPPORT_JACK
......@@ -2124,6 +2372,9 @@ struct ma_context
ma_proc AAudioStreamBuilder_setDataCallback;
ma_proc AAudioStreamBuilder_setErrorCallback;
ma_proc AAudioStreamBuilder_setPerformanceMode;
ma_proc AAudioStreamBuilder_setUsage;
ma_proc AAudioStreamBuilder_setContentType;
ma_proc AAudioStreamBuilder_setInputPreset;
ma_proc AAudioStreamBuilder_openStream;
ma_proc AAudioStream_close;
ma_proc AAudioStream_getState;
......@@ -2148,6 +2399,7 @@ struct ma_context
ma_handle SL_IID_RECORD;
ma_handle SL_IID_PLAY;
ma_handle SL_IID_OUTPUTMIX;
ma_handle SL_IID_ANDROIDCONFIGURATION;
ma_proc slCreateEngine;
} opensl;
#endif
......@@ -2157,6 +2409,9 @@ struct ma_context
int _unused;
} webaudio;
#endif
#ifdef MA_SUPPORT_CUSTOM
ma_backend_callbacks custom;
#endif
#ifdef MA_SUPPORT_NULL
struct
{
......@@ -2235,6 +2490,7 @@ struct ma_device
ma_bool32 noPreZeroedOutputBuffer : 1;
ma_bool32 noClip : 1;
volatile float masterVolumeFactor; /* Volatile so we can use some thread safety when applying volume to periods. */
ma_duplex_rb duplexRB; /* Intermediary buffer for duplex device on asynchronous backends. */
struct
{
ma_resample_algorithm algorithm;
......@@ -2358,19 +2614,9 @@ struct ma_device
#ifdef MA_SUPPORT_PULSEAUDIO
struct
{
/*pa_mainloop**/ ma_ptr pMainLoop;
/*pa_mainloop_api**/ ma_ptr pAPI;
/*pa_context**/ ma_ptr pPulseContext;
/*pa_stream**/ ma_ptr pStreamPlayback;
/*pa_stream**/ ma_ptr pStreamCapture;
/*pa_context_state*/ ma_uint32 pulseContextState;
void* pMappedBufferPlayback;
const void* pMappedBufferCapture;
ma_uint32 mappedBufferFramesRemainingPlayback;
ma_uint32 mappedBufferFramesRemainingCapture;
ma_uint32 mappedBufferFramesCapacityPlayback;
ma_uint32 mappedBufferFramesCapacityCapture;
ma_bool32 breakFromMainLoop : 1;
ma_pcm_rb duplexRB;
} pulse;
#endif
#ifdef MA_SUPPORT_JACK
......@@ -2391,7 +2637,8 @@ struct ma_device
ma_uint32 deviceObjectIDCapture;
/*AudioUnit*/ ma_ptr audioUnitPlayback;
/*AudioUnit*/ ma_ptr audioUnitCapture;
/*AudioBufferList**/ ma_ptr pAudioBufferList; /* Only used for input devices. */
/*AudioBufferList**/ ma_ptr pAudioBufferList; /* Only used for input devices. */
ma_uint32 audioBufferSizeInBytes; /* Only used for input devices. The size in bytes of each buffer in pAudioBufferList. */
ma_event stopEvent;
ma_uint32 originalPeriodSizeInFrames;
ma_uint32 originalPeriodSizeInMilliseconds;
......@@ -2484,7 +2731,7 @@ struct ma_device
};
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(pop)
#else
#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic pop /* For ISO C99 doesn't support unnamed structs/unions [-Wpedantic] */
#endif
......@@ -2570,7 +2817,7 @@ The context can be configured via the `pConfig` argument. The config object is i
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.
Callback for handling log messages from miniaudio.
threadPriority
The desired priority to use for the audio thread. Allowable values include the following:
......@@ -3144,7 +3391,7 @@ then be set directly on the structure. Below are the members of the `ma_device_c
ma_share_mode_shared and reinitializing.
wasapi.noAutoConvertSRC
WASAPI only. When set to true, disables WASAPI's automatic resampling and forces the use of miniaudio's resampler. Defaults to false.
WASAPI only. When set to true, disables WASAPI's automatic resampling and forces the use of miniaudio's resampler. Defaults to false.
wasapi.noDefaultQualitySRC
WASAPI only. Only used when `wasapi.noAutoConvertSRC` is set to false. When set to true, disables the use of `AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY`.
......@@ -3174,6 +3421,13 @@ then be set directly on the structure. Below are the members of the `ma_device_c
pulse.pStreamNameCapture
PulseAudio only. Sets the stream name for capture.
coreaudio.allowNominalSampleRateChange
Core Audio only. Desktop only. When enabled, allows the sample rate of the device to be changed at the operating system level. This
is disabled by default in order to prevent intrusive changes to the user's system. This is useful if you want to use a sample rate
that is known to be natively supported by the hardware thereby avoiding the cost of resampling. When set to true, miniaudio will
find the closest match between the sample rate requested in the device config and the sample rates natively supported by the
hardware. When set to false, the sample rate currently set by the operating system will always be used.
Once initialized, the device's config is immutable. If you need to change the config you will need to initialize a new device.
......@@ -3487,7 +3741,63 @@ See Also
ma_device_start()
ma_device_stop()
*/
MA_API ma_bool32 ma_device_is_started(ma_device* pDevice);
MA_API ma_bool32 ma_device_is_started(const ma_device* pDevice);
/*
Retrieves the state of the device.
Parameters
----------
pDevice (in)
A pointer to the device whose state is being retrieved.
Return Value
------------
The current state of the device. The return value will be one of the following:
+------------------------+------------------------------------------------------------------------------+
| MA_STATE_UNINITIALIZED | Will only be returned if the device is in the middle of initialization. |
+------------------------+------------------------------------------------------------------------------+
| MA_STATE_STOPPED | The device is stopped. The initial state of the device after initialization. |
+------------------------+------------------------------------------------------------------------------+
| MA_STATE_STARTED | The device started and requesting and/or delivering audio data. |
+------------------------+------------------------------------------------------------------------------+
| MA_STATE_STARTING | The device is in the process of starting. |
+------------------------+------------------------------------------------------------------------------+
| MA_STATE_STOPPING | The device is in the process of stopping. |
+------------------------+------------------------------------------------------------------------------+
Thread Safety
-------------
Safe. This is implemented as a simple accessor. Note that if the device is started or stopped at the same time as this function is called,
there's a possibility the return value could be out of sync. See remarks.
Callback Safety
---------------
Safe. This is implemented as a simple accessor.
Remarks
-------
The general flow of a devices state goes like this:
```
ma_device_init() -> MA_STATE_UNINITIALIZED -> MA_STATE_STOPPED
ma_device_start() -> MA_STATE_STARTING -> MA_STATE_STARTED
ma_device_stop() -> MA_STATE_STOPPING -> MA_STATE_STOPPED
```
When the state of the device is changed with `ma_device_start()` or `ma_device_stop()` at this same time as this function is called, the
value returned by this function could potentially be out of sync. If this is significant to your program you need to implement your own
synchronization.
*/
MA_API ma_uint32 ma_device_get_state(const ma_device* pDevice);
/*
Sets the master volume factor for the device.
......@@ -3671,6 +3981,56 @@ ma_device_get_master_volume()
MA_API ma_result ma_device_get_master_gain_db(ma_device* pDevice, float* pGainDB);
/*
Called from the data callback of asynchronous backends to allow miniaudio to process the data and fire the miniaudio data callback.
Parameters
----------
pDevice (in)
A pointer to device whose processing the data callback.
pOutput (out)
A pointer to the buffer that will receive the output PCM frame data. On a playback device this must not be NULL. On a duplex device
this can be NULL, in which case pInput must not be NULL.
pInput (in)
A pointer to the buffer containing input PCM frame data. On a capture device this must not be NULL. On a duplex device this can be
NULL, in which case `pOutput` must not be NULL.
frameCount (in)
The number of frames being processed.
Return Value
------------
MA_SUCCESS if successful; any other result code otherwise.
Thread Safety
-------------
This function should only ever be called from the internal data callback of the backend. It is safe to call this simultaneously between a
playback and capture device in duplex setups.
Callback Safety
---------------
Do not call this from the miniaudio data callback. It should only ever be called from the internal data callback of the backend.
Remarks
-------
If both `pOutput` and `pInput` are NULL, and error will be returned. In duplex scenarios, both `pOutput` and `pInput` can be non-NULL, in
which case `pInput` will be processed first, followed by `pOutput`.
If you are implementing a custom backend, and that backend uses a callback for data delivery, you'll need to call this from inside that
callback.
*/
MA_API ma_result ma_device_handle_backend_data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
/*
Retrieves a friendly name for a backend.
*/
......@@ -3687,14 +4047,14 @@ Retrieves compile-time enabled backends.
Parameters
----------
pBackends(out, optional)
pBackends (out, optional)
A pointer to the buffer that will receive the enabled backends. Set to NULL to retrieve the backend count. Setting
the capacity of the buffer to `MA_BUFFER_COUNT` will guarantee it's large enough for all backends.
backendCap(in)
backendCap (in)
The capacity of the `pBackends` buffer.
pBackendCount(out)
pBackendCount (out)
A pointer to the variable that will receive the enabled backend count.
......
/*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.10.23 - TBD
miniaudio - v0.10.23 - 2020-11-09
David Reid - mackron@gmail.com
......@@ -63725,7 +63725,7 @@ The following miscellaneous changes have also been made.
/*
REVISION HISTORY
================
v0.10.23 - TBD
v0.10.23 - 2020-11-09
- AAudio: Add support for configuring a playback stream's usage.
- Fix a compilation error when all built-in asynchronous backends are disabled at compile time.
- Fix compilation errors when compiling as C++.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment