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

Side by Side Diff: media/audio/audio_manager_base.cc

Issue 14273018: Use the browser UI thread for audio on OSX. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix device listener. 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/audio/audio_manager_base.h" 5 #include "media/audio/audio_manager_base.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
9 #include "base/message_loop_proxy.h" 10 #include "base/message_loop_proxy.h"
10 #include "base/threading/thread.h" 11 #include "base/threading/thread.h"
12 #include "build/build_config.h"
11 #include "media/audio/audio_output_dispatcher_impl.h" 13 #include "media/audio/audio_output_dispatcher_impl.h"
12 #include "media/audio/audio_output_proxy.h" 14 #include "media/audio/audio_output_proxy.h"
13 #include "media/audio/audio_output_resampler.h" 15 #include "media/audio/audio_output_resampler.h"
14 #include "media/audio/audio_util.h" 16 #include "media/audio/audio_util.h"
15 #include "media/audio/fake_audio_input_stream.h" 17 #include "media/audio/fake_audio_input_stream.h"
16 #include "media/audio/fake_audio_output_stream.h" 18 #include "media/audio/fake_audio_output_stream.h"
19 #include "media/base/media_switches.h"
17 20
18 namespace media { 21 namespace media {
19 22
20 static const int kStreamCloseDelaySeconds = 5; 23 static const int kStreamCloseDelaySeconds = 5;
21 24
22 // Default maximum number of output streams that can be open simultaneously 25 // Default maximum number of output streams that can be open simultaneously
23 // for all platforms. 26 // for all platforms.
24 static const int kDefaultMaxOutputStreams = 16; 27 static const int kDefaultMaxOutputStreams = 16;
25 28
26 // Default maximum number of input streams that can be open simultaneously 29 // Default maximum number of input streams that can be open simultaneously
27 // for all platforms. 30 // for all platforms.
28 static const int kDefaultMaxInputStreams = 16; 31 static const int kDefaultMaxInputStreams = 16;
29 32
30 static const int kMaxInputChannels = 2; 33 static const int kMaxInputChannels = 2;
31 34
32 const char AudioManagerBase::kDefaultDeviceName[] = "Default"; 35 const char AudioManagerBase::kDefaultDeviceName[] = "Default";
33 const char AudioManagerBase::kDefaultDeviceId[] = "default"; 36 const char AudioManagerBase::kDefaultDeviceId[] = "default";
34 37
35 AudioManagerBase::AudioManagerBase() 38 AudioManagerBase::AudioManagerBase()
36 : num_active_input_streams_(0), 39 : num_active_input_streams_(0),
37 max_num_output_streams_(kDefaultMaxOutputStreams), 40 max_num_output_streams_(kDefaultMaxOutputStreams),
38 max_num_input_streams_(kDefaultMaxInputStreams), 41 max_num_input_streams_(kDefaultMaxInputStreams),
39 num_output_streams_(0), 42 num_output_streams_(0),
40 num_input_streams_(0), 43 num_input_streams_(0),
41 output_listeners_( 44 output_listeners_(
42 ObserverList<AudioDeviceListener>::NOTIFY_EXISTING_ONLY), 45 ObserverList<AudioDeviceListener>::NOTIFY_EXISTING_ONLY),
43 audio_thread_(new base::Thread("AudioThread")) { 46 audio_thread_(new base::Thread("AudioThread")) {
44 #if defined(OS_WIN) 47 #if defined(OS_WIN)
45 audio_thread_->init_com_with_mta(true); 48 audio_thread_->init_com_with_mta(true);
49 #elif defined(OS_MACOSX)
50 // CoreAudio calls must occur on the main thread of the process, which in our
51 // case is sadly the browser UI thread. Failure to execute calls on the right
52 // thread leads to crashes and odd behavior. See http://crbug.com/158170.
53 const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
54 if (!cmd_line->HasSwitch(switches::kDisableMainThreadAudio) &&
55 base::MessageLoopProxy::current()) {
scherkus (not reviewing) 2013/05/31 19:30:35 when would this be NULL?
DaleCurtis 2013/06/03 19:51:10 Many unittests create an AudioManager without owni
scherkus (not reviewing) 2013/06/03 22:04:28 Hmm... it's unfortunate that production code is al
DaleCurtis 2013/06/03 22:26:35 "Fixing" means giving those tests a MessageLoop an
DaleCurtis 2013/06/03 22:59:28 Actually just changing BrowserMainLoop would means
scherkus (not reviewing) 2013/06/03 23:22:18 I agree that implicit dependencies kinda suck, hen
DaleCurtis 2013/06/04 00:15:17 Lets leave it as is until it's sticky then I'll su
scherkus (not reviewing) 2013/06/04 00:21:30 SGTM
56 message_loop_ = base::MessageLoopProxy::current();
57 return;
58 }
46 #endif 59 #endif
47 #if defined(OS_MACOSX) 60
48 // On Mac, use a UI loop to get native message pump so that CoreAudio property
49 // listener callbacks fire.
50 CHECK(audio_thread_->StartWithOptions(
51 base::Thread::Options(base::MessageLoop::TYPE_UI, 0)));
52 #else
53 CHECK(audio_thread_->Start()); 61 CHECK(audio_thread_->Start());
scherkus (not reviewing) 2013/05/31 19:30:35 does it make sense to lazily start this thread?
DaleCurtis 2013/06/03 19:51:10 It is lazily started? See if (!worker_loop_) on li
scherkus (not reviewing) 2013/06/03 22:04:28 I was referring to the Linux/Win/CrOS/disable-main
DaleCurtis 2013/06/03 22:26:35 Probably? I don't see any reason why not. We would
scherkus (not reviewing) 2013/06/03 23:22:18 Yeah I'm wonder if there would be any races as AFA
DaleCurtis 2013/06/04 00:15:17 Shouldn't be too hard, we'd need to make generic I
54 #endif 62 worker_loop_ = message_loop_ = audio_thread_->message_loop_proxy();
scherkus (not reviewing) 2013/05/31 19:30:35 nit: can you split the assignments? multiple assi
DaleCurtis 2013/06/03 19:51:10 Done. It shouldn't be possible to call GetWorkerL
55 message_loop_ = audio_thread_->message_loop_proxy();
56 } 63 }
57 64
58 AudioManagerBase::~AudioManagerBase() { 65 AudioManagerBase::~AudioManagerBase() {
59 // The platform specific AudioManager implementation must have already 66 // The platform specific AudioManager implementation must have already
60 // stopped the audio thread. Otherwise, we may destroy audio streams before 67 // stopped the audio thread. Otherwise, we may destroy audio streams before
61 // stopping the thread, resulting an unexpected behavior. 68 // stopping the thread, resulting an unexpected behavior.
62 // This way we make sure activities of the audio streams are all stopped 69 // This way we make sure activities of the audio streams are all stopped
63 // before we destroy them. 70 // before we destroy them.
64 CHECK(!audio_thread_.get()); 71 CHECK(!audio_thread_.get());
65 // All the output streams should have been deleted. 72 // All the output streams should have been deleted.
66 DCHECK_EQ(0, num_output_streams_); 73 DCHECK_EQ(0, num_output_streams_);
67 // All the input streams should have been deleted. 74 // All the input streams should have been deleted.
68 DCHECK_EQ(0, num_input_streams_); 75 DCHECK_EQ(0, num_input_streams_);
69 } 76 }
70 77
71 string16 AudioManagerBase::GetAudioInputDeviceModel() { 78 string16 AudioManagerBase::GetAudioInputDeviceModel() {
72 return string16(); 79 return string16();
73 } 80 }
74 81
75 scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetMessageLoop() { 82 scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetMessageLoop() {
76 return message_loop_; 83 return message_loop_;
77 } 84 }
78 85
86 scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetWorkerLoop() {
87 // Start the worker loop on demand.
88 if (!worker_loop_) {
89 CHECK(audio_thread_->Start());
90 worker_loop_ = audio_thread_->message_loop_proxy();
91 }
92
93 return worker_loop_;
94 }
95
79 AudioOutputStream* AudioManagerBase::MakeAudioOutputStream( 96 AudioOutputStream* AudioManagerBase::MakeAudioOutputStream(
80 const AudioParameters& params) { 97 const AudioParameters& params) {
81 // TODO(miu): Fix ~50 call points across several unit test modules to call 98 // TODO(miu): Fix ~50 call points across several unit test modules to call
82 // this method on the audio thread, then uncomment the following: 99 // this method on the audio thread, then uncomment the following:
83 // DCHECK(message_loop_->BelongsToCurrentThread()); 100 // DCHECK(message_loop_->BelongsToCurrentThread());
84 101
85 if (!params.IsValid()) { 102 if (!params.IsValid()) {
86 DLOG(ERROR) << "Audio parameters are invalid"; 103 DLOG(ERROR) << "Audio parameters are invalid";
87 return NULL; 104 return NULL;
88 } 105 }
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 // via a local variable while not holding the audio thread lock. 281 // via a local variable while not holding the audio thread lock.
265 scoped_ptr<base::Thread> audio_thread; 282 scoped_ptr<base::Thread> audio_thread;
266 { 283 {
267 base::AutoLock lock(audio_thread_lock_); 284 base::AutoLock lock(audio_thread_lock_);
268 audio_thread_.swap(audio_thread); 285 audio_thread_.swap(audio_thread);
269 } 286 }
270 287
271 if (!audio_thread) 288 if (!audio_thread)
272 return; 289 return;
273 290
274 CHECK_NE(base::MessageLoop::current(), audio_thread->message_loop()); 291 #if defined(OS_MACOSX)
292 // Only true when we're sharing the UI message loop with the browser.
293 if (message_loop_->BelongsToCurrentThread()) {
294 // After ShutdownOnAudioThread() there should be no tasks running on the
295 // |worker_loop_|.
296 ShutdownOnAudioThread();
297 return audio_thread->Stop();
scherkus (not reviewing) 2013/05/31 19:30:35 split return to next line -- it's too subtle and m
DaleCurtis 2013/06/03 19:51:10 Done.
298 }
299 #endif
275 300
276 // We must use base::Unretained since Shutdown might have been called from 301 message_loop_->PostTask(FROM_HERE, base::Bind(
277 // the destructor and we can't alter the refcount of the object at that point. 302 &AudioManagerBase::ShutdownOnAudioThread, base::Unretained(this)));
278 audio_thread->message_loop()->PostTask(FROM_HERE, base::Bind(
279 &AudioManagerBase::ShutdownOnAudioThread,
280 base::Unretained(this)));
281 303
282 // Stop() will wait for any posted messages to be processed first. 304 // Stop() will wait for any posted messages to be processed first.
283 audio_thread->Stop(); 305 audio_thread->Stop();
284 } 306 }
285 307
286 void AudioManagerBase::ShutdownOnAudioThread() { 308 void AudioManagerBase::ShutdownOnAudioThread() {
287 // IOS implements audio input only. 309 // IOS implements audio input only.
288 #if defined(OS_IOS) 310 #if defined(OS_IOS)
289 return; 311 return;
290 #else 312 #else
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
333 return GetPreferredOutputStreamParameters(AudioParameters()); 355 return GetPreferredOutputStreamParameters(AudioParameters());
334 } 356 }
335 357
336 AudioParameters AudioManagerBase::GetInputStreamParameters( 358 AudioParameters AudioManagerBase::GetInputStreamParameters(
337 const std::string& device_id) { 359 const std::string& device_id) {
338 NOTREACHED(); 360 NOTREACHED();
339 return AudioParameters(); 361 return AudioParameters();
340 } 362 }
341 363
342 } // namespace media 364 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698