OLD | NEW |
| (Empty) |
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/modules/audio_processing/utility/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 } | |
OLD | NEW |