- add sources.
[platform/framework/web/crosswalk.git] / src / content / renderer / pepper / pepper_audio_input_host.cc
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 "content/renderer/pepper/pepper_audio_input_host.h"
6
7 #include "base/logging.h"
8 #include "build/build_config.h"
9 #include "content/renderer/pepper/pepper_media_device_manager.h"
10 #include "content/renderer/pepper/pepper_platform_audio_input.h"
11 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
12 #include "content/renderer/pepper/renderer_ppapi_host_impl.h"
13 #include "content/renderer/render_view_impl.h"
14 #include "ipc/ipc_message.h"
15 #include "ppapi/c/pp_errors.h"
16 #include "ppapi/host/dispatch_host_message.h"
17 #include "ppapi/host/ppapi_host.h"
18 #include "ppapi/proxy/ppapi_messages.h"
19 #include "ppapi/proxy/serialized_structs.h"
20 #include "third_party/WebKit/public/web/WebDocument.h"
21 #include "third_party/WebKit/public/web/WebElement.h"
22 #include "third_party/WebKit/public/web/WebPluginContainer.h"
23
24 namespace content {
25
26 namespace {
27
28 base::PlatformFile ConvertSyncSocketHandle(const base::SyncSocket& socket) {
29   return socket.handle();
30 }
31
32 base::PlatformFile ConvertSharedMemoryHandle(
33     const base::SharedMemory& shared_memory) {
34 #if defined(OS_POSIX)
35   return shared_memory.handle().fd;
36 #elif defined(OS_WIN)
37   return shared_memory.handle();
38 #else
39 #error "Platform not supported."
40 #endif
41 }
42
43 }  // namespace
44
45 PepperAudioInputHost::PepperAudioInputHost(
46     RendererPpapiHostImpl* host,
47     PP_Instance instance,
48     PP_Resource resource)
49     : ResourceHost(host->GetPpapiHost(), instance, resource),
50       renderer_ppapi_host_(host),
51       audio_input_(NULL),
52       enumeration_helper_(
53           this,
54           PepperMediaDeviceManager::GetForRenderView(
55               host->GetRenderViewForInstance(pp_instance())),
56           PP_DEVICETYPE_DEV_AUDIOCAPTURE) {
57 }
58
59 PepperAudioInputHost::~PepperAudioInputHost() {
60   Close();
61 }
62
63 int32_t PepperAudioInputHost::OnResourceMessageReceived(
64     const IPC::Message& msg,
65     ppapi::host::HostMessageContext* context) {
66   int32_t result = PP_ERROR_FAILED;
67   if (enumeration_helper_.HandleResourceMessage(msg, context, &result))
68     return result;
69
70   IPC_BEGIN_MESSAGE_MAP(PepperAudioInputHost, msg)
71     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioInput_Open, OnOpen)
72     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioInput_StartOrStop,
73                                       OnStartOrStop);
74     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_AudioInput_Close,
75                                         OnClose);
76   IPC_END_MESSAGE_MAP()
77   return PP_ERROR_FAILED;
78 }
79
80 void PepperAudioInputHost::StreamCreated(
81     base::SharedMemoryHandle shared_memory_handle,
82     size_t shared_memory_size,
83     base::SyncSocket::Handle socket) {
84   OnOpenComplete(PP_OK, shared_memory_handle, shared_memory_size, socket);
85 }
86
87 void PepperAudioInputHost::StreamCreationFailed() {
88   OnOpenComplete(PP_ERROR_FAILED, base::SharedMemory::NULLHandle(), 0,
89                  base::SyncSocket::kInvalidHandle);
90 }
91
92 int32_t PepperAudioInputHost::OnOpen(
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_)
98     return PP_ERROR_INPROGRESS;
99   if (audio_input_)
100     return PP_ERROR_FAILED;
101
102   PepperPluginInstanceImpl* instance =
103       renderer_ppapi_host_->GetPluginInstanceImpl(pp_instance());
104   if (!instance)
105     return PP_ERROR_FAILED;
106
107   // When it is done, we'll get called back on StreamCreated() or
108   // StreamCreationFailed().
109   RenderViewImpl* render_view = static_cast<RenderViewImpl*>(
110       renderer_ppapi_host_->GetRenderViewForInstance(pp_instance()));
111
112   audio_input_ = PepperPlatformAudioInput::Create(
113       render_view->AsWeakPtr(), device_id,
114       instance->container()->element().document().url(),
115       static_cast<int>(sample_rate),
116       static_cast<int>(sample_frame_count), this);
117   if (audio_input_) {
118     open_context_.reset(new ppapi::host::ReplyMessageContext(
119         context->MakeReplyMessageContext()));
120     return PP_OK_COMPLETIONPENDING;
121   } else {
122     return PP_ERROR_FAILED;
123   }
124 }
125
126 int32_t PepperAudioInputHost::OnStartOrStop(
127     ppapi::host::HostMessageContext* /* context */,
128     bool capture) {
129   if (!audio_input_)
130     return PP_ERROR_FAILED;
131   if (capture)
132     audio_input_->StartCapture();
133   else
134     audio_input_->StopCapture();
135   return PP_OK;
136 }
137
138 int32_t PepperAudioInputHost::OnClose(
139     ppapi::host::HostMessageContext* /* context */) {
140   Close();
141   return PP_OK;
142 }
143
144 void PepperAudioInputHost::OnOpenComplete(
145     int32_t result,
146     base::SharedMemoryHandle shared_memory_handle,
147     size_t shared_memory_size,
148     base::SyncSocket::Handle socket_handle) {
149   // Make sure the handles are cleaned up.
150   base::SyncSocket scoped_socket(socket_handle);
151   base::SharedMemory scoped_shared_memory(shared_memory_handle, false);
152
153   if (!open_context_) {
154     NOTREACHED();
155     return;
156   }
157
158   ppapi::proxy::SerializedHandle serialized_socket_handle(
159       ppapi::proxy::SerializedHandle::SOCKET);
160   ppapi::proxy::SerializedHandle serialized_shared_memory_handle(
161       ppapi::proxy::SerializedHandle::SHARED_MEMORY);
162
163   if (result == PP_OK) {
164     IPC::PlatformFileForTransit temp_socket =
165         IPC::InvalidPlatformFileForTransit();
166     base::SharedMemoryHandle temp_shmem = base::SharedMemory::NULLHandle();
167     result = GetRemoteHandles(
168         scoped_socket, scoped_shared_memory, &temp_socket, &temp_shmem);
169
170     serialized_socket_handle.set_socket(temp_socket);
171     serialized_shared_memory_handle.set_shmem(temp_shmem, shared_memory_size);
172   }
173
174   // Send all the values, even on error. This simplifies some of our cleanup
175   // code since the handles will be in the other process and could be
176   // inconvenient to clean up. Our IPC code will automatically handle this for
177   // us, as long as the remote side always closes the handles it receives, even
178   // in the failure case.
179   open_context_->params.set_result(result);
180   open_context_->params.AppendHandle(serialized_socket_handle);
181   open_context_->params.AppendHandle(serialized_shared_memory_handle);
182
183   host()->SendReply(*open_context_, PpapiPluginMsg_AudioInput_OpenReply());
184   open_context_.reset();
185 }
186
187 int32_t PepperAudioInputHost::GetRemoteHandles(
188     const base::SyncSocket& socket,
189     const base::SharedMemory& shared_memory,
190     IPC::PlatformFileForTransit* remote_socket_handle,
191     base::SharedMemoryHandle* remote_shared_memory_handle) {
192   *remote_socket_handle = renderer_ppapi_host_->ShareHandleWithRemote(
193       ConvertSyncSocketHandle(socket), false);
194   if (*remote_socket_handle == IPC::InvalidPlatformFileForTransit())
195     return PP_ERROR_FAILED;
196
197   *remote_shared_memory_handle = renderer_ppapi_host_->ShareHandleWithRemote(
198       ConvertSharedMemoryHandle(shared_memory), false);
199   if (*remote_shared_memory_handle == IPC::InvalidPlatformFileForTransit())
200     return PP_ERROR_FAILED;
201
202   return PP_OK;
203 }
204
205 void PepperAudioInputHost::Close() {
206   if (!audio_input_)
207     return;
208
209   audio_input_->ShutDown();
210   audio_input_ = NULL;
211
212   if (open_context_) {
213     open_context_->params.set_result(PP_ERROR_ABORTED);
214     host()->SendReply(*open_context_, PpapiPluginMsg_AudioInput_OpenReply());
215     open_context_.reset();
216   }
217 }
218
219 }  // namespace content
220