1 /* 2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 // A ring buffer to hold arbitrary data. Provides no thread safety. Unless 12 // otherwise specified, functions return 0 on success and -1 on error. 13 14 #include "webrtc/modules/audio_processing/utility/ring_buffer.h" 15 16 #include <stddef.h> // size_t 17 #include <stdlib.h> 18 #include <string.h> 19 20 enum Wrap { 21 SAME_WRAP, 22 DIFF_WRAP 23 }; 24 25 struct RingBuffer { 26 size_t read_pos; 27 size_t write_pos; 28 size_t element_count; 29 size_t element_size; 30 enum Wrap rw_wrap; 31 char* data; 32 }; 33 34 // Get address of region(s) from which we can read data. 35 // If the region is contiguous, |data_ptr_bytes_2| will be zero. 36 // If non-contiguous, |data_ptr_bytes_2| will be the size in bytes of the second 37 // region. Returns room available to be read or |element_count|, whichever is 38 // smaller. 39 static size_t GetBufferReadRegions(RingBuffer* buf, 40 size_t element_count, 41 void** data_ptr_1, 42 size_t* data_ptr_bytes_1, 43 void** data_ptr_2, 44 size_t* data_ptr_bytes_2) { 45 46 const size_t readable_elements = WebRtc_available_read(buf); 47 const size_t read_elements = (readable_elements < element_count ? 48 readable_elements : element_count); 49 const size_t margin = buf->element_count - buf->read_pos; 50 51 // Check to see if read is not contiguous. 52 if (read_elements > margin) { 53 // Write data in two blocks that wrap the buffer. 54 *data_ptr_1 = buf->data + buf->read_pos * buf->element_size; 55 *data_ptr_bytes_1 = margin * buf->element_size; 56 *data_ptr_2 = buf->data; 57 *data_ptr_bytes_2 = (read_elements - margin) * buf->element_size; 58 } else { 59 *data_ptr_1 = buf->data + buf->read_pos * buf->element_size; 60 *data_ptr_bytes_1 = read_elements * buf->element_size; 61 *data_ptr_2 = NULL; 62 *data_ptr_bytes_2 = 0; 63 } 64 65 return read_elements; 66 } 67 68 RingBuffer* WebRtc_CreateBuffer(size_t element_count, size_t element_size) { 69 RingBuffer* self = NULL; 70 if (element_count == 0 || element_size == 0) { 71 return NULL; 72 } 73 74 self = malloc(sizeof(RingBuffer)); 75 if (!self) { 76 return NULL; 77 } 78 79 self->data = malloc(element_count * element_size); 80 if (!self->data) { 81 free(self); 82 self = NULL; 83 return NULL; 84 } 85 86 self->element_count = element_count; 87 self->element_size = element_size; 88 89 return self; 90 } 91 92 int WebRtc_InitBuffer(RingBuffer* self) { 93 if (!self) { 94 return -1; 95 } 96 97 self->read_pos = 0; 98 self->write_pos = 0; 99 self->rw_wrap = SAME_WRAP; 100 101 // Initialize buffer to zeros 102 memset(self->data, 0, self->element_count * self->element_size); 103 104 return 0; 105 } 106 107 void WebRtc_FreeBuffer(void* handle) { 108 RingBuffer* self = (RingBuffer*)handle; 109 if (!self) { 110 return; 111 } 112 113 free(self->data); 114 free(self); 115 } 116 117 size_t WebRtc_ReadBuffer(RingBuffer* self, 118 void** data_ptr, 119 void* data, 120 size_t element_count) { 121 122 if (self == NULL) { 123 return 0; 124 } 125 if (data == NULL) { 126 return 0; 127 } 128 129 { 130 void* buf_ptr_1 = NULL; 131 void* buf_ptr_2 = NULL; 132 size_t buf_ptr_bytes_1 = 0; 133 size_t buf_ptr_bytes_2 = 0; 134 const size_t read_count = GetBufferReadRegions(self, 135 element_count, 136 &buf_ptr_1, 137 &buf_ptr_bytes_1, 138 &buf_ptr_2, 139 &buf_ptr_bytes_2); 140 141 if (buf_ptr_bytes_2 > 0) { 142 // We have a wrap around when reading the buffer. Copy the buffer data to 143 // |data| and point to it. 144 memcpy(data, buf_ptr_1, buf_ptr_bytes_1); 145 memcpy(((char*) data) + buf_ptr_bytes_1, buf_ptr_2, buf_ptr_bytes_2); 146 buf_ptr_1 = data; 147 } else if (!data_ptr) { 148 // No wrap, but a memcpy was requested. 149 memcpy(data, buf_ptr_1, buf_ptr_bytes_1); 150 } 151 if (data_ptr) { 152 // |buf_ptr_1| == |data| in the case of a wrap. 153 *data_ptr = buf_ptr_1; 154 } 155 156 // Update read position 157 WebRtc_MoveReadPtr(self, (int) read_count); 158 159 return read_count; 160 } 161 } 162 163 size_t WebRtc_WriteBuffer(RingBuffer* self, 164 const void* data, 165 size_t element_count) { 166 if (!self) { 167 return 0; 168 } 169 if (!data) { 170 return 0; 171 } 172 173 { 174 const size_t free_elements = WebRtc_available_write(self); 175 const size_t write_elements = (free_elements < element_count ? free_elements 176 : element_count); 177 size_t n = write_elements; 178 const size_t margin = self->element_count - self->write_pos; 179 180 if (write_elements > margin) { 181 // Buffer wrap around when writing. 182 memcpy(self->data + self->write_pos * self->element_size, 183 data, margin * self->element_size); 184 self->write_pos = 0; 185 n -= margin; 186 self->rw_wrap = DIFF_WRAP; 187 } 188 memcpy(self->data + self->write_pos * self->element_size, 189 ((const char*) data) + ((write_elements - n) * self->element_size), 190 n * self->element_size); 191 self->write_pos += n; 192 193 return write_elements; 194 } 195 } 196 197 int WebRtc_MoveReadPtr(RingBuffer* self, int element_count) { 198 if (!self) { 199 return 0; 200 } 201 202 { 203 // We need to be able to take care of negative changes, hence use "int" 204 // instead of "size_t". 205 const int free_elements = (int) WebRtc_available_write(self); 206 const int readable_elements = (int) WebRtc_available_read(self); 207 int read_pos = (int) self->read_pos; 208 209 if (element_count > readable_elements) { 210 element_count = readable_elements; 211 } 212 if (element_count < -free_elements) { 213 element_count = -free_elements; 214 } 215 216 read_pos += element_count; 217 if (read_pos > (int) self->element_count) { 218 // Buffer wrap around. Restart read position and wrap indicator. 219 read_pos -= (int) self->element_count; 220 self->rw_wrap = SAME_WRAP; 221 } 222 if (read_pos < 0) { 223 // Buffer wrap around. Restart read position and wrap indicator. 224 read_pos += (int) self->element_count; 225 self->rw_wrap = DIFF_WRAP; 226 } 227 228 self->read_pos = (size_t) read_pos; 229 230 return element_count; 231 } 232 } 233 234 size_t WebRtc_available_read(const RingBuffer* self) { 235 if (!self) { 236 return 0; 237 } 238 239 if (self->rw_wrap == SAME_WRAP) { 240 return self->write_pos - self->read_pos; 241 } else { 242 return self->element_count - self->read_pos + self->write_pos; 243 } 244 } 245 246 size_t WebRtc_available_write(const RingBuffer* self) { 247 if (!self) { 248 return 0; 249 } 250 251 return self->element_count - WebRtc_available_read(self); 252 } 253