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

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

Issue 8138008: Implementation of ppapi audio. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 9 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
Property Changes:
Added: svn:executable
+ *
OLDNEW
(Empty)
1 // Copyright (c) 2011 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/ppb_audio_input_proxy.h"
6
7 #include <vector>
8
9 #include "base/logging.h"
10 #include "build/build_config.h"
11 #include "ppapi/c/dev/ppb_audio_input_dev.h"
12 #include "ppapi/c/pp_errors.h"
13 #include "ppapi/c/pp_resource.h"
14 #include "ppapi/c/ppb_core.h"
15 #include "ppapi/c/ppb_var.h"
16 #include "ppapi/proxy/enter_proxy.h"
17 #include "ppapi/proxy/interface_id.h"
18 #include "ppapi/proxy/plugin_dispatcher.h"
19 #include "ppapi/proxy/ppapi_messages.h"
20 #include "ppapi/shared_impl/audio_input_impl.h"
21 #include "ppapi/shared_impl/resource.h"
22 #include "ppapi/thunk/enter.h"
23 #include "ppapi/thunk/ppb_audio_config_api.h"
24 #include "ppapi/thunk/ppb_audio_input_api.h"
25 #include "ppapi/thunk/resource_creation_api.h"
26 #include "ppapi/thunk/thunk.h"
27
28 using ppapi::thunk::EnterResourceNoLock;
29 using ppapi::thunk::PPB_AudioInput_API;
30 using ppapi::thunk::PPB_AudioConfig_API;
31
32 namespace ppapi {
33 namespace proxy {
34
35 class AudioInput : public Resource, public AudioInputImpl {
36 public:
37 AudioInput(const HostResource& audio_input_id,
38 PP_Resource config_id,
39 PPB_AudioInput_Callback callback,
40 void* user_data);
41 virtual ~AudioInput();
42
43 // Resource overrides.
44 virtual PPB_AudioInput_API* AsPPB_AudioInput_API();
45
46 // PPB_AudioInput_API implementation.
47 virtual PP_Resource GetCurrentConfig() OVERRIDE;
48 virtual PP_Bool StartCapture() OVERRIDE;
49 virtual PP_Bool StopCapture() OVERRIDE;
50
51 virtual int32_t OpenTrusted(PP_Resource config_id,
52 PP_CompletionCallback create_callback) OVERRIDE;
53 virtual int32_t GetSyncSocket(int* sync_socket) OVERRIDE;
54 virtual int32_t GetSharedMemory(int* shm_handle, uint32_t* shm_size) OVERRIDE;
55
56 private:
57 // Owning reference to the current config object. This isn't actually used,
58 // we just dish it out as requested by the plugin.
59 PP_Resource config_;
60
61 DISALLOW_COPY_AND_ASSIGN(AudioInput);
62 };
63
64 AudioInput::AudioInput(const HostResource& audio_input_id,
65 PP_Resource config_id,
66 PPB_AudioInput_Callback callback,
67 void* user_data)
68 : Resource(audio_input_id),
69 config_(config_id) {
70 SetCallback(callback, user_data);
71 PluginResourceTracker::GetInstance()->AddRefResource(config_);
72 }
73
74 AudioInput::~AudioInput() {
75 PluginResourceTracker::GetInstance()->ReleaseResource(config_);
76 }
77
78 PPB_AudioInput_API* AudioInput::AsPPB_AudioInput_API() {
79 return this;
80 }
81
82 PP_Resource AudioInput::GetCurrentConfig() {
83 // AddRef for the caller.
84 PluginResourceTracker::GetInstance()->AddRefResource(config_);
85 return config_;
86 }
87
88 PP_Bool AudioInput::StartCapture() {
89 if (capturing())
90 return PP_TRUE;
91 SetStartCaptureState();
92 PluginDispatcher::GetForResource(this)->Send(
93 new PpapiHostMsg_PPBAudioInput_StartOrStop(
94 INTERFACE_ID_PPB_AUDIO_INPUT_DEV, host_resource(), true));
95 return PP_TRUE;
96 }
97
98 PP_Bool AudioInput::StopCapture() {
99 if (!capturing())
100 return PP_TRUE;
101 PluginDispatcher::GetForResource(this)->Send(
102 new PpapiHostMsg_PPBAudioInput_StartOrStop(
103 INTERFACE_ID_PPB_AUDIO_INPUT_DEV, host_resource(), false));
104 SetStopCaptureState();
105 return PP_TRUE;
106 }
107
108 int32_t AudioInput::OpenTrusted(PP_Resource config_id,
109 PP_CompletionCallback create_callback) {
110 return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface.
111 }
112
113 int32_t AudioInput::GetSyncSocket(int* sync_socket) {
114 return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface.
115 }
116
117 int32_t AudioInput::GetSharedMemory(int* shm_handle, uint32_t* shm_size) {
118 return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface.
119 }
120
121
122 namespace {
123
124 base::PlatformFile IntToPlatformFile(int32_t handle) {
125 // TODO(piman/brettw): Change trusted interface to return a PP_FileHandle,
126 // those casts are ugly.
127 #if defined(OS_WIN)
128 return reinterpret_cast<HANDLE>(static_cast<intptr_t>(handle));
129 #elif defined(OS_POSIX)
130 return handle;
131 #else
132 #error Not implemented.
133 #endif
134 }
135
136 } // namespace
137
138
139 PPB_AudioInput_Proxy::PPB_AudioInput_Proxy(Dispatcher* dispatcher)
140 : InterfaceProxy(dispatcher),
141 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
142 }
143
144 PPB_AudioInput_Proxy::~PPB_AudioInput_Proxy() {
145 }
146
147 // static
148 PP_Resource PPB_AudioInput_Proxy::CreateProxyResource(
149 PP_Instance instance_id,
150 PP_Resource config_id,
151 PPB_AudioInput_Callback audio_input_callback,
152 void* user_data) {
153 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id);
154 if (!dispatcher)
155 return 0;
156
157 EnterResourceNoLock<PPB_AudioConfig_API> config(config_id, true);
158 if (config.failed())
159 return 0;
160
161 HostResource result;
162 dispatcher->Send(new PpapiHostMsg_PPBAudioInput_Create(
163 INTERFACE_ID_PPB_AUDIO_INPUT_DEV, instance_id,
164 config.object()->GetSampleRate(), config.object()->GetSampleFrameCount(),
165 &result));
166 if (result.is_null())
167 return 0;
168
169 return (new AudioInput(result, config_id, audio_input_callback,
170 user_data))->GetReference();
171 }
172
173 bool PPB_AudioInput_Proxy::OnMessageReceived(const IPC::Message& msg) {
174 bool handled = true;
175 IPC_BEGIN_MESSAGE_MAP(PPB_AudioInput_Proxy, msg)
176 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudioInput_Create, OnMsgCreate)
177 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudioInput_StartOrStop,
178 OnMsgStartOrStop)
179 IPC_MESSAGE_HANDLER(PpapiMsg_PPBAudioInput_NotifyAudioStreamCreated,
180 OnMsgNotifyAudioStreamCreated)
181 IPC_MESSAGE_UNHANDLED(handled = false)
182 IPC_END_MESSAGE_MAP()
183 // TODO(brettw) handle bad messages!
184
185 return handled;
186 }
187
188 void PPB_AudioInput_Proxy::OnMsgCreate(PP_Instance instance_id,
189 int32_t sample_rate,
190 uint32_t sample_frame_count,
191 HostResource* result) {
192 thunk::EnterFunction<thunk::ResourceCreationAPI> resource_creation(
193 instance_id, true);
194 if (resource_creation.failed())
195 return;
196
197 // Make the resource and get the API pointer to its trusted interface.
198 result->SetHostResource(
199 instance_id,
200 resource_creation.functions()->CreateAudioInputTrusted(instance_id));
201 if (result->is_null())
202 return;
203
204
205 // At this point, we've set the result resource, and this is a sync request.
206 // Anything below this point must issue the AudioInputChannelConnected
207 // callback to the browser. Since that's an async message, it will be issued
208 // back to the plugin after the Create function returns (which is good
209 // because it would be weird to get a connected message with a failure code
210 // for a resource you haven't finished creating yet).
211 //
212 // The ...ForceCallback class will help ensure the callback is always called.
213 // All error cases must call SetResult on this class.
214
215 EnterHostFromHostResourceForceCallback<PPB_AudioInput_API> enter(
216 *result, callback_factory_,
217 &PPB_AudioInput_Proxy::AudioInputChannelConnected, *result);
218 if (enter.failed())
219 return; // When enter fails, it will internally schedule the callback.
220
221 // Make an audio config object.
222 PP_Resource audio_config_res =
223 resource_creation.functions()->CreateAudioConfig(
224 instance_id, static_cast<PP_AudioSampleRate>(sample_rate),
225 sample_frame_count);
226 if (!audio_config_res) {
227 enter.SetResult(PP_ERROR_FAILED);
228 return;
229 }
230
231 // Initiate opening the audio object.
232 enter.SetResult(enter.object()->OpenTrusted(audio_config_res,
233 enter.callback()));
234
235 // Clean up the temporary audio config resource we made.
236 const PPB_Core* core = static_cast<const PPB_Core*>(
237 dispatcher()->local_get_interface()(PPB_CORE_INTERFACE));
238 core->ReleaseResource(audio_config_res);
239 }
240
241 void PPB_AudioInput_Proxy::OnMsgStartOrStop(
242 const HostResource& resource,
243 bool capture) {
244 EnterHostFromHostResource<PPB_AudioInput_API> enter(resource);
245 if (enter.failed())
246 return;
247 if (capture)
248 enter.object()->StartCapture();
249 else
250 enter.object()->StopCapture();
251 }
252
253 // Processed in the plugin (message from host).
254 void PPB_AudioInput_Proxy::OnMsgNotifyAudioStreamCreated(
255 const HostResource& audio_id,
256 int32_t result_code,
257 IPC::PlatformFileForTransit socket_handle,
258 base::SharedMemoryHandle handle,
259 uint32_t length) {
260 EnterPluginFromHostResource<PPB_AudioInput_API> enter(audio_id);
261 if (enter.failed() || result_code != PP_OK) {
262 // The caller may still have given us these handles in the failure case.
263 // The easiest way to clean these up is to just put them in the objects
264 // and then close them. This failure case is not performance critical.
265 base::SyncSocket temp_socket(
266 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
267 base::SharedMemory temp_mem(handle, false);
268 } else {
269 static_cast<AudioInput*>(enter.object())->SetStreamInfo(
270 handle, length,
271 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
272 }
273 }
274
275 void PPB_AudioInput_Proxy::AudioInputChannelConnected(
276 int32_t result,
277 const HostResource& resource) {
278 IPC::PlatformFileForTransit socket_handle =
279 IPC::InvalidPlatformFileForTransit();
280 base::SharedMemoryHandle shared_memory = IPC::InvalidPlatformFileForTransit();
281 uint32_t shared_memory_length = 0;
282
283 int32_t result_code = result;
284 if (result_code == PP_OK) {
285 result_code = GetAudioInputConnectedHandles(resource, &socket_handle,
286 &shared_memory,
287 &shared_memory_length);
288 }
289
290 // Send all the values, even on error. This simplifies some of our cleanup
291 // code since the handles will be in the other process and could be
292 // inconvenient to clean up. Our IPC code will automatically handle this for
293 // us, as long as the remote side always closes the handles it receives
294 // (in OnMsgNotifyAudioStreamCreated), even in the failure case.
295 dispatcher()->Send(new PpapiMsg_PPBAudioInput_NotifyAudioStreamCreated(
296 INTERFACE_ID_PPB_AUDIO_INPUT_DEV, resource, result_code, socket_handle,
297 shared_memory, shared_memory_length));
298 }
299
300 int32_t PPB_AudioInput_Proxy::GetAudioInputConnectedHandles(
301 const HostResource& resource,
302 IPC::PlatformFileForTransit* foreign_socket_handle,
303 base::SharedMemoryHandle* foreign_shared_memory_handle,
304 uint32_t* shared_memory_length) {
305 // Get the audio interface which will give us the handles.
306 EnterHostFromHostResource<PPB_AudioInput_API> enter(resource);
307 if (enter.failed())
308 return PP_ERROR_NOINTERFACE;
309
310 // Get the socket handle for signaling.
311 int32_t socket_handle;
312 int32_t result = enter.object()->GetSyncSocket(&socket_handle);
313 if (result != PP_OK)
314 return result;
315
316 // socket_handle doesn't belong to us: don't close it.
317 *foreign_socket_handle = dispatcher()->ShareHandleWithRemote(
318 IntToPlatformFile(socket_handle), false);
319 if (*foreign_socket_handle == IPC::InvalidPlatformFileForTransit())
320 return PP_ERROR_FAILED;
321
322 // Get the shared memory for the buffer.
323 int shared_memory_handle;
324 result = enter.object()->GetSharedMemory(&shared_memory_handle,
325 shared_memory_length);
326 if (result != PP_OK)
327 return result;
328
329 // shared_memory_handle doesn't belong to us: don't close it.
330 *foreign_shared_memory_handle = dispatcher()->ShareHandleWithRemote(
331 IntToPlatformFile(shared_memory_handle), false);
332 if (*foreign_shared_memory_handle == IPC::InvalidPlatformFileForTransit())
333 return PP_ERROR_FAILED;
334
335 return PP_OK;
336 }
337
338 } // namespace proxy
339 } // namespace ppapi
340
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698