diff options
Diffstat (limited to 'media/libcubeb/src/cubeb_ring_array.h')
-rw-r--r-- | media/libcubeb/src/cubeb_ring_array.h | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/media/libcubeb/src/cubeb_ring_array.h b/media/libcubeb/src/cubeb_ring_array.h new file mode 100644 index 000000000..51b3b321a --- /dev/null +++ b/media/libcubeb/src/cubeb_ring_array.h @@ -0,0 +1,159 @@ +/* + * Copyright © 2016 Mozilla Foundation + * + * This program is made available under an ISC-style license. See the + * accompanying file LICENSE for details. + */ + +#ifndef CUBEB_RING_ARRAY_H +#define CUBEB_RING_ARRAY_H + +#include "cubeb_utils.h" + +/** Ring array of pointers is used to hold buffers. In case that + asynchronous producer/consumer callbacks do not arrive in a + repeated order the ring array stores the buffers and fetch + them in the correct order. */ + +typedef struct { + AudioBuffer * buffer_array; /**< Array that hold pointers of the allocated space for the buffers. */ + unsigned int tail; /**< Index of the last element (first to deliver). */ + unsigned int count; /**< Number of elements in the array. */ + unsigned int capacity; /**< Total length of the array. */ +} ring_array; + +static int +single_audiobuffer_init(AudioBuffer * buffer, + uint32_t bytesPerFrame, + uint32_t channelsPerFrame, + uint32_t frames) +{ + assert(buffer); + assert(bytesPerFrame > 0 && channelsPerFrame && frames > 0); + + size_t size = bytesPerFrame * frames; + buffer->mData = operator new(size); + if (buffer->mData == NULL) { + return CUBEB_ERROR; + } + PodZero(static_cast<char*>(buffer->mData), size); + + buffer->mNumberChannels = channelsPerFrame; + buffer->mDataByteSize = size; + + return CUBEB_OK; +} + +/** Initialize the ring array. + @param ra The ring_array pointer of allocated structure. + @retval 0 on success. */ +int +ring_array_init(ring_array * ra, + uint32_t capacity, + uint32_t bytesPerFrame, + uint32_t channelsPerFrame, + uint32_t framesPerBuffer) +{ + assert(ra); + if (capacity == 0 || bytesPerFrame == 0 || + channelsPerFrame == 0 || framesPerBuffer == 0) { + return CUBEB_ERROR_INVALID_PARAMETER; + } + ra->capacity = capacity; + ra->tail = 0; + ra->count = 0; + + ra->buffer_array = new AudioBuffer[ra->capacity]; + PodZero(ra->buffer_array, ra->capacity); + if (ra->buffer_array == NULL) { + return CUBEB_ERROR; + } + + for (unsigned int i = 0; i < ra->capacity; ++i) { + if (single_audiobuffer_init(&ra->buffer_array[i], + bytesPerFrame, + channelsPerFrame, + framesPerBuffer) != CUBEB_OK) { + return CUBEB_ERROR; + } + } + + return CUBEB_OK; +} + +/** Destroy the ring array. + @param ra The ring_array pointer.*/ +void +ring_array_destroy(ring_array * ra) +{ + assert(ra); + if (ra->buffer_array == NULL){ + return; + } + for (unsigned int i = 0; i < ra->capacity; ++i) { + if (ra->buffer_array[i].mData) { + operator delete(ra->buffer_array[i].mData); + } + } + delete [] ra->buffer_array; +} + +/** Get the allocated buffer to be stored with fresh data. + @param ra The ring_array pointer. + @retval Pointer of the allocated space to be stored with fresh data or NULL if full. */ +AudioBuffer * +ring_array_get_free_buffer(ring_array * ra) +{ + assert(ra && ra->buffer_array); + assert(ra->buffer_array[0].mData != NULL); + if (ra->count == ra->capacity) { + return NULL; + } + + assert(ra->count == 0 || (ra->tail + ra->count) % ra->capacity != ra->tail); + AudioBuffer * ret = &ra->buffer_array[(ra->tail + ra->count) % ra->capacity]; + + ++ra->count; + assert(ra->count <= ra->capacity); + + return ret; +} + +/** Get the next available buffer with data. + @param ra The ring_array pointer. + @retval Pointer of the next in order data buffer or NULL if empty. */ +AudioBuffer * +ring_array_get_data_buffer(ring_array * ra) +{ + assert(ra && ra->buffer_array); + assert(ra->buffer_array[0].mData != NULL); + + if (ra->count == 0) { + return NULL; + } + AudioBuffer * ret = &ra->buffer_array[ra->tail]; + + ra->tail = (ra->tail + 1) % ra->capacity; + assert(ra->tail < ra->capacity); + + assert(ra->count > 0); + --ra->count; + + return ret; +} + +/** When array is empty get the first allocated buffer in the array. + @param ra The ring_array pointer. + @retval If arrays is empty, pointer of the allocated space else NULL. */ +AudioBuffer * +ring_array_get_dummy_buffer(ring_array * ra) +{ + assert(ra && ra->buffer_array); + assert(ra->capacity > 0); + if (ra->count > 0) { + return NULL; + } + return &ra->buffer_array[0]; +} + +#endif //CUBEB_RING_ARRAY_H |