blob: 62cb8c3fb2943bd2b1752aa513d07a4ad118493c [file] [log] [blame]
[email protected]00d320a2012-02-14 00:27:041// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]5d84d012010-12-02 17:17:212// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ppapi/proxy/ppb_audio_proxy.h"
6
[email protected]79d23c72011-08-08 19:40:407#include "base/compiler_specific.h"
[email protected]ac9ba8fe2010-12-30 18:08:368#include "base/threading/simple_thread.h"
avie029c4132015-12-23 06:45:229#include "build/build_config.h"
[email protected]5d84d012010-12-02 17:17:2110#include "ppapi/c/pp_errors.h"
[email protected]b9a59842011-01-15 01:04:0011#include "ppapi/c/ppb_audio.h"
[email protected]55cdf6052011-05-13 19:22:5312#include "ppapi/c/ppb_audio_config.h"
13#include "ppapi/c/ppb_var.h"
[email protected]cd910b92011-06-01 07:19:3114#include "ppapi/proxy/enter_proxy.h"
[email protected]5d84d012010-12-02 17:17:2115#include "ppapi/proxy/plugin_dispatcher.h"
[email protected]5d84d012010-12-02 17:17:2116#include "ppapi/proxy/ppapi_messages.h"
[email protected]ac4b54d2011-10-20 23:09:2817#include "ppapi/shared_impl/api_id.h"
[email protected]5a77eca2011-11-23 23:46:4618#include "ppapi/shared_impl/platform_file.h"
[email protected]794d83cd2011-10-20 19:09:2019#include "ppapi/shared_impl/ppapi_globals.h"
[email protected]9a578392011-12-07 18:59:2720#include "ppapi/shared_impl/ppb_audio_shared.h"
[email protected]7f8b26b2011-08-18 15:41:0121#include "ppapi/shared_impl/resource.h"
[email protected]55cdf6052011-05-13 19:22:5322#include "ppapi/thunk/enter.h"
avie029c4132015-12-23 06:45:2223#include "ppapi/thunk/ppb_audio_config_api.h"
[email protected]55cdf6052011-05-13 19:22:5324#include "ppapi/thunk/resource_creation_api.h"
25#include "ppapi/thunk/thunk.h"
[email protected]5d84d012010-12-02 17:17:2126
[email protected]5a77eca2011-11-23 23:46:4627using ppapi::IntToPlatformFile;
[email protected]8510d282012-08-30 19:47:3828using ppapi::proxy::SerializedHandle;
[email protected]79d23c72011-08-08 19:40:4029using ppapi::thunk::EnterResourceNoLock;
30using ppapi::thunk::PPB_Audio_API;
31using ppapi::thunk::PPB_AudioConfig_API;
[email protected]cd910b92011-06-01 07:19:3132
[email protected]4d2efd22011-08-18 21:58:0233namespace ppapi {
[email protected]5d84d012010-12-02 17:17:2134namespace proxy {
35
[email protected]9a578392011-12-07 18:59:2736class Audio : public Resource, public PPB_Audio_Shared {
[email protected]5d84d012010-12-02 17:17:2137 public:
[email protected]f24448db2011-01-27 20:40:3938 Audio(const HostResource& audio_id,
[email protected]4614f192011-01-21 00:26:4339 PP_Resource config_id,
[email protected]6b1511262013-09-06 21:46:3440 const AudioCallbackCombined& callback,
[email protected]55cdf6052011-05-13 19:22:5341 void* user_data);
Peter Boström3d5b3cb2021-09-23 21:35:4542
43 Audio(const Audio&) = delete;
44 Audio& operator=(const Audio&) = delete;
45
jvoungbd2e01dd2015-01-21 20:35:3946 ~Audio() override;
[email protected]5d84d012010-12-02 17:17:2147
[email protected]7f8b26b2011-08-18 15:41:0148 // Resource overrides.
jvoungbd2e01dd2015-01-21 20:35:3949 PPB_Audio_API* AsPPB_Audio_API() override;
[email protected]5d84d012010-12-02 17:17:2150
[email protected]55cdf6052011-05-13 19:22:5351 // PPB_Audio_API implementation.
jvoungbd2e01dd2015-01-21 20:35:3952 PP_Resource GetCurrentConfig() override;
53 PP_Bool StartPlayback() override;
54 PP_Bool StopPlayback() override;
55 int32_t Open(PP_Resource config_id,
56 scoped_refptr<TrackedCallback> create_callback) override;
57 int32_t GetSyncSocket(int* sync_socket) override;
Alexandr Ilin20f2841c2018-06-01 11:56:1858 int32_t GetSharedMemory(base::UnsafeSharedMemoryRegion** shm) override;
[email protected]5d84d012010-12-02 17:17:2159
60 private:
[email protected]55cdf6052011-05-13 19:22:5361 // Owning reference to the current config object. This isn't actually used,
62 // we just dish it out as requested by the plugin.
[email protected]5d84d012010-12-02 17:17:2163 PP_Resource config_;
[email protected]5d84d012010-12-02 17:17:2164};
65
[email protected]55cdf6052011-05-13 19:22:5366Audio::Audio(const HostResource& audio_id,
67 PP_Resource config_id,
[email protected]6b1511262013-09-06 21:46:3468 const AudioCallbackCombined& callback,
[email protected]55cdf6052011-05-13 19:22:5369 void* user_data)
[email protected]00d320a2012-02-14 00:27:0470 : Resource(OBJECT_IS_PROXY, audio_id),
[email protected]55cdf6052011-05-13 19:22:5371 config_(config_id) {
72 SetCallback(callback, user_data);
[email protected]794d83cd2011-10-20 19:09:2073 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(config_);
[email protected]55cdf6052011-05-13 19:22:5374}
75
76Audio::~Audio() {
Xiaohan Wang0fd6e56a2022-01-13 20:26:1177#if BUILDFLAG(IS_NACL)
[email protected]4310fd82012-09-20 23:38:2978 // Invoke StopPlayback() to ensure audio back-end has a chance to send the
79 // escape value over the sync socket, which will terminate the client side
80 // audio callback loop. This is required for NaCl Plugins that can't escape
81 // by shutting down the sync_socket.
82 StopPlayback();
83#endif
[email protected]794d83cd2011-10-20 19:09:2084 PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(config_);
[email protected]55cdf6052011-05-13 19:22:5385}
86
[email protected]cd910b92011-06-01 07:19:3187PPB_Audio_API* Audio::AsPPB_Audio_API() {
[email protected]55cdf6052011-05-13 19:22:5388 return this;
89}
90
91PP_Resource Audio::GetCurrentConfig() {
92 // AddRef for the caller.
[email protected]794d83cd2011-10-20 19:09:2093 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(config_);
[email protected]55cdf6052011-05-13 19:22:5394 return config_;
95}
96
97PP_Bool Audio::StartPlayback() {
98 if (playing())
99 return PP_TRUE;
[email protected]a4a01e42014-04-21 10:36:21100 if (!PPB_Audio_Shared::IsThreadFunctionReady())
101 return PP_FALSE;
[email protected]55cdf6052011-05-13 19:22:53102 SetStartPlaybackState();
[email protected]7f8b26b2011-08-18 15:41:01103 PluginDispatcher::GetForResource(this)->Send(
[email protected]55cdf6052011-05-13 19:22:53104 new PpapiHostMsg_PPBAudio_StartOrStop(
[email protected]ac4b54d2011-10-20 23:09:28105 API_ID_PPB_AUDIO, host_resource(), true));
[email protected]55cdf6052011-05-13 19:22:53106 return PP_TRUE;
107}
108
109PP_Bool Audio::StopPlayback() {
110 if (!playing())
111 return PP_TRUE;
[email protected]7f8b26b2011-08-18 15:41:01112 PluginDispatcher::GetForResource(this)->Send(
[email protected]55cdf6052011-05-13 19:22:53113 new PpapiHostMsg_PPBAudio_StartOrStop(
[email protected]ac4b54d2011-10-20 23:09:28114 API_ID_PPB_AUDIO, host_resource(), false));
[email protected]55cdf6052011-05-13 19:22:53115 SetStopPlaybackState();
116 return PP_TRUE;
117}
118
[email protected]9590f8602013-04-23 18:55:21119int32_t Audio::Open(PP_Resource config_id,
120 scoped_refptr<TrackedCallback> create_callback) {
[email protected]79d23c72011-08-08 19:40:40121 return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface.
122}
123
124int32_t Audio::GetSyncSocket(int* sync_socket) {
125 return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface.
126}
127
Alexandr Ilin20f2841c2018-06-01 11:56:18128int32_t Audio::GetSharedMemory(base::UnsafeSharedMemoryRegion** shm) {
[email protected]79d23c72011-08-08 19:40:40129 return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface.
130}
131
[email protected]5c966022011-09-13 18:09:37132PPB_Audio_Proxy::PPB_Audio_Proxy(Dispatcher* dispatcher)
133 : InterfaceProxy(dispatcher),
[email protected]a2f53dc2013-04-30 01:06:35134 callback_factory_(this) {
[email protected]5d84d012010-12-02 17:17:21135}
136
137PPB_Audio_Proxy::~PPB_Audio_Proxy() {
138}
139
[email protected]465faa22011-02-08 16:31:46140// static
[email protected]55cdf6052011-05-13 19:22:53141PP_Resource PPB_Audio_Proxy::CreateProxyResource(
142 PP_Instance instance_id,
143 PP_Resource config_id,
[email protected]6b1511262013-09-06 21:46:34144 const AudioCallbackCombined& audio_callback,
[email protected]55cdf6052011-05-13 19:22:53145 void* user_data) {
146 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id);
147 if (!dispatcher)
148 return 0;
149
[email protected]79d23c72011-08-08 19:40:40150 EnterResourceNoLock<PPB_AudioConfig_API> config(config_id, true);
[email protected]55cdf6052011-05-13 19:22:53151 if (config.failed())
152 return 0;
153
[email protected]6b1511262013-09-06 21:46:34154 if (!audio_callback.IsValid())
[email protected]c6b2b7f2011-12-01 02:38:25155 return 0;
156
[email protected]55cdf6052011-05-13 19:22:53157 HostResource result;
158 dispatcher->Send(new PpapiHostMsg_PPBAudio_Create(
[email protected]ac4b54d2011-10-20 23:09:28159 API_ID_PPB_AUDIO, instance_id,
[email protected]55cdf6052011-05-13 19:22:53160 config.object()->GetSampleRate(), config.object()->GetSampleFrameCount(),
161 &result));
162 if (result.is_null())
163 return 0;
164
[email protected]bab65ef2011-08-20 04:53:22165 return (new Audio(result, config_id,
166 audio_callback, user_data))->GetReference();
[email protected]55cdf6052011-05-13 19:22:53167}
168
[email protected]a95986a82010-12-24 06:19:28169bool PPB_Audio_Proxy::OnMessageReceived(const IPC::Message& msg) {
170 bool handled = true;
[email protected]5d84d012010-12-02 17:17:21171 IPC_BEGIN_MESSAGE_MAP(PPB_Audio_Proxy, msg)
[email protected]771fc8d2012-05-19 01:39:05172// Don't build host side into NaCl IRT.
Xiaohan Wang0fd6e56a2022-01-13 20:26:11173#if !BUILDFLAG(IS_NACL)
[email protected]5d84d012010-12-02 17:17:21174 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_Create, OnMsgCreate)
175 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_StartOrStop,
176 OnMsgStartOrStop)
[email protected]771fc8d2012-05-19 01:39:05177#endif
[email protected]5d84d012010-12-02 17:17:21178 IPC_MESSAGE_HANDLER(PpapiMsg_PPBAudio_NotifyAudioStreamCreated,
179 OnMsgNotifyAudioStreamCreated)
[email protected]a95986a82010-12-24 06:19:28180 IPC_MESSAGE_UNHANDLED(handled = false)
[email protected]5d84d012010-12-02 17:17:21181 IPC_END_MESSAGE_MAP()
[email protected]a95986a82010-12-24 06:19:28182 return handled;
[email protected]5d84d012010-12-02 17:17:21183}
184
Xiaohan Wang0fd6e56a2022-01-13 20:26:11185#if !BUILDFLAG(IS_NACL)
[email protected]5d84d012010-12-02 17:17:21186void PPB_Audio_Proxy::OnMsgCreate(PP_Instance instance_id,
[email protected]55cdf6052011-05-13 19:22:53187 int32_t sample_rate,
188 uint32_t sample_frame_count,
[email protected]f24448db2011-01-27 20:40:39189 HostResource* result) {
[email protected]4f2006122012-04-30 05:13:17190 thunk::EnterResourceCreation resource_creation(instance_id);
[email protected]55cdf6052011-05-13 19:22:53191 if (resource_creation.failed())
[email protected]5d84d012010-12-02 17:17:21192 return;
[email protected]5d84d012010-12-02 17:17:21193
[email protected]55cdf6052011-05-13 19:22:53194 // Make the resource and get the API pointer to its trusted interface.
195 result->SetHostResource(
196 instance_id,
197 resource_creation.functions()->CreateAudioTrusted(instance_id));
[email protected]f24448db2011-01-27 20:40:39198 if (result->is_null())
[email protected]5d84d012010-12-02 17:17:21199 return;
[email protected]79d23c72011-08-08 19:40:40200
201 // At this point, we've set the result resource, and this is a sync request.
202 // Anything below this point must issue the AudioChannelConnected callback
203 // to the browser. Since that's an async message, it will be issued back to
204 // the plugin after the Create function returns (which is good because it
205 // would be weird to get a connected message with a failure code for a
206 // resource you haven't finished creating yet).
207 //
208 // The ...ForceCallback class will help ensure the callback is always called.
209 // All error cases must call SetResult on this class.
210 EnterHostFromHostResourceForceCallback<PPB_Audio_API> enter(
211 *result, callback_factory_,
212 &PPB_Audio_Proxy::AudioChannelConnected, *result);
213 if (enter.failed())
214 return; // When enter fails, it will internally schedule the callback.
[email protected]5d84d012010-12-02 17:17:21215
[email protected]55cdf6052011-05-13 19:22:53216 // Make an audio config object.
217 PP_Resource audio_config_res =
218 resource_creation.functions()->CreateAudioConfig(
219 instance_id, static_cast<PP_AudioSampleRate>(sample_rate),
220 sample_frame_count);
[email protected]79d23c72011-08-08 19:40:40221 if (!audio_config_res) {
222 enter.SetResult(PP_ERROR_FAILED);
[email protected]55cdf6052011-05-13 19:22:53223 return;
[email protected]79d23c72011-08-08 19:40:40224 }
[email protected]55cdf6052011-05-13 19:22:53225
226 // Initiate opening the audio object.
[email protected]9590f8602013-04-23 18:55:21227 enter.SetResult(enter.object()->Open(audio_config_res,
228 enter.callback()));
[email protected]55cdf6052011-05-13 19:22:53229
230 // Clean up the temporary audio config resource we made.
231 const PPB_Core* core = static_cast<const PPB_Core*>(
[email protected]5c966022011-09-13 18:09:37232 dispatcher()->local_get_interface()(PPB_CORE_INTERFACE));
[email protected]55cdf6052011-05-13 19:22:53233 core->ReleaseResource(audio_config_res);
[email protected]5d84d012010-12-02 17:17:21234}
235
[email protected]f24448db2011-01-27 20:40:39236void PPB_Audio_Proxy::OnMsgStartOrStop(const HostResource& audio_id,
237 bool play) {
[email protected]5c966022011-09-13 18:09:37238 EnterHostFromHostResource<PPB_Audio_API> enter(audio_id);
239 if (enter.failed())
240 return;
[email protected]5d84d012010-12-02 17:17:21241 if (play)
[email protected]5c966022011-09-13 18:09:37242 enter.object()->StartPlayback();
[email protected]5d84d012010-12-02 17:17:21243 else
[email protected]5c966022011-09-13 18:09:37244 enter.object()->StopPlayback();
[email protected]5d84d012010-12-02 17:17:21245}
246
[email protected]f24448db2011-01-27 20:40:39247void PPB_Audio_Proxy::AudioChannelConnected(
248 int32_t result,
249 const HostResource& resource) {
[email protected]5d84d012010-12-02 17:17:21250 IPC::PlatformFileForTransit socket_handle =
251 IPC::InvalidPlatformFileForTransit();
Alexandr Ilin20f2841c2018-06-01 11:56:18252 base::UnsafeSharedMemoryRegion shared_memory_region;
[email protected]5d84d012010-12-02 17:17:21253
254 int32_t result_code = result;
255 if (result_code == PP_OK) {
256 result_code = GetAudioConnectedHandles(resource, &socket_handle,
Alexandr Ilin20f2841c2018-06-01 11:56:18257 &shared_memory_region);
[email protected]5d84d012010-12-02 17:17:21258 }
259
260 // Send all the values, even on error. This simplifies some of our cleanup
261 // code since the handles will be in the other process and could be
262 // inconvenient to clean up. Our IPC code will automatically handle this for
263 // us, as long as the remote side always closes the handles it receives
264 // (in OnMsgNotifyAudioStreamCreated), even in the failure case.
[email protected]8510d282012-08-30 19:47:38265 SerializedHandle fd_wrapper(SerializedHandle::SOCKET, socket_handle);
Alexandr Ilin20f2841c2018-06-01 11:56:18266 SerializedHandle handle_wrapper(
267 base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
268 std::move(shared_memory_region)));
[email protected]5d84d012010-12-02 17:17:21269 dispatcher()->Send(new PpapiMsg_PPBAudio_NotifyAudioStreamCreated(
Alexandr Ilin20f2841c2018-06-01 11:56:18270 API_ID_PPB_AUDIO, resource, result_code, std::move(fd_wrapper),
271 std::move(handle_wrapper)));
[email protected]5d84d012010-12-02 17:17:21272}
273
274int32_t PPB_Audio_Proxy::GetAudioConnectedHandles(
[email protected]f24448db2011-01-27 20:40:39275 const HostResource& resource,
[email protected]5d84d012010-12-02 17:17:21276 IPC::PlatformFileForTransit* foreign_socket_handle,
Alexandr Ilin20f2841c2018-06-01 11:56:18277 base::UnsafeSharedMemoryRegion* foreign_shared_memory_region) {
[email protected]79d23c72011-08-08 19:40:40278 // Get the audio interface which will give us the handles.
[email protected]5c966022011-09-13 18:09:37279 EnterHostFromHostResource<PPB_Audio_API> enter(resource);
[email protected]79d23c72011-08-08 19:40:40280 if (enter.failed())
[email protected]5d84d012010-12-02 17:17:21281 return PP_ERROR_NOINTERFACE;
282
283 // Get the socket handle for signaling.
284 int32_t socket_handle;
[email protected]79d23c72011-08-08 19:40:40285 int32_t result = enter.object()->GetSyncSocket(&socket_handle);
[email protected]5d84d012010-12-02 17:17:21286 if (result != PP_OK)
287 return result;
288
[email protected]db0f57f52011-02-25 03:54:54289 // socket_handle doesn't belong to us: don't close it.
290 *foreign_socket_handle = dispatcher()->ShareHandleWithRemote(
291 IntToPlatformFile(socket_handle), false);
292 if (*foreign_socket_handle == IPC::InvalidPlatformFileForTransit())
293 return PP_ERROR_FAILED;
[email protected]5d84d012010-12-02 17:17:21294
295 // Get the shared memory for the buffer.
Alexandr Ilin20f2841c2018-06-01 11:56:18296 base::UnsafeSharedMemoryRegion* shared_memory_region;
297 result = enter.object()->GetSharedMemory(&shared_memory_region);
[email protected]5d84d012010-12-02 17:17:21298 if (result != PP_OK)
299 return result;
300
Alexandr Ilin20f2841c2018-06-01 11:56:18301 // shared_memory_region doesn't belong to us: don't close it.
302 *foreign_shared_memory_region =
303 dispatcher()->ShareUnsafeSharedMemoryRegionWithRemote(
304 *shared_memory_region);
305 if (!foreign_shared_memory_region->IsValid())
[email protected]5d84d012010-12-02 17:17:21306 return PP_ERROR_FAILED;
307
308 return PP_OK;
309}
Xiaohan Wang0fd6e56a2022-01-13 20:26:11310#endif // !BUILDFLAG(IS_NACL)
[email protected]771fc8d2012-05-19 01:39:05311
312// Processed in the plugin (message from host).
313void PPB_Audio_Proxy::OnMsgNotifyAudioStreamCreated(
314 const HostResource& audio_id,
315 int32_t result_code,
[email protected]8510d282012-08-30 19:47:38316 SerializedHandle socket_handle,
317 SerializedHandle handle) {
[email protected]246fc492012-08-27 20:28:18318 CHECK(socket_handle.is_socket());
Alexandr Ilin20f2841c2018-06-01 11:56:18319 CHECK(handle.is_shmem_region());
[email protected]771fc8d2012-05-19 01:39:05320 EnterPluginFromHostResource<PPB_Audio_API> enter(audio_id);
321 if (enter.failed() || result_code != PP_OK) {
322 // The caller may still have given us these handles in the failure case.
Alexandr Ilin20f2841c2018-06-01 11:56:18323 // The easiest way to clean socket handle up is to just put them in the
324 // SyncSocket object and then close it. The shared memory region will be
325 // cleaned up automatically. This failure case is not performance critical.
[email protected]771fc8d2012-05-19 01:39:05326 base::SyncSocket temp_socket(
[email protected]246fc492012-08-27 20:28:18327 IPC::PlatformFileForTransitToPlatformFile(socket_handle.descriptor()));
[email protected]771fc8d2012-05-19 01:39:05328 } else {
[email protected]dfc48e4c2012-09-05 13:39:21329 EnterResourceNoLock<PPB_AudioConfig_API> config(
330 static_cast<Audio*>(enter.object())->GetCurrentConfig(), true);
Alexandr Ilin20f2841c2018-06-01 11:56:18331 static_cast<Audio*>(enter.object())
332 ->SetStreamInfo(enter.resource()->pp_instance(),
333 base::UnsafeSharedMemoryRegion::Deserialize(
334 handle.TakeSharedMemoryRegion()),
Robert Sesek8dd06452020-02-19 01:10:49335 base::SyncSocket::ScopedHandle(
336 IPC::PlatformFileForTransitToPlatformFile(
337 socket_handle.descriptor())),
Alexandr Ilin20f2841c2018-06-01 11:56:18338 config.object()->GetSampleRate(),
339 config.object()->GetSampleFrameCount());
[email protected]771fc8d2012-05-19 01:39:05340 }
341}
[email protected]5d84d012010-12-02 17:17:21342
343} // namespace proxy
[email protected]4d2efd22011-08-18 21:58:02344} // namespace ppapi