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 size_t kBytesPerSample = sizeof(int32_t); |
29 const int kNumChannels = 2; | 30 const int kNumChannels = 2; |
30 const int kBytesPerSample = 4; | |
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 // Note: Test data should be represented as 32-bit integers and copied into |
| 40 // ::media::AudioBus instances, rather than wrapping statically declared float |
| 41 // arrays. The latter method is brittle, as ::media::AudioBus requires 16-bit |
| 42 // alignment for internal data. |
| 43 const int32_t kTestData[NUM_DATA_SETS][NUM_SAMPLES] = { |
40 { | 44 { |
41 0.034619, -0.62082, | 45 74343736, -1333200799, |
42 -0.633705, 0.530298, | 46 -1360871126, 1138806283, |
43 0.89957, 0.864411, | 47 1931811865, 1856308487, |
44 0.302309, 0.262931, | 48 649203634, 564640023, |
45 0.780742, 0.0109042, | 49 1676630678, 23416591, |
46 -0.602219, 0.255149, | 50 -1293255456, 547928305, |
47 -0.454606, 0.857073, | 51 -976258952, 1840550252, |
48 0.798388, 0.167035, | 52 1714525174, 358704931, |
49 0.458046, 0.588998, | 53 983646295, 1264863573, |
50 0.206043, 0.569494, | 54 442473973, 1222979052, |
51 0.147803, 0.170857, | 55 317404525, 366912613, |
52 0.648797, -0.475908, | 56 1393280948, -1022004648, |
53 -0.95678, -0.0743951, | 57 -2054669405, -159762261, |
54 0.524809, -0.924101, | 58 1127018745, -1984491787, |
55 0.65518, -0.322856, | 59 1406988336, -693327981, |
56 -0.721563, 0.573805, | 60 -1549544744, 1232236854, |
57 0.451849, -0.814982, | 61 970338338, -1750160519, |
58 -0.364712, 0.573464, | 62 -783213057, 1231504562, |
59 0.537977, -0.381851, | 63 1155296810, -820018779, |
60 0.53816, -0.516168, | 64 1155689800, -1108462340, |
61 -0.0700984, 0.481362, | 65 -150535168, 1033717023, |
62 0.98778, 0.852158, | 66 2121241397, 1829995370, |
63 -0.8815, -0.381422, | 67 -1893006836, -819097508, |
64 -0.230589, 0.466485, | 68 -495186107, 1001768909, |
65 -0.67107, 0.322319, | 69 -1441111852, 692174781, |
66 0.892472, -0.320276, | 70 1916569026, -687787473, |
67 -0.424015, 0.789646, | 71 -910565280, 1695751872, |
68 0.462945, 0.826759, | 72 994166817, 1775451433, |
69 0.423481, 0.229418, | 73 909418522, 492671403, |
70 -0.354715, -0.961272, | 74 -761744663, -2064315902, |
71 0.632236, -0.735754, | 75 1357716471, -1580019684, |
72 0.872045, -0.709881, | 76 1872702377, -1524457840, |
73 }, { | 77 }, { |
74 0.908805, 0.331583, | 78 1951643876, 712069070, |
75 0.514689, 0.803509, | 79 1105286211, 1725522438, |
76 -0.459579, 0.106887, | 80 -986938388, 229538084, |
77 0.48557, 0.879381, | 81 1042753634, 1888456317, |
78 0.688156, 0.692105, | 82 1477803757, 1486284170, |
79 -0.158415, -0.851542, | 83 -340193623, -1828672521, |
80 0.660676, -0.33735, | 84 1418790906, -724453609, |
81 -0.49228, 0.655911, | 85 -1057163251, 1408558147, |
82 -0.014641, 0.66197, | 86 -31441309, 1421569750, |
83 -0.573276, 0.254189, | 87 -1231100836, 545866721, |
84 0.666018, 0.98153, | 88 1430262764, 2107819625, |
85 -0.967202, -0.525433, | 89 -2077050480, -1128358776, |
86 -0.838106, -0.484799, | 90 -1799818931, -1041097926, |
87 0.889906, -0.548501, | 91 1911058583, -1177896929, |
88 -0.889936, -0.432651, | 92 -1911123008, -929110948, |
89 0.590209, 0.0801954, | 93 1267464176, 172218310, |
90 -0.953734, -0.994462, | 94 -2048128170, -2135590884, |
91 0.341957, 0.565746, | 95 734347065, 1214930283, |
92 0.605983, -0.152254, | 96 1301338583, -326962976, |
93 -0.232025, -0.54384, | 97 -498269894, -1167887508, |
94 -0.274306, 0.275652, | 98 -589067650, 591958162, |
95 0.276137, -0.367112, | 99 592999692, -788367017, |
96 -0.000647, 0.68271, | 100 -1389422, 1466108561, |
97 0.179821, 0.646818, | 101 386162657, 1389031078, |
98 0.435898, -0.669994, | 102 936083827, -1438801160, |
99 0.624382, -0.752883, | 103 1340850135, -1616803932, |
100 -0.396175, 0.776021, | 104 -850779335, 1666492408, |
101 0.600866, -0.2293, | 105 1290349909, -492418001, |
102 0.306964, -0.252563, | 106 659200170, -542374913, |
103 -0.055882, 0.480061, | 107 -120005682, 1030923147, |
104 -0.408798, -0.405238, | 108 -877887021, -870241979, |
105 0.61592, -0.16056, | 109 1322678128, -344799975, |
106 } | 110 } |
107 }; | 111 }; |
108 | 112 |
109 // Return a scoped pointer filled with the data laid out at |index| above. | 113 // Return a scoped pointer filled with the data laid out at |index| above. |
110 scoped_ptr<::media::AudioBus> GetTestData(size_t index) { | 114 scoped_ptr<::media::AudioBus> GetTestData(size_t index) { |
111 CHECK_LT(index, NUM_DATA_SETS); | 115 CHECK_LT(index, NUM_DATA_SETS); |
112 int frames = NUM_SAMPLES / kNumChannels; | 116 int frames = NUM_SAMPLES / kNumChannels; |
113 auto data = | 117 auto data = ::media::AudioBus::Create(kNumChannels, frames); |
114 ::media::AudioBus::WrapMemory(kNumChannels, frames, kTestData[index]); | 118 data->FromInterleaved(kTestData[index], frames, kBytesPerSample); |
115 return data; | 119 return data; |
116 } | 120 } |
117 | 121 |
118 class MockInputQueue : public StreamMixerAlsa::InputQueue { | 122 class MockInputQueue : public StreamMixerAlsa::InputQueue { |
119 public: | 123 public: |
120 explicit MockInputQueue(int samples_per_second) | 124 explicit MockInputQueue(int samples_per_second) |
121 : paused_(true), | 125 : paused_(true), |
122 samples_per_second_(samples_per_second), | 126 samples_per_second_(samples_per_second), |
123 max_read_size_(kTestMaxReadSize), | 127 max_read_size_(kTestMaxReadSize), |
124 multiplier_(1.0), | 128 multiplier_(1.0), |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
387 | 391 |
388 StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); | 392 StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); |
389 EXPECT_CALL(*input, Initialize(_)).Times(1); | 393 EXPECT_CALL(*input, Initialize(_)).Times(1); |
390 mixer->AddInput(make_scoped_ptr(input)); | 394 mixer->AddInput(make_scoped_ptr(input)); |
391 EXPECT_EQ(StreamMixerAlsa::kStateNormalPlayback, mixer->state()); | 395 EXPECT_EQ(StreamMixerAlsa::kStateNormalPlayback, mixer->state()); |
392 | 396 |
393 // Populate the stream with data. | 397 // Populate the stream with data. |
394 const int kNumFrames = 32; | 398 const int kNumFrames = 32; |
395 input->SetData(GetTestData(0)); | 399 input->SetData(GetTestData(0)); |
396 | 400 |
| 401 ASSERT_EQ(mock_alsa()->data().size(), 0u); |
| 402 |
397 // Write the stream to ALSA. | 403 // Write the stream to ALSA. |
398 EXPECT_CALL(*input, GetResampledData(_, kNumFrames)); | 404 EXPECT_CALL(*input, GetResampledData(_, kNumFrames)); |
399 EXPECT_CALL(*input, AfterWriteFrames(_)); | 405 EXPECT_CALL(*input, AfterWriteFrames(_)); |
400 mixer->WriteFramesForTest(); | 406 mixer->WriteFramesForTest(); |
401 | 407 |
402 // Get the actual stream rendered to ALSA, and compare it against the | 408 // Get the actual stream rendered to ALSA, and compare it against the |
403 // expected stream. The stream should match exactly. | 409 // expected stream. The stream should match exactly. |
404 auto actual = ::media::AudioBus::Create(kNumChannels, kNumFrames); | 410 auto actual = ::media::AudioBus::Create(kNumChannels, kNumFrames); |
405 ASSERT_GT(mock_alsa()->data().size(), 0u); | 411 ASSERT_GT(mock_alsa()->data().size(), 0u); |
406 actual->FromInterleaved( | 412 actual->FromInterleaved( |
407 &(mock_alsa()->data()[0]), kNumFrames, kBytesPerSample); | 413 &(mock_alsa()->data()[0]), kNumFrames, kBytesPerSample); |
408 auto expected = GetMixedAudioData(input); | 414 CompareAudioData(input->data(), *actual); |
409 CompareAudioData(*expected, *actual); | |
410 } | 415 } |
411 | 416 |
412 TEST_F(StreamMixerAlsaTest, OneStreamIsScaledDownProperly) { | 417 TEST_F(StreamMixerAlsaTest, OneStreamIsScaledDownProperly) { |
413 auto input = new testing::StrictMock<MockInputQueue>(kTestSamplesPerSecond); | 418 auto input = new testing::StrictMock<MockInputQueue>(kTestSamplesPerSecond); |
414 input->SetPaused(false); | 419 input->SetPaused(false); |
415 | 420 |
416 StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); | 421 StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); |
417 EXPECT_CALL(*input, Initialize(_)).Times(1); | 422 EXPECT_CALL(*input, Initialize(_)).Times(1); |
418 mixer->AddInput(make_scoped_ptr(input)); | 423 mixer->AddInput(make_scoped_ptr(input)); |
419 EXPECT_EQ(StreamMixerAlsa::kStateNormalPlayback, mixer->state()); | 424 EXPECT_EQ(StreamMixerAlsa::kStateNormalPlayback, mixer->state()); |
420 | 425 |
421 // Populate the stream with data. | 426 // Populate the stream with data. |
422 const int kNumFrames = 32; | 427 const int kNumFrames = 32; |
423 ASSERT_EQ((int)sizeof(kTestData[0]), | 428 ASSERT_EQ((int)sizeof(kTestData[0]), |
424 kNumChannels * kNumFrames * kBytesPerSample); | 429 kNumChannels * kNumFrames * kBytesPerSample); |
425 auto data = | 430 auto data = GetTestData(0); |
426 ::media::AudioBus::WrapMemory(kNumChannels, kNumFrames, kTestData[0]); | |
427 input->SetData(std::move(data)); | 431 input->SetData(std::move(data)); |
428 | 432 |
429 // Set a volume multiplier on the stream. | 433 // Set a volume multiplier on the stream. |
430 input->SetVolumeMultiplier(0.75); | 434 input->SetVolumeMultiplier(0.75); |
431 | 435 |
432 // Write the stream to ALSA. | 436 // Write the stream to ALSA. |
433 EXPECT_CALL(*input, GetResampledData(_, kNumFrames)); | 437 EXPECT_CALL(*input, GetResampledData(_, kNumFrames)); |
434 EXPECT_CALL(*input, AfterWriteFrames(_)); | 438 EXPECT_CALL(*input, AfterWriteFrames(_)); |
435 mixer->WriteFramesForTest(); | 439 mixer->WriteFramesForTest(); |
436 | 440 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
490 inputs.back()->SetPaused(false); | 494 inputs.back()->SetPaused(false); |
491 } | 495 } |
492 | 496 |
493 StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); | 497 StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); |
494 for (size_t i = 0; i < inputs.size(); ++i) { | 498 for (size_t i = 0; i < inputs.size(); ++i) { |
495 EXPECT_CALL(*inputs[i], Initialize(_)).Times(1); | 499 EXPECT_CALL(*inputs[i], Initialize(_)).Times(1); |
496 mixer->AddInput(make_scoped_ptr(inputs[i])); | 500 mixer->AddInput(make_scoped_ptr(inputs[i])); |
497 } | 501 } |
498 | 502 |
499 // Create edge case data for the inputs. By mixing these two short streams, | 503 // Create edge case data for the inputs. By mixing these two short streams, |
500 // every combination of {-1.0, 0.0, 1.0} is tested. Note that this test case | 504 // every combination of {-(2^31), 0, 2^31-1} is tested. This test case is |
501 // is intended to be a hand-checkable gut check. | 505 // intended to be a hand-checkable gut check. |
| 506 // Note: Test data should be represented as 32-bit integers and copied into |
| 507 // ::media::AudioBus instances, rather than wrapping statically declared float |
| 508 // arrays. The latter method is brittle, as ::media::AudioBus requires 16-bit |
| 509 // alignment for internal data. |
502 const int kNumFrames = 3; | 510 const int kNumFrames = 3; |
503 | 511 |
504 float kEdgeData[2][8] = { | 512 const int32_t kMaxSample = std::numeric_limits<int32_t>::max(); |
| 513 const int32_t kMinSample = std::numeric_limits<int32_t>::min(); |
| 514 const int32_t kEdgeData[2][8] = { |
505 { | 515 { |
506 -1.0, -1.0, | 516 kMinSample, kMinSample, |
507 -1.0, 0.0, | 517 kMinSample, 0.0, |
508 0.0, 1.0, | 518 0.0, kMaxSample, |
509 0.0, 0.0, | 519 0.0, 0.0, |
510 }, { | 520 }, { |
511 -1.0, 0.0, | 521 kMinSample, 0.0, |
512 1.0, 0.0, | 522 kMaxSample, 0.0, |
513 1.0, 1.0, | 523 kMaxSample, kMaxSample, |
514 0.0, 0.0, | 524 0.0, 0.0, |
515 } | 525 } |
516 }; | 526 }; |
517 | 527 |
518 // Hand-calculate the results. Index 0 is clamped to -1.0 from -2.0. Index | 528 // Hand-calculate the results. Index 0 is clamped to -(2^31). Index 5 is |
519 // 5 is clamped from 2.0 to 1.0. | 529 // clamped to 2^31-1. |
520 float kResult[8] = { | 530 const int32_t kResult[8] = { |
521 -1.0, -1.0, | 531 kMinSample, kMinSample, |
522 0.0, 0.0, | 532 0.0, 0.0, |
523 1.0, 1.0, | 533 kMaxSample, kMaxSample, |
524 0.0, 0.0, | 534 0.0, 0.0, |
525 }; | 535 }; |
526 | 536 |
527 for (size_t i = 0; i < inputs.size(); ++i) { | 537 for (size_t i = 0; i < inputs.size(); ++i) { |
528 auto test_data = | 538 auto test_data = ::media::AudioBus::Create(kNumChannels, kNumFrames); |
529 ::media::AudioBus::WrapMemory(kNumChannels, kNumFrames, kEdgeData[i]); | 539 test_data->FromInterleaved(kEdgeData[i], kNumFrames, kBytesPerSample); |
530 inputs[i]->SetData(std::move(test_data)); | 540 inputs[i]->SetData(std::move(test_data)); |
531 EXPECT_CALL(*inputs[i], GetResampledData(_, kNumFrames)); | 541 EXPECT_CALL(*inputs[i], GetResampledData(_, kNumFrames)); |
532 EXPECT_CALL(*inputs[i], AfterWriteFrames(_)); | 542 EXPECT_CALL(*inputs[i], AfterWriteFrames(_)); |
533 } | 543 } |
534 | 544 |
535 EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, kNumFrames)).Times(1); | 545 EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, kNumFrames)).Times(1); |
536 mixer->WriteFramesForTest(); | 546 mixer->WriteFramesForTest(); |
537 | 547 |
538 // Use the hand-calculated results above. | 548 // Use the hand-calculated results above. |
539 auto expected = | 549 auto expected = ::media::AudioBus::Create(kNumChannels, kNumFrames); |
540 ::media::AudioBus::WrapMemory(kNumChannels, kNumFrames, kResult); | 550 expected->FromInterleaved(kResult, kNumFrames, kBytesPerSample); |
541 | 551 |
542 // Get the actual stream rendered to ALSA, and compare it against the | 552 // Get the actual stream rendered to ALSA, and compare it against the |
543 // expected stream. The stream should match exactly. | 553 // expected stream. The stream should match exactly. |
544 auto actual = ::media::AudioBus::Create(kNumChannels, kNumFrames); | 554 auto actual = ::media::AudioBus::Create(kNumChannels, kNumFrames); |
545 actual->FromInterleaved( | 555 actual->FromInterleaved( |
546 &(mock_alsa()->data()[0]), kNumFrames, kBytesPerSample); | 556 &(mock_alsa()->data()[0]), kNumFrames, kBytesPerSample); |
547 CompareAudioData(*expected, *actual); | 557 CompareAudioData(*expected, *actual); |
548 } | 558 } |
549 | 559 |
550 TEST_F(StreamMixerAlsaTest, WriteBuffersOfVaryingLength) { | 560 TEST_F(StreamMixerAlsaTest, WriteBuffersOfVaryingLength) { |
(...skipping 26 matching lines...) Expand all Loading... |
577 | 587 |
578 input->SetMaxReadSize(1024); | 588 input->SetMaxReadSize(1024); |
579 EXPECT_CALL(*input, GetResampledData(_, 1024)); | 589 EXPECT_CALL(*input, GetResampledData(_, 1024)); |
580 EXPECT_CALL(*input, AfterWriteFrames(_)); | 590 EXPECT_CALL(*input, AfterWriteFrames(_)); |
581 EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, 1024)).Times(1); | 591 EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, 1024)).Times(1); |
582 mixer->WriteFramesForTest(); | 592 mixer->WriteFramesForTest(); |
583 } | 593 } |
584 | 594 |
585 } // namespace media | 595 } // namespace media |
586 } // namespace chromecast | 596 } // namespace chromecast |
OLD | NEW |