1 // Copyright (c) 2017 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_output_host.h"
6 
7 #include "base/check.h"
8 #include "base/notreached.h"
9 #include "build/build_config.h"
10 #include "content/common/pepper_file_util.h"
11 #include "content/renderer/pepper/pepper_audio_controller.h"
12 #include "content/renderer/pepper/pepper_media_device_manager.h"
13 #include "content/renderer/pepper/pepper_platform_audio_output_dev.h"
14 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
15 #include "content/renderer/pepper/renderer_ppapi_host_impl.h"
16 #include "content/renderer/render_frame_impl.h"
17 #include "ipc/ipc_message.h"
18 #include "ppapi/c/pp_errors.h"
19 #include "ppapi/host/dispatch_host_message.h"
20 #include "ppapi/host/ppapi_host.h"
21 #include "ppapi/proxy/ppapi_messages.h"
22 #include "ppapi/proxy/serialized_structs.h"
23 
24 namespace content {
25 
PepperAudioOutputHost(RendererPpapiHostImpl * host,PP_Instance instance,PP_Resource resource)26 PepperAudioOutputHost::PepperAudioOutputHost(RendererPpapiHostImpl* host,
27                                              PP_Instance instance,
28                                              PP_Resource resource)
29     : ResourceHost(host->GetPpapiHost(), instance, resource),
30       renderer_ppapi_host_(host),
31       audio_output_(nullptr),
32       enumeration_helper_(this,
33                           PepperMediaDeviceManager::GetForRenderFrame(
34                               host->GetRenderFrameForInstance(pp_instance())),
35                           PP_DEVICETYPE_DEV_AUDIOOUTPUT,
36                           host->GetDocumentURL(instance)) {
37 }
38 
~PepperAudioOutputHost()39 PepperAudioOutputHost::~PepperAudioOutputHost() {
40   PepperPluginInstanceImpl* instance = static_cast<PepperPluginInstanceImpl*>(
41       PepperPluginInstance::Get(pp_instance()));
42   if (instance) {
43     instance->audio_controller().RemoveInstance(this);
44   }
45   Close();
46 }
47 
OnResourceMessageReceived(const IPC::Message & msg,ppapi::host::HostMessageContext * context)48 int32_t PepperAudioOutputHost::OnResourceMessageReceived(
49     const IPC::Message& msg,
50     ppapi::host::HostMessageContext* context) {
51   int32_t result = PP_ERROR_FAILED;
52   if (enumeration_helper_.HandleResourceMessage(msg, context, &result))
53     return result;
54 
55   PPAPI_BEGIN_MESSAGE_MAP(PepperAudioOutputHost, msg)
56     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioOutput_Open, OnOpen)
57     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioOutput_StartOrStop,
58                                       OnStartOrStop)
59     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_AudioOutput_Close, OnClose)
60   PPAPI_END_MESSAGE_MAP()
61   return PP_ERROR_FAILED;
62 }
63 
StreamCreated(base::UnsafeSharedMemoryRegion shared_memory_region,base::SyncSocket::ScopedHandle socket)64 void PepperAudioOutputHost::StreamCreated(
65     base::UnsafeSharedMemoryRegion shared_memory_region,
66     base::SyncSocket::ScopedHandle socket) {
67   OnOpenComplete(PP_OK, std::move(shared_memory_region), std::move(socket));
68 }
69 
StreamCreationFailed()70 void PepperAudioOutputHost::StreamCreationFailed() {
71   OnOpenComplete(PP_ERROR_FAILED, base::UnsafeSharedMemoryRegion(),
72                  base::SyncSocket::ScopedHandle());
73 }
74 
SetVolume(double volume)75 void PepperAudioOutputHost::SetVolume(double volume) {
76   if (audio_output_)
77     audio_output_->SetVolume(volume);
78 }
79 
OnOpen(ppapi::host::HostMessageContext * context,const std::string & device_id,PP_AudioSampleRate sample_rate,uint32_t sample_frame_count)80 int32_t PepperAudioOutputHost::OnOpen(ppapi::host::HostMessageContext* context,
81                                       const std::string& device_id,
82                                       PP_AudioSampleRate sample_rate,
83                                       uint32_t sample_frame_count) {
84   if (open_context_.is_valid())
85     return PP_ERROR_INPROGRESS;
86 
87   if (audio_output_)
88     return PP_ERROR_FAILED;
89 
90   // When it is done, we'll get called back on StreamCreated() or
91   // StreamCreationFailed().
92   audio_output_ = PepperPlatformAudioOutputDev::Create(
93       renderer_ppapi_host_->GetRenderFrameForInstance(pp_instance())
94           ->GetRoutingID(),
95       device_id, static_cast<int>(sample_rate),
96       static_cast<int>(sample_frame_count), this);
97   if (audio_output_) {
98     open_context_ = context->MakeReplyMessageContext();
99     return PP_OK_COMPLETIONPENDING;
100   } else {
101     return PP_ERROR_FAILED;
102   }
103 }
104 
OnStartOrStop(ppapi::host::HostMessageContext *,bool playback)105 int32_t PepperAudioOutputHost::OnStartOrStop(
106     ppapi::host::HostMessageContext* /* context */,
107     bool playback) {
108   if (!audio_output_)
109     return PP_ERROR_FAILED;
110 
111   PepperPluginInstanceImpl* instance = static_cast<PepperPluginInstanceImpl*>(
112       PepperPluginInstance::Get(pp_instance()));
113 
114   if (playback) {
115     if (instance)
116       instance->audio_controller().AddInstance(this);
117 
118     audio_output_->StartPlayback();
119   } else {
120     if (instance)
121       instance->audio_controller().RemoveInstance(this);
122 
123     audio_output_->StopPlayback();
124   }
125   return PP_OK;
126 }
127 
OnClose(ppapi::host::HostMessageContext *)128 int32_t PepperAudioOutputHost::OnClose(
129     ppapi::host::HostMessageContext* /* context */) {
130   Close();
131   return PP_OK;
132 }
133 
OnOpenComplete(int32_t result,base::UnsafeSharedMemoryRegion shared_memory_region,base::SyncSocket::ScopedHandle socket_handle)134 void PepperAudioOutputHost::OnOpenComplete(
135     int32_t result,
136     base::UnsafeSharedMemoryRegion shared_memory_region,
137     base::SyncSocket::ScopedHandle socket_handle) {
138   // Make sure the handles are cleaned up.
139   base::SyncSocket scoped_socket(std::move(socket_handle));
140 
141   if (!open_context_.is_valid()) {
142     NOTREACHED();
143     return;
144   }
145 
146   ppapi::proxy::SerializedHandle serialized_socket_handle(
147       ppapi::proxy::SerializedHandle::SOCKET);
148   ppapi::proxy::SerializedHandle serialized_shared_memory_handle(
149       ppapi::proxy::SerializedHandle::SHARED_MEMORY_REGION);
150 
151   if (result == PP_OK) {
152     IPC::PlatformFileForTransit temp_socket =
153         IPC::InvalidPlatformFileForTransit();
154     base::UnsafeSharedMemoryRegion temp_shmem;
155     result = GetRemoteHandles(scoped_socket, shared_memory_region, &temp_socket,
156                               &temp_shmem);
157 
158     serialized_socket_handle.set_socket(temp_socket);
159     serialized_shared_memory_handle.set_shmem_region(
160         base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
161             std::move(temp_shmem)));
162   }
163 
164   // Send all the values, even on error. This simplifies some of our cleanup
165   // code since the handles will be in the other process and could be
166   // inconvenient to clean up. Our IPC code will automatically handle this for
167   // us, as long as the remote side always closes the handles it receives, even
168   // in the failure case.
169   open_context_.params.AppendHandle(std::move(serialized_socket_handle));
170   open_context_.params.AppendHandle(std::move(serialized_shared_memory_handle));
171   SendOpenReply(result);
172 }
173 
GetRemoteHandles(const base::SyncSocket & socket,const base::UnsafeSharedMemoryRegion & shared_memory_region,IPC::PlatformFileForTransit * remote_socket_handle,base::UnsafeSharedMemoryRegion * remote_shared_memory_region)174 int32_t PepperAudioOutputHost::GetRemoteHandles(
175     const base::SyncSocket& socket,
176     const base::UnsafeSharedMemoryRegion& shared_memory_region,
177     IPC::PlatformFileForTransit* remote_socket_handle,
178     base::UnsafeSharedMemoryRegion* remote_shared_memory_region) {
179   *remote_socket_handle =
180       renderer_ppapi_host_->ShareHandleWithRemote(socket.handle(), false);
181   if (*remote_socket_handle == IPC::InvalidPlatformFileForTransit())
182     return PP_ERROR_FAILED;
183 
184   *remote_shared_memory_region =
185       renderer_ppapi_host_->ShareUnsafeSharedMemoryRegionWithRemote(
186           shared_memory_region);
187   if (!remote_shared_memory_region->IsValid())
188     return PP_ERROR_FAILED;
189 
190   return PP_OK;
191 }
192 
Close()193 void PepperAudioOutputHost::Close() {
194   if (!audio_output_)
195     return;
196 
197   audio_output_->ShutDown();
198   audio_output_ = nullptr;
199 
200   if (open_context_.is_valid())
201     SendOpenReply(PP_ERROR_ABORTED);
202 }
203 
SendOpenReply(int32_t result)204 void PepperAudioOutputHost::SendOpenReply(int32_t result) {
205   open_context_.params.set_result(result);
206   host()->SendReply(open_context_, PpapiPluginMsg_AudioOutput_OpenReply());
207   open_context_ = ppapi::host::ReplyMessageContext();
208 }
209 
210 }  // namespace content
211