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

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: Simplify! 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"
(...skipping 12 matching lines...) Expand all
23 struct AudioRendererHost::AudioEntry { 23 struct AudioRendererHost::AudioEntry {
24 AudioEntry(); 24 AudioEntry();
25 ~AudioEntry(); 25 ~AudioEntry();
26 26
27 // The AudioOutputController that manages the audio stream. 27 // The AudioOutputController that manages the audio stream.
28 scoped_refptr<media::AudioOutputController> controller; 28 scoped_refptr<media::AudioOutputController> controller;
29 29
30 // The audio stream ID. 30 // The audio stream ID.
31 int stream_id; 31 int stream_id;
32 32
33 // The routing ID of the source render view.
34 int render_view_id;
35
33 // Shared memory for transmission of the audio data. 36 // Shared memory for transmission of the audio data.
34 base::SharedMemory shared_memory; 37 base::SharedMemory shared_memory;
35 38
36 // The synchronous reader to be used by the controller. We have the 39 // The synchronous reader to be used by the controller. We have the
37 // ownership of the reader. 40 // ownership of the reader.
38 scoped_ptr<media::AudioOutputController::SyncReader> reader; 41 scoped_ptr<media::AudioOutputController::SyncReader> reader;
39 42
40 // Set to true after we called Close() for the controller. 43 // Set to true after we called Close() for the controller.
41 bool pending_close; 44 bool pending_close;
42 }; 45 };
43 46
44 AudioRendererHost::AudioEntry::AudioEntry() 47 AudioRendererHost::AudioEntry::AudioEntry()
45 : stream_id(0), 48 : stream_id(0),
49 render_view_id(MSG_ROUTING_NONE),
46 pending_close(false) { 50 pending_close(false) {
47 } 51 }
48 52
49 AudioRendererHost::AudioEntry::~AudioEntry() {} 53 AudioRendererHost::AudioEntry::~AudioEntry() {}
50 54
55 AudioRendererHost::MirroringDestination::~MirroringDestination() {}
56
51 /////////////////////////////////////////////////////////////////////////////// 57 ///////////////////////////////////////////////////////////////////////////////
52 // AudioRendererHost implementations. 58 // AudioRendererHost implementations.
53 AudioRendererHost::AudioRendererHost( 59 AudioRendererHost::AudioRendererHost(
60 int render_process_id,
54 media::AudioManager* audio_manager, MediaObserver* media_observer) 61 media::AudioManager* audio_manager, MediaObserver* media_observer)
55 : audio_manager_(audio_manager), 62 : render_process_id_(render_process_id),
63 audio_manager_(audio_manager),
56 media_observer_(media_observer) { 64 media_observer_(media_observer) {
57 } 65 }
58 66
59 AudioRendererHost::~AudioRendererHost() { 67 AudioRendererHost::~AudioRendererHost() {
60 DCHECK(audio_entries_.empty()); 68 DCHECK(audio_entries_.empty());
69 DCHECK(mirror_sessions_.empty());
70 }
71
72 base::LazyInstance<AudioRendererHost::ActiveHostMap>::Leaky
73 AudioRendererHost::g_host_map_ = LAZY_INSTANCE_INITIALIZER;
tommi (sloooow) - chröme 2012/12/18 13:41:26 thinking out loud here... this map is only accesse
74
75 void AudioRendererHost::OnChannelConnected(int32 peer_pid) {
76 g_host_map_.Get().insert(std::make_pair(render_process_id_, this));
77
78 BrowserMessageFilter::OnChannelConnected(peer_pid);
61 } 79 }
62 80
63 void AudioRendererHost::OnChannelClosing() { 81 void AudioRendererHost::OnChannelClosing() {
64 BrowserMessageFilter::OnChannelClosing(); 82 BrowserMessageFilter::OnChannelClosing();
65 83
66 // Since the IPC channel is gone, close all requested audio streams. 84 // Since the IPC channel is gone, close all requested audio streams.
67 DeleteEntries(); 85 DeleteEntries();
86
87 while (!mirror_sessions_.empty()) {
88 MirrorSessionMap::iterator it = mirror_sessions_.begin();
89 DoStopMirroring(render_process_id_, it->first, it->second);
90 }
91
92 g_host_map_.Get().erase(render_process_id_);
68 } 93 }
69 94
70 void AudioRendererHost::OnDestruct() const { 95 void AudioRendererHost::OnDestruct() const {
71 BrowserThread::DeleteOnIOThread::Destruct(this); 96 BrowserThread::DeleteOnIOThread::Destruct(this);
72 } 97 }
73 98
74 /////////////////////////////////////////////////////////////////////////////// 99 ///////////////////////////////////////////////////////////////////////////////
75 // media::AudioOutputController::EventHandler implementations. 100 // media::AudioOutputController::EventHandler implementations.
76 void AudioRendererHost::OnCreated(media::AudioOutputController* controller) { 101 void AudioRendererHost::OnCreated(media::AudioOutputController* controller) {
77 BrowserThread::PostTask( 102 BrowserThread::PostTask(
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream) 234 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream)
210 IPC_MESSAGE_HANDLER(AudioHostMsg_FlushStream, OnFlushStream) 235 IPC_MESSAGE_HANDLER(AudioHostMsg_FlushStream, OnFlushStream)
211 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream) 236 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream)
212 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume) 237 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume)
213 IPC_MESSAGE_UNHANDLED(handled = false) 238 IPC_MESSAGE_UNHANDLED(handled = false)
214 IPC_END_MESSAGE_MAP_EX() 239 IPC_END_MESSAGE_MAP_EX()
215 240
216 return handled; 241 return handled;
217 } 242 }
218 243
244 // static
245 AudioRendererHost* AudioRendererHost::FromRenderProcessID(
246 int render_process_id) {
247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
248
249 // Note: It's possible for look-ups to fail since, for example, an
250 // AudioRendererHost could be shutdown before StartMirroring() is called.
251 // It's common for mirroring sessions to target a different render
252 // process/view than the one that will receive the mirrored audio data.
253 // Example sequence of events:
254 //
255 // 1. RenderProcess_1 wants to mirror a tab within RenderProcess_2.
256 // 2. RenderProcess_1 starts sending IPCs to initiate a mirroring session.
257 // 3. In the meantime, RenderProcess_2 is shut down (e.g., tab closed). The
258 // AudioRendererHost for RenderProcess_2 is destroyed as a result.
259 // 4. A browser-side entity for RenderProcess_1 attempts to call
260 // StartMirroring(), but since the AudioRendererHost for RenderProcess_2
261 // is gone, the look-up here fails.
262
263 ActiveHostMap& host_map = g_host_map_.Get();
264 ActiveHostMap::const_iterator it = host_map.find(render_process_id);
265 return it == host_map.end() ? NULL : it->second;
266 }
267
268 // static
269 void AudioRendererHost::StartMirroring(
270 int render_process_id, int render_view_id,
271 const scoped_refptr<MirroringDestination>& destination) {
272 BrowserThread::PostTask(
273 BrowserThread::IO, FROM_HERE,
274 base::Bind(&AudioRendererHost::DoStartMirroring,
275 render_process_id, render_view_id, destination));
276 }
277
278 // static
279 void AudioRendererHost::DoStartMirroring(
280 int render_process_id, int render_view_id,
281 const scoped_refptr<MirroringDestination>& destination) {
282 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
283 DCHECK(destination);
284
285 AudioRendererHost* const host = FromRenderProcessID(render_process_id);
286 if (!host) {
tommi (sloooow) - chröme 2012/12/18 13:41:26 no {}
287 return; // See comment in FromRenderProcessID().
288 }
289
290 // Insert an entry into the set of active mirroring sessions. If a mirroring
291 // session is already active for |render_process_id| + |render_view_id|,
292 // replace the entry.
293 MirrorSessionMap::iterator session_it =
294 host->mirror_sessions_.find(render_view_id);
295 scoped_refptr<MirroringDestination> old_destination;
296 if (session_it == host->mirror_sessions_.end()) {
297 host->mirror_sessions_.insert(std::make_pair(render_view_id, destination));
298
299 DVLOG(1) << "Start mirroring render_process_id:render_view_id="
300 << render_process_id << ':' << render_view_id
301 << " --> MirroringDestination@" << destination;
302 } else {
303 old_destination = session_it->second;
304 session_it->second = destination;
305
306 DVLOG(1) << "Switch mirroring of render_process_id:render_view_id="
307 << render_process_id << ':' << render_view_id
308 << " MirroringDestination@" << old_destination
309 << " --> MirroringDestination@" << destination;
310 }
311
312 // Divert any existing audio streams to |destination|. If streams were
313 // already diverted to the |old_destination|, remove them.
314 for (AudioEntryMap::const_iterator it = host->audio_entries_.begin();
315 it != host->audio_entries_.end(); ++it) {
316 AudioEntry* const entry = it->second;
317 if (entry->render_view_id == render_view_id && !entry->pending_close) {
318 if (old_destination)
319 entry->controller->RevertDiversion();
320 entry->controller->DivertToStream(
321 destination->AddInput(entry->controller->params()));
322 }
323 }
324 }
325
326 // static
327 void AudioRendererHost::StopMirroring(
328 int render_process_id, int render_view_id,
329 const scoped_refptr<MirroringDestination>& destination) {
330 BrowserThread::PostTask(
331 BrowserThread::IO, FROM_HERE,
332 base::Bind(&AudioRendererHost::DoStopMirroring,
333 render_process_id, render_view_id, destination));
334 }
335
336 // static
337 void AudioRendererHost::DoStopMirroring(
338 int render_process_id, int render_view_id,
339 const scoped_refptr<MirroringDestination>& destination) {
340 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
341
342 AudioRendererHost* const host = FromRenderProcessID(render_process_id);
343 if (!host) {
tommi (sloooow) - chröme 2012/12/18 13:41:26 no {}
344 return; // See comment in FromRenderProcessID().
345 }
346
347 MirrorSessionMap::iterator session_it =
348 host->mirror_sessions_.find(render_view_id);
349 if (session_it == host->mirror_sessions_.end() ||
350 destination != session_it->second) {
351 return;
352 }
353
354 DVLOG(1) << "Stop mirroring render_process_id:render_view_id="
355 << render_process_id << ':' << render_view_id
356 << " --> MirroringDestination@" << destination;
357
358 // Revert the "divert" for each audio stream currently active in the mirroring
359 // session being stopped.
360 for (AudioEntryMap::const_iterator it = host->audio_entries_.begin();
361 it != host->audio_entries_.end(); ++it) {
362 AudioEntry* const entry = it->second;
363 if (entry->render_view_id == render_view_id && !entry->pending_close) {
tommi (sloooow) - chröme 2012/12/18 13:41:26 same here (no {}) and throughout for single line i
364 entry->controller->RevertDiversion();
365 }
366 }
367
368 host->mirror_sessions_.erase(session_it);
369 }
370
219 void AudioRendererHost::OnCreateStream( 371 void AudioRendererHost::OnCreateStream(
220 int stream_id, const media::AudioParameters& params, int input_channels) { 372 int stream_id, const media::AudioParameters& params, int input_channels) {
221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 373 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
222 DCHECK(LookupById(stream_id) == NULL); 374 DCHECK(LookupById(stream_id) == NULL);
223 375
224 media::AudioParameters audio_params(params); 376 media::AudioParameters audio_params(params);
225 uint32 buffer_size = media::AudioBus::CalculateMemorySize(audio_params); 377 uint32 buffer_size = media::AudioBus::CalculateMemorySize(audio_params);
226 DCHECK_GT(buffer_size, 0U); 378 DCHECK_GT(buffer_size, 0U);
227 DCHECK_LE(buffer_size, 379 DCHECK_LE(buffer_size,
228 static_cast<uint32>(media::limits::kMaxPacketSizeInBytes)); 380 static_cast<uint32>(media::limits::kMaxPacketSizeInBytes));
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 // If we have created the controller successfully, create an entry and add it 430 // If we have created the controller successfully, create an entry and add it
279 // to the map. 431 // to the map.
280 entry->stream_id = stream_id; 432 entry->stream_id = stream_id;
281 audio_entries_.insert(std::make_pair(stream_id, entry.release())); 433 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
282 if (media_observer_) 434 if (media_observer_)
283 media_observer_->OnSetAudioStreamStatus(this, stream_id, "created"); 435 media_observer_->OnSetAudioStreamStatus(this, stream_id, "created");
284 } 436 }
285 437
286 void AudioRendererHost::OnAssociateStreamWithProducer(int stream_id, 438 void AudioRendererHost::OnAssociateStreamWithProducer(int stream_id,
287 int render_view_id) { 439 int render_view_id) {
288 // TODO(miu): Will use render_view_id in upcoming change. 440 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
289 DVLOG(1) << "AudioRendererHost@" << this 441
290 << "::OnAssociateStreamWithProducer(stream_id=" << stream_id 442 AudioEntry* const entry = LookupById(stream_id);
291 << ", render_view_id=" << render_view_id << ")"; 443 if (!entry) {
444 SendErrorMessage(stream_id);
445 return;
446 }
447
448 if (entry->render_view_id == render_view_id)
449 return; // No change.
450
451 MirrorSessionMap::const_iterator prev_session_it =
452 mirror_sessions_.find(entry->render_view_id);
453 if (prev_session_it != mirror_sessions_.end()) {
454 entry->controller->RevertDiversion();
455 }
456
457 entry->render_view_id = render_view_id;
458
459 MirrorSessionMap::const_iterator next_session_it =
460 mirror_sessions_.find(render_view_id);
461 if (next_session_it != mirror_sessions_.end()) {
462 entry->controller->DivertToStream(
463 next_session_it->second->AddInput(entry->controller->params()));
464 }
292 } 465 }
293 466
294 void AudioRendererHost::OnPlayStream(int stream_id) { 467 void AudioRendererHost::OnPlayStream(int stream_id) {
295 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 468 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
296 469
297 AudioEntry* entry = LookupById(stream_id); 470 AudioEntry* entry = LookupById(stream_id);
298 if (!entry) { 471 if (!entry) {
299 SendErrorMessage(stream_id); 472 SendErrorMessage(stream_id);
300 return; 473 return;
301 } 474 }
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
435 return NULL; 608 return NULL;
436 } 609 }
437 610
438 media::AudioOutputController* AudioRendererHost::LookupControllerByIdForTesting( 611 media::AudioOutputController* AudioRendererHost::LookupControllerByIdForTesting(
439 int stream_id) { 612 int stream_id) {
440 AudioEntry* const entry = LookupById(stream_id); 613 AudioEntry* const entry = LookupById(stream_id);
441 return entry ? entry->controller : NULL; 614 return entry ? entry->controller : NULL;
442 } 615 }
443 616
444 } // namespace content 617 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698