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

Side by Side Diff: chrome/browser/renderer_host/audio_renderer_host.cc

Issue 354002: Sixth patch in getting rid of caching MessageLoop pointers. Audio and automa... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 1 month 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) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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 // TODO(hclam): Several changes need to be made to this code: 5 // TODO(hclam): Several changes need to be made to this code:
6 // 1. We should host AudioRendererHost on a dedicated audio thread. Doing 6 // 1. We should host AudioRendererHost on a dedicated audio thread. Doing
7 // so we don't have to worry about blocking method calls such as 7 // so we don't have to worry about blocking method calls such as
8 // play / stop an audio stream. 8 // play / stop an audio stream.
9 // 2. Move locked data structures into a separate structure that sanity 9 // 2. Move locked data structures into a separate structure that sanity
10 // checks access by different threads that use it. 10 // checks access by different threads that use it.
11 // 11 //
12 // SEMANTICS OF |state_| 12 // SEMANTICS OF |state_|
13 // Note that |state_| of IPCAudioSource is accessed on two thread. Namely 13 // Note that |state_| of IPCAudioSource is accessed on two thread. Namely
14 // the IO thread and the audio thread. IO thread is the thread on which 14 // the IO thread and the audio thread. IO thread is the thread on which
15 // IPAudioSource::Play(), IPCAudioSource::Pause() are called. Audio thread 15 // IPAudioSource::Play(), IPCAudioSource::Pause() are called. Audio thread
16 // is a thread operated by the audio hardware for requesting data. 16 // is a thread operated by the audio hardware for requesting data.
17 // It is important that |state_| is only written on the IO thread because 17 // It is important that |state_| is only written on the IO thread because
18 // reading of such state in Play() and Pause() is not protected. However, 18 // reading of such state in Play() and Pause() is not protected. However,
19 // since OnMoreData() is called on the audio thread and reads |state_| 19 // since OnMoreData() is called on the audio thread and reads |state_|
20 // variable. Writing to this variable needs to be protected in Play() 20 // variable. Writing to this variable needs to be protected in Play()
21 // and Pause(). 21 // and Pause().
22 22
23 #include "base/histogram.h" 23 #include "base/histogram.h"
24 #include "base/lock.h" 24 #include "base/lock.h"
25 #include "base/message_loop.h"
26 #include "base/process.h" 25 #include "base/process.h"
27 #include "base/shared_memory.h" 26 #include "base/shared_memory.h"
28 #include "base/waitable_event.h" 27 #include "base/waitable_event.h"
28 #include "chrome/browser/chrome_thread.h"
29 #include "chrome/browser/renderer_host/audio_renderer_host.h" 29 #include "chrome/browser/renderer_host/audio_renderer_host.h"
30 #include "chrome/common/render_messages.h" 30 #include "chrome/common/render_messages.h"
31 #include "ipc/ipc_logging.h" 31 #include "ipc/ipc_logging.h"
32 32
33 namespace { 33 namespace {
34 34
35 // This constant governs the hardware audio buffer size, this value should be 35 // This constant governs the hardware audio buffer size, this value should be
36 // choosen carefully and is platform specific. 36 // choosen carefully and is platform specific.
37 const int kSamplesPerHardwarePacket = 8192; 37 const int kSamplesPerHardwarePacket = 8192;
38 38
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after
324 } 324 }
325 } 325 }
326 326
327 void AudioRendererHost::IPCAudioSource::StartBuffering() { 327 void AudioRendererHost::IPCAudioSource::StartBuffering() {
328 SubmitPacketRequest(NULL); 328 SubmitPacketRequest(NULL);
329 } 329 }
330 330
331 //----------------------------------------------------------------------------- 331 //-----------------------------------------------------------------------------
332 // AudioRendererHost implementations. 332 // AudioRendererHost implementations.
333 333
334 AudioRendererHost::AudioRendererHost(MessageLoop* message_loop) 334 AudioRendererHost::AudioRendererHost()
335 : process_id_(0), 335 : process_id_(0),
336 process_handle_(0), 336 process_handle_(0),
337 ipc_sender_(NULL), 337 ipc_sender_(NULL) {
338 io_loop_(message_loop) {
339 // Make sure we perform actual initialization operations in the thread where 338 // Make sure we perform actual initialization operations in the thread where
340 // this object should live. 339 // this object should live.
341 io_loop_->PostTask(FROM_HERE, 340 ChromeThread::PostTask(
341 ChromeThread::IO, FROM_HERE,
342 NewRunnableMethod(this, &AudioRendererHost::OnInitialized)); 342 NewRunnableMethod(this, &AudioRendererHost::OnInitialized));
343 } 343 }
344 344
345 AudioRendererHost::~AudioRendererHost() { 345 AudioRendererHost::~AudioRendererHost() {
346 DCHECK(sources_.empty()); 346 DCHECK(sources_.empty());
347 } 347 }
348 348
349 void AudioRendererHost::Destroy() { 349 void AudioRendererHost::Destroy() {
350 // Post a message to the thread where this object should live and do the 350 // Post a message to the thread where this object should live and do the
351 // actual operations there. 351 // actual operations there.
352 io_loop_->PostTask( 352 ChromeThread::PostTask(
353 FROM_HERE, NewRunnableMethod(this, &AudioRendererHost::OnDestroyed)); 353 ChromeThread::IO, FROM_HERE,
354 NewRunnableMethod(this, &AudioRendererHost::OnDestroyed));
354 } 355 }
355 356
356 // Event received when IPC channel is connected to the renderer process. 357 // Event received when IPC channel is connected to the renderer process.
357 void AudioRendererHost::IPCChannelConnected(int process_id, 358 void AudioRendererHost::IPCChannelConnected(int process_id,
358 base::ProcessHandle process_handle, 359 base::ProcessHandle process_handle,
359 IPC::Message::Sender* ipc_sender) { 360 IPC::Message::Sender* ipc_sender) {
360 DCHECK(MessageLoop::current() == io_loop_); 361 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
361 process_id_ = process_id; 362 process_id_ = process_id;
362 process_handle_ = process_handle; 363 process_handle_ = process_handle;
363 ipc_sender_ = ipc_sender; 364 ipc_sender_ = ipc_sender;
364 } 365 }
365 366
366 // Event received when IPC channel is closing. 367 // Event received when IPC channel is closing.
367 void AudioRendererHost::IPCChannelClosing() { 368 void AudioRendererHost::IPCChannelClosing() {
368 DCHECK(MessageLoop::current() == io_loop_); 369 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
369 ipc_sender_ = NULL; 370 ipc_sender_ = NULL;
370 process_handle_ = 0; 371 process_handle_ = 0;
371 process_id_ = 0; 372 process_id_ = 0;
372 DestroyAllSources(); 373 DestroyAllSources();
373 } 374 }
374 375
375 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message, 376 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message,
376 bool* message_was_ok) { 377 bool* message_was_ok) {
377 if (!IsAudioRendererHostMessage(message)) 378 if (!IsAudioRendererHostMessage(message))
378 return false; 379 return false;
(...skipping 25 matching lines...) Expand all
404 return true; 405 return true;
405 default: 406 default:
406 break; 407 break;
407 } 408 }
408 return false; 409 return false;
409 } 410 }
410 411
411 void AudioRendererHost::OnCreateStream( 412 void AudioRendererHost::OnCreateStream(
412 const IPC::Message& msg, int stream_id, 413 const IPC::Message& msg, int stream_id,
413 const ViewHostMsg_Audio_CreateStream& params) { 414 const ViewHostMsg_Audio_CreateStream& params) {
414 DCHECK(MessageLoop::current() == io_loop_); 415 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
415 DCHECK(Lookup(msg.routing_id(), stream_id) == NULL); 416 DCHECK(Lookup(msg.routing_id(), stream_id) == NULL);
416 417
417 IPCAudioSource* source = IPCAudioSource::CreateIPCAudioSource( 418 IPCAudioSource* source = IPCAudioSource::CreateIPCAudioSource(
418 this, 419 this,
419 process_id_, 420 process_id_,
420 msg.routing_id(), 421 msg.routing_id(),
421 stream_id, 422 stream_id,
422 process_handle_, 423 process_handle_,
423 params.format, 424 params.format,
424 params.channels, 425 params.channels,
425 params.sample_rate, 426 params.sample_rate,
426 params.bits_per_sample, 427 params.bits_per_sample,
427 params.packet_size, 428 params.packet_size,
428 params.buffer_capacity); 429 params.buffer_capacity);
429 430
430 // If we have created the source successfully, adds it to the map. 431 // If we have created the source successfully, adds it to the map.
431 if (source) { 432 if (source) {
432 sources_.insert( 433 sources_.insert(
433 std::make_pair( 434 std::make_pair(
434 SourceID(source->route_id(), source->stream_id()), source)); 435 SourceID(source->route_id(), source->stream_id()), source));
435 } else { 436 } else {
436 SendErrorMessage(msg.routing_id(), stream_id); 437 SendErrorMessage(msg.routing_id(), stream_id);
437 } 438 }
438 } 439 }
439 440
440 void AudioRendererHost::OnPlayStream(const IPC::Message& msg, int stream_id) { 441 void AudioRendererHost::OnPlayStream(const IPC::Message& msg, int stream_id) {
441 DCHECK(MessageLoop::current() == io_loop_); 442 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
442 IPCAudioSource* source = Lookup(msg.routing_id(), stream_id); 443 IPCAudioSource* source = Lookup(msg.routing_id(), stream_id);
443 if (source) { 444 if (source) {
444 source->Play(); 445 source->Play();
445 } else { 446 } else {
446 SendErrorMessage(msg.routing_id(), stream_id); 447 SendErrorMessage(msg.routing_id(), stream_id);
447 } 448 }
448 } 449 }
449 450
450 void AudioRendererHost::OnPauseStream(const IPC::Message& msg, int stream_id) { 451 void AudioRendererHost::OnPauseStream(const IPC::Message& msg, int stream_id) {
451 DCHECK(MessageLoop::current() == io_loop_); 452 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
452 IPCAudioSource* source = Lookup(msg.routing_id(), stream_id); 453 IPCAudioSource* source = Lookup(msg.routing_id(), stream_id);
453 if (source) { 454 if (source) {
454 source->Pause(); 455 source->Pause();
455 } else { 456 } else {
456 SendErrorMessage(msg.routing_id(), stream_id); 457 SendErrorMessage(msg.routing_id(), stream_id);
457 } 458 }
458 } 459 }
459 460
460 void AudioRendererHost::OnCloseStream(const IPC::Message& msg, int stream_id) { 461 void AudioRendererHost::OnCloseStream(const IPC::Message& msg, int stream_id) {
461 DCHECK(MessageLoop::current() == io_loop_); 462 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
462 IPCAudioSource* source = Lookup(msg.routing_id(), stream_id); 463 IPCAudioSource* source = Lookup(msg.routing_id(), stream_id);
463 if (source) { 464 if (source) {
464 DestroySource(source); 465 DestroySource(source);
465 } 466 }
466 } 467 }
467 468
468 void AudioRendererHost::OnSetVolume(const IPC::Message& msg, int stream_id, 469 void AudioRendererHost::OnSetVolume(const IPC::Message& msg, int stream_id,
469 double left_channel, double right_channel) { 470 double left_channel, double right_channel) {
470 DCHECK(MessageLoop::current() == io_loop_); 471 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
471 IPCAudioSource* source = Lookup(msg.routing_id(), stream_id); 472 IPCAudioSource* source = Lookup(msg.routing_id(), stream_id);
472 if (source) { 473 if (source) {
473 source->SetVolume(left_channel, right_channel); 474 source->SetVolume(left_channel, right_channel);
474 } else { 475 } else {
475 SendErrorMessage(msg.routing_id(), stream_id); 476 SendErrorMessage(msg.routing_id(), stream_id);
476 } 477 }
477 } 478 }
478 479
479 void AudioRendererHost::OnGetVolume(const IPC::Message& msg, int stream_id) { 480 void AudioRendererHost::OnGetVolume(const IPC::Message& msg, int stream_id) {
480 DCHECK(MessageLoop::current() == io_loop_); 481 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
481 IPCAudioSource* source = Lookup(msg.routing_id(), stream_id); 482 IPCAudioSource* source = Lookup(msg.routing_id(), stream_id);
482 if (source) { 483 if (source) {
483 source->GetVolume(); 484 source->GetVolume();
484 } else { 485 } else {
485 SendErrorMessage(msg.routing_id(), stream_id); 486 SendErrorMessage(msg.routing_id(), stream_id);
486 } 487 }
487 } 488 }
488 489
489 void AudioRendererHost::OnNotifyPacketReady(const IPC::Message& msg, 490 void AudioRendererHost::OnNotifyPacketReady(const IPC::Message& msg,
490 int stream_id, size_t packet_size) { 491 int stream_id, size_t packet_size) {
491 DCHECK(MessageLoop::current() == io_loop_); 492 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
492 IPCAudioSource* source = Lookup(msg.routing_id(), stream_id); 493 IPCAudioSource* source = Lookup(msg.routing_id(), stream_id);
493 if (source) { 494 if (source) {
494 source->NotifyPacketReady(packet_size); 495 source->NotifyPacketReady(packet_size);
495 } else { 496 } else {
496 SendErrorMessage(msg.routing_id(), stream_id); 497 SendErrorMessage(msg.routing_id(), stream_id);
497 } 498 }
498 } 499 }
499 500
500 void AudioRendererHost::OnInitialized() { 501 void AudioRendererHost::OnInitialized() {
501 DCHECK(MessageLoop::current() == io_loop_); 502 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
502 // Increase the ref count of this object so it is active until we do 503 // Increase the ref count of this object so it is active until we do
503 // Release(). 504 // Release().
504 AddRef(); 505 AddRef();
505 } 506 }
506 507
507 void AudioRendererHost::OnDestroyed() { 508 void AudioRendererHost::OnDestroyed() {
508 DCHECK(MessageLoop::current() == io_loop_); 509 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
509 ipc_sender_ = NULL; 510 ipc_sender_ = NULL;
510 process_handle_ = 0; 511 process_handle_ = 0;
511 process_id_ = 0; 512 process_id_ = 0;
512 DestroyAllSources(); 513 DestroyAllSources();
513 // Decrease the reference to this object, which may lead to self-destruction. 514 // Decrease the reference to this object, which may lead to self-destruction.
514 Release(); 515 Release();
515 } 516 }
516 517
517 void AudioRendererHost::OnSend(IPC::Message* message) { 518 void AudioRendererHost::OnSend(IPC::Message* message) {
518 DCHECK(MessageLoop::current() == io_loop_); 519 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
519 if (ipc_sender_) { 520 if (ipc_sender_) {
520 ipc_sender_->Send(message); 521 ipc_sender_->Send(message);
521 } 522 }
522 } 523 }
523 524
524 void AudioRendererHost::OnDestroySource(IPCAudioSource* source) { 525 void AudioRendererHost::OnDestroySource(IPCAudioSource* source) {
525 DCHECK(MessageLoop::current() == io_loop_); 526 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
526 if (source) { 527 if (source) {
527 sources_.erase(SourceID(source->route_id(), source->stream_id())); 528 sources_.erase(SourceID(source->route_id(), source->stream_id()));
528 source->Close(); 529 source->Close();
529 delete source; 530 delete source;
530 } 531 }
531 } 532 }
532 533
533 void AudioRendererHost::DestroyAllSources() { 534 void AudioRendererHost::DestroyAllSources() {
534 DCHECK(MessageLoop::current() == io_loop_); 535 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
535 std::vector<IPCAudioSource*> sources; 536 std::vector<IPCAudioSource*> sources;
536 for (SourceMap::iterator i = sources_.begin(); i != sources_.end(); ++i) { 537 for (SourceMap::iterator i = sources_.begin(); i != sources_.end(); ++i) {
537 sources.push_back(i->second); 538 sources.push_back(i->second);
538 } 539 }
539 for (size_t i = 0; i < sources.size(); ++i) { 540 for (size_t i = 0; i < sources.size(); ++i) {
540 DestroySource(sources[i]); 541 DestroySource(sources[i]);
541 } 542 }
542 DCHECK(sources_.empty()); 543 DCHECK(sources_.empty());
543 } 544 }
544 545
545 AudioRendererHost::IPCAudioSource* AudioRendererHost::Lookup(int route_id, 546 AudioRendererHost::IPCAudioSource* AudioRendererHost::Lookup(int route_id,
546 int stream_id) { 547 int stream_id) {
547 DCHECK(MessageLoop::current() == io_loop_); 548 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
548 SourceMap::iterator i = sources_.find(SourceID(route_id, stream_id)); 549 SourceMap::iterator i = sources_.find(SourceID(route_id, stream_id));
549 if (i != sources_.end()) 550 if (i != sources_.end())
550 return i->second; 551 return i->second;
551 return NULL; 552 return NULL;
552 } 553 }
553 554
554 void AudioRendererHost::Send(IPC::Message* message) { 555 void AudioRendererHost::Send(IPC::Message* message) {
555 if (MessageLoop::current() == io_loop_) { 556 if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
556 OnSend(message); 557 OnSend(message);
557 } else { 558 } else {
558 // TODO(hclam): make sure it's always safe to post a task to IO loop. 559 ChromeThread::PostTask(
559 // It is possible that IO message loop is destroyed but there's still some 560 ChromeThread::IO, FROM_HERE,
560 // dangling audio hardware threads that try to call this method.
561 io_loop_->PostTask(FROM_HERE,
562 NewRunnableMethod(this, &AudioRendererHost::OnSend, message)); 561 NewRunnableMethod(this, &AudioRendererHost::OnSend, message));
563 } 562 }
564 } 563 }
565 564
566 void AudioRendererHost::SendErrorMessage(int32 render_view_id, 565 void AudioRendererHost::SendErrorMessage(int32 render_view_id,
567 int32 stream_id) { 566 int32 stream_id) {
568 ViewMsg_AudioStreamState state; 567 ViewMsg_AudioStreamState state;
569 state.state = ViewMsg_AudioStreamState::kError; 568 state.state = ViewMsg_AudioStreamState::kError;
570 Send(new ViewMsg_NotifyAudioStreamStateChanged( 569 Send(new ViewMsg_NotifyAudioStreamStateChanged(
571 render_view_id, stream_id, state)); 570 render_view_id, stream_id, state));
572 } 571 }
573 572
574 void AudioRendererHost::DestroySource(IPCAudioSource* source) { 573 void AudioRendererHost::DestroySource(IPCAudioSource* source) {
575 if (MessageLoop::current() == io_loop_) { 574 if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
576 OnDestroySource(source); 575 OnDestroySource(source);
577 } else { 576 } else {
578 // TODO(hclam): make sure it's always safe to post a task to IO loop. 577 ChromeThread::PostTask(
579 // It is possible that IO message loop is destroyed but there's still some 578 ChromeThread::IO, FROM_HERE,
580 // dangling audio hardware threads that try to call this method. 579 NewRunnableMethod(this, &AudioRendererHost::OnDestroySource, source));
581 io_loop_->PostTask(FROM_HERE,
582 NewRunnableMethod(this, &AudioRendererHost::OnDestroySource, source));
583 } 580 }
584 } 581 }
OLDNEW
« no previous file with comments | « chrome/browser/renderer_host/audio_renderer_host.h ('k') | chrome/browser/renderer_host/audio_renderer_host_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698