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 "content/renderer/pepper/pepper_audio_input_host.h"
7 #include "base/logging.h"
8 #include "build/build_config.h"
9 #include "content/public/renderer/renderer_ppapi_host.h"
10 #include "ipc/ipc_message.h"
11 #include "media/audio/shared_memory_util.h"
12 #include "ppapi/c/pp_errors.h"
13 #include "ppapi/host/dispatch_host_message.h"
14 #include "ppapi/host/ppapi_host.h"
15 #include "ppapi/proxy/ppapi_messages.h"
16 #include "ppapi/proxy/serialized_structs.h"
17 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
23 base::PlatformFile
ConvertSyncSocketHandle(const base::SyncSocket
& socket
) {
24 return socket
.handle();
27 base::PlatformFile
ConvertSharedMemoryHandle(
28 const base::SharedMemory
& shared_memory
) {
30 return shared_memory
.handle().fd
;
32 return shared_memory
.handle();
34 #error "Platform not supported."
40 PepperAudioInputHost::PepperAudioInputHost(
41 RendererPpapiHost
* host
,
44 : ResourceHost(host
->GetPpapiHost(), instance
, resource
),
45 renderer_ppapi_host_(host
),
47 ALLOW_THIS_IN_INITIALIZER_LIST(
48 enumeration_helper_(this, this, PP_DEVICETYPE_DEV_AUDIOCAPTURE
)) {
51 PepperAudioInputHost::~PepperAudioInputHost() {
55 int32_t PepperAudioInputHost::OnResourceMessageReceived(
56 const IPC::Message
& msg
,
57 ppapi::host::HostMessageContext
* context
) {
58 int32_t result
= PP_ERROR_FAILED
;
59 if (enumeration_helper_
.HandleResourceMessage(msg
, context
, &result
))
62 IPC_BEGIN_MESSAGE_MAP(PepperAudioInputHost
, msg
)
63 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioInput_Open
, OnMsgOpen
)
64 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioInput_StartOrStop
,
66 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_AudioInput_Close
,
69 return PP_ERROR_FAILED
;
72 void PepperAudioInputHost::StreamCreated(
73 base::SharedMemoryHandle shared_memory_handle
,
74 size_t shared_memory_size
,
75 base::SyncSocket::Handle socket
) {
76 OnOpenComplete(PP_OK
, shared_memory_handle
, shared_memory_size
, socket
);
79 void PepperAudioInputHost::StreamCreationFailed() {
80 OnOpenComplete(PP_ERROR_FAILED
, base::SharedMemory::NULLHandle(), 0,
81 base::SyncSocket::kInvalidHandle
);
84 webkit::ppapi::PluginDelegate
* PepperAudioInputHost::GetPluginDelegate() {
85 webkit::ppapi::PluginInstance
* instance
=
86 renderer_ppapi_host_
->GetPluginInstance(pp_instance());
88 return instance
->delegate();
92 int32_t PepperAudioInputHost::OnMsgOpen(
93 ppapi::host::HostMessageContext
* context
,
94 const std::string
& device_id
,
95 PP_AudioSampleRate sample_rate
,
96 uint32_t sample_frame_count
) {
97 if (open_context_
.get())
98 return PP_ERROR_INPROGRESS
;
100 return PP_ERROR_FAILED
;
102 webkit::ppapi::PluginDelegate
* plugin_delegate
= GetPluginDelegate();
103 if (!plugin_delegate
)
104 return PP_ERROR_FAILED
;
106 // When it is done, we'll get called back on StreamCreated() or
107 // StreamCreationFailed().
108 audio_input_
= plugin_delegate
->CreateAudioInput(
109 device_id
, sample_rate
, sample_frame_count
, this);
111 open_context_
.reset(new ppapi::host::ReplyMessageContext(
112 context
->MakeReplyMessageContext()));
113 return PP_OK_COMPLETIONPENDING
;
115 return PP_ERROR_FAILED
;
119 int32_t PepperAudioInputHost::OnMsgStartOrStop(
120 ppapi::host::HostMessageContext
* /* context */,
123 return PP_ERROR_FAILED
;
125 audio_input_
->StartCapture();
127 audio_input_
->StopCapture();
131 int32_t PepperAudioInputHost::OnMsgClose(
132 ppapi::host::HostMessageContext
* /* context */) {
137 void PepperAudioInputHost::OnOpenComplete(
139 base::SharedMemoryHandle shared_memory_handle
,
140 size_t shared_memory_size
,
141 base::SyncSocket::Handle socket_handle
) {
142 // Make sure the handles are cleaned up.
143 base::SyncSocket
scoped_socket(socket_handle
);
144 base::SharedMemory
scoped_shared_memory(shared_memory_handle
, false);
146 if (!open_context_
.get()) {
151 ppapi::proxy::SerializedHandle
serialized_socket_handle(
152 ppapi::proxy::SerializedHandle::SOCKET
);
153 ppapi::proxy::SerializedHandle
serialized_shared_memory_handle(
154 ppapi::proxy::SerializedHandle::SHARED_MEMORY
);
156 if (result
== PP_OK
) {
157 IPC::PlatformFileForTransit temp_socket
=
158 IPC::InvalidPlatformFileForTransit();
159 base::SharedMemoryHandle temp_shmem
= base::SharedMemory::NULLHandle();
160 result
= GetRemoteHandles(
161 scoped_socket
, scoped_shared_memory
, &temp_socket
, &temp_shmem
);
163 serialized_socket_handle
.set_socket(temp_socket
);
164 // Note that we must call TotalSharedMemorySizeInBytes() because extra space
165 // in shared memory is allocated for book-keeping, so the actual size of the
166 // shared memory buffer is larger than |shared_memory_size|. When sending to
167 // NaCl, NaClIPCAdapter expects this size to match the size of the full
168 // shared memory buffer.
169 serialized_shared_memory_handle
.set_shmem(
170 temp_shmem
, media::TotalSharedMemorySizeInBytes(shared_memory_size
));
173 // Send all the values, even on error. This simplifies some of our cleanup
174 // code since the handles will be in the other process and could be
175 // inconvenient to clean up. Our IPC code will automatically handle this for
176 // us, as long as the remote side always closes the handles it receives, even
177 // in the failure case.
178 open_context_
->params
.set_result(result
);
179 open_context_
->params
.AppendHandle(serialized_socket_handle
);
180 open_context_
->params
.AppendHandle(serialized_shared_memory_handle
);
182 host()->SendReply(*open_context_
, PpapiPluginMsg_AudioInput_OpenReply());
183 open_context_
.reset();
186 int32_t PepperAudioInputHost::GetRemoteHandles(
187 const base::SyncSocket
& socket
,
188 const base::SharedMemory
& shared_memory
,
189 IPC::PlatformFileForTransit
* remote_socket_handle
,
190 base::SharedMemoryHandle
* remote_shared_memory_handle
) {
191 *remote_socket_handle
= renderer_ppapi_host_
->ShareHandleWithRemote(
192 ConvertSyncSocketHandle(socket
), false);
193 if (*remote_socket_handle
== IPC::InvalidPlatformFileForTransit())
194 return PP_ERROR_FAILED
;
196 *remote_shared_memory_handle
= renderer_ppapi_host_
->ShareHandleWithRemote(
197 ConvertSharedMemoryHandle(shared_memory
), false);
198 if (*remote_shared_memory_handle
== IPC::InvalidPlatformFileForTransit())
199 return PP_ERROR_FAILED
;
204 void PepperAudioInputHost::Close() {
208 audio_input_
->ShutDown();
211 if (open_context_
.get()) {
212 open_context_
->params
.set_result(PP_ERROR_ABORTED
);
213 host()->SendReply(*open_context_
, PpapiPluginMsg_AudioInput_OpenReply());
214 open_context_
.reset();
218 } // namespace content