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 "media/audio/shared_memory_util.h" 16#include "ppapi/c/pp_errors.h" 17#include "ppapi/host/dispatch_host_message.h" 18#include "ppapi/host/ppapi_host.h" 19#include "ppapi/proxy/ppapi_messages.h" 20#include "ppapi/proxy/serialized_structs.h" 21#include "third_party/WebKit/public/web/WebDocument.h" 22#include "third_party/WebKit/public/web/WebElement.h" 23#include "third_party/WebKit/public/web/WebPluginContainer.h" 24 25namespace content { 26 27namespace { 28 29base::PlatformFile ConvertSyncSocketHandle(const base::SyncSocket& socket) { 30 return socket.handle(); 31} 32 33base::PlatformFile ConvertSharedMemoryHandle( 34 const base::SharedMemory& shared_memory) { 35#if defined(OS_POSIX) 36 return shared_memory.handle().fd; 37#elif defined(OS_WIN) 38 return shared_memory.handle(); 39#else 40#error "Platform not supported." 41#endif 42} 43 44} // namespace 45 46PepperAudioInputHost::PepperAudioInputHost( 47 RendererPpapiHostImpl* host, 48 PP_Instance instance, 49 PP_Resource resource) 50 : ResourceHost(host->GetPpapiHost(), instance, resource), 51 renderer_ppapi_host_(host), 52 audio_input_(NULL), 53 enumeration_helper_( 54 this, 55 PepperMediaDeviceManager::GetForRenderView( 56 host->GetRenderViewForInstance(pp_instance())), 57 PP_DEVICETYPE_DEV_AUDIOCAPTURE) { 58} 59 60PepperAudioInputHost::~PepperAudioInputHost() { 61 Close(); 62} 63 64int32_t PepperAudioInputHost::OnResourceMessageReceived( 65 const IPC::Message& msg, 66 ppapi::host::HostMessageContext* context) { 67 int32_t result = PP_ERROR_FAILED; 68 if (enumeration_helper_.HandleResourceMessage(msg, context, &result)) 69 return result; 70 71 IPC_BEGIN_MESSAGE_MAP(PepperAudioInputHost, msg) 72 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioInput_Open, OnOpen) 73 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioInput_StartOrStop, 74 OnStartOrStop); 75 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_AudioInput_Close, 76 OnClose); 77 IPC_END_MESSAGE_MAP() 78 return PP_ERROR_FAILED; 79} 80 81void PepperAudioInputHost::StreamCreated( 82 base::SharedMemoryHandle shared_memory_handle, 83 size_t shared_memory_size, 84 base::SyncSocket::Handle socket) { 85 OnOpenComplete(PP_OK, shared_memory_handle, shared_memory_size, socket); 86} 87 88void PepperAudioInputHost::StreamCreationFailed() { 89 OnOpenComplete(PP_ERROR_FAILED, base::SharedMemory::NULLHandle(), 0, 90 base::SyncSocket::kInvalidHandle); 91} 92 93int32_t PepperAudioInputHost::OnOpen( 94 ppapi::host::HostMessageContext* context, 95 const std::string& device_id, 96 PP_AudioSampleRate sample_rate, 97 uint32_t sample_frame_count) { 98 if (open_context_) 99 return PP_ERROR_INPROGRESS; 100 if (audio_input_) 101 return PP_ERROR_FAILED; 102 103 PepperPluginInstanceImpl* instance = 104 renderer_ppapi_host_->GetPluginInstanceImpl(pp_instance()); 105 if (!instance) 106 return PP_ERROR_FAILED; 107 108 // When it is done, we'll get called back on StreamCreated() or 109 // StreamCreationFailed(). 110 RenderViewImpl* render_view = static_cast<RenderViewImpl*>( 111 renderer_ppapi_host_->GetRenderViewForInstance(pp_instance())); 112 113 audio_input_ = PepperPlatformAudioInput::Create( 114 render_view->AsWeakPtr(), device_id, 115 instance->container()->element().document().url(), 116 static_cast<int>(sample_rate), 117 static_cast<int>(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