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