/* 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). */
We need to explicitly signal the capture event in loopback mode to ensure we return from WaitForSingleObject() when nothing is being played. When nothing
It's possible for the main loop to get stuck if the device is disconnected.
In loopback mode it's possible for WaitForSingleObject() to get stuck in a deadlock when nothing is being played. When nothing
is being played, the event is never signalled internally by WASAPI which means we will deadlock when stopping the device.
if (c89atomic_fetch_sub_32(&g_maOpenSLInitCounter, 1) == 1) {
ma_spinlock_lock(&g_maOpenSLSpinlock);
{
MA_ASSERT(g_maOpenSLInitCounter > 0); /* If you've triggered this, it means you have ma_context_init/uninit mismatch. Each successful call to ma_context_init() must be matched up with a call to ma_context_uninit(). */
ma_copy_and_apply_volume_factor_pcm_frames(pPCMFrames, pPCMFrames, frameCount, format, channels, factor);
}
...
...
@@ -35298,7 +35526,8 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi
} else {
ma_format format;
ma_uint32 channels;
if (ma_data_source_get_data_format(pDataSource, &format, &channels) != MA_SUCCESS) {
ma_uint32 sampleRate;
if (ma_data_source_get_data_format(pDataSource, &format, &channels, &sampleRate) != MA_SUCCESS) {
return pCallbacks->onRead(pDataSource, pFramesOut, frameCount, pFramesRead); /* We don't have a way to retrieve the data format which means we don't know how to offset the output buffer. Just read as much as we can. */
} else {
ma_result result = MA_SUCCESS;
...
...
@@ -35317,7 +35546,7 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi
If we encounted an error from the read callback, make sure it's propagated to the caller. The caller may need to know whether or not MA_BUSY is returned which is
not necessarily considered an error.
*/
if (result != MA_SUCCESS) {
if (result != MA_SUCCESS && result != MA_AT_END) {
break;
}
...
...
@@ -35325,7 +35554,7 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi
We can determine if we've reached the end by checking the return value of the onRead() callback. If it's less than what we requested it means
we've reached the end. To loop back to the start, all we need to do is seek back to the first frame.
*/
if (framesProcessed < framesRemaining) {
if (framesProcessed < framesRemaining || result == MA_AT_END) {
if (ma_data_source_seek_to_pcm_frame(pDataSource, 0) != MA_SUCCESS) {
break;
}
...
...
@@ -35336,7 +35565,10 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi
}
}
*pFramesRead = totalFramesProcessed;
if (pFramesRead != NULL) {
*pFramesRead = totalFramesProcessed;
}
return result;
}
}
...
...
@@ -35377,18 +35609,19 @@ MA_API ma_result ma_data_source_unmap(ma_data_source* pDataSource, ma_uint64 fra
Getting here means we need to do data conversion. If we're seeking forward and are _not_ doing resampling we can run this in a fast path. If we're doing resampling we
need to run through each sample because we need to ensure it's internal cache is updated.
*/
if (pFramesOut == NULL && pDecoder->converter.hasResampler == MA_FALSE) {
return pDecoder->onReadPCMFrames(pDecoder, NULL, frameCount); /* All decoder backends must support passing in NULL for the output buffer. */
}
/* Slow path. Need to run everything through the data converter. */
Getting here means we need to do data conversion. If we're seeking forward and are _not_ doing resampling we can run this in a fast path. If we're doing resampling we
need to run through each sample because we need to ensure it's internal cache is updated.
*/
if (pFramesOut == NULL && pDecoder->converter.hasResampler == MA_FALSE) {
totalFramesReadOut = pDecoder->onReadPCMFrames(pDecoder, NULL, frameCount); /* All decoder backends must support passing in NULL for the output buffer. */
} else {
/* Slow path. Need to run everything through the data converter. */
totalFramesReadOut = 0;
totalFramesReadIn = 0;
pRunningFramesOut = pFramesOut;
while (totalFramesReadOut < frameCount) {
ma_uint8 pIntermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In internal format. */
ma_bool32noAudioSessionActivate;/* iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:true] on initialization. */
ma_bool32noAudioSessionDeactivate;/* iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:false] on uninitialization. */
}coreaudio;
struct
{
...
...
@@ -2075,6 +2056,8 @@ struct ma_context
ma_procAudioUnitRender;
/*AudioComponent*/ma_ptrcomponent;
ma_bool32noAudioSessionDeactivate;/* For tracking whether or not the iOS audio session should be explicitly deactivated. Set from the config in ma_context_init__coreaudio(). */
}coreaudio;
#endif
#ifdef MA_SUPPORT_SNDIO
...
...
@@ -2147,7 +2130,14 @@ struct ma_context
#ifdef MA_SUPPORT_OPENSL
struct
{
int_unused;
ma_handlelibOpenSLES;
ma_handleSL_IID_ENGINE;
ma_handleSL_IID_AUDIOIODEVICECAPABILITIES;
ma_handleSL_IID_ANDROIDSIMPLEBUFFERQUEUE;
ma_handleSL_IID_RECORD;
ma_handleSL_IID_PLAY;
ma_handleSL_IID_OUTPUTMIX;
ma_procslCreateEngine;
}opensl;
#endif
#ifdef MA_SUPPORT_WEBAUDIO
...
...
@@ -2248,6 +2238,7 @@ struct ma_device
}resampling;
struct
{
ma_device_idid;/* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */
charname[256];/* Maybe temporary. Likely to be replaced with a query API. */
ma_share_modeshareMode;/* Set to whatever was passed in when the device was initialized. */
ma_bool32usingDefaultFormat:1;
...
...
@@ -2266,6 +2257,7 @@ struct ma_device
}playback;
struct
{
ma_device_idid;/* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */
charname[256];/* Maybe temporary. Likely to be replaced with a query API. */
ma_share_modeshareMode;/* Set to whatever was passed in when the device was initialized. */
ma_bool32usingDefaultFormat:1;
...
...
@@ -3802,31 +3794,31 @@ Helper for applying a volume factor to samples.
Note that the source and destination buffers can be the same, in which case it'll perform the operation in-place.
ma_result(*onMap)(ma_data_source*pDataSource,void**ppFramesOut,ma_uint64*pFrameCount);/* Returns MA_AT_END if the end has been reached. This should be considered successful. */
MA_APIma_resultma_data_source_read_pcm_frames(ma_data_source*pDataSource,void*pFramesOut,ma_uint64frameCount,ma_uint64*pFramesRead,ma_bool32loop);/* Must support pFramesOut = NULL in which case a forward seek should be performed. */
MA_APIma_resultma_data_source_seek_pcm_frames(ma_data_source*pDataSource,ma_uint64frameCount,ma_uint64*pFramesSeeked,ma_bool32loop);/* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount); */
MA_APIma_resultma_data_source_unmap(ma_data_source*pDataSource,ma_uint64frameCount);/* Returns MA_AT_END if the end has been reached. This should be considered successful. */
MA_APIma_resultma_data_source_unmap(ma_data_source*pDataSource,ma_uint64frameCount);/* Returns MA_AT_END if the end has been reached. This should be considered successful. */
MA_APIma_resultma_data_source_get_length_in_pcm_frames(ma_data_source*pDataSource,ma_uint64*pLength);/* Returns MA_NOT_IMPLEMENTED if the length is unknown or cannot be determined. Decoders can return this. */
MA_APIma_resultma_audio_buffer_unmap(ma_audio_buffer*pAudioBuffer,ma_uint64frameCount);/* Returns MA_AT_END if the end has been reached. This should be considered successful. */