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
14namespace ppapi {
15
16namespace {
17bool g_nacl_mode = false;
18// Because this is static, the function pointers will be NULL initially.
19PP_ThreadFunctions g_thread_functions;
20}
21
22AudioCallbackCombined::AudioCallbackCombined()
23    : callback_1_0_(NULL), callback_(NULL) {}
24
25AudioCallbackCombined::AudioCallbackCombined(
26    PPB_Audio_Callback_1_0 callback_1_0)
27    : callback_1_0_(callback_1_0), callback_(NULL) {}
28
29AudioCallbackCombined::AudioCallbackCombined(PPB_Audio_Callback callback)
30    : callback_1_0_(NULL), callback_(callback) {}
31
32AudioCallbackCombined::~AudioCallbackCombined() {}
33
34bool AudioCallbackCombined::IsValid() const {
35  return callback_1_0_ || callback_;
36}
37
38void 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
51PPB_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
61PPB_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
68void PPB_Audio_Shared::SetCallback(const AudioCallbackCombined& callback,
69                                   void* user_data) {
70  callback_ = callback;
71  user_data_ = user_data;
72}
73
74void 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
87void PPB_Audio_Shared::SetStopPlaybackState() {
88  DCHECK(playing_);
89  StopThread();
90  playing_ = false;
91}
92
93void 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
125void 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
156void 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
180bool 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
189void PPB_Audio_Shared::SetNaClMode() {
190  g_nacl_mode = true;
191}
192
193// static
194void PPB_Audio_Shared::SetThreadFunctions(
195    const struct PP_ThreadFunctions* functions) {
196  DCHECK(g_nacl_mode);
197  g_thread_functions = *functions;
198}
199
200// static
201void PPB_Audio_Shared::CallRun(void* self) {
202  PPB_Audio_Shared* audio = static_cast<PPB_Audio_Shared*>(self);
203  audio->Run();
204}
205
206void 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