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" |
| 17 #include "base/strings/stringprintf.h" |
16 #include "base/threading/thread_task_runner_handle.h" | 18 #include "base/threading/thread_task_runner_handle.h" |
| 19 #include "base/values.h" |
17 #include "chromecast/media/cma/backend/alsa/mock_alsa_wrapper.h" | 20 #include "chromecast/media/cma/backend/alsa/mock_alsa_wrapper.h" |
| 21 #include "chromecast/media/cma/backend/alsa/post_processing_pipeline.h" |
18 #include "media/audio/audio_device_description.h" | 22 #include "media/audio/audio_device_description.h" |
19 #include "media/base/audio_bus.h" | 23 #include "media/base/audio_bus.h" |
20 #include "media/base/vector_math.h" | 24 #include "media/base/vector_math.h" |
21 #include "testing/gmock/include/gmock/gmock.h" | 25 #include "testing/gmock/include/gmock/gmock.h" |
22 #include "testing/gtest/include/gtest/gtest.h" | 26 #include "testing/gtest/include/gtest/gtest.h" |
23 | 27 |
24 using testing::_; | 28 using testing::_; |
25 | 29 |
26 namespace chromecast { | 30 namespace chromecast { |
27 namespace media { | 31 namespace media { |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 1340850135, -1616803932, | 117 1340850135, -1616803932, |
114 -850779335, 1666492408, | 118 -850779335, 1666492408, |
115 1290349909, -492418001, | 119 1290349909, -492418001, |
116 659200170, -542374913, | 120 659200170, -542374913, |
117 -120005682, 1030923147, | 121 -120005682, 1030923147, |
118 -877887021, -870241979, | 122 -877887021, -870241979, |
119 1322678128, -344799975, | 123 1322678128, -344799975, |
120 } | 124 } |
121 }; | 125 }; |
122 | 126 |
| 127 // Compensate for integer arithmatic errors. |
| 128 const int kMaxDelayErrorUs = 2; |
| 129 |
| 130 const char kDelayModuleSolib[] = "delay.so"; |
| 131 |
| 132 // Should match # of "processors" blocks below. |
| 133 const int kNumPostProcessors = 5; |
| 134 const char kTestPipelineJsonTemplate[] = R"json( |
| 135 { |
| 136 "output_streams": [{ |
| 137 "streams": [ "default" ], |
| 138 "processors": [{ |
| 139 "processor": "%s", |
| 140 "config": { "delay": %d } |
| 141 }] |
| 142 }, { |
| 143 "streams": [ "assistant-tts" ], |
| 144 "processors": [{ |
| 145 "processor": "%s", |
| 146 "config": { "delay": %d } |
| 147 }] |
| 148 }, { |
| 149 "streams": [ "communications" ], |
| 150 "processors": [] |
| 151 }], |
| 152 "mix": { |
| 153 "processors": [{ |
| 154 "processor": "%s", |
| 155 "config": { "delay": %d } |
| 156 }] |
| 157 }, |
| 158 "linearize": { |
| 159 "processors": [{ |
| 160 "processor": "%s", |
| 161 "config": { "delay": %d } |
| 162 }] |
| 163 } |
| 164 } |
| 165 )json"; |
| 166 |
| 167 const int kDefaultProcessorDelay = 10; |
| 168 const int kTtsProcessorDelay = 100; |
| 169 const int kMixProcessorDelay = 1000; |
| 170 const int kLinearizeProcessorDelay = 10000; |
| 171 |
123 // Return a scoped pointer filled with the data laid out at |index| above. | 172 // Return a scoped pointer filled with the data laid out at |index| above. |
124 std::unique_ptr<::media::AudioBus> GetTestData(size_t index) { | 173 std::unique_ptr<::media::AudioBus> GetTestData(size_t index) { |
125 CHECK_LT(index, NUM_DATA_SETS); | 174 CHECK_LT(index, NUM_DATA_SETS); |
126 int frames = NUM_SAMPLES / kNumChannels; | 175 int frames = NUM_SAMPLES / kNumChannels; |
127 auto data = ::media::AudioBus::Create(kNumChannels, frames); | 176 auto data = ::media::AudioBus::Create(kNumChannels, frames); |
128 data->FromInterleaved(kTestData[index], frames, kBytesPerSample); | 177 data->FromInterleaved(kTestData[index], frames, kBytesPerSample); |
129 return data; | 178 return data; |
130 } | 179 } |
131 | 180 |
132 class MockInputQueue : public StreamMixerAlsa::InputQueue { | 181 class MockInputQueue : public StreamMixerAlsa::InputQueue { |
133 public: | 182 public: |
134 explicit MockInputQueue(int samples_per_second, | 183 MockInputQueue(int samples_per_second, |
135 const std::string& device_id = | 184 const std::string& device_id = |
136 ::media::AudioDeviceDescription::kDefaultDeviceId) | 185 ::media::AudioDeviceDescription::kDefaultDeviceId) |
137 : paused_(true), | 186 : paused_(true), |
138 samples_per_second_(samples_per_second), | 187 samples_per_second_(samples_per_second), |
139 max_read_size_(kTestMaxReadSize), | 188 max_read_size_(kTestMaxReadSize), |
140 multiplier_(1.0), | 189 multiplier_(1.0), |
141 primary_(true), | 190 primary_(true), |
142 deleting_(false), | 191 deleting_(false), |
143 device_id_(device_id), | 192 device_id_(device_id), |
144 filter_group_(nullptr) { | 193 filter_group_(nullptr) { |
145 ON_CALL(*this, GetResampledData(_, _)).WillByDefault( | 194 ON_CALL(*this, GetResampledData(_, _)).WillByDefault( |
146 testing::Invoke(this, &MockInputQueue::DoGetResampledData)); | 195 testing::Invoke(this, &MockInputQueue::DoGetResampledData)); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 bool primary_; | 283 bool primary_; |
235 bool deleting_; | 284 bool deleting_; |
236 const std::string device_id_; | 285 const std::string device_id_; |
237 FilterGroup* filter_group_; | 286 FilterGroup* filter_group_; |
238 | 287 |
239 std::unique_ptr<::media::AudioBus> data_; | 288 std::unique_ptr<::media::AudioBus> data_; |
240 | 289 |
241 DISALLOW_COPY_AND_ASSIGN(MockInputQueue); | 290 DISALLOW_COPY_AND_ASSIGN(MockInputQueue); |
242 }; | 291 }; |
243 | 292 |
| 293 class MockPostProcessor : public PostProcessingPipeline { |
| 294 public: |
| 295 MockPostProcessor(const std::string& name, |
| 296 const base::ListValue* filter_description_list, |
| 297 int channels) |
| 298 : name_(name) { |
| 299 CHECK(instances_.insert({name_, this}).second); |
| 300 |
| 301 if (!filter_description_list) { |
| 302 // This happens for PostProcessingPipeline with no post-processors. |
| 303 return; |
| 304 } |
| 305 |
| 306 // Parse |filter_description_list| for parameters. |
| 307 for (size_t i = 0; i < filter_description_list->GetSize(); ++i) { |
| 308 const base::DictionaryValue* description_dict; |
| 309 CHECK(filter_description_list->GetDictionary(i, &description_dict)); |
| 310 std::string solib; |
| 311 CHECK(description_dict->GetString("processor", &solib)); |
| 312 // This will initially be called with the actual pipeline on creation. |
| 313 // Ignore and wait for the call to ResetPostProcessorsForTest. |
| 314 if (solib == kDelayModuleSolib) { |
| 315 const base::DictionaryValue* processor_config_dict; |
| 316 CHECK( |
| 317 description_dict->GetDictionary("config", &processor_config_dict)); |
| 318 int module_delay; |
| 319 CHECK(processor_config_dict->GetInteger("delay", &module_delay)); |
| 320 rendering_delay_ += module_delay; |
| 321 processor_config_dict->GetBoolean("ringing", &ringing_); |
| 322 } |
| 323 } |
| 324 ON_CALL(*this, ProcessFrames(_, _, _, _)) |
| 325 .WillByDefault( |
| 326 testing::Invoke(this, &MockPostProcessor::DoProcessFrames)); |
| 327 } |
| 328 ~MockPostProcessor() override { instances_.erase(name_); } |
| 329 MOCK_METHOD4(ProcessFrames, |
| 330 int(const std::vector<float*>& data, |
| 331 int num_frames, |
| 332 float current_volume, |
| 333 bool is_silence)); |
| 334 bool SetSampleRate(int sample_rate) override { return false; } |
| 335 bool IsRinging() override { return ringing_; } |
| 336 int delay() { return rendering_delay_; } |
| 337 std::string name() const { return name_; } |
| 338 |
| 339 static std::unordered_map<std::string, MockPostProcessor*>* instances() { |
| 340 return &instances_; |
| 341 } |
| 342 |
| 343 private: |
| 344 int DoProcessFrames(const std::vector<float*>& data, |
| 345 int num_frames, |
| 346 float current_volume, |
| 347 bool is_sience) { |
| 348 return rendering_delay_; |
| 349 } |
| 350 |
| 351 static std::unordered_map<std::string, MockPostProcessor*> instances_; |
| 352 std::string name_; |
| 353 int rendering_delay_ = 0; |
| 354 bool ringing_ = false; |
| 355 |
| 356 DISALLOW_COPY_AND_ASSIGN(MockPostProcessor); |
| 357 }; |
| 358 |
| 359 std::unordered_map<std::string, MockPostProcessor*> |
| 360 MockPostProcessor::instances_; |
| 361 |
244 // Given |inputs|, returns mixed audio data according to the mixing method used | 362 // Given |inputs|, returns mixed audio data according to the mixing method used |
245 // by the mixer. | 363 // by the mixer. |
246 std::unique_ptr<::media::AudioBus> GetMixedAudioData( | 364 std::unique_ptr<::media::AudioBus> GetMixedAudioData( |
247 const std::vector<testing::StrictMock<MockInputQueue>*>& inputs) { | 365 const std::vector<testing::StrictMock<MockInputQueue>*>& inputs) { |
248 int read_size = std::numeric_limits<int>::max(); | 366 int read_size = std::numeric_limits<int>::max(); |
249 for (auto* input : inputs) { | 367 for (auto* input : inputs) { |
250 CHECK(input); | 368 CHECK(input); |
251 read_size = std::min(input->MaxReadSize(), read_size); | 369 read_size = std::min(input->MaxReadSize(), read_size); |
252 } | 370 } |
253 | 371 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
290 ASSERT_EQ(expected.channels(), actual.channels()); | 408 ASSERT_EQ(expected.channels(), actual.channels()); |
291 ASSERT_EQ(expected.frames(), actual.frames()); | 409 ASSERT_EQ(expected.frames(), actual.frames()); |
292 for (int c = 0; c < expected.channels(); ++c) { | 410 for (int c = 0; c < expected.channels(); ++c) { |
293 const float* expected_data = expected.channel(c); | 411 const float* expected_data = expected.channel(c); |
294 const float* actual_data = actual.channel(c); | 412 const float* actual_data = actual.channel(c); |
295 for (int f = 0; f < expected.frames(); ++f) | 413 for (int f = 0; f < expected.frames(); ++f) |
296 ASSERT_FLOAT_EQ(*expected_data++, *actual_data++) << c << " " << f; | 414 ASSERT_FLOAT_EQ(*expected_data++, *actual_data++) << c << " " << f; |
297 } | 415 } |
298 } | 416 } |
299 | 417 |
| 418 // Check that MediaPipelineBackendAlsa::RenderingDelay.delay_microseconds is |
| 419 // within kMaxDelayErrorUs of |delay| |
| 420 MATCHER_P2(MatchDelay, delay, id, "") { |
| 421 bool result = std::abs(arg.delay_microseconds - delay) < kMaxDelayErrorUs; |
| 422 if (!result) { |
| 423 LOG(ERROR) << "Expected delay_microseconds for " << id << " to be " << delay |
| 424 << " but got " << arg.delay_microseconds; |
| 425 } |
| 426 return result; |
| 427 } |
| 428 |
| 429 // Convert a number of frames at kTestSamplesPerSecond to microseconds |
| 430 int64_t FramesToDelayUs(int64_t frames) { |
| 431 return frames * base::Time::kMicrosecondsPerSecond / kTestSamplesPerSecond; |
| 432 } |
| 433 |
300 } // namespace | 434 } // namespace |
301 | 435 |
| 436 std::unique_ptr<PostProcessingPipeline> PostProcessingPipeline::Create( |
| 437 const std::string& name, |
| 438 const base::ListValue* filter_description_list, |
| 439 int channels) { |
| 440 return base::MakeUnique<testing::NiceMock<MockPostProcessor>>( |
| 441 name, filter_description_list, channels); |
| 442 } |
| 443 |
302 class StreamMixerAlsaTest : public testing::Test { | 444 class StreamMixerAlsaTest : public testing::Test { |
303 protected: | 445 protected: |
304 StreamMixerAlsaTest() | 446 StreamMixerAlsaTest() |
305 : message_loop_(new base::MessageLoop()), | 447 : message_loop_(new base::MessageLoop()), |
306 mock_alsa_(new testing::NiceMock<MockAlsaWrapper>()) { | 448 mock_alsa_(new testing::NiceMock<MockAlsaWrapper>()) { |
307 StreamMixerAlsa::MakeSingleThreadedForTest(); | 449 StreamMixerAlsa::MakeSingleThreadedForTest(); |
308 StreamMixerAlsa::Get()->DisablePostProcessingForTest(); | 450 std::string test_pipeline_json = base::StringPrintf( |
| 451 kTestPipelineJsonTemplate, kDelayModuleSolib, kDefaultProcessorDelay, |
| 452 kDelayModuleSolib, kTtsProcessorDelay, kDelayModuleSolib, |
| 453 kMixProcessorDelay, kDelayModuleSolib, 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 std::string test_pipeline_json = base::StringPrintf( |
| 1083 kTestPipelineJson, kDelayModuleSolib, kDelayModuleSolib); |
| 1084 mixer->ResetPostProcessorsForTest(test_pipeline_json); |
| 1085 mixer->AddInput(base::WrapUnique(input)); |
| 1086 |
| 1087 // "mix" + "linearize" should be automatic |
| 1088 CHECK_EQ(MockPostProcessor::instances()->size(), 4u); |
| 1089 |
| 1090 mock_alsa()->set_avail(4086); |
| 1091 |
| 1092 auto* post_processors = MockPostProcessor::instances(); |
| 1093 EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(post_processors, "default", 1, |
| 1094 kNumFrames, false); |
| 1095 EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(post_processors, "mix", 1, kNumFrames, |
| 1096 false); |
| 1097 EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(post_processors, "linearize", 1, |
| 1098 kNumFrames, false); |
| 1099 EXPECT_POSTPROCESSOR_CALL_PROCESSFRAMES(post_processors, "assistant-tts", 1, |
| 1100 kNumFrames, true); |
| 1101 |
| 1102 mixer->WriteFramesForTest(); |
| 1103 } |
| 1104 |
| 1105 TEST_F(StreamMixerAlsaTest, PostProcessorProvidesDefaultPipeline) { |
| 1106 StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); |
| 1107 mixer->ResetPostProcessorsForTest("{}"); |
| 1108 |
| 1109 auto* instances = MockPostProcessor::instances(); |
| 1110 CHECK(instances->find("default") != instances->end()); |
| 1111 CHECK(instances->find("mix") != instances->end()); |
| 1112 CHECK(instances->find("linearize") != instances->end()); |
| 1113 CHECK_EQ(MockPostProcessor::instances()->size(), 3u); |
| 1114 } |
| 1115 |
| 1116 TEST_F(StreamMixerAlsaTest, InvalidStreamTypeCrashes) { |
| 1117 const char json[] = R"json( |
| 1118 { |
| 1119 "output_streams": [{ |
| 1120 "streams": [ "foobar" ], |
| 1121 "processors": [{ |
| 1122 "processor": "dont_care.so", |
| 1123 "config": { "delay": 0 } |
| 1124 }] |
| 1125 }] |
| 1126 } |
| 1127 )json"; |
| 1128 |
| 1129 EXPECT_DEATH(StreamMixerAlsa::Get()->ResetPostProcessorsForTest(json), |
| 1130 "foobar is not a stream type"); |
| 1131 } |
| 1132 |
| 1133 TEST_F(StreamMixerAlsaTest, BadJsonCrashes) { |
| 1134 const std::string json("{{"); |
| 1135 EXPECT_DEATH(StreamMixerAlsa::Get()->ResetPostProcessorsForTest(json), |
| 1136 "Invalid JSON"); |
| 1137 } |
| 1138 |
| 1139 TEST_F(StreamMixerAlsaTest, MultiplePostProcessorsInOneStream) { |
| 1140 const char kJsonTemplate[] = R"json( |
| 1141 { |
| 1142 "output_streams": [{ |
| 1143 "streams": [ "default" ], |
| 1144 "processors": [{ |
| 1145 "processor": "%s", |
| 1146 "config": { "delay": 10 } |
| 1147 }, { |
| 1148 "processor": "%s", |
| 1149 "config": { "delay": 100 } |
| 1150 }] |
| 1151 }], |
| 1152 "mix": { |
| 1153 "processors": [{ |
| 1154 "processor": "%s", |
| 1155 "config": { "delay": 1000 } |
| 1156 }, { |
| 1157 "processor": "%s", |
| 1158 "config": { "delay": 10000 } |
| 1159 }] |
| 1160 } |
| 1161 } |
| 1162 )json"; |
| 1163 |
| 1164 std::string json = |
| 1165 base::StringPrintf(kJsonTemplate, kDelayModuleSolib, kDelayModuleSolib, |
| 1166 kDelayModuleSolib, kDelayModuleSolib); |
| 1167 |
| 1168 StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); |
| 1169 mixer->ResetPostProcessorsForTest(json); |
| 1170 |
| 1171 // "mix" + "linearize" + "default" |
| 1172 CHECK_EQ(MockPostProcessor::instances()->size(), 3u); |
| 1173 |
| 1174 auto* post_processors = MockPostProcessor::instances(); |
| 1175 CHECK_EQ(post_processors->find("default")->second->delay(), 110); |
| 1176 CHECK_EQ(post_processors->find("mix")->second->delay(), 11000); |
| 1177 CHECK_EQ(post_processors->find("linearize")->second->delay(), 0); |
| 1178 mixer->WriteFramesForTest(); |
| 1179 } |
| 1180 |
806 } // namespace media | 1181 } // namespace media |
807 } // namespace chromecast | 1182 } // namespace chromecast |
OLD | NEW |