Home | History | Annotate | Download | only in pepper
      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
      3 // found in the LICENSE file.
      4 
      5 #include "content/renderer/pepper/pepper_platform_audio_output.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/logging.h"
      9 #include "base/message_loop/message_loop_proxy.h"
     10 #include "build/build_config.h"
     11 #include "content/child/child_process.h"
     12 #include "content/common/media/audio_messages.h"
     13 #include "content/renderer/media/audio_message_filter.h"
     14 #include "content/renderer/pepper/audio_helper.h"
     15 #include "content/renderer/render_thread_impl.h"
     16 #include "media/base/audio_hardware_config.h"
     17 #include "ppapi/shared_impl/ppb_audio_config_shared.h"
     18 
     19 namespace content {
     20 
     21 // static
     22 PepperPlatformAudioOutput* PepperPlatformAudioOutput::Create(
     23     int sample_rate,
     24     int frames_per_buffer,
     25     int source_render_view_id,
     26     int source_render_frame_id,
     27     AudioHelper* client) {
     28   scoped_refptr<PepperPlatformAudioOutput> audio_output(
     29       new PepperPlatformAudioOutput());
     30   if (audio_output->Initialize(sample_rate,
     31                                frames_per_buffer,
     32                                source_render_view_id,
     33                                source_render_frame_id,
     34                                client)) {
     35     // Balanced by Release invoked in
     36     // PepperPlatformAudioOutput::ShutDownOnIOThread().
     37     audio_output->AddRef();
     38     return audio_output.get();
     39   }
     40   return NULL;
     41 }
     42 
     43 bool PepperPlatformAudioOutput::StartPlayback() {
     44   if (ipc_) {
     45     io_message_loop_proxy_->PostTask(
     46         FROM_HERE,
     47         base::Bind(&PepperPlatformAudioOutput::StartPlaybackOnIOThread, this));
     48     return true;
     49   }
     50   return false;
     51 }
     52 
     53 bool PepperPlatformAudioOutput::StopPlayback() {
     54   if (ipc_) {
     55     io_message_loop_proxy_->PostTask(
     56         FROM_HERE,
     57         base::Bind(&PepperPlatformAudioOutput::StopPlaybackOnIOThread, this));
     58     return true;
     59   }
     60   return false;
     61 }
     62 
     63 void PepperPlatformAudioOutput::ShutDown() {
     64   // Called on the main thread to stop all audio callbacks. We must only change
     65   // the client on the main thread, and the delegates from the I/O thread.
     66   client_ = NULL;
     67   io_message_loop_proxy_->PostTask(
     68       FROM_HERE,
     69       base::Bind(&PepperPlatformAudioOutput::ShutDownOnIOThread, this));
     70 }
     71 
     72 void PepperPlatformAudioOutput::OnStateChanged(
     73     media::AudioOutputIPCDelegate::State state) {}
     74 
     75 void PepperPlatformAudioOutput::OnStreamCreated(
     76     base::SharedMemoryHandle handle,
     77     base::SyncSocket::Handle socket_handle,
     78     int length) {
     79 #if defined(OS_WIN)
     80   DCHECK(handle);
     81   DCHECK(socket_handle);
     82 #else
     83   DCHECK_NE(-1, handle.fd);
     84   DCHECK_NE(-1, socket_handle);
     85 #endif
     86   DCHECK(length);
     87 
     88   if (base::MessageLoopProxy::current().get() ==
     89       main_message_loop_proxy_.get()) {
     90     // Must dereference the client only on the main thread. Shutdown may have
     91     // occurred while the request was in-flight, so we need to NULL check.
     92     if (client_)
     93       client_->StreamCreated(handle, length, socket_handle);
     94   } else {
     95     main_message_loop_proxy_->PostTask(
     96         FROM_HERE,
     97         base::Bind(&PepperPlatformAudioOutput::OnStreamCreated,
     98                    this,
     99                    handle,
    100                    socket_handle,
    101                    length));
    102   }
    103 }
    104 
    105 void PepperPlatformAudioOutput::OnIPCClosed() { ipc_.reset(); }
    106 
    107 PepperPlatformAudioOutput::~PepperPlatformAudioOutput() {
    108   // Make sure we have been shut down. Warning: this will usually happen on
    109   // the I/O thread!
    110   DCHECK(!ipc_);
    111   DCHECK(!client_);
    112 }
    113 
    114 PepperPlatformAudioOutput::PepperPlatformAudioOutput()
    115     : client_(NULL),
    116       main_message_loop_proxy_(base::MessageLoopProxy::current()),
    117       io_message_loop_proxy_(ChildProcess::current()->io_message_loop_proxy()) {
    118 }
    119 
    120 bool PepperPlatformAudioOutput::Initialize(int sample_rate,
    121                                            int frames_per_buffer,
    122                                            int source_render_view_id,
    123                                            int source_render_frame_id,
    124                                            AudioHelper* client) {
    125   DCHECK(client);
    126   client_ = client;
    127 
    128   RenderThreadImpl* const render_thread = RenderThreadImpl::current();
    129   ipc_ = render_thread->audio_message_filter()->CreateAudioOutputIPC(
    130       source_render_view_id, source_render_frame_id);
    131   CHECK(ipc_);
    132 
    133   media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
    134                                 media::CHANNEL_LAYOUT_STEREO,
    135                                 sample_rate,
    136                                 ppapi::kBitsPerAudioOutputSample,
    137                                 frames_per_buffer);
    138 
    139   io_message_loop_proxy_->PostTask(
    140       FROM_HERE,
    141       base::Bind(
    142           &PepperPlatformAudioOutput::InitializeOnIOThread, this, params));
    143   return true;
    144 }
    145 
    146 void PepperPlatformAudioOutput::InitializeOnIOThread(
    147     const media::AudioParameters& params) {
    148   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
    149   const int kSessionId = 0;
    150   if (ipc_)
    151     ipc_->CreateStream(this, params, kSessionId);
    152 }
    153 
    154 void PepperPlatformAudioOutput::StartPlaybackOnIOThread() {
    155   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
    156   if (ipc_)
    157     ipc_->PlayStream();
    158 }
    159 
    160 void PepperPlatformAudioOutput::StopPlaybackOnIOThread() {
    161   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
    162   if (ipc_)
    163     ipc_->PauseStream();
    164 }
    165 
    166 void PepperPlatformAudioOutput::ShutDownOnIOThread() {
    167   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
    168 
    169   // Make sure we don't call shutdown more than once.
    170   if (!ipc_)
    171     return;
    172 
    173   ipc_->CloseStream();
    174   ipc_.reset();
    175 
    176   Release();  // Release for the delegate, balances out the reference taken in
    177               // PepperPlatformAudioOutput::Create.
    178 }
    179 
    180 }  // namespace content
    181