cubeb_ring_array.h (3916B)
1 /* 2 * Copyright © 2016 Mozilla Foundation 3 * 4 * This program is made available under an ISC-style license. See the 5 * accompanying file LICENSE for details. 6 */ 7 8 #ifndef CUBEB_RING_ARRAY_H 9 #define CUBEB_RING_ARRAY_H 10 11 #include "cubeb_utils.h" 12 #include <CoreAudio/CoreAudioTypes.h> 13 14 /** Ring array of pointers is used to hold buffers. In case that 15 asynchronous producer/consumer callbacks do not arrive in a 16 repeated order the ring array stores the buffers and fetch 17 them in the correct order. */ 18 19 typedef struct { 20 AudioBuffer * buffer_array; /**< Array that hold pointers of the allocated 21 space for the buffers. */ 22 unsigned int tail; /**< Index of the last element (first to deliver). */ 23 unsigned int count; /**< Number of elements in the array. */ 24 unsigned int capacity; /**< Total length of the array. */ 25 } ring_array; 26 27 static int 28 single_audiobuffer_init(AudioBuffer * buffer, uint32_t bytesPerFrame, 29 uint32_t channelsPerFrame, uint32_t frames) 30 { 31 assert(buffer); 32 assert(bytesPerFrame > 0 && channelsPerFrame && frames > 0); 33 34 size_t size = bytesPerFrame * frames; 35 buffer->mData = operator new(size); 36 if (buffer->mData == NULL) { 37 return CUBEB_ERROR; 38 } 39 PodZero(static_cast<char *>(buffer->mData), size); 40 41 buffer->mNumberChannels = channelsPerFrame; 42 buffer->mDataByteSize = size; 43 44 return CUBEB_OK; 45 } 46 47 /** Initialize the ring array. 48 @param ra The ring_array pointer of allocated structure. 49 @retval 0 on success. */ 50 static int 51 ring_array_init(ring_array * ra, uint32_t capacity, uint32_t bytesPerFrame, 52 uint32_t channelsPerFrame, uint32_t framesPerBuffer) 53 { 54 assert(ra); 55 if (capacity == 0 || bytesPerFrame == 0 || channelsPerFrame == 0 || 56 framesPerBuffer == 0) { 57 return CUBEB_ERROR_INVALID_PARAMETER; 58 } 59 ra->capacity = capacity; 60 ra->tail = 0; 61 ra->count = 0; 62 63 ra->buffer_array = new AudioBuffer[ra->capacity]; 64 PodZero(ra->buffer_array, ra->capacity); 65 if (ra->buffer_array == NULL) { 66 return CUBEB_ERROR; 67 } 68 69 for (unsigned int i = 0; i < ra->capacity; ++i) { 70 if (single_audiobuffer_init(&ra->buffer_array[i], bytesPerFrame, 71 channelsPerFrame, 72 framesPerBuffer) != CUBEB_OK) { 73 return CUBEB_ERROR; 74 } 75 } 76 77 return CUBEB_OK; 78 } 79 80 /** Destroy the ring array. 81 @param ra The ring_array pointer.*/ 82 static void 83 ring_array_destroy(ring_array * ra) 84 { 85 assert(ra); 86 if (ra->buffer_array == NULL) { 87 return; 88 } 89 for (unsigned int i = 0; i < ra->capacity; ++i) { 90 if (ra->buffer_array[i].mData) { 91 operator delete(ra->buffer_array[i].mData); 92 } 93 } 94 delete[] ra->buffer_array; 95 } 96 97 /** Get the allocated buffer to be stored with fresh data. 98 @param ra The ring_array pointer. 99 @retval Pointer of the allocated space to be stored with fresh data or NULL 100 if full. */ 101 static AudioBuffer * 102 ring_array_get_free_buffer(ring_array * ra) 103 { 104 assert(ra && ra->buffer_array); 105 assert(ra->buffer_array[0].mData != NULL); 106 if (ra->count == ra->capacity) { 107 return NULL; 108 } 109 110 assert(ra->count == 0 || (ra->tail + ra->count) % ra->capacity != ra->tail); 111 AudioBuffer * ret = &ra->buffer_array[(ra->tail + ra->count) % ra->capacity]; 112 113 ++ra->count; 114 assert(ra->count <= ra->capacity); 115 116 return ret; 117 } 118 119 /** Get the next available buffer with data. 120 @param ra The ring_array pointer. 121 @retval Pointer of the next in order data buffer or NULL if empty. */ 122 static AudioBuffer * 123 ring_array_get_data_buffer(ring_array * ra) 124 { 125 assert(ra && ra->buffer_array); 126 assert(ra->buffer_array[0].mData != NULL); 127 128 if (ra->count == 0) { 129 return NULL; 130 } 131 AudioBuffer * ret = &ra->buffer_array[ra->tail]; 132 133 ra->tail = (ra->tail + 1) % ra->capacity; 134 assert(ra->tail < ra->capacity); 135 136 assert(ra->count > 0); 137 --ra->count; 138 139 return ret; 140 } 141 142 #endif // CUBEB_RING_ARRAY_H