Commit 9efc8507 authored by David Reid's avatar David Reid

Improve support for asynchronous decoding of sounds of unknown length.

parent 63955a65
...@@ -48,6 +48,69 @@ useful to be told exactly what it being allocated so you can optimize your alloc ...@@ -48,6 +48,69 @@ useful to be told exactly what it being allocated so you can optimize your alloc
#define MA_ALLOCATION_TYPE_RESOURCE_MANAGER_DATA_STREAM 0x00000012 /* A ma_resource_manager_data_stream object. */ #define MA_ALLOCATION_TYPE_RESOURCE_MANAGER_DATA_STREAM 0x00000012 /* A ma_resource_manager_data_stream object. */
#define MA_ALLOCATION_TYPE_RESOURCE_MANAGER_DATA_SOURCE 0x00000013 /* A ma_resource_manager_data_source object. */ #define MA_ALLOCATION_TYPE_RESOURCE_MANAGER_DATA_SOURCE 0x00000013 /* A ma_resource_manager_data_source object. */
/*
Paged Audio Buffer
==================
A paged audio buffer is made up of a linked list of pages. It's expandable, but not shrinkable. It
can be used for cases where audio data is streamed in asynchronously while allowing data to be read
at the same time.
This is lock-free, but not 100% thread safe. You can append a page and read from the buffer across
simultaneously across different threads, however only one thread at a time can append, and only one
thread at a time can read and seek.
*/
typedef struct ma_paged_audio_buffer_page ma_paged_audio_buffer_page;
struct ma_paged_audio_buffer_page
{
MA_ATOMIC ma_paged_audio_buffer_page* pNext;
ma_uint32 sizeInFrames;
ma_uint8 pAudioData[1];
};
typedef struct
{
ma_format format;
ma_uint32 channels;
ma_paged_audio_buffer_page head; /* Dummy head for the lock-free algorithm. Always has a size of 0. */
MA_ATOMIC ma_paged_audio_buffer_page* pTail; /* Never null. Initially set to &head. */
} ma_paged_audio_buffer_data;
MA_API ma_result ma_paged_audio_buffer_data_init(ma_format format, ma_uint32 channels, ma_paged_audio_buffer_data* pData);
MA_API void ma_paged_audio_buffer_data_uninit(ma_paged_audio_buffer_data* pData, const ma_allocation_callbacks* pAllocationCallbacks);
MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_head(ma_paged_audio_buffer_data* pData);
MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_tail(ma_paged_audio_buffer_data* pData);
MA_API ma_result ma_paged_audio_buffer_data_get_length_in_pcm_frames(ma_paged_audio_buffer_data* pData, ma_uint64* pLength);
MA_API ma_result ma_paged_audio_buffer_data_allocate_page(ma_paged_audio_buffer_data* pData, ma_uint32 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks, ma_paged_audio_buffer_page** ppPage);
MA_API ma_result ma_paged_audio_buffer_data_append_page(ma_paged_audio_buffer_data* pData, ma_paged_audio_buffer_page* pPage);
MA_API ma_result ma_paged_audio_buffer_data_allocate_and_append_page(ma_paged_audio_buffer_data* pData, ma_uint32 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks);
typedef struct
{
ma_paged_audio_buffer_data* pData; /* Must not be null. */
} ma_paged_audio_buffer_config;
MA_API ma_paged_audio_buffer_config ma_paged_audio_buffer_config_init(ma_paged_audio_buffer_data* pData);
typedef struct
{
ma_data_source_base ds;
ma_paged_audio_buffer_data* pData; /* Audio data is read from here. Cannot be null. */
ma_paged_audio_buffer_page* pCurrent;
ma_uint64 relativeCursor; /* Relative to the current page. */
ma_uint64 absoluteCursor;
} ma_paged_audio_buffer;
MA_API ma_result ma_paged_audio_buffer_init(const ma_paged_audio_buffer_config* pConfig, ma_paged_audio_buffer* pPagedAudioBuffer);
MA_API void ma_paged_audio_buffer_uninit(ma_paged_audio_buffer* pPagedAudioBuffer, const ma_allocation_callbacks* pAllocationCallbacks);
MA_API ma_result ma_paged_audio_buffer_read_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); /* Returns MA_AT_END if no more pages available. */
MA_API ma_result ma_paged_audio_buffer_seek_to_pcm_frame(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64 frameIndex);
MA_API ma_result ma_paged_audio_buffer_get_cursor_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pCursor);
MA_API ma_result ma_paged_audio_buffer_get_length_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pLength);
/* /*
Resource Management Resource Management
=================== ===================
...@@ -1020,8 +1083,9 @@ typedef enum ...@@ -1020,8 +1083,9 @@ typedef enum
typedef enum typedef enum
{ {
ma_resource_manager_data_buffer_connector_unknown, ma_resource_manager_data_buffer_connector_unknown,
ma_resource_manager_data_buffer_connector_decoder, /* ma_decoder */ ma_resource_manager_data_buffer_connector_decoder, /* ma_decoder */
ma_resource_manager_data_buffer_connector_buffer /* ma_audio_buffer */ ma_resource_manager_data_buffer_connector_buffer, /* ma_audio_buffer */
ma_resource_manager_data_buffer_connector_paged_buffer /* ma_paged_audio_buffer */
} ma_resource_manager_data_buffer_connector; } ma_resource_manager_data_buffer_connector;
...@@ -1167,7 +1231,6 @@ typedef struct ...@@ -1167,7 +1231,6 @@ typedef struct
void* pData; void* pData;
size_t dataSizeInBytes; size_t dataSizeInBytes;
ma_uint64 decodedFrameCount; ma_uint64 decodedFrameCount;
ma_bool32 isUnknownLength; /* When set to true does not update the running frame count of the data buffer nor the data pointer until the last page has been decoded. */
} pageDataBuffer; } pageDataBuffer;
struct struct
...@@ -1241,11 +1304,20 @@ MA_API ma_result ma_job_queue_next(ma_job_queue* pQueue, ma_job* pJob); /* Retur ...@@ -1241,11 +1304,20 @@ MA_API ma_result ma_job_queue_next(ma_job_queue* pQueue, ma_job* pJob); /* Retur
#define MA_RESOURCE_MANAGER_FLAG_NO_THREADING 0x00000002 #define MA_RESOURCE_MANAGER_FLAG_NO_THREADING 0x00000002
typedef enum
{
ma_decoded_data_supplier_unknown,
ma_decoded_data_supplier_buffer,
ma_decoded_data_supplier_paged
} ma_decoded_data_supplier;
typedef struct typedef struct
{ {
const void* pData; ma_decoded_data_supplier supplier;
ma_uint64 frameCount; /* The total number of PCM frames making up the decoded data. */ const void* pData; /* Only used if `supplier` is ma_decoded_data_supplier_buffer. */
ma_uint64 decodedFrameCount; /* For async decoding. Keeps track of how many frames are *currently* decoded. */ ma_paged_audio_buffer_data pagedData; /* Only used if `supplier` is ma_decoded_data_supplier_paged. */
ma_uint64 frameCount; /* The total number of PCM frames making up the decoded data. */
ma_uint64 decodedFrameCount; /* For async decoding. Keeps track of how many frames are *currently* decoded. */
ma_format format; ma_format format;
ma_uint32 channels; ma_uint32 channels;
ma_uint32 sampleRate; ma_uint32 sampleRate;
...@@ -1296,6 +1368,7 @@ struct ma_resource_manager_data_buffer ...@@ -1296,6 +1368,7 @@ struct ma_resource_manager_data_buffer
{ {
ma_decoder decoder; ma_decoder decoder;
ma_audio_buffer buffer; ma_audio_buffer buffer;
ma_paged_audio_buffer pagedBuffer;
} connector; } connector;
}; };
...@@ -1926,6 +1999,380 @@ MA_API ma_result ma_sound_group_get_time_in_pcm_frames(const ma_sound_group* pGr ...@@ -1926,6 +1999,380 @@ MA_API ma_result ma_sound_group_get_time_in_pcm_frames(const ma_sound_group* pGr
#if defined(MA_IMPLEMENTATION) || defined(MINIAUDIO_IMPLEMENTATION) #if defined(MA_IMPLEMENTATION) || defined(MINIAUDIO_IMPLEMENTATION)
MA_API ma_result ma_paged_audio_buffer_data_init(ma_format format, ma_uint32 channels, ma_paged_audio_buffer_data* pData)
{
if (pData == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pData);
pData->format = format;
pData->channels = channels;
pData->pTail = &pData->head;
return MA_SUCCESS;
}
MA_API void ma_paged_audio_buffer_data_uninit(ma_paged_audio_buffer_data* pData, const ma_allocation_callbacks* pAllocationCallbacks)
{
ma_paged_audio_buffer_page* pPage;
if (pData == NULL) {
return;
}
/* All pages need to be freed. */
pPage = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pData->head.pNext);
while (pPage != NULL) {
ma_paged_audio_buffer_page* pNext = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pPage->pNext);
ma_free(pPage, pAllocationCallbacks);
pPage = pNext;
}
}
MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_head(ma_paged_audio_buffer_data* pData)
{
if (pData == NULL) {
return NULL;
}
return &pData->head;
}
MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_tail(ma_paged_audio_buffer_data* pData)
{
if (pData == NULL) {
return NULL;
}
return pData->pTail;
}
MA_API ma_result ma_paged_audio_buffer_data_get_length_in_pcm_frames(ma_paged_audio_buffer_data* pData, ma_uint64* pLength)
{
ma_paged_audio_buffer_page* pPage;
if (pLength == NULL) {
return MA_INVALID_ARGS;
}
*pLength = 0;
if (pData == NULL) {
return MA_INVALID_ARGS;
}
/* Calculate the length from the linked list. */
for (pPage = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pData->head.pNext); pPage != NULL; pPage = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pPage->pNext)) {
*pLength += pPage->sizeInFrames;
}
return MA_SUCCESS;
}
MA_API ma_result ma_paged_audio_buffer_data_allocate_page(ma_paged_audio_buffer_data* pData, ma_uint32 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks, ma_paged_audio_buffer_page** ppPage)
{
ma_paged_audio_buffer_page* pPage;
if (ppPage == NULL) {
return MA_INVALID_ARGS;
}
*ppPage = NULL;
if (pData == NULL) {
return MA_INVALID_ARGS;
}
pPage = (ma_paged_audio_buffer_page*)ma_malloc(sizeof(*pPage) + (pageSizeInFrames * ma_get_bytes_per_frame(pData->format, pData->channels)), pAllocationCallbacks);
if (pPage == NULL) {
return MA_OUT_OF_MEMORY;
}
pPage->pNext = NULL;
pPage->sizeInFrames = pageSizeInFrames;
if (pInitialData != NULL) {
ma_copy_pcm_frames(pPage->pAudioData, pInitialData, pageSizeInFrames, pData->format, pData->channels);
}
*ppPage = pPage;
return MA_SUCCESS;
}
MA_API ma_result ma_paged_audio_buffer_data_append_page(ma_paged_audio_buffer_data* pData, ma_paged_audio_buffer_page* pPage)
{
if (pData == NULL || pPage == NULL) {
return MA_INVALID_ARGS;
}
/* This function assumes the page has been filled with audio data by this point. As soon as we append, the page will be available for reading. */
/* First thing to do is update the tail. */
for (;;) {
ma_paged_audio_buffer_page* pOldTail = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pData->pTail);
ma_paged_audio_buffer_page* pNewTail = pPage;
if (c89atomic_compare_exchange_weak_ptr((void**)&pData->pTail, (void**)&pOldTail, pNewTail)) {
/* Here is where we append the page to the list. After this, the page is attached to the list and ready to be read from. */
c89atomic_exchange_ptr(&pOldTail->pNext, pPage);
break; /* Done. */
}
}
return MA_SUCCESS;
}
MA_API ma_result ma_paged_audio_buffer_data_allocate_and_append_page(ma_paged_audio_buffer_data* pData, ma_uint32 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks)
{
ma_result result;
ma_paged_audio_buffer_page* pPage;
result = ma_paged_audio_buffer_data_allocate_page(pData, pageSizeInFrames, pInitialData, pAllocationCallbacks, &pPage);
if (result != MA_SUCCESS) {
return result;
}
return ma_paged_audio_buffer_data_append_page(pData, pPage); /* <-- Should never fail. */
}
MA_API ma_paged_audio_buffer_config ma_paged_audio_buffer_config_init(ma_paged_audio_buffer_data* pData)
{
ma_paged_audio_buffer_config config;
MA_ZERO_OBJECT(&config);
config.pData = pData;
return config;
}
static ma_result ma_paged_audio_buffer__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
{
return ma_paged_audio_buffer_read_pcm_frames((ma_paged_audio_buffer*)pDataSource, pFramesOut, frameCount, pFramesRead);
}
static ma_result ma_paged_audio_buffer__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
{
return ma_paged_audio_buffer_seek_to_pcm_frame((ma_paged_audio_buffer*)pDataSource, frameIndex);
}
static ma_result ma_paged_audio_buffer__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate)
{
ma_paged_audio_buffer* pPagedAudioBuffer = (ma_paged_audio_buffer*)pDataSource;
*pFormat = pPagedAudioBuffer->pData->format;
*pChannels = pPagedAudioBuffer->pData->channels;
*pSampleRate = 0; /* There is no notion of a sample rate with audio buffers. */
return MA_SUCCESS;
}
static ma_result ma_paged_audio_buffer__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor)
{
return ma_paged_audio_buffer_get_cursor_in_pcm_frames((ma_paged_audio_buffer*)pDataSource, pCursor);
}
static ma_result ma_paged_audio_buffer__data_source_on_get_length(ma_data_source* pDataSource, ma_uint64* pLength)
{
return ma_paged_audio_buffer_get_length_in_pcm_frames((ma_paged_audio_buffer*)pDataSource, pLength);
}
static ma_data_source_vtable g_ma_paged_audio_buffer_data_source_vtable =
{
ma_paged_audio_buffer__data_source_on_read,
ma_paged_audio_buffer__data_source_on_seek,
NULL, /* onMap */
NULL, /* onUnmap */
ma_paged_audio_buffer__data_source_on_get_data_format,
ma_paged_audio_buffer__data_source_on_get_cursor,
ma_paged_audio_buffer__data_source_on_get_length
};
MA_API ma_result ma_paged_audio_buffer_init(const ma_paged_audio_buffer_config* pConfig, ma_paged_audio_buffer* pPagedAudioBuffer)
{
ma_result result;
ma_data_source_config dataSourceConfig;
if (pPagedAudioBuffer == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pPagedAudioBuffer);
/* A config is required for the format and channel count. */
if (pConfig == NULL) {
return MA_INVALID_ARGS;
}
if (pConfig->pData == NULL) {
return MA_INVALID_ARGS; /* No underlying data specified. */
}
dataSourceConfig = ma_data_source_config_init();
dataSourceConfig.vtable = &g_ma_paged_audio_buffer_data_source_vtable;
result = ma_data_source_init(&dataSourceConfig, &pPagedAudioBuffer->ds);
if (result != MA_SUCCESS) {
return result;
}
pPagedAudioBuffer->pData = pConfig->pData;
pPagedAudioBuffer->pCurrent = ma_paged_audio_buffer_data_get_head(pConfig->pData);
pPagedAudioBuffer->relativeCursor = 0;
pPagedAudioBuffer->absoluteCursor = 0;
return MA_SUCCESS;
}
MA_API void ma_paged_audio_buffer_uninit(ma_paged_audio_buffer* pPagedAudioBuffer, const ma_allocation_callbacks* pAllocationCallbacks)
{
ma_paged_audio_buffer_page* pPage;
if (pPagedAudioBuffer == NULL) {
return;
}
/* All pages need to be freed. */
pPage = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&ma_paged_audio_buffer_data_get_head(pPagedAudioBuffer->pData)->pNext);
while (pPage != NULL) {
ma_paged_audio_buffer_page* pNext = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pPage->pNext);
ma_free(pPage, pAllocationCallbacks);
pPage = pNext;
}
}
MA_API ma_result ma_paged_audio_buffer_read_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
{
ma_result result = MA_SUCCESS;
ma_uint64 totalFramesRead = 0;
ma_format format;
ma_uint32 channels;
if (pPagedAudioBuffer == NULL) {
return MA_INVALID_ARGS;
}
format = pPagedAudioBuffer->pData->format;
channels = pPagedAudioBuffer->pData->channels;
while (totalFramesRead < frameCount) {
/* Read from the current page. The buffer should never be in a state where this is NULL. */
ma_uint64 framesRemainingInCurrentPage;
ma_uint64 framesRemainingToRead = frameCount - totalFramesRead;
ma_uint64 framesToReadThisIteration;
MA_ASSERT(pPagedAudioBuffer->pCurrent != NULL);
framesRemainingInCurrentPage = pPagedAudioBuffer->pCurrent->sizeInFrames - pPagedAudioBuffer->relativeCursor;
framesToReadThisIteration = ma_min(framesRemainingInCurrentPage, framesRemainingToRead);
ma_copy_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, format, channels), ma_offset_pcm_frames_ptr(pPagedAudioBuffer->pCurrent->pAudioData, pPagedAudioBuffer->relativeCursor, format, channels), framesToReadThisIteration, format, channels);
totalFramesRead += framesToReadThisIteration;
pPagedAudioBuffer->absoluteCursor += framesToReadThisIteration;
pPagedAudioBuffer->relativeCursor += framesToReadThisIteration;
/* Move to the next page if necessary. If there's no more pages, we need to return MA_AT_END. */
MA_ASSERT(pPagedAudioBuffer->relativeCursor <= pPagedAudioBuffer->pCurrent->sizeInFrames);
if (pPagedAudioBuffer->relativeCursor == pPagedAudioBuffer->pCurrent->sizeInFrames) {
/* We reached the end of the page. Need to move to the next. If there's no more pages, we're done. */
ma_paged_audio_buffer_page* pNext = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pPagedAudioBuffer->pCurrent->pNext);
if (pNext == NULL) {
result = MA_AT_END;
break; /* We've reached the end. */
} else {
pPagedAudioBuffer->pCurrent = pNext;
pPagedAudioBuffer->relativeCursor = 0;
}
}
}
if (pFramesRead != NULL) {
*pFramesRead = totalFramesRead;
}
return result;
}
MA_API ma_result ma_paged_audio_buffer_seek_to_pcm_frame(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64 frameIndex)
{
if (pPagedAudioBuffer == NULL) {
return MA_INVALID_ARGS;
}
if (frameIndex == pPagedAudioBuffer->absoluteCursor) {
return MA_SUCCESS; /* Nothing to do. */
}
if (frameIndex < pPagedAudioBuffer->absoluteCursor) {
/* Moving backwards. Need to move the cursor back to the start, and then move forward. */
pPagedAudioBuffer->pCurrent = ma_paged_audio_buffer_data_get_head(pPagedAudioBuffer->pData);
pPagedAudioBuffer->absoluteCursor = 0;
pPagedAudioBuffer->relativeCursor = 0;
/* Fall through to the forward seeking section below. */
}
if (frameIndex > pPagedAudioBuffer->absoluteCursor) {
/* Moving forward. */
ma_paged_audio_buffer_page* pPage;
ma_uint64 runningCursor = 0;
for (pPage = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&ma_paged_audio_buffer_data_get_head(pPagedAudioBuffer->pData)->pNext); pPage != NULL; pPage = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pPage->pNext)) {
ma_uint64 pageRangeBeg = runningCursor;
ma_uint64 pageRangeEnd = pageRangeBeg + pPage->sizeInFrames;
if (frameIndex >= pageRangeBeg) {
if (frameIndex < pageRangeEnd || (frameIndex == pageRangeEnd && pPage == (ma_paged_audio_buffer_page*)c89atomic_load_ptr(ma_paged_audio_buffer_data_get_tail(pPagedAudioBuffer->pData)))) { /* A small edge case - allow seeking to the very end of the buffer. */
/* We found the page. */
pPagedAudioBuffer->pCurrent = pPage;
pPagedAudioBuffer->absoluteCursor = frameIndex;
pPagedAudioBuffer->relativeCursor = frameIndex - pageRangeBeg;
return MA_SUCCESS;
}
}
runningCursor = pageRangeEnd;
}
/* Getting here means we tried seeking too far forward. Don't change any state. */
return MA_BAD_SEEK;
}
return MA_SUCCESS;
}
MA_API ma_result ma_paged_audio_buffer_get_cursor_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pCursor)
{
if (pCursor == NULL) {
return MA_INVALID_ARGS;
}
*pCursor = 0; /* Safety. */
if (pPagedAudioBuffer == NULL) {
return MA_INVALID_ARGS;
}
*pCursor = pPagedAudioBuffer->absoluteCursor;
return MA_SUCCESS;
}
MA_API ma_result ma_paged_audio_buffer_get_length_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pLength)
{
return ma_paged_audio_buffer_data_get_length_in_pcm_frames(pPagedAudioBuffer->pData, pLength);
}
MA_API size_t ma_get_accumulation_bytes_per_sample(ma_format format) MA_API size_t ma_get_accumulation_bytes_per_sample(ma_format format)
{ {
size_t bytesPerSample[ma_format_count] = { size_t bytesPerSample[ma_format_count] = {
...@@ -6072,7 +6519,14 @@ static ma_result ma_resource_manager_data_buffer_init_connector(ma_resource_mana ...@@ -6072,7 +6519,14 @@ static ma_result ma_resource_manager_data_buffer_init_connector(ma_resource_mana
an ma_audio_buffer. This enables us to use memory mapping when mixing which saves us a bit of data movement overhead. an ma_audio_buffer. This enables us to use memory mapping when mixing which saves us a bit of data movement overhead.
*/ */
if (pDataBuffer->pNode->data.type == ma_resource_manager_data_buffer_encoding_decoded) { if (pDataBuffer->pNode->data.type == ma_resource_manager_data_buffer_encoding_decoded) {
pDataBuffer->connectorType = ma_resource_manager_data_buffer_connector_buffer; /* If the source is of an unknown length we need to use a paged buffer. Otherwise we'll use a regular buffer which is a bit more efficient. */
if (pDataBuffer->pNode->data.decoded.supplier == ma_decoded_data_supplier_buffer) {
pDataBuffer->connectorType = ma_resource_manager_data_buffer_connector_buffer;
} else if (pDataBuffer->pNode->data.decoded.supplier == ma_decoded_data_supplier_paged) {
pDataBuffer->connectorType = ma_resource_manager_data_buffer_connector_paged_buffer;
} else {
return MA_INVALID_ARGS; /* Unknown decoded data backend. */
}
} else { } else {
pDataBuffer->connectorType = ma_resource_manager_data_buffer_connector_decoder; pDataBuffer->connectorType = ma_resource_manager_data_buffer_connector_decoder;
} }
...@@ -6083,6 +6537,12 @@ static ma_result ma_resource_manager_data_buffer_init_connector(ma_resource_mana ...@@ -6083,6 +6537,12 @@ static ma_result ma_resource_manager_data_buffer_init_connector(ma_resource_mana
result = ma_audio_buffer_init(&config, &pDataBuffer->connector.buffer); result = ma_audio_buffer_init(&config, &pDataBuffer->connector.buffer);
pDataBuffer->lengthInPCMFrames = pDataBuffer->connector.buffer.ref.sizeInFrames; pDataBuffer->lengthInPCMFrames = pDataBuffer->connector.buffer.ref.sizeInFrames;
} else if (pDataBuffer->connectorType == ma_resource_manager_data_buffer_connector_paged_buffer) {
ma_paged_audio_buffer_config config;
config = ma_paged_audio_buffer_config_init(&pDataBuffer->pNode->data.decoded.pagedData);
result = ma_paged_audio_buffer_init(&config, &pDataBuffer->connector.pagedBuffer);
pDataBuffer->lengthInPCMFrames = 0; /* Length is unknown so far. */
} else { } else {
ma_decoder_config configOut; ma_decoder_config configOut;
configOut = ma_decoder_config_init(pDataBuffer->pResourceManager->config.decodedFormat, pDataBuffer->pResourceManager->config.decodedChannels, pDataBuffer->pResourceManager->config.decodedSampleRate); configOut = ma_decoder_config_init(pDataBuffer->pResourceManager->config.decodedFormat, pDataBuffer->pResourceManager->config.decodedChannels, pDataBuffer->pResourceManager->config.decodedSampleRate);
...@@ -6115,7 +6575,7 @@ static ma_result ma_resource_manager_data_buffer_init_connector(ma_resource_mana ...@@ -6115,7 +6575,7 @@ static ma_result ma_resource_manager_data_buffer_init_connector(ma_resource_mana
} }
/* /*
Initialization of the connector is when we can fire the MA_NOTIFICATION_COMPLETE notification. This will give the application access to Initialization of the connector is when we can fire the init notification. This will give the application access to
the format/channels/rate of the data source. the format/channels/rate of the data source.
*/ */
if (result == MA_SUCCESS) { if (result == MA_SUCCESS) {
...@@ -6135,6 +6595,8 @@ static ma_result ma_resource_manager_data_buffer_uninit_connector(ma_resource_ma ...@@ -6135,6 +6595,8 @@ static ma_result ma_resource_manager_data_buffer_uninit_connector(ma_resource_ma
if (pDataBuffer->connectorType == ma_resource_manager_data_buffer_connector_decoder) { if (pDataBuffer->connectorType == ma_resource_manager_data_buffer_connector_decoder) {
ma_decoder_uninit(&pDataBuffer->connector.decoder); ma_decoder_uninit(&pDataBuffer->connector.decoder);
} else if (pDataBuffer->connectorType == ma_resource_manager_data_buffer_connector_paged_buffer) {
ma_paged_audio_buffer_uninit(&pDataBuffer->connector.pagedBuffer, &pResourceManager->config.allocationCallbacks);
} else { } else {
ma_audio_buffer_uninit(&pDataBuffer->connector.buffer); ma_audio_buffer_uninit(&pDataBuffer->connector.buffer);
} }
...@@ -6175,6 +6637,8 @@ static ma_data_source* ma_resource_manager_data_buffer_get_connector(ma_resource ...@@ -6175,6 +6637,8 @@ static ma_data_source* ma_resource_manager_data_buffer_get_connector(ma_resource
{ {
if (pDataBuffer->connectorType == ma_resource_manager_data_buffer_connector_buffer) { if (pDataBuffer->connectorType == ma_resource_manager_data_buffer_connector_buffer) {
return &pDataBuffer->connector.buffer; return &pDataBuffer->connector.buffer;
} else if (pDataBuffer->connectorType == ma_resource_manager_data_buffer_connector_paged_buffer) {
return &pDataBuffer->connector.pagedBuffer;
} else { } else {
return &pDataBuffer->connector.decoder; return &pDataBuffer->connector.decoder;
} }
...@@ -6507,10 +6971,12 @@ static ma_result ma_resource_manager_data_buffer_init_nolock(ma_resource_manager ...@@ -6507,10 +6971,12 @@ static ma_result ma_resource_manager_data_buffer_init_nolock(ma_resource_manager
} }
if (result == MA_SUCCESS) { if (result == MA_SUCCESS) {
pDataBuffer->pNode->data.decoded.supplier = ma_decoded_data_supplier_buffer;
pDataBuffer->pNode->data.decoded.pData = pData; pDataBuffer->pNode->data.decoded.pData = pData;
pDataBuffer->pNode->data.decoded.frameCount = totalFrameCount; pDataBuffer->pNode->data.decoded.frameCount = totalFrameCount;
pDataBuffer->pNode->data.decoded.decodedFrameCount = totalFrameCount; /* We've decoded everything. */ pDataBuffer->pNode->data.decoded.decodedFrameCount = totalFrameCount; /* We've decoded everything. */
} else { } else {
pDataBuffer->pNode->data.decoded.supplier = ma_decoded_data_supplier_unknown;
pDataBuffer->pNode->data.decoded.pData = NULL; pDataBuffer->pNode->data.decoded.pData = NULL;
pDataBuffer->pNode->data.decoded.frameCount = 0; pDataBuffer->pNode->data.decoded.frameCount = 0;
pDataBuffer->pNode->data.decoded.decodedFrameCount = 0; pDataBuffer->pNode->data.decoded.decodedFrameCount = 0;
...@@ -6744,6 +7210,16 @@ MA_API ma_result ma_resource_manager_data_buffer_read_pcm_frames(ma_resource_man ...@@ -6744,6 +7210,16 @@ MA_API ma_result ma_resource_manager_data_buffer_read_pcm_frames(ma_resource_man
result = ma_data_source_read_pcm_frames(ma_resource_manager_data_buffer_get_connector(pDataBuffer), pFramesOut, frameCount, &framesRead, isLooping); result = ma_data_source_read_pcm_frames(ma_resource_manager_data_buffer_get_connector(pDataBuffer), pFramesOut, frameCount, &framesRead, isLooping);
pDataBuffer->cursorInPCMFrames += framesRead; pDataBuffer->cursorInPCMFrames += framesRead;
/*
If we returned MA_AT_END, but the node is still loading, we don't want to return that code or else the caller will interpret the sound
as at the end and terminate decoding.
*/
if (result == MA_AT_END) {
if (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_BUSY) {
result = MA_BUSY;
}
}
if (pFramesRead != NULL) { if (pFramesRead != NULL) {
*pFramesRead = framesRead; *pFramesRead = framesRead;
} }
...@@ -6833,7 +7309,7 @@ MA_API ma_result ma_resource_manager_data_buffer_get_data_format(ma_resource_man ...@@ -6833,7 +7309,7 @@ MA_API ma_result ma_resource_manager_data_buffer_get_data_format(ma_resource_man
return MA_BUSY; /* Still loading. */ return MA_BUSY; /* Still loading. */
} }
if (pDataBuffer->connectorType == ma_resource_manager_data_buffer_connector_buffer) { if (pDataBuffer->connectorType == ma_resource_manager_data_buffer_connector_buffer || pDataBuffer->connectorType == ma_resource_manager_data_buffer_connector_paged_buffer) {
MA_ASSERT(pDataBuffer->pNode->data.type == ma_resource_manager_data_buffer_encoding_decoded); MA_ASSERT(pDataBuffer->pNode->data.type == ma_resource_manager_data_buffer_encoding_decoded);
*pFormat = pDataBuffer->pNode->data.decoded.format; *pFormat = pDataBuffer->pNode->data.decoded.format;
...@@ -6938,7 +7414,7 @@ MA_API ma_result ma_resource_manager_data_buffer_get_available_frames(ma_resourc ...@@ -6938,7 +7414,7 @@ MA_API ma_result ma_resource_manager_data_buffer_get_available_frames(ma_resourc
} }
} }
if (pDataBuffer->connectorType == ma_resource_manager_data_buffer_connector_buffer) { if (pDataBuffer->connectorType == ma_resource_manager_data_buffer_connector_buffer || pDataBuffer->connectorType == ma_resource_manager_data_buffer_connector_paged_buffer) {
/* Retrieve the available frames based on how many frames we've currently decoded, and *not* the total capacity of the audio buffer. */ /* Retrieve the available frames based on how many frames we've currently decoded, and *not* the total capacity of the audio buffer. */
if (pDataBuffer->pNode->data.decoded.decodedFrameCount > pDataBuffer->cursorInPCMFrames) { if (pDataBuffer->pNode->data.decoded.decodedFrameCount > pDataBuffer->cursorInPCMFrames) {
*pAvailableFrames = pDataBuffer->pNode->data.decoded.decodedFrameCount - pDataBuffer->cursorInPCMFrames; *pAvailableFrames = pDataBuffer->pNode->data.decoded.decodedFrameCount - pDataBuffer->cursorInPCMFrames;
...@@ -8188,6 +8664,7 @@ static ma_result ma_resource_manager_process_job__load_data_buffer(ma_resource_m ...@@ -8188,6 +8664,7 @@ static ma_result ma_resource_manager_process_job__load_data_buffer(ma_resource_m
framesRead = ma_decoder_read_pcm_frames(pDecoder, pData, pageSizeInFrames); framesRead = ma_decoder_read_pcm_frames(pDecoder, pData, pageSizeInFrames);
if (framesRead < pageSizeInFrames) { if (framesRead < pageSizeInFrames) {
/* We've read the entire sound. This is the simple case. We just need to set the result to MA_SUCCESS. */ /* We've read the entire sound. This is the simple case. We just need to set the result to MA_SUCCESS. */
pDataBuffer->pNode->data.decoded.supplier = ma_decoded_data_supplier_buffer;
pDataBuffer->pNode->data.decoded.pData = pData; pDataBuffer->pNode->data.decoded.pData = pData;
pDataBuffer->pNode->data.decoded.frameCount = framesRead; pDataBuffer->pNode->data.decoded.frameCount = framesRead;
...@@ -8208,15 +8685,6 @@ static ma_result ma_resource_manager_process_job__load_data_buffer(ma_resource_m ...@@ -8208,15 +8685,6 @@ static ma_result ma_resource_manager_process_job__load_data_buffer(ma_resource_m
/* We've still got more to decode. We just set the result to MA_BUSY which will tell the next section below to post a paging event. */ /* We've still got more to decode. We just set the result to MA_BUSY which will tell the next section below to post a paging event. */
result = MA_BUSY; result = MA_BUSY;
} }
#if 0
/* If we successfully initialized and the sound is of a known length we can start initialize the connector. */
if (result == MA_SUCCESS || result == MA_BUSY) {
if (pDataBuffer->pNode->data.decoded.decodedFrameCount > 0) {
result = ma_resource_manager_data_buffer_init_connector(pDataBuffer, pJob->loadDataBuffer.pInitNotification);
}
}
#endif
} }
done: done:
...@@ -8254,9 +8722,10 @@ done: ...@@ -8254,9 +8722,10 @@ done:
pageDataBufferJob.pageDataBuffer.decodedFrameCount = framesRead; pageDataBufferJob.pageDataBuffer.decodedFrameCount = framesRead;
if (totalFrameCount > 0) { if (totalFrameCount > 0) {
pageDataBufferJob.pageDataBuffer.isUnknownLength = MA_FALSE; /* The length is known. Use a simple buffer. */
pageDataBufferJob.pageDataBuffer.pInitNotification = NULL; /* <-- Clear this notification to NULL to ensure it's not signalled a second time at the end of decoding, which will be done for sounds of unknown length. */ pageDataBufferJob.pageDataBuffer.pInitNotification = NULL; /* <-- Clear this notification to NULL to ensure it's not signalled a second time at the end of decoding, which will be done for sounds of unknown length. */
pDataBuffer->pNode->data.decoded.supplier = ma_decoded_data_supplier_buffer;
pDataBuffer->pNode->data.decoded.pData = pData; pDataBuffer->pNode->data.decoded.pData = pData;
pDataBuffer->pNode->data.decoded.frameCount = totalFrameCount; pDataBuffer->pNode->data.decoded.frameCount = totalFrameCount;
...@@ -8271,19 +8740,24 @@ done: ...@@ -8271,19 +8740,24 @@ done:
/* The sound is of a known length so we can go ahead and initialize the connector now. */ /* The sound is of a known length so we can go ahead and initialize the connector now. */
result = ma_resource_manager_data_buffer_init_connector(pDataBuffer, pJob->loadDataBuffer.pInitNotification); result = ma_resource_manager_data_buffer_init_connector(pDataBuffer, pJob->loadDataBuffer.pInitNotification);
} else { } else {
pageDataBufferJob.pageDataBuffer.isUnknownLength = MA_TRUE; /* The length is unknown. Need to use a paged buffer. */
pageDataBufferJob.pageDataBuffer.pInitNotification = pJob->loadDataBuffer.pInitNotification; /* <-- Set this to the init notification so that the PAGE_DATA_BUFFER job can signal it at the end of decoding. Only needed for sounds of unknown length. */ pDataBuffer->pNode->data.decoded.supplier = ma_decoded_data_supplier_paged;
pDataBuffer->pNode->data.decoded.pData = NULL; /* <-- Not used for paged buffers. Set to NULL for safety. */
pDataBuffer->pNode->data.decoded.frameCount = 0; /* <-- Will be set at the end of decoding. */
pDataBuffer->pNode->data.decoded.decodedFrameCount = framesRead;
/* /* For a paged data buffer need to initialize the data structure for the paged data before initializing the connector. */
These members are all set after the last page has been decoded. The reason for this is that the application should not be attempting to result = ma_paged_audio_buffer_data_init(pDataBuffer->pNode->data.decoded.format, pDataBuffer->pNode->data.decoded.channels, &pDataBuffer->pNode->data.decoded.pagedData);
read any data until the sound is fully decoded because we're going to be dynamically expanding pData and we'll be introducing complications if (result == MA_SUCCESS) {
by letting the application get access to it. /* A page needs to be allocated and appended for the initial data. Not doing this will result in the first page being missing. */
*/ result = ma_paged_audio_buffer_data_allocate_and_append_page(&pDataBuffer->pNode->data.decoded.pagedData, (ma_uint32)framesRead, pData, &pResourceManager->config.allocationCallbacks);
pDataBuffer->pNode->data.decoded.pData = NULL; if (result == MA_SUCCESS) {
pDataBuffer->pNode->data.decoded.frameCount = 0; result = ma_resource_manager_data_buffer_init_connector(pDataBuffer, pJob->loadDataBuffer.pInitNotification);
pDataBuffer->pNode->data.decoded.decodedFrameCount = 0; }
}
result = MA_SUCCESS; /* The pData pointer is no longer needed for the paged audio buffers (it's only used for regular buffers). */
ma_free(pData, &pResourceManager->config.allocationCallbacks/*, MA_ALLOCATION_TYPE_DECODED_BUFFER*/);
} }
if (result == MA_SUCCESS) { if (result == MA_SUCCESS) {
...@@ -8337,7 +8811,7 @@ static ma_result ma_resource_manager_process_job__free_data_buffer(ma_resource_m ...@@ -8337,7 +8811,7 @@ static ma_result ma_resource_manager_process_job__free_data_buffer(ma_resource_m
static ma_result ma_resource_manager_process_job__page_data_buffer(ma_resource_manager* pResourceManager, ma_job* pJob) static ma_result ma_resource_manager_process_job__page_data_buffer(ma_resource_manager* pResourceManager, ma_job* pJob)
{ {
ma_result result = MA_SUCCESS; ma_result result = MA_SUCCESS;
ma_uint64 pageSizeInFrames; ma_uint32 pageSizeInFrames;
ma_uint64 framesRead; ma_uint64 framesRead;
void* pRunningData; void* pRunningData;
ma_job jobCopy; ma_job jobCopy;
...@@ -8363,52 +8837,60 @@ static ma_result ma_resource_manager_process_job__page_data_buffer(ma_resource_m ...@@ -8363,52 +8837,60 @@ static ma_result ma_resource_manager_process_job__page_data_buffer(ma_resource_m
/* We need to know the size of a page in frames to know how many frames to decode. */ /* We need to know the size of a page in frames to know how many frames to decode. */
pageSizeInFrames = MA_RESOURCE_MANAGER_PAGE_SIZE_IN_MILLISECONDS * (jobCopy.pageDataBuffer.pDecoder->outputSampleRate/1000); pageSizeInFrames = MA_RESOURCE_MANAGER_PAGE_SIZE_IN_MILLISECONDS * (jobCopy.pageDataBuffer.pDecoder->outputSampleRate/1000);
/* If the total length is unknown we may need to expand the size of the buffer. */
if (jobCopy.pageDataBuffer.isUnknownLength == MA_TRUE) {
ma_uint64 requiredSize = (jobCopy.pageDataBuffer.decodedFrameCount + pageSizeInFrames) * ma_get_bytes_per_frame(jobCopy.pageDataBuffer.pDecoder->outputFormat, jobCopy.pageDataBuffer.pDecoder->outputChannels);
if (requiredSize <= MA_SIZE_MAX) {
if (requiredSize > jobCopy.pageDataBuffer.dataSizeInBytes) {
size_t newSize = (size_t)ma_max(requiredSize, jobCopy.pageDataBuffer.dataSizeInBytes * 2);
void *pNewData = ma__realloc_from_callbacks(jobCopy.pageDataBuffer.pData, newSize, jobCopy.pageDataBuffer.dataSizeInBytes, &pResourceManager->config.allocationCallbacks/*, MA_ALLOCATION_TYPE_DECODED_BUFFER*/);
if (pNewData != NULL) {
jobCopy.pageDataBuffer.pData = pNewData;
jobCopy.pageDataBuffer.dataSizeInBytes = newSize;
} else {
result = MA_OUT_OF_MEMORY;
}
}
} else {
result = MA_TOO_BIG;
}
}
/* We should have the memory set up so now we can decode the next page. */ /* We should have the memory set up so now we can decode the next page. */
if (result == MA_SUCCESS) { if (result == MA_SUCCESS) {
ma_uint64 framesToTryReading = pageSizeInFrames; ma_uint64 framesToTryReading = pageSizeInFrames;
ma_paged_audio_buffer_page* pPage = NULL; /* <-- Only used for sounds using a paged data buffer. */
/* Can't try reading more than what we originally retrieved when we first initialized the decoder. */ /* Can't try reading more than what we originally retrieved when we first initialized the decoder. */
if (jobCopy.pageDataBuffer.isUnknownLength == MA_FALSE) { if (pDataBuffer->connectorType == ma_resource_manager_data_buffer_connector_buffer) {
/* Using a regular buffer. Don't read more than we originally retrieved when we first initialized the decoder. */
ma_uint64 framesRemaining = pDataBuffer->pNode->data.decoded.frameCount - pDataBuffer->pNode->data.decoded.decodedFrameCount; ma_uint64 framesRemaining = pDataBuffer->pNode->data.decoded.frameCount - pDataBuffer->pNode->data.decoded.decodedFrameCount;
if (framesToTryReading > framesRemaining) { if (framesToTryReading > framesRemaining) {
framesToTryReading = framesRemaining; framesToTryReading = framesRemaining;
} }
pRunningData = ma_offset_ptr(jobCopy.pageDataBuffer.pData, jobCopy.pageDataBuffer.decodedFrameCount * ma_get_bytes_per_frame(jobCopy.pageDataBuffer.pDecoder->outputFormat, jobCopy.pageDataBuffer.pDecoder->outputChannels));
} else {
/* Using a paged buffer which means we don't know the length. Allocate a page and read as much as we can. This will be appended to the decoder. */
ma_paged_audio_buffer_data_allocate_page(&pDataBuffer->pNode->data.decoded.pagedData, pageSizeInFrames, NULL, &pResourceManager->config.allocationCallbacks, &pPage);
if (result == MA_SUCCESS) {
pPage->sizeInFrames = 0; /* <-- For safety just in case we get an error later on. We'll update this to it's proper value later. */
pRunningData = pPage->pAudioData;
} else {
pRunningData = NULL;
}
} }
pRunningData = ma_offset_ptr(jobCopy.pageDataBuffer.pData, jobCopy.pageDataBuffer.decodedFrameCount * ma_get_bytes_per_frame(jobCopy.pageDataBuffer.pDecoder->outputFormat, jobCopy.pageDataBuffer.pDecoder->outputChannels)); if (pRunningData != NULL) {
framesRead = ma_decoder_read_pcm_frames(jobCopy.pageDataBuffer.pDecoder, pRunningData, framesToTryReading);
if (framesRead < framesToTryReading) {
result = MA_AT_END;
}
framesRead = ma_decoder_read_pcm_frames(jobCopy.pageDataBuffer.pDecoder, pRunningData, framesToTryReading); if (pDataBuffer->connectorType == ma_resource_manager_data_buffer_connector_paged_buffer) {
if (framesRead < framesToTryReading) { pPage->sizeInFrames = (ma_uint32)framesRead; /* Safe cast. */
result = MA_AT_END; }
} else {
framesRead = 0;
result = MA_AT_END; /* We don't have a destination buffer which means we probably ran out of memory in ma_paged_audio_buffer_allocate_page(). Just terminate decoding by pretending we're at the end. */
}
/* Make sure the page is attached to the buffer if we're running a paged audio buffer. */
if (pDataBuffer->connectorType == ma_resource_manager_data_buffer_connector_paged_buffer) {
ma_paged_audio_buffer_data_append_page(&pDataBuffer->pNode->data.decoded.pagedData, pPage);
} }
/* If the total length is known we can increment out decoded frame count. Otherwise it needs to be left at 0 until the last page is decoded. */ pDataBuffer->pNode->data.decoded.decodedFrameCount += framesRead;
if (jobCopy.pageDataBuffer.isUnknownLength == MA_FALSE) {
pDataBuffer->pNode->data.decoded.decodedFrameCount += framesRead;
/* If we've read up to the length reported when we first loaded the file we've reached the end. */ /* If we've read up to the length reported when we first loaded the file we've reached the end. */
if (pDataBuffer->connectorType == ma_resource_manager_data_buffer_connector_buffer) {
if (pDataBuffer->pNode->data.decoded.decodedFrameCount == pDataBuffer->pNode->data.decoded.frameCount) { if (pDataBuffer->pNode->data.decoded.decodedFrameCount == pDataBuffer->pNode->data.decoded.frameCount) {
result = MA_AT_END; result = MA_AT_END;
} }
} else {
/* The length of a paged buffer needs to be dynamically expanded as we decode as we don't know the length until it's been fully decoded. */
pDataBuffer->lengthInPCMFrames += framesRead;
} }
/* /*
...@@ -8431,21 +8913,16 @@ static ma_result ma_resource_manager_process_job__page_data_buffer(ma_resource_m ...@@ -8431,21 +8913,16 @@ static ma_result ma_resource_manager_process_job__page_data_buffer(ma_resource_m
ma_decoder_uninit(jobCopy.pageDataBuffer.pDecoder); ma_decoder_uninit(jobCopy.pageDataBuffer.pDecoder);
ma__free_from_callbacks(jobCopy.pageDataBuffer.pDecoder, &pResourceManager->config.allocationCallbacks/*, MA_ALLOCATION_TYPE_DECODER*/); ma__free_from_callbacks(jobCopy.pageDataBuffer.pDecoder, &pResourceManager->config.allocationCallbacks/*, MA_ALLOCATION_TYPE_DECODER*/);
/* When the length is unknown we were doubling the size of the buffer each time we needed more data. Let's try reducing this by doing a final realloc(). */
if (jobCopy.pageDataBuffer.isUnknownLength) {
ma_uint64 newSizeInBytes = jobCopy.pageDataBuffer.decodedFrameCount * ma_get_bytes_per_frame(pDataBuffer->pNode->data.decoded.format, pDataBuffer->pNode->data.decoded.channels);
void* pNewData = ma__realloc_from_callbacks(jobCopy.pageDataBuffer.pData, (size_t)newSizeInBytes, jobCopy.pageDataBuffer.dataSizeInBytes, &pResourceManager->config.allocationCallbacks);
if (pNewData != NULL) {
jobCopy.pageDataBuffer.pData = pNewData;
jobCopy.pageDataBuffer.dataSizeInBytes = (size_t)newSizeInBytes; /* <-- Don't really need to set this, but I think it's good practice. */
}
}
/* /*
We can now set the frame counts appropriately. We want to set the frame count regardless of whether or not it had a known length just in case we have We can now set the frame counts appropriately. We want to set the frame count regardless of whether or not it had a known length just in case we have
a weird situation where the frame count an opening time was different to the final count we got after reading. a weird situation where the frame count an opening time was different to the final count we got after reading.
*/ */
pDataBuffer->pNode->data.decoded.pData = jobCopy.pageDataBuffer.pData; if (pDataBuffer->connectorType == ma_resource_manager_data_buffer_connector_buffer) {
pDataBuffer->pNode->data.decoded.pData = jobCopy.pageDataBuffer.pData;
} else {
pDataBuffer->pNode->data.decoded.pData = NULL; /* Must be null when a paged data buffer is being used. */
}
pDataBuffer->pNode->data.decoded.frameCount = jobCopy.pageDataBuffer.decodedFrameCount; pDataBuffer->pNode->data.decoded.frameCount = jobCopy.pageDataBuffer.decodedFrameCount;
/* /*
...@@ -8462,11 +8939,6 @@ static ma_result ma_resource_manager_process_job__page_data_buffer(ma_resource_m ...@@ -8462,11 +8939,6 @@ static ma_result ma_resource_manager_process_job__page_data_buffer(ma_resource_m
result = MA_SUCCESS; result = MA_SUCCESS;
} }
/* If it was an unknown length, we can finally initialize the connector. For sounds of a known length, the connector was initialized when the first page was decoded in MA_JOB_LOAD_DATA_BUFFER. */
if (jobCopy.pageDataBuffer.isUnknownLength) {
result = ma_resource_manager_data_buffer_init_connector(pDataBuffer, jobCopy.pageDataBuffer.pInitNotification);
}
/* We need to set the status of the page so other things can know about it. We can only change the status away from MA_BUSY. If it's anything else it cannot be changed. */ /* We need to set the status of the page so other things can know about it. We can only change the status away from MA_BUSY. If it's anything else it cannot be changed. */
c89atomic_compare_and_swap_32(&pDataBuffer->pNode->result, MA_BUSY, result); c89atomic_compare_and_swap_32(&pDataBuffer->pNode->result, MA_BUSY, result);
......
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