ppb_audio_shared.cc revision 0f1bc08d4cfcc34181b0b5cbf065c40f687bf740
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
12namespace ppapi {
13
14#if defined(OS_NACL)
15namespace {
16// Because this is static, the function pointers will be NULL initially.
17PP_ThreadFunctions thread_functions;
18}
19#endif  // defined(OS_NACL)
20
21AudioCallbackCombined::AudioCallbackCombined() : callback_1_0_(NULL),
22                                                 callback_(NULL) {
23}
24
25AudioCallbackCombined::AudioCallbackCombined(
26    PPB_Audio_Callback_1_0 callback_1_0)
27    : callback_1_0_(callback_1_0),
28      callback_(NULL) {
29}
30
31AudioCallbackCombined::AudioCallbackCombined(PPB_Audio_Callback callback)
32    : callback_1_0_(NULL),
33      callback_(callback) {
34}
35
36AudioCallbackCombined::~AudioCallbackCombined() {
37}
38
39bool AudioCallbackCombined::IsValid() const {
40  return callback_1_0_ || callback_;
41}
42
43void 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
56PPB_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
69PPB_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
76void PPB_Audio_Shared::SetCallback(const AudioCallbackCombined& callback,
77                                   void* user_data) {
78  callback_ = callback;
79  user_data_ = user_data;
80}
81
82void 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
98void PPB_Audio_Shared::SetStopPlaybackState() {
99  DCHECK(playing_);
100  StopThread();
101  playing_ = false;
102}
103
104void 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
137void 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
166void 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
191void 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
199void PPB_Audio_Shared::CallRun(void* self) {
200  PPB_Audio_Shared* audio = static_cast<PPB_Audio_Shared*>(self);
201  audio->Run();
202}
203#endif
204
205void 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