Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(35)

Unified Diff: media/audio/mac/audio_device_listener_mac.cc

Issue 14273018: Use the browser UI thread for audio on OSX. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comments. Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/audio/mac/audio_device_listener_mac.h ('k') | media/audio/mac/audio_manager_mac.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/audio/mac/audio_device_listener_mac.cc
diff --git a/media/audio/mac/audio_device_listener_mac.cc b/media/audio/mac/audio_device_listener_mac.cc
index 0c33d10c2fa330591490cff26e8b72e96170fe83..34c0a168327e3f1d8171148815facc45cfb78d7a 100644
--- a/media/audio/mac/audio_device_listener_mac.cc
+++ b/media/audio/mac/audio_device_listener_mac.cc
@@ -7,7 +7,6 @@
#include "base/bind.h"
#include "base/files/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"
@@ -16,74 +15,6 @@
namespace media {
-// 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 base::MessageLoop::TaskObserver {
- public:
- ExclusiveDispatchQueueTaskObserver()
- : property_listener_queue_(new base::mac::LibDispatchTaskRunner(
- "com.google.chrome.AudioPropertyListenerQueue")),
- queue_(property_listener_queue_->GetDispatchQueue()),
- message_loop_(base::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())
- SuspendDispatchQueue();
-
- 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())
- ResumeDispatchQueue();
-
- // This will hang if any listeners are still registered with the queue.
- property_listener_queue_->Shutdown();
- }
-
- virtual void WillProcessTask(const base::PendingTask& pending_task) OVERRIDE {
- SuspendDispatchQueue();
- }
-
- virtual void DidProcessTask(const base::PendingTask& pending_task) OVERRIDE {
- ResumeDispatchQueue();
- }
-
- dispatch_queue_t dispatch_queue() const {
- return queue_;
- }
-
- private:
- // 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.
- void SuspendDispatchQueue() {
- dispatch_sync(queue_, ^{
- dispatch_suspend(queue_);
- });
- }
-
- // Issue an asynchronous resume operation. Benchmarks on a retina 10.8.2
- // machine show this takes < 10us on average.
- void ResumeDispatchQueue() {
- dispatch_resume(queue_);
- }
-
- scoped_refptr<base::mac::LibDispatchTaskRunner> property_listener_queue_;
- const dispatch_queue_t queue_;
- base::MessageLoop* message_loop_;
-
- DISALLOW_COPY_AND_ASSIGN(ExclusiveDispatchQueueTaskObserver);
-};
-
// Property address to monitor for device changes.
const AudioObjectPropertyAddress
AudioDeviceListenerMac::kDeviceChangePropertyAddress = {
@@ -106,7 +37,10 @@ OSStatus AudioDeviceListenerMac::OnDefaultDeviceChanged(
addresses[i].mScope == kDeviceChangePropertyAddress.mScope &&
addresses[i].mElement == kDeviceChangePropertyAddress.mElement &&
context) {
- static_cast<AudioDeviceListenerMac*>(context)->listener_cb_.Run();
+ AudioDeviceListenerMac* p_this =
+ static_cast<AudioDeviceListenerMac*>(context);
+ DCHECK(p_this->thread_checker_.CalledOnValidThread());
+ p_this->listener_cb_.Run();
break;
}
}
@@ -114,72 +48,16 @@ OSStatus AudioDeviceListenerMac::OnDefaultDeviceChanged(
return noErr;
}
-AudioDeviceListenerMac::AudioDeviceListenerMac(const base::Closure& listener_cb)
- : listener_block_(NULL),
- add_listener_block_func_(NULL),
- remove_listener_block_func_(NULL) {
- // 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. 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
- // GetDefaultOutputStreamParameters() 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.
- if (base::mac::IsOSLionOrLater()) {
- if (!LoadAudioObjectPropertyListenerBlockFunctions())
- return;
-
- task_observer_.reset(new ExclusiveDispatchQueueTaskObserver());
- listener_block_ = Block_copy(^(
- UInt32 num_addresses, const AudioObjectPropertyAddress addresses[]) {
- OnDefaultDeviceChanged(
- kAudioObjectSystemObject, num_addresses, addresses, this);
- });
-
- OSStatus result = add_listener_block_func_(
- kAudioObjectSystemObject, &kDeviceChangePropertyAddress,
- task_observer_->dispatch_queue(), listener_block_);
-
- if (result != noErr) {
- task_observer_.reset();
- Block_release(listener_block_);
- listener_block_ = NULL;
- OSSTATUS_DLOG(ERROR, result)
- << "AudioObjectAddPropertyListenerBlock() failed!";
- return;
- }
- } else {
- const AudioObjectPropertyAddress kRunLoopAddress = {
- kAudioHardwarePropertyRunLoop,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster
- };
-
- CFRunLoopRef run_loop = CFRunLoopGetCurrent();
- UInt32 size = sizeof(CFRunLoopRef);
- OSStatus 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);
+AudioDeviceListenerMac::AudioDeviceListenerMac(
+ const base::Closure& listener_cb) {
+ OSStatus result = AudioObjectAddPropertyListener(
+ kAudioObjectSystemObject, &kDeviceChangePropertyAddress,
+ &AudioDeviceListenerMac::OnDefaultDeviceChanged, this);
- if (result != noErr) {
- OSSTATUS_DLOG(ERROR, result)
- << "AudioObjectAddPropertyListener() failed!";
- return;
- }
+ if (result != noErr) {
+ OSSTATUS_DLOG(ERROR, result)
+ << "AudioObjectAddPropertyListener() failed!";
+ return;
}
listener_cb_ = listener_cb;
@@ -190,20 +68,6 @@ AudioDeviceListenerMac::~AudioDeviceListenerMac() {
if (listener_cb_.is_null())
return;
- if (task_observer_) {
- OSStatus result = 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(
@@ -213,35 +77,4 @@ AudioDeviceListenerMac::~AudioDeviceListenerMac() {
<< "AudioObjectRemovePropertyListener() failed!";
}
-bool AudioDeviceListenerMac::LoadAudioObjectPropertyListenerBlockFunctions() {
- // Dynamically load required block functions.
- // TODO(dalecurtis): Remove once the deployment target is > 10.6.
- std::string error;
- base::NativeLibrary core_audio = base::LoadNativeLibrary(base::FilePath(
- "/System/Library/Frameworks/CoreAudio.framework/Versions/Current/"
- "CoreAudio"), &error);
- if (!error.empty()) {
- LOG(ERROR) << "Could not open CoreAudio library: " << error;
- return false;
- }
-
- core_audio_lib_.Reset(core_audio);
- add_listener_block_func_ =
- reinterpret_cast<AudioObjectPropertyListenerBlockT>(
- core_audio_lib_.GetFunctionPointer(
- "AudioObjectAddPropertyListenerBlock"));
- remove_listener_block_func_ =
- reinterpret_cast<AudioObjectPropertyListenerBlockT>(
- core_audio_lib_.GetFunctionPointer(
- "AudioObjectRemovePropertyListenerBlock"));
-
- // If either function failed to load, skip listener registration.
- if (!add_listener_block_func_ || !remove_listener_block_func_) {
- DLOG(ERROR) << "Failed to load audio property listener block functions!";
- return false;
- }
-
- return true;
-}
-
} // namespace media
« no previous file with comments | « media/audio/mac/audio_device_listener_mac.h ('k') | media/audio/mac/audio_manager_mac.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698