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