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