Chromium Code Reviews| 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); |
| 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. Note that this test |
|
cleichner
2016/01/12 18:15:27
seriously nitty nit: You have two notes in a row.
slan
2016/01/12 18:30:04
Done.
| |
| 501 // is intended to be a hand-checkable gut check. | 505 // case is 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 |