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