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 const size_t readable_elements = WebRtc_available_read(buf); | |
46 const size_t read_elements = (readable_elements < element_count ? | |
47 readable_elements : element_count); | |
48 const size_t margin = buf->element_count - buf->read_pos; | |
49 | |
50 // Check to see if read is not contiguous. | |
51 if (read_elements > margin) { | |
52 // Write data in two blocks that wrap the buffer. | |
53 *data_ptr_1 = buf->data + buf->read_pos * buf->element_size; | |
54 *data_ptr_bytes_1 = margin * buf->element_size; | |
55 *data_ptr_2 = buf->data; | |
56 *data_ptr_bytes_2 = (read_elements - margin) * buf->element_size; | |
57 } else { | |
58 *data_ptr_1 = buf->data + buf->read_pos * buf->element_size; | |
59 *data_ptr_bytes_1 = read_elements * buf->element_size; | |
60 *data_ptr_2 = NULL; | |
61 *data_ptr_bytes_2 = 0; | |
62 } | |
63 | |
64 return read_elements; | |
65 } | |
66 | |
67 RingBuffer* WebRtc_CreateBuffer(size_t element_count, size_t element_size) { | |
68 RingBuffer* self = NULL; | |
69 if (element_count == 0 || element_size == 0) { | |
70 return NULL; | |
71 } | |
72 | |
73 self = static_cast<RingBuffer*>(malloc(sizeof(RingBuffer))); | |
74 if (!self) { | |
75 return NULL; | |
76 } | |
77 | |
78 self->data = static_cast<char*>(malloc(element_count * element_size)); | |
79 if (!self->data) { | |
80 free(self); | |
81 self = NULL; | |
82 return NULL; | |
83 } | |
84 | |
85 self->element_count = element_count; | |
86 self->element_size = element_size; | |
87 WebRtc_InitBuffer(self); | |
88 | |
89 return self; | |
90 } | |
91 | |
92 void WebRtc_InitBuffer(RingBuffer* self) { | |
93 self->read_pos = 0; | |
94 self->write_pos = 0; | |
95 self->rw_wrap = SAME_WRAP; | |
96 | |
97 // Initialize buffer to zeros | |
98 memset(self->data, 0, self->element_count * self->element_size); | |
99 } | |
100 | |
101 void WebRtc_FreeBuffer(void* handle) { | |
102 RingBuffer* self = static_cast<RingBuffer*>(handle); | |
103 if (!self) { | |
104 return; | |
105 } | |
106 | |
107 free(self->data); | |
108 free(self); | |
109 } | |
110 | |
111 size_t WebRtc_ReadBuffer(RingBuffer* self, | |
112 void** data_ptr, | |
113 void* data, | |
114 size_t element_count) { | |
115 if (self == NULL) { | |
116 return 0; | |
117 } | |
118 if (data == NULL) { | |
119 return 0; | |
120 } | |
121 | |
122 { | |
123 void* buf_ptr_1 = NULL; | |
124 void* buf_ptr_2 = NULL; | |
125 size_t buf_ptr_bytes_1 = 0; | |
126 size_t buf_ptr_bytes_2 = 0; | |
127 const size_t read_count = GetBufferReadRegions(self, | |
128 element_count, | |
129 &buf_ptr_1, | |
130 &buf_ptr_bytes_1, | |
131 &buf_ptr_2, | |
132 &buf_ptr_bytes_2); | |
133 | |
134 if (buf_ptr_bytes_2 > 0) { | |
135 // We have a wrap around when reading the buffer. Copy the buffer data to | |
136 // |data| and point to it. | |
137 memcpy(data, buf_ptr_1, buf_ptr_bytes_1); | |
138 memcpy(static_cast<char*>(data) + buf_ptr_bytes_1, buf_ptr_2, | |
139 buf_ptr_bytes_2); | |
140 buf_ptr_1 = data; | |
141 } else if (!data_ptr) { | |
142 // No wrap, but a memcpy was requested. | |
143 memcpy(data, buf_ptr_1, buf_ptr_bytes_1); | |
144 } | |
145 if (data_ptr) { | |
146 // |buf_ptr_1| == |data| in the case of a wrap. | |
147 *data_ptr = buf_ptr_1; | |
148 } | |
149 | |
150 // Update read position | |
151 WebRtc_MoveReadPtr(self, static_cast<int>(read_count)); | |
152 | |
153 return read_count; | |
154 } | |
155 } | |
156 | |
157 size_t WebRtc_WriteBuffer(RingBuffer* self, | |
158 const void* data, | |
159 size_t element_count) { | |
160 if (!self) { | |
161 return 0; | |
162 } | |
163 if (!data) { | |
164 return 0; | |
165 } | |
166 | |
167 { | |
168 const size_t free_elements = WebRtc_available_write(self); | |
169 const size_t write_elements = (free_elements < element_count ? free_elements | |
170 : element_count); | |
171 size_t n = write_elements; | |
172 const size_t margin = self->element_count - self->write_pos; | |
173 | |
174 if (write_elements > margin) { | |
175 // Buffer wrap around when writing. | |
176 memcpy(self->data + self->write_pos * self->element_size, | |
177 data, margin * self->element_size); | |
178 self->write_pos = 0; | |
179 n -= margin; | |
180 self->rw_wrap = DIFF_WRAP; | |
181 } | |
182 memcpy(self->data + self->write_pos * self->element_size, | |
183 ((const char*) data) + ((write_elements - n) * self->element_size), | |
184 n * self->element_size); | |
185 self->write_pos += n; | |
186 | |
187 return write_elements; | |
188 } | |
189 } | |
190 | |
191 int WebRtc_MoveReadPtr(RingBuffer* self, int element_count) { | |
192 if (!self) { | |
193 return 0; | |
194 } | |
195 | |
196 { | |
197 // We need to be able to take care of negative changes, hence use "int" | |
198 // instead of "size_t". | |
199 const int free_elements = static_cast<int>(WebRtc_available_write(self)); | |
200 const int readable_elements = static_cast<int>(WebRtc_available_read(self)); | |
201 int read_pos = static_cast<int>(self->read_pos); | |
202 | |
203 if (element_count > readable_elements) { | |
204 element_count = readable_elements; | |
205 } | |
206 if (element_count < -free_elements) { | |
207 element_count = -free_elements; | |
208 } | |
209 | |
210 read_pos += element_count; | |
211 if (read_pos > static_cast<int>(self->element_count)) { | |
212 // Buffer wrap around. Restart read position and wrap indicator. | |
213 read_pos -= static_cast<int>(self->element_count); | |
214 self->rw_wrap = SAME_WRAP; | |
215 } | |
216 if (read_pos < 0) { | |
217 // Buffer wrap around. Restart read position and wrap indicator. | |
218 read_pos += static_cast<int>(self->element_count); | |
219 self->rw_wrap = DIFF_WRAP; | |
220 } | |
221 | |
222 self->read_pos = static_cast<size_t>(read_pos); | |
223 | |
224 return element_count; | |
225 } | |
226 } | |
227 | |
228 size_t WebRtc_available_read(const RingBuffer* self) { | |
229 if (!self) { | |
230 return 0; | |
231 } | |
232 | |
233 if (self->rw_wrap == SAME_WRAP) { | |
234 return self->write_pos - self->read_pos; | |
235 } else { | |
236 return self->element_count - self->read_pos + self->write_pos; | |
237 } | |
238 } | |
239 | |
240 size_t WebRtc_available_write(const RingBuffer* self) { | |
241 if (!self) { | |
242 return 0; | |
243 } | |
244 | |
245 return self->element_count - WebRtc_available_read(self); | |
246 } | |
OLD | NEW |