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

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: AudioSourceDiverter now in its own file. Other tweaks, per Dale's comments. Created 7 years, 11 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 "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_mirroring_manager.h"
12 #include "content/browser/renderer_host/media/audio_sync_reader.h" 13 #include "content/browser/renderer_host/media/audio_sync_reader.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"
15 #include "media/audio/shared_memory_util.h" 16 #include "media/audio/shared_memory_util.h"
16 #include "media/base/audio_bus.h" 17 #include "media/base/audio_bus.h"
17 #include "media/base/limits.h" 18 #include "media/base/limits.h"
18 19
19 using media::AudioBus; 20 using media::AudioBus;
20 21
21 namespace content { 22 namespace content {
22 23
23 struct AudioRendererHost::AudioEntry { 24 struct AudioRendererHost::AudioEntry {
24 AudioEntry(); 25 AudioEntry();
25 ~AudioEntry(); 26 ~AudioEntry();
26 27
27 // The AudioOutputController that manages the audio stream. 28 // The AudioOutputController that manages the audio stream.
28 scoped_refptr<media::AudioOutputController> controller; 29 scoped_refptr<media::AudioOutputController> controller;
29 30
30 // The audio stream ID. 31 // The audio stream ID.
31 int stream_id; 32 int stream_id;
32 33
34 // The routing ID of the source render view.
35 int render_view_id;
36
33 // Shared memory for transmission of the audio data. 37 // Shared memory for transmission of the audio data.
34 base::SharedMemory shared_memory; 38 base::SharedMemory shared_memory;
35 39
36 // The synchronous reader to be used by the controller. We have the 40 // The synchronous reader to be used by the controller. We have the
37 // ownership of the reader. 41 // ownership of the reader.
38 scoped_ptr<media::AudioOutputController::SyncReader> reader; 42 scoped_ptr<media::AudioOutputController::SyncReader> reader;
39 43
40 // Set to true after we called Close() for the controller. 44 // Set to true after we called Close() for the controller.
41 bool pending_close; 45 bool pending_close;
42 }; 46 };
43 47
44 AudioRendererHost::AudioEntry::AudioEntry() 48 AudioRendererHost::AudioEntry::AudioEntry()
45 : stream_id(0), 49 : stream_id(0),
50 render_view_id(MSG_ROUTING_NONE),
46 pending_close(false) { 51 pending_close(false) {
47 } 52 }
48 53
49 AudioRendererHost::AudioEntry::~AudioEntry() {} 54 AudioRendererHost::AudioEntry::~AudioEntry() {}
50 55
51 /////////////////////////////////////////////////////////////////////////////// 56 ///////////////////////////////////////////////////////////////////////////////
52 // AudioRendererHost implementations. 57 // AudioRendererHost implementations.
53 AudioRendererHost::AudioRendererHost( 58 AudioRendererHost::AudioRendererHost(
54 media::AudioManager* audio_manager, MediaObserver* media_observer) 59 int render_process_id,
55 : audio_manager_(audio_manager), 60 media::AudioManager* audio_manager,
61 AudioMirroringManager* mirroring_manager,
62 MediaObserver* media_observer)
63 : render_process_id_(render_process_id),
64 audio_manager_(audio_manager),
65 mirroring_manager_(mirroring_manager),
56 media_observer_(media_observer) { 66 media_observer_(media_observer) {
67 DCHECK(audio_manager_);
68 DCHECK(mirroring_manager_);
69 DCHECK(media_observer_);
57 } 70 }
58 71
59 AudioRendererHost::~AudioRendererHost() { 72 AudioRendererHost::~AudioRendererHost() {
60 DCHECK(audio_entries_.empty()); 73 DCHECK(audio_entries_.empty());
61 } 74 }
62 75
63 void AudioRendererHost::OnChannelClosing() { 76 void AudioRendererHost::OnChannelClosing() {
64 BrowserMessageFilter::OnChannelClosing(); 77 BrowserMessageFilter::OnChannelClosing();
65 78
66 // Since the IPC channel is gone, close all requested audio streams. 79 // Since the IPC channel is gone, close all requested audio streams.
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 if (!reader->Init()) { 271 if (!reader->Init()) {
259 SendErrorMessage(stream_id); 272 SendErrorMessage(stream_id);
260 return; 273 return;
261 } 274 }
262 275
263 // If we have successfully created the SyncReader then assign it to the 276 // If we have successfully created the SyncReader then assign it to the
264 // entry and construct an AudioOutputController. 277 // entry and construct an AudioOutputController.
265 entry->reader.reset(reader.release()); 278 entry->reader.reset(reader.release());
266 entry->controller = media::AudioOutputController::Create( 279 entry->controller = media::AudioOutputController::Create(
267 audio_manager_, this, audio_params, entry->reader.get()); 280 audio_manager_, this, audio_params, entry->reader.get());
268
269 if (!entry->controller) { 281 if (!entry->controller) {
270 SendErrorMessage(stream_id); 282 SendErrorMessage(stream_id);
271 return; 283 return;
272 } 284 }
273 285
274 // If we have created the controller successfully, create an entry and add it 286 // If we have created the controller successfully, create an entry and add it
275 // to the map. 287 // to the map.
276 entry->stream_id = stream_id; 288 entry->stream_id = stream_id;
277 audio_entries_.insert(std::make_pair(stream_id, entry.release())); 289 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
278 if (media_observer_) 290 media_observer_->OnSetAudioStreamStatus(this, stream_id, "created");
279 media_observer_->OnSetAudioStreamStatus(this, stream_id, "created");
280 } 291 }
281 292
282 void AudioRendererHost::OnAssociateStreamWithProducer(int stream_id, 293 void AudioRendererHost::OnAssociateStreamWithProducer(int stream_id,
283 int render_view_id) { 294 int render_view_id) {
284 // TODO(miu): Will use render_view_id in upcoming change. 295 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
296
285 DVLOG(1) << "AudioRendererHost@" << this 297 DVLOG(1) << "AudioRendererHost@" << this
286 << "::OnAssociateStreamWithProducer(stream_id=" << stream_id 298 << "::OnAssociateStreamWithProducer(stream_id=" << stream_id
287 << ", render_view_id=" << render_view_id << ")"; 299 << ", render_view_id=" << render_view_id << ")";
300
301 AudioEntry* const entry = LookupById(stream_id);
302 if (!entry) {
303 SendErrorMessage(stream_id);
304 return;
305 }
306
307 if (entry->render_view_id == render_view_id)
308 return; // No change.
309
310 mirroring_manager_->RemoveDiverter(
311 render_process_id_, entry->render_view_id, entry->controller);
312 entry->render_view_id = render_view_id;
313 mirroring_manager_->AddDiverter(
314 render_process_id_, entry->render_view_id, entry->controller);
288 } 315 }
289 316
290 void AudioRendererHost::OnPlayStream(int stream_id) { 317 void AudioRendererHost::OnPlayStream(int stream_id) {
291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
292 319
293 AudioEntry* entry = LookupById(stream_id); 320 AudioEntry* entry = LookupById(stream_id);
294 if (!entry) { 321 if (!entry) {
295 SendErrorMessage(stream_id); 322 SendErrorMessage(stream_id);
296 return; 323 return;
297 } 324 }
298 325
299 entry->controller->Play(); 326 entry->controller->Play();
300 if (media_observer_) 327 media_observer_->OnSetAudioStreamPlaying(this, stream_id, true);
301 media_observer_->OnSetAudioStreamPlaying(this, stream_id, true);
302 } 328 }
303 329
304 void AudioRendererHost::OnPauseStream(int stream_id) { 330 void AudioRendererHost::OnPauseStream(int stream_id) {
305 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
306 332
307 AudioEntry* entry = LookupById(stream_id); 333 AudioEntry* entry = LookupById(stream_id);
308 if (!entry) { 334 if (!entry) {
309 SendErrorMessage(stream_id); 335 SendErrorMessage(stream_id);
310 return; 336 return;
311 } 337 }
312 338
313 entry->controller->Pause(); 339 entry->controller->Pause();
314 if (media_observer_) 340 media_observer_->OnSetAudioStreamPlaying(this, stream_id, false);
315 media_observer_->OnSetAudioStreamPlaying(this, stream_id, false);
316 } 341 }
317 342
318 void AudioRendererHost::OnFlushStream(int stream_id) { 343 void AudioRendererHost::OnFlushStream(int stream_id) {
319 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 344 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
320 345
321 AudioEntry* entry = LookupById(stream_id); 346 AudioEntry* entry = LookupById(stream_id);
322 if (!entry) { 347 if (!entry) {
323 SendErrorMessage(stream_id); 348 SendErrorMessage(stream_id);
324 return; 349 return;
325 } 350 }
326 351
327 entry->controller->Flush(); 352 entry->controller->Flush();
328 if (media_observer_) 353 media_observer_->OnSetAudioStreamStatus(this, stream_id, "flushed");
329 media_observer_->OnSetAudioStreamStatus(this, stream_id, "flushed");
330 } 354 }
331 355
332 void AudioRendererHost::OnCloseStream(int stream_id) { 356 void AudioRendererHost::OnCloseStream(int stream_id) {
333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 357 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
334 358
335 if (media_observer_) 359 media_observer_->OnSetAudioStreamStatus(this, stream_id, "closed");
336 media_observer_->OnSetAudioStreamStatus(this, stream_id, "closed");
337 360
338 AudioEntry* entry = LookupById(stream_id); 361 AudioEntry* entry = LookupById(stream_id);
339 362
340 if (entry) 363 if (entry)
341 CloseAndDeleteStream(entry); 364 CloseAndDeleteStream(entry);
342 } 365 }
343 366
344 void AudioRendererHost::OnSetVolume(int stream_id, double volume) { 367 void AudioRendererHost::OnSetVolume(int stream_id, double volume) {
345 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 368 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
346 369
347 AudioEntry* entry = LookupById(stream_id); 370 AudioEntry* entry = LookupById(stream_id);
348 if (!entry) { 371 if (!entry) {
349 SendErrorMessage(stream_id); 372 SendErrorMessage(stream_id);
350 return; 373 return;
351 } 374 }
352 375
353 // Make sure the volume is valid. 376 // Make sure the volume is valid.
354 if (volume < 0 || volume > 1.0) 377 if (volume < 0 || volume > 1.0)
355 return; 378 return;
356 entry->controller->SetVolume(volume); 379 entry->controller->SetVolume(volume);
357 if (media_observer_) 380 media_observer_->OnSetAudioStreamVolume(this, stream_id, volume);
358 media_observer_->OnSetAudioStreamVolume(this, stream_id, volume);
359 } 381 }
360 382
361 void AudioRendererHost::SendErrorMessage(int32 stream_id) { 383 void AudioRendererHost::SendErrorMessage(int32 stream_id) {
362 Send(new AudioMsg_NotifyStreamStateChanged( 384 Send(new AudioMsg_NotifyStreamStateChanged(
363 stream_id, media::AudioOutputIPCDelegate::kError)); 385 stream_id, media::AudioOutputIPCDelegate::kError));
364 } 386 }
365 387
366 void AudioRendererHost::DeleteEntries() { 388 void AudioRendererHost::DeleteEntries() {
367 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 389 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
368 390
369 for (AudioEntryMap::iterator i = audio_entries_.begin(); 391 for (AudioEntryMap::iterator i = audio_entries_.begin();
370 i != audio_entries_.end(); ++i) { 392 i != audio_entries_.end(); ++i) {
371 CloseAndDeleteStream(i->second); 393 CloseAndDeleteStream(i->second);
372 } 394 }
373 } 395 }
374 396
375 void AudioRendererHost::CloseAndDeleteStream(AudioEntry* entry) { 397 void AudioRendererHost::CloseAndDeleteStream(AudioEntry* entry) {
376 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
377 399
378 if (!entry->pending_close) { 400 if (!entry->pending_close) {
401 mirroring_manager_->RemoveDiverter(
402 render_process_id_, entry->render_view_id, entry->controller);
379 entry->controller->Close( 403 entry->controller->Close(
380 base::Bind(&AudioRendererHost::DeleteEntry, this, entry)); 404 base::Bind(&AudioRendererHost::DeleteEntry, this, entry));
381 entry->pending_close = true; 405 entry->pending_close = true;
382 } 406 }
383 } 407 }
384 408
385 void AudioRendererHost::DeleteEntry(AudioEntry* entry) { 409 void AudioRendererHost::DeleteEntry(AudioEntry* entry) {
386 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 410 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
387 411
388 // Delete the entry when this method goes out of scope. 412 // Delete the entry when this method goes out of scope.
389 scoped_ptr<AudioEntry> entry_deleter(entry); 413 scoped_ptr<AudioEntry> entry_deleter(entry);
390 414
391 // Erase the entry identified by |stream_id| from the map. 415 // Erase the entry identified by |stream_id| from the map.
392 audio_entries_.erase(entry->stream_id); 416 audio_entries_.erase(entry->stream_id);
393 417
394 // Notify the media observer. 418 // Notify the media observer.
395 if (media_observer_) 419 media_observer_->OnDeleteAudioStream(this, entry->stream_id);
396 media_observer_->OnDeleteAudioStream(this, entry->stream_id);
397 } 420 }
398 421
399 void AudioRendererHost::DeleteEntryOnError(AudioEntry* entry) { 422 void AudioRendererHost::DeleteEntryOnError(AudioEntry* entry) {
400 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
401 424
402 // Sends the error message first before we close the stream because 425 // Sends the error message first before we close the stream because
403 // |entry| is destroyed in DeleteEntry(). 426 // |entry| is destroyed in DeleteEntry().
404 SendErrorMessage(entry->stream_id); 427 SendErrorMessage(entry->stream_id);
405 428
406 if (media_observer_) 429 media_observer_->OnSetAudioStreamStatus(this, entry->stream_id, "error");
407 media_observer_->OnSetAudioStreamStatus(this, entry->stream_id, "error");
408 CloseAndDeleteStream(entry); 430 CloseAndDeleteStream(entry);
409 } 431 }
410 432
411 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) { 433 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) {
412 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 434 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
413 435
414 AudioEntryMap::iterator i = audio_entries_.find(stream_id); 436 AudioEntryMap::iterator i = audio_entries_.find(stream_id);
415 if (i != audio_entries_.end() && !i->second->pending_close) 437 if (i != audio_entries_.end() && !i->second->pending_close)
416 return i->second; 438 return i->second;
417 return NULL; 439 return NULL;
(...skipping 13 matching lines...) Expand all
431 return NULL; 453 return NULL;
432 } 454 }
433 455
434 media::AudioOutputController* AudioRendererHost::LookupControllerByIdForTesting( 456 media::AudioOutputController* AudioRendererHost::LookupControllerByIdForTesting(
435 int stream_id) { 457 int stream_id) {
436 AudioEntry* const entry = LookupById(stream_id); 458 AudioEntry* const entry = LookupById(stream_id);
437 return entry ? entry->controller : NULL; 459 return entry ? entry->controller : NULL;
438 } 460 }
439 461
440 } // namespace content 462 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698