blob: 6f9be318762b4017fce2f982d162d8c81768b6da [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
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
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +000011// A ring buffer to hold arbitrary data. Provides no thread safety. Unless
12// otherwise specified, functions return 0 on success and -1 on error.
niklase@google.com470e71d2011-07-07 08:21:25 +000013
niklase@google.com470e71d2011-07-07 08:21:25 +000014#include "ring_buffer.h"
15
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +000016#include <stddef.h> // size_t
17#include <stdlib.h>
18#include <string.h>
19
20// TODO(bjornv): Remove tmp_buf_t once old buffer function has been replaced in
21// APM.
niklase@google.com470e71d2011-07-07 08:21:25 +000022typedef struct {
23 int readPos;
24 int writePos;
25 int size;
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +000026 int element_size;
niklase@google.com470e71d2011-07-07 08:21:25 +000027 char rwWrap;
28 bufdata_t *data;
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +000029} tmp_buf_t;
30
31typedef struct {
32 size_t read_pos;
33 size_t write_pos;
34 size_t element_count;
35 size_t element_size;
36 char rw_wrap;
37 void* data;
niklase@google.com470e71d2011-07-07 08:21:25 +000038} buf_t;
39
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +000040enum { SAME_WRAP, DIFF_WRAP };
niklase@google.com470e71d2011-07-07 08:21:25 +000041
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +000042// Get address of region(s) from which we can read data.
43// If the region is contiguous, |data_ptr_bytes_2| will be zero.
44// If non-contiguous, |data_ptr_bytes_2| will be the size in bytes of the second
45// region. Returns room available to be read or |element_count|, whichever is
46// smaller.
47static size_t GetBufferReadRegions(buf_t* buf,
48 size_t element_count,
49 void** data_ptr_1,
50 size_t* data_ptr_bytes_1,
51 void** data_ptr_2,
52 size_t* data_ptr_bytes_2) {
niklase@google.com470e71d2011-07-07 08:21:25 +000053
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +000054 const size_t readable_elements = WebRtc_available_read(buf);
55 const size_t read_elements = (readable_elements < element_count ?
56 readable_elements : element_count);
57 const size_t margin = buf->element_count - buf->read_pos;
niklase@google.com470e71d2011-07-07 08:21:25 +000058
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +000059 // Check to see if read is not contiguous.
60 if (read_elements > margin) {
61 // Write data in two blocks that wrap the buffer.
bjornv@webrtc.org267d0132011-12-28 10:26:17 +000062 *data_ptr_1 = ((char*) buf->data) + (buf->read_pos * buf->element_size);
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +000063 *data_ptr_bytes_1 = margin * buf->element_size;
64 *data_ptr_2 = buf->data;
65 *data_ptr_bytes_2 = (read_elements - margin) * buf->element_size;
66 } else {
bjornv@webrtc.org267d0132011-12-28 10:26:17 +000067 *data_ptr_1 = ((char*) buf->data) + (buf->read_pos * buf->element_size);
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +000068 *data_ptr_bytes_1 = read_elements * buf->element_size;
69 *data_ptr_2 = NULL;
70 *data_ptr_bytes_2 = 0;
71 }
niklase@google.com470e71d2011-07-07 08:21:25 +000072
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +000073 return read_elements;
niklase@google.com470e71d2011-07-07 08:21:25 +000074}
75
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +000076int WebRtcApm_CreateBuffer(void **bufInst, int size) {
77 tmp_buf_t *buf = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +000078
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +000079 if (size < 0) {
80 return -1;
81 }
niklase@google.com470e71d2011-07-07 08:21:25 +000082
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +000083 buf = malloc(sizeof(tmp_buf_t));
84 *bufInst = buf;
85 if (buf == NULL) {
86 return -1;
87 }
niklase@google.com470e71d2011-07-07 08:21:25 +000088
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +000089 buf->data = malloc(size * sizeof(bufdata_t));
90 if (buf->data == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +000091 free(buf);
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +000092 buf = NULL;
93 return -1;
94 }
niklase@google.com470e71d2011-07-07 08:21:25 +000095
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +000096 buf->size = size;
97 buf->element_size = 1;
98
99 return 0;
100}
101
102int WebRtcApm_InitBuffer(void *bufInst) {
103 tmp_buf_t *buf = (tmp_buf_t*)bufInst;
104
105 buf->readPos = 0;
106 buf->writePos = 0;
107 buf->rwWrap = SAME_WRAP;
108
109 // Initialize buffer to zeros
110 memset(buf->data, 0, sizeof(bufdata_t) * buf->size);
111
112 return 0;
113}
114
115int WebRtcApm_FreeBuffer(void *bufInst) {
116 tmp_buf_t *buf = (tmp_buf_t*)bufInst;
117
118 if (buf == NULL) {
119 return -1;
120 }
121
122 free(buf->data);
123 free(buf);
124
125 return 0;
126}
127
128int WebRtcApm_ReadBuffer(void *bufInst, bufdata_t *data, int size) {
129 tmp_buf_t *buf = (tmp_buf_t*)bufInst;
130 int n = 0, margin = 0;
131
132 if (size <= 0 || size > buf->size) {
133 return -1;
134 }
135
136 n = size;
137 if (buf->rwWrap == DIFF_WRAP) {
138 margin = buf->size - buf->readPos;
139 if (n > margin) {
140 buf->rwWrap = SAME_WRAP;
141 memcpy(data, buf->data + buf->readPos, sizeof(bufdata_t) * margin);
142 buf->readPos = 0;
143 n = size - margin;
144 } else {
145 memcpy(data, buf->data + buf->readPos, sizeof(bufdata_t) * n);
146 buf->readPos += n;
147 return n;
148 }
149 }
150
151 if (buf->rwWrap == SAME_WRAP) {
152 margin = buf->writePos - buf->readPos;
153 if (margin > n)
154 margin = n;
155 memcpy(data + size - n, buf->data + buf->readPos,
156 sizeof(bufdata_t) * margin);
157 buf->readPos += margin;
158 n -= margin;
159 }
160
161 return size - n;
162}
163
164int WebRtcApm_WriteBuffer(void *bufInst, const bufdata_t *data, int size) {
165 tmp_buf_t *buf = (tmp_buf_t*)bufInst;
166 int n = 0, margin = 0;
167
168 if (size < 0 || size > buf->size) {
169 return -1;
170 }
171
172 n = size;
173 if (buf->rwWrap == SAME_WRAP) {
174 margin = buf->size - buf->writePos;
175 if (n > margin) {
176 buf->rwWrap = DIFF_WRAP;
177 memcpy(buf->data + buf->writePos, data, sizeof(bufdata_t) * margin);
178 buf->writePos = 0;
179 n = size - margin;
180 } else {
181 memcpy(buf->data + buf->writePos, data, sizeof(bufdata_t) * n);
182 buf->writePos += n;
183 return n;
184 }
185 }
186
187 if (buf->rwWrap == DIFF_WRAP) {
188 margin = buf->readPos - buf->writePos;
189 if (margin > n)
190 margin = n;
191 memcpy(buf->data + buf->writePos, data + size - n,
192 sizeof(bufdata_t) * margin);
193 buf->writePos += margin;
194 n -= margin;
195 }
196
197 return size - n;
198}
199
200int WebRtcApm_FlushBuffer(void *bufInst, int size) {
201 tmp_buf_t *buf = (tmp_buf_t*)bufInst;
202 int n = 0, margin = 0;
203
204 if (size <= 0 || size > buf->size) {
205 return -1;
206 }
207
208 n = size;
209 if (buf->rwWrap == DIFF_WRAP) {
210 margin = buf->size - buf->readPos;
211 if (n > margin) {
212 buf->rwWrap = SAME_WRAP;
213 buf->readPos = 0;
214 n = size - margin;
215 } else {
216 buf->readPos += n;
217 return n;
218 }
219 }
220
221 if (buf->rwWrap == SAME_WRAP) {
222 margin = buf->writePos - buf->readPos;
223 if (margin > n)
224 margin = n;
225 buf->readPos += margin;
226 n -= margin;
227 }
228
229 return size - n;
230}
231
232int WebRtcApm_StuffBuffer(void *bufInst, int size) {
233 tmp_buf_t *buf = (tmp_buf_t*)bufInst;
234 int n = 0, margin = 0;
235
236 if (size <= 0 || size > buf->size) {
237 return -1;
238 }
239
240 n = size;
241 if (buf->rwWrap == SAME_WRAP) {
242 margin = buf->readPos;
243 if (n > margin) {
244 buf->rwWrap = DIFF_WRAP;
245 buf->readPos = buf->size - 1;
246 n -= margin + 1;
247 } else {
248 buf->readPos -= n;
249 return n;
250 }
251 }
252
253 if (buf->rwWrap == DIFF_WRAP) {
254 margin = buf->readPos - buf->writePos;
255 if (margin > n)
256 margin = n;
257 buf->readPos -= margin;
258 n -= margin;
259 }
260
261 return size - n;
262}
263
264int WebRtcApm_get_buffer_size(const void *bufInst) {
265 const tmp_buf_t *buf = (tmp_buf_t*)bufInst;
266
267 if (buf->rwWrap == SAME_WRAP)
268 return buf->writePos - buf->readPos;
269 else
270 return buf->size - buf->readPos + buf->writePos;
271}
272
273int WebRtc_CreateBuffer(void** handle,
274 size_t element_count,
275 size_t element_size) {
276 buf_t* self = NULL;
277
278 if (handle == NULL) {
279 return -1;
280 }
281
282 self = malloc(sizeof(buf_t));
283 if (self == NULL) {
284 return -1;
285 }
286 *handle = self;
287
288 self->data = malloc(element_count * element_size);
289 if (self->data == NULL) {
290 free(self);
291 self = NULL;
292 return -1;
293 }
294
295 self->element_count = element_count;
296 self->element_size = element_size;
297
298 return 0;
299}
300
301int WebRtc_InitBuffer(void* handle) {
302 buf_t* self = (buf_t*) handle;
303
304 if (self == NULL) {
305 return -1;
306 }
307
308 self->read_pos = 0;
309 self->write_pos = 0;
310 self->rw_wrap = SAME_WRAP;
311
312 // Initialize buffer to zeros
313 memset(self->data, 0, self->element_count * self->element_size);
314
315 return 0;
316}
317
318int WebRtc_FreeBuffer(void* handle) {
319 buf_t* self = (buf_t*) handle;
320
321 if (self == NULL) {
322 return -1;
323 }
324
325 free(self->data);
326 free(self);
327
328 return 0;
329}
330
331size_t WebRtc_ReadBuffer(void* handle,
332 void** data_ptr,
333 void* data,
334 size_t element_count) {
335
336 buf_t* self = (buf_t*) handle;
337
338 if (self == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000339 return 0;
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000340 }
341 if (data == NULL) {
342 return 0;
343 }
344 if (data_ptr == NULL) {
345 return 0;
346 }
347
348 {
349 void* buf_ptr_1 = NULL;
350 void* buf_ptr_2 = NULL;
351 size_t buf_ptr_bytes_1 = 0;
352 size_t buf_ptr_bytes_2 = 0;
353 const size_t read_count = GetBufferReadRegions(self,
354 element_count,
355 &buf_ptr_1,
356 &buf_ptr_bytes_1,
357 &buf_ptr_2,
358 &buf_ptr_bytes_2);
359
360 if (buf_ptr_bytes_2 > 0) {
361 // We have a wrap around when reading the buffer. Copy the buffer data to
362 // |data| and point to it.
363 memcpy(data, buf_ptr_1, buf_ptr_bytes_1);
bjornv@webrtc.org267d0132011-12-28 10:26:17 +0000364 memcpy(((char*) data) + buf_ptr_bytes_1, buf_ptr_2, buf_ptr_bytes_2);
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000365 *data_ptr = data;
366 } else {
367 *data_ptr = buf_ptr_1;
368 }
369
370 // Update read position
371 WebRtc_MoveReadPtr(handle, (int) read_count);
372
373 return read_count;
374 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000375}
376
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000377size_t WebRtc_WriteBuffer(void* handle,
378 const void* data,
379 size_t element_count) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000380
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000381 buf_t* self = (buf_t*) handle;
382
383 if (self == NULL) {
384 return 0;
385 }
386 if (data == NULL) {
387 return 0;
388 }
389
390 {
391 const size_t free_elements = WebRtc_available_write(handle);
392 const size_t write_elements = (free_elements < element_count ? free_elements
393 : element_count);
394 size_t n = write_elements;
395 const size_t margin = self->element_count - self->write_pos;
396
397 if (write_elements > margin) {
398 // Buffer wrap around when writing.
bjornv@webrtc.org267d0132011-12-28 10:26:17 +0000399 memcpy(((char*) self->data) + (self->write_pos * self->element_size),
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000400 data, margin * self->element_size);
401 self->write_pos = 0;
402 n -= margin;
403 self->rw_wrap = DIFF_WRAP;
niklase@google.com470e71d2011-07-07 08:21:25 +0000404 }
bjornv@webrtc.org267d0132011-12-28 10:26:17 +0000405 memcpy(((char*) self->data) + (self->write_pos * self->element_size),
406 ((const char*) data) + ((write_elements - n) * self->element_size),
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000407 n * self->element_size);
408 self->write_pos += n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000409
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000410 return write_elements;
411 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000412}
413
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000414int WebRtc_MoveReadPtr(void* handle, int element_count) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000415
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000416 buf_t* self = (buf_t*) handle;
417
418 if (self == NULL) {
419 return 0;
420 }
421
422 {
423 // We need to be able to take care of negative changes, hence use "int"
424 // instead of "size_t".
425 const int free_elements = (int) WebRtc_available_write(handle);
426 const int readable_elements = (int) WebRtc_available_read(handle);
427 int read_pos = (int) self->read_pos;
428
429 if (element_count > readable_elements) {
430 element_count = readable_elements;
431 }
432 if (element_count < -free_elements) {
433 element_count = -free_elements;
niklase@google.com470e71d2011-07-07 08:21:25 +0000434 }
435
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000436 read_pos += element_count;
437 if (read_pos > (int) self->element_count) {
438 // Buffer wrap around. Restart read position and wrap indicator.
439 read_pos -= (int) self->element_count;
440 self->rw_wrap = SAME_WRAP;
441 }
442 if (read_pos < 0) {
443 // Buffer wrap around. Restart read position and wrap indicator.
444 read_pos += (int) self->element_count;
445 self->rw_wrap = DIFF_WRAP;
niklase@google.com470e71d2011-07-07 08:21:25 +0000446 }
447
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000448 self->read_pos = (size_t) read_pos;
niklase@google.com470e71d2011-07-07 08:21:25 +0000449
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000450 return element_count;
451 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000452}
453
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000454size_t WebRtc_available_read(const void* handle) {
455 const buf_t* self = (buf_t*) handle;
niklase@google.com470e71d2011-07-07 08:21:25 +0000456
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000457 if (self == NULL) {
458 return 0;
459 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000460
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000461 if (self->rw_wrap == SAME_WRAP) {
462 return self->write_pos - self->read_pos;
463 } else {
464 return self->element_count - self->read_pos + self->write_pos;
465 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000466}
467
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000468size_t WebRtc_available_write(const void* handle) {
469 const buf_t* self = (buf_t*) handle;
niklase@google.com470e71d2011-07-07 08:21:25 +0000470
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000471 if (self == NULL) {
472 return 0;
473 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000474
bjornv@webrtc.org7270a6b2011-12-28 08:44:17 +0000475 return self->element_count - WebRtc_available_read(handle);
niklase@google.com470e71d2011-07-07 08:21:25 +0000476}