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