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