From 757a4d617dee1cff4031ac725604c1968d227f90 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 29 Sep 2019 08:46:29 +1000 Subject: [PATCH] Improvements to pre-init of the output buffer in the data callback. This commit makes it well defined as to whether or not the output buffer passed in to the data callback is initialized to zero or left undefined. By default it's initialized to zero, but can be changed to undefined by setting noPreZeroedOutputBuffer in the device config. --- miniaudio.h | 648 +++++++++++++++++++++++++--------------------------- 1 file changed, 313 insertions(+), 335 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 821348d7..da93c2a4 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -261,9 +261,9 @@ NOTES ===== - This library uses an asynchronous API for delivering and requesting audio data. Each device will have it's own worker thread which is managed by the library. -- If ma_device_init() is called with a device that's not aligned to the platform's natural alignment - boundary (4 bytes on 32-bit, 8 bytes on 64-bit), it will _not_ be thread-safe. The reason for this - is that it depends on members of ma_device being correctly aligned for atomic assignments. +- If ma_device_init() is called with a device that's not aligned to the 4 bytes on 32-bit or 8 bytes on + 64-bit it will _not_ be thread-safe. The reason for this is that it depends on members of ma_device being + correctly aligned for atomic assignments. - Sample data is always native-endian and interleaved. For example, ma_format_s16 means signed 16-bit integer samples, interleaved. Let me know if you need non-interleaved and I'll look into it. - The sndio backend is currently only enabled on OpenBSD builds. @@ -271,6 +271,9 @@ NOTES - Automatic stream routing is enabled on a per-backend basis. Support is explicitly enabled for WASAPI and Core Audio, however other backends such as PulseAudio may naturally support it, though not all have been tested. +- The contents of the output buffer passed into the data callback will always be pre-initialized to zero + unless the noPreZeroedOutputBuffer config variable in ma_device_config is set to true, in which case + it'll be undefined which will require you to write something to the entire buffer. BACKEND NUANCES @@ -1918,6 +1921,7 @@ typedef struct ma_uint32 bufferSizeInMilliseconds; ma_uint32 periods; ma_performance_profile performanceProfile; + ma_bool32 noPreZeroedOutputBuffer; /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to zero. */ ma_device_callback_proc dataCallback; ma_stop_proc stopCallback; void* pUserData; @@ -2366,10 +2370,11 @@ MA_ALIGNED_STRUCT(MA_SIMD_ALIGNMENT) ma_device 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 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; struct { char name[256]; /* Maybe temporary. Likely to be replaced with a query API. */ @@ -5291,25 +5296,32 @@ void ma_zero_pcm_frames(void* p, ma_uint32 frameCount, ma_format format, ma_uint } +static MA_INLINE void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) +{ + ma_device_callback_proc onData; + + onData = pDevice->onData; + if (onData) { + if (!pDevice->noPreZeroedOutputBuffer && pFramesOut != NULL) { + ma_zero_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels); + } + + onData(pDevice, pFramesOut, pFramesIn, frameCount); + } +} + /* The callback for reading from the client -> DSP -> device. */ ma_uint32 ma_device__on_read_from_client(ma_pcm_converter* pDSP, void* pFramesOut, ma_uint32 frameCount, void* pUserData) { ma_device* pDevice = (ma_device*)pUserData; - ma_device_callback_proc onData; ma_assert(pDevice != NULL); - ma_zero_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels); - - onData = pDevice->onData; - if (onData) { - onData(pDevice, pFramesOut, NULL, frameCount); - return frameCount; - } + ma_device__on_data(pDevice, pFramesOut, NULL, frameCount); (void)pDSP; - return 0; + return frameCount; } /* The PCM converter callback for reading from a buffer. */ @@ -5368,56 +5380,45 @@ ma_uint32 ma_device__pcm_converter__on_read_from_buffer_playback(ma_pcm_converte /* A helper function for reading sample data from the client. */ static MA_INLINE void ma_device__read_frames_from_client(ma_device* pDevice, ma_uint32 frameCount, void* pFramesOut) { - ma_device_callback_proc onData; - ma_assert(pDevice != NULL); ma_assert(frameCount > 0); ma_assert(pFramesOut != NULL); - onData = pDevice->onData; - if (onData) { - if (pDevice->playback.converter.isPassthrough) { - ma_zero_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels); - onData(pDevice, pFramesOut, NULL, frameCount); - } else { - ma_pcm_converter_read(&pDevice->playback.converter, pFramesOut, frameCount); - } + if (pDevice->playback.converter.isPassthrough) { + ma_device__on_data(pDevice, pFramesOut, NULL, frameCount); + } else { + ma_pcm_converter_read(&pDevice->playback.converter, pFramesOut, frameCount); } } /* A helper for sending sample data to the client. */ static MA_INLINE void ma_device__send_frames_to_client(ma_device* pDevice, ma_uint32 frameCount, const void* pFrames) { - ma_device_callback_proc onData; - ma_assert(pDevice != NULL); ma_assert(frameCount > 0); ma_assert(pFrames != NULL); - onData = pDevice->onData; - if (onData) { - if (pDevice->capture.converter.isPassthrough) { - onData(pDevice, NULL, pFrames, frameCount); - } else { - ma_uint8 chunkBuffer[4096]; - ma_uint32 chunkFrameCount; + if (pDevice->capture.converter.isPassthrough) { + ma_device__on_data(pDevice, NULL, pFrames, frameCount); + } else { + ma_uint8 chunkBuffer[4096]; + ma_uint32 chunkFrameCount; - pDevice->capture._dspFrameCount = frameCount; - pDevice->capture._dspFrames = (const ma_uint8*)pFrames; + pDevice->capture._dspFrameCount = frameCount; + pDevice->capture._dspFrames = (const ma_uint8*)pFrames; - chunkFrameCount = sizeof(chunkBuffer) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); + chunkFrameCount = sizeof(chunkBuffer) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); - for (;;) { - ma_uint32 framesJustRead = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, chunkBuffer, chunkFrameCount); - if (framesJustRead == 0) { - break; - } + for (;;) { + ma_uint32 framesJustRead = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, chunkBuffer, chunkFrameCount); + if (framesJustRead == 0) { + break; + } - onData(pDevice, NULL, chunkBuffer, framesJustRead); + ma_device__on_data(pDevice, NULL, chunkBuffer, framesJustRead); - if (framesJustRead < chunkFrameCount) { - break; - } + if (framesJustRead < chunkFrameCount) { + break; } } } @@ -5510,7 +5511,7 @@ static MA_INLINE ma_result ma_device__handle_duplex_callback_playback(ma_device* if (result == MA_SUCCESS) { if (inputFrameCount > 0) { /* Use actual input frames. */ - pDevice->onData(pDevice, playbackFramesInExternalFormat, pInputFrames, inputFrameCount); + ma_device__on_data(pDevice, playbackFramesInExternalFormat, pInputFrames, inputFrameCount); } else { if (ma_pcm_rb_pointer_disance(pRB) == 0) { break; /* Underrun. */ @@ -5529,7 +5530,7 @@ static MA_INLINE ma_result ma_device__handle_duplex_callback_playback(ma_device* sizeof(silentInputFrames) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels) ); - pDevice->onData(pDevice, playbackFramesInExternalFormat, silentInputFrames, inputFrameCount); + ma_device__on_data(pDevice, playbackFramesInExternalFormat, silentInputFrames, inputFrameCount); } /* We have samples in external format so now we need to convert to internal format and output to the device. */ @@ -6104,7 +6105,6 @@ ma_result ma_device_main_loop__null(ma_device* pDevice) ma_uint32 periodSizeInFrames = ma_min(pDevice->capture.internalBufferSizeInFrames/pDevice->capture.internalPeriods, pDevice->playback.internalBufferSizeInFrames/pDevice->playback.internalPeriods); while (totalFramesProcessed < periodSizeInFrames) { - ma_device_callback_proc onData; ma_uint32 framesRemaining = periodSizeInFrames - totalFramesProcessed; ma_uint32 framesProcessed; ma_uint32 framesToProcess = framesRemaining; @@ -6118,54 +6118,51 @@ ma_result ma_device_main_loop__null(ma_device* pDevice) break; } - onData = pDevice->onData; - if (onData != NULL) { - pDevice->capture._dspFrameCount = framesToProcess; - pDevice->capture._dspFrames = capturedDeviceData; + pDevice->capture._dspFrameCount = framesToProcess; + pDevice->capture._dspFrames = capturedDeviceData; + for (;;) { + ma_uint8 capturedData[8192]; + ma_uint8 playbackData[8192]; + ma_uint32 capturedDataCapInFrames = sizeof(capturedData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); + ma_uint32 playbackDataCapInFrames = sizeof(playbackData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); + + ma_uint32 capturedFramesToTryProcessing = ma_min(capturedDataCapInFrames, playbackDataCapInFrames); + ma_uint32 capturedFramesToProcess = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, capturedData, capturedFramesToTryProcessing); + if (capturedFramesToProcess == 0) { + break; /* Don't fire the data callback with zero frames. */ + } + + ma_device__on_data(pDevice, playbackData, capturedData, capturedFramesToProcess); + + /* At this point the playbackData buffer should be holding data that needs to be written to the device. */ + pDevice->playback._dspFrameCount = capturedFramesToProcess; + pDevice->playback._dspFrames = playbackData; for (;;) { - ma_uint8 capturedData[8192]; - ma_uint8 playbackData[8192]; - ma_uint32 capturedDataCapInFrames = sizeof(capturedData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); - ma_uint32 playbackDataCapInFrames = sizeof(playbackData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); - - ma_uint32 capturedFramesToTryProcessing = ma_min(capturedDataCapInFrames, playbackDataCapInFrames); - ma_uint32 capturedFramesToProcess = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, capturedData, capturedFramesToTryProcessing); - if (capturedFramesToProcess == 0) { - break; /* Don't fire the data callback with zero frames. */ - } - - onData(pDevice, playbackData, capturedData, capturedFramesToProcess); - - /* At this point the playbackData buffer should be holding data that needs to be written to the device. */ - pDevice->playback._dspFrameCount = capturedFramesToProcess; - pDevice->playback._dspFrames = playbackData; - for (;;) { - ma_uint32 playbackDeviceFramesCount = (ma_uint32)ma_pcm_converter_read(&pDevice->playback.converter, playbackDeviceData, playbackDeviceDataCapInFrames); - if (playbackDeviceFramesCount == 0) { - break; - } - - result = ma_device_write__null(pDevice, playbackDeviceData, playbackDeviceFramesCount, NULL); - if (result != MA_SUCCESS) { - exitLoop = MA_TRUE; - break; - } - - if (playbackDeviceFramesCount < playbackDeviceDataCapInFrames) { - break; - } - } - - if (capturedFramesToProcess < capturedFramesToTryProcessing) { + ma_uint32 playbackDeviceFramesCount = (ma_uint32)ma_pcm_converter_read(&pDevice->playback.converter, playbackDeviceData, playbackDeviceDataCapInFrames); + if (playbackDeviceFramesCount == 0) { break; } - /* In case an error happened from ma_device_write2__alsa()... */ + result = ma_device_write__null(pDevice, playbackDeviceData, playbackDeviceFramesCount, NULL); if (result != MA_SUCCESS) { exitLoop = MA_TRUE; break; } + + if (playbackDeviceFramesCount < playbackDeviceDataCapInFrames) { + break; + } + } + + if (capturedFramesToProcess < capturedFramesToTryProcessing) { + break; + } + + /* In case an error happened from ma_device_write2__alsa()... */ + if (result != MA_SUCCESS) { + exitLoop = MA_TRUE; + break; } } @@ -8812,7 +8809,7 @@ ma_result ma_device_main_loop__wasapi(ma_device* pDevice) framesToProcess = ma_min(mappedBufferFramesRemainingCapture, mappedBufferFramesRemainingPlayback); framesProcessed = framesToProcess; - pDevice->onData(pDevice, pRunningBufferPlayback, pRunningBufferCapture, framesToProcess); + ma_device__on_data(pDevice, pRunningBufferPlayback, pRunningBufferCapture, framesToProcess); mappedBufferFramesRemainingCapture -= framesProcessed; mappedBufferFramesRemainingPlayback -= framesProcessed; @@ -8828,7 +8825,7 @@ ma_result ma_device_main_loop__wasapi(ma_device* pDevice) framesToProcess = ma_min(mappedBufferFramesRemainingCapture, outputDataInExternalFormatCap); framesProcessed = framesToProcess; - pDevice->onData(pDevice, outputDataInExternalFormat, pRunningBufferCapture, framesToProcess); + ma_device__on_data(pDevice, outputDataInExternalFormat, pRunningBufferCapture, framesToProcess); mappedBufferFramesRemainingCapture -= framesProcessed; pDevice->playback._dspFrameCount = framesProcessed; @@ -8847,7 +8844,7 @@ ma_result ma_device_main_loop__wasapi(ma_device* pDevice) break; } - pDevice->onData(pDevice, pRunningBufferPlayback, inputDataInExternalFormat, framesProcessed); + ma_device__on_data(pDevice, pRunningBufferPlayback, inputDataInExternalFormat, framesProcessed); mappedBufferFramesRemainingPlayback -= framesProcessed; if (framesProcessed < framesToProcess) { @@ -8867,7 +8864,7 @@ ma_result ma_device_main_loop__wasapi(ma_device* pDevice) break; } - pDevice->onData(pDevice, outputDataInExternalFormat, inputDataInExternalFormat, framesProcessed); + ma_device__on_data(pDevice, outputDataInExternalFormat, inputDataInExternalFormat, framesProcessed); pDevice->playback._dspFrameCount = framesProcessed; pDevice->playback._dspFrames = (const ma_uint8*)outputDataInExternalFormat; @@ -10437,7 +10434,7 @@ ma_result ma_device_main_loop__dsound(ma_device* pDevice) break; /* No more input data. */ } - pDevice->onData(pDevice, outputFramesInExternalFormat, inputFramesInExternalFormat, inputFramesInExternalFormatCount); + ma_device__on_data(pDevice, outputFramesInExternalFormat, inputFramesInExternalFormat, inputFramesInExternalFormatCount); /* At this point we have input and output data in external format. All we need to do now is convert it to the output format. This may take a few passes. */ pDevice->playback._dspFrameCount = inputFramesInExternalFormatCount; @@ -11893,7 +11890,6 @@ ma_result ma_device_main_loop__winmm(ma_device* pDevice) ma_uint32 periodSizeInFrames = ma_min(pDevice->capture.internalBufferSizeInFrames/pDevice->capture.internalPeriods, pDevice->playback.internalBufferSizeInFrames/pDevice->playback.internalPeriods); while (totalFramesProcessed < periodSizeInFrames) { - ma_device_callback_proc onData; ma_uint32 framesRemaining = periodSizeInFrames - totalFramesProcessed; ma_uint32 framesProcessed; ma_uint32 framesToProcess = framesRemaining; @@ -11907,54 +11903,51 @@ ma_result ma_device_main_loop__winmm(ma_device* pDevice) break; } - onData = pDevice->onData; - if (onData != NULL) { - pDevice->capture._dspFrameCount = framesToProcess; - pDevice->capture._dspFrames = capturedDeviceData; + pDevice->capture._dspFrameCount = framesToProcess; + pDevice->capture._dspFrames = capturedDeviceData; + for (;;) { + ma_uint8 capturedData[8192]; + ma_uint8 playbackData[8192]; + ma_uint32 capturedDataCapInFrames = sizeof(capturedData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); + ma_uint32 playbackDataCapInFrames = sizeof(playbackData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); + + ma_uint32 capturedFramesToTryProcessing = ma_min(capturedDataCapInFrames, playbackDataCapInFrames); + ma_uint32 capturedFramesToProcess = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, capturedData, capturedFramesToTryProcessing); + if (capturedFramesToProcess == 0) { + break; /* Don't fire the data callback with zero frames. */ + } + + ma_device__on_data(pDevice, playbackData, capturedData, capturedFramesToProcess); + + /* At this point the playbackData buffer should be holding data that needs to be written to the device. */ + pDevice->playback._dspFrameCount = capturedFramesToProcess; + pDevice->playback._dspFrames = playbackData; for (;;) { - ma_uint8 capturedData[8192]; - ma_uint8 playbackData[8192]; - ma_uint32 capturedDataCapInFrames = sizeof(capturedData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); - ma_uint32 playbackDataCapInFrames = sizeof(playbackData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); - - ma_uint32 capturedFramesToTryProcessing = ma_min(capturedDataCapInFrames, playbackDataCapInFrames); - ma_uint32 capturedFramesToProcess = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, capturedData, capturedFramesToTryProcessing); - if (capturedFramesToProcess == 0) { - break; /* Don't fire the data callback with zero frames. */ - } - - onData(pDevice, playbackData, capturedData, capturedFramesToProcess); - - /* At this point the playbackData buffer should be holding data that needs to be written to the device. */ - pDevice->playback._dspFrameCount = capturedFramesToProcess; - pDevice->playback._dspFrames = playbackData; - for (;;) { - ma_uint32 playbackDeviceFramesCount = (ma_uint32)ma_pcm_converter_read(&pDevice->playback.converter, playbackDeviceData, playbackDeviceDataCapInFrames); - if (playbackDeviceFramesCount == 0) { - break; - } - - result = ma_device_write__winmm(pDevice, playbackDeviceData, playbackDeviceFramesCount, NULL); - if (result != MA_SUCCESS) { - exitLoop = MA_TRUE; - break; - } - - if (playbackDeviceFramesCount < playbackDeviceDataCapInFrames) { - break; - } - } - - if (capturedFramesToProcess < capturedFramesToTryProcessing) { + ma_uint32 playbackDeviceFramesCount = (ma_uint32)ma_pcm_converter_read(&pDevice->playback.converter, playbackDeviceData, playbackDeviceDataCapInFrames); + if (playbackDeviceFramesCount == 0) { break; } - /* In case an error happened from ma_device_write2__alsa()... */ + result = ma_device_write__winmm(pDevice, playbackDeviceData, playbackDeviceFramesCount, NULL); if (result != MA_SUCCESS) { exitLoop = MA_TRUE; break; } + + if (playbackDeviceFramesCount < playbackDeviceDataCapInFrames) { + break; + } + } + + if (capturedFramesToProcess < capturedFramesToTryProcessing) { + break; + } + + /* In case an error happened from ma_device_write2__alsa()... */ + if (result != MA_SUCCESS) { + exitLoop = MA_TRUE; + break; } } @@ -13989,7 +13982,6 @@ ma_result ma_device_main_loop__alsa(ma_device* pDevice) ma_uint32 periodSizeInFrames = ma_min(pDevice->capture.internalBufferSizeInFrames/pDevice->capture.internalPeriods, pDevice->playback.internalBufferSizeInFrames/pDevice->playback.internalPeriods); while (totalFramesProcessed < periodSizeInFrames) { - ma_device_callback_proc onData; ma_uint32 framesRemaining = periodSizeInFrames - totalFramesProcessed; ma_uint32 framesProcessed; ma_uint32 framesToProcess = framesRemaining; @@ -14003,54 +13995,51 @@ ma_result ma_device_main_loop__alsa(ma_device* pDevice) break; } - onData = pDevice->onData; - if (onData != NULL) { - pDevice->capture._dspFrameCount = framesToProcess; - pDevice->capture._dspFrames = capturedDeviceData; + pDevice->capture._dspFrameCount = framesToProcess; + pDevice->capture._dspFrames = capturedDeviceData; + for (;;) { + ma_uint8 capturedData[8192]; + ma_uint8 playbackData[8192]; + ma_uint32 capturedDataCapInFrames = sizeof(capturedData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); + ma_uint32 playbackDataCapInFrames = sizeof(playbackData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); + + ma_uint32 capturedFramesToTryProcessing = ma_min(capturedDataCapInFrames, playbackDataCapInFrames); + ma_uint32 capturedFramesToProcess = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, capturedData, capturedFramesToTryProcessing); + if (capturedFramesToProcess == 0) { + break; /* Don't fire the data callback with zero frames. */ + } + + ma_device__on_data(pDevice, playbackData, capturedData, capturedFramesToProcess); + + /* At this point the playbackData buffer should be holding data that needs to be written to the device. */ + pDevice->playback._dspFrameCount = capturedFramesToProcess; + pDevice->playback._dspFrames = playbackData; for (;;) { - ma_uint8 capturedData[8192]; - ma_uint8 playbackData[8192]; - ma_uint32 capturedDataCapInFrames = sizeof(capturedData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); - ma_uint32 playbackDataCapInFrames = sizeof(playbackData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); - - ma_uint32 capturedFramesToTryProcessing = ma_min(capturedDataCapInFrames, playbackDataCapInFrames); - ma_uint32 capturedFramesToProcess = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, capturedData, capturedFramesToTryProcessing); - if (capturedFramesToProcess == 0) { - break; /* Don't fire the data callback with zero frames. */ - } - - onData(pDevice, playbackData, capturedData, capturedFramesToProcess); - - /* At this point the playbackData buffer should be holding data that needs to be written to the device. */ - pDevice->playback._dspFrameCount = capturedFramesToProcess; - pDevice->playback._dspFrames = playbackData; - for (;;) { - ma_uint32 playbackDeviceFramesCount = (ma_uint32)ma_pcm_converter_read(&pDevice->playback.converter, playbackDeviceData, playbackDeviceDataCapInFrames); - if (playbackDeviceFramesCount == 0) { - break; - } - - result = ma_device_write__alsa(pDevice, playbackDeviceData, playbackDeviceFramesCount, NULL); - if (result != MA_SUCCESS) { - exitLoop = MA_TRUE; - break; - } - - if (playbackDeviceFramesCount < playbackDeviceDataCapInFrames) { - break; - } - } - - if (capturedFramesToProcess < capturedFramesToTryProcessing) { + ma_uint32 playbackDeviceFramesCount = (ma_uint32)ma_pcm_converter_read(&pDevice->playback.converter, playbackDeviceData, playbackDeviceDataCapInFrames); + if (playbackDeviceFramesCount == 0) { break; } - /* In case an error happened from ma_device_write2__alsa()... */ + result = ma_device_write__alsa(pDevice, playbackDeviceData, playbackDeviceFramesCount, NULL); if (result != MA_SUCCESS) { exitLoop = MA_TRUE; break; } + + if (playbackDeviceFramesCount < playbackDeviceDataCapInFrames) { + break; + } + } + + if (capturedFramesToProcess < capturedFramesToTryProcessing) { + break; + } + + /* In case an error happened from ma_device_write2__alsa()... */ + if (result != MA_SUCCESS) { + exitLoop = MA_TRUE; + break; } } @@ -16265,7 +16254,6 @@ ma_result ma_device_main_loop__pulse(ma_device* pDevice) ma_uint32 periodSizeInFrames = ma_min(pDevice->capture.internalBufferSizeInFrames/pDevice->capture.internalPeriods, pDevice->playback.internalBufferSizeInFrames/pDevice->playback.internalPeriods); while (totalFramesProcessed < periodSizeInFrames) { - ma_device_callback_proc onData; ma_uint32 framesRemaining = periodSizeInFrames - totalFramesProcessed; ma_uint32 framesProcessed; ma_uint32 framesToProcess = framesRemaining; @@ -16279,54 +16267,51 @@ ma_result ma_device_main_loop__pulse(ma_device* pDevice) break; } - onData = pDevice->onData; - if (onData != NULL) { - pDevice->capture._dspFrameCount = framesToProcess; - pDevice->capture._dspFrames = capturedDeviceData; + pDevice->capture._dspFrameCount = framesToProcess; + pDevice->capture._dspFrames = capturedDeviceData; + for (;;) { + ma_uint8 capturedData[8192]; + ma_uint8 playbackData[8192]; + ma_uint32 capturedDataCapInFrames = sizeof(capturedData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); + ma_uint32 playbackDataCapInFrames = sizeof(playbackData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); + + ma_uint32 capturedFramesToTryProcessing = ma_min(capturedDataCapInFrames, playbackDataCapInFrames); + ma_uint32 capturedFramesToProcess = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, capturedData, capturedFramesToTryProcessing); + if (capturedFramesToProcess == 0) { + break; /* Don't fire the data callback with zero frames. */ + } + + ma_device__on_data(pDevice, playbackData, capturedData, capturedFramesToProcess); + + /* At this point the playbackData buffer should be holding data that needs to be written to the device. */ + pDevice->playback._dspFrameCount = capturedFramesToProcess; + pDevice->playback._dspFrames = playbackData; for (;;) { - ma_uint8 capturedData[8192]; - ma_uint8 playbackData[8192]; - ma_uint32 capturedDataCapInFrames = sizeof(capturedData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); - ma_uint32 playbackDataCapInFrames = sizeof(playbackData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); - - ma_uint32 capturedFramesToTryProcessing = ma_min(capturedDataCapInFrames, playbackDataCapInFrames); - ma_uint32 capturedFramesToProcess = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, capturedData, capturedFramesToTryProcessing); - if (capturedFramesToProcess == 0) { - break; /* Don't fire the data callback with zero frames. */ - } - - onData(pDevice, playbackData, capturedData, capturedFramesToProcess); - - /* At this point the playbackData buffer should be holding data that needs to be written to the device. */ - pDevice->playback._dspFrameCount = capturedFramesToProcess; - pDevice->playback._dspFrames = playbackData; - for (;;) { - ma_uint32 playbackDeviceFramesCount = (ma_uint32)ma_pcm_converter_read(&pDevice->playback.converter, playbackDeviceData, playbackDeviceDataCapInFrames); - if (playbackDeviceFramesCount == 0) { - break; - } - - result = ma_device_write__pulse(pDevice, playbackDeviceData, playbackDeviceFramesCount, NULL); - if (result != MA_SUCCESS) { - exitLoop = MA_TRUE; - break; - } - - if (playbackDeviceFramesCount < playbackDeviceDataCapInFrames) { - break; - } - } - - if (capturedFramesToProcess < capturedFramesToTryProcessing) { + ma_uint32 playbackDeviceFramesCount = (ma_uint32)ma_pcm_converter_read(&pDevice->playback.converter, playbackDeviceData, playbackDeviceDataCapInFrames); + if (playbackDeviceFramesCount == 0) { break; } - /* In case an error happened from ma_device_write2__alsa()... */ + result = ma_device_write__pulse(pDevice, playbackDeviceData, playbackDeviceFramesCount, NULL); if (result != MA_SUCCESS) { exitLoop = MA_TRUE; break; } + + if (playbackDeviceFramesCount < playbackDeviceDataCapInFrames) { + break; + } + } + + if (capturedFramesToProcess < capturedFramesToTryProcessing) { + break; + } + + /* In case an error happened from ma_device_write2__alsa()... */ + if (result != MA_SUCCESS) { + exitLoop = MA_TRUE; + break; } } @@ -20892,7 +20877,6 @@ ma_result ma_device_main_loop__sndio(ma_device* pDevice) ma_uint32 periodSizeInFrames = ma_min(pDevice->capture.internalBufferSizeInFrames/pDevice->capture.internalPeriods, pDevice->playback.internalBufferSizeInFrames/pDevice->playback.internalPeriods); while (totalFramesProcessed < periodSizeInFrames) { - ma_device_callback_proc onData; ma_uint32 framesRemaining = periodSizeInFrames - totalFramesProcessed; ma_uint32 framesProcessed; ma_uint32 framesToProcess = framesRemaining; @@ -20906,54 +20890,51 @@ ma_result ma_device_main_loop__sndio(ma_device* pDevice) break; } - onData = pDevice->onData; - if (onData != NULL) { - pDevice->capture._dspFrameCount = framesToProcess; - pDevice->capture._dspFrames = capturedDeviceData; + pDevice->capture._dspFrameCount = framesToProcess; + pDevice->capture._dspFrames = capturedDeviceData; + for (;;) { + ma_uint8 capturedData[8192]; + ma_uint8 playbackData[8192]; + ma_uint32 capturedDataCapInFrames = sizeof(capturedData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); + ma_uint32 playbackDataCapInFrames = sizeof(playbackData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); + + ma_uint32 capturedFramesToTryProcessing = ma_min(capturedDataCapInFrames, playbackDataCapInFrames); + ma_uint32 capturedFramesToProcess = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, capturedData, capturedFramesToTryProcessing); + if (capturedFramesToProcess == 0) { + break; /* Don't fire the data callback with zero frames. */ + } + + ma_device__on_data(pDevice, playbackData, capturedData, capturedFramesToProcess); + + /* At this point the playbackData buffer should be holding data that needs to be written to the device. */ + pDevice->playback._dspFrameCount = capturedFramesToProcess; + pDevice->playback._dspFrames = playbackData; for (;;) { - ma_uint8 capturedData[8192]; - ma_uint8 playbackData[8192]; - ma_uint32 capturedDataCapInFrames = sizeof(capturedData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); - ma_uint32 playbackDataCapInFrames = sizeof(playbackData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); - - ma_uint32 capturedFramesToTryProcessing = ma_min(capturedDataCapInFrames, playbackDataCapInFrames); - ma_uint32 capturedFramesToProcess = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, capturedData, capturedFramesToTryProcessing); - if (capturedFramesToProcess == 0) { - break; /* Don't fire the data callback with zero frames. */ - } - - onData(pDevice, playbackData, capturedData, capturedFramesToProcess); - - /* At this point the playbackData buffer should be holding data that needs to be written to the device. */ - pDevice->playback._dspFrameCount = capturedFramesToProcess; - pDevice->playback._dspFrames = playbackData; - for (;;) { - ma_uint32 playbackDeviceFramesCount = (ma_uint32)ma_pcm_converter_read(&pDevice->playback.converter, playbackDeviceData, playbackDeviceDataCapInFrames); - if (playbackDeviceFramesCount == 0) { - break; - } - - result = ma_device_write__sndio(pDevice, playbackDeviceData, playbackDeviceFramesCount, NULL); - if (result != MA_SUCCESS) { - exitLoop = MA_TRUE; - break; - } - - if (playbackDeviceFramesCount < playbackDeviceDataCapInFrames) { - break; - } - } - - if (capturedFramesToProcess < capturedFramesToTryProcessing) { + ma_uint32 playbackDeviceFramesCount = (ma_uint32)ma_pcm_converter_read(&pDevice->playback.converter, playbackDeviceData, playbackDeviceDataCapInFrames); + if (playbackDeviceFramesCount == 0) { break; } - /* In case an error happened from ma_device_write2__alsa()... */ + result = ma_device_write__sndio(pDevice, playbackDeviceData, playbackDeviceFramesCount, NULL); if (result != MA_SUCCESS) { exitLoop = MA_TRUE; break; } + + if (playbackDeviceFramesCount < playbackDeviceDataCapInFrames) { + break; + } + } + + if (capturedFramesToProcess < capturedFramesToTryProcessing) { + break; + } + + /* In case an error happened from ma_device_write2__alsa()... */ + if (result != MA_SUCCESS) { + exitLoop = MA_TRUE; + break; } } @@ -21847,7 +21828,6 @@ ma_result ma_device_main_loop__audio4(ma_device* pDevice) ma_uint32 periodSizeInFrames = ma_min(pDevice->capture.internalBufferSizeInFrames/pDevice->capture.internalPeriods, pDevice->playback.internalBufferSizeInFrames/pDevice->playback.internalPeriods); while (totalFramesProcessed < periodSizeInFrames) { - ma_device_callback_proc onData; ma_uint32 framesRemaining = periodSizeInFrames - totalFramesProcessed; ma_uint32 framesProcessed; ma_uint32 framesToProcess = framesRemaining; @@ -21861,54 +21841,51 @@ ma_result ma_device_main_loop__audio4(ma_device* pDevice) break; } - onData = pDevice->onData; - if (onData != NULL) { - pDevice->capture._dspFrameCount = framesToProcess; - pDevice->capture._dspFrames = capturedDeviceData; + pDevice->capture._dspFrameCount = framesToProcess; + pDevice->capture._dspFrames = capturedDeviceData; + for (;;) { + ma_uint8 capturedData[8192]; + ma_uint8 playbackData[8192]; + ma_uint32 capturedDataCapInFrames = sizeof(capturedData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); + ma_uint32 playbackDataCapInFrames = sizeof(playbackData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); + + ma_uint32 capturedFramesToTryProcessing = ma_min(capturedDataCapInFrames, playbackDataCapInFrames); + ma_uint32 capturedFramesToProcess = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, capturedData, capturedFramesToTryProcessing); + if (capturedFramesToProcess == 0) { + break; /* Don't fire the data callback with zero frames. */ + } + + ma_device__on_data(pDevice, playbackData, capturedData, capturedFramesToProcess); + + /* At this point the playbackData buffer should be holding data that needs to be written to the device. */ + pDevice->playback._dspFrameCount = capturedFramesToProcess; + pDevice->playback._dspFrames = playbackData; for (;;) { - ma_uint8 capturedData[8192]; - ma_uint8 playbackData[8192]; - ma_uint32 capturedDataCapInFrames = sizeof(capturedData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); - ma_uint32 playbackDataCapInFrames = sizeof(playbackData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); - - ma_uint32 capturedFramesToTryProcessing = ma_min(capturedDataCapInFrames, playbackDataCapInFrames); - ma_uint32 capturedFramesToProcess = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, capturedData, capturedFramesToTryProcessing); - if (capturedFramesToProcess == 0) { - break; /* Don't fire the data callback with zero frames. */ - } - - onData(pDevice, playbackData, capturedData, capturedFramesToProcess); - - /* At this point the playbackData buffer should be holding data that needs to be written to the device. */ - pDevice->playback._dspFrameCount = capturedFramesToProcess; - pDevice->playback._dspFrames = playbackData; - for (;;) { - ma_uint32 playbackDeviceFramesCount = (ma_uint32)ma_pcm_converter_read(&pDevice->playback.converter, playbackDeviceData, playbackDeviceDataCapInFrames); - if (playbackDeviceFramesCount == 0) { - break; - } - - result = ma_device_write__audio4(pDevice, playbackDeviceData, playbackDeviceFramesCount, NULL); - if (result != MA_SUCCESS) { - exitLoop = MA_TRUE; - break; - } - - if (playbackDeviceFramesCount < playbackDeviceDataCapInFrames) { - break; - } - } - - if (capturedFramesToProcess < capturedFramesToTryProcessing) { + ma_uint32 playbackDeviceFramesCount = (ma_uint32)ma_pcm_converter_read(&pDevice->playback.converter, playbackDeviceData, playbackDeviceDataCapInFrames); + if (playbackDeviceFramesCount == 0) { break; } - /* In case an error happened from ma_device_write2__alsa()... */ + result = ma_device_write__audio4(pDevice, playbackDeviceData, playbackDeviceFramesCount, NULL); if (result != MA_SUCCESS) { exitLoop = MA_TRUE; break; } + + if (playbackDeviceFramesCount < playbackDeviceDataCapInFrames) { + break; + } + } + + if (capturedFramesToProcess < capturedFramesToTryProcessing) { + break; + } + + /* In case an error happened from ma_device_write2__alsa()... */ + if (result != MA_SUCCESS) { + exitLoop = MA_TRUE; + break; } } @@ -22559,7 +22536,6 @@ ma_result ma_device_main_loop__oss(ma_device* pDevice) ma_uint32 periodSizeInFrames = ma_min(pDevice->capture.internalBufferSizeInFrames/pDevice->capture.internalPeriods, pDevice->playback.internalBufferSizeInFrames/pDevice->playback.internalPeriods); while (totalFramesProcessed < periodSizeInFrames) { - ma_device_callback_proc onData; ma_uint32 framesRemaining = periodSizeInFrames - totalFramesProcessed; ma_uint32 framesProcessed; ma_uint32 framesToProcess = framesRemaining; @@ -22573,54 +22549,51 @@ ma_result ma_device_main_loop__oss(ma_device* pDevice) break; } - onData = pDevice->onData; - if (onData != NULL) { - pDevice->capture._dspFrameCount = framesToProcess; - pDevice->capture._dspFrames = capturedDeviceData; + pDevice->capture._dspFrameCount = framesToProcess; + pDevice->capture._dspFrames = capturedDeviceData; + for (;;) { + ma_uint8 capturedData[8192]; + ma_uint8 playbackData[8192]; + ma_uint32 capturedDataCapInFrames = sizeof(capturedData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); + ma_uint32 playbackDataCapInFrames = sizeof(playbackData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); + + ma_uint32 capturedFramesToTryProcessing = ma_min(capturedDataCapInFrames, playbackDataCapInFrames); + ma_uint32 capturedFramesToProcess = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, capturedData, capturedFramesToTryProcessing); + if (capturedFramesToProcess == 0) { + break; /* Don't fire the data callback with zero frames. */ + } + + ma_device__on_data(pDevice, playbackData, capturedData, capturedFramesToProcess); + + /* At this point the playbackData buffer should be holding data that needs to be written to the device. */ + pDevice->playback._dspFrameCount = capturedFramesToProcess; + pDevice->playback._dspFrames = playbackData; for (;;) { - ma_uint8 capturedData[8192]; - ma_uint8 playbackData[8192]; - ma_uint32 capturedDataCapInFrames = sizeof(capturedData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); - ma_uint32 playbackDataCapInFrames = sizeof(playbackData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); - - ma_uint32 capturedFramesToTryProcessing = ma_min(capturedDataCapInFrames, playbackDataCapInFrames); - ma_uint32 capturedFramesToProcess = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, capturedData, capturedFramesToTryProcessing); - if (capturedFramesToProcess == 0) { - break; /* Don't fire the data callback with zero frames. */ - } - - onData(pDevice, playbackData, capturedData, capturedFramesToProcess); - - /* At this point the playbackData buffer should be holding data that needs to be written to the device. */ - pDevice->playback._dspFrameCount = capturedFramesToProcess; - pDevice->playback._dspFrames = playbackData; - for (;;) { - ma_uint32 playbackDeviceFramesCount = (ma_uint32)ma_pcm_converter_read(&pDevice->playback.converter, playbackDeviceData, playbackDeviceDataCapInFrames); - if (playbackDeviceFramesCount == 0) { - break; - } - - result = ma_device_write__oss(pDevice, playbackDeviceData, playbackDeviceFramesCount, NULL); - if (result != MA_SUCCESS) { - exitLoop = MA_TRUE; - break; - } - - if (playbackDeviceFramesCount < playbackDeviceDataCapInFrames) { - break; - } - } - - if (capturedFramesToProcess < capturedFramesToTryProcessing) { + ma_uint32 playbackDeviceFramesCount = (ma_uint32)ma_pcm_converter_read(&pDevice->playback.converter, playbackDeviceData, playbackDeviceDataCapInFrames); + if (playbackDeviceFramesCount == 0) { break; } - /* In case an error happened from ma_device_write2__alsa()... */ + result = ma_device_write__oss(pDevice, playbackDeviceData, playbackDeviceFramesCount, NULL); if (result != MA_SUCCESS) { exitLoop = MA_TRUE; break; } + + if (playbackDeviceFramesCount < playbackDeviceDataCapInFrames) { + break; + } + } + + if (capturedFramesToProcess < capturedFramesToTryProcessing) { + break; + } + + /* In case an error happened from ma_device_write2__alsa()... */ + if (result != MA_SUCCESS) { + exitLoop = MA_TRUE; + break; } } @@ -25720,6 +25693,8 @@ ma_result ma_device_init(ma_context* pContext, const ma_device_config* pConfig, } } + pDevice->noPreZeroedOutputBuffer = config.noPreZeroedOutputBuffer; + /* When passing in 0 for the format/channels/rate/chmap it means the device will be using whatever is chosen by the backend. If everything is set to defaults it means the format conversion pipeline will run on a fast path where data transfer is just passed straight through to the backend. @@ -34898,7 +34873,10 @@ v0.9.8 - 2019-xx-xx - WASAPI: Fix a potential deadlock when starting a full-duplex device. - WASAPI: Enable automatic resampling by default. Disable with config.wasapi.noAutoConvertSRC. - Core Audio: Fix bugs with automatic stream routing. - - Fix some uncommon warnings emitted by GCC when `__inline__` is undefined or defined as nothing. + - Add support for controlling whether or not the content of the output buffer passed in to the data callback is pre-initialized + to zero. By default it will be initialized to zero, but this can be changed by setting noPreZeroedOutputBuffer in the device + config. Setting noPreZeroedOutputBuffer to true will leave the contents undefined. + - Fix warnings emitted by GCC when `__inline__` is undefined or defined as nothing. v0.9.7 - 2019-08-28 - Add support for loopback mode (WASAPI only).