Commit 700dba14 authored by David Reid's avatar David Reid

Version 0.11.3

parent beb4f31b
/* /*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.11.2 - 2021-12-31 miniaudio - v0.11.3 - 2022-01-07
David Reid - mackron@gmail.com David Reid - mackron@gmail.com
...@@ -859,11 +859,21 @@ static MA_INLINE double ma_sqrtd(double x) ...@@ -859,11 +859,21 @@ static MA_INLINE double ma_sqrtd(double x)
} }
static MA_INLINE float ma_sinf(float x)
{
return (float)ma_sind((float)x);
}
static MA_INLINE double ma_cosd(double x) static MA_INLINE double ma_cosd(double x)
{ {
return ma_sind((MA_PI_D*0.5) - x); return ma_sind((MA_PI_D*0.5) - x);
} }
static MA_INLINE float ma_cosf(float x)
{
return (float)ma_cosd((float)x);
}
static MA_INLINE double ma_log10d(double x) static MA_INLINE double ma_log10d(double x)
{ {
return ma_logd(x) * 0.43429448190325182765; return ma_logd(x) * 0.43429448190325182765;
...@@ -2093,15 +2103,6 @@ MA_API ma_result ma_log_post(ma_log* pLog, ma_uint32 level, const char* pMessage ...@@ -2093,15 +2103,6 @@ MA_API ma_result ma_log_post(ma_log* pLog, ma_uint32 level, const char* pMessage
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
/* If it's a debug log, ignore it unless MA_DEBUG_OUTPUT is enabled. */
#if !defined(MA_DEBUG_OUTPUT)
{
if (level == MA_LOG_LEVEL_DEBUG) {
return MA_INVALID_ARGS; /* Don't post debug messages if debug output is disabled. */
}
}
#endif
ma_log_lock(pLog); ma_log_lock(pLog);
{ {
ma_uint32 iLog; ma_uint32 iLog;
...@@ -2168,18 +2169,6 @@ MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat ...@@ -2168,18 +2169,6 @@ MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
/*
If it's a debug log, ignore it unless MA_DEBUG_OUTPUT is enabled. Do this before generating the
formatted message string so that we don't waste time only to have ma_log_post() reject it.
*/
#if !defined(MA_DEBUG_OUTPUT)
{
if (level == MA_LOG_LEVEL_DEBUG) {
return MA_INVALID_ARGS; /* Don't post debug messages if debug output is disabled. */
}
}
#endif
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || ((!defined(_MSC_VER) || _MSC_VER >= 1900) && !defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS)) #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || ((!defined(_MSC_VER) || _MSC_VER >= 1900) && !defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
{ {
ma_result result; ma_result result;
...@@ -2289,18 +2278,6 @@ MA_API ma_result ma_log_postf(ma_log* pLog, ma_uint32 level, const char* pFormat ...@@ -2289,18 +2278,6 @@ MA_API ma_result ma_log_postf(ma_log* pLog, ma_uint32 level, const char* pFormat
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
/*
If it's a debug log, ignore it unless MA_DEBUG_OUTPUT is enabled. Do this before generating the
formatted message string so that we don't waste time only to have ma_log_post() reject it.
*/
#if !defined(MA_DEBUG_OUTPUT)
{
if (level == MA_LOG_LEVEL_DEBUG) {
return MA_INVALID_ARGS; /* Don't post debug messages if debug output is disabled. */
}
}
#endif
va_start(args, pFormat); va_start(args, pFormat);
{ {
result = ma_log_postv(pLog, level, pFormat, args); result = ma_log_postv(pLog, level, pFormat, args);
...@@ -6014,7 +5991,109 @@ void ma_device__on_notification_interruption_ended(ma_device* pDevice) ...@@ -6014,7 +5991,109 @@ void ma_device__on_notification_interruption_ended(ma_device* pDevice)
} }
static void ma_device__on_data_inner(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount)
{
MA_ASSERT(pDevice != NULL);
MA_ASSERT(pDevice->onData != NULL);
if (!pDevice->noPreSilencedOutputBuffer && pFramesOut != NULL) {
ma_silence_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels);
}
pDevice->onData(pDevice, pFramesOut, pFramesIn, frameCount);
}
static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount)
{
MA_ASSERT(pDevice != NULL);
if (pDevice->noFixedSizedCallback) {
/* Fast path. Not using a fixed sized callback. Process directly from the specified buffers. */
ma_device__on_data_inner(pDevice, pFramesOut, pFramesIn, frameCount);
} else {
/* Slow path. Using a fixed sized callback. Need to use the intermediary buffer. */
ma_uint32 totalFramesProcessed = 0;
while (totalFramesProcessed < frameCount) {
ma_uint32 totalFramesRemaining = frameCount - totalFramesProcessed;
ma_uint32 framesToProcessThisIteration = 0;
if (pFramesIn != NULL) {
/* Capturing. Write to the intermediary buffer. If there's no room, fire the callback to empty it. */
if (pDevice->capture.intermediaryBufferLen < pDevice->capture.intermediaryBufferCap) {
/* There's some room left in the intermediary buffer. Write to it without firing the callback. */
framesToProcessThisIteration = totalFramesRemaining;
if (framesToProcessThisIteration > pDevice->capture.intermediaryBufferCap - pDevice->capture.intermediaryBufferLen) {
framesToProcessThisIteration = pDevice->capture.intermediaryBufferCap - pDevice->capture.intermediaryBufferLen;
}
ma_copy_pcm_frames(
ma_offset_pcm_frames_ptr(pDevice->capture.pIntermediaryBuffer, pDevice->capture.intermediaryBufferLen, pDevice->capture.format, pDevice->capture.channels),
ma_offset_pcm_frames_const_ptr(pFramesIn, totalFramesProcessed, pDevice->capture.format, pDevice->capture.channels),
framesToProcessThisIteration,
pDevice->capture.format, pDevice->capture.channels);
pDevice->capture.intermediaryBufferLen += framesToProcessThisIteration;
}
if (pDevice->capture.intermediaryBufferLen == pDevice->capture.intermediaryBufferCap) {
/* No room left in the intermediary buffer. Fire the data callback. */
if (pDevice->type == ma_device_type_duplex) {
ma_device__on_data_inner(pDevice, pDevice->playback.pIntermediaryBuffer, pDevice->capture.pIntermediaryBuffer, pDevice->capture.intermediaryBufferCap);
/* The playback buffer will have just been filled. */
pDevice->playback.intermediaryBufferLen = pDevice->capture.intermediaryBufferCap;
} else {
ma_device__on_data_inner(pDevice, NULL, pDevice->capture.pIntermediaryBuffer, pDevice->capture.intermediaryBufferCap);
}
/* The intermediary buffer has just been drained. */
pDevice->capture.intermediaryBufferLen = 0;
}
}
if (pFramesOut != NULL) {
/* Playing back. Read from the intermediary buffer. If there's nothing in it, fire the callback to fill it. */
if (pDevice->playback.intermediaryBufferLen > 0) {
/* There's some content in the intermediary buffer. Read from that without firing the callback. */
if (pDevice->type == ma_device_type_duplex) {
/* The frames processed this iteration for a duplex device will always be based on the capture side. Leave it unmodified. */
} else {
framesToProcessThisIteration = totalFramesRemaining;
if (framesToProcessThisIteration > pDevice->playback.intermediaryBufferLen) {
framesToProcessThisIteration = pDevice->playback.intermediaryBufferLen;
}
}
ma_copy_pcm_frames(
ma_offset_pcm_frames_ptr(pFramesOut, totalFramesProcessed, pDevice->playback.format, pDevice->playback.channels),
ma_offset_pcm_frames_ptr(pDevice->playback.pIntermediaryBuffer, pDevice->playback.intermediaryBufferCap - pDevice->playback.intermediaryBufferLen, pDevice->playback.format, pDevice->playback.channels),
framesToProcessThisIteration,
pDevice->playback.format, pDevice->playback.channels);
pDevice->playback.intermediaryBufferLen -= framesToProcessThisIteration;
}
if (pDevice->playback.intermediaryBufferLen == 0) {
/* There's nothing in the intermediary buffer. Fire the data callback to fill it. */
if (pDevice->type == ma_device_type_duplex) {
/* In duplex mode, the data callback will be fired from the capture side. Nothing to do here. */
} else {
ma_device__on_data_inner(pDevice, pDevice->playback.pIntermediaryBuffer, NULL, pDevice->playback.intermediaryBufferCap);
/* The intermediary buffer has just been filled. */
pDevice->playback.intermediaryBufferLen = pDevice->playback.intermediaryBufferCap;
}
}
}
/* Make sure this is only incremented once in the duplex case. */
totalFramesProcessed += framesToProcessThisIteration;
}
}
}
static void ma_device__handle_data_callback(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount)
{ {
float masterVolumeFactor; float masterVolumeFactor;
...@@ -6023,10 +6102,6 @@ static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void* ...@@ -6023,10 +6102,6 @@ static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void*
if (pDevice->onData) { if (pDevice->onData) {
unsigned int prevDenormalState = ma_device_disable_denormals(pDevice); unsigned int prevDenormalState = ma_device_disable_denormals(pDevice);
{ {
if (!pDevice->noPreSilencedOutputBuffer && pFramesOut != NULL) {
ma_silence_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels);
}
/* Volume control of input makes things a bit awkward because the input buffer is read-only. We'll need to use a temp buffer and loop in this case. */ /* Volume control of input makes things a bit awkward because the input buffer is read-only. We'll need to use a temp buffer and loop in this case. */
if (pFramesIn != NULL && masterVolumeFactor < 1) { if (pFramesIn != NULL && masterVolumeFactor < 1) {
ma_uint8 tempFramesIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; ma_uint8 tempFramesIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
...@@ -6041,12 +6116,12 @@ static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void* ...@@ -6041,12 +6116,12 @@ static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void*
ma_copy_and_apply_volume_factor_pcm_frames(tempFramesIn, ma_offset_ptr(pFramesIn, totalFramesProcessed*bpfCapture), framesToProcessThisIteration, pDevice->capture.format, pDevice->capture.channels, masterVolumeFactor); ma_copy_and_apply_volume_factor_pcm_frames(tempFramesIn, ma_offset_ptr(pFramesIn, totalFramesProcessed*bpfCapture), framesToProcessThisIteration, pDevice->capture.format, pDevice->capture.channels, masterVolumeFactor);
pDevice->onData(pDevice, ma_offset_ptr(pFramesOut, totalFramesProcessed*bpfPlayback), tempFramesIn, framesToProcessThisIteration); ma_device__on_data(pDevice, ma_offset_ptr(pFramesOut, totalFramesProcessed*bpfPlayback), tempFramesIn, framesToProcessThisIteration);
totalFramesProcessed += framesToProcessThisIteration; totalFramesProcessed += framesToProcessThisIteration;
} }
} else { } else {
pDevice->onData(pDevice, pFramesOut, pFramesIn, frameCount); ma_device__on_data(pDevice, pFramesOut, pFramesIn, frameCount);
} }
/* Volume control and clipping for playback devices. */ /* Volume control and clipping for playback devices. */
...@@ -6076,7 +6151,7 @@ static void ma_device__read_frames_from_client(ma_device* pDevice, ma_uint32 fra ...@@ -6076,7 +6151,7 @@ static void ma_device__read_frames_from_client(ma_device* pDevice, ma_uint32 fra
MA_ASSERT(pFramesOut != NULL); MA_ASSERT(pFramesOut != NULL);
if (pDevice->playback.converter.isPassthrough) { if (pDevice->playback.converter.isPassthrough) {
ma_device__on_data(pDevice, pFramesOut, NULL, frameCount); ma_device__handle_data_callback(pDevice, pFramesOut, NULL, frameCount);
} else { } else {
ma_result result; ma_result result;
ma_uint64 totalFramesReadOut; ma_uint64 totalFramesReadOut;
...@@ -6121,7 +6196,7 @@ static void ma_device__read_frames_from_client(ma_device* pDevice, ma_uint32 fra ...@@ -6121,7 +6196,7 @@ static void ma_device__read_frames_from_client(ma_device* pDevice, ma_uint32 fra
/* Getting here means there's no data in the cache and we need to fill it up with data from the client. */ /* Getting here means there's no data in the cache and we need to fill it up with data from the client. */
if (pDevice->playback.inputCacheRemaining == 0) { if (pDevice->playback.inputCacheRemaining == 0) {
ma_device__on_data(pDevice, pDevice->playback.pInputCache, NULL, (ma_uint32)pDevice->playback.inputCacheCap); ma_device__handle_data_callback(pDevice, pDevice->playback.pInputCache, NULL, (ma_uint32)pDevice->playback.inputCacheCap);
pDevice->playback.inputCacheConsumed = 0; pDevice->playback.inputCacheConsumed = 0;
pDevice->playback.inputCacheRemaining = pDevice->playback.inputCacheCap; pDevice->playback.inputCacheRemaining = pDevice->playback.inputCacheCap;
...@@ -6149,7 +6224,7 @@ static void ma_device__read_frames_from_client(ma_device* pDevice, ma_uint32 fra ...@@ -6149,7 +6224,7 @@ static void ma_device__read_frames_from_client(ma_device* pDevice, ma_uint32 fra
} }
if (framesToReadThisIterationIn > 0) { if (framesToReadThisIterationIn > 0) {
ma_device__on_data(pDevice, pIntermediaryBuffer, NULL, (ma_uint32)framesToReadThisIterationIn); ma_device__handle_data_callback(pDevice, pIntermediaryBuffer, NULL, (ma_uint32)framesToReadThisIterationIn);
} }
/* /*
...@@ -6182,7 +6257,7 @@ static void ma_device__send_frames_to_client(ma_device* pDevice, ma_uint32 frame ...@@ -6182,7 +6257,7 @@ static void ma_device__send_frames_to_client(ma_device* pDevice, ma_uint32 frame
MA_ASSERT(pFramesInDeviceFormat != NULL); MA_ASSERT(pFramesInDeviceFormat != NULL);
if (pDevice->capture.converter.isPassthrough) { if (pDevice->capture.converter.isPassthrough) {
ma_device__on_data(pDevice, NULL, pFramesInDeviceFormat, frameCountInDeviceFormat); ma_device__handle_data_callback(pDevice, NULL, pFramesInDeviceFormat, frameCountInDeviceFormat);
} else { } else {
ma_result result; ma_result result;
ma_uint8 pFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; ma_uint8 pFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
...@@ -6205,7 +6280,7 @@ static void ma_device__send_frames_to_client(ma_device* pDevice, ma_uint32 frame ...@@ -6205,7 +6280,7 @@ static void ma_device__send_frames_to_client(ma_device* pDevice, ma_uint32 frame
} }
if (clientFramesProcessedThisIteration > 0) { if (clientFramesProcessedThisIteration > 0) {
ma_device__on_data(pDevice, NULL, pFramesInClientFormat, (ma_uint32)clientFramesProcessedThisIteration); /* Safe cast. */ ma_device__handle_data_callback(pDevice, NULL, pFramesInClientFormat, (ma_uint32)clientFramesProcessedThisIteration); /* Safe cast. */
} }
pRunningFramesInDeviceFormat = ma_offset_ptr(pRunningFramesInDeviceFormat, deviceFramesProcessedThisIteration * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels)); pRunningFramesInDeviceFormat = ma_offset_ptr(pRunningFramesInDeviceFormat, deviceFramesProcessedThisIteration * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
...@@ -6320,7 +6395,7 @@ static ma_result ma_device__handle_duplex_callback_playback(ma_device* pDevice, ...@@ -6320,7 +6395,7 @@ static ma_result ma_device__handle_duplex_callback_playback(ma_device* pDevice,
result = ma_pcm_rb_acquire_read(pRB, &inputFrameCount, &pInputFrames); result = ma_pcm_rb_acquire_read(pRB, &inputFrameCount, &pInputFrames);
if (result == MA_SUCCESS) { if (result == MA_SUCCESS) {
if (inputFrameCount > 0) { if (inputFrameCount > 0) {
ma_device__on_data(pDevice, pDevice->playback.pInputCache, pInputFrames, inputFrameCount); ma_device__handle_data_callback(pDevice, pDevice->playback.pInputCache, pInputFrames, inputFrameCount);
} else { } else {
if (ma_pcm_rb_pointer_distance(pRB) == 0) { if (ma_pcm_rb_pointer_distance(pRB) == 0) {
break; /* Underrun. */ break; /* Underrun. */
...@@ -6329,7 +6404,7 @@ static ma_result ma_device__handle_duplex_callback_playback(ma_device* pDevice, ...@@ -6329,7 +6404,7 @@ static ma_result ma_device__handle_duplex_callback_playback(ma_device* pDevice,
} else { } else {
/* No capture data available. Feed in silence. */ /* No capture data available. Feed in silence. */
inputFrameCount = (ma_uint32)ma_min(pDevice->playback.inputCacheCap, sizeof(silentInputFrames) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels)); inputFrameCount = (ma_uint32)ma_min(pDevice->playback.inputCacheCap, sizeof(silentInputFrames) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels));
ma_device__on_data(pDevice, pDevice->playback.pInputCache, silentInputFrames, inputFrameCount); ma_device__handle_data_callback(pDevice, pDevice->playback.pInputCache, silentInputFrames, inputFrameCount);
} }
pDevice->playback.inputCacheConsumed = 0; pDevice->playback.inputCacheConsumed = 0;
...@@ -6479,7 +6554,7 @@ static ma_result ma_device_audio_thread__default_read_write(ma_device* pDevice) ...@@ -6479,7 +6554,7 @@ static ma_result ma_device_audio_thread__default_read_write(ma_device* pDevice)
break; break;
} }
ma_device__on_data(pDevice, playbackClientData, capturedClientData, (ma_uint32)capturedClientFramesToProcessThisIteration); /* Safe cast .*/ ma_device__handle_data_callback(pDevice, playbackClientData, capturedClientData, (ma_uint32)capturedClientFramesToProcessThisIteration); /* Safe cast .*/
capturedDeviceFramesProcessed += (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */ capturedDeviceFramesProcessed += (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
capturedDeviceFramesRemaining -= (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */ capturedDeviceFramesRemaining -= (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
...@@ -9344,15 +9419,11 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device ...@@ -9344,15 +9419,11 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device
/* The period needs to be clamped between minPeriodInFrames and maxPeriodInFrames. */ /* The period needs to be clamped between minPeriodInFrames and maxPeriodInFrames. */
actualPeriodInFrames = ma_clamp(actualPeriodInFrames, minPeriodInFrames, maxPeriodInFrames); actualPeriodInFrames = ma_clamp(actualPeriodInFrames, minPeriodInFrames, maxPeriodInFrames);
#if defined(MA_DEBUG_OUTPUT)
{
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] Trying IAudioClient3_InitializeSharedAudioStream(actualPeriodInFrames=%d)\n", actualPeriodInFrames); ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] Trying IAudioClient3_InitializeSharedAudioStream(actualPeriodInFrames=%d)\n", actualPeriodInFrames);
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " defaultPeriodInFrames=%d\n", defaultPeriodInFrames); ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " defaultPeriodInFrames=%d\n", defaultPeriodInFrames);
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " fundamentalPeriodInFrames=%d\n", fundamentalPeriodInFrames); ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " fundamentalPeriodInFrames=%d\n", fundamentalPeriodInFrames);
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " minPeriodInFrames=%d\n", minPeriodInFrames); ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " minPeriodInFrames=%d\n", minPeriodInFrames);
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " maxPeriodInFrames=%d\n", maxPeriodInFrames); ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " maxPeriodInFrames=%d\n", maxPeriodInFrames);
}
#endif
/* If the client requested a largish buffer than we don't actually want to use low latency shared mode because it forces small buffers. */ /* If the client requested a largish buffer than we don't actually want to use low latency shared mode because it forces small buffers. */
if (actualPeriodInFrames >= desiredPeriodInFrames) { if (actualPeriodInFrames >= desiredPeriodInFrames) {
...@@ -9364,12 +9435,9 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device ...@@ -9364,12 +9435,9 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
wasInitializedUsingIAudioClient3 = MA_TRUE; wasInitializedUsingIAudioClient3 = MA_TRUE;
pData->periodSizeInFramesOut = actualPeriodInFrames; pData->periodSizeInFramesOut = actualPeriodInFrames;
#if defined(MA_DEBUG_OUTPUT)
{
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] Using IAudioClient3\n"); ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] Using IAudioClient3\n");
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " periodSizeInFramesOut=%d\n", pData->periodSizeInFramesOut); ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " periodSizeInFramesOut=%d\n", pData->periodSizeInFramesOut);
}
#endif
} else { } else {
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] IAudioClient3_InitializeSharedAudioStream failed. Falling back to IAudioClient.\n"); ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] IAudioClient3_InitializeSharedAudioStream failed. Falling back to IAudioClient.\n");
} }
...@@ -9620,7 +9688,7 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev ...@@ -9620,7 +9688,7 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev
pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut; pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut;
ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualPeriodSizeInFramesPlayback); ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualPeriodSizeInFramesPlayback);
/* We must always have a valid ID. */ /* We must always have a valid ID because rerouting will look at it. */
ma_wcscpy_s(pDevice->playback.id.wasapi, sizeof(pDevice->playback.id.wasapi), data.id.wasapi); ma_wcscpy_s(pDevice->playback.id.wasapi, sizeof(pDevice->playback.id.wasapi), data.id.wasapi);
} }
...@@ -9794,7 +9862,7 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf ...@@ -9794,7 +9862,7 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf
pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut; pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut;
ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualPeriodSizeInFramesPlayback); ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualPeriodSizeInFramesPlayback);
/* We must always have a valid ID. */ /* We must always have a valid ID because rerouting will look at it. */
ma_wcscpy_s(pDevice->playback.id.wasapi, sizeof(pDevice->playback.id.wasapi), data.id.wasapi); ma_wcscpy_s(pDevice->playback.id.wasapi, sizeof(pDevice->playback.id.wasapi), data.id.wasapi);
/* The descriptor needs to be updated with actual values. */ /* The descriptor needs to be updated with actual values. */
...@@ -9915,7 +9983,7 @@ static ma_result ma_device_reroute__wasapi(ma_device* pDevice, ma_device_type de ...@@ -9915,7 +9983,7 @@ static ma_result ma_device_reroute__wasapi(ma_device* pDevice, ma_device_type de
result = ma_device_reinit__wasapi(pDevice, deviceType); result = ma_device_reinit__wasapi(pDevice, deviceType);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Reinitializing device after route change failed.\n"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[WASAPI] Reinitializing device after route change failed.\n");
return result; return result;
} }
...@@ -10182,11 +10250,9 @@ static ma_result ma_device_data_loop__wasapi(ma_device* pDevice) ...@@ -10182,11 +10250,9 @@ static ma_result ma_device_data_loop__wasapi(ma_device* pDevice)
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture);
} }
} else { } else {
#ifdef MA_DEBUG_OUTPUT
if (flagsCapture != 0) { if (flagsCapture != 0) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Capture Flags: %ld\n", flagsCapture); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Capture Flags: %ld\n", flagsCapture);
} }
#endif
} }
mappedDeviceBufferFramesRemainingCapture = mappedDeviceBufferSizeInFramesCapture; mappedDeviceBufferFramesRemainingCapture = mappedDeviceBufferSizeInFramesCapture;
...@@ -10231,7 +10297,7 @@ static ma_result ma_device_data_loop__wasapi(ma_device* pDevice) ...@@ -10231,7 +10297,7 @@ static ma_result ma_device_data_loop__wasapi(ma_device* pDevice)
framesToProcess = ma_min(mappedDeviceBufferFramesRemainingCapture, mappedDeviceBufferFramesRemainingPlayback); framesToProcess = ma_min(mappedDeviceBufferFramesRemainingCapture, mappedDeviceBufferFramesRemainingPlayback);
framesProcessed = framesToProcess; framesProcessed = framesToProcess;
ma_device__on_data(pDevice, pRunningDeviceBufferPlayback, pRunningDeviceBufferCapture, framesToProcess); ma_device__handle_data_callback(pDevice, pRunningDeviceBufferPlayback, pRunningDeviceBufferCapture, framesToProcess);
mappedDeviceBufferFramesRemainingCapture -= framesProcessed; mappedDeviceBufferFramesRemainingCapture -= framesProcessed;
mappedDeviceBufferFramesRemainingPlayback -= framesProcessed; mappedDeviceBufferFramesRemainingPlayback -= framesProcessed;
...@@ -10247,7 +10313,7 @@ static ma_result ma_device_data_loop__wasapi(ma_device* pDevice) ...@@ -10247,7 +10313,7 @@ static ma_result ma_device_data_loop__wasapi(ma_device* pDevice)
framesToProcess = ma_min(mappedDeviceBufferFramesRemainingCapture, outputDataInClientFormatCap); framesToProcess = ma_min(mappedDeviceBufferFramesRemainingCapture, outputDataInClientFormatCap);
framesProcessed = framesToProcess; framesProcessed = framesToProcess;
ma_device__on_data(pDevice, outputDataInClientFormat, pRunningDeviceBufferCapture, framesToProcess); ma_device__handle_data_callback(pDevice, outputDataInClientFormat, pRunningDeviceBufferCapture, framesToProcess);
outputDataInClientFormatCount = framesProcessed; outputDataInClientFormatCount = framesProcessed;
outputDataInClientFormatConsumed = 0; outputDataInClientFormatConsumed = 0;
...@@ -10269,7 +10335,7 @@ static ma_result ma_device_data_loop__wasapi(ma_device* pDevice) ...@@ -10269,7 +10335,7 @@ static ma_result ma_device_data_loop__wasapi(ma_device* pDevice)
break; break;
} }
ma_device__on_data(pDevice, pRunningDeviceBufferPlayback, inputDataInClientFormat, (ma_uint32)capturedClientFramesToProcess); /* Safe cast. */ ma_device__handle_data_callback(pDevice, pRunningDeviceBufferPlayback, inputDataInClientFormat, (ma_uint32)capturedClientFramesToProcess); /* Safe cast. */
mappedDeviceBufferFramesRemainingCapture -= (ma_uint32)capturedDeviceFramesToProcess; mappedDeviceBufferFramesRemainingCapture -= (ma_uint32)capturedDeviceFramesToProcess;
mappedDeviceBufferFramesRemainingPlayback -= (ma_uint32)capturedClientFramesToProcess; mappedDeviceBufferFramesRemainingPlayback -= (ma_uint32)capturedClientFramesToProcess;
...@@ -10286,7 +10352,7 @@ static ma_result ma_device_data_loop__wasapi(ma_device* pDevice) ...@@ -10286,7 +10352,7 @@ static ma_result ma_device_data_loop__wasapi(ma_device* pDevice)
break; break;
} }
ma_device__on_data(pDevice, outputDataInClientFormat, inputDataInClientFormat, (ma_uint32)capturedClientFramesToProcess); ma_device__handle_data_callback(pDevice, outputDataInClientFormat, inputDataInClientFormat, (ma_uint32)capturedClientFramesToProcess);
mappedDeviceBufferFramesRemainingCapture -= (ma_uint32)capturedDeviceFramesToProcess; mappedDeviceBufferFramesRemainingCapture -= (ma_uint32)capturedDeviceFramesToProcess;
outputDataInClientFormatCount = (ma_uint32)capturedClientFramesToProcess; outputDataInClientFormatCount = (ma_uint32)capturedClientFramesToProcess;
...@@ -10439,11 +10505,9 @@ static ma_result ma_device_data_loop__wasapi(ma_device* pDevice) ...@@ -10439,11 +10505,9 @@ static ma_result ma_device_data_loop__wasapi(ma_device* pDevice)
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture);
} }
} else { } else {
#ifdef MA_DEBUG_OUTPUT
if (flagsCapture != 0) { if (flagsCapture != 0) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Capture Flags: %ld\n", flagsCapture); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Capture Flags: %ld\n", flagsCapture);
} }
#endif
} }
/* We should have a buffer at this point, but let's just do a sanity check anyway. */ /* We should have a buffer at this point, but let's just do a sanity check anyway. */
...@@ -11965,7 +12029,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) ...@@ -11965,7 +12029,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice)
outputFramesInClientFormatCount = (ma_uint32)clientCapturedFramesToProcess; outputFramesInClientFormatCount = (ma_uint32)clientCapturedFramesToProcess;
mappedDeviceFramesProcessedCapture += (ma_uint32)deviceCapturedFramesToProcess; mappedDeviceFramesProcessedCapture += (ma_uint32)deviceCapturedFramesToProcess;
ma_device__on_data(pDevice, outputFramesInClientFormat, inputFramesInClientFormat, (ma_uint32)clientCapturedFramesToProcess); ma_device__handle_data_callback(pDevice, outputFramesInClientFormat, inputFramesInClientFormat, (ma_uint32)clientCapturedFramesToProcess);
/* At this point we have input and output data in client format. All we need to do now is convert it to the output device format. This may take a few passes. */ /* At this point we have input and output data in client format. All we need to do now is convert it to the output device format. This may take a few passes. */
for (;;) { for (;;) {
...@@ -11993,7 +12057,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) ...@@ -11993,7 +12057,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice)
availableBytesPlayback += physicalPlayCursorInBytes; /* Wrap around. */ availableBytesPlayback += physicalPlayCursorInBytes; /* Wrap around. */
} else { } else {
/* This is an error. */ /* This is an error. */
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Duplex/Playback) WARNING: Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[DirectSound] (Duplex/Playback): Play cursor has moved in front of the write cursor (same loop iteration). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
availableBytesPlayback = 0; availableBytesPlayback = 0;
} }
} else { } else {
...@@ -12002,7 +12066,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) ...@@ -12002,7 +12066,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice)
availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback; availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
} else { } else {
/* This is an error. */ /* This is an error. */
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Duplex/Playback) WARNING: Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[DirectSound] (Duplex/Playback): Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
availableBytesPlayback = 0; availableBytesPlayback = 0;
} }
} }
...@@ -12054,7 +12118,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) ...@@ -12054,7 +12118,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice)
silentPaddingInBytes = lockSizeInBytesPlayback; silentPaddingInBytes = lockSizeInBytesPlayback;
} }
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Duplex/Playback) Playback buffer starved. availableBytesPlayback=%ld, silentPaddingInBytes=%ld\n", availableBytesPlayback, silentPaddingInBytes); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[DirectSound] (Duplex/Playback) Playback buffer starved. availableBytesPlayback=%ld, silentPaddingInBytes=%ld\n", availableBytesPlayback, silentPaddingInBytes);
} }
} }
...@@ -12175,11 +12239,9 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) ...@@ -12175,11 +12239,9 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice)
result = ma_result_from_HRESULT(hr); result = ma_result_from_HRESULT(hr);
} }
#ifdef MA_DEBUG_OUTPUT
if (lockSizeInBytesCapture != mappedSizeInBytesCapture) { if (lockSizeInBytesCapture != mappedSizeInBytesCapture) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Capture) lockSizeInBytesCapture=%ld != mappedSizeInBytesCapture=%ld\n", lockSizeInBytesCapture, mappedSizeInBytesCapture); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Capture) lockSizeInBytesCapture=%ld != mappedSizeInBytesCapture=%ld\n", lockSizeInBytesCapture, mappedSizeInBytesCapture);
} }
#endif
ma_device__send_frames_to_client(pDevice, mappedSizeInBytesCapture/bpfDeviceCapture, pMappedDeviceBufferCapture); ma_device__send_frames_to_client(pDevice, mappedSizeInBytesCapture/bpfDeviceCapture, pMappedDeviceBufferCapture);
...@@ -12220,7 +12282,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) ...@@ -12220,7 +12282,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice)
availableBytesPlayback += physicalPlayCursorInBytes; /* Wrap around. */ availableBytesPlayback += physicalPlayCursorInBytes; /* Wrap around. */
} else { } else {
/* This is an error. */ /* This is an error. */
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Playback) WARNING: Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[DirectSound] (Playback): Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
availableBytesPlayback = 0; availableBytesPlayback = 0;
} }
} else { } else {
...@@ -12229,7 +12291,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) ...@@ -12229,7 +12291,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice)
availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback; availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
} else { } else {
/* This is an error. */ /* This is an error. */
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Playback) WARNING: Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[DirectSound] (Playback): Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
availableBytesPlayback = 0; availableBytesPlayback = 0;
} }
} }
...@@ -15047,30 +15109,30 @@ static ma_result ma_device_start__alsa(ma_device* pDevice) ...@@ -15047,30 +15109,30 @@ static ma_result ma_device_start__alsa(ma_device* pDevice)
static ma_result ma_device_stop__alsa(ma_device* pDevice) static ma_result ma_device_stop__alsa(ma_device* pDevice)
{ {
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping capture device... "); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping capture device...\n");
((ma_snd_pcm_drop_proc)pDevice->pContext->alsa.snd_pcm_drop)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture); ((ma_snd_pcm_drop_proc)pDevice->pContext->alsa.snd_pcm_drop)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Done\n"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping capture device successful.\n");
/* We need to prepare the device again, otherwise we won't be able to restart the device. */ /* We need to prepare the device again, otherwise we won't be able to restart the device. */
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing capture device... "); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing capture device...\n");
if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture) < 0) { if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture) < 0) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Failed\n"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing capture device failed.\n");
} else { } else {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Done\n"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing capture device successful.\n");
} }
} }
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping playback device... "); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping playback device...\n");
((ma_snd_pcm_drop_proc)pDevice->pContext->alsa.snd_pcm_drop)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback); ((ma_snd_pcm_drop_proc)pDevice->pContext->alsa.snd_pcm_drop)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Done\n"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping playback device successful.\n");
/* We need to prepare the device again, otherwise we won't be able to restart the device. */ /* We need to prepare the device again, otherwise we won't be able to restart the device. */
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing playback device... "); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing playback device...\n");
if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback) < 0) { if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback) < 0) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Failed\n"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing playback device failed.\n");
} else { } else {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Done\n"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing playback device successful.\n");
} }
} }
...@@ -15263,7 +15325,7 @@ static ma_result ma_device_data_loop_wakeup__alsa(ma_device* pDevice) ...@@ -15263,7 +15325,7 @@ static ma_result ma_device_data_loop_wakeup__alsa(ma_device* pDevice)
MA_ASSERT(pDevice != NULL); MA_ASSERT(pDevice != NULL);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Waking up... "); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Waking up...\n");
/* Write to an eventfd to trigger a wakeup from poll() and abort any reading or writing. */ /* Write to an eventfd to trigger a wakeup from poll() and abort any reading or writing. */
if (pDevice->alsa.pPollDescriptorsCapture != NULL) { if (pDevice->alsa.pPollDescriptorsCapture != NULL) {
...@@ -15274,11 +15336,11 @@ static ma_result ma_device_data_loop_wakeup__alsa(ma_device* pDevice) ...@@ -15274,11 +15336,11 @@ static ma_result ma_device_data_loop_wakeup__alsa(ma_device* pDevice)
} }
if (resultWrite < 0) { if (resultWrite < 0) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] write() failed."); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] write() failed.\n");
return ma_result_from_errno(errno); return ma_result_from_errno(errno);
} }
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Done\n"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Waking up completed successfully.\n");
return MA_SUCCESS; return MA_SUCCESS;
} }
...@@ -17103,7 +17165,7 @@ static ma_result ma_device_write_to_stream__pulse(ma_device* pDevice, ma_pa_stre ...@@ -17103,7 +17165,7 @@ static ma_result ma_device_write_to_stream__pulse(ma_device* pDevice, ma_pa_stre
framesProcessed += framesMapped; framesProcessed += framesMapped;
} else { } else {
result = MA_ERROR; /* No data available. Abort. */ result = MA_SUCCESS; /* No data available for writing. */
goto done; goto done;
} }
} else { } else {
...@@ -17235,8 +17297,6 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ...@@ -17235,8 +17297,6 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi
MA_ASSERT(pDevice != NULL); MA_ASSERT(pDevice != NULL);
MA_ZERO_OBJECT(&pDevice->pulse); MA_ZERO_OBJECT(&pDevice->pulse);
printf("TESTING\n");
if (pConfig->deviceType == ma_device_type_loopback) { if (pConfig->deviceType == ma_device_type_loopback) {
return MA_DEVICE_TYPE_NOT_SUPPORTED; return MA_DEVICE_TYPE_NOT_SUPPORTED;
} }
...@@ -17291,26 +17351,26 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ...@@ -17291,26 +17351,26 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi
} else { } else {
ss.format = MA_PA_SAMPLE_FLOAT32BE; ss.format = MA_PA_SAMPLE_FLOAT32BE;
} }
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] WARNING: sample_spec.format not supported by miniaudio. Defaulting to PA_SAMPLE_RATE_FLOAT32\n"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.format not supported by miniaudio. Defaulting to PA_SAMPLE_FLOAT32.\n");
} }
if (ss.rate == 0) { if (ss.rate == 0) {
ss.rate = MA_DEFAULT_SAMPLE_RATE; ss.rate = MA_DEFAULT_SAMPLE_RATE;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] WARNING: sample_spec.rate = 0. Defaulting to %d\n", ss.rate); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.rate = 0. Defaulting to %d.\n", ss.rate);
} }
if (ss.channels == 0) { if (ss.channels == 0) {
ss.channels = MA_DEFAULT_CHANNELS; ss.channels = MA_DEFAULT_CHANNELS;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] WARNING: sample_spec.channels = 0. Defaulting to %d\n", ss.channels); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.channels = 0. Defaulting to %d.\n", ss.channels);
} }
/* We now have enough information to calculate our actual period size in frames. */ /* We now have enough information to calculate our actual period size in frames. */
pDescriptorCapture->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorCapture, ss.rate, pConfig->performanceProfile); pDescriptorCapture->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorCapture, ss.rate, pConfig->performanceProfile);
attr = ma_device__pa_buffer_attr_new(pDescriptorCapture->periodSizeInFrames, pDescriptorCapture->periodCount, &ss); attr = ma_device__pa_buffer_attr_new(pDescriptorCapture->periodSizeInFrames, pDescriptorCapture->periodCount, &ss);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] Capture attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorCapture->periodSizeInFrames); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Capture attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorCapture->periodSizeInFrames);
pDevice->pulse.pStreamCapture = ma_device__pa_stream_new__pulse(pDevice, pConfig->pulse.pStreamNameCapture, &ss, &cmap); pDevice->pulse.pStreamCapture = ma_device__pa_stream_new__pulse(pDevice, pConfig->pulse.pStreamNameCapture, &ss, &cmap);
if (pDevice->pulse.pStreamCapture == NULL) { if (pDevice->pulse.pStreamCapture == NULL) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio capture stream."); ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio capture stream.\n");
result = MA_ERROR; result = MA_ERROR;
goto on_error0; goto on_error0;
} }
...@@ -17374,22 +17434,13 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ...@@ -17374,22 +17434,13 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi
pDescriptorCapture->periodCount = attr.maxlength / attr.fragsize; pDescriptorCapture->periodCount = attr.maxlength / attr.fragsize;
pDescriptorCapture->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) / pDescriptorCapture->periodCount; pDescriptorCapture->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) / pDescriptorCapture->periodCount;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] Capture actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorCapture->periodSizeInFrames); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Capture actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorCapture->periodSizeInFrames);
#if 0
/* Name. */
devCapture = ((ma_pa_stream_get_device_name_proc)pDevice->pContext->pulse.pa_stream_get_device_name)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
if (devCapture != NULL) {
ma_pa_operation* pOP = ((ma_pa_context_get_source_info_by_name_proc)pDevice->pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)pDevice->pulse.pPulseContext, devCapture, ma_device_source_name_callback, pDevice);
ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, pOP);
}
#endif
} }
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
result = ma_context_get_sink_info__pulse(pDevice->pContext, devPlayback, &sinkInfo); result = ma_context_get_sink_info__pulse(pDevice->pContext, devPlayback, &sinkInfo);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve sink info for playback device."); ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve sink info for playback device.\n");
goto on_error2; goto on_error2;
} }
...@@ -17402,15 +17453,15 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ...@@ -17402,15 +17453,15 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi
} else { } else {
ss.format = MA_PA_SAMPLE_FLOAT32BE; ss.format = MA_PA_SAMPLE_FLOAT32BE;
} }
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] WARNING: sample_spec.format not supported by miniaudio. Defaulting to PA_SAMPLE_RATE_FLOAT32\n"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.format not supported by miniaudio. Defaulting to PA_SAMPLE_FLOAT32.\n");
} }
if (ss.rate == 0) { if (ss.rate == 0) {
ss.rate = MA_DEFAULT_SAMPLE_RATE; ss.rate = MA_DEFAULT_SAMPLE_RATE;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] WARNING: sample_spec.rate = 0. Defaulting to %d\n", ss.rate); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.rate = 0. Defaulting to %d.\n", ss.rate);
} }
if (ss.channels == 0) { if (ss.channels == 0) {
ss.channels = MA_DEFAULT_CHANNELS; ss.channels = MA_DEFAULT_CHANNELS;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] WARNING: sample_spec.channels = 0. Defaulting to %d\n", ss.channels); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.channels = 0. Defaulting to %d.\n", ss.channels);
} }
/* We now have enough information to calculate the actual buffer size in frames. */ /* We now have enough information to calculate the actual buffer size in frames. */
...@@ -17418,11 +17469,11 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ...@@ -17418,11 +17469,11 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi
attr = ma_device__pa_buffer_attr_new(pDescriptorPlayback->periodSizeInFrames, pDescriptorPlayback->periodCount, &ss); attr = ma_device__pa_buffer_attr_new(pDescriptorPlayback->periodSizeInFrames, pDescriptorPlayback->periodCount, &ss);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] Playback attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorPlayback->periodSizeInFrames); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Playback attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorPlayback->periodSizeInFrames);
pDevice->pulse.pStreamPlayback = ma_device__pa_stream_new__pulse(pDevice, pConfig->pulse.pStreamNamePlayback, &ss, &cmap); pDevice->pulse.pStreamPlayback = ma_device__pa_stream_new__pulse(pDevice, pConfig->pulse.pStreamNamePlayback, &ss, &cmap);
if (pDevice->pulse.pStreamPlayback == NULL) { if (pDevice->pulse.pStreamPlayback == NULL) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio playback stream."); ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio playback stream.\n");
result = MA_ERROR; result = MA_ERROR;
goto on_error2; goto on_error2;
} }
...@@ -17489,16 +17540,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ...@@ -17489,16 +17540,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi
pDescriptorPlayback->periodCount = ma_max(attr.maxlength / attr.tlength, 1); pDescriptorPlayback->periodCount = ma_max(attr.maxlength / attr.tlength, 1);
pDescriptorPlayback->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels) / pDescriptorPlayback->periodCount; pDescriptorPlayback->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels) / pDescriptorPlayback->periodCount;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] Playback actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorPlayback->periodSizeInFrames); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Playback actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorPlayback->periodSizeInFrames);
#if 0
/* Name. */
devPlayback = ((ma_pa_stream_get_device_name_proc)pDevice->pContext->pulse.pa_stream_get_device_name)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
if (devPlayback != NULL) {
ma_pa_operation* pOP = ((ma_pa_context_get_sink_info_by_name_proc)pDevice->pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)pDevice->pulse.pPulseContext, devPlayback, ma_device_sink_name_callback, pDevice);
ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, pOP);
}
#endif
} }
...@@ -17606,11 +17648,12 @@ static ma_result ma_device_start__pulse(ma_device* pDevice) ...@@ -17606,11 +17648,12 @@ static ma_result ma_device_start__pulse(ma_device* pDevice)
} }
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
/* We need to fill some data before uncorking. Not doing this will result in the write callback never getting fired. */ /*
result = ma_device_write_to_stream__pulse(pDevice, (ma_pa_stream*)(pDevice->pulse.pStreamPlayback), NULL); We need to fill some data before uncorking. Not doing this will result in the write callback
if (result != MA_SUCCESS) { never getting fired. We're not going to abort if writing fails because I still want the device
return result; /* Failed to write data. Not sure what to do here... Just aborting. */ to get uncorked.
} */
ma_device_write_to_stream__pulse(pDevice, (ma_pa_stream*)(pDevice->pulse.pStreamPlayback), NULL); /* No need to check the result here. Always want to fall through an uncork.*/
result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 0); result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 0);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
...@@ -17624,7 +17667,6 @@ static ma_result ma_device_start__pulse(ma_device* pDevice) ...@@ -17624,7 +17667,6 @@ static ma_result ma_device_start__pulse(ma_device* pDevice)
static ma_result ma_device_stop__pulse(ma_device* pDevice) static ma_result ma_device_stop__pulse(ma_device* pDevice)
{ {
ma_result result; ma_result result;
ma_bool32 wasSuccessful;
MA_ASSERT(pDevice != NULL); MA_ASSERT(pDevice != NULL);
...@@ -17636,9 +17678,16 @@ static ma_result ma_device_stop__pulse(ma_device* pDevice) ...@@ -17636,9 +17678,16 @@ static ma_result ma_device_stop__pulse(ma_device* pDevice)
} }
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
/* The stream needs to be drained if it's a playback device. */ /*
Ideally we would drain the device here, but there's been cases where PulseAudio seems to be
broken on some systems to the point where no audio processing seems to happen. When this
happens, draining never completes and we get stuck here. For now I'm disabling draining of
the device so we don't just freeze the application.
*/
#if 0
ma_pa_operation* pOP = ((ma_pa_stream_drain_proc)pDevice->pContext->pulse.pa_stream_drain)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_pulse_operation_complete_callback, &wasSuccessful); ma_pa_operation* pOP = ((ma_pa_stream_drain_proc)pDevice->pContext->pulse.pa_stream_drain)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_pulse_operation_complete_callback, &wasSuccessful);
ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, pOP); ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, pOP);
#endif
result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 1); result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 1);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
...@@ -20048,7 +20097,7 @@ static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_ ...@@ -20048,7 +20097,7 @@ static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_
UInt32 propSize; UInt32 propSize;
/* We want to ensure we use a consistent device name to device enumeration. */ /* We want to ensure we use a consistent device name to device enumeration. */
if (pDeviceID != NULL) { if (pDeviceID != NULL && pDeviceID->coreaudio[0] != '\0') {
ma_bool32 found = MA_FALSE; ma_bool32 found = MA_FALSE;
if (deviceType == ma_device_type_playback) { if (deviceType == ma_device_type_playback) {
NSArray *pOutputs = [[[AVAudioSession sharedInstance] currentRoute] outputs]; NSArray *pOutputs = [[[AVAudioSession sharedInstance] currentRoute] outputs];
...@@ -20222,7 +20271,7 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl ...@@ -20222,7 +20271,7 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl
MA_ASSERT(pDevice != NULL); MA_ASSERT(pDevice != NULL);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "INFO: Output Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", (int)busNumber, (int)frameCount, (int)pBufferList->mNumberBuffers); /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "INFO: Output Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", (int)busNumber, (int)frameCount, (int)pBufferList->mNumberBuffers);*/
/* We need to check whether or not we are outputting interleaved or non-interleaved samples. The way we do this is slightly different for each type. */ /* We need to check whether or not we are outputting interleaved or non-interleaved samples. The way we do this is slightly different for each type. */
layout = ma_stream_layout_interleaved; layout = ma_stream_layout_interleaved;
...@@ -20240,7 +20289,7 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl ...@@ -20240,7 +20289,7 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl
ma_device_handle_backend_data_callback(pDevice, pBufferList->mBuffers[iBuffer].mData, NULL, frameCountForThisBuffer); ma_device_handle_backend_data_callback(pDevice, pBufferList->mBuffers[iBuffer].mData, NULL, frameCountForThisBuffer);
} }
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", (int)frameCount, (int)pBufferList->mBuffers[iBuffer].mNumberChannels, (int)pBufferList->mBuffers[iBuffer].mDataByteSize); /*a_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", (int)frameCount, (int)pBufferList->mBuffers[iBuffer].mNumberChannels, (int)pBufferList->mBuffers[iBuffer].mDataByteSize);*/
} else { } else {
/* /*
This case is where the number of channels in the output buffer do not match our internal channels. It could mean that it's This case is where the number of channels in the output buffer do not match our internal channels. It could mean that it's
...@@ -20248,7 +20297,7 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl ...@@ -20248,7 +20297,7 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl
output silence here. output silence here.
*/ */
MA_ZERO_MEMORY(pBufferList->mBuffers[iBuffer].mData, pBufferList->mBuffers[iBuffer].mDataByteSize); MA_ZERO_MEMORY(pBufferList->mBuffers[iBuffer].mData, pBufferList->mBuffers[iBuffer].mDataByteSize);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", (int)frameCount, (int)pBufferList->mBuffers[iBuffer].mNumberChannels, (int)pBufferList->mBuffers[iBuffer].mDataByteSize); /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", (int)frameCount, (int)pBufferList->mBuffers[iBuffer].mNumberChannels, (int)pBufferList->mBuffers[iBuffer].mDataByteSize);*/
} }
} }
} else { } else {
...@@ -20317,7 +20366,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla ...@@ -20317,7 +20366,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla
layout = ma_stream_layout_deinterleaved; layout = ma_stream_layout_deinterleaved;
} }
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "INFO: Input Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", (int)busNumber, (int)frameCount, (int)pRenderedBufferList->mNumberBuffers); /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "INFO: Input Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", (int)busNumber, (int)frameCount, (int)pRenderedBufferList->mNumberBuffers);*/
/* /*
There has been a situation reported where frame count passed into this function is greater than the capacity of There has been a situation reported where frame count passed into this function is greater than the capacity of
...@@ -20327,7 +20376,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla ...@@ -20327,7 +20376,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla
*/ */
result = ma_device_realloc_AudioBufferList__coreaudio(pDevice, frameCount, pDevice->capture.internalFormat, pDevice->capture.internalChannels, layout); result = ma_device_realloc_AudioBufferList__coreaudio(pDevice, frameCount, pDevice->capture.internalFormat, pDevice->capture.internalChannels, layout);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Failed to allocate AudioBufferList for capture."); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Failed to allocate AudioBufferList for capture.\n");
return noErr; return noErr;
} }
...@@ -20348,7 +20397,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla ...@@ -20348,7 +20397,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla
status = ((ma_AudioUnitRender_proc)pDevice->pContext->coreaudio.AudioUnitRender)((AudioUnit)pDevice->coreaudio.audioUnitCapture, pActionFlags, pTimeStamp, busNumber, frameCount, pRenderedBufferList); status = ((ma_AudioUnitRender_proc)pDevice->pContext->coreaudio.AudioUnitRender)((AudioUnit)pDevice->coreaudio.audioUnitCapture, pActionFlags, pTimeStamp, busNumber, frameCount, pRenderedBufferList);
if (status != noErr) { if (status != noErr) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " ERROR: AudioUnitRender() failed with %d\n", (int)status); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " ERROR: AudioUnitRender() failed with %d.\n", (int)status);
return status; return status;
} }
...@@ -20356,7 +20405,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla ...@@ -20356,7 +20405,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla
for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; ++iBuffer) { for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; ++iBuffer) {
if (pRenderedBufferList->mBuffers[iBuffer].mNumberChannels == pDevice->capture.internalChannels) { if (pRenderedBufferList->mBuffers[iBuffer].mNumberChannels == pDevice->capture.internalChannels) {
ma_device_handle_backend_data_callback(pDevice, NULL, pRenderedBufferList->mBuffers[iBuffer].mData, frameCount); ma_device_handle_backend_data_callback(pDevice, NULL, pRenderedBufferList->mBuffers[iBuffer].mData, frameCount);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " mDataByteSize=%d\n", (int)pRenderedBufferList->mBuffers[iBuffer].mDataByteSize); /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " mDataByteSize=%d.\n", (int)pRenderedBufferList->mBuffers[iBuffer].mDataByteSize);*/
} else { } else {
/* /*
This case is where the number of channels in the output buffer do not match our internal channels. It could mean that it's This case is where the number of channels in the output buffer do not match our internal channels. It could mean that it's
...@@ -20379,7 +20428,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla ...@@ -20379,7 +20428,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla
framesRemaining -= framesToSend; framesRemaining -= framesToSend;
} }
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", (int)frameCount, (int)pRenderedBufferList->mBuffers[iBuffer].mNumberChannels, (int)pRenderedBufferList->mBuffers[iBuffer].mDataByteSize); /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", (int)frameCount, (int)pRenderedBufferList->mBuffers[iBuffer].mNumberChannels, (int)pRenderedBufferList->mBuffers[iBuffer].mDataByteSize);*/
} }
} }
} else { } else {
...@@ -20745,13 +20794,13 @@ static ma_result ma_device__untrack__coreaudio(ma_device* pDevice) ...@@ -20745,13 +20794,13 @@ static ma_result ma_device__untrack__coreaudio(ma_device* pDevice)
{ {
case AVAudioSessionInterruptionTypeBegan: case AVAudioSessionInterruptionTypeBegan:
{ {
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Interruption: AVAudioSessionInterruptionTypeBegan\n"); ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Interruption: AVAudioSessionInterruptionTypeBegan\n");
ma_device__on_notification_interruption_began(m_pDevice); ma_device__on_notification_interruption_began(m_pDevice);
} break; } break;
case AVAudioSessionInterruptionTypeEnded: case AVAudioSessionInterruptionTypeEnded:
{ {
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Interruption: AVAudioSessionInterruptionTypeEnded\n"); ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Interruption: AVAudioSessionInterruptionTypeEnded\n");
ma_device__on_notification_interruption_ended(m_pDevice); ma_device__on_notification_interruption_ended(m_pDevice);
} break; } break;
} }
...@@ -20766,38 +20815,38 @@ static ma_result ma_device__untrack__coreaudio(ma_device* pDevice) ...@@ -20766,38 +20815,38 @@ static ma_result ma_device__untrack__coreaudio(ma_device* pDevice)
{ {
case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
{ {
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOldDeviceUnavailable\n"); ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOldDeviceUnavailable\n");
} break; } break;
case AVAudioSessionRouteChangeReasonNewDeviceAvailable: case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
{ {
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNewDeviceAvailable\n"); ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNewDeviceAvailable\n");
} break; } break;
case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory: case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory:
{ {
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory\n"); ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory\n");
} break; } break;
case AVAudioSessionRouteChangeReasonWakeFromSleep: case AVAudioSessionRouteChangeReasonWakeFromSleep:
{ {
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonWakeFromSleep\n"); ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonWakeFromSleep\n");
} break; } break;
case AVAudioSessionRouteChangeReasonOverride: case AVAudioSessionRouteChangeReasonOverride:
{ {
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOverride\n"); ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOverride\n");
} break; } break;
case AVAudioSessionRouteChangeReasonCategoryChange: case AVAudioSessionRouteChangeReasonCategoryChange:
{ {
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonCategoryChange\n"); ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonCategoryChange\n");
} break; } break;
case AVAudioSessionRouteChangeReasonUnknown: case AVAudioSessionRouteChangeReasonUnknown:
default: default:
{ {
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonUnknown\n"); ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonUnknown\n");
} break; } break;
} }
...@@ -21322,6 +21371,7 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev ...@@ -21322,6 +21371,7 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev
if (deviceType == ma_device_type_capture) { if (deviceType == ma_device_type_capture) {
#if defined(MA_APPLE_DESKTOP) #if defined(MA_APPLE_DESKTOP)
pDevice->coreaudio.deviceObjectIDCapture = (ma_uint32)data.deviceObjectID; pDevice->coreaudio.deviceObjectIDCapture = (ma_uint32)data.deviceObjectID;
ma_get_AudioObject_uid(pDevice->pContext, pDevice->coreaudio.deviceObjectIDCapture, sizeof(pDevice->capture.id.coreaudio), pDevice->capture.id.coreaudio);
#endif #endif
pDevice->coreaudio.audioUnitCapture = (ma_ptr)data.audioUnit; pDevice->coreaudio.audioUnitCapture = (ma_ptr)data.audioUnit;
pDevice->coreaudio.pAudioBufferList = (ma_ptr)data.pAudioBufferList; pDevice->coreaudio.pAudioBufferList = (ma_ptr)data.pAudioBufferList;
...@@ -21336,6 +21386,7 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev ...@@ -21336,6 +21386,7 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev
} else if (deviceType == ma_device_type_playback) { } else if (deviceType == ma_device_type_playback) {
#if defined(MA_APPLE_DESKTOP) #if defined(MA_APPLE_DESKTOP)
pDevice->coreaudio.deviceObjectIDPlayback = (ma_uint32)data.deviceObjectID; pDevice->coreaudio.deviceObjectIDPlayback = (ma_uint32)data.deviceObjectID;
ma_get_AudioObject_uid(pDevice->pContext, pDevice->coreaudio.deviceObjectIDPlayback, sizeof(pDevice->playback.id.coreaudio), pDevice->playback.id.coreaudio);
#endif #endif
pDevice->coreaudio.audioUnitPlayback = (ma_ptr)data.audioUnit; pDevice->coreaudio.audioUnitPlayback = (ma_ptr)data.audioUnit;
...@@ -21413,6 +21464,8 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c ...@@ -21413,6 +21464,8 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c
pDescriptorCapture->periodCount = data.periodsOut; pDescriptorCapture->periodCount = data.periodsOut;
#if defined(MA_APPLE_DESKTOP) #if defined(MA_APPLE_DESKTOP)
ma_get_AudioObject_uid(pDevice->pContext, pDevice->coreaudio.deviceObjectIDCapture, sizeof(pDevice->capture.id.coreaudio), pDevice->capture.id.coreaudio);
/* /*
If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly
switch the device in the background. switch the device in the background.
...@@ -21475,6 +21528,8 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c ...@@ -21475,6 +21528,8 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c
pDescriptorPlayback->periodCount = data.periodsOut; pDescriptorPlayback->periodCount = data.periodsOut;
#if defined(MA_APPLE_DESKTOP) #if defined(MA_APPLE_DESKTOP)
ma_get_AudioObject_uid(pDevice->pContext, pDevice->coreaudio.deviceObjectIDPlayback, sizeof(pDevice->playback.id.coreaudio), pDevice->playback.id.coreaudio);
/* /*
If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly
switch the device in the background. switch the device in the background.
...@@ -22463,19 +22518,6 @@ static ma_result ma_device_init_handle__sndio(ma_device* pDevice, const ma_devic ...@@ -22463,19 +22518,6 @@ static ma_result ma_device_init_handle__sndio(ma_device* pDevice, const ma_devic
pDescriptor->periodSizeInFrames = internalPeriodSizeInFrames; pDescriptor->periodSizeInFrames = internalPeriodSizeInFrames;
pDescriptor->periodCount = internalPeriods; pDescriptor->periodCount = internalPeriods;
#ifdef MA_DEBUG_OUTPUT
{
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "DEVICE INFO\n");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Format: %s\n", ma_get_format_name(internalFormat));
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Channels: %d\n", internalChannels);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Sample Rate: %d\n", internalSampleRate);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Period Size: %d\n", internalPeriodSizeInFrames);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Periods: %d\n", internalPeriods);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " appbufsz: %d\n", par.appbufsz);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " round: %d\n", par.round);
}
#endif
return MA_SUCCESS; return MA_SUCCESS;
} }
...@@ -24334,14 +24376,14 @@ static void ma_stream_error_callback__aaudio(ma_AAudioStream* pStream, void* pUs ...@@ -24334,14 +24376,14 @@ static void ma_stream_error_callback__aaudio(ma_AAudioStream* pStream, void* pUs
(void)error; (void)error;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[AAudio] ERROR CALLBACK: error=%d, AAudioStream_getState()=%d\n", error, ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream)); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] ERROR CALLBACK: error=%d, AAudioStream_getState()=%d\n", error, ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream));
/* /*
From the documentation for AAudio, when a device is disconnected all we can do is stop it. However, we cannot stop it from the callback - we need From the documentation for AAudio, when a device is disconnected all we can do is stop it. However, we cannot stop it from the callback - we need
to do it from another thread. Therefore we are going to use an event thread for the AAudio backend to do this cleanly and safely. to do it from another thread. Therefore we are going to use an event thread for the AAudio backend to do this cleanly and safely.
*/ */
if (((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream) == MA_AAUDIO_STREAM_STATE_DISCONNECTED) { if (((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream) == MA_AAUDIO_STREAM_STATE_DISCONNECTED) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[AAudio] Device Disconnected.\n"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Device Disconnected.\n");
} }
} }
...@@ -27480,14 +27522,11 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC ...@@ -27480,14 +27522,11 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device info retrieval. ma_context_get_device_info() is not thread safe.\n"); ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device info retrieval. ma_context_get_device_info() is not thread safe.\n");
} }
#ifdef MA_DEBUG_OUTPUT ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "System Architecture:\n");
{ ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " Endian: %s\n", ma_is_little_endian() ? "LE" : "BE");
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[miniaudio] Endian: %s\n", ma_is_little_endian() ? "LE" : "BE"); ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " SSE2: %s\n", ma_has_sse2() ? "YES" : "NO");
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[miniaudio] SSE2: %s\n", ma_has_sse2() ? "YES" : "NO"); ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " AVX2: %s\n", ma_has_avx2() ? "YES" : "NO");
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[miniaudio] AVX2: %s\n", ma_has_avx2() ? "YES" : "NO"); ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, " NEON: %s\n", ma_has_neon() ? "YES" : "NO");
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[miniaudio] NEON: %s\n", ma_has_neon() ? "YES" : "NO");
}
#endif
pContext->backend = backend; pContext->backend = backend;
return result; return result;
...@@ -27767,14 +27806,22 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC ...@@ -27767,14 +27806,22 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
if (pConfig->playback.pDeviceID != NULL) { if (pConfig->playback.pDeviceID != NULL) {
MA_COPY_MEMORY(&pDevice->playback.id, pConfig->playback.pDeviceID, sizeof(pDevice->playback.id)); MA_COPY_MEMORY(&pDevice->playback.id, pConfig->playback.pDeviceID, sizeof(pDevice->playback.id));
pDevice->playback.pID = &pDevice->playback.id;
} else {
pDevice->playback.pID = NULL;
} }
if (pConfig->capture.pDeviceID != NULL) { if (pConfig->capture.pDeviceID != NULL) {
MA_COPY_MEMORY(&pDevice->capture.id, pConfig->capture.pDeviceID, sizeof(pDevice->capture.id)); MA_COPY_MEMORY(&pDevice->capture.id, pConfig->capture.pDeviceID, sizeof(pDevice->capture.id));
pDevice->capture.pID = &pDevice->capture.id;
} else {
pDevice->capture.pID = NULL;
} }
pDevice->noPreSilencedOutputBuffer = pConfig->noPreSilencedOutputBuffer; pDevice->noPreSilencedOutputBuffer = pConfig->noPreSilencedOutputBuffer;
pDevice->noClip = pConfig->noClip; pDevice->noClip = pConfig->noClip;
pDevice->noDisableDenormals = pConfig->noDisableDenormals;
pDevice->noFixedSizedCallback = pConfig->noFixedSizedCallback;
pDevice->masterVolumeFactor = 1; pDevice->masterVolumeFactor = 1;
pDevice->type = pConfig->deviceType; pDevice->type = pConfig->deviceType;
...@@ -27953,6 +28000,61 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC ...@@ -27953,6 +28000,61 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
ma_device__post_init_setup(pDevice, pConfig->deviceType); ma_device__post_init_setup(pDevice, pConfig->deviceType);
/*
If we're using fixed sized callbacks we'll need to make use of an intermediary buffer. Needs to
be done after post_init_setup() because we'll need access to the sample rate.
*/
if (pConfig->noFixedSizedCallback == MA_FALSE) {
/* We're using a fixed sized data callback so we'll need an intermediary buffer. */
ma_uint32 intermediaryBufferCap = pConfig->periodSizeInFrames;
if (intermediaryBufferCap == 0) {
intermediaryBufferCap = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->periodSizeInMilliseconds, pDevice->sampleRate);
}
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) {
ma_uint32 intermediaryBufferSizeInBytes;
pDevice->capture.intermediaryBufferLen = 0;
pDevice->capture.intermediaryBufferCap = intermediaryBufferCap;
if (pDevice->capture.intermediaryBufferCap == 0) {
pDevice->capture.intermediaryBufferCap = pDevice->capture.internalPeriodSizeInFrames;
}
intermediaryBufferSizeInBytes = pDevice->capture.intermediaryBufferCap * ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
pDevice->capture.pIntermediaryBuffer = ma_malloc((size_t)intermediaryBufferSizeInBytes, &pContext->allocationCallbacks);
if (pDevice->capture.pIntermediaryBuffer == NULL) {
ma_device_uninit(pDevice);
return MA_OUT_OF_MEMORY;
}
}
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
ma_uint64 intermediaryBufferSizeInBytes;
pDevice->playback.intermediaryBufferLen = 0;
if (pConfig->deviceType == ma_device_type_duplex) {
pDevice->playback.intermediaryBufferCap = pDevice->capture.intermediaryBufferCap; /* In duplex mode, make sure the intermediary buffer is always the same size as the capture side. */
} else {
pDevice->playback.intermediaryBufferCap = intermediaryBufferCap;
if (pDevice->playback.intermediaryBufferCap == 0) {
pDevice->playback.intermediaryBufferCap = pDevice->playback.internalPeriodSizeInFrames;
}
}
intermediaryBufferSizeInBytes = pDevice->playback.intermediaryBufferCap * ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
pDevice->playback.pIntermediaryBuffer = ma_malloc((size_t)intermediaryBufferSizeInBytes, &pContext->allocationCallbacks);
if (pDevice->playback.pIntermediaryBuffer == NULL) {
ma_device_uninit(pDevice);
return MA_OUT_OF_MEMORY;
}
}
} else {
/* Not using a fixed sized data callback so no need for an intermediary buffer. */
}
/* Some backends don't require the worker thread. */ /* Some backends don't require the worker thread. */
if (!ma_context_is_backend_asynchronous(pContext)) { if (!ma_context_is_backend_asynchronous(pContext)) {
/* The worker thread. */ /* The worker thread. */
...@@ -27983,44 +28085,42 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC ...@@ -27983,44 +28085,42 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
ma_device__set_state(pDevice, ma_device_state_stopped); ma_device__set_state(pDevice, ma_device_state_stopped);
} }
/* Restricting this to debug output because it's a bit spamy and only really needed for debugging. */ /* Log device information. */
#if defined(MA_DEBUG_OUTPUT)
{ {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[%s]\n", ma_get_backend_name(pDevice->pContext->backend)); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[%s]\n", ma_get_backend_name(pDevice->pContext->backend));
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; char name[MA_MAX_DEVICE_NAME_LENGTH + 1];
ma_device_get_name(pDevice, ma_device_type_capture, name, sizeof(name), NULL); ma_device_get_name(pDevice, ma_device_type_capture, name, sizeof(name), NULL);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " %s (%s)\n", name, "Capture"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " %s (%s)\n", name, "Capture");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Format: %s -> %s\n", ma_get_format_name(pDevice->capture.internalFormat), ma_get_format_name(pDevice->capture.format)); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Format: %s -> %s\n", ma_get_format_name(pDevice->capture.internalFormat), ma_get_format_name(pDevice->capture.format));
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Channels: %d -> %d\n", pDevice->capture.internalChannels, pDevice->capture.channels); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channels: %d -> %d\n", pDevice->capture.internalChannels, pDevice->capture.channels);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Sample Rate: %d -> %d\n", pDevice->capture.internalSampleRate, pDevice->sampleRate); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Sample Rate: %d -> %d\n", pDevice->capture.internalSampleRate, pDevice->sampleRate);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Buffer Size: %d*%d (%d)\n", pDevice->capture.internalPeriodSizeInFrames, pDevice->capture.internalPeriods, (pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods)); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Buffer Size: %d*%d (%d)\n", pDevice->capture.internalPeriodSizeInFrames, pDevice->capture.internalPeriods, (pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods));
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Conversion:\n"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Conversion:\n");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Pre Format Conversion: %s\n", pDevice->capture.converter.hasPreFormatConversion ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Pre Format Conversion: %s\n", pDevice->capture.converter.hasPreFormatConversion ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Post Format Conversion: %s\n", pDevice->capture.converter.hasPostFormatConversion ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Post Format Conversion: %s\n", pDevice->capture.converter.hasPostFormatConversion ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Channel Routing: %s\n", pDevice->capture.converter.hasChannelConverter ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Routing: %s\n", pDevice->capture.converter.hasChannelConverter ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Resampling: %s\n", pDevice->capture.converter.hasResampler ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Resampling: %s\n", pDevice->capture.converter.hasResampler ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Passthrough: %s\n", pDevice->capture.converter.isPassthrough ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Passthrough: %s\n", pDevice->capture.converter.isPassthrough ? "YES" : "NO");
} }
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; char name[MA_MAX_DEVICE_NAME_LENGTH + 1];
ma_device_get_name(pDevice, ma_device_type_playback, name, sizeof(name), NULL); ma_device_get_name(pDevice, ma_device_type_playback, name, sizeof(name), NULL);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " %s (%s)\n", name, "Playback"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " %s (%s)\n", name, "Playback");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Format: %s -> %s\n", ma_get_format_name(pDevice->playback.format), ma_get_format_name(pDevice->playback.internalFormat)); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Format: %s -> %s\n", ma_get_format_name(pDevice->playback.format), ma_get_format_name(pDevice->playback.internalFormat));
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Channels: %d -> %d\n", pDevice->playback.channels, pDevice->playback.internalChannels); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channels: %d -> %d\n", pDevice->playback.channels, pDevice->playback.internalChannels);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Sample Rate: %d -> %d\n", pDevice->sampleRate, pDevice->playback.internalSampleRate); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Sample Rate: %d -> %d\n", pDevice->sampleRate, pDevice->playback.internalSampleRate);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Buffer Size: %d*%d (%d)\n", pDevice->playback.internalPeriodSizeInFrames, pDevice->playback.internalPeriods, (pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods)); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Buffer Size: %d*%d (%d)\n", pDevice->playback.internalPeriodSizeInFrames, pDevice->playback.internalPeriods, (pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods));
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Conversion:\n"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Conversion:\n");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Pre Format Conversion: %s\n", pDevice->playback.converter.hasPreFormatConversion ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Pre Format Conversion: %s\n", pDevice->playback.converter.hasPreFormatConversion ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Post Format Conversion: %s\n", pDevice->playback.converter.hasPostFormatConversion ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Post Format Conversion: %s\n", pDevice->playback.converter.hasPostFormatConversion ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Channel Routing: %s\n", pDevice->playback.converter.hasChannelConverter ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Routing: %s\n", pDevice->playback.converter.hasChannelConverter ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Resampling: %s\n", pDevice->playback.converter.hasResampler ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Resampling: %s\n", pDevice->playback.converter.hasResampler ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Passthrough: %s\n", pDevice->playback.converter.isPassthrough ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Passthrough: %s\n", pDevice->playback.converter.isPassthrough ? "YES" : "NO");
} }
} }
#endif
MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_stopped); MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_stopped);
return MA_SUCCESS; return MA_SUCCESS;
...@@ -28136,6 +28236,13 @@ MA_API void ma_device_uninit(ma_device* pDevice) ...@@ -28136,6 +28236,13 @@ MA_API void ma_device_uninit(ma_device* pDevice)
ma_free(pDevice->playback.pInputCache, &pDevice->pContext->allocationCallbacks); ma_free(pDevice->playback.pInputCache, &pDevice->pContext->allocationCallbacks);
} }
if (pDevice->capture.pIntermediaryBuffer != NULL) {
ma_free(pDevice->capture.pIntermediaryBuffer, &pDevice->pContext->allocationCallbacks);
}
if (pDevice->playback.pIntermediaryBuffer != NULL) {
ma_free(pDevice->playback.pIntermediaryBuffer, &pDevice->pContext->allocationCallbacks);
}
if (pDevice->isOwnerOfContext) { if (pDevice->isOwnerOfContext) {
ma_allocation_callbacks allocationCallbacks = pDevice->pContext->allocationCallbacks; ma_allocation_callbacks allocationCallbacks = pDevice->pContext->allocationCallbacks;
...@@ -28179,9 +28286,9 @@ MA_API ma_result ma_device_get_info(ma_device* pDevice, ma_device_type type, ma_ ...@@ -28179,9 +28286,9 @@ MA_API ma_result ma_device_get_info(ma_device* pDevice, ma_device_type type, ma_
/* Getting here means onDeviceGetInfo is not implemented so we need to fall back to an alternative. */ /* Getting here means onDeviceGetInfo is not implemented so we need to fall back to an alternative. */
if (type == ma_device_type_playback) { if (type == ma_device_type_playback) {
return ma_context_get_device_info(pDevice->pContext, type, &pDevice->playback.id, pDeviceInfo); return ma_context_get_device_info(pDevice->pContext, type, pDevice->playback.pID, pDeviceInfo);
} else { } else {
return ma_context_get_device_info(pDevice->pContext, type, &pDevice->capture.id, pDeviceInfo); return ma_context_get_device_info(pDevice->pContext, type, pDevice->capture.pID, pDeviceInfo);
} }
} }
...@@ -42766,6 +42873,14 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi ...@@ -42766,6 +42873,14 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi
MA_AT_END. To loop back to the start, all we need to do is seek back to the first frame. MA_AT_END. To loop back to the start, all we need to do is seek back to the first frame.
*/ */
if (result == MA_AT_END) { if (result == MA_AT_END) {
/*
The result needs to be reset back to MA_SUCCESS (from MA_AT_END) so that we don't
accidentally return MA_AT_END when data has been read in prior loop iterations. at the
end of this function, the result will be checked for MA_SUCCESS, and if the total
number of frames processed is 0, will be explicitly set to MA_AT_END.
*/
result = MA_SUCCESS;
/* /*
We reached the end. If we're looping, we just loop back to the start of the current We reached the end. If we're looping, we just loop back to the start of the current
data source. If we're not looping we need to check if we have another in the chain, and data source. If we're not looping we need to check if we have another in the chain, and
...@@ -42806,13 +42921,6 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi ...@@ -42806,13 +42921,6 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
break; break;
} }
/*
We need to make sure we clear the MA_AT_END result so we don't accidentally return
it in the event that we coincidentally ended reading at the exact transition point
of two data sources in a chain.
*/
result = MA_SUCCESS;
} }
} }
...@@ -42825,6 +42933,8 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi ...@@ -42825,6 +42933,8 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi
*pFramesRead = totalFramesProcessed; *pFramesRead = totalFramesProcessed;
} }
MA_ASSERT(!(result == MA_AT_END && totalFramesProcessed > 0)); /* We should never be returning MA_AT_END if we read some data. */
if (result == MA_SUCCESS && totalFramesProcessed == 0) { if (result == MA_SUCCESS && totalFramesProcessed == 0) {
result = MA_AT_END; result = MA_AT_END;
} }
...@@ -45606,7 +45716,7 @@ extern "C" { ...@@ -45606,7 +45716,7 @@ extern "C" {
#define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x) #define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x)
#define DRFLAC_VERSION_MAJOR 0 #define DRFLAC_VERSION_MAJOR 0
#define DRFLAC_VERSION_MINOR 12 #define DRFLAC_VERSION_MINOR 12
#define DRFLAC_VERSION_REVISION 33 #define DRFLAC_VERSION_REVISION 34
#define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION) #define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION)
#include <stddef.h> #include <stddef.h>
typedef signed char drflac_int8; typedef signed char drflac_int8;
...@@ -46609,7 +46719,7 @@ static ma_result ma_wav_init_internal(const ma_decoding_backend_config* pConfig, ...@@ -46609,7 +46719,7 @@ static ma_result ma_wav_init_internal(const ma_decoding_backend_config* pConfig,
} }
MA_ZERO_OBJECT(pWav); MA_ZERO_OBJECT(pWav);
pWav->format = ma_format_f32; /* f32 by default. */ pWav->format = ma_format_unknown; /* Use closest match to source file by default. */
if (pConfig != NULL && (pConfig->preferredFormat == ma_format_f32 || pConfig->preferredFormat == ma_format_s16 || pConfig->preferredFormat == ma_format_s32)) { if (pConfig != NULL && (pConfig->preferredFormat == ma_format_f32 || pConfig->preferredFormat == ma_format_s16 || pConfig->preferredFormat == ma_format_s32)) {
pWav->format = pConfig->preferredFormat; pWav->format = pConfig->preferredFormat;
...@@ -46656,6 +46766,42 @@ MA_API ma_result ma_wav_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_p ...@@ -46656,6 +46766,42 @@ MA_API ma_result ma_wav_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_p
return MA_INVALID_FILE; return MA_INVALID_FILE;
} }
/*
If an explicit format was not specified, try picking the closest match based on the internal
format. The format needs to be supported by miniaudio.
*/
if (pWav->format == ma_format_unknown) {
switch (pWav->dr.translatedFormatTag)
{
case DR_WAVE_FORMAT_PCM:
{
if (pWav->dr.bitsPerSample == 8) {
pWav->format = ma_format_u8;
} else if (pWav->dr.bitsPerSample == 16) {
pWav->format = ma_format_s16;
} else if (pWav->dr.bitsPerSample == 24) {
pWav->format = ma_format_s24;
} else if (pWav->dr.bitsPerSample == 32) {
pWav->format = ma_format_s32;
}
} break;
case DR_WAVE_FORMAT_IEEE_FLOAT:
{
if (pWav->dr.bitsPerSample == 32) {
pWav->format = ma_format_f32;
}
} break;
default: break;
}
/* Fall back to f32 if we couldn't find anything. */
if (pWav->format == ma_format_unknown) {
pWav->format = ma_format_f32;
}
}
return MA_SUCCESS; return MA_SUCCESS;
} }
#else #else
...@@ -46824,7 +46970,7 @@ MA_API ma_result ma_wav_read_pcm_frames(ma_wav* pWav, void* pFramesOut, ma_uint6 ...@@ -46824,7 +46970,7 @@ MA_API ma_result ma_wav_read_pcm_frames(ma_wav* pWav, void* pFramesOut, ma_uint6
} break; } break;
/* Fallback to a raw read. */ /* Fallback to a raw read. */
case ma_format_unknown: return MA_INVALID_OPERATION; /* <-- this should never be hit because initialization would just fall back to supported format. */ case ma_format_unknown: return MA_INVALID_OPERATION; /* <-- this should never be hit because initialization would just fall back to a supported format. */
default: default:
{ {
totalFramesRead = drwav_read_pcm_frames(&pWav->dr, frameCount, pFramesOut); totalFramesRead = drwav_read_pcm_frames(&pWav->dr, frameCount, pFramesOut);
...@@ -53934,7 +54080,7 @@ static ma_result ma_resource_manager_data_buffer_init_ex_internal(ma_resource_ma ...@@ -53934,7 +54080,7 @@ static ma_result ma_resource_manager_data_buffer_init_ex_internal(ma_resource_ma
if (pDataBuffer == NULL) { if (pDataBuffer == NULL) {
if (pConfig != NULL && pConfig->pNotifications != NULL) { if (pConfig != NULL && pConfig->pNotifications != NULL) {
ma_resource_manager_pipeline_notifications_signal_all_notifications(&notifications); ma_resource_manager_pipeline_notifications_signal_all_notifications(pConfig->pNotifications);
} }
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
...@@ -54660,7 +54806,7 @@ MA_API ma_result ma_resource_manager_data_stream_init_ex(ma_resource_manager* pR ...@@ -54660,7 +54806,7 @@ MA_API ma_result ma_resource_manager_data_stream_init_ex(ma_resource_manager* pR
if (pDataStream == NULL) { if (pDataStream == NULL) {
if (pConfig != NULL && pConfig->pNotifications != NULL) { if (pConfig != NULL && pConfig->pNotifications != NULL) {
ma_resource_manager_pipeline_notifications_signal_all_notifications(&notifications); ma_resource_manager_pipeline_notifications_signal_all_notifications(pConfig->pNotifications);
} }
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
...@@ -56258,6 +56404,7 @@ MA_API ma_node_graph_config ma_node_graph_config_init(ma_uint32 channels) ...@@ -56258,6 +56404,7 @@ MA_API ma_node_graph_config ma_node_graph_config_init(ma_uint32 channels)
MA_ZERO_OBJECT(&config); MA_ZERO_OBJECT(&config);
config.channels = channels; config.channels = channels;
config.nodeCacheCapInFrames = MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS;
return config; return config;
} }
...@@ -56321,6 +56468,10 @@ MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const m ...@@ -56321,6 +56468,10 @@ MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const m
} }
MA_ZERO_OBJECT(pNodeGraph); MA_ZERO_OBJECT(pNodeGraph);
pNodeGraph->nodeCacheCapInFrames = pConfig->nodeCacheCapInFrames;
if (pNodeGraph->nodeCacheCapInFrames == 0) {
pNodeGraph->nodeCacheCapInFrames = MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS;
}
endpointConfig = ma_node_config_init(); endpointConfig = ma_node_config_init();
endpointConfig.vtable = &g_node_graph_endpoint_vtable; endpointConfig.vtable = &g_node_graph_endpoint_vtable;
...@@ -56775,6 +56926,7 @@ static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_ ...@@ -56775,6 +56926,7 @@ static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_
ma_node_output_bus* pOutputBus; ma_node_output_bus* pOutputBus;
ma_node_output_bus* pFirst; ma_node_output_bus* pFirst;
ma_uint32 inputChannels; ma_uint32 inputChannels;
ma_bool32 doesOutputBufferHaveContent = MA_FALSE;
/* /*
This will be called from the audio thread which means we can't be doing any locking. Basically, This will be called from the audio thread which means we can't be doing any locking. Basically,
...@@ -56815,9 +56967,12 @@ static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_ ...@@ -56815,9 +56967,12 @@ static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_
for (pOutputBus = pFirst; pOutputBus != NULL; pOutputBus = ma_node_input_bus_next(pInputBus, pOutputBus)) { for (pOutputBus = pFirst; pOutputBus != NULL; pOutputBus = ma_node_input_bus_next(pInputBus, pOutputBus)) {
ma_uint32 framesProcessed = 0; ma_uint32 framesProcessed = 0;
ma_bool32 isSilentOutput = MA_FALSE;
MA_ASSERT(pOutputBus->pNode != NULL); MA_ASSERT(pOutputBus->pNode != NULL);
isSilentOutput = (((ma_node_base*)pOutputBus->pNode)->vtable->flags & MA_NODE_FLAG_SILENT_OUTPUT) != 0;
if (pFramesOut != NULL) { if (pFramesOut != NULL) {
/* Read. */ /* Read. */
float temp[MA_DATA_CONVERTER_STACK_BUFFER_SIZE / sizeof(float)]; float temp[MA_DATA_CONVERTER_STACK_BUFFER_SIZE / sizeof(float)];
...@@ -56835,16 +56990,18 @@ static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_ ...@@ -56835,16 +56990,18 @@ static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_
pRunningFramesOut = ma_offset_pcm_frames_ptr_f32(pFramesOut, framesProcessed, inputChannels); pRunningFramesOut = ma_offset_pcm_frames_ptr_f32(pFramesOut, framesProcessed, inputChannels);
if (pOutputBus == pFirst) { if (doesOutputBufferHaveContent == MA_FALSE) {
/* Fast path. First attachment. We just read straight into the output buffer (no mixing required). */ /* Fast path. First attachment. We just read straight into the output buffer (no mixing required). */
result = ma_node_read_pcm_frames(pOutputBus->pNode, pOutputBus->outputBusIndex, pRunningFramesOut, framesToRead, &framesJustRead, globalTime + framesProcessed); result = ma_node_read_pcm_frames(pOutputBus->pNode, pOutputBus->outputBusIndex, pRunningFramesOut, framesToRead, &framesJustRead, globalTime + framesProcessed);
} else { } else {
/* Slow path. Not the first attachment. Mixing required. */ /* Slow path. Not the first attachment. Mixing required. */
result = ma_node_read_pcm_frames(pOutputBus->pNode, pOutputBus->outputBusIndex, temp, framesToRead, &framesJustRead, globalTime + framesProcessed); result = ma_node_read_pcm_frames(pOutputBus->pNode, pOutputBus->outputBusIndex, temp, framesToRead, &framesJustRead, globalTime + framesProcessed);
if (result == MA_SUCCESS || result == MA_AT_END) { if (result == MA_SUCCESS || result == MA_AT_END) {
if (isSilentOutput == MA_FALSE) { /* Don't mix if the node outputs silence. */
ma_mix_pcm_frames_f32(pRunningFramesOut, temp, framesJustRead, inputChannels, /*volume*/1); ma_mix_pcm_frames_f32(pRunningFramesOut, temp, framesJustRead, inputChannels, /*volume*/1);
} }
} }
}
framesProcessed += framesJustRead; framesProcessed += framesJustRead;
...@@ -56863,12 +57020,21 @@ static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_ ...@@ -56863,12 +57020,21 @@ static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_
if (pOutputBus == pFirst && framesProcessed < frameCount) { if (pOutputBus == pFirst && framesProcessed < frameCount) {
ma_silence_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, framesProcessed, ma_format_f32, inputChannels), (frameCount - framesProcessed), ma_format_f32, inputChannels); ma_silence_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, framesProcessed, ma_format_f32, inputChannels), (frameCount - framesProcessed), ma_format_f32, inputChannels);
} }
if (isSilentOutput == MA_FALSE) {
doesOutputBufferHaveContent = MA_TRUE;
}
} else { } else {
/* Seek. */ /* Seek. */
ma_node_read_pcm_frames(pOutputBus->pNode, pOutputBus->outputBusIndex, NULL, frameCount, &framesProcessed, globalTime); ma_node_read_pcm_frames(pOutputBus->pNode, pOutputBus->outputBusIndex, NULL, frameCount, &framesProcessed, globalTime);
} }
} }
/* If we didn't output anything, output silence. */
if (doesOutputBufferHaveContent == MA_FALSE && pFramesOut != NULL) {
ma_silence_pcm_frames(pFramesOut, frameCount, ma_format_f32, inputChannels);
}
/* In this path we always "process" the entire amount. */ /* In this path we always "process" the entire amount. */
*pFramesRead = frameCount; *pFramesRead = frameCount;
...@@ -57002,7 +57168,7 @@ static ma_result ma_node_translate_bus_counts(const ma_node_config* pConfig, ma_ ...@@ -57002,7 +57168,7 @@ static ma_result ma_node_translate_bus_counts(const ma_node_config* pConfig, ma_
return MA_SUCCESS; return MA_SUCCESS;
} }
static ma_result ma_node_get_heap_layout(const ma_node_config* pConfig, ma_node_heap_layout* pHeapLayout) static ma_result ma_node_get_heap_layout(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, ma_node_heap_layout* pHeapLayout)
{ {
ma_result result; ma_result result;
ma_uint32 inputBusCount; ma_uint32 inputBusCount;
...@@ -57063,14 +57229,12 @@ static ma_result ma_node_get_heap_layout(const ma_node_config* pConfig, ma_node_ ...@@ -57063,14 +57229,12 @@ static ma_result ma_node_get_heap_layout(const ma_node_config* pConfig, ma_node_
size_t cachedDataSizeInBytes = 0; size_t cachedDataSizeInBytes = 0;
ma_uint32 iBus; ma_uint32 iBus;
MA_ASSERT(MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS <= 0xFFFF); /* Clamped to 16 bits. */
for (iBus = 0; iBus < inputBusCount; iBus += 1) { for (iBus = 0; iBus < inputBusCount; iBus += 1) {
cachedDataSizeInBytes += MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS * ma_get_bytes_per_frame(ma_format_f32, pConfig->pInputChannels[iBus]); cachedDataSizeInBytes += pNodeGraph->nodeCacheCapInFrames * ma_get_bytes_per_frame(ma_format_f32, pConfig->pInputChannels[iBus]);
} }
for (iBus = 0; iBus < outputBusCount; iBus += 1) { for (iBus = 0; iBus < outputBusCount; iBus += 1) {
cachedDataSizeInBytes += MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS * ma_get_bytes_per_frame(ma_format_f32, pConfig->pOutputChannels[iBus]); cachedDataSizeInBytes += pNodeGraph->nodeCacheCapInFrames * ma_get_bytes_per_frame(ma_format_f32, pConfig->pOutputChannels[iBus]);
} }
pHeapLayout->cachedDataOffset = pHeapLayout->sizeInBytes; pHeapLayout->cachedDataOffset = pHeapLayout->sizeInBytes;
...@@ -57091,7 +57255,7 @@ static ma_result ma_node_get_heap_layout(const ma_node_config* pConfig, ma_node_ ...@@ -57091,7 +57255,7 @@ static ma_result ma_node_get_heap_layout(const ma_node_config* pConfig, ma_node_
return MA_SUCCESS; return MA_SUCCESS;
} }
MA_API ma_result ma_node_get_heap_size(const ma_node_config* pConfig, size_t* pHeapSizeInBytes) MA_API ma_result ma_node_get_heap_size(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, size_t* pHeapSizeInBytes)
{ {
ma_result result; ma_result result;
ma_node_heap_layout heapLayout; ma_node_heap_layout heapLayout;
...@@ -57102,7 +57266,7 @@ MA_API ma_result ma_node_get_heap_size(const ma_node_config* pConfig, size_t* pH ...@@ -57102,7 +57266,7 @@ MA_API ma_result ma_node_get_heap_size(const ma_node_config* pConfig, size_t* pH
*pHeapSizeInBytes = 0; *pHeapSizeInBytes = 0;
result = ma_node_get_heap_layout(pConfig, &heapLayout); result = ma_node_get_heap_layout(pNodeGraph, pConfig, &heapLayout);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
return result; return result;
} }
...@@ -57126,7 +57290,7 @@ MA_API ma_result ma_node_init_preallocated(ma_node_graph* pNodeGraph, const ma_n ...@@ -57126,7 +57290,7 @@ MA_API ma_result ma_node_init_preallocated(ma_node_graph* pNodeGraph, const ma_n
MA_ZERO_OBJECT(pNodeBase); MA_ZERO_OBJECT(pNodeBase);
result = ma_node_get_heap_layout(pConfig, &heapLayout); result = ma_node_get_heap_layout(pNodeGraph, pConfig, &heapLayout);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
return result; return result;
} }
...@@ -57156,7 +57320,7 @@ MA_API ma_result ma_node_init_preallocated(ma_node_graph* pNodeGraph, const ma_n ...@@ -57156,7 +57320,7 @@ MA_API ma_result ma_node_init_preallocated(ma_node_graph* pNodeGraph, const ma_n
if (heapLayout.cachedDataOffset != MA_SIZE_MAX) { if (heapLayout.cachedDataOffset != MA_SIZE_MAX) {
pNodeBase->pCachedData = (float*)ma_offset_ptr(pHeap, heapLayout.cachedDataOffset); pNodeBase->pCachedData = (float*)ma_offset_ptr(pHeap, heapLayout.cachedDataOffset);
pNodeBase->cachedDataCapInFramesPerBus = MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS; pNodeBase->cachedDataCapInFramesPerBus = pNodeGraph->nodeCacheCapInFrames;
} else { } else {
pNodeBase->pCachedData = NULL; pNodeBase->pCachedData = NULL;
} }
...@@ -57211,7 +57375,7 @@ MA_API ma_result ma_node_init(ma_node_graph* pNodeGraph, const ma_node_config* p ...@@ -57211,7 +57375,7 @@ MA_API ma_result ma_node_init(ma_node_graph* pNodeGraph, const ma_node_config* p
size_t heapSizeInBytes; size_t heapSizeInBytes;
void* pHeap; void* pHeap;
result = ma_node_get_heap_size(pConfig, &heapSizeInBytes); result = ma_node_get_heap_size(pNodeGraph, pConfig, &heapSizeInBytes);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
return result; return result;
} }
...@@ -59508,7 +59672,7 @@ static ma_result ma_engine_node_get_heap_layout(const ma_engine_node_config* pCo ...@@ -59508,7 +59672,7 @@ static ma_result ma_engine_node_get_heap_layout(const ma_engine_node_config* pCo
baseNodeConfig.pInputChannels = &channelsIn; baseNodeConfig.pInputChannels = &channelsIn;
baseNodeConfig.pOutputChannels = &channelsOut; baseNodeConfig.pOutputChannels = &channelsOut;
result = ma_node_get_heap_size(&baseNodeConfig, &tempHeapSize); result = ma_node_get_heap_size(ma_engine_get_node_graph(pConfig->pEngine), &baseNodeConfig, &tempHeapSize);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
return result; /* Failed to retrieve the size of the heap for the base node. */ return result; /* Failed to retrieve the size of the heap for the base node. */
} }
...@@ -59913,6 +60077,7 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng ...@@ -59913,6 +60077,7 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng
/* The engine is a node graph. This needs to be initialized after we have the device so we can can determine the channel count. */ /* The engine is a node graph. This needs to be initialized after we have the device so we can can determine the channel count. */
nodeGraphConfig = ma_node_graph_config_init(engineConfig.channels); nodeGraphConfig = ma_node_graph_config_init(engineConfig.channels);
nodeGraphConfig.nodeCacheCapInFrames = (engineConfig.periodSizeInFrames > 0xFFFF) ? 0xFFFF : (ma_uint16)engineConfig.periodSizeInFrames;
result = ma_node_graph_init(&nodeGraphConfig, &pEngine->allocationCallbacks, &pEngine->nodeGraph); result = ma_node_graph_init(&nodeGraphConfig, &pEngine->allocationCallbacks, &pEngine->nodeGraph);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
...@@ -67431,6 +67596,11 @@ static DRFLAC_INLINE drflac_uint32 drflac__be2host_32(drflac_uint32 n) ...@@ -67431,6 +67596,11 @@ static DRFLAC_INLINE drflac_uint32 drflac__be2host_32(drflac_uint32 n)
} }
return n; return n;
} }
static DRFLAC_INLINE drflac_uint32 drflac__be2host_32_ptr_unaligned(const void* pData)
{
const drflac_uint8* pNum = (drflac_uint8*)pData;
return *(pNum) << 24 | *(pNum+1) << 16 | *(pNum+2) << 8 | *(pNum+3);
}
static DRFLAC_INLINE drflac_uint64 drflac__be2host_64(drflac_uint64 n) static DRFLAC_INLINE drflac_uint64 drflac__be2host_64(drflac_uint64 n)
{ {
if (drflac__is_little_endian()) { if (drflac__is_little_endian()) {
...@@ -67445,6 +67615,11 @@ static DRFLAC_INLINE drflac_uint32 drflac__le2host_32(drflac_uint32 n) ...@@ -67445,6 +67615,11 @@ static DRFLAC_INLINE drflac_uint32 drflac__le2host_32(drflac_uint32 n)
} }
return n; return n;
} }
static DRFLAC_INLINE drflac_uint32 drflac__le2host_32_ptr_unaligned(const void* pData)
{
const drflac_uint8* pNum = (drflac_uint8*)pData;
return *pNum | *(pNum+1) << 8 | *(pNum+2) << 16 | *(pNum+3) << 24;
}
static DRFLAC_INLINE drflac_uint32 drflac__unsynchsafe_32(drflac_uint32 n) static DRFLAC_INLINE drflac_uint32 drflac__unsynchsafe_32(drflac_uint32 n)
{ {
drflac_uint32 result = 0; drflac_uint32 result = 0;
...@@ -70856,13 +71031,13 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d ...@@ -70856,13 +71031,13 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
metadata.rawDataSize = blockSize; metadata.rawDataSize = blockSize;
pRunningData = (const char*)pRawData; pRunningData = (const char*)pRawData;
pRunningDataEnd = (const char*)pRawData + blockSize; pRunningDataEnd = (const char*)pRawData + blockSize;
metadata.data.vorbis_comment.vendorLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; metadata.data.vorbis_comment.vendorLength = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
if ((pRunningDataEnd - pRunningData) - 4 < (drflac_int64)metadata.data.vorbis_comment.vendorLength) { if ((pRunningDataEnd - pRunningData) - 4 < (drflac_int64)metadata.data.vorbis_comment.vendorLength) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks); drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE; return DRFLAC_FALSE;
} }
metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength; metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength;
metadata.data.vorbis_comment.commentCount = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; metadata.data.vorbis_comment.commentCount = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
if ((pRunningDataEnd - pRunningData) / sizeof(drflac_uint32) < metadata.data.vorbis_comment.commentCount) { if ((pRunningDataEnd - pRunningData) / sizeof(drflac_uint32) < metadata.data.vorbis_comment.commentCount) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks); drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE; return DRFLAC_FALSE;
...@@ -70874,7 +71049,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d ...@@ -70874,7 +71049,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
drflac__free_from_callbacks(pRawData, pAllocationCallbacks); drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE; return DRFLAC_FALSE;
} }
commentLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; commentLength = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
if (pRunningDataEnd - pRunningData < (drflac_int64)commentLength) { if (pRunningDataEnd - pRunningData < (drflac_int64)commentLength) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks); drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE; return DRFLAC_FALSE;
...@@ -70958,24 +71133,24 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d ...@@ -70958,24 +71133,24 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
metadata.rawDataSize = blockSize; metadata.rawDataSize = blockSize;
pRunningData = (const char*)pRawData; pRunningData = (const char*)pRawData;
pRunningDataEnd = (const char*)pRawData + blockSize; pRunningDataEnd = (const char*)pRawData + blockSize;
metadata.data.picture.type = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; metadata.data.picture.type = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
metadata.data.picture.mimeLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; metadata.data.picture.mimeLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
if ((pRunningDataEnd - pRunningData) - 24 < (drflac_int64)metadata.data.picture.mimeLength) { if ((pRunningDataEnd - pRunningData) - 24 < (drflac_int64)metadata.data.picture.mimeLength) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks); drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE; return DRFLAC_FALSE;
} }
metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength; metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength;
metadata.data.picture.descriptionLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; metadata.data.picture.descriptionLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
if ((pRunningDataEnd - pRunningData) - 20 < (drflac_int64)metadata.data.picture.descriptionLength) { if ((pRunningDataEnd - pRunningData) - 20 < (drflac_int64)metadata.data.picture.descriptionLength) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks); drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE; return DRFLAC_FALSE;
} }
metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength; metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength;
metadata.data.picture.width = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; metadata.data.picture.width = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
metadata.data.picture.height = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; metadata.data.picture.height = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
metadata.data.picture.colorDepth = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; metadata.data.picture.colorDepth = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
metadata.data.picture.indexColorCount = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; metadata.data.picture.indexColorCount = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
metadata.data.picture.pictureDataSize = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; metadata.data.picture.pictureDataSize = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
metadata.data.picture.pPictureData = (const drflac_uint8*)pRunningData; metadata.data.picture.pPictureData = (const drflac_uint8*)pRunningData;
if (pRunningDataEnd - pRunningData < (drflac_int64)metadata.data.picture.pictureDataSize) { if (pRunningDataEnd - pRunningData < (drflac_int64)metadata.data.picture.pictureDataSize) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks); drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
...@@ -75096,7 +75271,7 @@ DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator ...@@ -75096,7 +75271,7 @@ DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator
if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) { if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) {
return NULL; return NULL;
} }
length = drflac__le2host_32(*(const drflac_uint32*)pIter->pRunningData); length = drflac__le2host_32_ptr_unaligned(pIter->pRunningData);
pIter->pRunningData += 4; pIter->pRunningData += 4;
pComment = pIter->pRunningData; pComment = pIter->pRunningData;
pIter->pRunningData += length; pIter->pRunningData += length;
/* /*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.11.2 - 2021-12-31 miniaudio - v0.11.3 - 2022-01-07
David Reid - mackron@gmail.com David Reid - mackron@gmail.com
...@@ -20,7 +20,7 @@ extern "C" { ...@@ -20,7 +20,7 @@ extern "C" {
#define MA_VERSION_MAJOR 0 #define MA_VERSION_MAJOR 0
#define MA_VERSION_MINOR 11 #define MA_VERSION_MINOR 11
#define MA_VERSION_REVISION 2 #define MA_VERSION_REVISION 3
#define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION) #define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION)
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER) && !defined(__clang__)
...@@ -223,31 +223,33 @@ typedef ma_uint16 wchar_t; ...@@ -223,31 +223,33 @@ typedef ma_uint16 wchar_t;
Logging Levels Logging Levels
============== ==============
Log levels are only used to give logging callbacks some context as to the severity of a log message Log levels are only used to give logging callbacks some context as to the severity of a log message
so they can do filtering. All log levels will be posted to registered logging callbacks, except for so they can do filtering. All log levels will be posted to registered logging callbacks. If you
MA_LOG_LEVEL_DEBUG which will only get processed if MA_DEBUG_OUTPUT is enabled. don't want to output a certain log level you can discriminate against the log level in the callback.
MA_LOG_LEVEL_DEBUG MA_LOG_LEVEL_DEBUG
Used for debugging. These log messages are only posted when `MA_DEBUG_OUTPUT` is enabled. Used for debugging. Useful for debug and test builds, but should be disabled in release builds.
MA_LOG_LEVEL_INFO MA_LOG_LEVEL_INFO
Informational logging. Useful for debugging. This will also enable warning and error logs. This Informational logging. Useful for debugging. This will never be called from within the data
will never be called from within the data callback. callback.
MA_LOG_LEVEL_WARNING MA_LOG_LEVEL_WARNING
Warnings. You should enable this in you development builds and action them when encounted. This Warnings. You should enable this in you development builds and action them when encounted. These
will also enable error logs. These logs usually indicate a potential problem or logs usually indicate a potential problem or misconfiguration, but still allow you to keep
misconfiguration, but still allow you to keep running. This will never be called from within running. This will never be called from within the data callback.
the data callback.
MA_LOG_LEVEL_ERROR MA_LOG_LEVEL_ERROR
Error logging. This will be fired when an operation fails and is subsequently aborted. This can Error logging. This will be fired when an operation fails and is subsequently aborted. This can
be fired from within the data callback, in which case the device will be stopped. You should be fired from within the data callback, in which case the device will be stopped. You should
always have this log level enabled. always have this log level enabled.
*/ */
#define MA_LOG_LEVEL_DEBUG 4 typedef enum
#define MA_LOG_LEVEL_INFO 3 {
#define MA_LOG_LEVEL_WARNING 2 MA_LOG_LEVEL_DEBUG = 4,
#define MA_LOG_LEVEL_ERROR 1 MA_LOG_LEVEL_INFO = 3,
MA_LOG_LEVEL_WARNING = 2,
MA_LOG_LEVEL_ERROR = 1
} ma_log_level;
/* /*
Variables needing to be accessed atomically should be declared with this macro for two reasons: Variables needing to be accessed atomically should be declared with this macro for two reasons:
...@@ -2476,6 +2478,7 @@ struct ma_device_config ...@@ -2476,6 +2478,7 @@ struct ma_device_config
ma_bool8 noPreSilencedOutputBuffer; /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to silence. */ ma_bool8 noPreSilencedOutputBuffer; /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to silence. */
ma_bool8 noClip; /* When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. Only applies when the playback sample format is f32. */ ma_bool8 noClip; /* When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. Only applies when the playback sample format is f32. */
ma_bool8 noDisableDenormals; /* Do not disable denormals when firing the data callback. */ ma_bool8 noDisableDenormals; /* Do not disable denormals when firing the data callback. */
ma_bool8 noFixedSizedCallback; /* Disables strict fixed-sized data callbacks. Setting this to true will result in the period size being treated only as a hint to the backend. This is an optimization for those who don't need fixed sized callbacks. */
ma_device_data_proc dataCallback; ma_device_data_proc dataCallback;
ma_device_notification_proc notificationCallback; ma_device_notification_proc notificationCallback;
ma_stop_proc stopCallback; ma_stop_proc stopCallback;
...@@ -3151,6 +3154,7 @@ struct ma_device ...@@ -3151,6 +3154,7 @@ struct ma_device
ma_bool8 noPreSilencedOutputBuffer; ma_bool8 noPreSilencedOutputBuffer;
ma_bool8 noClip; ma_bool8 noClip;
ma_bool8 noDisableDenormals; ma_bool8 noDisableDenormals;
ma_bool8 noFixedSizedCallback;
MA_ATOMIC(4, float) masterVolumeFactor; /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */ MA_ATOMIC(4, float) masterVolumeFactor; /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */
ma_duplex_rb duplexRB; /* Intermediary buffer for duplex device on asynchronous backends. */ ma_duplex_rb duplexRB; /* Intermediary buffer for duplex device on asynchronous backends. */
struct struct
...@@ -3165,6 +3169,7 @@ struct ma_device ...@@ -3165,6 +3169,7 @@ struct ma_device
} resampling; } resampling;
struct struct
{ {
ma_device_id* pID; /* Set to NULL if using default ID, otherwise set to the address of "id". */
ma_device_id id; /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */ ma_device_id id; /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */
char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; /* Maybe temporary. Likely to be replaced with a query API. */ char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; /* Maybe temporary. Likely to be replaced with a query API. */
ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */ ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */
...@@ -3179,6 +3184,9 @@ struct ma_device ...@@ -3179,6 +3184,9 @@ struct ma_device
ma_uint32 internalPeriods; ma_uint32 internalPeriods;
ma_channel_mix_mode channelMixMode; ma_channel_mix_mode channelMixMode;
ma_data_converter converter; ma_data_converter converter;
void* pIntermediaryBuffer; /* For implementing fixed sized buffer callbacks. Will be null if using variable sized callbacks. */
ma_uint32 intermediaryBufferCap;
ma_uint32 intermediaryBufferLen; /* How many valid frames are sitting in the intermediary buffer. */
void* pInputCache; /* In external format. Can be null. */ void* pInputCache; /* In external format. Can be null. */
ma_uint64 inputCacheCap; ma_uint64 inputCacheCap;
ma_uint64 inputCacheConsumed; ma_uint64 inputCacheConsumed;
...@@ -3186,6 +3194,7 @@ struct ma_device ...@@ -3186,6 +3194,7 @@ struct ma_device
} playback; } playback;
struct struct
{ {
ma_device_id* pID; /* Set to NULL if using default ID, otherwise set to the address of "id". */
ma_device_id id; /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */ ma_device_id id; /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */
char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; /* Maybe temporary. Likely to be replaced with a query API. */ char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; /* Maybe temporary. Likely to be replaced with a query API. */
ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */ ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */
...@@ -3200,6 +3209,9 @@ struct ma_device ...@@ -3200,6 +3209,9 @@ struct ma_device
ma_uint32 internalPeriods; ma_uint32 internalPeriods;
ma_channel_mix_mode channelMixMode; ma_channel_mix_mode channelMixMode;
ma_data_converter converter; ma_data_converter converter;
void* pIntermediaryBuffer; /* For implementing fixed sized buffer callbacks. Will be null if using variable sized callbacks. */
ma_uint32 intermediaryBufferCap;
ma_uint32 intermediaryBufferLen; /* How many valid frames are sitting in the intermediary buffer. */
} capture; } capture;
union union
...@@ -4028,6 +4040,11 @@ then be set directly on the structure. Below are the members of the `ma_device_c ...@@ -4028,6 +4040,11 @@ then be set directly on the structure. Below are the members of the `ma_device_c
noDisableDenormals noDisableDenormals
By default, miniaudio will disable denormals when the data callback is called. Setting this to true will prevent the disabling of denormals. By default, miniaudio will disable denormals when the data callback is called. Setting this to true will prevent the disabling of denormals.
noFixedSizedCallback
Allows miniaudio to fire the data callback with any frame count. When this is set to true, the data callback will be fired with a consistent frame
count as specified by `periodSizeInFrames` or `periodSizeInMilliseconds`. When set to false, miniaudio will fire the callback with whatever the
backend requests, which could be anything.
dataCallback dataCallback
The callback to fire whenever data is ready to be delivered to or from the device. The callback to fire whenever data is ready to be delivered to or from the device.
...@@ -6359,7 +6376,8 @@ typedef enum ...@@ -6359,7 +6376,8 @@ typedef enum
MA_NODE_FLAG_PASSTHROUGH = 0x00000001, MA_NODE_FLAG_PASSTHROUGH = 0x00000001,
MA_NODE_FLAG_CONTINUOUS_PROCESSING = 0x00000002, MA_NODE_FLAG_CONTINUOUS_PROCESSING = 0x00000002,
MA_NODE_FLAG_ALLOW_NULL_INPUT = 0x00000004, MA_NODE_FLAG_ALLOW_NULL_INPUT = 0x00000004,
MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES = 0x00000008 MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES = 0x00000008,
MA_NODE_FLAG_SILENT_OUTPUT = 0x00000010
} ma_node_flags; } ma_node_flags;
...@@ -6498,7 +6516,7 @@ struct ma_node_base ...@@ -6498,7 +6516,7 @@ struct ma_node_base
ma_bool32 _ownsHeap; /* If set to true, the node owns the heap allocation and _pHeap will be freed in ma_node_uninit(). */ ma_bool32 _ownsHeap; /* If set to true, the node owns the heap allocation and _pHeap will be freed in ma_node_uninit(). */
}; };
MA_API ma_result ma_node_get_heap_size(const ma_node_config* pConfig, size_t* pHeapSizeInBytes); MA_API ma_result ma_node_get_heap_size(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, size_t* pHeapSizeInBytes);
MA_API ma_result ma_node_init_preallocated(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, void* pHeap, ma_node* pNode); MA_API ma_result ma_node_init_preallocated(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, void* pHeap, ma_node* pNode);
MA_API ma_result ma_node_init(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node* pNode); MA_API ma_result ma_node_init(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node* pNode);
MA_API void ma_node_uninit(ma_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); MA_API void ma_node_uninit(ma_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks);
...@@ -6525,6 +6543,7 @@ MA_API ma_result ma_node_set_time(ma_node* pNode, ma_uint64 localTime); ...@@ -6525,6 +6543,7 @@ MA_API ma_result ma_node_set_time(ma_node* pNode, ma_uint64 localTime);
typedef struct typedef struct
{ {
ma_uint32 channels; ma_uint32 channels;
ma_uint16 nodeCacheCapInFrames;
} ma_node_graph_config; } ma_node_graph_config;
MA_API ma_node_graph_config ma_node_graph_config_init(ma_uint32 channels); MA_API ma_node_graph_config ma_node_graph_config_init(ma_uint32 channels);
...@@ -6534,6 +6553,7 @@ struct ma_node_graph ...@@ -6534,6 +6553,7 @@ struct ma_node_graph
{ {
/* Immutable. */ /* Immutable. */
ma_node_base endpoint; /* Special node that all nodes eventually connect to. Data is read from this node in ma_node_graph_read_pcm_frames(). */ ma_node_base endpoint; /* Special node that all nodes eventually connect to. Data is read from this node in ma_node_graph_read_pcm_frames(). */
ma_uint16 nodeCacheCapInFrames;
/* Read and written by multiple threads. */ /* Read and written by multiple threads. */
MA_ATOMIC(4, ma_bool32) isReading; MA_ATOMIC(4, ma_bool32) isReading;
......
/* /*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.11.3 - TBD miniaudio - v0.11.3 - 2022-01-07
David Reid - mackron@gmail.com David Reid - mackron@gmail.com
...@@ -89538,7 +89538,7 @@ There have also been some other smaller changes added to this release. ...@@ -89538,7 +89538,7 @@ There have also been some other smaller changes added to this release.
/* /*
REVISION HISTORY REVISION HISTORY
================ ================
v0.11.3 - TBD v0.11.3 - 2022-01-07
- Add a new flag for nodes called MA_NODE_FLAG_SILENT_OUTPUT which tells miniaudio that the - Add a new flag for nodes called MA_NODE_FLAG_SILENT_OUTPUT which tells miniaudio that the
output of the node should always be treated as silence. This gives miniaudio an optimization output of the node should always be treated as silence. This gives miniaudio an optimization
opportunity by skipping mixing of those nodes. Useful for special nodes that need to have opportunity by skipping mixing of those nodes. Useful for special nodes that need to have
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment