Refactor android test results logging.
[chromium-blink-merge.git] / ppapi / proxy / audio_input_resource.cc
blob2f17c6cfe65b9121c15c766651dc78cbd8f4a421
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/audio/shared_memory_util.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_structs.h"
16 #include "ppapi/shared_impl/ppapi_globals.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_(NULL),
33 user_data_(NULL),
34 ALLOW_THIS_IN_INITIALIZER_LIST(enumeration_helper_(this)) {
35 SendCreate(RENDERER, PpapiHostMsg_AudioInput_Create());
38 AudioInputResource::~AudioInputResource() {
39 Close();
42 thunk::PPB_AudioInput_API* AudioInputResource::AsPPB_AudioInput_API() {
43 return this;
46 void AudioInputResource::OnReplyReceived(
47 const ResourceMessageReplyParams& params,
48 const IPC::Message& msg) {
49 if (!enumeration_helper_.HandleReply(params, msg))
50 PluginResource::OnReplyReceived(params, msg);
53 int32_t AudioInputResource::EnumerateDevices0_2(
54 PP_Resource* devices,
55 scoped_refptr<TrackedCallback> callback) {
56 return enumeration_helper_.EnumerateDevices0_2(devices, callback);
59 int32_t AudioInputResource::EnumerateDevices(
60 const PP_ArrayOutput& output,
61 scoped_refptr<TrackedCallback> callback) {
62 return enumeration_helper_.EnumerateDevices(output, callback);
65 int32_t AudioInputResource::MonitorDeviceChange(
66 PP_MonitorDeviceChangeCallback callback,
67 void* user_data) {
68 return enumeration_helper_.MonitorDeviceChange(callback, user_data);
71 int32_t AudioInputResource::Open(const std::string& device_id,
72 PP_Resource config,
73 PPB_AudioInput_Callback audio_input_callback,
74 void* user_data,
75 scoped_refptr<TrackedCallback> callback) {
76 if (TrackedCallback::IsPending(open_callback_))
77 return PP_ERROR_INPROGRESS;
78 if (open_state_ != BEFORE_OPEN)
79 return PP_ERROR_FAILED;
81 if (!audio_input_callback)
82 return PP_ERROR_BADARGUMENT;
83 thunk::EnterResourceNoLock<thunk::PPB_AudioConfig_API> enter_config(config,
84 true);
85 if (enter_config.failed())
86 return PP_ERROR_BADARGUMENT;
88 config_ = config;
89 audio_input_callback_ = audio_input_callback;
90 user_data_ = user_data;
91 open_callback_ = callback;
93 PpapiHostMsg_AudioInput_Open msg(
94 device_id, enter_config.object()->GetSampleRate(),
95 enter_config.object()->GetSampleFrameCount());
96 Call<PpapiPluginMsg_AudioInput_OpenReply>(
97 RENDERER, msg,
98 base::Bind(&AudioInputResource::OnPluginMsgOpenReply,
99 base::Unretained(this)));
100 return PP_OK_COMPLETIONPENDING;
103 PP_Resource AudioInputResource::GetCurrentConfig() {
104 // AddRef for the caller.
105 if (config_.get())
106 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(config_);
107 return config_;
110 PP_Bool AudioInputResource::StartCapture() {
111 if (open_state_ == CLOSED || (open_state_ == BEFORE_OPEN &&
112 !TrackedCallback::IsPending(open_callback_))) {
113 return PP_FALSE;
115 if (capturing_)
116 return PP_TRUE;
118 capturing_ = true;
119 // Return directly if the audio input device hasn't been opened. Capturing
120 // will be started once the open operation is completed.
121 if (open_state_ == BEFORE_OPEN)
122 return PP_TRUE;
124 StartThread();
126 Post(RENDERER, PpapiHostMsg_AudioInput_StartOrStop(true));
127 return PP_TRUE;
130 PP_Bool AudioInputResource::StopCapture() {
131 if (open_state_ == CLOSED)
132 return PP_FALSE;
133 if (!capturing_)
134 return PP_TRUE;
136 // If the audio input device hasn't been opened, set |capturing_| to false and
137 // return directly.
138 if (open_state_ == BEFORE_OPEN) {
139 capturing_ = false;
140 return PP_TRUE;
143 Post(RENDERER, PpapiHostMsg_AudioInput_StartOrStop(false));
145 StopThread();
146 capturing_ = false;
148 return PP_TRUE;
151 void AudioInputResource::Close() {
152 if (open_state_ == CLOSED)
153 return;
155 open_state_ = CLOSED;
156 Post(RENDERER, PpapiHostMsg_AudioInput_Close());
157 StopThread();
159 if (TrackedCallback::IsPending(open_callback_))
160 open_callback_->PostAbort();
163 void AudioInputResource::LastPluginRefWasDeleted() {
164 enumeration_helper_.LastPluginRefWasDeleted();
167 void AudioInputResource::OnPluginMsgOpenReply(
168 const ResourceMessageReplyParams& params) {
169 if (open_state_ == BEFORE_OPEN && params.result() == PP_OK) {
170 IPC::PlatformFileForTransit socket_handle_for_transit =
171 IPC::InvalidPlatformFileForTransit();
172 params.TakeSocketHandleAtIndex(0, &socket_handle_for_transit);
173 base::SyncSocket::Handle socket_handle =
174 IPC::PlatformFileForTransitToPlatformFile(socket_handle_for_transit);
175 CHECK(socket_handle != base::SyncSocket::kInvalidHandle);
177 SerializedHandle serialized_shared_memory_handle =
178 params.TakeHandleOfTypeAtIndex(1, SerializedHandle::SHARED_MEMORY);
179 CHECK(serialized_shared_memory_handle.IsHandleValid());
181 // See the comment in pepper_audio_input_host.cc about how we must call
182 // TotalSharedMemorySizeInBytes to get the actual size of the buffer. Here,
183 // we must call PacketSizeInBytes to get back the size of the audio buffer,
184 // excluding the bytes that audio uses for book-keeping.
185 size_t shared_memory_size = media::PacketSizeInBytes(
186 serialized_shared_memory_handle.size());
188 open_state_ = OPENED;
189 SetStreamInfo(serialized_shared_memory_handle.shmem(), shared_memory_size,
190 socket_handle);
191 } else {
192 capturing_ = false;
195 // The callback may have been aborted by Close().
196 if (TrackedCallback::IsPending(open_callback_))
197 open_callback_->Run(params.result());
200 void AudioInputResource::SetStreamInfo(
201 base::SharedMemoryHandle shared_memory_handle,
202 size_t shared_memory_size,
203 base::SyncSocket::Handle socket_handle) {
204 socket_.reset(new base::CancelableSyncSocket(socket_handle));
205 shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false));
206 shared_memory_size_ = shared_memory_size;
208 if (!shared_memory_->Map(shared_memory_size_)) {
209 PpapiGlobals::Get()->LogWithSource(pp_instance(), PP_LOGLEVEL_WARNING, "",
210 "Failed to map shared memory for PPB_AudioInput_Shared.");
213 // There is a pending capture request before SetStreamInfo().
214 if (capturing_) {
215 // Set |capturing_| to false so that the state looks consistent to
216 // StartCapture(), which will reset it to true.
217 capturing_ = false;
218 StartCapture();
222 void AudioInputResource::StartThread() {
223 // Don't start the thread unless all our state is set up correctly.
224 if (!audio_input_callback_ || !socket_.get() || !capturing_ ||
225 !shared_memory_->memory()) {
226 return;
228 DCHECK(!audio_input_thread_.get());
229 audio_input_thread_.reset(new base::DelegateSimpleThread(
230 this, "plugin_audio_input_thread"));
231 audio_input_thread_->Start();
234 void AudioInputResource::StopThread() {
235 // Shut down the socket to escape any hanging |Receive|s.
236 if (socket_.get())
237 socket_->Shutdown();
238 if (audio_input_thread_.get()) {
239 audio_input_thread_->Join();
240 audio_input_thread_.reset();
244 void AudioInputResource::Run() {
245 // The shared memory represents AudioInputBufferParameters and the actual data
246 // buffer.
247 media::AudioInputBuffer* buffer =
248 static_cast<media::AudioInputBuffer*>(shared_memory_->memory());
249 uint32_t data_buffer_size =
250 shared_memory_size_ - sizeof(media::AudioInputBufferParameters);
251 int pending_data;
253 while (sizeof(pending_data) == socket_->Receive(&pending_data,
254 sizeof(pending_data)) &&
255 pending_data >= 0) {
256 // While closing the stream, we may receive buffers whose size is different
257 // from |data_buffer_size|.
258 CHECK_LE(buffer->params.size, data_buffer_size);
259 if (buffer->params.size > 0)
260 audio_input_callback_(&buffer->audio[0], buffer->params.size, user_data_);
264 } // namespace proxy
265 } // namespace ppapi