Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(32)

Side by Side Diff: webrtc/modules/audio_coding/neteq/audio_vector.cc

Issue 1948483002: Using ring buffer for AudioVector in NetEq. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: removing a unittest Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #include "webrtc/modules/audio_coding/neteq/audio_vector.h" 11 #include "webrtc/modules/audio_coding/neteq/audio_vector.h"
12 12
13 #include <assert.h> 13 #include <assert.h>
14 14
15 #include <algorithm> 15 #include <algorithm>
16 #include <memory> 16 #include <memory>
17 17
18 #include "webrtc/base/checks.h"
18 #include "webrtc/typedefs.h" 19 #include "webrtc/typedefs.h"
19 20
20 namespace webrtc { 21 namespace webrtc {
21 22
22 AudioVector::AudioVector() 23 AudioVector::AudioVector()
23 : array_(new int16_t[kDefaultInitialSize]), 24 : AudioVector(kDefaultInitialSize) {
24 first_free_ix_(0), 25 Clear();
25 capacity_(kDefaultInitialSize) {
26 } 26 }
27 27
28 AudioVector::AudioVector(size_t initial_size) 28 AudioVector::AudioVector(size_t initial_size)
29 : array_(new int16_t[initial_size]), 29 : array_(new int16_t[initial_size + 1]),
30 first_free_ix_(initial_size), 30 capacity_(initial_size + 1),
31 capacity_(initial_size) { 31 begin_index_(0),
32 memset(array_.get(), 0, initial_size * sizeof(int16_t)); 32 end_index_(capacity_ - 1) {
33 memset(array_.get(), 0, capacity_ * sizeof(int16_t));
33 } 34 }
34 35
35 AudioVector::~AudioVector() = default; 36 AudioVector::~AudioVector() = default;
36 37
37 void AudioVector::Clear() { 38 void AudioVector::Clear() {
38 first_free_ix_ = 0; 39 end_index_ = begin_index_ = 0;
39 } 40 }
40 41
41 void AudioVector::CopyTo(AudioVector* copy_to) const { 42 void AudioVector::CopyTo(AudioVector* copy_to) const {
42 if (copy_to) { 43 RTC_DCHECK(copy_to);
43 copy_to->Reserve(Size()); 44 copy_to->Reserve(Size());
44 assert(copy_to->capacity_ >= Size()); 45 CopyTo(Size(), 0, copy_to->array_.get());
45 memcpy(copy_to->array_.get(), array_.get(), Size() * sizeof(int16_t)); 46 copy_to->begin_index_ = 0;
46 copy_to->first_free_ix_ = first_free_ix_; 47 copy_to->end_index_ = Size();
48 }
49
50 void AudioVector::CopyTo(
51 size_t length, size_t position, int16_t* copy_to) const {
52 if (length == 0)
53 return;
54 length = std::min(length, Size() - position);
55 const size_t copy_index = (begin_index_ + position) % capacity_;
56 const size_t first_chunk_length =
57 std::min(length, capacity_ - copy_index);
58 memcpy(copy_to, &array_[copy_index],
59 first_chunk_length * sizeof(int16_t));
60 const size_t remaining_length = length - first_chunk_length;
61 if (remaining_length > 0) {
62 memcpy(&copy_to[first_chunk_length], array_.get(),
63 remaining_length * sizeof(int16_t));
47 } 64 }
48 } 65 }
49 66
50 void AudioVector::PushFront(const AudioVector& prepend_this) { 67 void AudioVector::PushFront(const AudioVector& prepend_this) {
51 size_t insert_length = prepend_this.Size(); 68 const size_t length = prepend_this.Size();
52 Reserve(Size() + insert_length); 69 if (length == 0)
53 memmove(&array_[insert_length], &array_[0], Size() * sizeof(int16_t)); 70 return;
54 memcpy(&array_[0], &prepend_this.array_[0], insert_length * sizeof(int16_t)); 71
55 first_free_ix_ += insert_length; 72 // Although the subsequent calling to PushFront does Reserve in it, it is
73 // always more efficient to do a big Reserve first.
74 Reserve(Size() + length);
75
76 const size_t first_chunk_length =
77 std::min(length, prepend_this.capacity_ - prepend_this.begin_index_);
78 const size_t remaining_length = length - first_chunk_length;
79 if (remaining_length > 0)
80 PushFront(prepend_this.array_.get(), remaining_length);
81 PushFront(&prepend_this.array_[prepend_this.begin_index_],
82 first_chunk_length);
56 } 83 }
57 84
58 void AudioVector::PushFront(const int16_t* prepend_this, size_t length) { 85 void AudioVector::PushFront(const int16_t* prepend_this, size_t length) {
59 // Same operation as InsertAt beginning. 86 if (length == 0)
60 InsertAt(prepend_this, length, 0); 87 return;
88 Reserve(Size() + length);
89 const size_t first_chunk_length = std::min(length, begin_index_);
90 memcpy(&array_[begin_index_ - first_chunk_length],
91 &prepend_this[length - first_chunk_length],
92 first_chunk_length * sizeof(int16_t));
93 const size_t remaining_length = length - first_chunk_length;
94 if (remaining_length > 0) {
95 memcpy(&array_[capacity_ - remaining_length], prepend_this,
96 remaining_length * sizeof(int16_t));
97 }
98 begin_index_ = (begin_index_ + capacity_ - length) % capacity_;
61 } 99 }
62 100
63 void AudioVector::PushBack(const AudioVector& append_this) { 101 void AudioVector::PushBack(const AudioVector& append_this) {
64 PushBack(append_this.array_.get(), append_this.Size()); 102 PushBack(append_this, append_this.Size(), 0);
103 }
104
105 void AudioVector::PushBack(
106 const AudioVector& append_this, size_t length, size_t position) {
107 RTC_DCHECK_LE(position, append_this.Size());
108 RTC_DCHECK_LE(length, append_this.Size() - position);
109
110 if (length == 0)
111 return;
112
113 // Although the subsequent calling to PushBack does Reserve in it, it is
114 // always more efficient to do a big Reserve first.
115 Reserve(Size() + length);
116
117 const size_t start_index =
118 (append_this.begin_index_ + position) % append_this.capacity_;
119 const size_t first_chunk_length = std::min(
120 length, append_this.capacity_ - start_index);
121 PushBack(&append_this.array_[start_index], first_chunk_length);
122
123 const size_t remaining_length = length - first_chunk_length;
124 if (remaining_length > 0)
125 PushBack(append_this.array_.get(), remaining_length);
65 } 126 }
66 127
67 void AudioVector::PushBack(const int16_t* append_this, size_t length) { 128 void AudioVector::PushBack(const int16_t* append_this, size_t length) {
68 Reserve(Size() + length); 129 if (length == 0)
69 memcpy(&array_[first_free_ix_], append_this, length * sizeof(int16_t)); 130 return;
70 first_free_ix_ += length; 131 Reserve(Size() + length);
132 const size_t first_chunk_length = std::min(length, capacity_ - end_index_);
133 memcpy(&array_[end_index_], append_this,
134 first_chunk_length * sizeof(int16_t));
135 const size_t remaining_length = length - first_chunk_length;
136 if (remaining_length > 0) {
137 memcpy(array_.get(), &append_this[first_chunk_length],
138 remaining_length * sizeof(int16_t));
139 }
140 end_index_ = (end_index_ + length) % capacity_;
71 } 141 }
72 142
73 void AudioVector::PopFront(size_t length) { 143 void AudioVector::PopFront(size_t length) {
74 if (length >= Size()) { 144 if (length == 0)
75 // Remove all elements. 145 return;
76 Clear(); 146 length = std::min(length, Size());
77 } else { 147 begin_index_ = (begin_index_ + length) % capacity_;
78 size_t remaining_samples = Size() - length;
79 memmove(&array_[0], &array_[length], remaining_samples * sizeof(int16_t));
80 first_free_ix_ -= length;
81 }
82 } 148 }
83 149
84 void AudioVector::PopBack(size_t length) { 150 void AudioVector::PopBack(size_t length) {
151 if (length == 0)
152 return;
85 // Never remove more than what is in the array. 153 // Never remove more than what is in the array.
86 length = std::min(length, Size()); 154 length = std::min(length, Size());
87 first_free_ix_ -= length; 155 end_index_ = (end_index_ + capacity_ - length) % capacity_;
88 } 156 }
89 157
90 void AudioVector::Extend(size_t extra_length) { 158 void AudioVector::Extend(size_t extra_length) {
91 Reserve(Size() + extra_length); 159 if (extra_length == 0)
92 memset(&array_[first_free_ix_], 0, extra_length * sizeof(int16_t)); 160 return;
93 first_free_ix_ += extra_length; 161 InsertZerosByPushBack(extra_length, Size());
94 } 162 }
95 163
96 void AudioVector::InsertAt(const int16_t* insert_this, 164 void AudioVector::InsertAt(const int16_t* insert_this,
97 size_t length, 165 size_t length,
98 size_t position) { 166 size_t position) {
99 Reserve(Size() + length); 167 if (length == 0)
100 // Cap the position at the current vector length, to be sure the iterator 168 return;
101 // does not extend beyond the end of the vector. 169 // Cap the insert position at the current array length.
102 position = std::min(Size(), position); 170 position = std::min(Size(), position);
103 int16_t* insert_position_ptr = &array_[position]; 171
104 size_t samples_to_move = Size() - position; 172 // When inserting to a position closer to the beginning, it is more efficient
105 memmove(insert_position_ptr + length, insert_position_ptr, 173 // to insert by pushing front than to insert by pushing back, since less data
106 samples_to_move * sizeof(int16_t)); 174 // will be moved, vice versa.
107 memcpy(insert_position_ptr, insert_this, length * sizeof(int16_t)); 175 if (position <= Size() - position) {
108 first_free_ix_ += length; 176 InsertByPushFront(insert_this, length, position);
177 } else {
178 InsertByPushBack(insert_this, length, position);
179 }
109 } 180 }
110 181
111 void AudioVector::InsertZerosAt(size_t length, 182 void AudioVector::InsertZerosAt(size_t length,
112 size_t position) { 183 size_t position) {
113 Reserve(Size() + length); 184 if (length == 0)
114 // Cap the position at the current vector length, to be sure the iterator 185 return;
115 // does not extend beyond the end of the vector. 186 // Cap the insert position at the current array length.
116 position = std::min(capacity_, position); 187 position = std::min(Size(), position);
117 int16_t* insert_position_ptr = &array_[position]; 188
118 size_t samples_to_move = Size() - position; 189 // When inserting to a position closer to the beginning, it is more efficient
119 memmove(insert_position_ptr + length, insert_position_ptr, 190 // to insert by pushing front than to insert by pushing back, since less data
120 samples_to_move * sizeof(int16_t)); 191 // will be moved, vice versa.
121 memset(insert_position_ptr, 0, length * sizeof(int16_t)); 192 if (position <= Size() - position) {
122 first_free_ix_ += length; 193 InsertZerosByPushFront(length, position);
194 } else {
195 InsertZerosByPushBack(length, position);
196 }
197 }
198
199 void AudioVector::OverwriteAt(const AudioVector& insert_this,
200 size_t length,
201 size_t position) {
202 RTC_DCHECK_LE(length, insert_this.Size());
203 if (length == 0)
204 return;
205
206 // Cap the insert position at the current array length.
207 position = std::min(Size(), position);
208
209 // Although the subsequent calling to OverwriteAt does Reserve in it, it is
210 // always more efficient to do a big Reserve first.
211 size_t new_size = std::max(Size(), position + length);
212 Reserve(new_size);
213
214 const size_t first_chunk_length =
215 std::min(length, insert_this.capacity_ - insert_this.begin_index_);
216 OverwriteAt(&insert_this.array_[insert_this.begin_index_], first_chunk_length,
217 position);
218 const size_t remaining_length = length - first_chunk_length;
219 if (remaining_length > 0) {
220 OverwriteAt(insert_this.array_.get(), remaining_length,
221 position + first_chunk_length);
222 }
123 } 223 }
124 224
125 void AudioVector::OverwriteAt(const int16_t* insert_this, 225 void AudioVector::OverwriteAt(const int16_t* insert_this,
126 size_t length, 226 size_t length,
127 size_t position) { 227 size_t position) {
128 // Cap the insert position at the current array length. 228 if (length == 0)
129 position = std::min(Size(), position); 229 return;
130 Reserve(position + length); 230 // Cap the insert position at the current array length.
131 memcpy(&array_[position], insert_this, length * sizeof(int16_t)); 231 position = std::min(Size(), position);
132 if (position + length > Size()) { 232
133 // Array was expanded. 233 size_t new_size = std::max(Size(), position + length);
134 first_free_ix_ += position + length - Size(); 234 Reserve(new_size);
135 } 235
236 const size_t overwrite_index = (begin_index_ + position) % capacity_;
237 const size_t first_chunk_length =
238 std::min(length, capacity_ - overwrite_index);
239 memcpy(&array_[overwrite_index], insert_this,
240 first_chunk_length * sizeof(int16_t));
241 const size_t remaining_length = length - first_chunk_length;
242 if (remaining_length > 0) {
243 memcpy(array_.get(), &insert_this[first_chunk_length],
244 remaining_length * sizeof(int16_t));
245 }
246
247 end_index_ = (begin_index_ + new_size) % capacity_;
136 } 248 }
137 249
138 void AudioVector::CrossFade(const AudioVector& append_this, 250 void AudioVector::CrossFade(const AudioVector& append_this,
139 size_t fade_length) { 251 size_t fade_length) {
140 // Fade length cannot be longer than the current vector or |append_this|. 252 // Fade length cannot be longer than the current vector or |append_this|.
141 assert(fade_length <= Size()); 253 assert(fade_length <= Size());
142 assert(fade_length <= append_this.Size()); 254 assert(fade_length <= append_this.Size());
143 fade_length = std::min(fade_length, Size()); 255 fade_length = std::min(fade_length, Size());
144 fade_length = std::min(fade_length, append_this.Size()); 256 fade_length = std::min(fade_length, append_this.Size());
145 size_t position = Size() - fade_length; 257 size_t position = Size() - fade_length + begin_index_;
146 // Cross fade the overlapping regions. 258 // Cross fade the overlapping regions.
147 // |alpha| is the mixing factor in Q14. 259 // |alpha| is the mixing factor in Q14.
148 // TODO(hlundin): Consider skipping +1 in the denominator to produce a 260 // TODO(hlundin): Consider skipping +1 in the denominator to produce a
149 // smoother cross-fade, in particular at the end of the fade. 261 // smoother cross-fade, in particular at the end of the fade.
150 int alpha_step = 16384 / (static_cast<int>(fade_length) + 1); 262 int alpha_step = 16384 / (static_cast<int>(fade_length) + 1);
151 int alpha = 16384; 263 int alpha = 16384;
152 for (size_t i = 0; i < fade_length; ++i) { 264 for (size_t i = 0; i < fade_length; ++i) {
153 alpha -= alpha_step; 265 alpha -= alpha_step;
154 array_[position + i] = (alpha * array_[position + i] + 266 array_[(position + i) % capacity_] =
155 (16384 - alpha) * append_this[i] + 8192) >> 14; 267 (alpha * array_[(position + i) % capacity_] +
268 (16384 - alpha) * append_this[i] + 8192) >> 14;
156 } 269 }
157 assert(alpha >= 0); // Verify that the slope was correct. 270 assert(alpha >= 0); // Verify that the slope was correct.
158 // Append what is left of |append_this|. 271 // Append what is left of |append_this|.
159 size_t samples_to_push_back = append_this.Size() - fade_length; 272 size_t samples_to_push_back = append_this.Size() - fade_length;
160 if (samples_to_push_back > 0) 273 if (samples_to_push_back > 0)
161 PushBack(&append_this[fade_length], samples_to_push_back); 274 PushBack(append_this, samples_to_push_back, fade_length);
162 } 275 }
163 276
164 // Returns the number of elements in this AudioVector. 277 // Returns the number of elements in this AudioVector.
165 size_t AudioVector::Size() const { 278 size_t AudioVector::Size() const {
166 return first_free_ix_; 279 return (end_index_ + capacity_ - begin_index_) % capacity_;
167 } 280 }
168 281
169 // Returns true if this AudioVector is empty. 282 // Returns true if this AudioVector is empty.
170 bool AudioVector::Empty() const { 283 bool AudioVector::Empty() const {
171 return first_free_ix_ == 0; 284 return begin_index_ == end_index_;
172 } 285 }
173 286
174 const int16_t& AudioVector::operator[](size_t index) const { 287 const int16_t& AudioVector::operator[](size_t index) const {
175 return array_[index]; 288 return array_[(begin_index_ + index) % capacity_];
176 } 289 }
177 290
178 int16_t& AudioVector::operator[](size_t index) { 291 int16_t& AudioVector::operator[](size_t index) {
179 return array_[index]; 292 return array_[(begin_index_ + index) % capacity_];
180 } 293 }
181 294
182 void AudioVector::Reserve(size_t n) { 295 void AudioVector::Reserve(size_t n) {
183 if (capacity_ < n) { 296 if (capacity_ > n)
184 std::unique_ptr<int16_t[]> temp_array(new int16_t[n]); 297 return;
185 memcpy(temp_array.get(), array_.get(), Size() * sizeof(int16_t)); 298 const size_t length = Size();
186 array_.swap(temp_array); 299 // Reserve one more sample to remove the ambiguity between empty vector and
187 capacity_ = n; 300 // full vector. Therefore |begin_index_| == |end_index_| indicates empty
301 // vector, and |begin_index_| == (|end_index_| + 1) % capacity indicates
302 // full vector.
303 std::unique_ptr<int16_t[]> temp_array(new int16_t[n + 1]);
304 CopyTo(length, 0, temp_array.get());
305 array_.swap(temp_array);
306 begin_index_ = 0;
307 end_index_ = length;
308 capacity_ = n + 1;
309 }
310
311 void AudioVector::InsertByPushBack(const int16_t* insert_this,
312 size_t length,
313 size_t position) {
314 const size_t move_chunk_length = Size() - position;
315 std::unique_ptr<int16_t[]> temp_array(nullptr);
316 if (move_chunk_length > 0) {
317 // TODO(minyue): see if it is possible to avoid copying to a buffer.
318 temp_array.reset(new int16_t[move_chunk_length]);
319 CopyTo(move_chunk_length, position, temp_array.get());
320 PopBack(move_chunk_length);
188 } 321 }
322
323 Reserve(Size() + length + move_chunk_length);
324 PushBack(insert_this, length);
325 if (move_chunk_length > 0)
326 PushBack(temp_array.get(), move_chunk_length);
327 }
328
329 void AudioVector::InsertByPushFront(const int16_t* insert_this,
330 size_t length,
331 size_t position) {
332 std::unique_ptr<int16_t[]> temp_array(nullptr);
333 if (position > 0) {
334 // TODO(minyue): see if it is possible to avoid copying to a buffer.
335 temp_array.reset(new int16_t[position]);
336 CopyTo(position, 0, temp_array.get());
337 PopFront(position);
338 }
339
340 Reserve(Size() + length + position);
341 PushFront(insert_this, length);
342 if (position > 0)
343 PushFront(temp_array.get(), position);
344 }
345
346 void AudioVector::InsertZerosByPushBack(size_t length,
347 size_t position) {
348 const size_t move_chunk_length = Size() - position;
349 std::unique_ptr<int16_t[]> temp_array(nullptr);
350 if (move_chunk_length > 0) {
351 temp_array.reset(new int16_t[move_chunk_length]);
352 CopyTo(move_chunk_length, position, temp_array.get());
353 PopBack(move_chunk_length);
354 }
355
356 Reserve(Size() + length + move_chunk_length);
357
358 const size_t first_zero_chunk_length =
359 std::min(length, capacity_ - end_index_);
360 memset(&array_[end_index_], 0, first_zero_chunk_length * sizeof(int16_t));
361 const size_t remaining_zero_length = length - first_zero_chunk_length;
362 if (remaining_zero_length > 0)
363 memset(array_.get(), 0, remaining_zero_length * sizeof(int16_t));
364 end_index_ = (end_index_ + length) % capacity_;
365
366 if (move_chunk_length > 0)
367 PushBack(temp_array.get(), move_chunk_length);
368 }
369
370 void AudioVector::InsertZerosByPushFront(size_t length,
371 size_t position) {
372 std::unique_ptr<int16_t[]> temp_array(nullptr);
373 if (position > 0) {
374 temp_array.reset(new int16_t[position]);
375 CopyTo(position, 0, temp_array.get());
376 PopFront(position);
377 }
378
379 Reserve(Size() + length + position);
380
381 const size_t first_zero_chunk_length = std::min(length, begin_index_);
382 memset(&array_[begin_index_ - first_zero_chunk_length], 0,
383 first_zero_chunk_length * sizeof(int16_t));
384 const size_t remaining_zero_length = length - first_zero_chunk_length;
385 if (remaining_zero_length > 0)
386 memset(&array_[capacity_ - remaining_zero_length], 0,
387 remaining_zero_length * sizeof(int16_t));
388 begin_index_ = (begin_index_ + capacity_ - length) % capacity_;
389
390 if (position > 0)
391 PushFront(temp_array.get(), position);
189 } 392 }
190 393
191 } // namespace webrtc 394 } // namespace webrtc
OLDNEW
« no previous file with comments | « webrtc/modules/audio_coding/neteq/audio_vector.h ('k') | webrtc/modules/audio_coding/neteq/audio_vector_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698