Use ExtensionRegistry::enabled_extensions instead of deprecated ExtensionService...
[chromium-blink-merge.git] / ppapi / proxy / audio_input_resource.cc
blob0ae1831afa8cf9c66409cde60cce814683696ce5
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/proxy/audio_input_resource.h"
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "ipc/ipc_platform_file.h"
10 #include "media/audio/audio_parameters.h"
11 #include "ppapi/c/pp_errors.h"
12 #include "ppapi/proxy/ppapi_messages.h"
13 #include "ppapi/proxy/resource_message_params.h"
14 #include "ppapi/proxy/serialized_handle.h"
15 #include "ppapi/shared_impl/ppapi_globals.h"
16 #include "ppapi/shared_impl/ppb_audio_config_shared.h"
17 #include "ppapi/shared_impl/resource_tracker.h"
18 #include "ppapi/shared_impl/tracked_callback.h"
19 #include "ppapi/thunk/enter.h"
20 #include "ppapi/thunk/ppb_audio_config_api.h"
22 namespace ppapi {
23 namespace proxy {
25 AudioInputResource::AudioInputResource(
26 Connection connection,
27 PP_Instance instance)
28 : PluginResource(connection, instance),
29 open_state_(BEFORE_OPEN),
30 capturing_(false),
31 shared_memory_size_(0),
32 audio_input_callback_0_3_(NULL),
33 audio_input_callback_(NULL),
34 user_data_(NULL),
35 enumeration_helper_(this),
36 bytes_per_second_(0) {
37 SendCreate(RENDERER, PpapiHostMsg_AudioInput_Create());
40 AudioInputResource::~AudioInputResource() {
41 Close();
44 thunk::PPB_AudioInput_API* AudioInputResource::AsPPB_AudioInput_API() {
45 return this;
48 void AudioInputResource::OnReplyReceived(
49 const ResourceMessageReplyParams& params,
50 const IPC::Message& msg) {
51 if (!enumeration_helper_.HandleReply(params, msg))
52 PluginResource::OnReplyReceived(params, msg);
55 int32_t AudioInputResource::EnumerateDevices(
56 const PP_ArrayOutput& output,
57 scoped_refptr<TrackedCallback> callback) {
58 return enumeration_helper_.EnumerateDevices(output, callback);
61 int32_t AudioInputResource::MonitorDeviceChange(
62 PP_MonitorDeviceChangeCallback callback,
63 void* user_data) {
64 return enumeration_helper_.MonitorDeviceChange(callback, user_data);
67 int32_t AudioInputResource::Open0_3(
68 PP_Resource device_ref,
69 PP_Resource config,
70 PPB_AudioInput_Callback_0_3 audio_input_callback_0_3,
71 void* user_data,
72 scoped_refptr<TrackedCallback> callback) {
73 return CommonOpen(device_ref, config, audio_input_callback_0_3, NULL,
74 user_data, callback);
77 int32_t AudioInputResource::Open(PP_Resource device_ref,
78 PP_Resource config,
79 PPB_AudioInput_Callback audio_input_callback,
80 void* user_data,
81 scoped_refptr<TrackedCallback> callback) {
82 return CommonOpen(device_ref, config, NULL, audio_input_callback, user_data,
83 callback);
86 PP_Resource AudioInputResource::GetCurrentConfig() {
87 // AddRef for the caller.
88 if (config_.get())
89 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(config_);
90 return config_;
93 PP_Bool AudioInputResource::StartCapture() {
94 if (open_state_ == CLOSED || (open_state_ == BEFORE_OPEN &&
95 !TrackedCallback::IsPending(open_callback_))) {
96 return PP_FALSE;
98 if (capturing_)
99 return PP_TRUE;
101 capturing_ = true;
102 // Return directly if the audio input device hasn't been opened. Capturing
103 // will be started once the open operation is completed.
104 if (open_state_ == BEFORE_OPEN)
105 return PP_TRUE;
107 StartThread();
109 Post(RENDERER, PpapiHostMsg_AudioInput_StartOrStop(true));
110 return PP_TRUE;
113 PP_Bool AudioInputResource::StopCapture() {
114 if (open_state_ == CLOSED)
115 return PP_FALSE;
116 if (!capturing_)
117 return PP_TRUE;
119 // If the audio input device hasn't been opened, set |capturing_| to false and
120 // return directly.
121 if (open_state_ == BEFORE_OPEN) {
122 capturing_ = false;
123 return PP_TRUE;
126 Post(RENDERER, PpapiHostMsg_AudioInput_StartOrStop(false));
128 StopThread();
129 capturing_ = false;
131 return PP_TRUE;
134 void AudioInputResource::Close() {
135 if (open_state_ == CLOSED)
136 return;
138 open_state_ = CLOSED;
139 Post(RENDERER, PpapiHostMsg_AudioInput_Close());
140 StopThread();
142 if (TrackedCallback::IsPending(open_callback_))
143 open_callback_->PostAbort();
146 void AudioInputResource::LastPluginRefWasDeleted() {
147 enumeration_helper_.LastPluginRefWasDeleted();
150 void AudioInputResource::OnPluginMsgOpenReply(
151 const ResourceMessageReplyParams& params) {
152 if (open_state_ == BEFORE_OPEN && params.result() == PP_OK) {
153 IPC::PlatformFileForTransit socket_handle_for_transit =
154 IPC::InvalidPlatformFileForTransit();
155 params.TakeSocketHandleAtIndex(0, &socket_handle_for_transit);
156 base::SyncSocket::Handle socket_handle =
157 IPC::PlatformFileForTransitToPlatformFile(socket_handle_for_transit);
158 CHECK(socket_handle != base::SyncSocket::kInvalidHandle);
160 SerializedHandle serialized_shared_memory_handle =
161 params.TakeHandleOfTypeAtIndex(1, SerializedHandle::SHARED_MEMORY);
162 CHECK(serialized_shared_memory_handle.IsHandleValid());
164 open_state_ = OPENED;
165 SetStreamInfo(serialized_shared_memory_handle.shmem(),
166 serialized_shared_memory_handle.size(),
167 socket_handle);
168 } else {
169 capturing_ = false;
172 // The callback may have been aborted by Close().
173 if (TrackedCallback::IsPending(open_callback_))
174 open_callback_->Run(params.result());
177 void AudioInputResource::SetStreamInfo(
178 base::SharedMemoryHandle shared_memory_handle,
179 size_t shared_memory_size,
180 base::SyncSocket::Handle socket_handle) {
181 socket_.reset(new base::CancelableSyncSocket(socket_handle));
182 shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false));
183 shared_memory_size_ = shared_memory_size;
185 if (!shared_memory_->Map(shared_memory_size_)) {
186 PpapiGlobals::Get()->LogWithSource(
187 pp_instance(),
188 PP_LOGLEVEL_WARNING,
189 std::string(),
190 "Failed to map shared memory for PPB_AudioInput_Shared.");
193 // There is a pending capture request before SetStreamInfo().
194 if (capturing_) {
195 // Set |capturing_| to false so that the state looks consistent to
196 // StartCapture(), which will reset it to true.
197 capturing_ = false;
198 StartCapture();
202 void AudioInputResource::StartThread() {
203 // Don't start the thread unless all our state is set up correctly.
204 if ((!audio_input_callback_0_3_ && !audio_input_callback_) ||
205 !socket_.get() || !capturing_ || !shared_memory_->memory()) {
206 return;
208 DCHECK(!audio_input_thread_.get());
209 audio_input_thread_.reset(new base::DelegateSimpleThread(
210 this, "plugin_audio_input_thread"));
211 audio_input_thread_->Start();
214 void AudioInputResource::StopThread() {
215 // Shut down the socket to escape any hanging |Receive|s.
216 if (socket_.get())
217 socket_->Shutdown();
218 if (audio_input_thread_.get()) {
219 audio_input_thread_->Join();
220 audio_input_thread_.reset();
224 void AudioInputResource::Run() {
225 // The shared memory represents AudioInputBufferParameters and the actual data
226 // buffer.
227 media::AudioInputBuffer* buffer =
228 static_cast<media::AudioInputBuffer*>(shared_memory_->memory());
229 uint32_t data_buffer_size =
230 shared_memory_size_ - sizeof(media::AudioInputBufferParameters);
231 int pending_data;
233 while (sizeof(pending_data) == socket_->Receive(&pending_data,
234 sizeof(pending_data)) &&
235 pending_data >= 0) {
236 // While closing the stream, we may receive buffers whose size is different
237 // from |data_buffer_size|.
238 CHECK_LE(buffer->params.size, data_buffer_size);
239 if (buffer->params.size > 0) {
240 if (audio_input_callback_) {
241 PP_TimeDelta latency =
242 static_cast<double>(pending_data) / bytes_per_second_;
243 audio_input_callback_(&buffer->audio[0], buffer->params.size, latency,
244 user_data_);
245 } else {
246 audio_input_callback_0_3_(&buffer->audio[0], buffer->params.size,
247 user_data_);
253 int32_t AudioInputResource::CommonOpen(
254 PP_Resource device_ref,
255 PP_Resource config,
256 PPB_AudioInput_Callback_0_3 audio_input_callback_0_3,
257 PPB_AudioInput_Callback audio_input_callback,
258 void* user_data,
259 scoped_refptr<TrackedCallback> callback) {
260 std::string device_id;
261 // |device_id| remains empty if |device_ref| is 0, which means the default
262 // device.
263 if (device_ref != 0) {
264 thunk::EnterResourceNoLock<thunk::PPB_DeviceRef_API> enter_device_ref(
265 device_ref, true);
266 if (enter_device_ref.failed())
267 return PP_ERROR_BADRESOURCE;
268 device_id = enter_device_ref.object()->GetDeviceRefData().id;
271 if (TrackedCallback::IsPending(open_callback_))
272 return PP_ERROR_INPROGRESS;
273 if (open_state_ != BEFORE_OPEN)
274 return PP_ERROR_FAILED;
276 if (!audio_input_callback_0_3 && !audio_input_callback)
277 return PP_ERROR_BADARGUMENT;
278 thunk::EnterResourceNoLock<thunk::PPB_AudioConfig_API> enter_config(config,
279 true);
280 if (enter_config.failed())
281 return PP_ERROR_BADARGUMENT;
283 config_ = config;
284 audio_input_callback_0_3_ = audio_input_callback_0_3;
285 audio_input_callback_ = audio_input_callback;
286 user_data_ = user_data;
287 open_callback_ = callback;
288 bytes_per_second_ = kAudioInputChannels * (kBitsPerAudioInputSample / 8) *
289 enter_config.object()->GetSampleRate();
291 PpapiHostMsg_AudioInput_Open msg(
292 device_id, enter_config.object()->GetSampleRate(),
293 enter_config.object()->GetSampleFrameCount());
294 Call<PpapiPluginMsg_AudioInput_OpenReply>(
295 RENDERER, msg,
296 base::Bind(&AudioInputResource::OnPluginMsgOpenReply,
297 base::Unretained(this)));
298 return PP_OK_COMPLETIONPENDING;
300 } // namespace proxy
301 } // namespace ppapi