diff --git a/miniaudio.h b/miniaudio.h index 540d8330..ca05a50c 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -6270,6 +6270,29 @@ MA_API ma_uint32 ma_ring_buffer_length(const ma_ring_buffer* pRingBuffer); MA_API ma_uint32 ma_ring_buffer_capacity(const ma_ring_buffer* pRingBuffer); /* END ma_ring_buffer.h */ + +typedef struct ma_audio_ring_buffer +{ + ma_data_source_base ds; + ma_ring_buffer rb; + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; /* Not required for the ring buffer itself, but useful for associating the data with some sample rate, particularly for data sources. */ + void* pBuffer; + ma_allocation_callbacks allocationCallbacks; +} ma_audio_ring_buffer; + +MA_API ma_result ma_audio_ring_buffer_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 capacityInFrames, const ma_allocation_callbacks* pAllocationCallbacks, ma_audio_ring_buffer* pRingBuffer); +MA_API void ma_audio_ring_buffer_uninit(ma_audio_ring_buffer* pRingBuffer); +MA_API ma_uint64 ma_audio_ring_buffer_map_produce(ma_audio_ring_buffer* pRingBuffer, ma_uint64 frameCount, void** ppMappedBuffer); /* Returns the number of frames actually mapped. */ +MA_API void ma_audio_ring_buffer_unmap_produce(ma_audio_ring_buffer* pRingBuffer, ma_uint64 frameCount); +MA_API ma_uint64 ma_audio_ring_buffer_map_consume(ma_audio_ring_buffer* pRingBuffer, ma_uint64 frameCount, void** ppMappedBuffer); /* Returns the number of frames actually mapped. */ +MA_API void ma_audio_ring_buffer_unmap_consume(ma_audio_ring_buffer* pRingBuffer, ma_uint64 frameCount); +MA_API ma_result ma_audio_ring_buffer_write_pcm_frames(ma_audio_ring_buffer* pRingBuffer, const void* pFrames, ma_uint64 frameCount, ma_uint64* pFramesWritten); +MA_API ma_result ma_audio_ring_buffer_read_pcm_frames(ma_audio_ring_buffer* pRingBuffer, void* pFrames, ma_uint64 frameCount, ma_uint64* pFramesRead); +MA_API ma_result ma_audio_ring_buffer_get_length_in_pcm_frames(ma_audio_ring_buffer* pRingBuffer, ma_uint64* pLength); + + typedef struct { void* pBuffer; @@ -6346,7 +6369,7 @@ in frames. The internal sample rate of the capture device is also needed in orde */ typedef struct { - ma_pcm_rb rb; + ma_audio_ring_buffer rb; } ma_duplex_rb; MA_API ma_result ma_duplex_rb_init(ma_format captureFormat, ma_uint32 captureChannels, ma_uint32 sampleRate, ma_uint32 captureInternalSampleRate, ma_uint32 captureInternalPeriodSizeInFrames, const ma_allocation_callbacks* pAllocationCallbacks, ma_duplex_rb* pRB); @@ -20750,7 +20773,7 @@ static void ma_device__send_frames_to_client(ma_device* pDevice, ma_uint32 frame } } -static ma_result ma_device__handle_duplex_callback_capture(ma_device* pDevice, ma_uint32 frameCountInDeviceFormat, const void* pFramesInDeviceFormat, ma_pcm_rb* pRB) +static ma_result ma_device__handle_duplex_callback_capture(ma_device* pDevice, ma_uint32 frameCountInDeviceFormat, const void* pFramesInDeviceFormat, ma_audio_ring_buffer* pRB) { ma_result result; ma_uint32 totalDeviceFramesProcessed = 0; @@ -20763,22 +20786,15 @@ static ma_result ma_device__handle_duplex_callback_capture(ma_device* pDevice, m /* Write to the ring buffer. The ring buffer is in the client format which means we need to convert. */ for (;;) { - ma_uint32 framesToProcessInDeviceFormat = (frameCountInDeviceFormat - totalDeviceFramesProcessed); - ma_uint32 framesToProcessInClientFormat = MA_DATA_CONVERTER_STACK_BUFFER_SIZE / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); + ma_uint64 framesToProcessInDeviceFormat = (frameCountInDeviceFormat - totalDeviceFramesProcessed); + ma_uint64 framesToProcessInClientFormat = MA_DATA_CONVERTER_STACK_BUFFER_SIZE / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); ma_uint64 framesProcessedInDeviceFormat; ma_uint64 framesProcessedInClientFormat; void* pFramesInClientFormat; - result = ma_pcm_rb_acquire_write(pRB, &framesToProcessInClientFormat, &pFramesInClientFormat); - if (result != MA_SUCCESS) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "Failed to acquire capture PCM frames from ring buffer."); - break; - } - + framesToProcessInClientFormat = ma_audio_ring_buffer_map_produce(pRB, framesToProcessInClientFormat, &pFramesInClientFormat); if (framesToProcessInClientFormat == 0) { - if (ma_pcm_rb_pointer_distance(pRB) == (ma_int32)ma_pcm_rb_get_subbuffer_size(pRB)) { - break; /* Overrun. Not enough room in the ring buffer for input frame. Excess frames are dropped. */ - } + break; /* Overrun. Not enough room in the ring buffer for input frame. Excess frames are dropped. */ } /* Convert. */ @@ -20789,11 +20805,7 @@ static ma_result ma_device__handle_duplex_callback_capture(ma_device* pDevice, m break; } - result = ma_pcm_rb_commit_write(pRB, (ma_uint32)framesProcessedInClientFormat); /* Safe cast. */ - if (result != MA_SUCCESS) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "Failed to commit capture PCM frames to ring buffer."); - break; - } + ma_audio_ring_buffer_unmap_produce(pRB, framesProcessedInClientFormat); pRunningFramesInDeviceFormat = ma_offset_ptr(pRunningFramesInDeviceFormat, framesProcessedInDeviceFormat * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels)); totalDeviceFramesProcessed += (ma_uint32)framesProcessedInDeviceFormat; /* Safe cast. */ @@ -20807,9 +20819,8 @@ static ma_result ma_device__handle_duplex_callback_capture(ma_device* pDevice, m return MA_SUCCESS; } -static ma_result ma_device__handle_duplex_callback_playback(ma_device* pDevice, ma_uint32 frameCount, void* pFramesInInternalFormat, ma_pcm_rb* pRB) +static ma_result ma_device__handle_duplex_callback_playback(ma_device* pDevice, ma_uint32 frameCount, void* pFramesInInternalFormat, ma_audio_ring_buffer* pRB) { - ma_result result; ma_uint8 silentInputFrames[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; ma_uint32 totalFramesReadOut = 0; @@ -20838,38 +20849,29 @@ static ma_result ma_device__handle_duplex_callback_playback(ma_device* pDevice, pDevice->playback.inputCacheConsumed += framesConvertedIn; pDevice->playback.inputCacheRemaining -= framesConvertedIn; - totalFramesReadOut += (ma_uint32)framesConvertedOut; /* Safe cast. */ - pFramesInInternalFormat = ma_offset_ptr(pFramesInInternalFormat, framesConvertedOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); + totalFramesReadOut += (ma_uint32)framesConvertedOut; /* Safe cast. */ + pFramesInInternalFormat = ma_offset_ptr(pFramesInInternalFormat, framesConvertedOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); } /* If there's no more data in the cache we'll need to fill it with some. */ if (totalFramesReadOut < frameCount && pDevice->playback.inputCacheRemaining == 0) { - ma_uint32 inputFrameCount; + ma_uint64 inputFrameCount; void* pInputFrames; - inputFrameCount = (ma_uint32)pDevice->playback.inputCacheCap; - result = ma_pcm_rb_acquire_read(pRB, &inputFrameCount, &pInputFrames); - if (result == MA_SUCCESS) { - if (inputFrameCount > 0) { - ma_device__handle_data_callback(pDevice, pDevice->playback.pInputCache, pInputFrames, inputFrameCount); - } else { - if (ma_pcm_rb_pointer_distance(pRB) == 0) { - break; /* Underrun. */ - } - } + inputFrameCount = pDevice->playback.inputCacheCap; + inputFrameCount = ma_audio_ring_buffer_map_consume(pRB, inputFrameCount, &pInputFrames); + if (inputFrameCount > 0) { + ma_device__handle_data_callback(pDevice, pDevice->playback.pInputCache, pInputFrames, inputFrameCount); + ma_audio_ring_buffer_unmap_consume(pRB, inputFrameCount); } else { - /* No capture data available. Feed in silence. */ + /* Underrun. 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)); ma_device__handle_data_callback(pDevice, pDevice->playback.pInputCache, silentInputFrames, inputFrameCount); + ma_audio_ring_buffer_unmap_consume(pRB, 0); /* <-- Don't *actually* have to unmap this since it's a count of zero, but it makes me feel better having it be properly paired. */ } pDevice->playback.inputCacheConsumed = 0; pDevice->playback.inputCacheRemaining = inputFrameCount; - - result = ma_pcm_rb_commit_read(pRB, inputFrameCount); - if (result != MA_SUCCESS) { - return result; /* Should never happen. */ - } } } @@ -63661,6 +63663,222 @@ MA_API ma_uint32 ma_ring_buffer_capacity(const ma_ring_buffer* pRingBuffer) /* END ma_ring_buffer.c */ +static ma_result ma_audio_ring_buffer__data_source_on_read(ma_data_source* pDataSource, void* pFrames, ma_uint64 frameCount, ma_uint64* pFramesRead) +{ + return ma_audio_ring_buffer_read_pcm_frames((ma_audio_ring_buffer*)pDataSource, pFrames, frameCount, pFramesRead); +} + +static ma_result ma_audio_ring_buffer__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +{ + ma_audio_ring_buffer* pAudioQueue = (ma_audio_ring_buffer*)pDataSource; + + *pFormat = pAudioQueue->format; + *pChannels = pAudioQueue->channels; + *pSampleRate = pAudioQueue->sampleRate; + ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pAudioQueue->channels); + + return MA_SUCCESS; +} + +static ma_result ma_audio_ring_buffer__data_source_on_get_length(ma_data_source* pDataSource, ma_uint64* pLength) +{ + return ma_audio_ring_buffer_get_length_in_pcm_frames((ma_audio_ring_buffer*)pDataSource, pLength); +} + +static ma_data_source_vtable ma_gDataSourceVTable_AudioRingBuffer = +{ + ma_audio_ring_buffer__data_source_on_read, + NULL, /* No seeking in ring buffers. */ + ma_audio_ring_buffer__data_source_on_get_data_format, + NULL, /* No notion of a cursor. */ + ma_audio_ring_buffer__data_source_on_get_length, + NULL, /* onSetLooping */ + 0 +}; + + +MA_API ma_result ma_audio_ring_buffer_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 capacityInFrames, const ma_allocation_callbacks* pAllocationCallbacks, ma_audio_ring_buffer* pRingBuffer) +{ + ma_result result; + ma_data_source_config dataSourceConfig; + ma_uint32 bpf; + void* pBuffer; + + if (pRingBuffer == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pRingBuffer); + + if (capacityInFrames == 0) { + return MA_INVALID_ARGS; + } + + bpf = ma_get_bytes_per_frame(format, channels); + if (bpf == 0) { + return MA_INVALID_ARGS; + } + + pBuffer = ma_malloc(capacityInFrames * bpf * 2, pAllocationCallbacks); + if (pBuffer == NULL) { + return MA_OUT_OF_MEMORY; + } + + /* Initialize the data source. */ + dataSourceConfig = ma_data_source_config_init(); + dataSourceConfig.vtable = &ma_gDataSourceVTable_AudioRingBuffer; + + result = ma_data_source_init(&dataSourceConfig, &pRingBuffer->ds); + if (result != MA_SUCCESS) { + ma_free(pBuffer, pAllocationCallbacks); + return result; + } + + /* Now for the ring buffer. */ + ma_ring_buffer_init(capacityInFrames, bpf, 0, pBuffer, &pRingBuffer->rb); + pRingBuffer->format = format; + pRingBuffer->channels = channels; + pRingBuffer->sampleRate = sampleRate; + pRingBuffer->pBuffer = pBuffer; + ma_allocation_callbacks_init_copy(&pRingBuffer->allocationCallbacks, pAllocationCallbacks); + + return MA_SUCCESS; +} + +MA_API void ma_audio_ring_buffer_uninit(ma_audio_ring_buffer* pRingBuffer) +{ + if (pRingBuffer == NULL) { + return; + } + + ma_free(pRingBuffer->pBuffer, &pRingBuffer->allocationCallbacks); + ma_data_source_uninit(&pRingBuffer->ds); +} + +MA_API ma_uint64 ma_audio_ring_buffer_map_produce(ma_audio_ring_buffer* pRingBuffer, ma_uint64 frameCount, void** ppMappedBuffer) +{ + if (pRingBuffer == NULL) { + return 0; + } + + /* We're not going to write more than 32-bits worth of frames at a time. */ + if (frameCount > 0xFFFFFFFF) { + frameCount = 0xFFFFFFFF; + } + + return (ma_uint64)ma_ring_buffer_map_produce(&pRingBuffer->rb, (size_t)frameCount, ppMappedBuffer); +} + +MA_API void ma_audio_ring_buffer_unmap_produce(ma_audio_ring_buffer* pRingBuffer, ma_uint64 frameCount) +{ + if (pRingBuffer == NULL) { + return; + } + + ma_ring_buffer_unmap_produce(&pRingBuffer->rb, (size_t)frameCount); +} + +MA_API ma_uint64 ma_audio_ring_buffer_map_consume(ma_audio_ring_buffer* pRingBuffer, ma_uint64 frameCount, void** ppMappedBuffer) +{ + if (pRingBuffer == NULL) { + return 0; + } + + /* We're not going to write more than 32-bits worth of frames at a time. */ + if (frameCount > 0xFFFFFFFF) { + frameCount = 0xFFFFFFFF; + } + + return (ma_uint64)ma_ring_buffer_map_consume(&pRingBuffer->rb, (size_t)frameCount, ppMappedBuffer); +} + +MA_API void ma_audio_ring_buffer_unmap_consume(ma_audio_ring_buffer* pRingBuffer, ma_uint64 frameCount) +{ + if (pRingBuffer == NULL) { + return; + } + + ma_ring_buffer_unmap_consume(&pRingBuffer->rb, (size_t)frameCount); +} + +MA_API ma_result ma_audio_ring_buffer_write_pcm_frames(ma_audio_ring_buffer* pRingBuffer, const void* pFrames, ma_uint64 frameCount, ma_uint64* pFramesWritten) +{ + void* pMappedBuffer; + + if (pFramesWritten != NULL) { + *pFramesWritten = 0; + } + + if (pRingBuffer == NULL) { + return MA_INVALID_ARGS; + } + + frameCount = ma_ring_buffer_map_produce(&pRingBuffer->rb, frameCount, &pMappedBuffer); + { + size_t bytesToCopy = (size_t)(frameCount * ma_get_bytes_per_frame(pRingBuffer->format, pRingBuffer->channels)); + + if (pFrames != NULL) { + MA_COPY_MEMORY(pMappedBuffer, pFrames, bytesToCopy); + } else { + MA_ZERO_MEMORY(pMappedBuffer, bytesToCopy); + } + } + ma_ring_buffer_unmap_produce(&pRingBuffer->rb, frameCount); + + if (pFramesWritten != NULL) { + *pFramesWritten = frameCount; + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_audio_ring_buffer_read_pcm_frames(ma_audio_ring_buffer* pRingBuffer, void* pFrames, ma_uint64 frameCount, ma_uint64* pFramesRead) +{ + void* pMappedBuffer; + + if (pFramesRead != NULL) { + *pFramesRead = 0; + } + + if (pRingBuffer == NULL) { + return MA_INVALID_ARGS; + } + + frameCount = ma_ring_buffer_map_consume(&pRingBuffer->rb, frameCount, &pMappedBuffer); + { + size_t bytesToCopy = (size_t)(frameCount * ma_get_bytes_per_frame(pRingBuffer->format, pRingBuffer->channels)); + + if (pFrames != NULL) { + MA_COPY_MEMORY(pFrames, pMappedBuffer, bytesToCopy); + } + } + ma_ring_buffer_unmap_consume(&pRingBuffer->rb, frameCount); + + if (pFramesRead != NULL) { + *pFramesRead = frameCount; + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_audio_ring_buffer_get_length_in_pcm_frames(ma_audio_ring_buffer* pRingBuffer, ma_uint64* pLength) +{ + if (pLength == NULL) { + return MA_INVALID_ARGS; + } + + *pLength = 0; + + if (pRingBuffer == NULL) { + return MA_INVALID_ARGS; + } + + *pLength = ma_ring_buffer_length(&pRingBuffer->rb); + + return MA_SUCCESS; +} + + static MA_INLINE ma_uint32 ma_rb__extract_offset_in_bytes(ma_uint32 encodedOffset) @@ -64460,25 +64678,25 @@ MA_API ma_result ma_duplex_rb_init(ma_format captureFormat, ma_uint32 captureCha ma_result result; ma_uint32 sizeInFrames; - sizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(sampleRate, captureInternalSampleRate, captureInternalPeriodSizeInFrames * 5); + sizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(sampleRate, captureInternalSampleRate, captureInternalPeriodSizeInFrames * 3); if (sizeInFrames == 0) { return MA_INVALID_ARGS; } - result = ma_pcm_rb_init(captureFormat, captureChannels, sizeInFrames, NULL, pAllocationCallbacks, &pRB->rb); + result = ma_audio_ring_buffer_init(captureFormat, captureChannels, sampleRate, sizeInFrames, pAllocationCallbacks, &pRB->rb); if (result != MA_SUCCESS) { return result; } /* Seek forward a bit so we have a bit of a buffer in case of desyncs. */ - ma_pcm_rb_seek_write((ma_pcm_rb*)pRB, captureInternalPeriodSizeInFrames * 2); + ma_audio_ring_buffer_write_pcm_frames(&pRB->rb, NULL, captureInternalPeriodSizeInFrames * 2, NULL); return MA_SUCCESS; } MA_API ma_result ma_duplex_rb_uninit(ma_duplex_rb* pRB) { - ma_pcm_rb_uninit((ma_pcm_rb*)pRB); + ma_audio_ring_buffer_uninit(&pRB->rb); return MA_SUCCESS; } @@ -66551,6 +66769,7 @@ MA_API void ma_audio_queue_uninit(ma_audio_queue* pAudioQueue) } ma_free(pAudioQueue->pBuffer, &pAudioQueue->allocationCallbacks); + ma_data_source_uninit(&pAudioQueue->ds); } static void ma_audio_queue_write_pcm_frames_nolock(ma_audio_queue* pAudioQueue, const void* pFrames, ma_uint64 frameCount, ma_uint32 bpf)