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

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

Issue 11298006: Browser-wide audio mirroring for TabCapture API (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Review comments, some unit tests, move attach/detach into virtual audio output stream Created 8 years 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/command_line.h" 8 #include "base/command_line.h"
9 #include "base/message_loop_proxy.h" 9 #include "base/message_loop_proxy.h"
10 #include "base/threading/thread.h" 10 #include "base/threading/thread.h"
11 #include "media/audio/audio_output_dispatcher_impl.h" 11 #include "media/audio/audio_output_dispatcher_impl.h"
12 #include "media/audio/audio_output_proxy.h" 12 #include "media/audio/audio_output_proxy.h"
13 #include "media/audio/audio_output_resampler.h" 13 #include "media/audio/audio_output_resampler.h"
14 #include "media/audio/audio_util.h" 14 #include "media/audio/audio_util.h"
15 #include "media/audio/fake_audio_input_stream.h" 15 #include "media/audio/fake_audio_input_stream.h"
16 #include "media/audio/fake_audio_output_stream.h" 16 #include "media/audio/fake_audio_output_stream.h"
17 #include "media/audio/virtual_audio_input_stream.h"
18 #include "media/audio/virtual_audio_output_stream.h"
17 #include "media/base/media_switches.h" 19 #include "media/base/media_switches.h"
18 20
19 // TODO(dalecurtis): Temporarily disabled while switching pipeline to use float, 21 // TODO(dalecurtis): Temporarily disabled while switching pipeline to use float,
20 // http://crbug.com/114700 22 // http://crbug.com/114700
21 #if defined(ENABLE_AUDIO_MIXER) 23 #if defined(ENABLE_AUDIO_MIXER)
22 #include "media/audio/audio_output_mixer.h" 24 #include "media/audio/audio_output_mixer.h"
23 #endif 25 #endif
24 26
25 namespace media { 27 namespace media {
26 28
(...skipping 11 matching lines...) Expand all
38 40
39 const char AudioManagerBase::kDefaultDeviceName[] = "Default"; 41 const char AudioManagerBase::kDefaultDeviceName[] = "Default";
40 const char AudioManagerBase::kDefaultDeviceId[] = "default"; 42 const char AudioManagerBase::kDefaultDeviceId[] = "default";
41 43
42 AudioManagerBase::AudioManagerBase() 44 AudioManagerBase::AudioManagerBase()
43 : num_active_input_streams_(0), 45 : num_active_input_streams_(0),
44 max_num_output_streams_(kDefaultMaxOutputStreams), 46 max_num_output_streams_(kDefaultMaxOutputStreams),
45 max_num_input_streams_(kDefaultMaxInputStreams), 47 max_num_input_streams_(kDefaultMaxInputStreams),
46 num_output_streams_(0), 48 num_output_streams_(0),
47 num_input_streams_(0), 49 num_input_streams_(0),
48 audio_thread_(new base::Thread("AudioThread")) { 50 audio_thread_(new base::Thread("AudioThread")),
51 virtual_audio_input_stream_(NULL) {
49 #if defined(OS_WIN) 52 #if defined(OS_WIN)
50 audio_thread_->init_com_with_mta(true); 53 audio_thread_->init_com_with_mta(true);
51 #endif 54 #endif
52 CHECK(audio_thread_->Start()); 55 CHECK(audio_thread_->Start());
53 message_loop_ = audio_thread_->message_loop_proxy(); 56 message_loop_ = audio_thread_->message_loop_proxy();
54 } 57 }
55 58
56 AudioManagerBase::~AudioManagerBase() { 59 AudioManagerBase::~AudioManagerBase() {
57 // The platform specific AudioManager implementation must have already 60 // The platform specific AudioManager implementation must have already
58 // stopped the audio thread. Otherwise, we may destroy audio streams before 61 // stopped the audio thread. Otherwise, we may destroy audio streams before
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 return NULL; 96 return NULL;
94 } 97 }
95 98
96 // If there are no audio output devices we should use a FakeAudioOutputStream 99 // If there are no audio output devices we should use a FakeAudioOutputStream
97 // to ensure video playback continues to work. 100 // to ensure video playback continues to work.
98 bool audio_output_disabled = 101 bool audio_output_disabled =
99 params.format() == AudioParameters::AUDIO_FAKE || 102 params.format() == AudioParameters::AUDIO_FAKE ||
100 !HasAudioOutputDevices(); 103 !HasAudioOutputDevices();
101 104
102 AudioOutputStream* stream = NULL; 105 AudioOutputStream* stream = NULL;
103 if (audio_output_disabled) { 106 if (virtual_audio_input_stream_ &&
107 params.format() != AudioParameters::AUDIO_FAKE) {
108 // TODO(justinlin): This seems to sometimes be called twice for 1 video.
Alpha Left Google 2012/11/28 01:04:47 What should this TODO do?
justinlin 2012/11/28 14:30:31 Right, I'll remove the TODO and fix this.
109 // They both attach, but then one of them detaches prematurely, and the
110 // other one doesn't detach which causes a DCHECK fail?
111 stream = VirtualAudioOutputStream::MakeStream(this, params,
112 virtual_audio_input_stream_);
113 } else if (audio_output_disabled) {
104 stream = FakeAudioOutputStream::MakeFakeStream(this, params); 114 stream = FakeAudioOutputStream::MakeFakeStream(this, params);
105 } else if (params.format() == AudioParameters::AUDIO_PCM_LINEAR) { 115 } else if (params.format() == AudioParameters::AUDIO_PCM_LINEAR) {
106 stream = MakeLinearOutputStream(params); 116 stream = MakeLinearOutputStream(params);
107 } else if (params.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) { 117 } else if (params.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) {
108 stream = MakeLowLatencyOutputStream(params); 118 stream = MakeLowLatencyOutputStream(params);
109 } 119 }
110 120
111 if (stream) 121 if (stream)
112 ++num_output_streams_; 122 ++num_output_streams_;
113 123
114 return stream; 124 return stream;
115 } 125 }
116 126
117 AudioInputStream* AudioManagerBase::MakeAudioInputStream( 127 AudioInputStream* AudioManagerBase::MakeAudioInputStream(
118 const AudioParameters& params, const std::string& device_id) { 128 const AudioParameters& params, const std::string& device_id) {
119 if (!params.IsValid() || (params.channels() > kMaxInputChannels) || 129 if (!params.IsValid() || (params.channels() > kMaxInputChannels) ||
120 device_id.empty()) { 130 device_id.empty()) {
121 DLOG(ERROR) << "Audio parameters are invalid for device " << device_id; 131 DLOG(ERROR) << "Audio parameters are invalid for device " << device_id;
122 return NULL; 132 return NULL;
123 } 133 }
124 134
125 if (num_input_streams_ >= max_num_input_streams_) { 135 if (num_input_streams_ >= max_num_input_streams_) {
126 DLOG(ERROR) << "Number of opened input audio streams " 136 DLOG(ERROR) << "Number of opened input audio streams "
127 << num_input_streams_ 137 << num_input_streams_
128 << " exceed the max allowed number " << max_num_input_streams_; 138 << " exceed the max allowed number " << max_num_input_streams_;
129 return NULL; 139 return NULL;
130 } 140 }
131 141
132 AudioInputStream* stream = NULL; 142 AudioInputStream* stream = NULL;
133 if (params.format() == AudioParameters::AUDIO_FAKE) { 143 if (params.format() == AudioParameters::AUDIO_MIRROR_BROWSER) {
144 // TODO(justinlin): Currently, we can only support mirroring audio from 1
Alpha Left Google 2012/11/28 01:04:47 No need to mention tab. You can just mention the
justinlin 2012/11/28 14:30:31 Done.
145 // tab, so subsequent tab capture requests will just get fake audio.
146 // Maybe we should just return the same stream and ref-count, so that we
147 // only actually destroy the stream when there's no mirroring?
148 if (!virtual_audio_input_stream_) {
149 virtual_audio_input_stream_ =
150 VirtualAudioInputStream::MakeStream(this, params);
151 stream = virtual_audio_input_stream_;
152 message_loop_->PostTask(FROM_HERE, base::Bind(
Alpha Left Google 2012/11/28 01:04:47 What would this task do?
justinlin 2012/11/28 14:30:31 NotifyAllOutputChangeListeners needs to be called
153 &AudioManagerBase::NotifyAllOutputDeviceChangeListeners,
154 base::Unretained(this)));
155 } else {
156 // TODO(justinlin): Maybe we can return NULL if this doesn't cause the
Alpha Left Google 2012/11/28 01:04:47 This code doesn't need a TODO isn't it?
justinlin 2012/11/28 14:30:31 Done.
157 // media request to fail?
158 stream = FakeAudioInputStream::MakeFakeStream(this, params);
159 }
160 } else if (params.format() == AudioParameters::AUDIO_FAKE) {
134 stream = FakeAudioInputStream::MakeFakeStream(this, params); 161 stream = FakeAudioInputStream::MakeFakeStream(this, params);
135 } else if (params.format() == AudioParameters::AUDIO_PCM_LINEAR) { 162 } else if (params.format() == AudioParameters::AUDIO_PCM_LINEAR) {
136 stream = MakeLinearInputStream(params, device_id); 163 stream = MakeLinearInputStream(params, device_id);
137 } else if (params.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) { 164 } else if (params.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) {
138 stream = MakeLowLatencyInputStream(params, device_id); 165 stream = MakeLowLatencyInputStream(params, device_id);
139 } 166 }
140 167
141 if (stream) 168 if (stream)
142 ++num_input_streams_; 169 ++num_input_streams_;
143 170
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 } 253 }
227 254
228 void AudioManagerBase::ShowAudioInputSettings() { 255 void AudioManagerBase::ShowAudioInputSettings() {
229 } 256 }
230 257
231 void AudioManagerBase::GetAudioInputDeviceNames( 258 void AudioManagerBase::GetAudioInputDeviceNames(
232 media::AudioDeviceNames* device_names) { 259 media::AudioDeviceNames* device_names) {
233 } 260 }
234 261
235 void AudioManagerBase::ReleaseOutputStream(AudioOutputStream* stream) { 262 void AudioManagerBase::ReleaseOutputStream(AudioOutputStream* stream) {
263 DCHECK(message_loop_->BelongsToCurrentThread());
236 DCHECK(stream); 264 DCHECK(stream);
237 // TODO(xians) : Have a clearer destruction path for the AudioOutputStream. 265 // TODO(xians) : Have a clearer destruction path for the AudioOutputStream.
238 // For example, pass the ownership to AudioManager so it can delete the 266 // For example, pass the ownership to AudioManager so it can delete the
239 // streams. 267 // streams.
240 num_output_streams_--; 268 num_output_streams_--;
241 delete stream; 269 delete stream;
242 } 270 }
243 271
244 void AudioManagerBase::ReleaseInputStream(AudioInputStream* stream) { 272 void AudioManagerBase::ReleaseInputStream(AudioInputStream* stream) {
273 DCHECK(message_loop_->BelongsToCurrentThread());
245 DCHECK(stream); 274 DCHECK(stream);
246 // TODO(xians) : Have a clearer destruction path for the AudioInputStream. 275 // TODO(xians) : Have a clearer destruction path for the AudioInputStream.
276
277 if (virtual_audio_input_stream_ == stream) {
278 virtual_audio_input_stream_->Stop();
279 virtual_audio_input_stream_ = NULL;
280 NotifyAllOutputDeviceChangeListeners();
Alpha Left Google 2012/11/28 01:04:47 What should the output streams do? Write a comment
justinlin 2012/11/28 14:30:31 Done.
281 }
282
247 num_input_streams_--; 283 num_input_streams_--;
248 delete stream; 284 delete stream;
249 } 285 }
250 286
251 void AudioManagerBase::IncreaseActiveInputStreamCount() { 287 void AudioManagerBase::IncreaseActiveInputStreamCount() {
252 base::AtomicRefCountInc(&num_active_input_streams_); 288 base::AtomicRefCountInc(&num_active_input_streams_);
253 } 289 }
254 290
255 void AudioManagerBase::DecreaseActiveInputStreamCount() { 291 void AudioManagerBase::DecreaseActiveInputStreamCount() {
256 DCHECK(IsRecordingInProcess()); 292 DCHECK(IsRecordingInProcess());
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 output_listeners_.RemoveObserver(listener); 376 output_listeners_.RemoveObserver(listener);
341 } 377 }
342 378
343 void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() { 379 void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() {
344 DCHECK(message_loop_->BelongsToCurrentThread()); 380 DCHECK(message_loop_->BelongsToCurrentThread());
345 DVLOG(1) << "Firing OnDeviceChange() notifications."; 381 DVLOG(1) << "Firing OnDeviceChange() notifications.";
346 FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange()); 382 FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange());
347 } 383 }
348 384
349 } // namespace media 385 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698