Home | History | Annotate | Download | only in shared_impl
      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 "ppapi/shared_impl/ppb_audio_shared.h"
      6 
      7 #include "base/logging.h"
      8 #include "media/audio/shared_memory_util.h"
      9 #include "ppapi/shared_impl/ppapi_globals.h"
     10 #include "ppapi/shared_impl/proxy_lock.h"
     11 
     12 // Hard coded values from PepperPlatformAudioOutputImpl.
     13 // TODO(dalecurtis): PPAPI shouldn't hard code these values for all clients.
     14 enum { kChannels = 2, kBytesPerSample = 2 };
     15 
     16 namespace ppapi {
     17 
     18 #if defined(OS_NACL)
     19 namespace {
     20 // Because this is static, the function pointers will be NULL initially.
     21 PP_ThreadFunctions thread_functions;
     22 }
     23 #endif  // defined(OS_NACL)
     24 
     25 PPB_Audio_Shared::PPB_Audio_Shared()
     26     : playing_(false),
     27       shared_memory_size_(0),
     28 #if defined(OS_NACL)
     29       thread_id_(0),
     30       thread_active_(false),
     31 #endif
     32       callback_(NULL),
     33       user_data_(NULL),
     34       client_buffer_size_bytes_(0) {
     35 }
     36 
     37 PPB_Audio_Shared::~PPB_Audio_Shared() {
     38   // Shut down the socket to escape any hanging |Receive|s.
     39   if (socket_.get())
     40     socket_->Shutdown();
     41   StopThread();
     42 }
     43 
     44 void PPB_Audio_Shared::SetCallback(PPB_Audio_Callback callback,
     45                                    void* user_data) {
     46   callback_ = callback;
     47   user_data_ = user_data;
     48 }
     49 
     50 void PPB_Audio_Shared::SetStartPlaybackState() {
     51   DCHECK(!playing_);
     52 #if !defined(OS_NACL)
     53   DCHECK(!audio_thread_.get());
     54 #else
     55   DCHECK(!thread_active_);
     56 #endif
     57   // If the socket doesn't exist, that means that the plugin has started before
     58   // the browser has had a chance to create all the shared memory info and
     59   // notify us. This is a common case. In this case, we just set the playing_
     60   // flag and the playback will automatically start when that data is available
     61   // in SetStreamInfo.
     62   playing_ = true;
     63   StartThread();
     64 }
     65 
     66 void PPB_Audio_Shared::SetStopPlaybackState() {
     67   DCHECK(playing_);
     68   StopThread();
     69   playing_ = false;
     70 }
     71 
     72 void PPB_Audio_Shared::SetStreamInfo(
     73     PP_Instance instance,
     74     base::SharedMemoryHandle shared_memory_handle,
     75     size_t shared_memory_size,
     76     base::SyncSocket::Handle socket_handle,
     77     int sample_frame_count) {
     78   socket_.reset(new base::CancelableSyncSocket(socket_handle));
     79   shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false));
     80   shared_memory_size_ = shared_memory_size;
     81 
     82   if (!shared_memory_->Map(
     83           media::TotalSharedMemorySizeInBytes(shared_memory_size_))) {
     84     PpapiGlobals::Get()->LogWithSource(
     85         instance,
     86         PP_LOGLEVEL_WARNING,
     87         std::string(),
     88         "Failed to map shared memory for PPB_Audio_Shared.");
     89   } else {
     90     audio_bus_ = media::AudioBus::WrapMemory(
     91         kChannels, sample_frame_count, shared_memory_->memory());
     92     // Setup integer audio buffer for user audio data.
     93     client_buffer_size_bytes_ =
     94         audio_bus_->frames() * audio_bus_->channels() * kBytesPerSample;
     95     client_buffer_.reset(new uint8_t[client_buffer_size_bytes_]);
     96   }
     97 
     98   StartThread();
     99 }
    100 
    101 void PPB_Audio_Shared::StartThread() {
    102   // Don't start the thread unless all our state is set up correctly.
    103   if (!playing_ || !callback_ || !socket_.get() || !shared_memory_->memory() ||
    104       !audio_bus_.get() || !client_buffer_.get())
    105     return;
    106   // Clear contents of shm buffer before starting audio thread. This will
    107   // prevent a burst of static if for some reason the audio thread doesn't
    108   // start up quickly enough.
    109   memset(shared_memory_->memory(), 0, shared_memory_size_);
    110   memset(client_buffer_.get(), 0, client_buffer_size_bytes_);
    111 #if !defined(OS_NACL)
    112   DCHECK(!audio_thread_.get());
    113   audio_thread_.reset(new base::DelegateSimpleThread(
    114       this, "plugin_audio_thread"));
    115   audio_thread_->Start();
    116 #else
    117   // Use NaCl's special API for IRT code that creates threads that call back
    118   // into user code.
    119   if (NULL == thread_functions.thread_create ||
    120       NULL == thread_functions.thread_join)
    121     return;
    122 
    123   int result = thread_functions.thread_create(&thread_id_, CallRun, this);
    124   DCHECK_EQ(result, 0);
    125   thread_active_ = true;
    126 #endif
    127 }
    128 
    129 void PPB_Audio_Shared::StopThread() {
    130 #if !defined(OS_NACL)
    131   if (audio_thread_.get()) {
    132     // In general, the audio thread should not do Pepper calls, but it might
    133     // anyway (for example, our Audio test does CallOnMainThread). If it did
    134     // a pepper call which acquires the lock (most of them do), and we try to
    135     // shut down the thread and Join it while holding the lock, we would
    136     // deadlock. So we give up the lock here so that the thread at least _can_
    137     // make Pepper calls without causing deadlock.
    138     CallWhileUnlocked(base::Bind(&base::DelegateSimpleThread::Join,
    139                                  base::Unretained(audio_thread_.get())));
    140     audio_thread_.reset();
    141   }
    142 #else
    143   if (thread_active_) {
    144     // See comment above about why we unlock here.
    145     int result = CallWhileUnlocked(thread_functions.thread_join, thread_id_);
    146     DCHECK_EQ(0, result);
    147     thread_active_ = false;
    148   }
    149 #endif
    150 }
    151 
    152 #if defined(OS_NACL)
    153 // static
    154 void PPB_Audio_Shared::SetThreadFunctions(
    155     const struct PP_ThreadFunctions* functions) {
    156   DCHECK(thread_functions.thread_create == NULL);
    157   DCHECK(thread_functions.thread_join == NULL);
    158   thread_functions = *functions;
    159 }
    160 
    161 // static
    162 void PPB_Audio_Shared::CallRun(void* self) {
    163   PPB_Audio_Shared* audio = static_cast<PPB_Audio_Shared*>(self);
    164   audio->Run();
    165 }
    166 #endif
    167 
    168 void PPB_Audio_Shared::Run() {
    169   int pending_data;
    170   const int bytes_per_frame =
    171       sizeof(*audio_bus_->channel(0)) * audio_bus_->channels();
    172 
    173   while (sizeof(pending_data) ==
    174       socket_->Receive(&pending_data, sizeof(pending_data)) &&
    175       pending_data != media::kPauseMark) {
    176     callback_(client_buffer_.get(), client_buffer_size_bytes_, user_data_);
    177 
    178     // Deinterleave the audio data into the shared memory as float.
    179     audio_bus_->FromInterleaved(
    180         client_buffer_.get(), audio_bus_->frames(), kBytesPerSample);
    181 
    182     // Let the host know we are done.
    183     // TODO(dalecurtis): Technically this is not the exact size.  Due to channel
    184     // padding for alignment, there may be more data available than this.  We're
    185     // relying on AudioSyncReader::Read() to parse this with that in mind.
    186     // Rename these methods to Set/GetActualFrameCount().
    187     media::SetActualDataSizeInBytes(
    188         shared_memory_.get(), shared_memory_size_,
    189         audio_bus_->frames() * bytes_per_frame);
    190   }
    191 }
    192 
    193 }  // namespace ppapi
    194