OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ppapi/proxy/audio_input_resource.h" | 5 #include "ppapi/proxy/audio_input_resource.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "ipc/ipc_platform_file.h" | 9 #include "ipc/ipc_platform_file.h" |
10 #include "media/audio/audio_parameters.h" | 10 #include "media/audio/audio_parameters.h" |
| 11 #include "media/base/audio_bus.h" |
11 #include "ppapi/c/pp_errors.h" | 12 #include "ppapi/c/pp_errors.h" |
12 #include "ppapi/proxy/ppapi_messages.h" | 13 #include "ppapi/proxy/ppapi_messages.h" |
13 #include "ppapi/proxy/resource_message_params.h" | 14 #include "ppapi/proxy/resource_message_params.h" |
14 #include "ppapi/proxy/serialized_handle.h" | 15 #include "ppapi/proxy/serialized_handle.h" |
15 #include "ppapi/shared_impl/ppapi_globals.h" | 16 #include "ppapi/shared_impl/ppapi_globals.h" |
16 #include "ppapi/shared_impl/ppb_audio_config_shared.h" | 17 #include "ppapi/shared_impl/ppb_audio_config_shared.h" |
17 #include "ppapi/shared_impl/resource_tracker.h" | 18 #include "ppapi/shared_impl/resource_tracker.h" |
18 #include "ppapi/shared_impl/tracked_callback.h" | 19 #include "ppapi/shared_impl/tracked_callback.h" |
19 #include "ppapi/thunk/enter.h" | 20 #include "ppapi/thunk/enter.h" |
20 #include "ppapi/thunk/ppb_audio_config_api.h" | 21 #include "ppapi/thunk/ppb_audio_config_api.h" |
21 | 22 |
22 namespace ppapi { | 23 namespace ppapi { |
23 namespace proxy { | 24 namespace proxy { |
24 | 25 |
25 AudioInputResource::AudioInputResource( | 26 AudioInputResource::AudioInputResource(Connection connection, |
26 Connection connection, | 27 PP_Instance instance) |
27 PP_Instance instance) | |
28 : PluginResource(connection, instance), | 28 : PluginResource(connection, instance), |
29 open_state_(BEFORE_OPEN), | 29 open_state_(BEFORE_OPEN), |
30 capturing_(false), | 30 capturing_(false), |
31 shared_memory_size_(0), | 31 shared_memory_size_(0), |
32 audio_input_callback_0_3_(NULL), | 32 audio_input_callback_0_3_(NULL), |
33 audio_input_callback_(NULL), | 33 audio_input_callback_(NULL), |
34 user_data_(NULL), | 34 user_data_(NULL), |
35 enumeration_helper_(this), | 35 enumeration_helper_(this), |
36 bytes_per_second_(0) { | 36 bytes_per_second_(0), |
| 37 sample_frame_count_(0), |
| 38 client_buffer_size_bytes_(0) { |
37 SendCreate(RENDERER, PpapiHostMsg_AudioInput_Create()); | 39 SendCreate(RENDERER, PpapiHostMsg_AudioInput_Create()); |
38 } | 40 } |
39 | 41 |
40 AudioInputResource::~AudioInputResource() { | 42 AudioInputResource::~AudioInputResource() { |
41 Close(); | 43 Close(); |
42 } | 44 } |
43 | 45 |
44 thunk::PPB_AudioInput_API* AudioInputResource::AsPPB_AudioInput_API() { | 46 thunk::PPB_AudioInput_API* AudioInputResource::AsPPB_AudioInput_API() { |
45 return this; | 47 return this; |
46 } | 48 } |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 open_callback_->Run(params.result()); | 176 open_callback_->Run(params.result()); |
175 } | 177 } |
176 | 178 |
177 void AudioInputResource::SetStreamInfo( | 179 void AudioInputResource::SetStreamInfo( |
178 base::SharedMemoryHandle shared_memory_handle, | 180 base::SharedMemoryHandle shared_memory_handle, |
179 size_t shared_memory_size, | 181 size_t shared_memory_size, |
180 base::SyncSocket::Handle socket_handle) { | 182 base::SyncSocket::Handle socket_handle) { |
181 socket_.reset(new base::CancelableSyncSocket(socket_handle)); | 183 socket_.reset(new base::CancelableSyncSocket(socket_handle)); |
182 shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false)); | 184 shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false)); |
183 shared_memory_size_ = shared_memory_size; | 185 shared_memory_size_ = shared_memory_size; |
| 186 DCHECK(!shared_memory_->memory()); |
184 | 187 |
185 if (!shared_memory_->Map(shared_memory_size_)) { | 188 // If we fail to map the shared memory into the caller's address space we |
186 PpapiGlobals::Get()->LogWithSource( | 189 // might as well fail here since nothing will work if this is the case. |
187 pp_instance(), | 190 CHECK(shared_memory_->Map(shared_memory_size_)); |
188 PP_LOGLEVEL_WARNING, | 191 |
189 std::string(), | 192 // Create a new audio bus and wrap the audio data section in shared memory. |
190 "Failed to map shared memory for PPB_AudioInput_Shared."); | 193 media::AudioInputBuffer* buffer = |
191 } | 194 static_cast<media::AudioInputBuffer*>(shared_memory_->memory()); |
| 195 audio_bus_ = media::AudioBus::WrapMemory( |
| 196 kAudioInputChannels, sample_frame_count_, buffer->audio); |
| 197 |
| 198 // Ensure that the size of the created audio bus matches the allocated |
| 199 // size in shared memory. |
| 200 // Example: DCHECK_EQ(8208 - 16, 8192) for |sample_frame_count_| = 2048. |
| 201 const uint32_t audio_bus_size_bytes = media::AudioBus::CalculateMemorySize( |
| 202 audio_bus_->channels(), audio_bus_->frames()); |
| 203 DCHECK_EQ(shared_memory_size_ - sizeof(media::AudioInputBufferParameters), |
| 204 audio_bus_size_bytes); |
| 205 |
| 206 // Create an extra integer audio buffer for user audio data callbacks. |
| 207 // Data in shared memory will be copied to this buffer, after interleaving |
| 208 // and truncation, before each input callback to match the format expected |
| 209 // by the client. |
| 210 client_buffer_size_bytes_ = audio_bus_->frames() * audio_bus_->channels() * |
| 211 kBitsPerAudioInputSample / 8; |
| 212 client_buffer_.reset(new uint8_t[client_buffer_size_bytes_]); |
192 | 213 |
193 // There is a pending capture request before SetStreamInfo(). | 214 // There is a pending capture request before SetStreamInfo(). |
194 if (capturing_) { | 215 if (capturing_) { |
195 // Set |capturing_| to false so that the state looks consistent to | 216 // Set |capturing_| to false so that the state looks consistent to |
196 // StartCapture(), which will reset it to true. | 217 // StartCapture(), which will reset it to true. |
197 capturing_ = false; | 218 capturing_ = false; |
198 StartCapture(); | 219 StartCapture(); |
199 } | 220 } |
200 } | 221 } |
201 | 222 |
202 void AudioInputResource::StartThread() { | 223 void AudioInputResource::StartThread() { |
203 // Don't start the thread unless all our state is set up correctly. | 224 // Don't start the thread unless all our state is set up correctly. |
204 if ((!audio_input_callback_0_3_ && !audio_input_callback_) || | 225 if ((!audio_input_callback_0_3_ && !audio_input_callback_) || |
205 !socket_.get() || !capturing_ || !shared_memory_->memory()) { | 226 !socket_.get() || !capturing_ || !shared_memory_->memory() || |
| 227 !audio_bus_.get() || !client_buffer_.get()) { |
206 return; | 228 return; |
207 } | 229 } |
208 DCHECK(!audio_input_thread_.get()); | 230 DCHECK(!audio_input_thread_.get()); |
209 audio_input_thread_.reset(new base::DelegateSimpleThread( | 231 audio_input_thread_.reset(new base::DelegateSimpleThread( |
210 this, "plugin_audio_input_thread")); | 232 this, "plugin_audio_input_thread")); |
211 audio_input_thread_->Start(); | 233 audio_input_thread_->Start(); |
212 } | 234 } |
213 | 235 |
214 void AudioInputResource::StopThread() { | 236 void AudioInputResource::StopThread() { |
215 // Shut down the socket to escape any hanging |Receive|s. | 237 // Shut down the socket to escape any hanging |Receive|s. |
216 if (socket_.get()) | 238 if (socket_.get()) |
217 socket_->Shutdown(); | 239 socket_->Shutdown(); |
218 if (audio_input_thread_.get()) { | 240 if (audio_input_thread_.get()) { |
219 audio_input_thread_->Join(); | 241 audio_input_thread_->Join(); |
220 audio_input_thread_.reset(); | 242 audio_input_thread_.reset(); |
221 } | 243 } |
222 } | 244 } |
223 | 245 |
224 void AudioInputResource::Run() { | 246 void AudioInputResource::Run() { |
225 // The shared memory represents AudioInputBufferParameters and the actual data | 247 // The shared memory represents AudioInputBufferParameters and the actual data |
226 // buffer. | 248 // buffer stored as an audio bus. |
227 media::AudioInputBuffer* buffer = | 249 media::AudioInputBuffer* buffer = |
228 static_cast<media::AudioInputBuffer*>(shared_memory_->memory()); | 250 static_cast<media::AudioInputBuffer*>(shared_memory_->memory()); |
229 uint32_t data_buffer_size = | 251 const uint32_t audio_bus_size_bytes = |
230 shared_memory_size_ - sizeof(media::AudioInputBufferParameters); | 252 shared_memory_size_ - sizeof(media::AudioInputBufferParameters); |
231 int pending_data; | |
232 | 253 |
233 while (sizeof(pending_data) == socket_->Receive(&pending_data, | 254 while (true) { |
234 sizeof(pending_data)) && | 255 int pending_data = 0; |
235 pending_data >= 0) { | 256 size_t bytes_read = socket_->Receive(&pending_data, sizeof(pending_data)); |
| 257 if (bytes_read != sizeof(pending_data)) { |
| 258 DCHECK_EQ(bytes_read, 0U); |
| 259 break; |
| 260 } |
| 261 if (pending_data < 0) |
| 262 break; |
| 263 |
| 264 // Convert an AudioBus from deinterleaved float to interleaved integer data. |
| 265 // Store the result in a preallocated |client_buffer_|. |
| 266 audio_bus_->ToInterleaved(audio_bus_->frames(), |
| 267 kBitsPerAudioInputSample / 8, |
| 268 client_buffer_.get()); |
| 269 |
236 // While closing the stream, we may receive buffers whose size is different | 270 // While closing the stream, we may receive buffers whose size is different |
237 // from |data_buffer_size|. | 271 // from |data_buffer_size|. |
238 CHECK_LE(buffer->params.size, data_buffer_size); | 272 CHECK_LE(buffer->params.size, audio_bus_size_bytes); |
239 if (buffer->params.size > 0) { | 273 if (buffer->params.size > 0) { |
240 if (audio_input_callback_) { | 274 if (audio_input_callback_) { |
241 PP_TimeDelta latency = | 275 PP_TimeDelta latency = |
242 static_cast<double>(pending_data) / bytes_per_second_; | 276 static_cast<double>(pending_data) / bytes_per_second_; |
243 audio_input_callback_(&buffer->audio[0], buffer->params.size, latency, | 277 audio_input_callback_(client_buffer_.get(), |
| 278 client_buffer_size_bytes_, |
| 279 latency, |
244 user_data_); | 280 user_data_); |
245 } else { | 281 } else { |
246 audio_input_callback_0_3_(&buffer->audio[0], buffer->params.size, | 282 audio_input_callback_0_3_( |
247 user_data_); | 283 client_buffer_.get(), client_buffer_size_bytes_, user_data_); |
248 } | 284 } |
249 } | 285 } |
250 } | 286 } |
251 } | 287 } |
252 | 288 |
253 int32_t AudioInputResource::CommonOpen( | 289 int32_t AudioInputResource::CommonOpen( |
254 PP_Resource device_ref, | 290 PP_Resource device_ref, |
255 PP_Resource config, | 291 PP_Resource config, |
256 PPB_AudioInput_Callback_0_3 audio_input_callback_0_3, | 292 PPB_AudioInput_Callback_0_3 audio_input_callback_0_3, |
257 PPB_AudioInput_Callback audio_input_callback, | 293 PPB_AudioInput_Callback audio_input_callback, |
(...skipping 22 matching lines...) Expand all Loading... |
280 if (enter_config.failed()) | 316 if (enter_config.failed()) |
281 return PP_ERROR_BADARGUMENT; | 317 return PP_ERROR_BADARGUMENT; |
282 | 318 |
283 config_ = config; | 319 config_ = config; |
284 audio_input_callback_0_3_ = audio_input_callback_0_3; | 320 audio_input_callback_0_3_ = audio_input_callback_0_3; |
285 audio_input_callback_ = audio_input_callback; | 321 audio_input_callback_ = audio_input_callback; |
286 user_data_ = user_data; | 322 user_data_ = user_data; |
287 open_callback_ = callback; | 323 open_callback_ = callback; |
288 bytes_per_second_ = kAudioInputChannels * (kBitsPerAudioInputSample / 8) * | 324 bytes_per_second_ = kAudioInputChannels * (kBitsPerAudioInputSample / 8) * |
289 enter_config.object()->GetSampleRate(); | 325 enter_config.object()->GetSampleRate(); |
| 326 sample_frame_count_ = enter_config.object()->GetSampleFrameCount(); |
290 | 327 |
291 PpapiHostMsg_AudioInput_Open msg( | 328 PpapiHostMsg_AudioInput_Open msg( |
292 device_id, enter_config.object()->GetSampleRate(), | 329 device_id, enter_config.object()->GetSampleRate(), |
293 enter_config.object()->GetSampleFrameCount()); | 330 enter_config.object()->GetSampleFrameCount()); |
294 Call<PpapiPluginMsg_AudioInput_OpenReply>( | 331 Call<PpapiPluginMsg_AudioInput_OpenReply>( |
295 RENDERER, msg, | 332 RENDERER, msg, |
296 base::Bind(&AudioInputResource::OnPluginMsgOpenReply, | 333 base::Bind(&AudioInputResource::OnPluginMsgOpenReply, |
297 base::Unretained(this))); | 334 base::Unretained(this))); |
298 return PP_OK_COMPLETIONPENDING; | 335 return PP_OK_COMPLETIONPENDING; |
299 } | 336 } |
300 } // namespace proxy | 337 } // namespace proxy |
301 } // namespace ppapi | 338 } // namespace ppapi |
OLD | NEW |