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

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: refinements 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/typedefs.h" 18 #include "webrtc/typedefs.h"
19 19
20 namespace webrtc { 20 namespace webrtc {
21 21
22 AudioVector::AudioVector() 22 AudioVector::AudioVector()
23 : array_(new int16_t[kDefaultInitialSize]), 23 : array_(new int16_t[kDefaultInitialSize + 1]),
hlundin-webrtc 2016/05/10 07:53:18 You can just delegate this to the other ctor: Audi
minyue-webrtc 2016/05/10 12:48:07 Done.
24 first_free_ix_(0), 24 capacity_(kDefaultInitialSize + 1),
25 capacity_(kDefaultInitialSize) { 25 begin_index_(0),
26 end_index_(begin_index_) {
26 } 27 }
27 28
28 AudioVector::AudioVector(size_t initial_size) 29 AudioVector::AudioVector(size_t initial_size)
29 : array_(new int16_t[initial_size]), 30 : array_(new int16_t[initial_size + 1]),
30 first_free_ix_(initial_size), 31 capacity_(initial_size + 1),
31 capacity_(initial_size) { 32 begin_index_(0),
32 memset(array_.get(), 0, initial_size * sizeof(int16_t)); 33 end_index_(capacity_ - 1) {
34 memset(array_.get(), 0, capacity_ * sizeof(int16_t));
33 } 35 }
34 36
35 AudioVector::~AudioVector() = default; 37 AudioVector::~AudioVector() = default;
36 38
37 void AudioVector::Clear() { 39 void AudioVector::Clear() {
38 first_free_ix_ = 0; 40 end_index_ = begin_index_ = 0;
39 } 41 }
40 42
41 void AudioVector::CopyTo(AudioVector* copy_to) const { 43 void AudioVector::CopyTo(AudioVector* copy_to) const {
42 if (copy_to) { 44 if (!copy_to)
hlundin-webrtc 2016/05/10 07:53:17 Simply RTC_DCHECK(copy_to). I think the old implem
minyue-webrtc 2016/05/10 12:48:07 Done.
43 copy_to->Reserve(Size()); 45 return;
44 assert(copy_to->capacity_ >= Size()); 46 copy_to->Reserve(Size());
45 memcpy(copy_to->array_.get(), array_.get(), Size() * sizeof(int16_t)); 47 CopyTo(Size(), 0, copy_to->array_.get());
46 copy_to->first_free_ix_ = first_free_ix_; 48 copy_to->begin_index_ = 0;
49 copy_to->end_index_ = Size();
50 }
51
52 void AudioVector::CopyTo(
53 size_t length, size_t position, int16_t* copy_to) const {
54 if (length == 0)
55 return;
56 length = std::min(length, Size() - position);
57 const size_t copy_index = (begin_index_ + position) % capacity_;
58 const size_t first_chunk_length =
59 std::min(length, capacity_ - copy_index);
60 memcpy(copy_to, &array_[copy_index],
61 first_chunk_length * sizeof(int16_t));
62 const size_t remaining_length = length - first_chunk_length;
63 if (remaining_length > 0) {
64 memcpy(&copy_to[first_chunk_length], array_.get(),
65 remaining_length * sizeof(int16_t));
47 } 66 }
48 } 67 }
49 68
50 void AudioVector::PushFront(const AudioVector& prepend_this) { 69 void AudioVector::PushFront(const AudioVector& prepend_this) {
51 size_t insert_length = prepend_this.Size(); 70 const size_t length = prepend_this.Size();
52 Reserve(Size() + insert_length); 71 if (length == 0)
53 memmove(&array_[insert_length], &array_[0], Size() * sizeof(int16_t)); 72 return;
54 memcpy(&array_[0], &prepend_this.array_[0], insert_length * sizeof(int16_t)); 73
55 first_free_ix_ += insert_length; 74 // Although the subsequent calling to PushFront does Reserve in it, it is
75 // always more efficient to do a big Reserve first.
76 Reserve(Size() + length);
77
78 const size_t first_chunk_length =
79 std::min(length, prepend_this.capacity_ - prepend_this.begin_index_);
80 const size_t remaining_length = length - first_chunk_length;
81 if (remaining_length > 0)
82 PushFront(prepend_this.array_.get(), remaining_length);
83 PushFront(&prepend_this.array_[prepend_this.begin_index_],
84 first_chunk_length);
56 } 85 }
57 86
58 void AudioVector::PushFront(const int16_t* prepend_this, size_t length) { 87 void AudioVector::PushFront(const int16_t* prepend_this, size_t length) {
59 // Same operation as InsertAt beginning. 88 if (length == 0)
60 InsertAt(prepend_this, length, 0); 89 return;
90 Reserve(Size() + length);
91 const size_t first_chunk_length = std::min(length, begin_index_);
92 memcpy(&array_[begin_index_ - first_chunk_length],
93 &prepend_this[length - first_chunk_length],
94 first_chunk_length * sizeof(int16_t));
95 const size_t remaining_length = length - first_chunk_length;
96 if (remaining_length > 0) {
97 memcpy(&array_[capacity_ - remaining_length], prepend_this,
98 remaining_length * sizeof(int16_t));
99 }
100 begin_index_ = (begin_index_ + capacity_ - length) % capacity_;
61 } 101 }
62 102
63 void AudioVector::PushBack(const AudioVector& append_this) { 103 void AudioVector::PushBack(const AudioVector& append_this) {
64 PushBack(append_this.array_.get(), append_this.Size()); 104 PushBack(append_this, append_this.Size(), 0);
105 }
106
107 void AudioVector::PushBack(
108 const AudioVector& append_this, size_t length, size_t position) {
109 position = std::min(append_this.Size(), position);
hlundin-webrtc 2016/05/10 07:53:18 Is it valid to call with a position larger than Si
minyue-webrtc 2016/05/10 12:48:07 good point. since |length| and |position| refers t
110 length = std::min(length, append_this.Size() - position);
hlundin-webrtc 2016/05/10 07:53:17 Same with length...
minyue-webrtc 2016/05/10 12:48:07 Done.
111 if (length == 0)
112 return;
113
114 // Although the subsequent calling to PushBack does Reserve in it, it is
115 // always more efficient to do a big Reserve first.
116 Reserve(Size() + length);
117
118 const size_t start_index =
119 (append_this.begin_index_ + position) % append_this.capacity_;
120 const size_t first_chunk_length = std::min(
121 length, append_this.capacity_ - start_index);
122 PushBack(&append_this.array_[start_index], first_chunk_length);
123
124 const size_t remaining_length = length - first_chunk_length;
125 if (remaining_length > 0)
126 PushBack(append_this.array_.get(), remaining_length);
65 } 127 }
66 128
67 void AudioVector::PushBack(const int16_t* append_this, size_t length) { 129 void AudioVector::PushBack(const int16_t* append_this, size_t length) {
68 Reserve(Size() + length); 130 if (length == 0)
69 memcpy(&array_[first_free_ix_], append_this, length * sizeof(int16_t)); 131 return;
70 first_free_ix_ += length; 132 Reserve(Size() + length);
133 const size_t first_chunk_length = std::min(length, capacity_ - end_index_);
134 memcpy(&array_[end_index_], append_this,
135 first_chunk_length * sizeof(int16_t));
136 const size_t remaining_length = length - first_chunk_length;
137 if (remaining_length > 0) {
138 memcpy(array_.get(), &append_this[first_chunk_length],
139 remaining_length * sizeof(int16_t));
140 }
141 end_index_ = (end_index_ + length) % capacity_;
71 } 142 }
72 143
73 void AudioVector::PopFront(size_t length) { 144 void AudioVector::PopFront(size_t length) {
74 if (length >= Size()) { 145 if (length == 0)
75 // Remove all elements. 146 return;
76 Clear(); 147 length = std::min(length, Size());
77 } else { 148 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 } 149 }
83 150
84 void AudioVector::PopBack(size_t length) { 151 void AudioVector::PopBack(size_t length) {
152 if (length == 0)
153 return;
85 // Never remove more than what is in the array. 154 // Never remove more than what is in the array.
86 length = std::min(length, Size()); 155 length = std::min(length, Size());
87 first_free_ix_ -= length; 156 end_index_ = (end_index_ + capacity_ - length) % capacity_;
88 } 157 }
89 158
90 void AudioVector::Extend(size_t extra_length) { 159 void AudioVector::Extend(size_t extra_length) {
91 Reserve(Size() + extra_length); 160 if (extra_length == 0)
92 memset(&array_[first_free_ix_], 0, extra_length * sizeof(int16_t)); 161 return;
93 first_free_ix_ += extra_length; 162 InsertZerosByPushBack(extra_length, Size());
94 } 163 }
95 164
96 void AudioVector::InsertAt(const int16_t* insert_this, 165 void AudioVector::InsertAt(const int16_t* insert_this,
97 size_t length, 166 size_t length,
98 size_t position) { 167 size_t position) {
99 Reserve(Size() + length); 168 if (length == 0)
100 // Cap the position at the current vector length, to be sure the iterator 169 return;
101 // does not extend beyond the end of the vector. 170 // Cap the insert position at the current array length.
102 position = std::min(Size(), position); 171 position = std::min(Size(), position);
103 int16_t* insert_position_ptr = &array_[position]; 172
104 size_t samples_to_move = Size() - position; 173 if (position <= Size() - position) {
hlundin-webrtc 2016/05/10 07:53:18 Please, add a comment about what this if-statement
minyue-webrtc 2016/05/10 12:48:07 Done.
105 memmove(insert_position_ptr + length, insert_position_ptr, 174 InsertByPushFront(insert_this, length, position);
106 samples_to_move * sizeof(int16_t)); 175 } else {
107 memcpy(insert_position_ptr, insert_this, length * sizeof(int16_t)); 176 InsertByPushBack(insert_this, length, position);
108 first_free_ix_ += length; 177 }
109 } 178 }
110 179
111 void AudioVector::InsertZerosAt(size_t length, 180 void AudioVector::InsertZerosAt(size_t length,
112 size_t position) { 181 size_t position) {
113 Reserve(Size() + length); 182 if (length == 0)
114 // Cap the position at the current vector length, to be sure the iterator 183 return;
115 // does not extend beyond the end of the vector. 184 // Cap the insert position at the current array length.
116 position = std::min(capacity_, position); 185 position = std::min(Size(), position);
117 int16_t* insert_position_ptr = &array_[position]; 186
118 size_t samples_to_move = Size() - position; 187 if (position <= Size() - position) {
hlundin-webrtc 2016/05/10 07:53:18 Comment again.
minyue-webrtc 2016/05/10 12:48:07 Done.
119 memmove(insert_position_ptr + length, insert_position_ptr, 188 InsertZerosByPushFront(length, position);
120 samples_to_move * sizeof(int16_t)); 189 } else {
121 memset(insert_position_ptr, 0, length * sizeof(int16_t)); 190 InsertZerosByPushBack(length, position);
122 first_free_ix_ += length; 191 }
192 }
193
194 void AudioVector::OverwriteAt(const AudioVector& insert_this,
195 size_t length,
196 size_t position) {
197 length = std::min(length, insert_this.Size());
198 if (length == 0)
199 return;
200
201 position = std::min(Size(), position);
202 const size_t first_chunk_length =
203 std::min(length, insert_this.capacity_ - insert_this.begin_index_);
204 OverwriteAt(&insert_this.array_[insert_this.begin_index_], first_chunk_length,
205 position);
206 const size_t remaining_length = length - first_chunk_length;
207 if (remaining_length > 0) {
208 OverwriteAt(insert_this.array_.get(), remaining_length,
209 position + first_chunk_length);
hlundin-webrtc 2016/05/10 07:53:18 What if position + first_chunk_length > Size()? Th
minyue-webrtc 2016/05/10 12:48:07 OverwriteAt(const int16_t* insert_this will reserv
210 }
123 } 211 }
124 212
125 void AudioVector::OverwriteAt(const int16_t* insert_this, 213 void AudioVector::OverwriteAt(const int16_t* insert_this,
126 size_t length, 214 size_t length,
127 size_t position) { 215 size_t position) {
216 if (length == 0)
217 return;
128 // Cap the insert position at the current array length. 218 // Cap the insert position at the current array length.
129 position = std::min(Size(), position); 219 position = std::min(Size(), position);
130 Reserve(position + length); 220
131 memcpy(&array_[position], insert_this, length * sizeof(int16_t)); 221 size_t new_size = std::max(Size(), position + length);
132 if (position + length > Size()) { 222 Reserve(new_size);
133 // Array was expanded. 223
134 first_free_ix_ += position + length - Size(); 224 const size_t overwrite_index = (begin_index_ + position) % capacity_;
135 } 225 const size_t first_chunk_length =
226 std::min(length, capacity_ - overwrite_index);
227 memcpy(&array_[overwrite_index], insert_this,
228 first_chunk_length * sizeof(int16_t));
229 const size_t remaining_length = length - first_chunk_length;
230 if (remaining_length > 0) {
231 memcpy(array_.get(), &insert_this[first_chunk_length],
232 remaining_length * sizeof(int16_t));
233 }
234
235 end_index_ = (begin_index_ + new_size) % capacity_;
136 } 236 }
137 237
138 void AudioVector::CrossFade(const AudioVector& append_this, 238 void AudioVector::CrossFade(const AudioVector& append_this,
139 size_t fade_length) { 239 size_t fade_length) {
140 // Fade length cannot be longer than the current vector or |append_this|. 240 // Fade length cannot be longer than the current vector or |append_this|.
141 assert(fade_length <= Size()); 241 assert(fade_length <= Size());
142 assert(fade_length <= append_this.Size()); 242 assert(fade_length <= append_this.Size());
143 fade_length = std::min(fade_length, Size()); 243 fade_length = std::min(fade_length, Size());
144 fade_length = std::min(fade_length, append_this.Size()); 244 fade_length = std::min(fade_length, append_this.Size());
145 size_t position = Size() - fade_length; 245 size_t position = Size() - fade_length + begin_index_;
146 // Cross fade the overlapping regions. 246 // Cross fade the overlapping regions.
147 // |alpha| is the mixing factor in Q14. 247 // |alpha| is the mixing factor in Q14.
148 // TODO(hlundin): Consider skipping +1 in the denominator to produce a 248 // TODO(hlundin): Consider skipping +1 in the denominator to produce a
149 // smoother cross-fade, in particular at the end of the fade. 249 // smoother cross-fade, in particular at the end of the fade.
150 int alpha_step = 16384 / (static_cast<int>(fade_length) + 1); 250 int alpha_step = 16384 / (static_cast<int>(fade_length) + 1);
151 int alpha = 16384; 251 int alpha = 16384;
152 for (size_t i = 0; i < fade_length; ++i) { 252 for (size_t i = 0; i < fade_length; ++i) {
153 alpha -= alpha_step; 253 alpha -= alpha_step;
154 array_[position + i] = (alpha * array_[position + i] + 254 array_[(position + i) % capacity_] =
155 (16384 - alpha) * append_this[i] + 8192) >> 14; 255 (alpha * array_[(position + i) % capacity_] +
256 (16384 - alpha) * append_this[i] + 8192) >> 14;
156 } 257 }
157 assert(alpha >= 0); // Verify that the slope was correct. 258 assert(alpha >= 0); // Verify that the slope was correct.
158 // Append what is left of |append_this|. 259 // Append what is left of |append_this|.
159 size_t samples_to_push_back = append_this.Size() - fade_length; 260 size_t samples_to_push_back = append_this.Size() - fade_length;
160 if (samples_to_push_back > 0) 261 if (samples_to_push_back > 0)
161 PushBack(&append_this[fade_length], samples_to_push_back); 262 PushBack(append_this, samples_to_push_back, fade_length);
162 } 263 }
163 264
164 // Returns the number of elements in this AudioVector. 265 // Returns the number of elements in this AudioVector.
165 size_t AudioVector::Size() const { 266 size_t AudioVector::Size() const {
166 return first_free_ix_; 267 return (end_index_ + capacity_ - begin_index_) % capacity_;
167 } 268 }
168 269
169 // Returns true if this AudioVector is empty. 270 // Returns true if this AudioVector is empty.
170 bool AudioVector::Empty() const { 271 bool AudioVector::Empty() const {
171 return first_free_ix_ == 0; 272 return begin_index_ == end_index_;
172 } 273 }
173 274
174 const int16_t& AudioVector::operator[](size_t index) const { 275 const int16_t& AudioVector::operator[](size_t index) const {
175 return array_[index]; 276 return array_[(begin_index_ + index) % capacity_];
176 } 277 }
177 278
178 int16_t& AudioVector::operator[](size_t index) { 279 int16_t& AudioVector::operator[](size_t index) {
179 return array_[index]; 280 return array_[(begin_index_ + index) % capacity_];
180 } 281 }
181 282
182 void AudioVector::Reserve(size_t n) { 283 void AudioVector::Reserve(size_t n) {
183 if (capacity_ < n) { 284 if (capacity_ > n)
184 std::unique_ptr<int16_t[]> temp_array(new int16_t[n]); 285 return;
185 memcpy(temp_array.get(), array_.get(), Size() * sizeof(int16_t)); 286 const size_t length = Size();
186 array_.swap(temp_array); 287 // Reserve one more sample to remove the ambiguity between empty vector and
187 capacity_ = n; 288 // full vector. Therefore |begin_index_| == |end_index_| indicates empty
289 // vector, and |begin_index_| == (|end_index_| + 1) % capacity indicates
290 // full vector.
291 std::unique_ptr<int16_t[]> temp_array(new int16_t[n + 1]);
292 const size_t first_chunk_length =
hlundin-webrtc 2016/05/10 07:53:18 Why not use the CopyTo method?
minyue-webrtc 2016/05/10 12:48:07 very good point, I should have used it. Thanks!
293 std::min(length, capacity_ - begin_index_);
294 memcpy(temp_array.get(), &array_[begin_index_],
295 first_chunk_length * sizeof(int16_t));
296 const size_t remaining_length = length - first_chunk_length;
297 if (remaining_length > 0) {
298 memcpy(&temp_array[first_chunk_length], array_.get(),
299 remaining_length * sizeof(int16_t));
188 } 300 }
301 array_.swap(temp_array);
302 begin_index_ = 0;
303 end_index_ = length;
304 capacity_ = n + 1;
305 }
306
307 void AudioVector::InsertByPushBack(const int16_t* insert_this,
308 size_t length,
309 size_t position) {
310 const size_t move_chunk_length = Size() - position;
311 std::unique_ptr<int16_t[]> temp_array(nullptr);
312 if (move_chunk_length > 0) {
313 temp_array.reset(new int16_t[move_chunk_length]);
hlundin-webrtc 2016/05/10 07:53:18 It seems inefficient to me to store the move-chunk
minyue-webrtc 2016/05/10 12:48:07 I thought about it, but it can be a bit complicate
314 CopyTo(move_chunk_length, position, temp_array.get());
315 PopBack(move_chunk_length);
316 }
317
318 Reserve(Size() + length + move_chunk_length);
319 PushBack(insert_this, length);
320 if (move_chunk_length > 0)
321 PushBack(temp_array.get(), move_chunk_length);
322 }
323
324 void AudioVector::InsertByPushFront(const int16_t* insert_this,
325 size_t length,
326 size_t position) {
327 std::unique_ptr<int16_t[]> temp_array(nullptr);
328 if (position > 0) {
329 temp_array.reset(new int16_t[position]);
330 CopyTo(position, 0, temp_array.get());
331 PopFront(position);
332 }
333
334 Reserve(Size() + length + position);
335 PushFront(insert_this, length);
336 if (position > 0)
337 PushFront(temp_array.get(), position);
338 }
339
340 void AudioVector::InsertZerosByPushBack(size_t length,
341 size_t position) {
342 const size_t move_chunk_length = Size() - position;
343 std::unique_ptr<int16_t[]> temp_array(nullptr);
344 if (move_chunk_length > 0) {
345 temp_array.reset(new int16_t[move_chunk_length]);
346 CopyTo(move_chunk_length, position, temp_array.get());
347 PopBack(move_chunk_length);
348 }
349
350 Reserve(Size() + length + move_chunk_length);
351
352 const size_t first_zero_chunk_length =
353 std::min(length, capacity_ - end_index_);
354 memset(&array_[end_index_], 0, first_zero_chunk_length * sizeof(int16_t));
355 const size_t remaining_zero_length = length - first_zero_chunk_length;
356 if (remaining_zero_length > 0)
357 memset(array_.get(), 0, remaining_zero_length * sizeof(int16_t));
358 end_index_ = (end_index_ + length) % capacity_;
359
360 if (move_chunk_length > 0)
361 PushBack(temp_array.get(), move_chunk_length);
362 }
363
364 void AudioVector::InsertZerosByPushFront(size_t length,
365 size_t position) {
366 std::unique_ptr<int16_t[]> temp_array(nullptr);
367 if (position > 0) {
368 temp_array.reset(new int16_t[position]);
369 CopyTo(position, 0, temp_array.get());
370 PopFront(position);
371 }
372
373 Reserve(Size() + length + position);
374
375 const size_t first_zero_chunk_length = std::min(length, begin_index_);
376 memset(&array_[begin_index_ - first_zero_chunk_length], 0,
377 first_zero_chunk_length * sizeof(int16_t));
378 const size_t remaining_zero_length = length - first_zero_chunk_length;
379 if (remaining_zero_length > 0)
380 memset(&array_[capacity_ - remaining_zero_length], 0,
381 remaining_zero_length * sizeof(int16_t));
382 begin_index_ = (begin_index_ + capacity_ - length) % capacity_;
383
384 if (position > 0)
385 PushFront(temp_array.get(), position);
189 } 386 }
190 387
191 } // namespace webrtc 388 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698