Commit 493fe2e7 authored by Sergei Istomin's avatar Sergei Istomin Committed by Commit Bot

Fix failure of ExternalAudioPipelineLoopbackData unittest ran on devices

StreamMixer can be configured to use audio post processor. The test
did not set any post processing pipeline for StreamMixer. When the test ran
on a device test failed because a device additionaly processed audio and test got
audio data changed. The test succeeded only when it is run on host (testx86).
The test was fixed to use fake post processor.

Bug: 117792326
Test: Unittests on device.
Change-Id: Ife64df2690504bac249829f98ca659b19d763f23
Reviewed-on: https://chromium-review.googlesource.com/c/1285124
Commit-Queue: Sergei Istomin <sistomin@chromium.org>
Reviewed-by: default avatarKenneth MacKay <kmackay@chromium.org>
Cr-Commit-Position: refs/heads/master@{#600888}
parent 9566887b
...@@ -259,6 +259,8 @@ test("cast_audio_backend_unittests") { ...@@ -259,6 +259,8 @@ test("cast_audio_backend_unittests") {
"filter_group_unittest.cc", "filter_group_unittest.cc",
"mock_mixer_source.cc", "mock_mixer_source.cc",
"mock_mixer_source.h", "mock_mixer_source.h",
"mock_post_processor_factory.cc",
"mock_post_processor_factory.h",
"mock_redirected_audio_output.cc", "mock_redirected_audio_output.cc",
"mock_redirected_audio_output.h", "mock_redirected_audio_output.h",
"stream_mixer_external_audio_pipeline_unittest.cc", "stream_mixer_external_audio_pipeline_unittest.cc",
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromecast/media/cma/backend/mock_post_processor_factory.h"
#include "base/logging.h"
#include "base/values.h"
namespace chromecast {
namespace media {
using testing::_;
using testing::NiceMock;
MockPostProcessor::MockPostProcessor(
MockPostProcessorFactory* factory,
const std::string& name,
const base::ListValue* filter_description_list,
int channels)
: factory_(factory), name_(name), num_output_channels_(channels) {
DCHECK(factory_);
CHECK(factory_->instances.insert({name_, this}).second);
ON_CALL(*this, ProcessFrames(_, _, _, _))
.WillByDefault(
testing::Invoke(this, &MockPostProcessor::DoProcessFrames));
if (!filter_description_list) {
// This happens for PostProcessingPipeline with no post-processors.
return;
}
// Parse |filter_description_list| for parameters.
for (size_t i = 0; i < filter_description_list->GetSize(); ++i) {
const base::DictionaryValue* description_dict;
CHECK(filter_description_list->GetDictionary(i, &description_dict));
std::string solib;
CHECK(description_dict->GetString("processor", &solib));
// This will initially be called with the actual pipeline on creation.
// Ignore and wait for the call to ResetPostProcessorsForTest.
const std::string kDelayModuleSolib = "delay.so";
if (solib == kDelayModuleSolib) {
const base::DictionaryValue* processor_config_dict;
CHECK(description_dict->GetDictionary("config", &processor_config_dict));
int module_delay;
CHECK(processor_config_dict->GetInteger("delay", &module_delay));
rendering_delay_ += module_delay;
processor_config_dict->GetBoolean("ringing", &ringing_);
processor_config_dict->GetInteger("output_channels",
&num_output_channels_);
}
}
}
MockPostProcessor::~MockPostProcessor() {
factory_->instances.erase(name_);
}
std::unique_ptr<PostProcessingPipeline>
MockPostProcessorFactory::CreatePipeline(
const std::string& name,
const base::ListValue* filter_description_list,
int channels) {
return std::make_unique<testing::NiceMock<MockPostProcessor>>(
this, name, filter_description_list, channels);
}
MockPostProcessorFactory::MockPostProcessorFactory() = default;
MockPostProcessorFactory::~MockPostProcessorFactory() = default;
} // namespace media
} // namespace chromecast
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MOCK_POST_PROCESSOR_FACTORY_H_
#define CHROMECAST_MEDIA_CMA_BACKEND_MOCK_POST_PROCESSOR_FACTORY_H_
#include <memory>
#include <string>
#include <unordered_map>
#include "base/macros.h"
#include "chromecast/media/cma/backend/post_processing_pipeline.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace chromecast {
namespace media {
class MockPostProcessorFactory;
class MockPostProcessor : public PostProcessingPipeline {
public:
MockPostProcessor(MockPostProcessorFactory* factory,
const std::string& name,
const base::ListValue* filter_description_list,
int channels);
~MockPostProcessor() override;
MOCK_METHOD4(
ProcessFrames,
int(float* data, int num_frames, float current_volume, bool is_silence));
MOCK_METHOD1(SetContentType, void(AudioContentType));
bool SetSampleRate(int sample_rate) override { return true; }
bool IsRinging() override { return ringing_; }
int delay() { return rendering_delay_; }
std::string name() const { return name_; }
float* GetOutputBuffer() override { return output_buffer_; }
int NumOutputChannels() override { return num_output_channels_; }
MOCK_METHOD2(SetPostProcessorConfig,
void(const std::string& name, const std::string& config));
MOCK_METHOD1(UpdatePlayoutChannel, void(int));
private:
int DoProcessFrames(float* data,
int num_frames,
float current_volume,
bool is_silence) {
output_buffer_ = data;
return rendering_delay_;
}
MockPostProcessorFactory* const factory_;
const std::string name_;
int rendering_delay_ = 0;
bool ringing_ = false;
float* output_buffer_ = nullptr;
int num_output_channels_;
DISALLOW_COPY_AND_ASSIGN(MockPostProcessor);
};
class MockPostProcessorFactory : public PostProcessingPipelineFactory {
public:
MockPostProcessorFactory();
~MockPostProcessorFactory() override;
std::unique_ptr<PostProcessingPipeline> CreatePipeline(
const std::string& name,
const base::ListValue* filter_description_list,
int channels) override;
std::unordered_map<std::string, MockPostProcessor*> instances;
};
} // namespace media
} // namespace chromecast
#endif // CHROMECAST_MEDIA_CMA_BACKEND_MOCK_POST_PROCESSOR_FACTORY_H_
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "chromecast/media/audio/fake_external_audio_pipeline_support.h" #include "chromecast/media/audio/fake_external_audio_pipeline_support.h"
#include "chromecast/media/cma/backend/mock_mixer_source.h" #include "chromecast/media/cma/backend/mock_mixer_source.h"
#include "chromecast/media/cma/backend/mock_post_processor_factory.h"
#include "chromecast/media/cma/backend/stream_mixer.h" #include "chromecast/media/cma/backend/stream_mixer.h"
#include "chromecast/public/media/external_audio_pipeline_shlib.h" #include "chromecast/public/media/external_audio_pipeline_shlib.h"
#include "chromecast/public/media/mixer_output_stream.h" #include "chromecast/public/media/mixer_output_stream.h"
...@@ -162,6 +163,10 @@ TEST_F(ExternalAudioPipelineTest, ExternalAudioPipelineLoopbackData) { ...@@ -162,6 +163,10 @@ TEST_F(ExternalAudioPipelineTest, ExternalAudioPipelineLoopbackData) {
// Set Volume to 1, because we'd like the input to be w/o changes. // Set Volume to 1, because we'd like the input to be w/o changes.
mixer_->SetVolume(AudioContentType::kMedia, 1); mixer_->SetVolume(AudioContentType::kMedia, 1);
// Add fake postprocessor to override test configuration running on device.
mixer_->ResetPostProcessorsForTest(
std::make_unique<MockPostProcessorFactory>(), "{}");
// CastMediaShlib::LoopbackAudioObserver mock observer. // CastMediaShlib::LoopbackAudioObserver mock observer.
MockLoopbackAudioObserver mock_loopback_observer; MockLoopbackAudioObserver mock_loopback_observer;
EXPECT_CALL(mock_loopback_observer, OnLoopbackAudio(_, _, _, _, _, _)) EXPECT_CALL(mock_loopback_observer, OnLoopbackAudio(_, _, _, _, _, _))
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <cmath> #include <cmath>
#include <limits> #include <limits>
#include <memory> #include <memory>
#include <unordered_map>
#include <utility> #include <utility>
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
...@@ -20,8 +19,8 @@ ...@@ -20,8 +19,8 @@
#include "chromecast/media/cma/backend/audio_output_redirector.h" #include "chromecast/media/cma/backend/audio_output_redirector.h"
#include "chromecast/media/cma/backend/mixer_input.h" #include "chromecast/media/cma/backend/mixer_input.h"
#include "chromecast/media/cma/backend/mock_mixer_source.h" #include "chromecast/media/cma/backend/mock_mixer_source.h"
#include "chromecast/media/cma/backend/mock_post_processor_factory.h"
#include "chromecast/media/cma/backend/mock_redirected_audio_output.h" #include "chromecast/media/cma/backend/mock_redirected_audio_output.h"
#include "chromecast/media/cma/backend/post_processing_pipeline.h"
#include "chromecast/public/media/mixer_output_stream.h" #include "chromecast/public/media/mixer_output_stream.h"
#include "chromecast/public/volume_control.h" #include "chromecast/public/volume_control.h"
#include "media/audio/audio_device_description.h" #include "media/audio/audio_device_description.h"
...@@ -204,63 +203,6 @@ class MockMixerOutput : public MixerOutputStream { ...@@ -204,63 +203,6 @@ class MockMixerOutput : public MixerOutputStream {
std::vector<float> data_; std::vector<float> data_;
}; };
class MockPostProcessorFactory;
class MockPostProcessor : public PostProcessingPipeline {
public:
MockPostProcessor(MockPostProcessorFactory* factory,
const std::string& name,
const base::ListValue* filter_description_list,
int channels);
~MockPostProcessor() override;
MOCK_METHOD4(
ProcessFrames,
int(float* data, int num_frames, float current_volume, bool is_silence));
MOCK_METHOD1(SetContentType, void(AudioContentType));
bool SetSampleRate(int sample_rate) override { return true; }
bool IsRinging() override { return ringing_; }
int delay() { return rendering_delay_; }
std::string name() const { return name_; }
float* GetOutputBuffer() override { return output_buffer_; }
int NumOutputChannels() override { return num_output_channels_; }
MOCK_METHOD2(SetPostProcessorConfig,
void(const std::string& name, const std::string& config));
MOCK_METHOD1(UpdatePlayoutChannel, void(int));
private:
int DoProcessFrames(float* data,
int num_frames,
float current_volume,
bool is_silence) {
output_buffer_ = data;
return rendering_delay_;
}
MockPostProcessorFactory* const factory_;
const std::string name_;
int rendering_delay_ = 0;
bool ringing_ = false;
float* output_buffer_ = nullptr;
int num_output_channels_;
DISALLOW_COPY_AND_ASSIGN(MockPostProcessor);
};
class MockPostProcessorFactory : public PostProcessingPipelineFactory {
public:
MockPostProcessorFactory() = default;
~MockPostProcessorFactory() override = default;
std::unique_ptr<PostProcessingPipeline> CreatePipeline(
const std::string& name,
const base::ListValue* filter_description_list,
int channels) override {
return std::make_unique<testing::NiceMock<MockPostProcessor>>(
this, name, filter_description_list, channels);
}
std::unordered_map<std::string, MockPostProcessor*> instances;
};
#define EXPECT_CALL_ALL_POSTPROCESSORS(factory, call_sig) \ #define EXPECT_CALL_ALL_POSTPROCESSORS(factory, call_sig) \
do { \ do { \
for (auto& itr : factory->instances) { \ for (auto& itr : factory->instances) { \
...@@ -274,49 +216,6 @@ void VerifyAndClearPostProcessors(MockPostProcessorFactory* factory) { ...@@ -274,49 +216,6 @@ void VerifyAndClearPostProcessors(MockPostProcessorFactory* factory) {
} }
} }
MockPostProcessor::MockPostProcessor(
MockPostProcessorFactory* factory,
const std::string& name,
const base::ListValue* filter_description_list,
int channels)
: factory_(factory), name_(name), num_output_channels_(channels) {
DCHECK(factory_);
CHECK(factory_->instances.insert({name_, this}).second);
ON_CALL(*this, ProcessFrames(_, _, _, _))
.WillByDefault(
testing::Invoke(this, &MockPostProcessor::DoProcessFrames));
if (!filter_description_list) {
// This happens for PostProcessingPipeline with no post-processors.
return;
}
// Parse |filter_description_list| for parameters.
for (size_t i = 0; i < filter_description_list->GetSize(); ++i) {
const base::DictionaryValue* description_dict;
CHECK(filter_description_list->GetDictionary(i, &description_dict));
std::string solib;
CHECK(description_dict->GetString("processor", &solib));
// This will initially be called with the actual pipeline on creation.
// Ignore and wait for the call to ResetPostProcessorsForTest.
if (solib == kDelayModuleSolib) {
const base::DictionaryValue* processor_config_dict;
CHECK(description_dict->GetDictionary("config", &processor_config_dict));
int module_delay;
CHECK(processor_config_dict->GetInteger("delay", &module_delay));
rendering_delay_ += module_delay;
processor_config_dict->GetBoolean("ringing", &ringing_);
processor_config_dict->GetInteger("output_channels",
&num_output_channels_);
}
}
}
MockPostProcessor::~MockPostProcessor() {
factory_->instances.erase(name_);
}
class MockLoopbackAudioObserver : public CastMediaShlib::LoopbackAudioObserver { class MockLoopbackAudioObserver : public CastMediaShlib::LoopbackAudioObserver {
public: public:
MockLoopbackAudioObserver() = default; MockLoopbackAudioObserver() = default;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment