1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "gmock/gmock.h"
7 #include "gtest/gtest-printers.h"
8 #include "gtest/gtest.h"
9
10 #include "DynamicResampler.h"
11
12 using namespace mozilla;
13
TEST(TestDynamicResampler,SameRates_Float1)14 TEST(TestDynamicResampler, SameRates_Float1)
15 {
16 const uint32_t in_frames = 100;
17 const uint32_t out_frames = 100;
18 uint32_t channels = 2;
19 uint32_t in_rate = 44100;
20 uint32_t out_rate = 44100;
21
22 DynamicResampler dr(in_rate, out_rate);
23 dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
24 EXPECT_EQ(dr.GetOutRate(), out_rate);
25 EXPECT_EQ(dr.GetChannels(), channels);
26
27 // float in_ch1[] = {.1, .2, .3, .4, .5, .6, .7, .8, .9, 1.0};
28 // float in_ch2[] = {.1, .2, .3, .4, .5, .6, .7, .8, .9, 1.0};
29 float in_ch1[in_frames] = {};
30 float in_ch2[in_frames] = {};
31 AutoTArray<const float*, 2> in_buffer;
32 in_buffer.AppendElements(channels);
33 in_buffer[0] = in_ch1;
34 in_buffer[1] = in_ch2;
35
36 float out_ch1[out_frames] = {};
37 float out_ch2[out_frames] = {};
38
39 // Warm up with zeros
40 dr.AppendInput(in_buffer, in_frames);
41 uint32_t out_frames_used = out_frames;
42 bool rv = dr.Resample(out_ch1, &out_frames_used, 0);
43 EXPECT_TRUE(rv);
44 EXPECT_EQ(out_frames_used, out_frames);
45 rv = dr.Resample(out_ch2, &out_frames_used, 1);
46 EXPECT_TRUE(rv);
47 EXPECT_EQ(out_frames_used, out_frames);
48 for (uint32_t i = 0; i < out_frames; ++i) {
49 EXPECT_FLOAT_EQ(in_ch1[i], out_ch1[i]);
50 EXPECT_FLOAT_EQ(in_ch2[i], out_ch2[i]);
51 }
52
53 // Continue with non zero
54 for (uint32_t i = 0; i < in_frames; ++i) {
55 in_ch1[i] = in_ch2[i] = 0.01f * i;
56 }
57 dr.AppendInput(in_buffer, in_frames);
58 out_frames_used = out_frames;
59 rv = dr.Resample(out_ch1, &out_frames_used, 0);
60 EXPECT_TRUE(rv);
61 EXPECT_EQ(out_frames_used, out_frames);
62 rv = dr.Resample(out_ch2, &out_frames_used, 1);
63 EXPECT_TRUE(rv);
64 EXPECT_EQ(out_frames_used, out_frames);
65 for (uint32_t i = 0; i < out_frames; ++i) {
66 EXPECT_FLOAT_EQ(in_ch1[i], out_ch1[i]);
67 EXPECT_FLOAT_EQ(in_ch2[i], out_ch2[i]);
68 }
69
70 // No more frames in the input buffer
71 rv = dr.Resample(out_ch1, &out_frames_used, 0);
72 EXPECT_FALSE(rv);
73 EXPECT_EQ(out_frames_used, 0u);
74 out_frames_used = 2;
75 rv = dr.Resample(out_ch2, &out_frames_used, 1);
76 EXPECT_FALSE(rv);
77 EXPECT_EQ(out_frames_used, 0u);
78 }
79
TEST(TestDynamicResampler,SameRates_Short1)80 TEST(TestDynamicResampler, SameRates_Short1)
81 {
82 uint32_t in_frames = 2;
83 uint32_t out_frames = 2;
84 uint32_t channels = 2;
85 uint32_t in_rate = 44100;
86 uint32_t out_rate = 44100;
87
88 DynamicResampler dr(in_rate, out_rate);
89 dr.SetSampleFormat(AUDIO_FORMAT_S16);
90 EXPECT_EQ(dr.GetOutRate(), out_rate);
91 EXPECT_EQ(dr.GetChannels(), channels);
92
93 short in_ch1[] = {1, 2, 3};
94 short in_ch2[] = {4, 5, 6};
95 AutoTArray<const short*, 2> in_buffer;
96 in_buffer.AppendElements(channels);
97 in_buffer[0] = in_ch1;
98 in_buffer[1] = in_ch2;
99
100 short out_ch1[3] = {};
101 short out_ch2[3] = {};
102
103 dr.AppendInput(in_buffer, in_frames);
104 bool rv = dr.Resample(out_ch1, &out_frames, 0);
105 EXPECT_TRUE(rv);
106 EXPECT_EQ(out_frames, 2u);
107 rv = dr.Resample(out_ch2, &out_frames, 1);
108 EXPECT_TRUE(rv);
109 EXPECT_EQ(out_frames, 2u);
110 for (uint32_t i = 0; i < out_frames; ++i) {
111 EXPECT_EQ(in_ch1[i], out_ch1[i]);
112 EXPECT_EQ(in_ch2[i], out_ch2[i]);
113 }
114
115 // No more frames in the input buffer
116 rv = dr.Resample(out_ch1, &out_frames, 0);
117 EXPECT_FALSE(rv);
118 EXPECT_EQ(out_frames, 0u);
119 out_frames = 2;
120 rv = dr.Resample(out_ch2, &out_frames, 1);
121 EXPECT_FALSE(rv);
122 EXPECT_EQ(out_frames, 0u);
123 }
124
TEST(TestDynamicResampler,SameRates_Float2)125 TEST(TestDynamicResampler, SameRates_Float2)
126 {
127 uint32_t in_frames = 3;
128 uint32_t out_frames = 2;
129 uint32_t channels = 2;
130 uint32_t in_rate = 44100;
131 uint32_t out_rate = 44100;
132
133 DynamicResampler dr(in_rate, out_rate);
134 dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
135
136 float in_ch1[] = {0.1, 0.2, 0.3};
137 float in_ch2[] = {0.4, 0.5, 0.6};
138 AutoTArray<const float*, 2> in_buffer;
139 in_buffer.AppendElements(channels);
140 in_buffer[0] = in_ch1;
141 in_buffer[1] = in_ch2;
142
143 float out_ch1[3] = {};
144 float out_ch2[3] = {};
145
146 dr.AppendInput(in_buffer, in_frames);
147 bool rv = dr.Resample(out_ch1, &out_frames, 0);
148 EXPECT_TRUE(rv);
149 EXPECT_EQ(out_frames, 2u);
150 rv = dr.Resample(out_ch2, &out_frames, 1);
151 EXPECT_TRUE(rv);
152 EXPECT_EQ(out_frames, 2u);
153 for (uint32_t i = 0; i < out_frames; ++i) {
154 EXPECT_FLOAT_EQ(in_ch1[i], out_ch1[i]);
155 EXPECT_FLOAT_EQ(in_ch2[i], out_ch2[i]);
156 }
157
158 out_frames = 1;
159 rv = dr.Resample(out_ch1, &out_frames, 0);
160 EXPECT_TRUE(rv);
161 EXPECT_EQ(out_frames, 1u);
162 rv = dr.Resample(out_ch2, &out_frames, 1);
163 EXPECT_TRUE(rv);
164 EXPECT_EQ(out_frames, 1u);
165 for (uint32_t i = 0; i < out_frames; ++i) {
166 EXPECT_FLOAT_EQ(in_ch1[i + 2], out_ch1[i]);
167 EXPECT_FLOAT_EQ(in_ch2[i + 2], out_ch2[i]);
168 }
169
170 // No more frames, the input buffer has drained
171 rv = dr.Resample(out_ch1, &out_frames, 0);
172 EXPECT_FALSE(rv);
173 EXPECT_EQ(out_frames, 0u);
174 out_frames = 1;
175 rv = dr.Resample(out_ch2, &out_frames, 1);
176 EXPECT_FALSE(rv);
177 EXPECT_EQ(out_frames, 0u);
178 }
179
TEST(TestDynamicResampler,SameRates_Short2)180 TEST(TestDynamicResampler, SameRates_Short2)
181 {
182 uint32_t in_frames = 3;
183 uint32_t out_frames = 2;
184 uint32_t channels = 2;
185 uint32_t in_rate = 44100;
186 uint32_t out_rate = 44100;
187
188 DynamicResampler dr(in_rate, out_rate);
189 dr.SetSampleFormat(AUDIO_FORMAT_S16);
190
191 short in_ch1[] = {1, 2, 3};
192 short in_ch2[] = {4, 5, 6};
193 AutoTArray<const short*, 2> in_buffer;
194 in_buffer.AppendElements(channels);
195 in_buffer[0] = in_ch1;
196 in_buffer[1] = in_ch2;
197
198 short out_ch1[3] = {};
199 short out_ch2[3] = {};
200
201 dr.AppendInput(in_buffer, in_frames);
202 bool rv = dr.Resample(out_ch1, &out_frames, 0);
203 EXPECT_TRUE(rv);
204 EXPECT_EQ(out_frames, 2u);
205 rv = dr.Resample(out_ch2, &out_frames, 1);
206 EXPECT_TRUE(rv);
207 EXPECT_EQ(out_frames, 2u);
208 for (uint32_t i = 0; i < out_frames; ++i) {
209 EXPECT_EQ(in_ch1[i], out_ch1[i]);
210 EXPECT_EQ(in_ch2[i], out_ch2[i]);
211 }
212
213 out_frames = 1;
214 rv = dr.Resample(out_ch1, &out_frames, 0);
215 EXPECT_TRUE(rv);
216 EXPECT_EQ(out_frames, 1u);
217 rv = dr.Resample(out_ch2, &out_frames, 1);
218 EXPECT_TRUE(rv);
219 EXPECT_EQ(out_frames, 1u);
220 for (uint32_t i = 0; i < out_frames; ++i) {
221 EXPECT_EQ(in_ch1[i + 2], out_ch1[i]);
222 EXPECT_EQ(in_ch2[i + 2], out_ch2[i]);
223 }
224
225 // No more frames, the input buffer has drained
226 rv = dr.Resample(out_ch1, &out_frames, 0);
227 EXPECT_FALSE(rv);
228 EXPECT_EQ(out_frames, 0u);
229 out_frames = 1;
230 rv = dr.Resample(out_ch2, &out_frames, 1);
231 EXPECT_FALSE(rv);
232 EXPECT_EQ(out_frames, 0u);
233 }
234
TEST(TestDynamicResampler,SameRates_Float3)235 TEST(TestDynamicResampler, SameRates_Float3)
236 {
237 uint32_t in_frames = 2;
238 uint32_t out_frames = 3;
239 uint32_t channels = 2;
240 uint32_t in_rate = 44100;
241 uint32_t out_rate = 44100;
242
243 DynamicResampler dr(in_rate, out_rate);
244 dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
245
246 float in_ch1[] = {0.1, 0.2, 0.3};
247 float in_ch2[] = {0.4, 0.5, 0.6};
248 AutoTArray<const float*, 2> in_buffer;
249 in_buffer.AppendElements(channels);
250 in_buffer[0] = in_ch1;
251 in_buffer[1] = in_ch2;
252
253 float out_ch1[3] = {};
254 float out_ch2[3] = {};
255
256 // Not enough frames in the input buffer
257 dr.AppendInput(in_buffer, in_frames);
258 bool rv = dr.Resample(out_ch1, &out_frames, 0);
259 EXPECT_FALSE(rv);
260 EXPECT_EQ(out_frames, 0u);
261 out_frames = 3;
262 rv = dr.Resample(out_ch2, &out_frames, 1);
263 EXPECT_FALSE(rv);
264 EXPECT_EQ(out_frames, 0u);
265
266 // Add one more frame
267 in_buffer[0] = in_ch1 + 2;
268 in_buffer[1] = in_ch2 + 2;
269 dr.AppendInput(in_buffer, 1);
270 out_frames = 3;
271 rv = dr.Resample(out_ch1, &out_frames, 0);
272 EXPECT_TRUE(rv);
273 EXPECT_EQ(out_frames, 3u);
274 rv = dr.Resample(out_ch2, &out_frames, 1);
275 EXPECT_TRUE(rv);
276 EXPECT_EQ(out_frames, 3u);
277 for (uint32_t i = 0; i < out_frames; ++i) {
278 EXPECT_FLOAT_EQ(in_ch1[i], out_ch1[i]);
279 EXPECT_FLOAT_EQ(in_ch2[i], out_ch2[i]);
280 }
281 }
282
TEST(TestDynamicResampler,SameRates_Short3)283 TEST(TestDynamicResampler, SameRates_Short3)
284 {
285 uint32_t in_frames = 2;
286 uint32_t out_frames = 3;
287 uint32_t channels = 2;
288 uint32_t in_rate = 44100;
289 uint32_t out_rate = 44100;
290
291 DynamicResampler dr(in_rate, out_rate);
292 dr.SetSampleFormat(AUDIO_FORMAT_S16);
293
294 short in_ch1[] = {1, 2, 3};
295 short in_ch2[] = {4, 5, 6};
296 AutoTArray<const short*, 2> in_buffer;
297 in_buffer.AppendElements(channels);
298 in_buffer[0] = in_ch1;
299 in_buffer[1] = in_ch2;
300
301 short out_ch1[3] = {};
302 short out_ch2[3] = {};
303
304 // Not enough frames in the input buffer
305 dr.AppendInput(in_buffer, in_frames);
306 bool rv = dr.Resample(out_ch1, &out_frames, 0);
307 EXPECT_FALSE(rv);
308 EXPECT_EQ(out_frames, 0u);
309 out_frames = 3;
310 rv = dr.Resample(out_ch2, &out_frames, 1);
311 EXPECT_FALSE(rv);
312 EXPECT_EQ(out_frames, 0u);
313
314 // Add one more frame
315 in_buffer[0] = in_ch1 + 2;
316 in_buffer[1] = in_ch2 + 2;
317 dr.AppendInput(in_buffer, 1);
318 out_frames = 3;
319 rv = dr.Resample(out_ch1, &out_frames, 0);
320 EXPECT_TRUE(rv);
321 EXPECT_EQ(out_frames, 3u);
322 rv = dr.Resample(out_ch2, &out_frames, 1);
323 EXPECT_TRUE(rv);
324 EXPECT_EQ(out_frames, 3u);
325 for (uint32_t i = 0; i < out_frames; ++i) {
326 EXPECT_EQ(in_ch1[i], out_ch1[i]);
327 EXPECT_EQ(in_ch2[i], out_ch2[i]);
328 }
329 }
330
TEST(TestDynamicResampler,UpdateOutRate_Float)331 TEST(TestDynamicResampler, UpdateOutRate_Float)
332 {
333 uint32_t in_frames = 10;
334 uint32_t out_frames = 40;
335 uint32_t channels = 2;
336 uint32_t in_rate = 24000;
337 uint32_t out_rate = 48000;
338
339 uint32_t pre_buffer = 20;
340
341 DynamicResampler dr(in_rate, out_rate, pre_buffer);
342 dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
343 EXPECT_EQ(dr.GetOutRate(), out_rate);
344 EXPECT_EQ(dr.GetChannels(), channels);
345
346 float in_ch1[10] = {};
347 float in_ch2[10] = {};
348 for (uint32_t i = 0; i < in_frames; ++i) {
349 in_ch1[i] = in_ch2[i] = 0.01f * i;
350 }
351 AutoTArray<const float*, 2> in_buffer;
352 in_buffer.AppendElements(channels);
353 in_buffer[0] = in_ch1;
354 in_buffer[1] = in_ch2;
355
356 float out_ch1[40] = {};
357 float out_ch2[40] = {};
358
359 dr.AppendInput(in_buffer, in_frames);
360 bool rv = dr.Resample(out_ch1, &out_frames, 0);
361 EXPECT_TRUE(rv);
362 EXPECT_EQ(out_frames, 40u);
363 rv = dr.Resample(out_ch2, &out_frames, 1);
364 EXPECT_TRUE(rv);
365 EXPECT_EQ(out_frames, 40u);
366 for (uint32_t i = 0; i < out_frames; ++i) {
367 // Only pre buffered data reach output
368 EXPECT_FLOAT_EQ(out_ch1[i], 0.0);
369 EXPECT_FLOAT_EQ(out_ch2[i], 0.0);
370 }
371
372 // Update out rate
373 out_rate = 44100;
374 dr.UpdateResampler(out_rate, channels);
375 EXPECT_EQ(dr.GetOutRate(), out_rate);
376 EXPECT_EQ(dr.GetChannels(), channels);
377 out_frames = in_frames * out_rate / in_rate;
378 EXPECT_EQ(out_frames, 18u);
379 // Even if we provide no input if we have enough buffered input, we can create
380 // output
381 rv = dr.Resample(out_ch1, &out_frames, 0);
382 EXPECT_TRUE(rv);
383 EXPECT_EQ(out_frames, 18u);
384 rv = dr.Resample(out_ch2, &out_frames, 1);
385 EXPECT_TRUE(rv);
386 EXPECT_EQ(out_frames, 18u);
387 }
388
TEST(TestDynamicResampler,UpdateOutRate_Short)389 TEST(TestDynamicResampler, UpdateOutRate_Short)
390 {
391 uint32_t in_frames = 10;
392 uint32_t out_frames = 40;
393 uint32_t channels = 2;
394 uint32_t in_rate = 24000;
395 uint32_t out_rate = 48000;
396
397 uint32_t pre_buffer = 20;
398
399 DynamicResampler dr(in_rate, out_rate, pre_buffer);
400 dr.SetSampleFormat(AUDIO_FORMAT_S16);
401 EXPECT_EQ(dr.GetOutRate(), out_rate);
402 EXPECT_EQ(dr.GetChannels(), channels);
403
404 short in_ch1[10] = {};
405 short in_ch2[10] = {};
406 for (uint32_t i = 0; i < in_frames; ++i) {
407 in_ch1[i] = in_ch2[i] = i;
408 }
409 AutoTArray<const short*, 2> in_buffer;
410 in_buffer.AppendElements(channels);
411 in_buffer[0] = in_ch1;
412 in_buffer[1] = in_ch2;
413
414 short out_ch1[40] = {};
415 short out_ch2[40] = {};
416
417 dr.AppendInput(in_buffer, in_frames);
418 bool rv = dr.Resample(out_ch1, &out_frames, 0);
419 EXPECT_TRUE(rv);
420 EXPECT_EQ(out_frames, 40u);
421 rv = dr.Resample(out_ch2, &out_frames, 1);
422 EXPECT_TRUE(rv);
423 EXPECT_EQ(out_frames, 40u);
424 for (uint32_t i = 0; i < out_frames; ++i) {
425 // Only pre buffered data reach output
426 EXPECT_EQ(out_ch1[i], 0.0);
427 EXPECT_EQ(out_ch2[i], 0.0);
428 }
429
430 // Update out rate
431 out_rate = 44100;
432 dr.UpdateResampler(out_rate, channels);
433 EXPECT_EQ(dr.GetOutRate(), out_rate);
434 EXPECT_EQ(dr.GetChannels(), channels);
435 out_frames = in_frames * out_rate / in_rate;
436 EXPECT_EQ(out_frames, 18u);
437 // Even if we provide no input if we have enough buffered input, we can create
438 // output
439 rv = dr.Resample(out_ch1, &out_frames, 0);
440 EXPECT_TRUE(rv);
441 EXPECT_EQ(out_frames, 18u);
442 rv = dr.Resample(out_ch2, &out_frames, 1);
443 EXPECT_TRUE(rv);
444 EXPECT_EQ(out_frames, 18u);
445 }
446
TEST(TestDynamicResampler,BigRangeOutRates_Float)447 TEST(TestDynamicResampler, BigRangeOutRates_Float)
448 {
449 uint32_t in_frames = 10;
450 uint32_t out_frames = 10;
451 uint32_t channels = 2;
452 uint32_t in_rate = 44100;
453 uint32_t out_rate = 44100;
454 uint32_t pre_buffer = 20;
455
456 DynamicResampler dr(in_rate, out_rate, pre_buffer);
457 dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
458
459 const uint32_t in_capacity = 40;
460 float in_ch1[in_capacity] = {};
461 float in_ch2[in_capacity] = {};
462 for (uint32_t i = 0; i < in_capacity; ++i) {
463 in_ch1[i] = in_ch2[i] = 0.01f * i;
464 }
465 AutoTArray<const float*, 2> in_buffer;
466 in_buffer.AppendElements(channels);
467 in_buffer[0] = in_ch1;
468 in_buffer[1] = in_ch2;
469
470 const uint32_t out_capacity = 1000;
471 float out_ch1[out_capacity] = {};
472 float out_ch2[out_capacity] = {};
473
474 for (uint32_t rate = 10000; rate < 90000; ++rate) {
475 out_rate = rate;
476 dr.UpdateResampler(out_rate, channels);
477 EXPECT_EQ(dr.GetOutRate(), out_rate);
478 EXPECT_EQ(dr.GetChannels(), channels);
479 in_frames = 20; // more than we need
480 out_frames = in_frames * out_rate / in_rate;
481 uint32_t expected_out_frames = out_frames;
482 for (uint32_t y = 0; y < 2; ++y) {
483 dr.AppendInput(in_buffer, in_frames);
484 bool rv = dr.Resample(out_ch1, &out_frames, 0);
485 EXPECT_TRUE(rv);
486 EXPECT_EQ(out_frames, expected_out_frames);
487 rv = dr.Resample(out_ch2, &out_frames, 1);
488 EXPECT_TRUE(rv);
489 EXPECT_EQ(out_frames, expected_out_frames);
490 }
491 }
492 }
493
TEST(TestDynamicResampler,BigRangeOutRates_Short)494 TEST(TestDynamicResampler, BigRangeOutRates_Short)
495 {
496 uint32_t in_frames = 10;
497 uint32_t out_frames = 10;
498 uint32_t channels = 2;
499 uint32_t in_rate = 44100;
500 uint32_t out_rate = 44100;
501 uint32_t pre_buffer = 20;
502
503 DynamicResampler dr(in_rate, out_rate, pre_buffer);
504 dr.SetSampleFormat(AUDIO_FORMAT_S16);
505
506 const uint32_t in_capacity = 40;
507 short in_ch1[in_capacity] = {};
508 short in_ch2[in_capacity] = {};
509 for (uint32_t i = 0; i < in_capacity; ++i) {
510 in_ch1[i] = in_ch2[i] = i;
511 }
512 AutoTArray<const short*, 2> in_buffer;
513 in_buffer.AppendElements(channels);
514 in_buffer[0] = in_ch1;
515 in_buffer[1] = in_ch2;
516
517 const uint32_t out_capacity = 1000;
518 short out_ch1[out_capacity] = {};
519 short out_ch2[out_capacity] = {};
520
521 for (uint32_t rate = 10000; rate < 90000; ++rate) {
522 out_rate = rate;
523 dr.UpdateResampler(out_rate, channels);
524 in_frames = 20; // more than we need
525 out_frames = in_frames * out_rate / in_rate;
526 uint32_t expected_out_frames = out_frames;
527 for (uint32_t y = 0; y < 2; ++y) {
528 dr.AppendInput(in_buffer, in_frames);
529 bool rv = dr.Resample(out_ch1, &out_frames, 0);
530 EXPECT_TRUE(rv);
531 EXPECT_EQ(out_frames, expected_out_frames);
532 rv = dr.Resample(out_ch2, &out_frames, 1);
533 EXPECT_TRUE(rv);
534 EXPECT_EQ(out_frames, expected_out_frames);
535 }
536 }
537 }
538
TEST(TestDynamicResampler,UpdateChannels_Float)539 TEST(TestDynamicResampler, UpdateChannels_Float)
540 {
541 uint32_t in_frames = 10;
542 uint32_t out_frames = 10;
543 uint32_t channels = 2;
544 uint32_t in_rate = 44100;
545 uint32_t out_rate = 48000;
546
547 DynamicResampler dr(in_rate, out_rate);
548 dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
549
550 float in_ch1[10] = {};
551 float in_ch2[10] = {};
552 for (uint32_t i = 0; i < in_frames; ++i) {
553 in_ch1[i] = in_ch2[i] = 0.01f * i;
554 }
555 AutoTArray<const float*, 2> in_buffer;
556 in_buffer.AppendElements(channels);
557 in_buffer[0] = in_ch1;
558 in_buffer[1] = in_ch2;
559
560 float out_ch1[10] = {};
561 float out_ch2[10] = {};
562
563 dr.AppendInput(in_buffer, in_frames);
564 bool rv = dr.Resample(out_ch1, &out_frames, 0);
565 EXPECT_TRUE(rv);
566 EXPECT_EQ(out_frames, 10u);
567 rv = dr.Resample(out_ch2, &out_frames, 1);
568 EXPECT_TRUE(rv);
569 EXPECT_EQ(out_frames, 10u);
570
571 // Add 3rd channel
572 dr.UpdateResampler(out_rate, 3);
573 EXPECT_EQ(dr.GetOutRate(), out_rate);
574 EXPECT_EQ(dr.GetChannels(), 3u);
575
576 float in_ch3[10] = {};
577 for (uint32_t i = 0; i < in_frames; ++i) {
578 in_ch3[i] = 0.01f * i;
579 }
580 in_buffer.AppendElement();
581 in_buffer[2] = in_ch3;
582 float out_ch3[10] = {};
583
584 dr.AppendInput(in_buffer, in_frames);
585
586 rv = dr.Resample(out_ch1, &out_frames, 0);
587 EXPECT_TRUE(rv);
588 EXPECT_EQ(out_frames, 10u);
589 rv = dr.Resample(out_ch2, &out_frames, 1);
590 EXPECT_TRUE(rv);
591 EXPECT_EQ(out_frames, 10u);
592 rv = dr.Resample(out_ch3, &out_frames, 2);
593 EXPECT_TRUE(rv);
594 EXPECT_EQ(out_frames, 10u);
595
596 float in_ch4[10] = {};
597 for (uint32_t i = 0; i < in_frames; ++i) {
598 in_ch3[i] = 0.01f * i;
599 }
600 in_buffer.AppendElement();
601 in_buffer[3] = in_ch4;
602 float out_ch4[10] = {};
603
604 dr.UpdateResampler(out_rate, 4);
605 EXPECT_EQ(dr.GetOutRate(), out_rate);
606 EXPECT_EQ(dr.GetChannels(), 4u);
607 dr.AppendInput(in_buffer, in_frames);
608
609 rv = dr.Resample(out_ch1, &out_frames, 0);
610 EXPECT_TRUE(rv);
611 EXPECT_EQ(out_frames, 10u);
612 rv = dr.Resample(out_ch2, &out_frames, 1);
613 EXPECT_TRUE(rv);
614 EXPECT_EQ(out_frames, 10u);
615 rv = dr.Resample(out_ch3, &out_frames, 2);
616 EXPECT_TRUE(rv);
617 EXPECT_EQ(out_frames, 10u);
618 rv = dr.Resample(out_ch4, &out_frames, 3);
619 EXPECT_TRUE(rv);
620 EXPECT_EQ(out_frames, 10u);
621 }
622
TEST(TestDynamicResampler,UpdateChannels_Short)623 TEST(TestDynamicResampler, UpdateChannels_Short)
624 {
625 uint32_t in_frames = 10;
626 uint32_t out_frames = 10;
627 uint32_t channels = 2;
628 uint32_t in_rate = 44100;
629 uint32_t out_rate = 48000;
630
631 DynamicResampler dr(in_rate, out_rate);
632 dr.SetSampleFormat(AUDIO_FORMAT_S16);
633
634 short in_ch1[10] = {};
635 short in_ch2[10] = {};
636 for (uint32_t i = 0; i < in_frames; ++i) {
637 in_ch1[i] = in_ch2[i] = i;
638 }
639 AutoTArray<const short*, 2> in_buffer;
640 in_buffer.AppendElements(channels);
641 in_buffer[0] = in_ch1;
642 in_buffer[1] = in_ch2;
643
644 short out_ch1[10] = {};
645 short out_ch2[10] = {};
646
647 dr.AppendInput(in_buffer, in_frames);
648 bool rv = dr.Resample(out_ch1, &out_frames, 0);
649 EXPECT_TRUE(rv);
650 EXPECT_EQ(out_frames, 10u);
651 rv = dr.Resample(out_ch2, &out_frames, 1);
652 EXPECT_TRUE(rv);
653 EXPECT_EQ(out_frames, 10u);
654
655 // Add 3rd channel
656 dr.UpdateResampler(out_rate, 3);
657 EXPECT_EQ(dr.GetOutRate(), out_rate);
658 EXPECT_EQ(dr.GetChannels(), 3u);
659
660 short in_ch3[10] = {};
661 for (uint32_t i = 0; i < in_frames; ++i) {
662 in_ch3[i] = i;
663 }
664 in_buffer.AppendElement();
665 in_buffer[2] = in_ch3;
666 short out_ch3[10] = {};
667
668 dr.AppendInput(in_buffer, in_frames);
669
670 rv = dr.Resample(out_ch1, &out_frames, 0);
671 EXPECT_TRUE(rv);
672 EXPECT_EQ(out_frames, 10u);
673 rv = dr.Resample(out_ch2, &out_frames, 1);
674 EXPECT_TRUE(rv);
675 EXPECT_EQ(out_frames, 10u);
676 rv = dr.Resample(out_ch3, &out_frames, 2);
677 EXPECT_TRUE(rv);
678 EXPECT_EQ(out_frames, 10u);
679
680 // Check update with AudioSegment
681 short in_ch4[10] = {};
682 for (uint32_t i = 0; i < in_frames; ++i) {
683 in_ch3[i] = i;
684 }
685 in_buffer.AppendElement();
686 in_buffer[3] = in_ch4;
687 short out_ch4[10] = {};
688
689 dr.UpdateResampler(out_rate, 4);
690 EXPECT_EQ(dr.GetOutRate(), out_rate);
691 EXPECT_EQ(dr.GetChannels(), 4u);
692 dr.AppendInput(in_buffer, in_frames);
693
694 rv = dr.Resample(out_ch1, &out_frames, 0);
695 EXPECT_TRUE(rv);
696 EXPECT_EQ(out_frames, 10u);
697 rv = dr.Resample(out_ch2, &out_frames, 1);
698 EXPECT_TRUE(rv);
699 EXPECT_EQ(out_frames, 10u);
700 rv = dr.Resample(out_ch3, &out_frames, 2);
701 EXPECT_TRUE(rv);
702 EXPECT_EQ(out_frames, 10u);
703 rv = dr.Resample(out_ch4, &out_frames, 3);
704 EXPECT_TRUE(rv);
705 EXPECT_EQ(out_frames, 10u);
706 }
707
TEST(TestAudioChunkList,Basic1)708 TEST(TestAudioChunkList, Basic1)
709 {
710 AudioChunkList list(256, 2);
711 list.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
712 EXPECT_EQ(list.ChunkCapacity(), 128u);
713 EXPECT_EQ(list.TotalCapacity(), 256u);
714
715 AudioChunk& c1 = list.GetNext();
716 float* c1_ch1 = c1.ChannelDataForWrite<float>(0);
717 float* c1_ch2 = c1.ChannelDataForWrite<float>(1);
718 EXPECT_EQ(c1.mBufferFormat, AUDIO_FORMAT_FLOAT32);
719 for (uint32_t i = 0; i < list.ChunkCapacity(); ++i) {
720 c1_ch1[i] = c1_ch2[i] = 0.01f * static_cast<float>(i);
721 }
722 AudioChunk& c2 = list.GetNext();
723 EXPECT_EQ(c2.mBufferFormat, AUDIO_FORMAT_FLOAT32);
724 EXPECT_NE(c1.mBuffer.get(), c2.mBuffer.get());
725 AudioChunk& c3 = list.GetNext();
726 EXPECT_EQ(c3.mBufferFormat, AUDIO_FORMAT_FLOAT32);
727 // Cycle
728 EXPECT_EQ(c1.mBuffer.get(), c3.mBuffer.get());
729 float* c3_ch1 = c3.ChannelDataForWrite<float>(0);
730 float* c3_ch2 = c3.ChannelDataForWrite<float>(1);
731 for (uint32_t i = 0; i < list.ChunkCapacity(); ++i) {
732 EXPECT_FLOAT_EQ(c1_ch1[i], c3_ch1[i]);
733 EXPECT_FLOAT_EQ(c1_ch2[i], c3_ch2[i]);
734 }
735 }
736
TEST(TestAudioChunkList,Basic2)737 TEST(TestAudioChunkList, Basic2)
738 {
739 AudioChunkList list(256, 2);
740 list.SetSampleFormat(AUDIO_FORMAT_S16);
741 EXPECT_EQ(list.ChunkCapacity(), 256u);
742 EXPECT_EQ(list.TotalCapacity(), 512u);
743
744 AudioChunk& c1 = list.GetNext();
745 EXPECT_EQ(c1.mBufferFormat, AUDIO_FORMAT_S16);
746 short* c1_ch1 = c1.ChannelDataForWrite<short>(0);
747 short* c1_ch2 = c1.ChannelDataForWrite<short>(1);
748 for (uint32_t i = 0; i < list.ChunkCapacity(); ++i) {
749 c1_ch1[i] = c1_ch2[i] = static_cast<short>(i);
750 }
751 AudioChunk& c2 = list.GetNext();
752 EXPECT_EQ(c2.mBufferFormat, AUDIO_FORMAT_S16);
753 EXPECT_NE(c1.mBuffer.get(), c2.mBuffer.get());
754 AudioChunk& c3 = list.GetNext();
755 EXPECT_EQ(c3.mBufferFormat, AUDIO_FORMAT_S16);
756 AudioChunk& c4 = list.GetNext();
757 EXPECT_EQ(c4.mBufferFormat, AUDIO_FORMAT_S16);
758 // Cycle
759 AudioChunk& c5 = list.GetNext();
760 EXPECT_EQ(c5.mBufferFormat, AUDIO_FORMAT_S16);
761 EXPECT_EQ(c1.mBuffer.get(), c5.mBuffer.get());
762 short* c5_ch1 = c5.ChannelDataForWrite<short>(0);
763 short* c5_ch2 = c5.ChannelDataForWrite<short>(1);
764 for (uint32_t i = 0; i < list.ChunkCapacity(); ++i) {
765 EXPECT_EQ(c1_ch1[i], c5_ch1[i]);
766 EXPECT_EQ(c1_ch2[i], c5_ch2[i]);
767 }
768 }
769
TEST(TestAudioChunkList,Basic3)770 TEST(TestAudioChunkList, Basic3)
771 {
772 AudioChunkList list(260, 2);
773 list.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
774 EXPECT_EQ(list.ChunkCapacity(), 128u);
775 EXPECT_EQ(list.TotalCapacity(), 256u + 128u);
776
777 AudioChunk& c1 = list.GetNext();
778 AudioChunk& c2 = list.GetNext();
779 EXPECT_NE(c1.mBuffer.get(), c2.mBuffer.get());
780 AudioChunk& c3 = list.GetNext();
781 EXPECT_NE(c1.mBuffer.get(), c3.mBuffer.get());
782 AudioChunk& c4 = list.GetNext();
783 EXPECT_EQ(c1.mBuffer.get(), c4.mBuffer.get());
784 }
785
TEST(TestAudioChunkList,Basic4)786 TEST(TestAudioChunkList, Basic4)
787 {
788 AudioChunkList list(260, 2);
789 list.SetSampleFormat(AUDIO_FORMAT_S16);
790 EXPECT_EQ(list.ChunkCapacity(), 256u);
791 EXPECT_EQ(list.TotalCapacity(), 512u + 256u);
792
793 AudioChunk& c1 = list.GetNext();
794 AudioChunk& c2 = list.GetNext();
795 EXPECT_NE(c1.mBuffer.get(), c2.mBuffer.get());
796 AudioChunk& c3 = list.GetNext();
797 EXPECT_NE(c1.mBuffer.get(), c3.mBuffer.get());
798 AudioChunk& c4 = list.GetNext();
799 EXPECT_EQ(c1.mBuffer.get(), c4.mBuffer.get());
800 }
801
TEST(TestAudioChunkList,UpdateChannels)802 TEST(TestAudioChunkList, UpdateChannels)
803 {
804 AudioChunkList list(256, 2);
805 list.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
806
807 AudioChunk& c1 = list.GetNext();
808 AudioChunk& c2 = list.GetNext();
809 EXPECT_EQ(c1.ChannelCount(), 2u);
810 EXPECT_EQ(c2.ChannelCount(), 2u);
811
812 // Update to Quad
813 list.Update(4);
814
815 AudioChunk& c3 = list.GetNext();
816 AudioChunk& c4 = list.GetNext();
817 EXPECT_EQ(c3.ChannelCount(), 4u);
818 EXPECT_EQ(c4.ChannelCount(), 4u);
819 }
820
TEST(TestAudioChunkList,UpdateBetweenMonoAndStereo)821 TEST(TestAudioChunkList, UpdateBetweenMonoAndStereo)
822 {
823 AudioChunkList list(256, 2);
824 list.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
825
826 AudioChunk& c1 = list.GetNext();
827 float* c1_ch1 = c1.ChannelDataForWrite<float>(0);
828 float* c1_ch2 = c1.ChannelDataForWrite<float>(1);
829 for (uint32_t i = 0; i < list.ChunkCapacity(); ++i) {
830 c1_ch1[i] = c1_ch2[i] = 0.01f * static_cast<float>(i);
831 }
832
833 AudioChunk& c2 = list.GetNext();
834 EXPECT_EQ(c1.ChannelCount(), 2u);
835 EXPECT_EQ(c2.ChannelCount(), 2u);
836
837 // Downmix to mono
838 list.Update(1);
839
840 AudioChunk& c3 = list.GetNext();
841 float* c3_ch1 = c3.ChannelDataForWrite<float>(0);
842 for (uint32_t i = 0; i < list.ChunkCapacity(); ++i) {
843 EXPECT_FLOAT_EQ(c3_ch1[i], c1_ch1[i]);
844 }
845
846 AudioChunk& c4 = list.GetNext();
847 EXPECT_EQ(c3.ChannelCount(), 1u);
848 EXPECT_EQ(c4.ChannelCount(), 1u);
849 EXPECT_EQ(static_cast<SharedChannelArrayBuffer<float>*>(c3.mBuffer.get())
850 ->mBuffers[0]
851 .Length(),
852 list.ChunkCapacity());
853
854 // Upmix to stereo
855 list.Update(2);
856
857 AudioChunk& c5 = list.GetNext();
858 AudioChunk& c6 = list.GetNext();
859 EXPECT_EQ(c5.ChannelCount(), 2u);
860 EXPECT_EQ(c6.ChannelCount(), 2u);
861 EXPECT_EQ(static_cast<SharedChannelArrayBuffer<float>*>(c5.mBuffer.get())
862 ->mBuffers[0]
863 .Length(),
864 list.ChunkCapacity());
865 EXPECT_EQ(static_cast<SharedChannelArrayBuffer<float>*>(c5.mBuffer.get())
866 ->mBuffers[1]
867 .Length(),
868 list.ChunkCapacity());
869
870 // Downmix to mono
871 list.Update(1);
872
873 AudioChunk& c7 = list.GetNext();
874 float* c7_ch1 = c7.ChannelDataForWrite<float>(0);
875 for (uint32_t i = 0; i < list.ChunkCapacity(); ++i) {
876 EXPECT_FLOAT_EQ(c7_ch1[i], c1_ch1[i]);
877 }
878
879 AudioChunk& c8 = list.GetNext();
880 EXPECT_EQ(c7.ChannelCount(), 1u);
881 EXPECT_EQ(c8.ChannelCount(), 1u);
882 EXPECT_EQ(static_cast<SharedChannelArrayBuffer<float>*>(c7.mBuffer.get())
883 ->mBuffers[0]
884 .Length(),
885 list.ChunkCapacity());
886 }
887
TEST(TestAudioChunkList,ConsumeAndForget)888 TEST(TestAudioChunkList, ConsumeAndForget)
889 {
890 AudioSegment s;
891 AudioChunkList list(256, 2);
892 list.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
893
894 AudioChunk& c1 = list.GetNext();
895 AudioChunk tmp1 = c1;
896 s.AppendAndConsumeChunk(std::move(tmp1));
897 EXPECT_FALSE(c1.mBuffer.get() == nullptr);
898 EXPECT_EQ(c1.ChannelData<float>().Length(), 2u);
899
900 AudioChunk& c2 = list.GetNext();
901 AudioChunk tmp2 = c2;
902 s.AppendAndConsumeChunk(std::move(tmp2));
903 EXPECT_FALSE(c2.mBuffer.get() == nullptr);
904 EXPECT_EQ(c2.ChannelData<float>().Length(), 2u);
905
906 s.ForgetUpTo(256);
907 list.GetNext();
908 list.GetNext();
909 }
910
911 template <class T>
CreateAudioChunk(uint32_t aFrames,uint32_t aChannels,AudioSampleFormat aSampleFormat)912 AudioChunk CreateAudioChunk(uint32_t aFrames, uint32_t aChannels,
913 AudioSampleFormat aSampleFormat) {
914 AudioChunk chunk;
915 nsTArray<nsTArray<T>> buffer;
916 buffer.AppendElements(aChannels);
917
918 nsTArray<const T*> bufferPtrs;
919 bufferPtrs.AppendElements(aChannels);
920
921 for (uint32_t i = 0; i < aChannels; ++i) {
922 T* ptr = buffer[i].AppendElements(aFrames);
923 bufferPtrs[i] = ptr;
924 for (uint32_t j = 0; j < aFrames; ++j) {
925 if (aSampleFormat == AUDIO_FORMAT_FLOAT32) {
926 ptr[j] = 0.01 * j;
927 } else {
928 ptr[j] = j;
929 }
930 }
931 }
932
933 chunk.mBuffer = new mozilla::SharedChannelArrayBuffer(std::move(buffer));
934 chunk.mBufferFormat = aSampleFormat;
935 chunk.mChannelData.AppendElements(aChannels);
936 for (uint32_t i = 0; i < aChannels; ++i) {
937 chunk.mChannelData[i] = bufferPtrs[i];
938 }
939 chunk.mDuration = aFrames;
940 return chunk;
941 }
942
943 template <class T>
CreateAudioSegment(uint32_t aFrames,uint32_t aChannels,AudioSampleFormat aSampleFormat)944 AudioSegment CreateAudioSegment(uint32_t aFrames, uint32_t aChannels,
945 AudioSampleFormat aSampleFormat) {
946 AudioSegment segment;
947 AudioChunk chunk = CreateAudioChunk<T>(aFrames, aChannels, aSampleFormat);
948 segment.AppendAndConsumeChunk(std::move(chunk));
949 return segment;
950 }
951
TEST(TestAudioResampler,OutAudioSegment_Float)952 TEST(TestAudioResampler, OutAudioSegment_Float)
953 {
954 uint32_t in_frames = 10;
955 uint32_t out_frames = 40;
956 uint32_t channels = 2;
957 uint32_t in_rate = 24000;
958 uint32_t out_rate = 48000;
959
960 uint32_t pre_buffer = 21;
961
962 AudioResampler dr(in_rate, out_rate, pre_buffer);
963
964 AudioSegment inSegment =
965 CreateAudioSegment<float>(in_frames, channels, AUDIO_FORMAT_FLOAT32);
966 dr.AppendInput(inSegment);
967
968 AudioSegment s = dr.Resample(out_frames);
969 EXPECT_EQ(s.GetDuration(), 40);
970 EXPECT_EQ(s.GetType(), MediaSegment::AUDIO);
971 EXPECT_TRUE(!s.IsNull());
972 EXPECT_TRUE(!s.IsEmpty());
973
974 for (AudioSegment::ChunkIterator ci(s); !ci.IsEnded(); ci.Next()) {
975 AudioChunk& c = *ci;
976 EXPECT_EQ(c.ChannelCount(), 2u);
977 for (uint32_t i = 0; i < out_frames; ++i) {
978 // Only pre buffered data reach output
979 EXPECT_FLOAT_EQ(c.ChannelData<float>()[0][i], 0.0);
980 EXPECT_FLOAT_EQ(c.ChannelData<float>()[1][i], 0.0);
981 }
982 }
983
984 // Update out rate
985 out_rate = 44100;
986 dr.UpdateOutRate(out_rate);
987 out_frames = in_frames * out_rate / in_rate;
988 EXPECT_EQ(out_frames, 18u);
989 // Even if we provide no input if we have enough buffered input, we can create
990 // output
991 AudioSegment s1 = dr.Resample(out_frames);
992 EXPECT_EQ(s1.GetDuration(), out_frames);
993 EXPECT_EQ(s1.GetType(), MediaSegment::AUDIO);
994 EXPECT_TRUE(!s1.IsNull());
995 EXPECT_TRUE(!s1.IsEmpty());
996 }
997
TEST(TestAudioResampler,OutAudioSegment_Short)998 TEST(TestAudioResampler, OutAudioSegment_Short)
999 {
1000 uint32_t in_frames = 10;
1001 uint32_t out_frames = 40;
1002 uint32_t channels = 2;
1003 uint32_t in_rate = 24000;
1004 uint32_t out_rate = 48000;
1005
1006 uint32_t pre_buffer = 21;
1007
1008 AudioResampler dr(in_rate, out_rate, pre_buffer);
1009
1010 AudioSegment inSegment =
1011 CreateAudioSegment<short>(in_frames, channels, AUDIO_FORMAT_S16);
1012 dr.AppendInput(inSegment);
1013
1014 AudioSegment s = dr.Resample(out_frames);
1015 EXPECT_EQ(s.GetDuration(), 40);
1016 EXPECT_EQ(s.GetType(), MediaSegment::AUDIO);
1017 EXPECT_TRUE(!s.IsNull());
1018 EXPECT_TRUE(!s.IsEmpty());
1019
1020 for (AudioSegment::ChunkIterator ci(s); !ci.IsEnded(); ci.Next()) {
1021 AudioChunk& c = *ci;
1022 EXPECT_EQ(c.ChannelCount(), 2u);
1023 for (uint32_t i = 0; i < out_frames; ++i) {
1024 // Only pre buffered data reach output
1025 EXPECT_FLOAT_EQ(c.ChannelData<short>()[0][i], 0.0);
1026 EXPECT_FLOAT_EQ(c.ChannelData<short>()[1][i], 0.0);
1027 }
1028 }
1029
1030 // Update out rate
1031 out_rate = 44100;
1032 dr.UpdateOutRate(out_rate);
1033 out_frames = in_frames * out_rate / in_rate;
1034 EXPECT_EQ(out_frames, 18u);
1035 // Even if we provide no input if we have enough buffered input, we can create
1036 // output
1037 AudioSegment s1 = dr.Resample(out_frames);
1038 EXPECT_EQ(s1.GetDuration(), out_frames);
1039 EXPECT_EQ(s1.GetType(), MediaSegment::AUDIO);
1040 EXPECT_TRUE(!s1.IsNull());
1041 EXPECT_TRUE(!s1.IsEmpty());
1042 }
1043
TEST(TestAudioResampler,OutAudioSegmentFail_Float)1044 TEST(TestAudioResampler, OutAudioSegmentFail_Float)
1045 {
1046 const uint32_t in_frames = 130;
1047 const uint32_t out_frames = 300;
1048 uint32_t channels = 2;
1049 uint32_t in_rate = 24000;
1050 uint32_t out_rate = 48000;
1051
1052 uint32_t pre_buffer = 5;
1053
1054 AudioResampler dr(in_rate, out_rate, pre_buffer);
1055 AudioSegment inSegment =
1056 CreateAudioSegment<float>(in_frames, channels, AUDIO_FORMAT_FLOAT32);
1057 dr.AppendInput(inSegment);
1058
1059 AudioSegment s = dr.Resample(out_frames);
1060 EXPECT_EQ(s.GetDuration(), 0);
1061 EXPECT_EQ(s.GetType(), MediaSegment::AUDIO);
1062 EXPECT_TRUE(s.IsNull());
1063 EXPECT_TRUE(s.IsEmpty());
1064 }
1065
TEST(TestAudioResampler,InAudioSegment_Float)1066 TEST(TestAudioResampler, InAudioSegment_Float)
1067 {
1068 uint32_t in_frames = 10;
1069 uint32_t out_frames = 40;
1070 uint32_t channels = 2;
1071 uint32_t in_rate = 24000;
1072 uint32_t out_rate = 48000;
1073
1074 uint32_t pre_buffer = 10;
1075 AudioResampler dr(in_rate, out_rate, pre_buffer);
1076
1077 AudioSegment inSegment;
1078
1079 AudioChunk chunk1;
1080 chunk1.SetNull(in_frames / 2);
1081 inSegment.AppendAndConsumeChunk(std::move(chunk1));
1082
1083 AudioChunk chunk2;
1084 nsTArray<nsTArray<float>> buffer;
1085 buffer.AppendElements(channels);
1086
1087 nsTArray<const float*> bufferPtrs;
1088 bufferPtrs.AppendElements(channels);
1089
1090 for (uint32_t i = 0; i < channels; ++i) {
1091 float* ptr = buffer[i].AppendElements(5);
1092 bufferPtrs[i] = ptr;
1093 for (uint32_t j = 0; j < 5; ++j) {
1094 ptr[j] = 0.01f * j;
1095 }
1096 }
1097
1098 chunk2.mBuffer = new mozilla::SharedChannelArrayBuffer(std::move(buffer));
1099 chunk2.mBufferFormat = AUDIO_FORMAT_FLOAT32;
1100 chunk2.mChannelData.AppendElements(channels);
1101 for (uint32_t i = 0; i < channels; ++i) {
1102 chunk2.mChannelData[i] = bufferPtrs[i];
1103 }
1104 chunk2.mDuration = in_frames / 2;
1105 inSegment.AppendAndConsumeChunk(std::move(chunk2));
1106
1107 dr.AppendInput(inSegment);
1108 AudioSegment outSegment = dr.Resample(out_frames);
1109 // Faild because the first chunk is ignored
1110 EXPECT_EQ(outSegment.GetDuration(), 0u);
1111 EXPECT_EQ(outSegment.MaxChannelCount(), 0u);
1112
1113 // Add the 5 more frames that are missing
1114 dr.AppendInput(inSegment);
1115 AudioSegment outSegment2 = dr.Resample(out_frames);
1116 EXPECT_EQ(outSegment2.GetDuration(), 40u);
1117 EXPECT_EQ(outSegment2.MaxChannelCount(), 2u);
1118 }
1119
TEST(TestAudioResampler,InAudioSegment_Short)1120 TEST(TestAudioResampler, InAudioSegment_Short)
1121 {
1122 uint32_t in_frames = 10;
1123 uint32_t out_frames = 40;
1124 uint32_t channels = 2;
1125 uint32_t in_rate = 24000;
1126 uint32_t out_rate = 48000;
1127
1128 uint32_t pre_buffer = 10;
1129 AudioResampler dr(in_rate, out_rate, pre_buffer);
1130
1131 AudioSegment inSegment;
1132
1133 // The null chunk at the beginning will be ignored.
1134 AudioChunk chunk1;
1135 chunk1.SetNull(in_frames / 2);
1136 inSegment.AppendAndConsumeChunk(std::move(chunk1));
1137
1138 AudioChunk chunk2;
1139 nsTArray<nsTArray<short>> buffer;
1140 buffer.AppendElements(channels);
1141
1142 nsTArray<const short*> bufferPtrs;
1143 bufferPtrs.AppendElements(channels);
1144
1145 for (uint32_t i = 0; i < channels; ++i) {
1146 short* ptr = buffer[i].AppendElements(5);
1147 bufferPtrs[i] = ptr;
1148 for (uint32_t j = 0; j < 5; ++j) {
1149 ptr[j] = j;
1150 }
1151 }
1152
1153 chunk2.mBuffer = new mozilla::SharedChannelArrayBuffer(std::move(buffer));
1154 chunk2.mBufferFormat = AUDIO_FORMAT_S16;
1155 chunk2.mChannelData.AppendElements(channels);
1156 for (uint32_t i = 0; i < channels; ++i) {
1157 chunk2.mChannelData[i] = bufferPtrs[i];
1158 }
1159 chunk2.mDuration = in_frames / 2;
1160 inSegment.AppendAndConsumeChunk(std::move(chunk2));
1161
1162 dr.AppendInput(inSegment);
1163 AudioSegment outSegment = dr.Resample(out_frames);
1164 // Faild because the first chunk is ignored
1165 EXPECT_EQ(outSegment.GetDuration(), 0u);
1166 EXPECT_EQ(outSegment.MaxChannelCount(), 0u);
1167
1168 dr.AppendInput(inSegment);
1169 AudioSegment outSegment2 = dr.Resample(out_frames);
1170 EXPECT_EQ(outSegment2.GetDuration(), 40u);
1171 EXPECT_EQ(outSegment2.MaxChannelCount(), 2u);
1172 }
1173
TEST(TestAudioResampler,ChannelChange_MonoToStereo)1174 TEST(TestAudioResampler, ChannelChange_MonoToStereo)
1175 {
1176 uint32_t in_frames = 10;
1177 uint32_t out_frames = 40;
1178 // uint32_t channels = 2;
1179 uint32_t in_rate = 24000;
1180 uint32_t out_rate = 48000;
1181
1182 uint32_t pre_buffer = 0;
1183
1184 AudioResampler dr(in_rate, out_rate, pre_buffer);
1185
1186 AudioChunk monoChunk =
1187 CreateAudioChunk<float>(in_frames, 1, AUDIO_FORMAT_FLOAT32);
1188 AudioChunk stereoChunk =
1189 CreateAudioChunk<float>(in_frames, 2, AUDIO_FORMAT_FLOAT32);
1190
1191 AudioSegment inSegment;
1192 inSegment.AppendAndConsumeChunk(std::move(monoChunk));
1193 inSegment.AppendAndConsumeChunk(std::move(stereoChunk));
1194 dr.AppendInput(inSegment);
1195
1196 AudioSegment s = dr.Resample(out_frames);
1197 EXPECT_EQ(s.GetDuration(), 40);
1198 EXPECT_EQ(s.GetType(), MediaSegment::AUDIO);
1199 EXPECT_TRUE(!s.IsNull());
1200 EXPECT_TRUE(!s.IsEmpty());
1201 EXPECT_EQ(s.MaxChannelCount(), 2u);
1202 }
1203
TEST(TestAudioResampler,ChannelChange_StereoToMono)1204 TEST(TestAudioResampler, ChannelChange_StereoToMono)
1205 {
1206 uint32_t in_frames = 10;
1207 uint32_t out_frames = 40;
1208 // uint32_t channels = 2;
1209 uint32_t in_rate = 24000;
1210 uint32_t out_rate = 48000;
1211
1212 uint32_t pre_buffer = 0;
1213
1214 AudioResampler dr(in_rate, out_rate, pre_buffer);
1215
1216 AudioChunk monoChunk =
1217 CreateAudioChunk<float>(in_frames, 1, AUDIO_FORMAT_FLOAT32);
1218 AudioChunk stereoChunk =
1219 CreateAudioChunk<float>(in_frames, 2, AUDIO_FORMAT_FLOAT32);
1220
1221 AudioSegment inSegment;
1222 inSegment.AppendAndConsumeChunk(std::move(stereoChunk));
1223 inSegment.AppendAndConsumeChunk(std::move(monoChunk));
1224 dr.AppendInput(inSegment);
1225
1226 AudioSegment s = dr.Resample(out_frames);
1227 EXPECT_EQ(s.GetDuration(), 40);
1228 EXPECT_EQ(s.GetType(), MediaSegment::AUDIO);
1229 EXPECT_TRUE(!s.IsNull());
1230 EXPECT_TRUE(!s.IsEmpty());
1231 EXPECT_EQ(s.MaxChannelCount(), 1u);
1232 }
1233
TEST(TestAudioResampler,ChannelChange_StereoToQuad)1234 TEST(TestAudioResampler, ChannelChange_StereoToQuad)
1235 {
1236 uint32_t in_frames = 10;
1237 uint32_t out_frames = 40;
1238 // uint32_t channels = 2;
1239 uint32_t in_rate = 24000;
1240 uint32_t out_rate = 48000;
1241
1242 uint32_t pre_buffer = 0;
1243
1244 AudioResampler dr(in_rate, out_rate, pre_buffer);
1245
1246 AudioChunk stereoChunk =
1247 CreateAudioChunk<float>(in_frames, 2, AUDIO_FORMAT_FLOAT32);
1248 AudioChunk quadChunk =
1249 CreateAudioChunk<float>(in_frames, 4, AUDIO_FORMAT_FLOAT32);
1250
1251 AudioSegment inSegment;
1252 inSegment.AppendAndConsumeChunk(std::move(stereoChunk));
1253 inSegment.AppendAndConsumeChunk(std::move(quadChunk));
1254 dr.AppendInput(inSegment);
1255
1256 AudioSegment s = dr.Resample(out_frames);
1257 EXPECT_EQ(s.GetDuration(), 0);
1258 EXPECT_EQ(s.GetType(), MediaSegment::AUDIO);
1259 EXPECT_TRUE(s.IsNull());
1260 EXPECT_TRUE(s.IsEmpty());
1261
1262 AudioSegment s2 = dr.Resample(out_frames / 2);
1263 EXPECT_EQ(s2.GetDuration(), out_frames / 2);
1264 EXPECT_EQ(s2.GetType(), MediaSegment::AUDIO);
1265 EXPECT_TRUE(!s2.IsNull());
1266 EXPECT_TRUE(!s2.IsEmpty());
1267 }
1268
TEST(TestAudioResampler,ChannelChange_QuadToStereo)1269 TEST(TestAudioResampler, ChannelChange_QuadToStereo)
1270 {
1271 uint32_t in_frames = 10;
1272 uint32_t out_frames = 40;
1273 // uint32_t channels = 2;
1274 uint32_t in_rate = 24000;
1275 uint32_t out_rate = 48000;
1276
1277 AudioResampler dr(in_rate, out_rate);
1278
1279 AudioChunk stereoChunk =
1280 CreateAudioChunk<float>(in_frames, 2, AUDIO_FORMAT_FLOAT32);
1281 AudioChunk quadChunk =
1282 CreateAudioChunk<float>(in_frames, 4, AUDIO_FORMAT_FLOAT32);
1283
1284 AudioSegment inSegment;
1285 inSegment.AppendAndConsumeChunk(std::move(quadChunk));
1286 inSegment.AppendAndConsumeChunk(std::move(stereoChunk));
1287 dr.AppendInput(inSegment);
1288
1289 AudioSegment s = dr.Resample(out_frames);
1290 EXPECT_EQ(s.GetDuration(), 0);
1291 EXPECT_EQ(s.GetType(), MediaSegment::AUDIO);
1292 EXPECT_TRUE(s.IsNull());
1293 EXPECT_TRUE(s.IsEmpty());
1294
1295 AudioSegment s2 = dr.Resample(out_frames / 2);
1296 EXPECT_EQ(s2.GetDuration(), out_frames / 2);
1297 EXPECT_EQ(s2.GetType(), MediaSegment::AUDIO);
1298 EXPECT_TRUE(!s2.IsNull());
1299 EXPECT_TRUE(!s2.IsEmpty());
1300 }
1301
1302 void printAudioSegment(const AudioSegment& segment);
1303
TEST(TestAudioResampler,ChannelChange_Discontinuity)1304 TEST(TestAudioResampler, ChannelChange_Discontinuity)
1305 {
1306 uint32_t in_rate = 24000;
1307 uint32_t out_rate = 48000;
1308
1309 const float amplitude = 0.5;
1310 const float frequency = 200;
1311 const float phase = 0.0;
1312 float time = 0.0;
1313 const float deltaTime = 1.0f / static_cast<float>(in_rate);
1314
1315 uint32_t in_frames = in_rate / 100;
1316 uint32_t out_frames = out_rate / 100;
1317 AudioResampler dr(in_rate, out_rate);
1318
1319 AudioChunk monoChunk =
1320 CreateAudioChunk<float>(in_frames, 1, AUDIO_FORMAT_FLOAT32);
1321 for (uint32_t i = 0; i < monoChunk.GetDuration(); ++i) {
1322 double value = amplitude * sin(2 * M_PI * frequency * time + phase);
1323 monoChunk.ChannelDataForWrite<float>(0)[i] = static_cast<float>(value);
1324 time += deltaTime;
1325 }
1326 AudioChunk stereoChunk =
1327 CreateAudioChunk<float>(in_frames, 2, AUDIO_FORMAT_FLOAT32);
1328 for (uint32_t i = 0; i < stereoChunk.GetDuration(); ++i) {
1329 double value = amplitude * sin(2 * M_PI * frequency * time + phase);
1330 stereoChunk.ChannelDataForWrite<float>(0)[i] = static_cast<float>(value);
1331 if (stereoChunk.ChannelCount() == 2) {
1332 stereoChunk.ChannelDataForWrite<float>(1)[i] = value;
1333 }
1334 time += deltaTime;
1335 }
1336
1337 AudioSegment inSegment;
1338 inSegment.AppendAndConsumeChunk(std::move(stereoChunk));
1339 // printAudioSegment(inSegment);
1340
1341 dr.AppendInput(inSegment);
1342 AudioSegment s = dr.Resample(out_frames);
1343 // printAudioSegment(s);
1344
1345 AudioSegment inSegment2;
1346 inSegment2.AppendAndConsumeChunk(std::move(monoChunk));
1347 // The resampler here is updated due to the channel change and that creates
1348 // discontinuity.
1349 dr.AppendInput(inSegment2);
1350 AudioSegment s2 = dr.Resample(out_frames);
1351 // printAudioSegment(s2);
1352
1353 EXPECT_EQ(s2.GetDuration(), 480);
1354 EXPECT_EQ(s2.GetType(), MediaSegment::AUDIO);
1355 EXPECT_TRUE(!s2.IsNull());
1356 EXPECT_TRUE(!s2.IsEmpty());
1357 EXPECT_EQ(s2.MaxChannelCount(), 1u);
1358 }
1359
TEST(TestAudioResampler,ChannelChange_Discontinuity2)1360 TEST(TestAudioResampler, ChannelChange_Discontinuity2)
1361 {
1362 uint32_t in_rate = 24000;
1363 uint32_t out_rate = 48000;
1364
1365 const float amplitude = 0.5;
1366 const float frequency = 200;
1367 const float phase = 0.0;
1368 float time = 0.0;
1369 const float deltaTime = 1.0f / static_cast<float>(in_rate);
1370
1371 uint32_t in_frames = in_rate / 100;
1372 uint32_t out_frames = out_rate / 100;
1373 AudioResampler dr(in_rate, out_rate, 10);
1374
1375 AudioChunk monoChunk =
1376 CreateAudioChunk<float>(in_frames / 2, 1, AUDIO_FORMAT_FLOAT32);
1377 for (uint32_t i = 0; i < monoChunk.GetDuration(); ++i) {
1378 double value = amplitude * sin(2 * M_PI * frequency * time + phase);
1379 monoChunk.ChannelDataForWrite<float>(0)[i] = static_cast<float>(value);
1380 time += deltaTime;
1381 }
1382 AudioChunk stereoChunk =
1383 CreateAudioChunk<float>(in_frames / 2, 2, AUDIO_FORMAT_FLOAT32);
1384 for (uint32_t i = 0; i < stereoChunk.GetDuration(); ++i) {
1385 double value = amplitude * sin(2 * M_PI * frequency * time + phase);
1386 stereoChunk.ChannelDataForWrite<float>(0)[i] = static_cast<float>(value);
1387 if (stereoChunk.ChannelCount() == 2) {
1388 stereoChunk.ChannelDataForWrite<float>(1)[i] = value;
1389 }
1390 time += deltaTime;
1391 }
1392
1393 AudioSegment inSegment;
1394 inSegment.AppendAndConsumeChunk(std::move(monoChunk));
1395 inSegment.AppendAndConsumeChunk(std::move(stereoChunk));
1396 // printAudioSegment(inSegment);
1397
1398 dr.AppendInput(inSegment);
1399 AudioSegment s1 = dr.Resample(out_frames);
1400 // printAudioSegment(s1);
1401
1402 EXPECT_EQ(s1.GetDuration(), 480);
1403 EXPECT_EQ(s1.GetType(), MediaSegment::AUDIO);
1404 EXPECT_TRUE(!s1.IsNull());
1405 EXPECT_TRUE(!s1.IsEmpty());
1406 EXPECT_EQ(s1.MaxChannelCount(), 2u);
1407
1408 // The resampler here is updated due to the channel change and that creates
1409 // discontinuity.
1410 dr.AppendInput(inSegment);
1411 AudioSegment s2 = dr.Resample(out_frames);
1412 // printAudioSegment(s2);
1413
1414 EXPECT_EQ(s2.GetDuration(), 480);
1415 EXPECT_EQ(s2.GetType(), MediaSegment::AUDIO);
1416 EXPECT_TRUE(!s2.IsNull());
1417 EXPECT_TRUE(!s2.IsEmpty());
1418 EXPECT_EQ(s2.MaxChannelCount(), 2u);
1419 }
1420
TEST(TestAudioResampler,ChannelChange_Discontinuity3)1421 TEST(TestAudioResampler, ChannelChange_Discontinuity3)
1422 {
1423 uint32_t in_rate = 48000;
1424 uint32_t out_rate = 48000;
1425
1426 const float amplitude = 0.5;
1427 const float frequency = 200;
1428 const float phase = 0.0;
1429 float time = 0.0;
1430 const float deltaTime = 1.0f / static_cast<float>(in_rate);
1431
1432 uint32_t in_frames = in_rate / 100;
1433 uint32_t out_frames = out_rate / 100;
1434 AudioResampler dr(in_rate, out_rate, 10);
1435
1436 AudioChunk stereoChunk =
1437 CreateAudioChunk<float>(in_frames, 2, AUDIO_FORMAT_FLOAT32);
1438 for (uint32_t i = 0; i < stereoChunk.GetDuration(); ++i) {
1439 double value = amplitude * sin(2 * M_PI * frequency * time + phase);
1440 stereoChunk.ChannelDataForWrite<float>(0)[i] = static_cast<float>(value);
1441 if (stereoChunk.ChannelCount() == 2) {
1442 stereoChunk.ChannelDataForWrite<float>(1)[i] = value;
1443 }
1444 time += deltaTime;
1445 }
1446
1447 AudioSegment inSegment;
1448 inSegment.AppendAndConsumeChunk(std::move(stereoChunk));
1449 // printAudioSegment(inSegment);
1450
1451 dr.AppendInput(inSegment);
1452 AudioSegment s = dr.Resample(out_frames);
1453 // printAudioSegment(s);
1454
1455 // The resampler here is updated due to the rate change. This is because the
1456 // in and out rate was the same so a pass through logice was used. By updating
1457 // the out rate to something different than the in rate, the resampler will
1458 // start being use dand discontinuity will exist.
1459 dr.UpdateOutRate(out_rate + 100);
1460 dr.AppendInput(inSegment);
1461 AudioSegment s2 = dr.Resample(out_frames);
1462 // printAudioSegment(s2);
1463
1464 EXPECT_EQ(s2.GetDuration(), 480);
1465 EXPECT_EQ(s2.GetType(), MediaSegment::AUDIO);
1466 EXPECT_TRUE(!s2.IsNull());
1467 EXPECT_TRUE(!s2.IsEmpty());
1468 EXPECT_EQ(s2.MaxChannelCount(), 2u);
1469 }
1470