1470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/*
2470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
4470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  Use of this source code is governed by a BSD-style license
5470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  that can be found in the LICENSE file in the root of the source
6470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  tree. An additional intellectual property rights grant can be found
7470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  in the file PATENTS.  All contributing project authors may
8470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  be found in the AUTHORS file in the root of the source tree.
9470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
10470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
117270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org// A ring buffer to hold arbitrary data. Provides no thread safety. Unless
127270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org// otherwise specified, functions return 0 on success and -1 on error.
13470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
146b6301588ef2d7b5f5d442aa95bef442a43ead53andrew@webrtc.org#include "webrtc/common_audio/ring_buffer.h"
157270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
169ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org#include <stddef.h>  // size_t
17470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include <stdlib.h>
18470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include <string.h>
19470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
206d6a43d6e3dc0c83f79df9ce96597d90925e8cadandrew@webrtc.orgenum Wrap {
216d6a43d6e3dc0c83f79df9ce96597d90925e8cadandrew@webrtc.org  SAME_WRAP,
226d6a43d6e3dc0c83f79df9ce96597d90925e8cadandrew@webrtc.org  DIFF_WRAP
236d6a43d6e3dc0c83f79df9ce96597d90925e8cadandrew@webrtc.org};
246d6a43d6e3dc0c83f79df9ce96597d90925e8cadandrew@webrtc.org
259ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.orgstruct RingBuffer {
267270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  size_t read_pos;
277270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  size_t write_pos;
287270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  size_t element_count;
297270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  size_t element_size;
306d6a43d6e3dc0c83f79df9ce96597d90925e8cadandrew@webrtc.org  enum Wrap rw_wrap;
316d6a43d6e3dc0c83f79df9ce96597d90925e8cadandrew@webrtc.org  char* data;
329ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org};
33470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
347270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org// Get address of region(s) from which we can read data.
357270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org// If the region is contiguous, |data_ptr_bytes_2| will be zero.
367270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org// If non-contiguous, |data_ptr_bytes_2| will be the size in bytes of the second
377270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org// region. Returns room available to be read or |element_count|, whichever is
387270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org// smaller.
399ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.orgstatic size_t GetBufferReadRegions(RingBuffer* buf,
407270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org                                   size_t element_count,
417270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org                                   void** data_ptr_1,
427270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org                                   size_t* data_ptr_bytes_1,
437270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org                                   void** data_ptr_2,
447270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org                                   size_t* data_ptr_bytes_2) {
457270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
467270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  const size_t readable_elements = WebRtc_available_read(buf);
477270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  const size_t read_elements = (readable_elements < element_count ?
487270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org      readable_elements : element_count);
497270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  const size_t margin = buf->element_count - buf->read_pos;
507270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
517270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  // Check to see if read is not contiguous.
527270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  if (read_elements > margin) {
537270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    // Write data in two blocks that wrap the buffer.
546d6a43d6e3dc0c83f79df9ce96597d90925e8cadandrew@webrtc.org    *data_ptr_1 = buf->data + buf->read_pos * buf->element_size;
557270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    *data_ptr_bytes_1 = margin * buf->element_size;
567270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    *data_ptr_2 = buf->data;
577270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    *data_ptr_bytes_2 = (read_elements - margin) * buf->element_size;
587270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  } else {
596d6a43d6e3dc0c83f79df9ce96597d90925e8cadandrew@webrtc.org    *data_ptr_1 = buf->data + buf->read_pos * buf->element_size;
607270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    *data_ptr_bytes_1 = read_elements * buf->element_size;
617270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    *data_ptr_2 = NULL;
627270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    *data_ptr_bytes_2 = 0;
637270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  }
647270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
657270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  return read_elements;
667270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org}
67470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
6891f325586d5e43b13782fe9aa29c14697dc16470andrew@webrtc.orgRingBuffer* WebRtc_CreateBuffer(size_t element_count, size_t element_size) {
699ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org  RingBuffer* self = NULL;
709ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org  if (element_count == 0 || element_size == 0) {
7191f325586d5e43b13782fe9aa29c14697dc16470andrew@webrtc.org    return NULL;
727270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  }
737270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
749ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org  self = malloc(sizeof(RingBuffer));
759ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org  if (!self) {
7691f325586d5e43b13782fe9aa29c14697dc16470andrew@webrtc.org    return NULL;
777270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  }
78470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
797270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  self->data = malloc(element_count * element_size);
809ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org  if (!self->data) {
817270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    free(self);
827270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    self = NULL;
8391f325586d5e43b13782fe9aa29c14697dc16470andrew@webrtc.org    return NULL;
847270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  }
857270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
867270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  self->element_count = element_count;
877270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  self->element_size = element_size;
886b6301588ef2d7b5f5d442aa95bef442a43ead53andrew@webrtc.org  WebRtc_InitBuffer(self);
897270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
9091f325586d5e43b13782fe9aa29c14697dc16470andrew@webrtc.org  return self;
91470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
92470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
936b6301588ef2d7b5f5d442aa95bef442a43ead53andrew@webrtc.orgvoid WebRtc_InitBuffer(RingBuffer* self) {
947270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  self->read_pos = 0;
957270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  self->write_pos = 0;
967270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  self->rw_wrap = SAME_WRAP;
97470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
987270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  // Initialize buffer to zeros
997270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  memset(self->data, 0, self->element_count * self->element_size);
1007270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org}
1017270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
1029ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.orgvoid WebRtc_FreeBuffer(void* handle) {
1039ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org  RingBuffer* self = (RingBuffer*)handle;
1049ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org  if (!self) {
1059ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org    return;
1067270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  }
1077270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
1087270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  free(self->data);
1097270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  free(self);
1107270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org}
1117270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
1129ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.orgsize_t WebRtc_ReadBuffer(RingBuffer* self,
1137270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org                         void** data_ptr,
1147270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org                         void* data,
1157270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org                         size_t element_count) {
1167270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
1177270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  if (self == NULL) {
1187270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    return 0;
1197270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  }
1207270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  if (data == NULL) {
1217270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    return 0;
1227270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  }
1237270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
1247270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  {
1257270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    void* buf_ptr_1 = NULL;
1267270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    void* buf_ptr_2 = NULL;
1277270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    size_t buf_ptr_bytes_1 = 0;
1287270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    size_t buf_ptr_bytes_2 = 0;
1297270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    const size_t read_count = GetBufferReadRegions(self,
1307270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org                                                   element_count,
1317270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org                                                   &buf_ptr_1,
1327270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org                                                   &buf_ptr_bytes_1,
1337270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org                                                   &buf_ptr_2,
1347270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org                                                   &buf_ptr_bytes_2);
1357270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
1367270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    if (buf_ptr_bytes_2 > 0) {
1377270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org      // We have a wrap around when reading the buffer. Copy the buffer data to
1387270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org      // |data| and point to it.
1397270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org      memcpy(data, buf_ptr_1, buf_ptr_bytes_1);
140267d0133fff6af4153311c612fed12e1bc121ec3bjornv@webrtc.org      memcpy(((char*) data) + buf_ptr_bytes_1, buf_ptr_2, buf_ptr_bytes_2);
1419ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org      buf_ptr_1 = data;
1429ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org    } else if (!data_ptr) {
1439ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org      // No wrap, but a memcpy was requested.
1449ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org      memcpy(data, buf_ptr_1, buf_ptr_bytes_1);
1459ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org    }
1469ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org    if (data_ptr) {
1479ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org      // |buf_ptr_1| == |data| in the case of a wrap.
1487270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org      *data_ptr = buf_ptr_1;
149470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
150470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1517270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    // Update read position
1529ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org    WebRtc_MoveReadPtr(self, (int) read_count);
1537270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
1547270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    return read_count;
1557270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  }
156470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
157470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1589ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.orgsize_t WebRtc_WriteBuffer(RingBuffer* self,
1597270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org                          const void* data,
1607270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org                          size_t element_count) {
1619ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org  if (!self) {
1627270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    return 0;
1637270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  }
1649ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org  if (!data) {
1657270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    return 0;
1667270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  }
1677270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
1687270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  {
1699ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org    const size_t free_elements = WebRtc_available_write(self);
1707270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    const size_t write_elements = (free_elements < element_count ? free_elements
1717270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org        : element_count);
1727270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    size_t n = write_elements;
1737270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    const size_t margin = self->element_count - self->write_pos;
1747270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
1757270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    if (write_elements > margin) {
1767270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org      // Buffer wrap around when writing.
1776d6a43d6e3dc0c83f79df9ce96597d90925e8cadandrew@webrtc.org      memcpy(self->data + self->write_pos * self->element_size,
1787270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org             data, margin * self->element_size);
1797270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org      self->write_pos = 0;
1807270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org      n -= margin;
1817270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org      self->rw_wrap = DIFF_WRAP;
182470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1836d6a43d6e3dc0c83f79df9ce96597d90925e8cadandrew@webrtc.org    memcpy(self->data + self->write_pos * self->element_size,
184267d0133fff6af4153311c612fed12e1bc121ec3bjornv@webrtc.org           ((const char*) data) + ((write_elements - n) * self->element_size),
1857270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org           n * self->element_size);
1867270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    self->write_pos += n;
187470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1887270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    return write_elements;
1897270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  }
1907270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org}
1917270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
1929ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.orgint WebRtc_MoveReadPtr(RingBuffer* self, int element_count) {
1939ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org  if (!self) {
1947270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    return 0;
1957270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  }
1967270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
1977270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  {
1987270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    // We need to be able to take care of negative changes, hence use "int"
1997270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    // instead of "size_t".
2009ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org    const int free_elements = (int) WebRtc_available_write(self);
2019ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org    const int readable_elements = (int) WebRtc_available_read(self);
2027270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    int read_pos = (int) self->read_pos;
2037270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
2047270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    if (element_count > readable_elements) {
2057270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org      element_count = readable_elements;
2067270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    }
2077270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    if (element_count < -free_elements) {
2087270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org      element_count = -free_elements;
209470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
210470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2117270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    read_pos += element_count;
2127270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    if (read_pos > (int) self->element_count) {
2137270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org      // Buffer wrap around. Restart read position and wrap indicator.
2147270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org      read_pos -= (int) self->element_count;
2157270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org      self->rw_wrap = SAME_WRAP;
2167270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    }
2177270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    if (read_pos < 0) {
2187270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org      // Buffer wrap around. Restart read position and wrap indicator.
2197270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org      read_pos += (int) self->element_count;
2207270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org      self->rw_wrap = DIFF_WRAP;
221470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2237270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    self->read_pos = (size_t) read_pos;
2247270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
2257270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    return element_count;
2267270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  }
2277270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org}
2287270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
2299ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.orgsize_t WebRtc_available_read(const RingBuffer* self) {
2309ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org  if (!self) {
2317270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    return 0;
2327270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  }
2337270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org
2347270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  if (self->rw_wrap == SAME_WRAP) {
2357270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    return self->write_pos - self->read_pos;
2367270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  } else {
2377270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    return self->element_count - self->read_pos + self->write_pos;
2387270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  }
239470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
240470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2419ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.orgsize_t WebRtc_available_write(const RingBuffer* self) {
2429ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org  if (!self) {
2437270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org    return 0;
2447270a6bcc288012a340c152ef63cc773c08dbedbbjornv@webrtc.org  }
245470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2469ae1354e250bebaba295048e1cb47a74d33bf8e0andrew@webrtc.org  return self->element_count - WebRtc_available_read(self);
247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
248