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