From 8e273264c96562ee35f60b03a1ef4e32ef8f7fcf Mon Sep 17 00:00:00 2001 From: slan Date: Thu, 23 Apr 2015 12:26:10 -0700 Subject: [PATCH] Adds method to provide custom AudioManager at runtime. Adds a static SetFactory method to media::AudioManager which allows a caller to pass an AudioManagerFactory to the AudioMananger. The static instance of AudioManager will be obtained from this factory. Also adds an implementation for Cast, to be used on third party platforms, with associated tests. BUG=none Review URL: https://codereview.chromium.org/1104583002 Cr-Commit-Position: refs/heads/master@{#326604} --- media/audio/BUILD.gn | 1 + media/audio/audio_manager.cc | 34 +++++++++++++++- media/audio/audio_manager.h | 22 ++++++++-- media/audio/audio_manager_factory.h | 28 +++++++++++++ media/audio/audio_manager_factory_unittest.cc | 58 +++++++++++++++++++++++++++ media/media.gyp | 1 + 6 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 media/audio/audio_manager_factory.h create mode 100644 media/audio/audio_manager_factory_unittest.cc diff --git a/media/audio/BUILD.gn b/media/audio/BUILD.gn index 968a2e92a81b..efdad90efea9 100644 --- a/media/audio/BUILD.gn +++ b/media/audio/BUILD.gn @@ -270,6 +270,7 @@ source_set("unittests") { sources = [ "audio_input_controller_unittest.cc", "audio_input_unittest.cc", + "audio_manager_factory_unittest.cc", "audio_manager_unittest.cc", "audio_output_controller_unittest.cc", "audio_output_device_unittest.cc", diff --git a/media/audio/audio_manager.cc b/media/audio/audio_manager.cc index 2bbffa7eb6a3..9e2ac35f9cea 100644 --- a/media/audio/audio_manager.cc +++ b/media/audio/audio_manager.cc @@ -13,12 +13,22 @@ #include "base/power_monitor/power_monitor.h" #include "base/synchronization/waitable_event.h" #include "build/build_config.h" +#include "media/audio/audio_manager_factory.h" #include "media/audio/fake_audio_log_factory.h" namespace media { namespace { + +// The singleton instance of AudioManager. This is set when Create() is called. AudioManager* g_last_created = NULL; +// The singleton instance of AudioManagerFactory. This is only set if +// SetFactory() is called. If it is set when Create() is called, its +// CreateInstance() function is used to set |g_last_created|. Otherwise, the +// linked implementation of media::CreateAudioManager is used to set +// |g_last_created|. +AudioManagerFactory* g_audio_manager_factory = NULL; + // Maximum number of failed pings to the audio thread allowed. A crash will be // issued once this count is reached. We require at least two pings before // crashing to ensure unobservable power events aren't mistakenly caught (e.g., @@ -124,7 +134,7 @@ class AudioManagerHelper : public base::PowerObserver { static base::LazyInstance::Leaky g_helper = LAZY_INSTANCE_INITIALIZER; -} +} // namespace // Forward declaration of the platform specific AudioManager factory function. AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory); @@ -137,9 +147,29 @@ AudioManager::~AudioManager() { } // static +void AudioManager::SetFactory(AudioManagerFactory* factory) { + CHECK(factory); + CHECK(!g_last_created); + CHECK(!g_audio_manager_factory); + g_audio_manager_factory = factory; +} + +// static +void AudioManager::ResetFactoryForTesting() { + if (g_audio_manager_factory) { + delete g_audio_manager_factory; + g_audio_manager_factory = nullptr; + } +} + +// static AudioManager* AudioManager::Create(AudioLogFactory* audio_log_factory) { CHECK(!g_last_created); - g_last_created = CreateAudioManager(audio_log_factory); + if (g_audio_manager_factory) + g_last_created = g_audio_manager_factory->CreateInstance(audio_log_factory); + else + g_last_created = CreateAudioManager(audio_log_factory); + return g_last_created; } diff --git a/media/audio/audio_manager.h b/media/audio/audio_manager.h index 5e49b8b399af..5da521dcca33 100644 --- a/media/audio/audio_manager.h +++ b/media/audio/audio_manager.h @@ -21,13 +21,24 @@ class SingleThreadTaskRunner; namespace media { class AudioInputStream; +class AudioManagerFactory; class AudioOutputStream; // Manages all audio resources. Provides some convenience functions that avoid // the need to provide iterators over the existing streams. class MEDIA_EXPORT AudioManager { - public: - virtual ~AudioManager(); + public: + virtual ~AudioManager(); + + // This provides an alternative to the statically linked factory method used + // to create AudioManager. This is useful for dynamically-linked third + // party clients seeking to provide a platform-specific implementation of + // AudioManager. After this is called, all static AudioManager::Create* + // methods will return an instance of AudioManager provided by |factory|. This + // call may be made at most once per process, and before any calls to static + // AudioManager::Create* methods. This method takes ownership of |factory|, + // which must not be NULL. + static void SetFactory(AudioManagerFactory* factory); // Construct the audio manager; only one instance is allowed. The manager // will forward CreateAudioLog() calls to the provided AudioLogFactory; as @@ -44,6 +55,10 @@ class MEDIA_EXPORT AudioManager { // Similar to Create() except uses a FakeAudioLogFactory for testing. static AudioManager* CreateForTesting(); + // Should only be used for testing. Resets a previously-set + // AudioManagerFactory. The instance of AudioManager is not affected. + static void ResetFactoryForTesting(); + // Returns the pointer to the last created instance, or NULL if not yet // created. This is a utility method for the code outside of media directory, // like src/chrome. @@ -130,7 +145,8 @@ class MEDIA_EXPORT AudioManager { // Do not free the returned AudioInputStream. It is owned by AudioManager. // When you are done with it, call |Stop()| and |Close()| to release it. virtual AudioInputStream* MakeAudioInputStream( - const AudioParameters& params, const std::string& device_id) = 0; + const AudioParameters& params, + const std::string& device_id) = 0; // Returns the task runner used for audio IO. virtual scoped_refptr GetTaskRunner() = 0; diff --git a/media/audio/audio_manager_factory.h b/media/audio/audio_manager_factory.h new file mode 100644 index 000000000000..11f1338d0ba5 --- /dev/null +++ b/media/audio/audio_manager_factory.h @@ -0,0 +1,28 @@ +// Copyright 2015 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 MEDIA_AUDIO_AUDIO_MANAGER_FACTORY_H_ +#define MEDIA_AUDIO_AUDIO_MANAGER_FACTORY_H_ + +#include "media/base/media_export.h" + +namespace media { + +class AudioManager; +class AudioLogFactory; + +// Allows a platform-specific implementation of AudioManager to be provided in +// place of the default implementation at run-time. +class MEDIA_EXPORT AudioManagerFactory { + public: + virtual ~AudioManagerFactory() {} + + // Creates an instance of AudioManager implementation. Caller owns the + // returned instance. |audio_log_factory| must outlive the returned instance. + virtual AudioManager* CreateInstance(AudioLogFactory* audio_log_factory) = 0; +}; + +} // namespace media + +#endif // MEDIA_AUDIO_AUDIO_MANAGER_FACTORY_H_ diff --git a/media/audio/audio_manager_factory_unittest.cc b/media/audio/audio_manager_factory_unittest.cc new file mode 100644 index 000000000000..1d13c2e02697 --- /dev/null +++ b/media/audio/audio_manager_factory_unittest.cc @@ -0,0 +1,58 @@ +// Copyright 2015 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 "base/memory/scoped_ptr.h" +#include "media/audio/audio_manager.h" +#include "media/audio/audio_manager_factory.h" +#include "media/audio/fake_audio_log_factory.h" +#include "media/audio/fake_audio_manager.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { +namespace { + +class FakeAudioManagerFactory : public AudioManagerFactory { + public: + FakeAudioManagerFactory() {} + ~FakeAudioManagerFactory() override {} + + AudioManager* CreateInstance(AudioLogFactory* audio_log_factory) override { + // |created_instance_| is used for verifying. Ownership is transferred to + // caller. + created_instance_ = new FakeAudioManager(audio_log_factory); + return created_instance_; + } + + AudioManager* created_instance() { return created_instance_; } + + private: + AudioManager* created_instance_; +}; + +} // namespace + +// Verifies that SetFactory has the intended effect. +TEST(AudioManagerFactoryTest, CreateInstance) { + // Create an audio manager and verify that it is not null. + scoped_ptr manager(AudioManager::CreateForTesting()); + ASSERT_NE(nullptr, manager.get()); + manager.reset(); + + // Set the factory. Note that ownership of |factory| is transferred to + // AudioManager. + FakeAudioManagerFactory* factory = new FakeAudioManagerFactory(); + AudioManager::SetFactory(factory); + + // Create the AudioManager instance. Verify that it matches the instance + // provided by the factory. + manager.reset(AudioManager::CreateForTesting()); + ASSERT_NE(nullptr, manager.get()); + ASSERT_EQ(factory->created_instance(), manager.get()); + + // Reset AudioManagerFactory to prevent factory from persisting to other + // tests on the same process. |manager| will reset when scope exits. + AudioManager::ResetFactoryForTesting(); +} + +} // namespace media diff --git a/media/media.gyp b/media/media.gyp index 272ee39f630b..f24cb290d334 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -1146,6 +1146,7 @@ 'audio/audio_input_unittest.cc', 'audio/audio_input_volume_unittest.cc', 'audio/audio_low_latency_input_output_unittest.cc', + 'audio/audio_manager_factory_unittest.cc', 'audio/audio_manager_unittest.cc', 'audio/audio_output_controller_unittest.cc', 'audio/audio_output_device_unittest.cc', -- 2.11.4.GIT