Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(134)

Side by Side Diff: ppapi/proxy/audio_input_resource.cc

Issue 11366038: Rewrite PPB_AudioInput_Dev to use the new-style host/resource. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "ppapi/proxy/audio_input_resource.h"
6
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/ppb_device_ref_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"
22
23 namespace ppapi {
24 namespace proxy {
25
26 AudioInputResource::AudioInputResource(
27 Connection connection,
28 PP_Instance instance)
29 : PluginResource(connection, instance),
30 open_state_(BEFORE_OPEN),
31 capturing_(false),
32 shared_memory_size_(0),
33 audio_input_callback_(NULL),
34 user_data_(NULL),
35 pending_enumerate_devices_(false),
36 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
37 SendCreate(RENDERER, PpapiHostMsg_AudioInput_Create());
38 }
39
40 AudioInputResource::~AudioInputResource() {
41 Close();
42 }
43
44 thunk::PPB_AudioInput_API* AudioInputResource::AsPPB_AudioInput_API() {
45 return this;
46 }
47
48 int32_t AudioInputResource::EnumerateDevices(
49 PP_Resource* devices,
50 scoped_refptr<TrackedCallback> callback) {
51 if (pending_enumerate_devices_)
raymes 2012/11/04 20:59:59 Is only one request allowed to be in progress at a
yzshen1 2012/11/06 22:14:20 I did it to match the previous behavior.
52 return PP_ERROR_INPROGRESS;
53 if (!devices)
54 return PP_ERROR_BADARGUMENT;
55
56 pending_enumerate_devices_ = true;
57 PpapiHostMsg_AudioInput_EnumerateDevices msg;
58 Call<PpapiPluginMsg_AudioInput_EnumerateDevicesReply>(
59 RENDERER, msg,
60 base::Bind(&AudioInputResource::OnPluginMsgEnumerateDevicesReply,
61 weak_ptr_factory_.GetWeakPtr(), devices, callback));
62 return PP_OK_COMPLETIONPENDING;
63 }
64
65 int32_t AudioInputResource::Open(const std::string& device_id,
66 PP_Resource config,
67 PPB_AudioInput_Callback audio_input_callback,
68 void* user_data,
69 scoped_refptr<TrackedCallback> callback) {
70 if (TrackedCallback::IsPending(open_callback_))
71 return PP_ERROR_INPROGRESS;
72 if (open_state_ != BEFORE_OPEN)
73 return PP_ERROR_FAILED;
74
75 if (!audio_input_callback)
76 return PP_ERROR_BADARGUMENT;
77 thunk::EnterResourceNoLock<thunk::PPB_AudioConfig_API> enter_config(config,
78 true);
79 if (enter_config.failed())
80 return PP_ERROR_BADARGUMENT;
81
82 config_ = config;
83 audio_input_callback_ = audio_input_callback;
84 user_data_ = user_data;
85 open_callback_ = callback;
86
87 PpapiHostMsg_AudioInput_Open msg(
88 device_id, enter_config.object()->GetSampleRate(),
89 enter_config.object()->GetSampleFrameCount());
90 Call<PpapiPluginMsg_AudioInput_OpenReply>(
91 RENDERER, msg,
92 base::Bind(&AudioInputResource::OnPluginMsgOpenReply,
93 weak_ptr_factory_.GetWeakPtr()));
94 return PP_OK_COMPLETIONPENDING;
95 }
96
97 PP_Resource AudioInputResource::GetCurrentConfig() {
98 // AddRef for the caller.
99 if (config_.get())
100 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(config_);
101 return config_;
102 }
103
104 PP_Bool AudioInputResource::StartCapture() {
105 if (open_state_ == CLOSED || (open_state_ == BEFORE_OPEN &&
106 !TrackedCallback::IsPending(open_callback_))) {
107 return PP_FALSE;
108 }
109 if (capturing_)
110 return PP_TRUE;
111
112 capturing_ = true;
113 // Return directly if the audio input device hasn't been opened. Capturing
114 // will be started once the open operation is completed.
115 if (open_state_ == BEFORE_OPEN)
116 return PP_TRUE;
117
118 StartThread();
119
120 Post(RENDERER, PpapiHostMsg_AudioInput_StartOrStop(true));
121 return PP_TRUE;
122 }
123
124 PP_Bool AudioInputResource::StopCapture() {
125 if (open_state_ == CLOSED)
126 return PP_FALSE;
127 if (!capturing_)
128 return PP_TRUE;
129
130 // If the audio input device hasn't been opened, set |capturing_| to false and
131 // return directly.
132 if (open_state_ == BEFORE_OPEN) {
133 capturing_ = false;
134 return PP_TRUE;
135 }
136
137 Post(RENDERER, PpapiHostMsg_AudioInput_StartOrStop(false));
138
139 StopThread();
140 capturing_ = false;
141
142 return PP_TRUE;
143 }
144
145 void AudioInputResource::Close() {
146 if (open_state_ == CLOSED)
147 return;
148
149 open_state_ = CLOSED;
150 Post(RENDERER, PpapiHostMsg_AudioInput_Close());
151 StopThread();
152
153 if (TrackedCallback::IsPending(open_callback_))
154 open_callback_->PostAbort();
155 }
156
157 void AudioInputResource::OnPluginMsgEnumerateDevicesReply(
158 PP_Resource* devices_resource,
159 scoped_refptr<TrackedCallback> callback,
160 const ResourceMessageReplyParams& params,
161 const std::vector<DeviceRefData>& devices) {
162 pending_enumerate_devices_ = false;
163
164 // We shouldn't access |devices_resource| if the callback has been called,
165 // which is possible if the last plugin reference to this resource has gone
166 // away, and the callback has been aborted.
167 if (!TrackedCallback::IsPending(callback))
168 return;
169
170 if (params.result() == PP_OK) {
171 *devices_resource = PPB_DeviceRef_Shared::CreateResourceArray(
172 OBJECT_IS_PROXY, pp_instance(), devices);
173 }
174
175 TrackedCallback::ClearAndRun(&callback, params.result());
176 }
177
178 void AudioInputResource::OnPluginMsgOpenReply(
179 const ResourceMessageReplyParams& params) {
180 if (open_state_ == BEFORE_OPEN && params.result() == PP_OK) {
181 IPC::PlatformFileForTransit socket_handle_for_transit =
182 IPC::InvalidPlatformFileForTransit();
183 params.TakeSocketHandleAtIndex(0, &socket_handle_for_transit);
184 base::SyncSocket::Handle socket_handle =
185 IPC::PlatformFileForTransitToPlatformFile(socket_handle_for_transit);
186 CHECK(socket_handle != base::SyncSocket::kInvalidHandle);
187
188 SerializedHandle serialized_shared_memory_handle =
189 params.TakeHandleOfTypeAtIndex(1, SerializedHandle::SHARED_MEMORY);
190 CHECK(serialized_shared_memory_handle.IsHandleValid());
191
192 // See the comment in pepper_audio_input_host.cc about how we must call
193 // TotalSharedMemorySizeInBytes to get the actual size of the buffer. Here,
194 // we must call PacketSizeInBytes to get back the size of the audio buffer,
195 // excluding the bytes that audio uses for book-keeping.
196 size_t shared_memory_size = media::PacketSizeInBytes(
197 serialized_shared_memory_handle.size());
198
199 open_state_ = OPENED;
200 SetStreamInfo(serialized_shared_memory_handle.shmem(), shared_memory_size,
201 socket_handle);
202 } else {
203 capturing_ = false;
204 }
205
206 // The callback may have been aborted by Close().
207 if (TrackedCallback::IsPending(open_callback_))
208 TrackedCallback::ClearAndRun(&open_callback_, params.result());
209 }
210
211 void AudioInputResource::SetStreamInfo(
212 base::SharedMemoryHandle shared_memory_handle,
213 size_t shared_memory_size,
214 base::SyncSocket::Handle socket_handle) {
215 socket_.reset(new base::CancelableSyncSocket(socket_handle));
216 shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false));
217 shared_memory_size_ = shared_memory_size;
218
219 if (!shared_memory_->Map(shared_memory_size_)) {
220 PpapiGlobals::Get()->LogWithSource(pp_instance(), PP_LOGLEVEL_WARNING, "",
221 "Failed to map shared memory for PPB_AudioInput_Shared.");
222 }
223
224 // There is a pending capture request before SetStreamInfo().
225 if (capturing_) {
226 // Set |capturing_| to false so that the state looks consistent to
227 // StartCapture(), which will reset it to true.
228 capturing_ = false;
229 StartCapture();
230 }
231 }
232
233 void AudioInputResource::StartThread() {
234 // Don't start the thread unless all our state is set up correctly.
235 if (!audio_input_callback_ || !socket_.get() || !capturing_ ||
236 !shared_memory_->memory()) {
237 return;
238 }
239 DCHECK(!audio_input_thread_.get());
240 audio_input_thread_.reset(new base::DelegateSimpleThread(
241 this, "plugin_audio_input_thread"));
242 audio_input_thread_->Start();
243 }
244
245 void AudioInputResource::StopThread() {
246 // Shut down the socket to escape any hanging |Receive|s.
247 if (socket_.get())
248 socket_->Shutdown();
249 if (audio_input_thread_.get()) {
250 audio_input_thread_->Join();
251 audio_input_thread_.reset();
252 }
253 }
254
255 void AudioInputResource::Run() {
256 // The shared memory represents AudioInputBufferParameters and the actual data
257 // buffer.
258 media::AudioInputBuffer* buffer =
259 static_cast<media::AudioInputBuffer*>(shared_memory_->memory());
260 uint32_t data_buffer_size =
261 shared_memory_size_ - sizeof(media::AudioInputBufferParameters);
262 int pending_data;
263
264 while (sizeof(pending_data) == socket_->Receive(&pending_data,
265 sizeof(pending_data)) &&
266 pending_data >= 0) {
267 // While closing the stream, we may receive buffers whose size is different
268 // from |data_buffer_size|.
269 CHECK_LE(buffer->params.size, data_buffer_size);
270 if (buffer->params.size > 0)
271 audio_input_callback_(&buffer->audio[0], buffer->params.size, user_data_);
272 }
273 }
274
275 } // namespace proxy
276 } // namespace ppapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698