mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-23 00:34:03 +02:00
Fix some subtle multi-threading errors due to lacking atomic loads.
Public issue https://github.com/mackron/miniaudio/issues/237
This commit is contained in:
+37
-37
@@ -4006,12 +4006,12 @@ struct ma_device
|
||||
ma_uint32 originalPeriodSizeInMilliseconds;
|
||||
ma_uint32 originalPeriods;
|
||||
ma_performance_profile originalPerformanceProfile;
|
||||
ma_bool32 hasDefaultPlaybackDeviceChanged; /* <-- Make sure this is always a whole 32-bits because we use atomic assignments. */
|
||||
ma_bool32 hasDefaultCaptureDeviceChanged; /* <-- Make sure this is always a whole 32-bits because we use atomic assignments. */
|
||||
volatile ma_bool32 hasDefaultPlaybackDeviceChanged; /* <-- Make sure this is always a whole 32-bits because we use atomic assignments. */
|
||||
volatile ma_bool32 hasDefaultCaptureDeviceChanged; /* <-- Make sure this is always a whole 32-bits because we use atomic assignments. */
|
||||
ma_uint32 periodSizeInFramesPlayback;
|
||||
ma_uint32 periodSizeInFramesCapture;
|
||||
ma_bool32 isStartedCapture; /* <-- Make sure this is always a whole 32-bits because we use atomic assignments. */
|
||||
ma_bool32 isStartedPlayback; /* <-- Make sure this is always a whole 32-bits because we use atomic assignments. */
|
||||
volatile ma_bool32 isStartedCapture; /* <-- Make sure this is always a whole 32-bits because we use atomic assignments. */
|
||||
volatile ma_bool32 isStartedPlayback; /* <-- Make sure this is always a whole 32-bits because we use atomic assignments. */
|
||||
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;
|
||||
@@ -4162,14 +4162,14 @@ struct ma_device
|
||||
ma_event operationCompletionEvent;
|
||||
ma_semaphore operationSemaphore;
|
||||
ma_uint32 operation;
|
||||
ma_result operationResult;
|
||||
volatile ma_result operationResult;
|
||||
ma_timer timer;
|
||||
double priorRunTime;
|
||||
ma_uint32 currentPeriodFramesRemainingPlayback;
|
||||
ma_uint32 currentPeriodFramesRemainingCapture;
|
||||
ma_uint64 lastProcessedFramePlayback;
|
||||
ma_uint64 lastProcessedFrameCapture;
|
||||
ma_bool32 isStarted;
|
||||
volatile ma_bool32 isStarted;
|
||||
} null_device;
|
||||
#endif
|
||||
};
|
||||
@@ -12176,7 +12176,7 @@ static ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrame
|
||||
*pFramesWritten = 0;
|
||||
}
|
||||
|
||||
wasStartedOnEntry = pDevice->null_device.isStarted;
|
||||
wasStartedOnEntry = c89atomic_load_32(&pDevice->null_device.isStarted);
|
||||
|
||||
/* Keep going until everything has been read. */
|
||||
totalPCMFramesProcessed = 0;
|
||||
@@ -12202,7 +12202,7 @@ static ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrame
|
||||
if (pDevice->null_device.currentPeriodFramesRemainingPlayback == 0) {
|
||||
pDevice->null_device.currentPeriodFramesRemainingPlayback = 0;
|
||||
|
||||
if (!pDevice->null_device.isStarted && !wasStartedOnEntry) {
|
||||
if (!c89atomic_load_32(&pDevice->null_device.isStarted) && !wasStartedOnEntry) {
|
||||
result = ma_device_start__null(pDevice);
|
||||
if (result != MA_SUCCESS) {
|
||||
break;
|
||||
@@ -12222,7 +12222,7 @@ static ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrame
|
||||
ma_uint64 currentFrame;
|
||||
|
||||
/* Stop waiting if the device has been stopped. */
|
||||
if (!pDevice->null_device.isStarted) {
|
||||
if (!c89atomic_load_32(&pDevice->null_device.isStarted)) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -12293,7 +12293,7 @@ static ma_result ma_device_read__null(ma_device* pDevice, void* pPCMFrames, ma_u
|
||||
ma_uint64 currentFrame;
|
||||
|
||||
/* Stop waiting if the device has been stopped. */
|
||||
if (!pDevice->null_device.isStarted) {
|
||||
if (!c89atomic_load_32(&pDevice->null_device.isStarted)) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -13153,7 +13153,7 @@ typedef struct
|
||||
struct ma_completion_handler_uwp
|
||||
{
|
||||
ma_completion_handler_uwp_vtbl* lpVtbl;
|
||||
ma_uint32 counter;
|
||||
volatile ma_uint32 counter;
|
||||
HANDLE hEvent;
|
||||
};
|
||||
|
||||
@@ -13367,7 +13367,7 @@ static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDefaultDeviceChanged
|
||||
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);
|
||||
c89atomic_exchange_32(&pThis->pDevice->wasapi.hasDefaultCaptureDeviceChanged, MA_TRUE);
|
||||
}
|
||||
|
||||
(void)pDefaultDeviceID;
|
||||
@@ -14550,7 +14550,7 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev
|
||||
ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualPeriodSizeInFramesCapture);
|
||||
|
||||
/* The device may be in a started state. If so we need to immediately restart it. */
|
||||
if (pDevice->wasapi.isStartedCapture) {
|
||||
if (c89atomic_load_32(&pDevice->wasapi.isStartedCapture)) {
|
||||
HRESULT hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
|
||||
if (FAILED(hr)) {
|
||||
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal capture device after reinitialization.", ma_result_from_HRESULT(hr));
|
||||
@@ -14586,7 +14586,7 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev
|
||||
ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualPeriodSizeInFramesPlayback);
|
||||
|
||||
/* The device may be in a started state. If so we need to immediately restart it. */
|
||||
if (pDevice->wasapi.isStartedPlayback) {
|
||||
if (c89atomic_load_32(&pDevice->wasapi.isStartedPlayback)) {
|
||||
HRESULT hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
|
||||
if (FAILED(hr)) {
|
||||
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device after reinitialization.", ma_result_from_HRESULT(hr));
|
||||
@@ -14849,11 +14849,11 @@ static ma_bool32 ma_device_is_reroute_required__wasapi(ma_device* pDevice, ma_de
|
||||
MA_ASSERT(pDevice != NULL);
|
||||
|
||||
if (deviceType == ma_device_type_playback) {
|
||||
return pDevice->wasapi.hasDefaultPlaybackDeviceChanged;
|
||||
return c89atomic_load_32(&pDevice->wasapi.hasDefaultPlaybackDeviceChanged);
|
||||
}
|
||||
|
||||
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
|
||||
return pDevice->wasapi.hasDefaultCaptureDeviceChanged;
|
||||
return c89atomic_load_32(&pDevice->wasapi.hasDefaultCaptureDeviceChanged);
|
||||
}
|
||||
|
||||
return MA_FALSE;
|
||||
@@ -15258,7 +15258,7 @@ static ma_result ma_device_audio_thread__wasapi(ma_device* pDevice)
|
||||
mappedDeviceBufferSizeInFramesPlayback = 0;
|
||||
}
|
||||
|
||||
if (!pDevice->wasapi.isStartedPlayback) {
|
||||
if (!c89atomic_load_32(&pDevice->wasapi.isStartedPlayback)) {
|
||||
ma_uint32 startThreshold = pDevice->playback.internalPeriodSizeInFrames * 1;
|
||||
|
||||
/* Prevent a deadlock. If we don't clamp against the actual buffer size we'll never end up starting the playback device which will result in a deadlock. */
|
||||
@@ -15424,7 +15424,7 @@ static ma_result ma_device_audio_thread__wasapi(ma_device* pDevice)
|
||||
}
|
||||
|
||||
framesWrittenToPlaybackDevice += framesAvailablePlayback;
|
||||
if (!pDevice->wasapi.isStartedPlayback) {
|
||||
if (!c89atomic_load_32(&pDevice->wasapi.isStartedPlayback)) {
|
||||
if (pDevice->playback.shareMode == ma_share_mode_exclusive || framesWrittenToPlaybackDevice >= pDevice->playback.internalPeriodSizeInFrames*1) {
|
||||
hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
|
||||
if (FAILED(hr)) {
|
||||
@@ -15472,7 +15472,7 @@ static ma_result ma_device_audio_thread__wasapi(ma_device* pDevice)
|
||||
The buffer needs to be drained before stopping the device. Not doing this will result in the last few frames not getting output to
|
||||
the speakers. This is a problem for very short sounds because it'll result in a significant portion of it not getting played.
|
||||
*/
|
||||
if (pDevice->wasapi.isStartedPlayback) {
|
||||
if (c89atomic_load_32(&pDevice->wasapi.isStartedPlayback)) {
|
||||
/* We need to make sure we put a timeout here or else we'll risk getting stuck in a deadlock in some cases. */
|
||||
DWORD waitTime = pDevice->wasapi.actualPeriodSizeInFramesPlayback / pDevice->playback.internalSampleRate;
|
||||
|
||||
@@ -30701,7 +30701,7 @@ static void ma_buffer_queue_callback_capture__opensl_android(SLAndroidSimpleBuff
|
||||
*/
|
||||
|
||||
/* Don't do anything if the device is not started. */
|
||||
if (pDevice->state != MA_STATE_STARTED) {
|
||||
if (ma_device_get_state(pDevice) != MA_STATE_STARTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -30739,7 +30739,7 @@ static void ma_buffer_queue_callback_playback__opensl_android(SLAndroidSimpleBuf
|
||||
(void)pBufferQueue;
|
||||
|
||||
/* Don't do anything if the device is not started. */
|
||||
if (pDevice->state != MA_STATE_STARTED) {
|
||||
if (ma_device_get_state(pDevice) != MA_STATE_STARTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -42263,13 +42263,13 @@ static MA_INLINE ma_uint32 ma_rb__extract_offset_loop_flag(ma_uint32 encodedOffs
|
||||
static MA_INLINE void* ma_rb__get_read_ptr(ma_rb* pRB)
|
||||
{
|
||||
MA_ASSERT(pRB != NULL);
|
||||
return ma_offset_ptr(pRB->pBuffer, ma_rb__extract_offset_in_bytes(pRB->encodedReadOffset));
|
||||
return ma_offset_ptr(pRB->pBuffer, ma_rb__extract_offset_in_bytes(c89atomic_load_32(&pRB->encodedReadOffset)));
|
||||
}
|
||||
|
||||
static MA_INLINE void* ma_rb__get_write_ptr(ma_rb* pRB)
|
||||
{
|
||||
MA_ASSERT(pRB != NULL);
|
||||
return ma_offset_ptr(pRB->pBuffer, ma_rb__extract_offset_in_bytes(pRB->encodedWriteOffset));
|
||||
return ma_offset_ptr(pRB->pBuffer, ma_rb__extract_offset_in_bytes(c89atomic_load_32(&pRB->encodedWriteOffset)));
|
||||
}
|
||||
|
||||
static MA_INLINE ma_uint32 ma_rb__construct_offset(ma_uint32 offsetInBytes, ma_uint32 offsetLoopFlag)
|
||||
@@ -42362,8 +42362,8 @@ MA_API void ma_rb_reset(ma_rb* pRB)
|
||||
return;
|
||||
}
|
||||
|
||||
pRB->encodedReadOffset = 0;
|
||||
pRB->encodedWriteOffset = 0;
|
||||
c89atomic_exchange_32(&pRB->encodedReadOffset, 0);
|
||||
c89atomic_exchange_32(&pRB->encodedWriteOffset, 0);
|
||||
}
|
||||
|
||||
MA_API ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut)
|
||||
@@ -42382,10 +42382,10 @@ MA_API ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppB
|
||||
}
|
||||
|
||||
/* The returned buffer should never move ahead of the write pointer. */
|
||||
writeOffset = pRB->encodedWriteOffset;
|
||||
writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset);
|
||||
ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
|
||||
|
||||
readOffset = pRB->encodedReadOffset;
|
||||
readOffset = c89atomic_load_32(&pRB->encodedReadOffset);
|
||||
ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
|
||||
|
||||
/*
|
||||
@@ -42426,7 +42426,7 @@ MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes, void* pBuffer
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
readOffset = pRB->encodedReadOffset;
|
||||
readOffset = c89atomic_load_32(&pRB->encodedReadOffset);
|
||||
ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
|
||||
|
||||
/* Check that sizeInBytes is correct. It should never go beyond the end of the buffer. */
|
||||
@@ -42462,10 +42462,10 @@ MA_API ma_result ma_rb_acquire_write(ma_rb* pRB, size_t* pSizeInBytes, void** pp
|
||||
}
|
||||
|
||||
/* The returned buffer should never overtake the read buffer. */
|
||||
readOffset = pRB->encodedReadOffset;
|
||||
readOffset = c89atomic_load_32(&pRB->encodedReadOffset);
|
||||
ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
|
||||
|
||||
writeOffset = pRB->encodedWriteOffset;
|
||||
writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset);
|
||||
ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
|
||||
|
||||
/*
|
||||
@@ -42512,7 +42512,7 @@ MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes, void* pBuffe
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
writeOffset = pRB->encodedWriteOffset;
|
||||
writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset);
|
||||
ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
|
||||
|
||||
/* Check that sizeInBytes is correct. It should never go beyond the end of the buffer. */
|
||||
@@ -42547,10 +42547,10 @@ MA_API ma_result ma_rb_seek_read(ma_rb* pRB, size_t offsetInBytes)
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
readOffset = pRB->encodedReadOffset;
|
||||
readOffset = c89atomic_load_32(&pRB->encodedReadOffset);
|
||||
ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
|
||||
|
||||
writeOffset = pRB->encodedWriteOffset;
|
||||
writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset);
|
||||
ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
|
||||
|
||||
newReadOffsetLoopFlag = readOffsetLoopFlag;
|
||||
@@ -42591,10 +42591,10 @@ MA_API ma_result ma_rb_seek_write(ma_rb* pRB, size_t offsetInBytes)
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
readOffset = pRB->encodedReadOffset;
|
||||
readOffset = c89atomic_load_32(&pRB->encodedReadOffset);
|
||||
ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
|
||||
|
||||
writeOffset = pRB->encodedWriteOffset;
|
||||
writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset);
|
||||
ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
|
||||
|
||||
newWriteOffsetLoopFlag = writeOffsetLoopFlag;
|
||||
@@ -42633,10 +42633,10 @@ MA_API ma_int32 ma_rb_pointer_distance(ma_rb* pRB)
|
||||
return 0;
|
||||
}
|
||||
|
||||
readOffset = pRB->encodedReadOffset;
|
||||
readOffset = c89atomic_load_32(&pRB->encodedReadOffset);
|
||||
ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
|
||||
|
||||
writeOffset = pRB->encodedWriteOffset;
|
||||
writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset);
|
||||
ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
|
||||
|
||||
if (readOffsetLoopFlag == writeOffsetLoopFlag) {
|
||||
|
||||
Reference in New Issue
Block a user