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 <unordered_map> | |
| 10 #include <utility> | 11 #include <utility> |
| 11 | 12 |
| 12 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
| 13 #include "base/memory/scoped_vector.h" | 14 #include "base/memory/scoped_vector.h" |
| 14 #include "base/message_loop/message_loop.h" | 15 #include "base/message_loop/message_loop.h" |
| 15 #include "base/run_loop.h" | 16 #include "base/run_loop.h" |
| 16 #include "base/threading/thread_task_runner_handle.h" | 17 #include "base/threading/thread_task_runner_handle.h" |
| 18 #include "base/values.h" | |
| 17 #include "chromecast/media/cma/backend/alsa/mock_alsa_wrapper.h" | 19 #include "chromecast/media/cma/backend/alsa/mock_alsa_wrapper.h" |
| 20 #include "chromecast/media/cma/backend/alsa/post_processing_pipeline.h" | |
| 18 #include "media/audio/audio_device_description.h" | 21 #include "media/audio/audio_device_description.h" |
| 19 #include "media/base/audio_bus.h" | 22 #include "media/base/audio_bus.h" |
| 20 #include "media/base/vector_math.h" | 23 #include "media/base/vector_math.h" |
| 21 #include "testing/gmock/include/gmock/gmock.h" | 24 #include "testing/gmock/include/gmock/gmock.h" |
| 22 #include "testing/gtest/include/gtest/gtest.h" | 25 #include "testing/gtest/include/gtest/gtest.h" |
| 23 | 26 |
| 24 using testing::_; | 27 using testing::_; |
| 25 | 28 |
| 26 namespace chromecast { | 29 namespace chromecast { |
| 27 namespace media { | 30 namespace media { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 113 1340850135, -1616803932, | 116 1340850135, -1616803932, |
| 114 -850779335, 1666492408, | 117 -850779335, 1666492408, |
| 115 1290349909, -492418001, | 118 1290349909, -492418001, |
| 116 659200170, -542374913, | 119 659200170, -542374913, |
| 117 -120005682, 1030923147, | 120 -120005682, 1030923147, |
| 118 -877887021, -870241979, | 121 -877887021, -870241979, |
| 119 1322678128, -344799975, | 122 1322678128, -344799975, |
| 120 } | 123 } |
| 121 }; | 124 }; |
| 122 | 125 |
| 126 // Compensate for integer arithmatic errors. | |
| 127 const int kMaxDelayErrorUs = 2; | |
| 128 | |
| 129 const char kDelayModuleSolib[] = "delay.so"; | |
| 130 | |
| 131 // Should match # of "processors" blocks below. | |
| 132 const int kNumPostProcessors = 5; | |
| 133 const char kTestPipelineJsonTemplate[] = R"json( | |
| 134 { | |
| 135 "output_streams": [{ | |
| 136 "streams": [ "default" ], | |
| 137 "processors": [{ | |
| 138 "processor": "%s", | |
| 139 "config": { "delay": %d } | |
| 140 }] | |
| 141 }, { | |
| 142 "streams": [ "assistant-tts" ], | |
| 143 "processors": [{ | |
| 144 "processor": "%s", | |
| 145 "config": { "delay": %d } | |
| 146 }] | |
| 147 }, { | |
| 148 "streams": [ "communications" ], | |
| 149 "processors": [] | |
| 150 }], | |
| 151 "mix": { | |
| 152 "processors": [{ | |
| 153 "processor": "%s", | |
| 154 "config": { "delay": %d } | |
| 155 }] | |
| 156 }, | |
| 157 "linearize": { | |
| 158 "processors": [{ | |
| 159 "processor": "%s", | |
| 160 "config": { "delay": %d } | |
| 161 }] | |
| 162 } | |
| 163 } | |
| 164 )json"; | |
|
kmackay
2017/04/28 21:20:08
There should be a test with multiple processors fo
bshaya
2017/04/28 22:59:30
Done.
| |
| 165 | |
| 166 const int kDefaultProcessorDelay = 10; | |
| 167 const int kTtsProcessorDelay = 100; | |
| 168 const int kMixProcessorDelay = 1000; | |
| 169 const int kLinearizeProcessorDelay = 10000; | |
| 170 | |
| 123 // Return a scoped pointer filled with the data laid out at |index| above. | 171 // Return a scoped pointer filled with the data laid out at |index| above. |
| 124 std::unique_ptr<::media::AudioBus> GetTestData(size_t index) { | 172 std::unique_ptr<::media::AudioBus> GetTestData(size_t index) { |
| 125 CHECK_LT(index, NUM_DATA_SETS); | 173 CHECK_LT(index, NUM_DATA_SETS); |
| 126 int frames = NUM_SAMPLES / kNumChannels; | 174 int frames = NUM_SAMPLES / kNumChannels; |
| 127 auto data = ::media::AudioBus::Create(kNumChannels, frames); | 175 auto data = ::media::AudioBus::Create(kNumChannels, frames); |
| 128 data->FromInterleaved(kTestData[index], frames, kBytesPerSample); | 176 data->FromInterleaved(kTestData[index], frames, kBytesPerSample); |
| 129 return data; | 177 return data; |
| 130 } | 178 } |
| 131 | 179 |
| 132 class MockInputQueue : public StreamMixerAlsa::InputQueue { | 180 class MockInputQueue : public StreamMixerAlsa::InputQueue { |
| 133 public: | 181 public: |
| 134 explicit MockInputQueue(int samples_per_second, | 182 MockInputQueue(int samples_per_second, |
| 135 const std::string& device_id = | 183 const std::string& device_id = |
| 136 ::media::AudioDeviceDescription::kDefaultDeviceId) | 184 ::media::AudioDeviceDescription::kDefaultDeviceId) |
| 137 : paused_(true), | 185 : paused_(true), |
| 138 samples_per_second_(samples_per_second), | 186 samples_per_second_(samples_per_second), |
| 139 max_read_size_(kTestMaxReadSize), | 187 max_read_size_(kTestMaxReadSize), |
| 140 multiplier_(1.0), | 188 multiplier_(1.0), |
| 141 primary_(true), | 189 primary_(true), |
| 142 deleting_(false), | 190 deleting_(false), |
| 143 device_id_(device_id), | 191 device_id_(device_id), |
| 144 filter_group_(nullptr) { | 192 filter_group_(nullptr) { |
| 145 ON_CALL(*this, GetResampledData(_, _)).WillByDefault( | 193 ON_CALL(*this, GetResampledData(_, _)).WillByDefault( |
| 146 testing::Invoke(this, &MockInputQueue::DoGetResampledData)); | 194 testing::Invoke(this, &MockInputQueue::DoGetResampledData)); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 234 bool primary_; | 282 bool primary_; |
| 235 bool deleting_; | 283 bool deleting_; |
| 236 const std::string device_id_; | 284 const std::string device_id_; |
| 237 FilterGroup* filter_group_; | 285 FilterGroup* filter_group_; |
| 238 | 286 |
| 239 std::unique_ptr<::media::AudioBus> data_; | 287 std::unique_ptr<::media::AudioBus> data_; |
| 240 | 288 |
| 241 DISALLOW_COPY_AND_ASSIGN(MockInputQueue); | 289 DISALLOW_COPY_AND_ASSIGN(MockInputQueue); |
| 242 }; | 290 }; |
| 243 | 291 |
| 292 class MockPostProcessor : public PostProcessingPipeline { | |
| 293 public: | |
| 294 MockPostProcessor(const std::string& name, | |
| 295 const base::ListValue* filter_description_list, | |
| 296 int channels) | |
| 297 : name_(name) { | |
| 298 CHECK(instances_.insert({name_, this}).second); | |
| 299 | |
| 300 if (!filter_description_list) { | |
| 301 // This happens for PostProcessingPipeline with no post-processors. | |
| 302 return; | |
| 303 } | |
| 304 | |
| 305 // Parse |filter_description_list| for parameters. | |
| 306 for (size_t i = 0; i < filter_description_list->GetSize(); ++i) { | |
| 307 const base::DictionaryValue* description_dict; | |
| 308 CHECK(filter_description_list->GetDictionary(i, &description_dict)); | |
| 309 std::string solib; | |
| 310 CHECK(description_dict->GetString("processor", &solib)); | |
| 311 // This will initially be called with the actual pipeline on creation. | |
| 312 // Ignore and wait for the call to ResetPostProcessorsForTest. | |
| 313 if (solib == kDelayModuleSolib) { | |
| 314 const base::DictionaryValue* processor_config_dict; | |
| 315 CHECK( | |
| 316 description_dict->GetDictionary("config", &processor_config_dict)); | |
| 317 int module_delay; | |
| 318 CHECK(processor_config_dict->GetInteger("delay", &module_delay)); | |
| 319 rendering_delay_ += module_delay; | |
| 320 processor_config_dict->GetBoolean("ringing", &ringing_); | |
| 321 } | |
| 322 } | |
| 323 ON_CALL(*this, ProcessFrames(_, _, _, _)) | |
| 324 .WillByDefault( | |
| 325 testing::Invoke(this, &MockPostProcessor::DoProcessFrames)); | |
| 326 } | |
| 327 ~MockPostProcessor() override { instances_.erase(name_); } | |
| 328 MOCK_METHOD4(ProcessFrames, | |
| 329 int(const std::vector<float*>& data, | |
| 330 int num_frames, | |
| 331 float current_volume, | |
| 332 bool is_silence)); | |
| 333 bool SetSampleRate(int sample_rate) override { return false; } | |
| 334 bool IsRinging() override { return ringing_; } | |
| 335 std::string name() const { return name_; } | |
| 336 | |
| 337 static std::unordered_map<std::string, MockPostProcessor*>* instances() { | |
| 338 return &instances_; | |
| 339 } | |
| 340 | |
| 341 private: | |
| 342 int DoProcessFrames(const std::vector<float*>& data, | |
| 343 int num_frames, | |
| 344 float current_volume, | |
| 345 bool is_sience) { | |
| 346 return rendering_delay_; | |
| 347 } | |
| 348 | |
| 349 static std::unordered_map<std::string, MockPostProcessor*> instances_; | |
| 350 std::string name_; | |
| 351 int rendering_delay_ = 0; | |
| 352 bool ringing_ = false; | |
| 353 | |
| 354 DISALLOW_COPY_AND_ASSIGN(MockPostProcessor); | |
| 355 }; | |
| 356 | |
| 357 std::unordered_map<std::string, MockPostProcessor*> | |
| 358 MockPostProcessor::instances_; | |
| 359 | |
| 244 // Given |inputs|, returns mixed audio data according to the mixing method used | 360 // Given |inputs|, returns mixed audio data according to the mixing method used |
| 245 // by the mixer. | 361 // by the mixer. |
| 246 std::unique_ptr<::media::AudioBus> GetMixedAudioData( | 362 std::unique_ptr<::media::AudioBus> GetMixedAudioData( |
| 247 const std::vector<testing::StrictMock<MockInputQueue>*>& inputs) { | 363 const std::vector<testing::StrictMock<MockInputQueue>*>& inputs) { |
| 248 int read_size = std::numeric_limits<int>::max(); | 364 int read_size = std::numeric_limits<int>::max(); |
| 249 for (auto* input : inputs) { | 365 for (auto* input : inputs) { |
| 250 CHECK(input); | 366 CHECK(input); |
| 251 read_size = std::min(input->MaxReadSize(), read_size); | 367 read_size = std::min(input->MaxReadSize(), read_size); |
| 252 } | 368 } |
| 253 | 369 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 290 ASSERT_EQ(expected.channels(), actual.channels()); | 406 ASSERT_EQ(expected.channels(), actual.channels()); |
| 291 ASSERT_EQ(expected.frames(), actual.frames()); | 407 ASSERT_EQ(expected.frames(), actual.frames()); |
| 292 for (int c = 0; c < expected.channels(); ++c) { | 408 for (int c = 0; c < expected.channels(); ++c) { |
| 293 const float* expected_data = expected.channel(c); | 409 const float* expected_data = expected.channel(c); |
| 294 const float* actual_data = actual.channel(c); | 410 const float* actual_data = actual.channel(c); |
| 295 for (int f = 0; f < expected.frames(); ++f) | 411 for (int f = 0; f < expected.frames(); ++f) |
| 296 ASSERT_FLOAT_EQ(*expected_data++, *actual_data++) << c << " " << f; | 412 ASSERT_FLOAT_EQ(*expected_data++, *actual_data++) << c << " " << f; |
| 297 } | 413 } |
| 298 } | 414 } |
| 299 | 415 |
| 416 // Check that MediaPipelineBackendAlsa::RenderingDelay.delay_microseconds is | |
| 417 // within kMaxDelayErrorUs of |delay| | |
| 418 MATCHER_P2(MatchDelay, delay, id, "") { | |
| 419 bool result = std::abs(arg.delay_microseconds - delay) < kMaxDelayErrorUs; | |
| 420 if (!result) { | |
| 421 LOG(ERROR) << "Expected delay_microseconds for " << id << " to be " << delay | |
| 422 << " but got " << arg.delay_microseconds; | |
| 423 } | |
| 424 return result; | |
| 425 } | |
| 426 | |
| 427 // Convert a number of frames at kTestSamplesPerSecond to microseconds | |
| 428 int64_t FramesToDelayUs(int64_t frames) { | |
| 429 return frames * base::Time::kMicrosecondsPerSecond / kTestSamplesPerSecond; | |
| 430 } | |
| 431 | |
| 300 } // namespace | 432 } // namespace |
| 301 | 433 |
| 434 std::unique_ptr<PostProcessingPipeline> PostProcessingPipeline::Create( | |
| 435 const std::string& name, | |
| 436 const base::ListValue* filter_description_list, | |
| 437 int channels) { | |
| 438 return base::MakeUnique<testing::NiceMock<MockPostProcessor>>( | |
| 439 name, filter_description_list, channels); | |
| 440 } | |
| 441 | |
| 302 class StreamMixerAlsaTest : public testing::Test { | 442 class StreamMixerAlsaTest : public testing::Test { |
| 303 protected: | 443 protected: |
| 304 StreamMixerAlsaTest() | 444 StreamMixerAlsaTest() |
| 305 : message_loop_(new base::MessageLoop()), | 445 : message_loop_(new base::MessageLoop()), |
| 306 mock_alsa_(new testing::NiceMock<MockAlsaWrapper>()) { | 446 mock_alsa_(new testing::NiceMock<MockAlsaWrapper>()) { |
| 307 StreamMixerAlsa::MakeSingleThreadedForTest(); | 447 StreamMixerAlsa::MakeSingleThreadedForTest(); |
| 308 StreamMixerAlsa::Get()->DisablePostProcessingForTest(); | 448 char test_pipeline_json[sizeof(kTestPipelineJsonTemplate) * 2]; |
|
kmackay
2017/04/28 21:20:08
The size calculation here seems a bit ad-hoc. Why
bshaya
2017/04/28 22:59:30
Done.
| |
| 449 snprintf(test_pipeline_json, sizeof(test_pipeline_json), | |
| 450 kTestPipelineJsonTemplate, kDelayModuleSolib, | |
| 451 kDefaultProcessorDelay, kDelayModuleSolib, kTtsProcessorDelay, | |
| 452 kDelayModuleSolib, kMixProcessorDelay, kDelayModuleSolib, | |
| 453 kLinearizeProcessorDelay); | |
| 454 StreamMixerAlsa::Get()->ResetPostProcessorsForTest(test_pipeline_json); | |
| 455 CHECK_EQ(MockPostProcessor::instances()->size(), | |
| 456 static_cast<size_t>(kNumPostProcessors)); | |
| 309 StreamMixerAlsa::Get()->SetAlsaWrapperForTest(base::WrapUnique(mock_alsa_)); | 457 StreamMixerAlsa::Get()->SetAlsaWrapperForTest(base::WrapUnique(mock_alsa_)); |
| 310 } | 458 } |
| 311 | 459 |
| 312 ~StreamMixerAlsaTest() override { | 460 ~StreamMixerAlsaTest() override { |
| 313 StreamMixerAlsa::Get()->ClearInputsForTest(); | 461 StreamMixerAlsa::Get()->ClearInputsForTest(); |
| 314 StreamMixerAlsa::Get()->SetAlsaWrapperForTest(nullptr); | 462 StreamMixerAlsa::Get()->SetAlsaWrapperForTest(nullptr); |
| 315 } | 463 } |
| 316 | 464 |
| 317 MockAlsaWrapper* mock_alsa() { return mock_alsa_; } | 465 MockAlsaWrapper* mock_alsa() { return mock_alsa_; } |
| 318 | 466 |
| (...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 796 EXPECT_CALL(*inputs[0], AfterWriteFrames(_)); | 944 EXPECT_CALL(*inputs[0], AfterWriteFrames(_)); |
| 797 EXPECT_CALL(*inputs[1], GetResampledData(_, _)).Times(0); | 945 EXPECT_CALL(*inputs[1], GetResampledData(_, _)).Times(0); |
| 798 EXPECT_CALL(*inputs[1], VolumeScaleAccumulate(_, _, _, _)).Times(0); | 946 EXPECT_CALL(*inputs[1], VolumeScaleAccumulate(_, _, _, _)).Times(0); |
| 799 EXPECT_CALL(*inputs[1], OnSkipped()); | 947 EXPECT_CALL(*inputs[1], OnSkipped()); |
| 800 EXPECT_CALL(*inputs[1], AfterWriteFrames(_)); | 948 EXPECT_CALL(*inputs[1], AfterWriteFrames(_)); |
| 801 | 949 |
| 802 EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, kNumFrames)).Times(1); | 950 EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, kNumFrames)).Times(1); |
| 803 mixer->WriteFramesForTest(); | 951 mixer->WriteFramesForTest(); |
| 804 } | 952 } |
| 805 | 953 |
| 954 #define EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(map, name, times, frames, \ | |
| 955 silence) \ | |
| 956 do { \ | |
| 957 auto itr = map->find(name); \ | |
| 958 CHECK(itr != map->end()) << "Could not find processor for " << name; \ | |
| 959 EXPECT_CALL(*(itr->second), ProcessFrames(_, frames, _, silence)) \ | |
| 960 .Times(times); \ | |
| 961 } while (0); | |
| 962 | |
| 963 TEST_F(StreamMixerAlsaTest, PostProcessorDelayListedDeviceId) { | |
| 964 int common_delay = kMixProcessorDelay + kLinearizeProcessorDelay; | |
| 965 std::vector<testing::StrictMock<MockInputQueue>*> inputs; | |
| 966 std::vector<int64_t> delays; | |
| 967 inputs.push_back(new testing::StrictMock<MockInputQueue>( | |
| 968 kTestSamplesPerSecond, "default")); | |
| 969 delays.push_back(common_delay + kDefaultProcessorDelay); | |
| 970 | |
| 971 inputs.push_back(new testing::StrictMock<MockInputQueue>( | |
| 972 kTestSamplesPerSecond, "communications")); | |
| 973 delays.push_back(common_delay); | |
| 974 | |
| 975 inputs.push_back(new testing::StrictMock<MockInputQueue>( | |
| 976 kTestSamplesPerSecond, "assistant-tts")); | |
| 977 delays.push_back(common_delay + kTtsProcessorDelay); | |
| 978 | |
| 979 // Convert delay from frames to microseconds. | |
| 980 std::transform(delays.begin(), delays.end(), delays.begin(), | |
| 981 &FramesToDelayUs); | |
| 982 | |
| 983 const int kNumFrames = 10; | |
| 984 for (auto* input : inputs) { | |
| 985 input->SetMaxReadSize(kNumFrames); | |
| 986 input->SetPaused(false); | |
| 987 } | |
| 988 | |
| 989 StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); | |
| 990 for (size_t i = 0; i < inputs.size(); ++i) { | |
| 991 EXPECT_CALL(*inputs[i], Initialize(_)).Times(1); | |
| 992 mixer->AddInput(base::WrapUnique(inputs[i])); | |
| 993 } | |
| 994 | |
| 995 mock_alsa()->set_avail(4086); | |
| 996 | |
| 997 auto* post_processors = MockPostProcessor::instances(); | |
| 998 EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(post_processors, "default", 1, | |
| 999 kNumFrames, false); | |
| 1000 EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(post_processors, "mix", 1, kNumFrames, | |
| 1001 false); | |
| 1002 EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(post_processors, "linearize", 1, | |
| 1003 kNumFrames, false); | |
| 1004 EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(post_processors, "communications", 1, | |
| 1005 kNumFrames, false); | |
| 1006 EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(post_processors, "assistant-tts", 1, | |
| 1007 kNumFrames, false); | |
| 1008 | |
| 1009 // Poll the inputs for data. Each input will get a different | |
| 1010 // rendering delay based on their device type. | |
| 1011 for (size_t i = 0; i < inputs.size(); ++i) { | |
| 1012 EXPECT_CALL(*inputs[i], GetResampledData(_, kNumFrames)); | |
| 1013 EXPECT_CALL(*inputs[i], VolumeScaleAccumulate(_, _, kNumFrames, _)) | |
| 1014 .Times(kNumChannels); | |
| 1015 EXPECT_CALL(*inputs[i], AfterWriteFrames( | |
| 1016 MatchDelay(delays[i], inputs[i]->device_id()))); | |
| 1017 } | |
| 1018 mixer->WriteFramesForTest(); | |
| 1019 } | |
| 1020 | |
| 1021 TEST_F(StreamMixerAlsaTest, PostProcessorDelayUnlistedDevice) { | |
| 1022 const std::string device_id = "not-a-device-id"; | |
| 1023 testing::StrictMock<MockInputQueue>* input = | |
| 1024 new testing::StrictMock<MockInputQueue>(kTestSamplesPerSecond, device_id); | |
| 1025 | |
| 1026 // Delay should be based on default processor | |
| 1027 int64_t delay = FramesToDelayUs( | |
| 1028 kDefaultProcessorDelay + kLinearizeProcessorDelay + kMixProcessorDelay); | |
| 1029 const int kNumFrames = 10; | |
| 1030 input->SetMaxReadSize(kNumFrames); | |
| 1031 input->SetPaused(false); | |
| 1032 | |
| 1033 auto* post_processors = MockPostProcessor::instances(); | |
| 1034 EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(post_processors, "default", 1, | |
| 1035 kNumFrames, false); | |
| 1036 EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(post_processors, "mix", 1, kNumFrames, | |
| 1037 false); | |
| 1038 EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(post_processors, "linearize", 1, | |
| 1039 kNumFrames, false); | |
| 1040 EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(post_processors, "communications", 0, | |
| 1041 _, _); | |
| 1042 EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(post_processors, "assistant-tts", 0, | |
| 1043 _, _); | |
| 1044 | |
| 1045 StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); | |
| 1046 EXPECT_CALL(*input, Initialize(_)); | |
| 1047 mixer->AddInput(base::WrapUnique(input)); | |
| 1048 | |
| 1049 EXPECT_CALL(*input, GetResampledData(_, kNumFrames)); | |
| 1050 EXPECT_CALL(*input, VolumeScaleAccumulate(_, _, kNumFrames, _)) | |
| 1051 .Times(kNumChannels); | |
| 1052 EXPECT_CALL(*input, AfterWriteFrames(MatchDelay(delay, device_id))); | |
| 1053 mixer->WriteFramesForTest(); | |
| 1054 } | |
| 1055 | |
| 1056 TEST_F(StreamMixerAlsaTest, PostProcessorRingingWithoutInput) { | |
| 1057 const char kTestPipelineJson[] = R"json( | |
| 1058 { | |
| 1059 "output_streams": [{ | |
| 1060 "streams": [ "default" ], | |
| 1061 "processors": [{ | |
| 1062 "processor": "%s", | |
| 1063 "config": { "delay": 0, "ringing": true} | |
| 1064 }] | |
| 1065 }, { | |
| 1066 "streams": [ "assistant-tts" ], | |
| 1067 "processors": [{ | |
| 1068 "processor": "%s", | |
| 1069 "config": { "delay": 0, "ringing": true} | |
| 1070 }] | |
| 1071 }] | |
| 1072 } | |
| 1073 )json"; | |
| 1074 | |
| 1075 const int kNumFrames = 32; | |
| 1076 testing::NiceMock<MockInputQueue>* input = | |
| 1077 new testing::NiceMock<MockInputQueue>(kTestSamplesPerSecond, "default"); | |
| 1078 input->SetMaxReadSize(kNumFrames); | |
| 1079 input->SetPaused(false); | |
| 1080 | |
| 1081 StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); | |
| 1082 char test_pipeline_json[sizeof(kTestPipelineJson) * 2]; | |
|
kmackay
2017/04/28 21:20:08
base::StringPrintf()?
bshaya
2017/04/28 22:59:30
Done.
| |
| 1083 snprintf(test_pipeline_json, sizeof(test_pipeline_json), kTestPipelineJson, | |
| 1084 kDelayModuleSolib, kDelayModuleSolib); | |
| 1085 mixer->ResetPostProcessorsForTest(test_pipeline_json); | |
| 1086 mixer->AddInput(base::WrapUnique(input)); | |
| 1087 | |
| 1088 // "mix" + "linearize" should be automatic | |
| 1089 CHECK_EQ(MockPostProcessor::instances()->size(), 4u); | |
| 1090 | |
| 1091 mock_alsa()->set_avail(4086); | |
| 1092 | |
| 1093 auto* post_processors = MockPostProcessor::instances(); | |
| 1094 EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(post_processors, "default", 1, | |
| 1095 kNumFrames, false); | |
| 1096 EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(post_processors, "mix", 1, kNumFrames, | |
| 1097 false); | |
| 1098 EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(post_processors, "linearize", 1, | |
| 1099 kNumFrames, false); | |
| 1100 EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(post_processors, "assistant-tts", 1, | |
| 1101 kNumFrames, true); | |
| 1102 | |
| 1103 mixer->WriteFramesForTest(); | |
| 1104 } | |
| 1105 | |
| 1106 TEST_F(StreamMixerAlsaTest, PostProcessorProvidesDefaultPipeline) { | |
| 1107 StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); | |
| 1108 mixer->ResetPostProcessorsForTest(""); | |
| 1109 | |
| 1110 auto* instances = MockPostProcessor::instances(); | |
| 1111 CHECK(instances->find("default") != instances->end()); | |
| 1112 CHECK(instances->find("mix") != instances->end()); | |
| 1113 CHECK(instances->find("linearize") != instances->end()); | |
| 1114 CHECK_EQ(MockPostProcessor::instances()->size(), 3u); | |
| 1115 } | |
| 1116 | |
| 1117 TEST_F(StreamMixerAlsaTest, InvalidStreamTypeCrashes) { | |
| 1118 const char json[] = R"json( | |
| 1119 { | |
| 1120 "output_streams": [{ | |
| 1121 "streams": [ "foobar" ], | |
| 1122 "processors": [{ | |
| 1123 "processor": "%s", | |
| 1124 "config": { "delay": 0 } | |
| 1125 }] | |
| 1126 }] | |
| 1127 } | |
| 1128 )json"; | |
| 1129 | |
| 1130 EXPECT_DEATH(StreamMixerAlsa::Get()->ResetPostProcessorsForTest(json), | |
| 1131 "foobar is not a stream type"); | |
| 1132 } | |
| 1133 | |
| 806 } // namespace media | 1134 } // namespace media |
| 807 } // namespace chromecast | 1135 } // namespace chromecast |
| OLD | NEW |