Delay default apps installation on Chrome OS for first time sign-in
[chromium-blink-merge.git] / ppapi / proxy / audio_input_resource.cc
blob7f1f81983e6ae77d4f5acd52ae537ab67204ea01
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 "media/base/audio_bus.h"
12 #include "ppapi/c/pp_errors.h"
13 #include "ppapi/proxy/ppapi_messages.h"
14 #include "ppapi/proxy/resource_message_params.h"
15 #include "ppapi/proxy/serialized_handle.h"
16 #include "ppapi/shared_impl/ppapi_globals.h"
17 #include "ppapi/shared_impl/ppb_audio_config_shared.h"
18 #include "ppapi/shared_impl/resource_tracker.h"
19 #include "ppapi/shared_impl/tracked_callback.h"
20 #include "ppapi/thunk/enter.h"
21 #include "ppapi/thunk/ppb_audio_config_api.h"
23 namespace ppapi {
24 namespace proxy {
26 AudioInputResource::AudioInputResource(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 sample_frame_count_(0),
38 client_buffer_size_bytes_(0) {
39 SendCreate(RENDERER, PpapiHostMsg_AudioInput_Create());
42 AudioInputResource::~AudioInputResource() {
43 Close();
46 thunk::PPB_AudioInput_API* AudioInputResource::AsPPB_AudioInput_API() {
47 return this;
50 void AudioInputResource::OnReplyReceived(
51 const ResourceMessageReplyParams& params,
52 const IPC::Message& msg) {
53 if (!enumeration_helper_.HandleReply(params, msg))
54 PluginResource::OnReplyReceived(params, msg);
57 int32_t AudioInputResource::EnumerateDevices(
58 const PP_ArrayOutput& output,
59 scoped_refptr<TrackedCallback> callback) {
60 return enumeration_helper_.EnumerateDevices(output, callback);
63 int32_t AudioInputResource::MonitorDeviceChange(
64 PP_MonitorDeviceChangeCallback callback,
65 void* user_data) {
66 return enumeration_helper_.MonitorDeviceChange(callback, user_data);
69 int32_t AudioInputResource::Open0_3(
70 PP_Resource device_ref,
71 PP_Resource config,
72 PPB_AudioInput_Callback_0_3 audio_input_callback_0_3,
73 void* user_data,
74 scoped_refptr<TrackedCallback> callback) {
75 return CommonOpen(device_ref, config, audio_input_callback_0_3, NULL,
76 user_data, callback);
79 int32_t AudioInputResource::Open(PP_Resource device_ref,
80 PP_Resource config,
81 PPB_AudioInput_Callback audio_input_callback,
82 void* user_data,
83 scoped_refptr<TrackedCallback> callback) {
84 return CommonOpen(device_ref, config, NULL, audio_input_callback, user_data,
85 callback);
88 PP_Resource AudioInputResource::GetCurrentConfig() {
89 // AddRef for the caller.
90 if (config_.get())
91 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(config_);
92 return config_;
95 PP_Bool AudioInputResource::StartCapture() {
96 if (open_state_ == CLOSED || (open_state_ == BEFORE_OPEN &&
97 !TrackedCallback::IsPending(open_callback_))) {
98 return PP_FALSE;
100 if (capturing_)
101 return PP_TRUE;
103 capturing_ = true;
104 // Return directly if the audio input device hasn't been opened. Capturing
105 // will be started once the open operation is completed.
106 if (open_state_ == BEFORE_OPEN)
107 return PP_TRUE;
109 StartThread();
111 Post(RENDERER, PpapiHostMsg_AudioInput_StartOrStop(true));
112 return PP_TRUE;
115 PP_Bool AudioInputResource::StopCapture() {
116 if (open_state_ == CLOSED)
117 return PP_FALSE;
118 if (!capturing_)
119 return PP_TRUE;
121 // If the audio input device hasn't been opened, set |capturing_| to false and
122 // return directly.
123 if (open_state_ == BEFORE_OPEN) {
124 capturing_ = false;
125 return PP_TRUE;
128 Post(RENDERER, PpapiHostMsg_AudioInput_StartOrStop(false));
130 StopThread();
131 capturing_ = false;
133 return PP_TRUE;
136 void AudioInputResource::Close() {
137 if (open_state_ == CLOSED)
138 return;
140 open_state_ = CLOSED;
141 Post(RENDERER, PpapiHostMsg_AudioInput_Close());
142 StopThread();
144 if (TrackedCallback::IsPending(open_callback_))
145 open_callback_->PostAbort();
148 void AudioInputResource::LastPluginRefWasDeleted() {
149 enumeration_helper_.LastPluginRefWasDeleted();
152 void AudioInputResource::OnPluginMsgOpenReply(
153 const ResourceMessageReplyParams& params) {
154 if (open_state_ == BEFORE_OPEN && params.result() == PP_OK) {
155 IPC::PlatformFileForTransit socket_handle_for_transit =
156 IPC::InvalidPlatformFileForTransit();
157 params.TakeSocketHandleAtIndex(0, &socket_handle_for_transit);
158 base::SyncSocket::Handle socket_handle =
159 IPC::PlatformFileForTransitToPlatformFile(socket_handle_for_transit);
160 CHECK(socket_handle != base::SyncSocket::kInvalidHandle);
162 SerializedHandle serialized_shared_memory_handle =
163 params.TakeHandleOfTypeAtIndex(1, SerializedHandle::SHARED_MEMORY);
164 CHECK(serialized_shared_memory_handle.IsHandleValid());
166 open_state_ = OPENED;
167 SetStreamInfo(serialized_shared_memory_handle.shmem(),
168 serialized_shared_memory_handle.size(),
169 socket_handle);
170 } else {
171 capturing_ = false;
174 // The callback may have been aborted by Close().
175 if (TrackedCallback::IsPending(open_callback_))
176 open_callback_->Run(params.result());
179 void AudioInputResource::SetStreamInfo(
180 base::SharedMemoryHandle shared_memory_handle,
181 size_t shared_memory_size,
182 base::SyncSocket::Handle socket_handle) {
183 socket_.reset(new base::CancelableSyncSocket(socket_handle));
184 shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false));
185 shared_memory_size_ = shared_memory_size;
186 DCHECK(!shared_memory_->memory());
188 // If we fail to map the shared memory into the caller's address space we
189 // might as well fail here since nothing will work if this is the case.
190 CHECK(shared_memory_->Map(shared_memory_size_));
192 // Create a new audio bus and wrap the audio data section in shared memory.
193 media::AudioInputBuffer* buffer =
194 static_cast<media::AudioInputBuffer*>(shared_memory_->memory());
195 audio_bus_ = media::AudioBus::WrapMemory(
196 kAudioInputChannels, sample_frame_count_, buffer->audio);
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);
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_]);
214 // There is a pending capture request before SetStreamInfo().
215 if (capturing_) {
216 // Set |capturing_| to false so that the state looks consistent to
217 // StartCapture(), which will reset it to true.
218 capturing_ = false;
219 StartCapture();
223 void AudioInputResource::StartThread() {
224 // Don't start the thread unless all our state is set up correctly.
225 if ((!audio_input_callback_0_3_ && !audio_input_callback_) ||
226 !socket_.get() || !capturing_ || !shared_memory_->memory() ||
227 !audio_bus_.get() || !client_buffer_.get()) {
228 return;
230 DCHECK(!audio_input_thread_.get());
231 audio_input_thread_.reset(new base::DelegateSimpleThread(
232 this, "plugin_audio_input_thread"));
233 audio_input_thread_->Start();
236 void AudioInputResource::StopThread() {
237 // Shut down the socket to escape any hanging |Receive|s.
238 if (socket_.get())
239 socket_->Shutdown();
240 if (audio_input_thread_.get()) {
241 audio_input_thread_->Join();
242 audio_input_thread_.reset();
246 void AudioInputResource::Run() {
247 // The shared memory represents AudioInputBufferParameters and the actual data
248 // buffer stored as an audio bus.
249 media::AudioInputBuffer* buffer =
250 static_cast<media::AudioInputBuffer*>(shared_memory_->memory());
251 const uint32_t audio_bus_size_bytes =
252 shared_memory_size_ - sizeof(media::AudioInputBufferParameters);
254 while (true) {
255 int 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;
261 if (pending_data < 0)
262 break;
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());
270 // While closing the stream, we may receive buffers whose size is different
271 // from |data_buffer_size|.
272 CHECK_LE(buffer->params.size, audio_bus_size_bytes);
273 if (buffer->params.size > 0) {
274 if (audio_input_callback_) {
275 PP_TimeDelta latency =
276 static_cast<double>(pending_data) / bytes_per_second_;
277 audio_input_callback_(client_buffer_.get(),
278 client_buffer_size_bytes_,
279 latency,
280 user_data_);
281 } else {
282 audio_input_callback_0_3_(
283 client_buffer_.get(), client_buffer_size_bytes_, user_data_);
289 int32_t AudioInputResource::CommonOpen(
290 PP_Resource device_ref,
291 PP_Resource config,
292 PPB_AudioInput_Callback_0_3 audio_input_callback_0_3,
293 PPB_AudioInput_Callback audio_input_callback,
294 void* user_data,
295 scoped_refptr<TrackedCallback> callback) {
296 std::string device_id;
297 // |device_id| remains empty if |device_ref| is 0, which means the default
298 // device.
299 if (device_ref != 0) {
300 thunk::EnterResourceNoLock<thunk::PPB_DeviceRef_API> enter_device_ref(
301 device_ref, true);
302 if (enter_device_ref.failed())
303 return PP_ERROR_BADRESOURCE;
304 device_id = enter_device_ref.object()->GetDeviceRefData().id;
307 if (TrackedCallback::IsPending(open_callback_))
308 return PP_ERROR_INPROGRESS;
309 if (open_state_ != BEFORE_OPEN)
310 return PP_ERROR_FAILED;
312 if (!audio_input_callback_0_3 && !audio_input_callback)
313 return PP_ERROR_BADARGUMENT;
314 thunk::EnterResourceNoLock<thunk::PPB_AudioConfig_API> enter_config(config,
315 true);
316 if (enter_config.failed())
317 return PP_ERROR_BADARGUMENT;
319 config_ = config;
320 audio_input_callback_0_3_ = audio_input_callback_0_3;
321 audio_input_callback_ = audio_input_callback;
322 user_data_ = user_data;
323 open_callback_ = callback;
324 bytes_per_second_ = kAudioInputChannels * (kBitsPerAudioInputSample / 8) *
325 enter_config.object()->GetSampleRate();
326 sample_frame_count_ = enter_config.object()->GetSampleFrameCount();
328 PpapiHostMsg_AudioInput_Open msg(
329 device_id, enter_config.object()->GetSampleRate(),
330 enter_config.object()->GetSampleFrameCount());
331 Call<PpapiPluginMsg_AudioInput_OpenReply>(
332 RENDERER, msg,
333 base::Bind(&AudioInputResource::OnPluginMsgOpenReply,
334 base::Unretained(this)));
335 return PP_OK_COMPLETIONPENDING;
337 } // namespace proxy
338 } // namespace ppapi