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/common_audio/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 WebRtc_InitBuffer(self); 89 90 return self; 91 } 92 93 void WebRtc_InitBuffer(RingBuffer* self) { 94 self->read_pos = 0; 95 self->write_pos = 0; 96 self->rw_wrap = SAME_WRAP; 97 98 // Initialize buffer to zeros 99 memset(self->data, 0, self->element_count * self->element_size); 100 } 101 102 void WebRtc_FreeBuffer(void* handle) { 103 RingBuffer* self = (RingBuffer*)handle; 104 if (!self) { 105 return; 106 } 107 108 free(self->data); 109 free(self); 110 } 111 112 size_t WebRtc_ReadBuffer(RingBuffer* self, 113 void** data_ptr, 114 void* data, 115 size_t element_count) { 116 117 if (self == NULL) { 118 return 0; 119 } 120 if (data == NULL) { 121 return 0; 122 } 123 124 { 125 void* buf_ptr_1 = NULL; 126 void* buf_ptr_2 = NULL; 127 size_t buf_ptr_bytes_1 = 0; 128 size_t buf_ptr_bytes_2 = 0; 129 const size_t read_count = GetBufferReadRegions(self, 130 element_count, 131 &buf_ptr_1, 132 &buf_ptr_bytes_1, 133 &buf_ptr_2, 134 &buf_ptr_bytes_2); 135 136 if (buf_ptr_bytes_2 > 0) { 137 // We have a wrap around when reading the buffer. Copy the buffer data to 138 // |data| and point to it. 139 memcpy(data, buf_ptr_1, buf_ptr_bytes_1); 140 memcpy(((char*) data) + buf_ptr_bytes_1, buf_ptr_2, buf_ptr_bytes_2); 141 buf_ptr_1 = data; 142 } else if (!data_ptr) { 143 // No wrap, but a memcpy was requested. 144 memcpy(data, buf_ptr_1, buf_ptr_bytes_1); 145 } 146 if (data_ptr) { 147 // |buf_ptr_1| == |data| in the case of a wrap. 148 *data_ptr = buf_ptr_1; 149 } 150 151 // Update read position 152 WebRtc_MoveReadPtr(self, (int) read_count); 153 154 return read_count; 155 } 156 } 157 158 size_t WebRtc_WriteBuffer(RingBuffer* self, 159 const void* data, 160 size_t element_count) { 161 if (!self) { 162 return 0; 163 } 164 if (!data) { 165 return 0; 166 } 167 168 { 169 const size_t free_elements = WebRtc_available_write(self); 170 const size_t write_elements = (free_elements < element_count ? free_elements 171 : element_count); 172 size_t n = write_elements; 173 const size_t margin = self->element_count - self->write_pos; 174 175 if (write_elements > margin) { 176 // Buffer wrap around when writing. 177 memcpy(self->data + self->write_pos * self->element_size, 178 data, margin * self->element_size); 179 self->write_pos = 0; 180 n -= margin; 181 self->rw_wrap = DIFF_WRAP; 182 } 183 memcpy(self->data + self->write_pos * self->element_size, 184 ((const char*) data) + ((write_elements - n) * self->element_size), 185 n * self->element_size); 186 self->write_pos += n; 187 188 return write_elements; 189 } 190 } 191 192 int WebRtc_MoveReadPtr(RingBuffer* self, int element_count) { 193 if (!self) { 194 return 0; 195 } 196 197 { 198 // We need to be able to take care of negative changes, hence use "int" 199 // instead of "size_t". 200 const int free_elements = (int) WebRtc_available_write(self); 201 const int readable_elements = (int) WebRtc_available_read(self); 202 int read_pos = (int) self->read_pos; 203 204 if (element_count > readable_elements) { 205 element_count = readable_elements; 206 } 207 if (element_count < -free_elements) { 208 element_count = -free_elements; 209 } 210 211 read_pos += element_count; 212 if (read_pos > (int) self->element_count) { 213 // Buffer wrap around. Restart read position and wrap indicator. 214 read_pos -= (int) self->element_count; 215 self->rw_wrap = SAME_WRAP; 216 } 217 if (read_pos < 0) { 218 // Buffer wrap around. Restart read position and wrap indicator. 219 read_pos += (int) self->element_count; 220 self->rw_wrap = DIFF_WRAP; 221 } 222 223 self->read_pos = (size_t) read_pos; 224 225 return element_count; 226 } 227 } 228 229 size_t WebRtc_available_read(const RingBuffer* self) { 230 if (!self) { 231 return 0; 232 } 233 234 if (self->rw_wrap == SAME_WRAP) { 235 return self->write_pos - self->read_pos; 236 } else { 237 return self->element_count - self->read_pos + self->write_pos; 238 } 239 } 240 241 size_t WebRtc_available_write(const RingBuffer* self) { 242 if (!self) { 243 return 0; 244 } 245 246 return self->element_count - WebRtc_available_read(self); 247 } 248