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/debug/trace_event.h"
      8 #include "base/logging.h"
      9 #include "ppapi/nacl_irt/public/irt_ppapi.h"
     10 #include "ppapi/shared_impl/ppapi_globals.h"
     11 #include "ppapi/shared_impl/ppb_audio_config_shared.h"
     12 #include "ppapi/shared_impl/proxy_lock.h"
     13 
     14 namespace ppapi {
     15 
     16 namespace {
     17 bool g_nacl_mode = false;
     18 // Because this is static, the function pointers will be NULL initially.
     19 PP_ThreadFunctions g_thread_functions;
     20 }
     21 
     22 AudioCallbackCombined::AudioCallbackCombined()
     23     : callback_1_0_(NULL), callback_(NULL) {}
     24 
     25 AudioCallbackCombined::AudioCallbackCombined(
     26     PPB_Audio_Callback_1_0 callback_1_0)
     27     : callback_1_0_(callback_1_0), callback_(NULL) {}
     28 
     29 AudioCallbackCombined::AudioCallbackCombined(PPB_Audio_Callback callback)
     30     : callback_1_0_(NULL), callback_(callback) {}
     31 
     32 AudioCallbackCombined::~AudioCallbackCombined() {}
     33 
     34 bool AudioCallbackCombined::IsValid() const {
     35   return callback_1_0_ || callback_;
     36 }
     37 
     38 void AudioCallbackCombined::Run(void* sample_buffer,
     39                                 uint32_t buffer_size_in_bytes,
     40                                 PP_TimeDelta latency,
     41                                 void* user_data) const {
     42   if (callback_) {
     43     callback_(sample_buffer, buffer_size_in_bytes, latency, user_data);
     44   } else if (callback_1_0_) {
     45     callback_1_0_(sample_buffer, buffer_size_in_bytes, user_data);
     46   } else {
     47     NOTREACHED();
     48   }
     49 }
     50 
     51 PPB_Audio_Shared::PPB_Audio_Shared()
     52     : playing_(false),
     53       shared_memory_size_(0),
     54       nacl_thread_active_(false),
     55       user_data_(NULL),
     56       client_buffer_size_bytes_(0),
     57       bytes_per_second_(0),
     58       buffer_index_(0) {
     59 }
     60 
     61 PPB_Audio_Shared::~PPB_Audio_Shared() {
     62   // Shut down the socket to escape any hanging |Receive|s.
     63   if (socket_.get())
     64     socket_->Shutdown();
     65   StopThread();
     66 }
     67 
     68 void PPB_Audio_Shared::SetCallback(const AudioCallbackCombined& callback,
     69                                    void* user_data) {
     70   callback_ = callback;
     71   user_data_ = user_data;
     72 }
     73 
     74 void PPB_Audio_Shared::SetStartPlaybackState() {
     75   DCHECK(!playing_);
     76   DCHECK(!audio_thread_.get());
     77   DCHECK(!nacl_thread_active_);
     78   // If the socket doesn't exist, that means that the plugin has started before
     79   // the browser has had a chance to create all the shared memory info and
     80   // notify us. This is a common case. In this case, we just set the playing_
     81   // flag and the playback will automatically start when that data is available
     82   // in SetStreamInfo.
     83   playing_ = true;
     84   StartThread();
     85 }
     86 
     87 void PPB_Audio_Shared::SetStopPlaybackState() {
     88   DCHECK(playing_);
     89   StopThread();
     90   playing_ = false;
     91 }
     92 
     93 void PPB_Audio_Shared::SetStreamInfo(
     94     PP_Instance instance,
     95     base::SharedMemoryHandle shared_memory_handle,
     96     size_t shared_memory_size,
     97     base::SyncSocket::Handle socket_handle,
     98     PP_AudioSampleRate sample_rate,
     99     int sample_frame_count) {
    100   socket_.reset(new base::CancelableSyncSocket(socket_handle));
    101   shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false));
    102   shared_memory_size_ = shared_memory_size;
    103   bytes_per_second_ =
    104       kAudioOutputChannels * (kBitsPerAudioOutputSample / 8) * sample_rate;
    105   buffer_index_ = 0;
    106 
    107   if (!shared_memory_->Map(shared_memory_size_)) {
    108     PpapiGlobals::Get()->LogWithSource(
    109         instance,
    110         PP_LOGLEVEL_WARNING,
    111         std::string(),
    112         "Failed to map shared memory for PPB_Audio_Shared.");
    113   } else {
    114     audio_bus_ = media::AudioBus::WrapMemory(
    115         kAudioOutputChannels, sample_frame_count, shared_memory_->memory());
    116     // Setup integer audio buffer for user audio data.
    117     client_buffer_size_bytes_ = audio_bus_->frames() * audio_bus_->channels() *
    118                                 kBitsPerAudioOutputSample / 8;
    119     client_buffer_.reset(new uint8_t[client_buffer_size_bytes_]);
    120   }
    121 
    122   StartThread();
    123 }
    124 
    125 void PPB_Audio_Shared::StartThread() {
    126   // Don't start the thread unless all our state is set up correctly.
    127   if (!playing_ || !callback_.IsValid() || !socket_.get() ||
    128       !shared_memory_->memory() || !audio_bus_.get() || !client_buffer_.get() ||
    129       bytes_per_second_ == 0)
    130     return;
    131   // Clear contents of shm buffer before starting audio thread. This will
    132   // prevent a burst of static if for some reason the audio thread doesn't
    133   // start up quickly enough.
    134   memset(shared_memory_->memory(), 0, shared_memory_size_);
    135   memset(client_buffer_.get(), 0, client_buffer_size_bytes_);
    136 
    137   if (g_nacl_mode) {
    138     // Use NaCl's special API for IRT code that creates threads that call back
    139     // into user code.
    140     if (!IsThreadFunctionReady())
    141       return;
    142 
    143     DCHECK(!nacl_thread_active_);
    144     int result =
    145         g_thread_functions.thread_create(&nacl_thread_id_, CallRun, this);
    146     DCHECK_EQ(0, result);
    147     nacl_thread_active_ = true;
    148   } else {
    149     DCHECK(!audio_thread_.get());
    150     audio_thread_.reset(
    151         new base::DelegateSimpleThread(this, "plugin_audio_thread"));
    152     audio_thread_->Start();
    153   }
    154 }
    155 
    156 void PPB_Audio_Shared::StopThread() {
    157   // In general, the audio thread should not do Pepper calls, but it might
    158   // anyway (for example, our Audio test does CallOnMainThread). If it did a
    159   // pepper call which acquires the lock (most of them do), and we try to shut
    160   // down the thread and Join it while holding the lock, we would deadlock. So
    161   // we give up the lock here so that the thread at least _can_ make Pepper
    162   // calls without causing deadlock.
    163   if (g_nacl_mode) {
    164     if (nacl_thread_active_) {
    165       int result =
    166           CallWhileUnlocked(g_thread_functions.thread_join, nacl_thread_id_);
    167       DCHECK_EQ(0, result);
    168       nacl_thread_active_ = false;
    169     }
    170   } else {
    171     if (audio_thread_.get()) {
    172       CallWhileUnlocked(base::Bind(&base::DelegateSimpleThread::Join,
    173                                    base::Unretained(audio_thread_.get())));
    174       audio_thread_.reset();
    175     }
    176   }
    177 }
    178 
    179 // static
    180 bool PPB_Audio_Shared::IsThreadFunctionReady() {
    181   if (!g_nacl_mode)
    182     return true;
    183 
    184   return (g_thread_functions.thread_create != NULL &&
    185           g_thread_functions.thread_join != NULL);
    186 }
    187 
    188 // static
    189 void PPB_Audio_Shared::SetNaClMode() {
    190   g_nacl_mode = true;
    191 }
    192 
    193 // static
    194 void PPB_Audio_Shared::SetThreadFunctions(
    195     const struct PP_ThreadFunctions* functions) {
    196   DCHECK(g_nacl_mode);
    197   g_thread_functions = *functions;
    198 }
    199 
    200 // static
    201 void PPB_Audio_Shared::CallRun(void* self) {
    202   PPB_Audio_Shared* audio = static_cast<PPB_Audio_Shared*>(self);
    203   audio->Run();
    204 }
    205 
    206 void PPB_Audio_Shared::Run() {
    207   int pending_data = 0;
    208   while (sizeof(pending_data) ==
    209          socket_->Receive(&pending_data, sizeof(pending_data))) {
    210     // |buffer_index_| must track the number of Receive() calls.  See the Send()
    211     // call below for why this is important.
    212     ++buffer_index_;
    213     if (pending_data < 0)
    214       break;
    215 
    216     {
    217       TRACE_EVENT0("audio", "PPB_Audio_Shared::FireRenderCallback");
    218       PP_TimeDelta latency =
    219           static_cast<double>(pending_data) / bytes_per_second_;
    220       callback_.Run(
    221           client_buffer_.get(), client_buffer_size_bytes_, latency, user_data_);
    222     }
    223 
    224     // Deinterleave the audio data into the shared memory as floats.
    225     audio_bus_->FromInterleaved(client_buffer_.get(),
    226                                 audio_bus_->frames(),
    227                                 kBitsPerAudioOutputSample / 8);
    228 
    229     // Let the other end know which buffer we just filled.  The buffer index is
    230     // used to ensure the other end is getting the buffer it expects.  For more
    231     // details on how this works see AudioSyncReader::WaitUntilDataIsReady().
    232     size_t bytes_sent = socket_->Send(&buffer_index_, sizeof(buffer_index_));
    233     if (bytes_sent != sizeof(buffer_index_))
    234       break;
    235   }
    236 }
    237 
    238 }  // namespace ppapi
    239