diff options
author | dalecurtis@google.com <dalecurtis@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-11 01:59:37 +0000 |
---|---|---|
committer | dalecurtis@google.com <dalecurtis@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-11 01:59:37 +0000 |
commit | ca8ceaa180917272404e2de7752a2052bd2dbfbf (patch) | |
tree | 3e4b8c1f025125b5875a8228296fabfdc3f2a1bd /media | |
parent | 9bb9f99499ea9e60b3269c9e6053b5a3af1d51eb (diff) | |
download | chromium_src-ca8ceaa180917272404e2de7752a2052bd2dbfbf.zip chromium_src-ca8ceaa180917272404e2de7752a2052bd2dbfbf.tar.gz chromium_src-ca8ceaa180917272404e2de7752a2052bd2dbfbf.tar.bz2 |
Revert 176228
> Improve thread safety for device changes on OSX.
>
> Device changes are hard, lets go shopping! Sadly OSX does not handle property
> listener callbacks in a thread safe manner. On 10.6 we can set
> kAudioHardwarePropertyRunLoop to account for this. On 10.7 this is broken
> and we need to create a dispatch queue to drive callbacks. However code
> running on the dispatch queue must be mutually exclusive with code running
> on the audio thread.
>
> ExclusiveDispatchQueueTaskObserver works around this by pausing and resuming
> the dispatch queue before and after each pumped task. Benchmarks on my retina
> 10.8.2 macbook pro show on average this takes < 30us in total. No performance
> issues were seen even using FakeAudioOutputStream which drives audio callbacks
> on the message loop.
>
> Complicating matters it the fact that the AudioProperty(Add|Remove)ListenerBlock
> functions are not available on 10.6... so we need to dynamically load them :-/
>
> This is not ideal and long term we should replace the audio thread on OSX with a
> dispatch queue to avoid having to suspend/resume the queue; this is non-trivial
> and requires a significant refactoring of the AudioManager to support.
>
> BUG=158170
> TEST=media_unittests. manual device changes.
>
> Review URL: https://codereview.chromium.org/11824018
Fails on 10.6 :(
TBR=dalecurtis@google.com
Review URL: https://codereview.chromium.org/11840005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@176230 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/audio/audio_manager_base.cc | 7 | ||||
-rw-r--r-- | media/audio/mac/audio_device_listener_mac.cc | 243 | ||||
-rw-r--r-- | media/audio/mac/audio_device_listener_mac.h | 59 | ||||
-rw-r--r-- | media/audio/mac/audio_device_listener_mac_unittest.cc | 82 | ||||
-rw-r--r-- | media/audio/mac/audio_manager_mac.cc | 87 | ||||
-rw-r--r-- | media/audio/mac/audio_manager_mac.h | 12 | ||||
-rw-r--r-- | media/audio/win/audio_manager_win.h | 2 | ||||
-rw-r--r-- | media/media.gyp | 3 |
8 files changed, 76 insertions, 419 deletions
diff --git a/media/audio/audio_manager_base.cc b/media/audio/audio_manager_base.cc index 41c226d..458e53b 100644 --- a/media/audio/audio_manager_base.cc +++ b/media/audio/audio_manager_base.cc @@ -54,14 +54,7 @@ AudioManagerBase::AudioManagerBase() #if defined(OS_WIN) audio_thread_->init_com_with_mta(true); #endif -#if defined(OS_MACOSX) - // On Mac, use a UI loop to get native message pump so that CoreAudio property - // listener callbacks fire. - CHECK(audio_thread_->StartWithOptions( - base::Thread::Options(MessageLoop::TYPE_UI, 0))); -#else CHECK(audio_thread_->Start()); -#endif message_loop_ = audio_thread_->message_loop_proxy(); } diff --git a/media/audio/mac/audio_device_listener_mac.cc b/media/audio/mac/audio_device_listener_mac.cc deleted file mode 100644 index a868e05..0000000 --- a/media/audio/mac/audio_device_listener_mac.cc +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright (c) 2013 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 "media/audio/mac/audio_device_listener_mac.h" - -#include "base/file_path.h" -#include "base/logging.h" -#include "base/mac/libdispatch_task_runner.h" -#include "base/mac/mac_logging.h" -#include "base/mac/mac_util.h" -#include "base/message_loop.h" -#include "base/native_library.h" - -namespace media { - -// The following three variables are used for dynamically loading the required -// AudioObject(Add|Remove)PropertyListenerBlock functions on 10.7+ while keeping -// a 10.6 deployment target. See http://crbug.com/158170 for details on why. -// TODO(dalecurtis): Remove once the deployment target is > 10.6. -static const char kCoreAudioFrameworkPath[] = - "/System/Library/Frameworks/CoreAudio.framework/Versions/Current/CoreAudio"; - -typedef OSStatus(*AudioObjectPropertyListenerBlockT)( - AudioObjectID inObjectID, - const AudioObjectPropertyAddress* inAddress, - dispatch_queue_t inDispatchQueue, - CrAudioObjectPropertyListenerBlock inListener); - -static AudioObjectPropertyListenerBlockT g_add_listener_block_func = NULL; -static AudioObjectPropertyListenerBlockT g_remove_listener_block_func = NULL; - -// TaskObserver which guarantees that dispatch queue operations such as property -// listener callbacks are mutually exclusive to operations on the audio thread. -// TODO(dalecurtis): Instead we should replace the main thread with a dispatch -// queue. See http://crbug.com/158170. -class ExclusiveDispatchQueueTaskObserver : public MessageLoop::TaskObserver { - public: - ExclusiveDispatchQueueTaskObserver() - : property_listener_queue_(new base::mac::LibDispatchTaskRunner( - "com.google.chrome.AudioPropertyListenerQueue")), - queue_(property_listener_queue_->GetDispatchQueue()), - message_loop_(MessageLoop::current()) { - // If we're currently on the thread, fire the suspend operation so we don't - // end up with an unbalanced resume. - if (message_loop_->message_loop_proxy()->BelongsToCurrentThread()) - WillProcessTask(base::TimeTicks()); - - message_loop_->AddTaskObserver(this); - } - - virtual ~ExclusiveDispatchQueueTaskObserver() { - message_loop_->RemoveTaskObserver(this); - - // If we're currently on the thread, fire the resume operation so we don't - // end up with an unbalanced suspend. - if (message_loop_->message_loop_proxy()->BelongsToCurrentThread()) - DidProcessTask(base::TimeTicks()); - - // This will hang if any listeners are still registered with the queue. - property_listener_queue_->Shutdown(); - } - - virtual void WillProcessTask(base::TimeTicks time_posted) OVERRIDE { - // Issue a synchronous suspend operation. Benchmarks on a retina 10.8.2 - // machine show this takes < 20us on average. dispatch_suspend() is an - // asynchronous operation so we need to issue it inside of a synchronous - // block to ensure it completes before WillProccesTask() completes. - dispatch_sync(queue_, ^{ - dispatch_suspend(queue_); - }); - } - - virtual void DidProcessTask(base::TimeTicks time_posted) OVERRIDE { - // Issue an asynchronous resume operation. Benchmarks on a retina 10.8.2 - // machine show this takes < 10us on average. - dispatch_resume(queue_); - } - - dispatch_queue_t dispatch_queue() const { - return queue_; - } - - private: - scoped_refptr<base::mac::LibDispatchTaskRunner> property_listener_queue_; - const dispatch_queue_t queue_; - MessageLoop* message_loop_; - - DISALLOW_COPY_AND_ASSIGN(ExclusiveDispatchQueueTaskObserver); -}; - -static bool LoadAudioObjectPropertyListenerBlockFunctions() { - if (g_add_listener_block_func && g_remove_listener_block_func) - return true; - - // Dynamically load required block functions. - // TODO(dalecurtis): Remove once the deployment target is > 10.6. - std::string error; - base::NativeLibrary core_audio = base::LoadNativeLibrary( - FilePath(kCoreAudioFrameworkPath), &error); - if (!error.empty()) { - LOG(ERROR) << "Could not open CoreAudio library: " << error; - return false; - } - - g_add_listener_block_func = - reinterpret_cast<AudioObjectPropertyListenerBlockT>( - base::GetFunctionPointerFromNativeLibrary( - core_audio, "AudioObjectAddPropertyListenerBlock")); - g_remove_listener_block_func = - reinterpret_cast<AudioObjectPropertyListenerBlockT>( - base::GetFunctionPointerFromNativeLibrary( - core_audio, "AudioObjectRemovePropertyListenerBlock")); - - // If either function failed to load, skip listener registration. - if (!g_add_listener_block_func || !g_remove_listener_block_func) { - g_add_listener_block_func = NULL; - g_remove_listener_block_func = NULL; - return false; - } - - return true; -} - -// Property address to monitor for device changes. -const AudioObjectPropertyAddress -AudioDeviceListenerMac::kDeviceChangePropertyAddress = { - kAudioHardwarePropertyDefaultOutputDevice, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster -}; - -// Callback from the system when the default device changes; this must be called -// on the MessageLoop that created the AudioManager. -// static -OSStatus AudioDeviceListenerMac::OnDefaultDeviceChanged( - AudioObjectID object, UInt32 num_addresses, - const AudioObjectPropertyAddress addresses[], void* context) { - if (object != kAudioObjectSystemObject) - return noErr; - - for (UInt32 i = 0; i < num_addresses; ++i) { - if (addresses[i].mSelector == kDeviceChangePropertyAddress.mSelector && - addresses[i].mScope == kDeviceChangePropertyAddress.mScope && - addresses[i].mElement == kDeviceChangePropertyAddress.mElement && - context) { - static_cast<AudioDeviceListenerMac*>(context)->listener_cb_.Run(); - break; - } - } - - return noErr; -} - -AudioDeviceListenerMac::AudioDeviceListenerMac( - const base::Closure& listener_cb) { - if (!LoadAudioObjectPropertyListenerBlockFunctions()) - return; - - // Device changes are hard, lets go shopping! Sadly OSX does not handle - // property listener callbacks in a thread safe manner. On 10.6 we can set - // kAudioHardwarePropertyRunLoop to account for this. On 10.7 this is broken - // and we need to create our dispatch queue to drive callbacks. However code - // running on the dispatch queue must be mutually exclusive with code running - // on the audio thread. ExclusiveDispatchQueueTaskObserver works around this - // by pausing and resuming the dispatch queue before and after each pumped - // task. This is not ideal and long term we should replace the audio thread - // on OSX with a dispatch queue. See http://crbug.com/158170 for discussion. - // TODO(dalecurtis): Does not fix the cases where GetAudioHardwareSampleRate() - // and GetAudioInputHardwareSampleRate() are called by the browser process. - // These are one time events due to renderer side cache and thus unlikely to - // occur at the same time as a device callback. Should be fixed along with - // http://crbug.com/137326 using a forced PostTask. - OSStatus result; - if (base::mac::IsOSLionOrLater()) { - task_observer_.reset(new ExclusiveDispatchQueueTaskObserver()); - listener_block_ = Block_copy(^( - UInt32 num_addresses, const AudioObjectPropertyAddress addresses[]) { - OnDefaultDeviceChanged( - kAudioObjectSystemObject, num_addresses, addresses, this); - }); - result = g_add_listener_block_func( - kAudioObjectSystemObject, &kDeviceChangePropertyAddress, - task_observer_->dispatch_queue(), listener_block_); - } else { - const AudioObjectPropertyAddress kRunLoopAddress = { - kAudioHardwarePropertyRunLoop, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - - CFRunLoopRef run_loop = CFRunLoopGetCurrent(); - UInt32 size = sizeof(CFRunLoopRef); - result = AudioObjectSetPropertyData( - kAudioObjectSystemObject, &kRunLoopAddress, 0, 0, size, &run_loop); - if (result != noErr) { - OSSTATUS_DLOG(ERROR, result) << "Failed to set property listener thread."; - return; - } - - result = AudioObjectAddPropertyListener( - kAudioObjectSystemObject, &kDeviceChangePropertyAddress, - &AudioDeviceListenerMac::OnDefaultDeviceChanged, this); - } - - if (result != noErr) { - task_observer_.reset(); - OSSTATUS_DLOG(ERROR, result) << "AudioObjectAddPropertyListener() failed!"; - return; - } - - listener_cb_ = listener_cb; -} - -AudioDeviceListenerMac::~AudioDeviceListenerMac() { - DCHECK(thread_checker_.CalledOnValidThread()); - if (listener_cb_.is_null()) - return; - - if (task_observer_) { - OSStatus result = g_remove_listener_block_func( - kAudioObjectSystemObject, &kDeviceChangePropertyAddress, - task_observer_->dispatch_queue(), listener_block_); - - OSSTATUS_DLOG_IF(ERROR, result != noErr, result) - << "AudioObjectRemovePropertyListenerBlock() failed!"; - - // Task observer will wait for all outstanding callbacks to complete. - task_observer_.reset(); - Block_release(listener_block_); - return; - } - - // Since we're running on the same CFRunLoop, there can be no outstanding - // callbacks in flight. - OSStatus result = AudioObjectRemovePropertyListener( - kAudioObjectSystemObject, &kDeviceChangePropertyAddress, - &AudioDeviceListenerMac::OnDefaultDeviceChanged, this); - OSSTATUS_DLOG_IF(ERROR, result != noErr, result) - << "AudioObjectRemovePropertyListener() failed!"; -} - -} // namespace media diff --git a/media/audio/mac/audio_device_listener_mac.h b/media/audio/mac/audio_device_listener_mac.h deleted file mode 100644 index b944817..0000000 --- a/media/audio/mac/audio_device_listener_mac.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2012 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_MAC_AUDIO_DEVICE_LISTENER_MAC_H_ -#define MEDIA_AUDIO_MAC_AUDIO_DEVICE_LISTENER_MAC_H_ - -#include <CoreAudio/AudioHardware.h> - -#include "base/basictypes.h" -#include "base/callback.h" -#include "base/threading/thread_checker.h" -#include "media/base/media_export.h" - -namespace media { - -// TODO(dalecurtis): Use the standard AudioObjectPropertyListenerBlock when -// the deployment target is > 10.6. -typedef void (^CrAudioObjectPropertyListenerBlock)( - UInt32 num_addresses, const AudioObjectPropertyAddress addresses[]); - -class ExclusiveDispatchQueueTaskObserver; - -// AudioDeviceListenerMac facilitates thread safe execution of device listener -// callbacks issued via CoreAudio. On 10.6 this means correctly binding the -// CFRunLoop driving callbacks to the CFRunLoop AudioDeviceListenerMac is -// constructed on. On 10.7 this means creating a dispatch queue to drive -// callbacks and modifying the message loop AudioDeviceListenerMac to ensure -// message loop tasks and dispatch queue tasks are executed in a mutually -// exclusive manner. See http://crbug.com/158170 for more discussion. -class MEDIA_EXPORT AudioDeviceListenerMac { - public: - // |listener_cb| will be called when a device change occurs; it's a permanent - // callback and must outlive AudioDeviceListenerMac. - explicit AudioDeviceListenerMac(const base::Closure& listener_cb); - ~AudioDeviceListenerMac(); - - private: - friend class AudioDeviceListenerMacTest; - static const AudioObjectPropertyAddress kDeviceChangePropertyAddress; - - static OSStatus OnDefaultDeviceChanged( - AudioObjectID object, UInt32 num_addresses, - const AudioObjectPropertyAddress addresses[], void* context); - - base::Closure listener_cb_; - CrAudioObjectPropertyListenerBlock listener_block_; - scoped_ptr<ExclusiveDispatchQueueTaskObserver> task_observer_; - - // AudioDeviceListenerMac must be constructed and destructed on the same - // thread. - base::ThreadChecker thread_checker_; - - DISALLOW_COPY_AND_ASSIGN(AudioDeviceListenerMac); -}; - -} // namespace media - -#endif // MEDIA_AUDIO_MAC_AUDIO_DEVICE_LISTENER_MAC_H_ diff --git a/media/audio/mac/audio_device_listener_mac_unittest.cc b/media/audio/mac/audio_device_listener_mac_unittest.cc deleted file mode 100644 index cff3b05..0000000 --- a/media/audio/mac/audio_device_listener_mac_unittest.cc +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2013 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 <CoreAudio/AudioHardware.h> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop.h" -#include "media/audio/mac/audio_device_listener_mac.h" -#include "media/base/bind_to_loop.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace media { - -class AudioDeviceListenerMacTest : public testing::Test { - public: - AudioDeviceListenerMacTest() { - // It's important to create the device listener from the message loop in - // order to ensure we don't end up with unbalanced TaskObserver calls. - message_loop_.PostTask(FROM_HERE, base::Bind( - &AudioDeviceListenerMacTest::CreateDeviceListener, - base::Unretained(this))); - message_loop_.RunUntilIdle(); - } - - virtual ~AudioDeviceListenerMacTest() { - // It's important to destroy the device listener from the message loop in - // order to ensure we don't end up with unbalanced TaskObserver calls. - message_loop_.PostTask(FROM_HERE, base::Bind( - &AudioDeviceListenerMacTest::DestroyDeviceListener, - base::Unretained(this))); - message_loop_.RunUntilIdle(); - } - - void CreateDeviceListener() { - // Force a post task using BindToLoop to ensure device listener internals - // are working correctly. - output_device_listener_.reset(new AudioDeviceListenerMac(BindToLoop( - message_loop_.message_loop_proxy(), base::Bind( - &AudioDeviceListenerMacTest::OnDeviceChange, - base::Unretained(this))))); - } - - void DestroyDeviceListener() { - output_device_listener_.reset(); - } - - // Simulate a device change where no output devices are available. - bool SimulateDefaultOutputDeviceChange() { - // Include multiple addresses to ensure only a single device change event - // occurs. - const AudioObjectPropertyAddress addresses[] = { - AudioDeviceListenerMac::kDeviceChangePropertyAddress, - { kAudioHardwarePropertyDevices, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster } - }; - - return noErr == output_device_listener_->OnDefaultDeviceChanged( - kAudioObjectSystemObject, 1, addresses, output_device_listener_.get()); - } - - MOCK_METHOD0(OnDeviceChange, void()); - - protected: - MessageLoop message_loop_; - scoped_ptr<AudioDeviceListenerMac> output_device_listener_; - - DISALLOW_COPY_AND_ASSIGN(AudioDeviceListenerMacTest); -}; - -// Simulate a device change events and ensure we get the right callbacks. -TEST_F(AudioDeviceListenerMacTest, OutputDeviceChange) { - EXPECT_CALL(*this, OnDeviceChange()).Times(1); - ASSERT_TRUE(SimulateDefaultOutputDeviceChange()); - message_loop_.RunUntilIdle(); -} - -} // namespace media diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc index 288ac14..e0300ed 100644 --- a/media/audio/mac/audio_manager_mac.cc +++ b/media/audio/mac/audio_manager_mac.cc @@ -233,20 +233,74 @@ static AudioDeviceID GetAudioDeviceIdByUId(bool is_input, return audio_device_id; } -AudioManagerMac::AudioManagerMac() { +// Property address to monitor for device changes. +static const AudioObjectPropertyAddress kDeviceChangePropertyAddress = { + kAudioHardwarePropertyDefaultOutputDevice, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster +}; + +// Callback from the system when the default device changes; this must be called +// on the MessageLoop that created the AudioManager. +static OSStatus OnDefaultDeviceChangedCallback( + AudioObjectID object, + UInt32 num_addresses, + const AudioObjectPropertyAddress addresses[], + void* context) { + if (object != kAudioObjectSystemObject) + return noErr; + + for (UInt32 i = 0; i < num_addresses; ++i) { + if (addresses[i].mSelector == kDeviceChangePropertyAddress.mSelector && + addresses[i].mScope == kDeviceChangePropertyAddress.mScope && + addresses[i].mElement == kDeviceChangePropertyAddress.mElement && + context) { + static_cast<AudioManagerMac*>(context)->OnDeviceChange(); + break; + } + } + + return noErr; +} + +AudioManagerMac::AudioManagerMac() + : listener_registered_(false), + creating_message_loop_(base::MessageLoopProxy::current()) { SetMaxOutputStreamsAllowed(kMaxOutputStreams); - // Task must be posted last to avoid races from handing out "this" to the - // audio thread. - GetMessageLoop()->PostTask(FROM_HERE, base::Bind( - &AudioManagerMac::CreateDeviceListener, base::Unretained(this))); + // AudioManagerMac is expected to be created by the root platform thread, this + // is generally BrowserMainLoop, it's MessageLoop will drive the NSApplication + // pump which in turn fires the property listener callbacks. + if (!creating_message_loop_) + return; + + OSStatus result = AudioObjectAddPropertyListener( + kAudioObjectSystemObject, + &kDeviceChangePropertyAddress, + &OnDefaultDeviceChangedCallback, + this); + + if (result != noErr) { + OSSTATUS_DLOG(ERROR, result) << "AudioObjectAddPropertyListener() failed!"; + return; + } + + listener_registered_ = true; } AudioManagerMac::~AudioManagerMac() { - // It's safe to post a task here since Shutdown() will wait for all tasks to - // complete before returning. - GetMessageLoop()->PostTask(FROM_HERE, base::Bind( - &AudioManagerMac::DestroyDeviceListener, base::Unretained(this))); + if (listener_registered_) { + // TODO(dalecurtis): CHECK destruction happens on |creating_message_loop_|, + // should be true, but currently several unit tests perform destruction in + // odd places so we can't CHECK here currently. + OSStatus result = AudioObjectRemovePropertyListener( + kAudioObjectSystemObject, + &kDeviceChangePropertyAddress, + &OnDefaultDeviceChangedCallback, + this); + OSSTATUS_DLOG_IF(ERROR, result != noErr, result) + << "AudioObjectRemovePropertyListener() failed!"; + } Shutdown(); } @@ -335,17 +389,14 @@ AudioParameters AudioManagerMac::GetPreferredLowLatencyOutputStreamParameters( input_params); } -void AudioManagerMac::CreateDeviceListener() { - DCHECK(GetMessageLoop()->BelongsToCurrentThread()); - output_device_listener_.reset(new AudioDeviceListenerMac(BindToLoop( +void AudioManagerMac::OnDeviceChange() { + // Post the task to the |creating_message_loop_| to execute our listener + // callback. The callback is created using BindToLoop() so will hop over + // to the audio thread upon execution. + creating_message_loop_->PostTask(FROM_HERE, BindToLoop( GetMessageLoop(), base::Bind( &AudioManagerMac::NotifyAllOutputDeviceChangeListeners, - base::Unretained(this))))); -} - -void AudioManagerMac::DestroyDeviceListener() { - DCHECK(GetMessageLoop()->BelongsToCurrentThread()); - output_device_listener_.reset(); + base::Unretained(this)))); } AudioManager* CreateAudioManager() { diff --git a/media/audio/mac/audio_manager_mac.h b/media/audio/mac/audio_manager_mac.h index 40ed54e..d8b6b2d 100644 --- a/media/audio/mac/audio_manager_mac.h +++ b/media/audio/mac/audio_manager_mac.h @@ -9,7 +9,6 @@ #include "base/compiler_specific.h" #include "base/message_loop_proxy.h" #include "media/audio/audio_manager_base.h" -#include "media/audio/mac/audio_device_listener_mac.h" namespace media { @@ -38,15 +37,16 @@ class MEDIA_EXPORT AudioManagerMac : public AudioManagerBase { virtual AudioParameters GetPreferredLowLatencyOutputStreamParameters( const AudioParameters& input_params) OVERRIDE; + // Called by an internal device change listener. Must be called on + // |creating_message_loop_|. + void OnDeviceChange(); + protected: virtual ~AudioManagerMac(); private: - // Helper methods for constructing AudioDeviceListenerMac on the audio thread. - void CreateDeviceListener(); - void DestroyDeviceListener(); - - scoped_ptr<AudioDeviceListenerMac> output_device_listener_; + bool listener_registered_; + scoped_refptr<base::MessageLoopProxy> creating_message_loop_; DISALLOW_COPY_AND_ASSIGN(AudioManagerMac); }; diff --git a/media/audio/win/audio_manager_win.h b/media/audio/win/audio_manager_win.h index 61bd8a6..4ce2fbc 100644 --- a/media/audio/win/audio_manager_win.h +++ b/media/audio/win/audio_manager_win.h @@ -1,4 +1,4 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. diff --git a/media/media.gyp b/media/media.gyp index 963369d..05b35cc 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -111,8 +111,6 @@ 'audio/linux/cras_input.h', 'audio/linux/cras_output.cc', 'audio/linux/cras_output.h', - 'audio/mac/audio_device_listener_mac.cc', - 'audio/mac/audio_device_listener_mac.h', 'audio/mac/audio_input_mac.cc', 'audio/mac/audio_input_mac.h', 'audio/mac/audio_low_latency_input_mac.cc', @@ -669,7 +667,6 @@ 'audio/fake_audio_output_stream_unittest.cc', 'audio/ios/audio_manager_ios_unittest.cc', 'audio/linux/alsa_output_unittest.cc', - 'audio/mac/audio_device_listener_mac_unittest.cc', 'audio/mac/audio_low_latency_input_mac_unittest.cc', 'audio/mac/audio_output_mac_unittest.cc', 'audio/simple_sources_unittest.cc', |