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