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