ma_resource_manager_data_buffer_uninit takes a synchronous teardown path as
soon as it observes result == MA_SUCCESS, freeing the buffer. But the load
job (ma_job_process__resource_manager__load_data_buffer) publishes that
result code via a CAS several instructions before it finishes referencing
the buffer: it still reads has_connector() and does the executionPointer
increment afterward. A concurrent uninit that observes MA_SUCCESS therefore
frees the buffer out from under the job tail, which then reads and
atomically increments freed (and possibly recycled) memory.
The asynchronous free path is safe because it waits on the order /
executionPointer ticket scheme; the synchronous shortcut bypassed it. Make
the synchronous path wait for executionPointer to catch up to
executionCounter before tearing down, so no job is still referencing the
buffer. Caught by ThreadSanitizer.
Support for custom attenuation models has been added.
Attenuation models are now a callback rather than an enumerator. The
callback takes a user data pointer in case the standard distance/rolloff
variables do not suffice. The following APIs have changed in order to
accommodate this:
ma_spatializer_set_attenuation_model()
ma_sound_set_attenuation_model()
ma_sound_group_set_attenuation_model()
These now take an extra parameter for the user data pointer. For stock
attenuation models this should always be set to NULL:
ma_sound_set_attenuation_model(&sound,
ma_attenuation_model_linear, NULL);
To plug in a custom model, just implement a callback and plug it in:
float your_custom_attenuation_model(
void* pUserData,
float distance,
float minDistance,
float maxDistance,
float rolloff)
{
// Return a value between 0 (silence) and 1 (full volume).
}
...
ma_sound_set_attenuation_model(&sound,
your_custom_attenuation_model, &userDataIfRequiredByYourModel);
Previously, setting the attenuation model to none would disable
spatialization completely. This behaviour has changed and now
spatialization will still be applied in this case. You should use
`ma_sound_set_spatialization_enabled(&sound, MA_FALSE)` instead if you
want to disable spatialization.
Prior to this commit, the number of frames read was always reported as
the whole frame count. This is incorrect for leaf nodes which don't
always produce the full frame count (an example being when the end of a
sound is reached).
This addresses a case when PulseAudio may negotiate S24_32 which is not
a format supported by miniaudio. This commit does two things to guard
against this:
* The requested format is now explicitly used instead of using the
queried format from `pa_context_get_source_info_by_name()`.
* The `PA_STREAM_FIX_FORMAT` stream flag is no longer used as that can
possibly negotiate something different to what we request. I.e., it
can possibly give us S24_32 which is not usable.
A new callback called `onProp` has been added to
`ma_data_source_vtable`. This replaces the following callbacks:
onGetDataFormat
onGetCursor
onGetLength
onSetLooping
This new callback is for retrieving and setting various properties
relating to the data source. It takes a `prop` parameter which is an ID
for the property being handled, and a `void*` pointer for
property-specific data.
Typically onProp implementations would discriminate on the property type
using a switch. The example below shows how to handle the old callbacks:
switch (prop)
{
// Replaces onGetDataFormat (format/channels/rate).
case MA_DATA_SOURCE_GET_DATA_SOURCE:
{
ma_data_source_data_format* pDataFormat =
(ma_data_source_data_format*)pData;
pDataFormat->format = pCustomDataSource->format;
pDataFormat->channels = pCustomDataSource->channels;
pDataFormat->sampleRate = pCustomDataSource->sampleRate;
return MA_SUCCESS;
}
// Replaces onGetDataFormat (channel map)
case MA_DATA_SOURCE_GET_CHANNEL_MAP:
{
ma_channel_map_init_standard(
ma_standard_channel_map_default,
(ma_channel*)pData,
MA_MAX_CHANNELS,
pCustomDataSource->channels);
return MA_SUCCESS;
}
// Replaces onGetCursor
case MA_DATA_SOURCE_GET_CURSOR:
{
*((ma_uint64*)pData) = pCustomDataSource->cursor;
return MA_SUCCESS;
}
// Replaces onGetLength
case MA_DATA_SOURCE_GET_LENGTH:
{
*((ma_uint64*)pData) = pCustomDataSource->length;
return MA_SUCCESS;
}
// Replaces onSetLooping
case MA_DATA_SOURCE_SET_LOOPING:
{
pCustomDataSource->isLooping = *((ma_bool32*)pData);
return MA_SUCCESS;
}
// Mandatory when MA_DATA_SOURCE_SET_LOOPING is implemented.
case MA_DATA_SOURCE_GET_LOOPING:
{
*((ma_bool32*)pData) = pCustomDataSource->isLooping;
return MA_SUCCESS;
}
// Return MA_NOT_IMPLEMENTED for any ignored properties.
default: return MA_NOT_IMPLEMENTED;
}
Note how the format/channels/rate and channel map properties have been
split across two separate properties, `MA_DATA_SOURCE_GET_DATA_SOURCE`
and `MA_DATA_SOURCE_GET_CHANNEL_MAP`. Along with this change, the
channel map parameters have been removed from
`ma_data_source_get_data_format()` and a new function called
`ma_data_source_get_channel_map()` has been added.
New properties have also been added for handling ranges and loop points.
This allows the data source implementation itself to handle it rather
than miniaudio doing it at a higher level. Where this is useful is if
your data source is a wrapper around another data source and you want to
route ranges and loop points to the internal data source.
The reason for this change is that it allows for properties to be added
without having to break the build due to yet another callback being
added. It also hides away the more niche properties that the majority of
data sources do not care about. For example, rarely does a data source
need to handle the `onSetLooping` callback, yet every data source needed
to add a `NULL` entry to their vtables just for this one extremely niche
property.
See documentation for further details.
Tag: release-notes
Tag: api-change