mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 08:14:04 +02:00
Refactoring work on the null backend.
This commit is contained in:
+186
-13
@@ -5899,12 +5899,16 @@ ma_result ma_device_stop__null(ma_device* pDevice)
|
|||||||
return MA_SUCCESS;
|
return MA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount)
|
ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
|
||||||
{
|
{
|
||||||
ma_result result = MA_SUCCESS;
|
ma_result result = MA_SUCCESS;
|
||||||
ma_uint32 totalPCMFramesProcessed;
|
ma_uint32 totalPCMFramesProcessed;
|
||||||
ma_bool32 wasStartedOnEntry;
|
ma_bool32 wasStartedOnEntry;
|
||||||
|
|
||||||
|
if (pFramesWritten != NULL) {
|
||||||
|
*pFramesWritten = 0;
|
||||||
|
}
|
||||||
|
|
||||||
wasStartedOnEntry = pDevice->null_device.isStarted;
|
wasStartedOnEntry = pDevice->null_device.isStarted;
|
||||||
|
|
||||||
/* Keep going until everything has been read. */
|
/* Keep going until everything has been read. */
|
||||||
@@ -5968,20 +5972,20 @@ ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrames, ma_u
|
|||||||
pDevice->null_device.currentPeriodFramesRemainingPlayback = pDevice->playback.internalBufferSizeInFrames / pDevice->playback.internalPeriods;
|
pDevice->null_device.currentPeriodFramesRemainingPlayback = pDevice->playback.internalBufferSizeInFrames / pDevice->playback.internalPeriods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pFramesWritten != NULL) {
|
||||||
|
*pFramesWritten = totalPCMFramesProcessed;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ma_result ma_device_read__null(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount)
|
ma_result ma_device_read__null(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
|
||||||
{
|
{
|
||||||
ma_result result = MA_SUCCESS;
|
ma_result result = MA_SUCCESS;
|
||||||
ma_uint32 totalPCMFramesProcessed;
|
ma_uint32 totalPCMFramesProcessed;
|
||||||
|
|
||||||
/* The device needs to be started immediately. */
|
if (pFramesRead != NULL) {
|
||||||
if (!pDevice->null_device.isStarted) {
|
*pFramesRead = 0;
|
||||||
result = ma_device_start__null(pDevice);
|
|
||||||
if (result != MA_SUCCESS) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep going until everything has been read. */
|
/* Keep going until everything has been read. */
|
||||||
@@ -6039,6 +6043,176 @@ ma_result ma_device_read__null(ma_device* pDevice, void* pPCMFrames, ma_uint32 f
|
|||||||
pDevice->null_device.currentPeriodFramesRemainingCapture = pDevice->capture.internalBufferSizeInFrames / pDevice->capture.internalPeriods;
|
pDevice->null_device.currentPeriodFramesRemainingCapture = pDevice->capture.internalBufferSizeInFrames / pDevice->capture.internalPeriods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pFramesRead != NULL) {
|
||||||
|
*pFramesRead = totalPCMFramesProcessed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ma_result ma_device_main_loop__null(ma_device* pDevice)
|
||||||
|
{
|
||||||
|
ma_result result = MA_SUCCESS;
|
||||||
|
ma_bool32 exitLoop = MA_FALSE;
|
||||||
|
|
||||||
|
ma_assert(pDevice != NULL);
|
||||||
|
|
||||||
|
/* The capture device needs to be started immediately. */
|
||||||
|
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
|
||||||
|
result = ma_device_start__null(pDevice);
|
||||||
|
if (result != MA_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ma_device__get_state(pDevice) == MA_STATE_STARTED && !exitLoop) {
|
||||||
|
switch (pDevice->type)
|
||||||
|
{
|
||||||
|
case ma_device_type_duplex:
|
||||||
|
{
|
||||||
|
/* The process is: device_read -> convert -> callback -> convert -> device_write */
|
||||||
|
ma_uint8 capturedDeviceData[8192];
|
||||||
|
ma_uint8 playbackDeviceData[8192];
|
||||||
|
ma_uint32 capturedDeviceDataCapInFrames = sizeof(capturedDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
|
||||||
|
ma_uint32 playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
|
||||||
|
|
||||||
|
ma_uint32 totalFramesProcessed = 0;
|
||||||
|
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;
|
||||||
|
if (framesToProcess > capturedDeviceDataCapInFrames) {
|
||||||
|
framesToProcess = capturedDeviceDataCapInFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = ma_device_read__null(pDevice, capturedDeviceData, framesToProcess, &framesProcessed);
|
||||||
|
if (result != MA_SUCCESS) {
|
||||||
|
exitLoop = MA_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
onData = pDevice->onData;
|
||||||
|
if (onData != NULL) {
|
||||||
|
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. */
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In case an error happened from ma_device_write2__alsa()... */
|
||||||
|
if (result != MA_SUCCESS) {
|
||||||
|
exitLoop = MA_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
totalFramesProcessed += framesProcessed;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case ma_device_type_capture:
|
||||||
|
{
|
||||||
|
/* We read in chunks of the period size, but use a stack allocated buffer for the intermediary. */
|
||||||
|
ma_uint8 intermediaryBuffer[8192];
|
||||||
|
ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
|
||||||
|
ma_uint32 periodSizeInFrames = pDevice->capture.internalBufferSizeInFrames / pDevice->capture.internalPeriods;
|
||||||
|
ma_uint32 framesReadThisPeriod = 0;
|
||||||
|
while (framesReadThisPeriod < periodSizeInFrames) {
|
||||||
|
ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesReadThisPeriod;
|
||||||
|
ma_uint32 framesProcessed;
|
||||||
|
ma_uint32 framesToReadThisIteration = framesRemainingInPeriod;
|
||||||
|
if (framesToReadThisIteration > intermediaryBufferSizeInFrames) {
|
||||||
|
framesToReadThisIteration = intermediaryBufferSizeInFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = ma_device_read__null(pDevice, intermediaryBuffer, framesToReadThisIteration, &framesProcessed);
|
||||||
|
if (result != MA_SUCCESS) {
|
||||||
|
exitLoop = MA_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ma_device__send_frames_to_client(pDevice, framesProcessed, intermediaryBuffer);
|
||||||
|
|
||||||
|
framesReadThisPeriod += framesProcessed;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case ma_device_type_playback:
|
||||||
|
{
|
||||||
|
/* We write in chunks of the period size, but use a stack allocated buffer for the intermediary. */
|
||||||
|
ma_uint8 intermediaryBuffer[8192];
|
||||||
|
ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
|
||||||
|
ma_uint32 periodSizeInFrames = pDevice->playback.internalBufferSizeInFrames / pDevice->playback.internalPeriods;
|
||||||
|
ma_uint32 framesWrittenThisPeriod = 0;
|
||||||
|
while (framesWrittenThisPeriod < periodSizeInFrames) {
|
||||||
|
ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesWrittenThisPeriod;
|
||||||
|
ma_uint32 framesProcessed;
|
||||||
|
ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod;
|
||||||
|
if (framesToWriteThisIteration > intermediaryBufferSizeInFrames) {
|
||||||
|
framesToWriteThisIteration = intermediaryBufferSizeInFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, intermediaryBuffer);
|
||||||
|
|
||||||
|
result = ma_device_write__null(pDevice, intermediaryBuffer, framesToWriteThisIteration, &framesProcessed);
|
||||||
|
if (result != MA_SUCCESS) {
|
||||||
|
exitLoop = MA_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
framesWrittenThisPeriod += framesProcessed;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
/* To silence a warning. Will never hit this. */
|
||||||
|
case ma_device_type_loopback:
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Here is where the device is started. */
|
||||||
|
ma_device_stop__null(pDevice);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6063,10 +6237,9 @@ ma_result ma_context_init__null(const ma_context_config* pConfig, ma_context* pC
|
|||||||
pContext->onGetDeviceInfo = ma_context_get_device_info__null;
|
pContext->onGetDeviceInfo = ma_context_get_device_info__null;
|
||||||
pContext->onDeviceInit = ma_device_init__null;
|
pContext->onDeviceInit = ma_device_init__null;
|
||||||
pContext->onDeviceUninit = ma_device_uninit__null;
|
pContext->onDeviceUninit = ma_device_uninit__null;
|
||||||
pContext->onDeviceStart = ma_device_start__null;
|
pContext->onDeviceStart = NULL; /* Not required for synchronous backends. */
|
||||||
pContext->onDeviceStop = ma_device_stop__null;
|
pContext->onDeviceStop = NULL; /* Not required for synchronous backends. */
|
||||||
pContext->onDeviceWrite = ma_device_write__null;
|
pContext->onDeviceMainLoop = ma_device_main_loop__null;
|
||||||
pContext->onDeviceRead = ma_device_read__null;
|
|
||||||
|
|
||||||
/* The null backend always works. */
|
/* The null backend always works. */
|
||||||
return MA_SUCCESS;
|
return MA_SUCCESS;
|
||||||
@@ -34438,7 +34611,7 @@ v0.9.7 - 2019-xx-xx
|
|||||||
- Fix a crash when an error is posted in ma_device_init().
|
- Fix a crash when an error is posted in ma_device_init().
|
||||||
- Fix a compilation error when compiling for ARM architectures.
|
- Fix a compilation error when compiling for ARM architectures.
|
||||||
- Fix a bug with the audio(4) backend where the device is incorrectly being opened in non-blocking mode.
|
- Fix a bug with the audio(4) backend where the device is incorrectly being opened in non-blocking mode.
|
||||||
- Minor refactoring to the WinMM, ALSA, PulseAudio, OSS, audio(4) and sndio backends.
|
- Minor refactoring to the WinMM, ALSA, PulseAudio, OSS, audio(4), sndio and null backends.
|
||||||
|
|
||||||
v0.9.6 - 2019-08-04
|
v0.9.6 - 2019-08-04
|
||||||
- Add support for loading decoders using a wchar_t string for file paths.
|
- Add support for loading decoders using a wchar_t string for file paths.
|
||||||
|
|||||||
Reference in New Issue
Block a user