123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- // Copyright (c) 2021 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 "services/audio/device_listener_output_stream.h"
- #include "base/memory/raw_ptr.h"
- #include "base/test/gmock_callback_support.h"
- #include "base/test/task_environment.h"
- #include "media/audio/fake_audio_log_factory.h"
- #include "media/audio/fake_audio_manager.h"
- #include "media/audio/mock_audio_source_callback.h"
- #include "media/audio/test_audio_thread.h"
- #include "media/base/audio_parameters.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- using ::testing::_;
- using ::testing::InSequence;
- using media::AudioBus;
- using media::AudioManager;
- using media::AudioOutputStream;
- using media::MockAudioSourceCallback;
- using base::test::RunOnceClosure;
- namespace audio {
- namespace {
- class MockAudioOutputStream : public AudioOutputStream {
- public:
- MockAudioOutputStream() = default;
- ~MockAudioOutputStream() override = default;
- void Start(AudioSourceCallback* callback) override {
- provided_callback_ = callback;
- StartCalled(provided_callback_);
- }
- MOCK_METHOD1(StartCalled, void(AudioSourceCallback*));
- MOCK_METHOD0(Stop, void());
- MOCK_METHOD0(Open, bool());
- MOCK_METHOD1(SetVolume, void(double volume));
- MOCK_METHOD1(GetVolume, void(double* volume));
- MOCK_METHOD0(Close, void());
- MOCK_METHOD0(Flush, void());
- int SimulateOnMoreData(base::TimeDelta delay,
- base::TimeTicks delay_timestamp,
- int prior_frames_skipped,
- AudioBus* dest) {
- DCHECK(provided_callback_);
- return provided_callback_->OnMoreData(delay, delay_timestamp,
- prior_frames_skipped, dest);
- }
- void SimulateError(AudioSourceCallback::ErrorType error) {
- DCHECK(provided_callback_);
- provided_callback_->OnError(error);
- }
- private:
- raw_ptr<AudioOutputStream::AudioSourceCallback> provided_callback_ = nullptr;
- };
- class FakeAudioManagerForDeviceChange : public media::FakeAudioManager {
- public:
- FakeAudioManagerForDeviceChange()
- : FakeAudioManager(std::make_unique<media::TestAudioThread>(),
- &fake_audio_log_factory_) {}
- ~FakeAudioManagerForDeviceChange() override = default;
- void AddOutputDeviceChangeListener(AudioDeviceListener* listener) override {
- media::FakeAudioManager::AddOutputDeviceChangeListener(listener);
- AddOutputDeviceChangeListenerCalled(listener);
- }
- void RemoveOutputDeviceChangeListener(
- AudioDeviceListener* listener) override {
- media::FakeAudioManager::RemoveOutputDeviceChangeListener(listener);
- RemoveOutputDeviceChangeListenerCalled(listener);
- }
- MOCK_METHOD1(AddOutputDeviceChangeListenerCalled,
- void(AudioManager::AudioDeviceListener*));
- MOCK_METHOD1(RemoveOutputDeviceChangeListenerCalled,
- void(AudioManager::AudioDeviceListener*));
- void SimulateDeviceChange() { NotifyAllOutputDeviceChangeListeners(); }
- private:
- media::FakeAudioLogFactory fake_audio_log_factory_;
- };
- class DeviceListenerOutputStreamTest : public ::testing::Test {
- public:
- using ErrorType = AudioOutputStream::AudioSourceCallback::ErrorType;
- MOCK_METHOD0(DeviceChangeCallbackCalled, void());
- };
- // Verifies DeviceListenerOutputStream forwards all calls to the wrapped stream.
- TEST_F(DeviceListenerOutputStreamTest, DelegatesCallsToWrappedStream) {
- base::test::SingleThreadTaskEnvironment task_environment;
- FakeAudioManagerForDeviceChange mock_audio_manager;
- MockAudioOutputStream mock_stream;
- MockAudioSourceCallback mock_callback;
- double volume = 200;
- base::TimeDelta delay = base::Milliseconds(30);
- base::TimeTicks delay_timestamp =
- base::TimeTicks() + base::Milliseconds(21);
- int prior_frames_skipped = 44;
- std::unique_ptr<media::AudioBus> dest = media::AudioBus::Create(1, 128);
- InSequence sequence;
- EXPECT_CALL(mock_audio_manager, AddOutputDeviceChangeListenerCalled(_))
- .Times(1);
- EXPECT_CALL(mock_stream, Open()).Times(1);
- EXPECT_CALL(mock_stream, StartCalled(_)).Times(1);
- EXPECT_CALL(mock_callback, OnMoreData(delay, delay_timestamp,
- prior_frames_skipped, dest.get()));
- EXPECT_CALL(mock_stream, SetVolume(volume)).Times(1);
- EXPECT_CALL(mock_stream, GetVolume(&volume)).Times(1);
- EXPECT_CALL(mock_stream, Stop()).Times(1);
- EXPECT_CALL(mock_stream, Flush()).Times(1);
- EXPECT_CALL(mock_stream, Close()).Times(1);
- DeviceListenerOutputStream* stream_under_test =
- new DeviceListenerOutputStream(
- &mock_audio_manager, &mock_stream,
- base::BindRepeating(
- &DeviceListenerOutputStreamTest::DeviceChangeCallbackCalled,
- base::Unretained(this)));
- EXPECT_CALL(mock_audio_manager,
- RemoveOutputDeviceChangeListenerCalled(stream_under_test))
- .Times(1);
- stream_under_test->Open();
- stream_under_test->Start(&mock_callback);
- mock_stream.SimulateOnMoreData(delay, delay_timestamp, prior_frames_skipped,
- dest.get());
- stream_under_test->SetVolume(volume);
- stream_under_test->GetVolume(&volume);
- stream_under_test->Stop();
- stream_under_test->Flush();
- stream_under_test->Close();
- mock_audio_manager.Shutdown();
- }
- // Verifies DeviceListenerOutputStream calls device change callback on device
- // change.
- TEST_F(DeviceListenerOutputStreamTest, DeviceChangeNotification) {
- base::test::SingleThreadTaskEnvironment task_environment;
- FakeAudioManagerForDeviceChange mock_audio_manager;
- MockAudioOutputStream mock_stream;
- MockAudioSourceCallback mock_callback;
- // |stream_under_test| should call the provided callback on device change.
- EXPECT_CALL(*this, DeviceChangeCallbackCalled()).Times(1);
- DeviceListenerOutputStream* stream_under_test =
- new DeviceListenerOutputStream(
- &mock_audio_manager, &mock_stream,
- base::BindRepeating(
- &DeviceListenerOutputStreamTest::DeviceChangeCallbackCalled,
- base::Unretained(this)));
- stream_under_test->Open();
- stream_under_test->Start(&mock_callback);
- mock_audio_manager.SimulateDeviceChange();
- stream_under_test->Stop();
- stream_under_test->Close();
- mock_audio_manager.Shutdown();
- }
- // Verifies DeviceListenerOutputStream calls device change callbacks on device
- // change errors.
- TEST_F(DeviceListenerOutputStreamTest, DeviceChangeError) {
- base::test::SingleThreadTaskEnvironment task_environment;
- FakeAudioManagerForDeviceChange mock_audio_manager;
- MockAudioOutputStream mock_stream;
- MockAudioSourceCallback mock_callback;
- base::RunLoop loop;
- // |stream_under_test| should call the provided callback if it received a
- // device change error.
- EXPECT_CALL(*this, DeviceChangeCallbackCalled())
- .WillOnce(RunOnceClosure(loop.QuitClosure()));
- // |stream_under_test| should not forward device change errors.
- EXPECT_CALL(mock_callback, OnError(_)).Times(0);
- DeviceListenerOutputStream* stream_under_test =
- new DeviceListenerOutputStream(
- &mock_audio_manager, &mock_stream,
- base::BindRepeating(
- &DeviceListenerOutputStreamTest::DeviceChangeCallbackCalled,
- base::Unretained(this)));
- stream_under_test->Open();
- stream_under_test->Start(&mock_callback);
- // Simulate a device change error.
- mock_stream.SimulateError(ErrorType::kDeviceChange);
- loop.Run();
- stream_under_test->Stop();
- stream_under_test->Close();
- mock_audio_manager.Shutdown();
- }
- // Verifies DeviceListenerOutputStream forwards error callbacks.
- TEST_F(DeviceListenerOutputStreamTest, UnknownError) {
- base::test::SingleThreadTaskEnvironment task_environment;
- FakeAudioManagerForDeviceChange mock_audio_manager;
- MockAudioOutputStream mock_stream;
- MockAudioSourceCallback mock_callback;
- base::RunLoop loop;
- // |stream_under_test| should forward errors.
- EXPECT_CALL(*this, DeviceChangeCallbackCalled()).Times(0);
- EXPECT_CALL(mock_callback, OnError(ErrorType::kUnknown))
- .WillOnce(RunOnceClosure(loop.QuitClosure()));
- DeviceListenerOutputStream* stream_under_test =
- new DeviceListenerOutputStream(
- &mock_audio_manager, &mock_stream,
- base::BindRepeating(
- &DeviceListenerOutputStreamTest::DeviceChangeCallbackCalled,
- base::Unretained(this)));
- stream_under_test->Open();
- stream_under_test->Start(&mock_callback);
- // Simulate a device change error.
- mock_stream.SimulateError(ErrorType::kUnknown);
- loop.Run();
- stream_under_test->Stop();
- stream_under_test->Close();
- mock_audio_manager.Shutdown();
- }
- // Verifies DeviceListenerOutputStream elides error notifications during device
- // changes.
- TEST_F(DeviceListenerOutputStreamTest, ErrorThenDeviceChange) {
- base::test::SingleThreadTaskEnvironment task_environment;
- FakeAudioManagerForDeviceChange mock_audio_manager;
- MockAudioOutputStream mock_stream;
- MockAudioSourceCallback mock_callback;
- base::RunLoop loop;
- // |stream_under_test| should call device change callback.
- EXPECT_CALL(*this, DeviceChangeCallbackCalled())
- .WillOnce(RunOnceClosure(loop.QuitClosure()));
- // |stream_under_test| should drop deferred errors.
- EXPECT_CALL(mock_callback, OnError(_)).Times(0);
- DeviceListenerOutputStream* stream_under_test =
- new DeviceListenerOutputStream(
- &mock_audio_manager, &mock_stream,
- base::BindRepeating(
- &DeviceListenerOutputStreamTest::DeviceChangeCallbackCalled,
- base::Unretained(this)));
- stream_under_test->Open();
- stream_under_test->Start(&mock_callback);
- // Simulate an error, followed by a device change.
- mock_stream.SimulateError(ErrorType::kUnknown);
- mock_audio_manager.SimulateDeviceChange();
- loop.Run();
- stream_under_test->Stop();
- stream_under_test->Close();
- mock_audio_manager.Shutdown();
- }
- // Verifies DeviceListenerOutputStream can be stopped after receiving an error.
- TEST_F(DeviceListenerOutputStreamTest, ErrorThenStop) {
- base::test::SingleThreadTaskEnvironment task_environment(
- base::test::TaskEnvironment::TimeSource::MOCK_TIME);
- FakeAudioManagerForDeviceChange mock_audio_manager;
- MockAudioOutputStream mock_stream;
- MockAudioSourceCallback mock_callback;
- // |stream_under_test| should not call its error callback after it has been
- // stopped.
- EXPECT_CALL(mock_callback, OnError(_)).Times(0);
- DeviceListenerOutputStream* stream_under_test =
- new DeviceListenerOutputStream(
- &mock_audio_manager, &mock_stream,
- base::BindRepeating(
- &DeviceListenerOutputStreamTest::DeviceChangeCallbackCalled,
- base::Unretained(this)));
- stream_under_test->Open();
- stream_under_test->Start(&mock_callback);
- // Call stop() immediately after an error.
- mock_stream.SimulateError(ErrorType::kUnknown);
- stream_under_test->Stop();
- // Reporting the error should be delayed by 1s.
- task_environment.FastForwardUntilNoTasksRemain();
- stream_under_test->Close();
- mock_audio_manager.Shutdown();
- }
- } // namespace
- } // namespace audio
|