OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chromecast/media/cma/backend/alsa/stream_mixer_alsa.h" | 5 #include "chromecast/media/cma/backend/alsa/stream_mixer_alsa.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 #include <limits> | 9 #include <limits> |
10 #include <utility> | 10 #include <utility> |
11 | 11 |
12 #include "base/memory/scoped_vector.h" | 12 #include "base/memory/scoped_vector.h" |
13 #include "base/message_loop/message_loop.h" | 13 #include "base/message_loop/message_loop.h" |
14 #include "base/run_loop.h" | 14 #include "base/run_loop.h" |
15 #include "base/thread_task_runner_handle.h" | 15 #include "base/thread_task_runner_handle.h" |
16 #include "chromecast/media/cma/backend/alsa/mock_alsa_wrapper.h" | 16 #include "chromecast/media/cma/backend/alsa/mock_alsa_wrapper.h" |
17 #include "media/base/audio_bus.h" | 17 #include "media/base/audio_bus.h" |
18 #include "testing/gmock/include/gmock/gmock.h" | 18 #include "testing/gmock/include/gmock/gmock.h" |
19 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
20 | 20 |
21 using testing::_; | 21 using testing::_; |
22 | 22 |
23 namespace chromecast { | 23 namespace chromecast { |
24 namespace media { | 24 namespace media { |
25 | 25 |
26 namespace { | 26 namespace { |
27 | 27 |
28 // Testing constants that are common to multiple test cases. | 28 // Testing constants that are common to multiple test cases. |
29 const int kNumChannels = 2; | 29 const int kNumChannels = 2; |
30 const int kBytesPerSample = 4; | 30 const int kBytesPerSample = sizeof(int32_t); |
cleichner
2016/01/12 17:12:32
size_t
slan
2016/01/12 17:45:07
Are you proposing sizeof(size_t)? The datatype is
cleichner
2016/01/12 18:13:54
const int kBytesPerSample = sizeof(int32_t); shoul
slan
2016/01/12 18:30:04
Ah, of course.... Done.
| |
31 const int kTestMaxReadSize = 4096; | 31 const int kTestMaxReadSize = 4096; |
32 const int kTestSamplesPerSecond = 12345; | 32 const int kTestSamplesPerSecond = 12345; |
33 | 33 |
34 // This array holds |NUM_DATA_SETS| sets of arbitrary interleaved float data. | 34 // This array holds |NUM_DATA_SETS| sets of arbitrary interleaved float data. |
35 // Each set holds |NUM_SAMPLES| / kNumChannels frames of data. | 35 // Each set holds |NUM_SAMPLES| / kNumChannels frames of data. |
36 #define NUM_DATA_SETS 2u | 36 #define NUM_DATA_SETS 2u |
37 #define NUM_SAMPLES 64u | 37 #define NUM_SAMPLES 64u |
38 | 38 |
39 float kTestData[NUM_DATA_SETS][NUM_SAMPLES] = { | 39 const int32_t kTestData[NUM_DATA_SETS][NUM_SAMPLES] = { |
40 { | 40 { |
41 0.034619, -0.62082, | 41 74343736, -1333200799, |
42 -0.633705, 0.530298, | 42 -1360871126, 1138806283, |
43 0.89957, 0.864411, | 43 1931811865, 1856308487, |
44 0.302309, 0.262931, | 44 649203634, 564640023, |
45 0.780742, 0.0109042, | 45 1676630678, 23416591, |
46 -0.602219, 0.255149, | 46 -1293255456, 547928305, |
47 -0.454606, 0.857073, | 47 -976258952, 1840550252, |
48 0.798388, 0.167035, | 48 1714525174, 358704931, |
49 0.458046, 0.588998, | 49 983646295, 1264863573, |
50 0.206043, 0.569494, | 50 442473973, 1222979052, |
51 0.147803, 0.170857, | 51 317404525, 366912613, |
52 0.648797, -0.475908, | 52 1393280948, -1022004648, |
53 -0.95678, -0.0743951, | 53 -2054669405, -159762261, |
54 0.524809, -0.924101, | 54 1127018745, -1984491787, |
55 0.65518, -0.322856, | 55 1406988336, -693327981, |
56 -0.721563, 0.573805, | 56 -1549544744, 1232236854, |
57 0.451849, -0.814982, | 57 970338338, -1750160519, |
58 -0.364712, 0.573464, | 58 -783213057, 1231504562, |
59 0.537977, -0.381851, | 59 1155296810, -820018779, |
60 0.53816, -0.516168, | 60 1155689800, -1108462340, |
61 -0.0700984, 0.481362, | 61 -150535168, 1033717023, |
62 0.98778, 0.852158, | 62 2121241397, 1829995370, |
63 -0.8815, -0.381422, | 63 -1893006836, -819097508, |
64 -0.230589, 0.466485, | 64 -495186107, 1001768909, |
65 -0.67107, 0.322319, | 65 -1441111852, 692174781, |
66 0.892472, -0.320276, | 66 1916569026, -687787473, |
67 -0.424015, 0.789646, | 67 -910565280, 1695751872, |
68 0.462945, 0.826759, | 68 994166817, 1775451433, |
69 0.423481, 0.229418, | 69 909418522, 492671403, |
70 -0.354715, -0.961272, | 70 -761744663, -2064315902, |
71 0.632236, -0.735754, | 71 1357716471, -1580019684, |
72 0.872045, -0.709881, | 72 1872702377, -1524457840, |
73 }, { | 73 }, { |
74 0.908805, 0.331583, | 74 1951643876, 712069070, |
75 0.514689, 0.803509, | 75 1105286211, 1725522438, |
76 -0.459579, 0.106887, | 76 -986938388, 229538084, |
77 0.48557, 0.879381, | 77 1042753634, 1888456317, |
78 0.688156, 0.692105, | 78 1477803757, 1486284170, |
79 -0.158415, -0.851542, | 79 -340193623, -1828672521, |
80 0.660676, -0.33735, | 80 1418790906, -724453609, |
81 -0.49228, 0.655911, | 81 -1057163251, 1408558147, |
82 -0.014641, 0.66197, | 82 -31441309, 1421569750, |
83 -0.573276, 0.254189, | 83 -1231100836, 545866721, |
84 0.666018, 0.98153, | 84 1430262764, 2107819625, |
85 -0.967202, -0.525433, | 85 -2077050480, -1128358776, |
86 -0.838106, -0.484799, | 86 -1799818931, -1041097926, |
87 0.889906, -0.548501, | 87 1911058583, -1177896929, |
88 -0.889936, -0.432651, | 88 -1911123008, -929110948, |
89 0.590209, 0.0801954, | 89 1267464176, 172218310, |
90 -0.953734, -0.994462, | 90 -2048128170, -2135590884, |
91 0.341957, 0.565746, | 91 734347065, 1214930283, |
92 0.605983, -0.152254, | 92 1301338583, -326962976, |
93 -0.232025, -0.54384, | 93 -498269894, -1167887508, |
94 -0.274306, 0.275652, | 94 -589067650, 591958162, |
95 0.276137, -0.367112, | 95 592999692, -788367017, |
96 -0.000647, 0.68271, | 96 -1389422, 1466108561, |
97 0.179821, 0.646818, | 97 386162657, 1389031078, |
98 0.435898, -0.669994, | 98 936083827, -1438801160, |
99 0.624382, -0.752883, | 99 1340850135, -1616803932, |
100 -0.396175, 0.776021, | 100 -850779335, 1666492408, |
101 0.600866, -0.2293, | 101 1290349909, -492418001, |
102 0.306964, -0.252563, | 102 659200170, -542374913, |
103 -0.055882, 0.480061, | 103 -120005682, 1030923147, |
104 -0.408798, -0.405238, | 104 -877887021, -870241979, |
105 0.61592, -0.16056, | 105 1322678128, -344799975, |
106 } | 106 } |
107 }; | 107 }; |
108 | 108 |
109 // Return a scoped pointer filled with the data laid out at |index| above. | 109 // Return a scoped pointer filled with the data laid out at |index| above. |
110 scoped_ptr<::media::AudioBus> GetTestData(size_t index) { | 110 scoped_ptr<::media::AudioBus> GetTestData(size_t index) { |
111 CHECK_LT(index, NUM_DATA_SETS); | 111 CHECK_LT(index, NUM_DATA_SETS); |
112 int frames = NUM_SAMPLES / kNumChannels; | 112 int frames = NUM_SAMPLES / kNumChannels; |
113 auto data = | 113 auto data = ::media::AudioBus::Create(kNumChannels, frames); |
114 ::media::AudioBus::WrapMemory(kNumChannels, frames, kTestData[index]); | 114 data->FromInterleaved(kTestData[index], frames, kBytesPerSample); |
115 return data; | 115 return data; |
116 } | 116 } |
117 | 117 |
118 class MockInputQueue : public StreamMixerAlsa::InputQueue { | 118 class MockInputQueue : public StreamMixerAlsa::InputQueue { |
119 public: | 119 public: |
120 explicit MockInputQueue(int samples_per_second) | 120 explicit MockInputQueue(int samples_per_second) |
121 : paused_(true), | 121 : paused_(true), |
122 samples_per_second_(samples_per_second), | 122 samples_per_second_(samples_per_second), |
123 max_read_size_(kTestMaxReadSize), | 123 max_read_size_(kTestMaxReadSize), |
124 multiplier_(1.0), | 124 multiplier_(1.0), |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
387 | 387 |
388 StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); | 388 StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); |
389 EXPECT_CALL(*input, Initialize(_)).Times(1); | 389 EXPECT_CALL(*input, Initialize(_)).Times(1); |
390 mixer->AddInput(make_scoped_ptr(input)); | 390 mixer->AddInput(make_scoped_ptr(input)); |
391 EXPECT_EQ(StreamMixerAlsa::kStateNormalPlayback, mixer->state()); | 391 EXPECT_EQ(StreamMixerAlsa::kStateNormalPlayback, mixer->state()); |
392 | 392 |
393 // Populate the stream with data. | 393 // Populate the stream with data. |
394 const int kNumFrames = 32; | 394 const int kNumFrames = 32; |
395 input->SetData(GetTestData(0)); | 395 input->SetData(GetTestData(0)); |
396 | 396 |
397 ASSERT_EQ(mock_alsa()->data().size(), 0u); | |
398 | |
397 // Write the stream to ALSA. | 399 // Write the stream to ALSA. |
398 EXPECT_CALL(*input, GetResampledData(_, kNumFrames)); | 400 EXPECT_CALL(*input, GetResampledData(_, kNumFrames)); |
399 EXPECT_CALL(*input, AfterWriteFrames(_)); | 401 EXPECT_CALL(*input, AfterWriteFrames(_)); |
400 mixer->WriteFramesForTest(); | 402 mixer->WriteFramesForTest(); |
401 | 403 |
402 // Get the actual stream rendered to ALSA, and compare it against the | 404 // Get the actual stream rendered to ALSA, and compare it against the |
403 // expected stream. The stream should match exactly. | 405 // expected stream. The stream should match exactly. |
404 auto actual = ::media::AudioBus::Create(kNumChannels, kNumFrames); | 406 auto actual = ::media::AudioBus::Create(kNumChannels, kNumFrames); |
405 ASSERT_GT(mock_alsa()->data().size(), 0u); | 407 ASSERT_GT(mock_alsa()->data().size(), 0u); |
406 actual->FromInterleaved( | 408 actual->FromInterleaved( |
407 &(mock_alsa()->data()[0]), kNumFrames, kBytesPerSample); | 409 &(mock_alsa()->data()[0]), kNumFrames, kBytesPerSample); |
408 auto expected = GetMixedAudioData(input); | 410 CompareAudioData(input->data(), *actual); |
409 CompareAudioData(*expected, *actual); | |
410 } | 411 } |
411 | 412 |
412 TEST_F(StreamMixerAlsaTest, OneStreamIsScaledDownProperly) { | 413 TEST_F(StreamMixerAlsaTest, OneStreamIsScaledDownProperly) { |
413 auto input = new testing::StrictMock<MockInputQueue>(kTestSamplesPerSecond); | 414 auto input = new testing::StrictMock<MockInputQueue>(kTestSamplesPerSecond); |
414 input->SetPaused(false); | 415 input->SetPaused(false); |
415 | 416 |
416 StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); | 417 StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); |
417 EXPECT_CALL(*input, Initialize(_)).Times(1); | 418 EXPECT_CALL(*input, Initialize(_)).Times(1); |
418 mixer->AddInput(make_scoped_ptr(input)); | 419 mixer->AddInput(make_scoped_ptr(input)); |
419 EXPECT_EQ(StreamMixerAlsa::kStateNormalPlayback, mixer->state()); | 420 EXPECT_EQ(StreamMixerAlsa::kStateNormalPlayback, mixer->state()); |
420 | 421 |
421 // Populate the stream with data. | 422 // Populate the stream with data. |
422 const int kNumFrames = 32; | 423 const int kNumFrames = 32; |
423 ASSERT_EQ((int)sizeof(kTestData[0]), | 424 ASSERT_EQ((int)sizeof(kTestData[0]), |
424 kNumChannels * kNumFrames * kBytesPerSample); | 425 kNumChannels * kNumFrames * kBytesPerSample); |
425 auto data = | 426 auto data = GetTestData(0); |
426 ::media::AudioBus::WrapMemory(kNumChannels, kNumFrames, kTestData[0]); | |
427 input->SetData(std::move(data)); | 427 input->SetData(std::move(data)); |
428 | 428 |
429 // Set a volume multiplier on the stream. | 429 // Set a volume multiplier on the stream. |
430 input->SetVolumeMultiplier(0.75); | 430 input->SetVolumeMultiplier(0.75); |
431 | 431 |
432 // Write the stream to ALSA. | 432 // Write the stream to ALSA. |
433 EXPECT_CALL(*input, GetResampledData(_, kNumFrames)); | 433 EXPECT_CALL(*input, GetResampledData(_, kNumFrames)); |
434 EXPECT_CALL(*input, AfterWriteFrames(_)); | 434 EXPECT_CALL(*input, AfterWriteFrames(_)); |
435 mixer->WriteFramesForTest(); | 435 mixer->WriteFramesForTest(); |
436 | 436 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
489 new testing::StrictMock<MockInputQueue>(kTestSamplesPerSecond)); | 489 new testing::StrictMock<MockInputQueue>(kTestSamplesPerSecond)); |
490 inputs.back()->SetPaused(false); | 490 inputs.back()->SetPaused(false); |
491 } | 491 } |
492 | 492 |
493 StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); | 493 StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); |
494 for (size_t i = 0; i < inputs.size(); ++i) { | 494 for (size_t i = 0; i < inputs.size(); ++i) { |
495 EXPECT_CALL(*inputs[i], Initialize(_)).Times(1); | 495 EXPECT_CALL(*inputs[i], Initialize(_)).Times(1); |
496 mixer->AddInput(make_scoped_ptr(inputs[i])); | 496 mixer->AddInput(make_scoped_ptr(inputs[i])); |
497 } | 497 } |
498 | 498 |
499 // Create edge case data for the inputs. By mixing these two short streams, | 499 // Create edge case data for the inputs. These are respresented as raw |
kmackay
2016/01/12 17:19:28
nit: represented
slan
2016/01/12 17:45:07
Done.
| |
500 // every combination of {-1.0, 0.0, 1.0} is tested. Note that this test case | 500 // samples instead of floats to avoid alignment issues. By mixing these two |
cleichner
2016/01/12 17:12:32
Mind clarifying the nature of the issues?
slan
2016/01/12 17:45:07
Clarified.
| |
501 // is intended to be a hand-checkable gut check. | 501 // short streams, every combination of {-(2^31), 0, 2^31} is tested. Note |
502 // that this test case is intended to be a hand-checkable gut check. | |
502 const int kNumFrames = 3; | 503 const int kNumFrames = 3; |
503 | 504 |
504 float kEdgeData[2][8] = { | 505 const int32_t kEdgeData[2][8] = { |
505 { | 506 { |
506 -1.0, -1.0, | 507 -0x7FFFFFFF, -0x7FFFFFFF, |
cleichner
2016/01/12 17:12:32
This isn't 2^31, is the range meant to be inclusiv
kmackay
2016/01/12 17:19:28
+1, should be -0x80000000 (or std::numeric_limits<
slan
2016/01/12 17:45:07
Ah, darn. My mistake. Done.
| |
507 -1.0, 0.0, | 508 -0x7FFFFFFF, 0.0, |
508 0.0, 1.0, | 509 0.0, 0x7FFFFFFF, |
509 0.0, 0.0, | 510 0.0, 0.0, |
510 }, { | 511 }, { |
511 -1.0, 0.0, | 512 -0x7FFFFFFF, 0.0, |
512 1.0, 0.0, | 513 0x7FFFFFFF, 0.0, |
513 1.0, 1.0, | 514 0x7FFFFFFF, 0x7FFFFFFF, |
514 0.0, 0.0, | 515 0.0, 0.0, |
515 } | 516 } |
516 }; | 517 }; |
517 | 518 |
518 // Hand-calculate the results. Index 0 is clamped to -1.0 from -2.0. Index | 519 // Hand-calculate the results. Index 0 is clamped from -(2^32) to -(2^31). |
519 // 5 is clamped from 2.0 to 1.0. | 520 // Index 5 is clamped from 2^32 to 2^31. |
520 float kResult[8] = { | 521 const int32_t kResult[8] = { |
521 -1.0, -1.0, | 522 -0x7FFFFFFF, -0x7FFFFFFF, |
cleichner
2016/01/12 17:12:32
Ditto.
slan
2016/01/12 17:45:07
Done.
| |
522 0.0, 0.0, | 523 0.0, 0.0, |
523 1.0, 1.0, | 524 0x7FFFFFFF, 0x7FFFFFFF, |
524 0.0, 0.0, | 525 0.0, 0.0, |
525 }; | 526 }; |
526 | 527 |
527 for (size_t i = 0; i < inputs.size(); ++i) { | 528 for (size_t i = 0; i < inputs.size(); ++i) { |
528 auto test_data = | 529 auto test_data = ::media::AudioBus::Create(kNumChannels, kNumFrames); |
529 ::media::AudioBus::WrapMemory(kNumChannels, kNumFrames, kEdgeData[i]); | 530 test_data->FromInterleaved(kEdgeData[i], kNumFrames, kBytesPerSample); |
530 inputs[i]->SetData(std::move(test_data)); | 531 inputs[i]->SetData(std::move(test_data)); |
531 EXPECT_CALL(*inputs[i], GetResampledData(_, kNumFrames)); | 532 EXPECT_CALL(*inputs[i], GetResampledData(_, kNumFrames)); |
532 EXPECT_CALL(*inputs[i], AfterWriteFrames(_)); | 533 EXPECT_CALL(*inputs[i], AfterWriteFrames(_)); |
533 } | 534 } |
534 | 535 |
535 EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, kNumFrames)).Times(1); | 536 EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, kNumFrames)).Times(1); |
536 mixer->WriteFramesForTest(); | 537 mixer->WriteFramesForTest(); |
537 | 538 |
538 // Use the hand-calculated results above. | 539 // Use the hand-calculated results above. |
539 auto expected = | 540 auto expected = ::media::AudioBus::Create(kNumChannels, kNumFrames); |
540 ::media::AudioBus::WrapMemory(kNumChannels, kNumFrames, kResult); | 541 expected->FromInterleaved(kResult, kNumFrames, kBytesPerSample); |
541 | 542 |
542 // Get the actual stream rendered to ALSA, and compare it against the | 543 // Get the actual stream rendered to ALSA, and compare it against the |
543 // expected stream. The stream should match exactly. | 544 // expected stream. The stream should match exactly. |
544 auto actual = ::media::AudioBus::Create(kNumChannels, kNumFrames); | 545 auto actual = ::media::AudioBus::Create(kNumChannels, kNumFrames); |
545 actual->FromInterleaved( | 546 actual->FromInterleaved( |
546 &(mock_alsa()->data()[0]), kNumFrames, kBytesPerSample); | 547 &(mock_alsa()->data()[0]), kNumFrames, kBytesPerSample); |
547 CompareAudioData(*expected, *actual); | 548 CompareAudioData(*expected, *actual); |
548 } | 549 } |
549 | 550 |
550 TEST_F(StreamMixerAlsaTest, WriteBuffersOfVaryingLength) { | 551 TEST_F(StreamMixerAlsaTest, WriteBuffersOfVaryingLength) { |
(...skipping 26 matching lines...) Expand all Loading... | |
577 | 578 |
578 input->SetMaxReadSize(1024); | 579 input->SetMaxReadSize(1024); |
579 EXPECT_CALL(*input, GetResampledData(_, 1024)); | 580 EXPECT_CALL(*input, GetResampledData(_, 1024)); |
580 EXPECT_CALL(*input, AfterWriteFrames(_)); | 581 EXPECT_CALL(*input, AfterWriteFrames(_)); |
581 EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, 1024)).Times(1); | 582 EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, 1024)).Times(1); |
582 mixer->WriteFramesForTest(); | 583 mixer->WriteFramesForTest(); |
583 } | 584 } |
584 | 585 |
585 } // namespace media | 586 } // namespace media |
586 } // namespace chromecast | 587 } // namespace chromecast |
OLD | NEW |