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

Side by Side Diff: content/browser/renderer_host/media/audio_renderer_host.cc

Issue 11413078: Tab Audio Capture: Browser-side connect/disconnect functionality. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Minor tweaks and added some useful comments. 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 "content/browser/renderer_host/media/audio_renderer_host.h" 5 #include "content/browser/renderer_host/media/audio_renderer_host.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/metrics/histogram.h" 8 #include "base/metrics/histogram.h"
9 #include "base/process.h" 9 #include "base/process.h"
10 #include "base/shared_memory.h" 10 #include "base/shared_memory.h"
11 #include "content/browser/browser_main_loop.h" 11 #include "content/browser/browser_main_loop.h"
12 #include "content/browser/renderer_host/media/audio_sync_reader.h" 12 #include "content/browser/renderer_host/media/audio_sync_reader.h"
13 #include "content/browser/renderer_host/media/web_contents_audio_input_stream.h"
13 #include "content/common/media/audio_messages.h" 14 #include "content/common/media/audio_messages.h"
14 #include "content/public/browser/media_observer.h" 15 #include "content/public/browser/media_observer.h"
16 #include "media/audio/audio_io.h"
15 #include "media/audio/shared_memory_util.h" 17 #include "media/audio/shared_memory_util.h"
16 #include "media/base/audio_bus.h" 18 #include "media/base/audio_bus.h"
17 #include "media/base/limits.h" 19 #include "media/base/limits.h"
18 20
19 using media::AudioBus; 21 using media::AudioBus;
20 22
21 namespace content { 23 namespace content {
22 24
23 struct AudioRendererHost::AudioEntry { 25 struct AudioRendererHost::AudioEntry {
24 AudioEntry(); 26 AudioEntry();
25 ~AudioEntry(); 27 ~AudioEntry();
26 28
27 // The AudioOutputController that manages the audio stream. 29 // The AudioOutputController that manages the audio stream.
28 scoped_refptr<media::AudioOutputController> controller; 30 scoped_refptr<media::AudioOutputController> controller;
29 31
30 // The audio stream ID. 32 // The audio stream ID.
31 int stream_id; 33 int stream_id;
32 34
35 // The routing ID of the source render view.
36 int render_view_id;
37
33 // Shared memory for transmission of the audio data. 38 // Shared memory for transmission of the audio data.
34 base::SharedMemory shared_memory; 39 base::SharedMemory shared_memory;
35 40
36 // The synchronous reader to be used by the controller. We have the 41 // The synchronous reader to be used by the controller. We have the
37 // ownership of the reader. 42 // ownership of the reader.
38 scoped_ptr<media::AudioOutputController::SyncReader> reader; 43 scoped_ptr<media::AudioOutputController::SyncReader> reader;
39 44
45 // When non-NULL, normal audio output is being diverted for audio mirroring.
46 media::AudioOutputStream::AudioSourceCallback* diverted_callback;
47
40 // Set to true after we called Close() for the controller. 48 // Set to true after we called Close() for the controller.
41 bool pending_close; 49 bool pending_close;
42 }; 50 };
43 51
44 AudioRendererHost::AudioEntry::AudioEntry() 52 AudioRendererHost::AudioEntry::AudioEntry()
45 : stream_id(0), 53 : stream_id(0),
54 render_view_id(MSG_ROUTING_NONE),
55 diverted_callback(NULL),
46 pending_close(false) { 56 pending_close(false) {
47 } 57 }
48 58
49 AudioRendererHost::AudioEntry::~AudioEntry() {} 59 AudioRendererHost::AudioEntry::~AudioEntry() {
60 DCHECK(!diverted_callback);
61 }
50 62
51 /////////////////////////////////////////////////////////////////////////////// 63 ///////////////////////////////////////////////////////////////////////////////
52 // AudioRendererHost implementations. 64 // AudioRendererHost implementations.
53 AudioRendererHost::AudioRendererHost( 65 AudioRendererHost::AudioRendererHost(
66 int render_process_id,
54 media::AudioManager* audio_manager, MediaObserver* media_observer) 67 media::AudioManager* audio_manager, MediaObserver* media_observer)
55 : audio_manager_(audio_manager), 68 : render_process_id_(render_process_id),
69 audio_manager_(audio_manager),
56 media_observer_(media_observer) { 70 media_observer_(media_observer) {
57 } 71 }
58 72
59 AudioRendererHost::~AudioRendererHost() { 73 AudioRendererHost::~AudioRendererHost() {
60 DCHECK(audio_entries_.empty()); 74 DCHECK(audio_entries_.empty());
75 DCHECK(mirror_sessions_.empty());
76 }
77
78 base::LazyInstance<AudioRendererHost::ActiveHostMap>::Leaky
79 AudioRendererHost::g_host_map_ = LAZY_INSTANCE_INITIALIZER;
80
81 void AudioRendererHost::OnChannelConnected(int32 peer_pid) {
82 g_host_map_.Get().insert(std::make_pair(render_process_id_, this));
83
84 BrowserMessageFilter::OnChannelConnected(peer_pid);
61 } 85 }
62 86
63 void AudioRendererHost::OnChannelClosing() { 87 void AudioRendererHost::OnChannelClosing() {
64 BrowserMessageFilter::OnChannelClosing(); 88 BrowserMessageFilter::OnChannelClosing();
65 89
66 // Since the IPC channel is gone, close all requested audio streams. 90 // Since the IPC channel is gone, close all requested audio streams.
67 DeleteEntries(); 91 DeleteEntries();
92
93 while (!mirror_sessions_.empty()) {
94 MirrorSessionMap::iterator it = mirror_sessions_.begin();
95 DoStopMirroring(render_process_id_, it->first, it->second);
96 }
97
98 g_host_map_.Get().erase(render_process_id_);
68 } 99 }
69 100
70 void AudioRendererHost::OnDestruct() const { 101 void AudioRendererHost::OnDestruct() const {
71 BrowserThread::DeleteOnIOThread::Destruct(this); 102 BrowserThread::DeleteOnIOThread::Destruct(this);
72 } 103 }
73 104
74 /////////////////////////////////////////////////////////////////////////////// 105 ///////////////////////////////////////////////////////////////////////////////
75 // media::AudioOutputController::EventHandler implementations. 106 // media::AudioOutputController::EventHandler implementations.
76 void AudioRendererHost::OnCreated(media::AudioOutputController* controller) { 107 void AudioRendererHost::OnCreated(media::AudioOutputController* controller) {
77 BrowserThread::PostTask( 108 BrowserThread::PostTask(
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream) 238 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream)
208 IPC_MESSAGE_HANDLER(AudioHostMsg_FlushStream, OnFlushStream) 239 IPC_MESSAGE_HANDLER(AudioHostMsg_FlushStream, OnFlushStream)
209 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream) 240 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream)
210 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume) 241 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume)
211 IPC_MESSAGE_UNHANDLED(handled = false) 242 IPC_MESSAGE_UNHANDLED(handled = false)
212 IPC_END_MESSAGE_MAP_EX() 243 IPC_END_MESSAGE_MAP_EX()
213 244
214 return handled; 245 return handled;
215 } 246 }
216 247
248 // static
249 AudioRendererHost* AudioRendererHost::FromRenderProcessID(
250 int render_process_id) {
251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
252
253 ActiveHostMap& host_map = g_host_map_.Get();
254 ActiveHostMap::const_iterator it = host_map.find(render_process_id);
255 return it == host_map.end() ? NULL : it->second;
256 }
257
258 // static
259 void AudioRendererHost::StartMirroring(
260 int render_process_id, int render_view_id,
Alpha Left Google 2012/11/28 20:02:25 This is called on the IO thread, why the extra thr
miu 2012/11/28 22:05:50 It's called from the audio thread. To make this c
261 const scoped_refptr<WebContentsAudioInputStream>& destination) {
262 BrowserThread::PostTask(
263 BrowserThread::IO, FROM_HERE,
264 base::Bind(&AudioRendererHost::DoStartMirroring,
265 render_process_id, render_view_id, destination));
266 }
267
268 // static
269 void AudioRendererHost::DoStartMirroring(
270 int render_process_id, int render_view_id,
271 const scoped_refptr<WebContentsAudioInputStream>& destination) {
272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
273 DCHECK(destination);
274
275 AudioRendererHost* const host = FromRenderProcessID(render_process_id);
276 if (!host) {
277 return;
278 }
279
280 // If a mirroring session is already active for |render_process_id| +
281 // |render_view_id|, force-stop it.
282 MirrorSessionMap::iterator session_it =
283 host->mirror_sessions_.find(render_view_id);
284 if (session_it != host->mirror_sessions_.end()) {
285 DVLOG(1) << "Forcing StopMirroring(" << render_view_id
286 << ") on existing mirroring session (@" << session_it->second
287 << ").";
288 DoStopMirroring(render_process_id, render_view_id, session_it->second);
289 }
290
291 DVLOG(1) << "Start mirroring RenderProcess:View="
292 << render_process_id << ':' << render_view_id
293 << " --> WebContentsAudioInputStream@" << destination;
294
295 // Insert an entry into the set of active mirroring sessions and divert any
296 // existing audio outputs to |destination|.
297 host->mirror_sessions_.insert(std::make_pair(render_view_id, destination));
298 for (AudioEntryMap::const_iterator it = host->audio_entries_.begin();
299 it != host->audio_entries_.end(); ++it) {
300 AudioEntry* const entry = it->second;
301 if (entry->render_view_id == render_view_id &&
302 !entry->pending_close) {
303 entry->diverted_callback = entry->controller->Divert();
304 destination->AddInput(entry->diverted_callback,
305 entry->controller->params());
306 }
307 }
308 }
309
310 // static
311 void AudioRendererHost::StopMirroring(
312 int render_process_id, int render_view_id,
313 const scoped_refptr<WebContentsAudioInputStream>& destination) {
314 BrowserThread::PostTask(
315 BrowserThread::IO, FROM_HERE,
316 base::Bind(&AudioRendererHost::DoStopMirroring,
317 render_process_id, render_view_id, destination));
318 }
319
320 // static
321 void AudioRendererHost::DoStopMirroring(
322 int render_process_id, int render_view_id,
323 const scoped_refptr<WebContentsAudioInputStream>& destination) {
324 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
325
326 AudioRendererHost* const host = FromRenderProcessID(render_process_id);
327 if (!host) {
328 return;
329 }
330
331 MirrorSessionMap::iterator session_it =
332 host->mirror_sessions_.find(render_view_id);
333 if (session_it == host->mirror_sessions_.end() ||
334 destination != session_it->second) {
335 return;
336 }
337
338 DVLOG(1) << "Stop mirroring RenderProcess:View="
339 << render_process_id << ':' << render_view_id
340 << " --> WebContentsAudioInputStream@" << destination;
341
342 // Revert the "divert" for each audio stream currently active in the mirroring
343 // session being stopped.
344 for (AudioEntryMap::const_iterator it = host->audio_entries_.begin();
345 it != host->audio_entries_.end(); ++it) {
346 AudioEntry* const entry = it->second;
347 if (entry->render_view_id == render_view_id &&
348 entry->diverted_callback) {
349 destination->RemoveInput(entry->diverted_callback);
350 entry->controller->Revert(entry->diverted_callback);
351 entry->diverted_callback = NULL;
352 }
353 }
354
355 host->mirror_sessions_.erase(session_it);
356 }
357
217 void AudioRendererHost::OnCreateStream( 358 void AudioRendererHost::OnCreateStream(
218 int stream_id, const media::AudioParameters& params, int input_channels) { 359 int stream_id, const media::AudioParameters& params, int input_channels) {
219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 360 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
220 DCHECK(LookupById(stream_id) == NULL); 361 DCHECK(LookupById(stream_id) == NULL);
221 362
222 media::AudioParameters audio_params(params); 363 media::AudioParameters audio_params(params);
223 uint32 buffer_size = media::AudioBus::CalculateMemorySize(audio_params); 364 uint32 buffer_size = media::AudioBus::CalculateMemorySize(audio_params);
224 DCHECK_GT(buffer_size, 0U); 365 DCHECK_GT(buffer_size, 0U);
225 DCHECK_LE(buffer_size, 366 DCHECK_LE(buffer_size,
226 static_cast<uint32>(media::limits::kMaxPacketSizeInBytes)); 367 static_cast<uint32>(media::limits::kMaxPacketSizeInBytes));
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 } 415 }
275 416
276 // If we have created the controller successfully, create an entry and add it 417 // If we have created the controller successfully, create an entry and add it
277 // to the map. 418 // to the map.
278 entry->stream_id = stream_id; 419 entry->stream_id = stream_id;
279 audio_entries_.insert(std::make_pair(stream_id, entry.release())); 420 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
280 if (media_observer_) 421 if (media_observer_)
281 media_observer_->OnSetAudioStreamStatus(this, stream_id, "created"); 422 media_observer_->OnSetAudioStreamStatus(this, stream_id, "created");
282 } 423 }
283 424
425 void AudioRendererHost::OnAssociateStreamWithProducer(int stream_id,
426 int render_view_id) {
427 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
428
429 AudioEntry* const entry = LookupById(stream_id);
430 if (!entry) {
431 SendErrorMessage(stream_id);
432 return;
433 }
434
435 if (entry->render_view_id == render_view_id)
436 return; // No change.
437
438 // If this stream is currently being mirrored, remove it from that mirroring
439 // session.
440 MirrorSessionMap::const_iterator prev_session_it =
441 mirror_sessions_.find(entry->render_view_id);
442 if (prev_session_it != mirror_sessions_.end()) {
443 if (entry->diverted_callback) {
444 prev_session_it->second->RemoveInput(entry->diverted_callback);
445 }
446 }
447
448 entry->render_view_id = render_view_id;
449
450 // If a mirroring session is already active for the RenderView, add this
451 // stream to that mirroring session.
452 MirrorSessionMap::const_iterator next_session_it =
453 mirror_sessions_.find(render_view_id);
454 if (next_session_it != mirror_sessions_.end()) {
455 if (!entry->pending_close) {
456 if (!entry->diverted_callback) {
457 entry->diverted_callback = entry->controller->Divert();
458 }
459 next_session_it->second->AddInput(entry->diverted_callback,
460 entry->controller->params());
461 }
462 } else if (entry->diverted_callback) {
463 // Clean-up: The audio stream was removed from the previous mirroring
464 // session, but there is no other mirroring session for it to be added to.
465 // So, "revert the divert."
466 entry->controller->Revert(entry->diverted_callback);
467 entry->diverted_callback = NULL;
468 }
469 }
470
284 void AudioRendererHost::OnPlayStream(int stream_id) { 471 void AudioRendererHost::OnPlayStream(int stream_id) {
285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 472 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
286 473
287 AudioEntry* entry = LookupById(stream_id); 474 AudioEntry* entry = LookupById(stream_id);
288 if (!entry) { 475 if (!entry) {
289 SendErrorMessage(stream_id); 476 SendErrorMessage(stream_id);
290 return; 477 return;
291 } 478 }
292 479
293 entry->controller->Play(); 480 entry->controller->Play();
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
363 for (AudioEntryMap::iterator i = audio_entries_.begin(); 550 for (AudioEntryMap::iterator i = audio_entries_.begin();
364 i != audio_entries_.end(); ++i) { 551 i != audio_entries_.end(); ++i) {
365 CloseAndDeleteStream(i->second); 552 CloseAndDeleteStream(i->second);
366 } 553 }
367 } 554 }
368 555
369 void AudioRendererHost::CloseAndDeleteStream(AudioEntry* entry) { 556 void AudioRendererHost::CloseAndDeleteStream(AudioEntry* entry) {
370 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 557 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
371 558
372 if (!entry->pending_close) { 559 if (!entry->pending_close) {
560 // If this stream is currently being mirrored, remove it from the mirroring
561 // session.
562 MirrorSessionMap::const_iterator session_it =
563 mirror_sessions_.find(entry->render_view_id);
564 if (session_it != mirror_sessions_.end() &&
565 entry->diverted_callback) {
566 session_it->second->RemoveInput(entry->diverted_callback);
567 // Note: We don't call AudioOutputController::Revert() since we're about
568 // to close the controller below. If we did call Revert(), it would cause
569 // an unnecessary round of immediate starting and stopping.
570 }
571
373 entry->controller->Close( 572 entry->controller->Close(
374 base::Bind(&AudioRendererHost::DeleteEntry, this, entry)); 573 base::Bind(&AudioRendererHost::DeleteEntry, this, entry));
574 entry->diverted_callback = NULL;
375 entry->pending_close = true; 575 entry->pending_close = true;
376 } 576 }
377 } 577 }
378 578
379 void AudioRendererHost::DeleteEntry(AudioEntry* entry) { 579 void AudioRendererHost::DeleteEntry(AudioEntry* entry) {
380 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 580 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
381 581
382 // Delete the entry when this method goes out of scope. 582 // Delete the entry when this method goes out of scope.
383 scoped_ptr<AudioEntry> entry_deleter(entry); 583 scoped_ptr<AudioEntry> entry_deleter(entry);
384 584
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
425 return NULL; 625 return NULL;
426 } 626 }
427 627
428 media::AudioOutputController* AudioRendererHost::LookupControllerByIdForTesting( 628 media::AudioOutputController* AudioRendererHost::LookupControllerByIdForTesting(
429 int stream_id) { 629 int stream_id) {
430 AudioEntry* const entry = LookupById(stream_id); 630 AudioEntry* const entry = LookupById(stream_id);
431 return entry ? entry->controller : NULL; 631 return entry ? entry->controller : NULL;
432 } 632 }
433 633
434 } // namespace content 634 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698