Chromium Code Reviews| Index: ppapi/proxy/ppb_audio_proxy.cc |
| =================================================================== |
| --- ppapi/proxy/ppb_audio_proxy.cc (revision 0) |
| +++ ppapi/proxy/ppb_audio_proxy.cc (revision 0) |
| @@ -0,0 +1,286 @@ |
| +// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "ppapi/proxy/ppb_audio_proxy.h" |
| + |
| +#include "base/simple_thread.h" |
| +#include "ppapi/c/dev/ppb_audio_dev.h" |
| +#include "ppapi/c/dev/ppb_audio_trusted_dev.h" |
| +#include "ppapi/c/pp_errors.h" |
| +#include "ppapi/proxy/interface_id.h" |
| +#include "ppapi/proxy/plugin_dispatcher.h" |
| +#include "ppapi/proxy/plugin_resource.h" |
| +#include "ppapi/proxy/ppapi_messages.h" |
| +#include "ppapi/shared_impl/audio_impl.h" |
| + |
| +namespace pp { |
| +namespace proxy { |
| + |
| +class Audio : public PluginResource, public pp::shared_impl::AudioImpl { |
| + public: |
| + Audio(PP_Resource config_id, PPB_Audio_Callback callback, void* user_data) |
| + : config_(config_id) { |
| + SetCallback(callback, user_data); |
| + PluginDispatcher::Get()->plugin_resource_tracker()->AddRefResource( |
| + config_); |
| + } |
| + virtual ~Audio() { |
| + PluginDispatcher::Get()->plugin_resource_tracker()->ReleaseResource( |
| + config_); |
| + } |
| + |
| + // Resource overrides. |
| + virtual Audio* AsAudio() { return this; } |
| + |
| + PP_Resource config() const { return config_; } |
| + |
| + void StartPlayback(PP_Resource resource) { |
| + if (playing()) |
| + return; |
| + SetStartPlaybackState(); |
| + PluginDispatcher::Get()->Send(new PpapiHostMsg_PPBAudio_StartOrStop( |
| + INTERFACE_ID_PPB_AUDIO, resource, true)); |
| + } |
| + |
| + void StopPlayback(PP_Resource resource) { |
| + if (!playing()) |
| + return; |
| + PluginDispatcher::Get()->Send(new PpapiHostMsg_PPBAudio_StartOrStop( |
| + INTERFACE_ID_PPB_AUDIO, resource, false)); |
| + SetStopPlaybackState(); |
| + } |
| + |
| + private: |
| + PP_Resource config_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(Audio); |
| +}; |
| + |
| +namespace { |
| + |
| +PP_Resource Create(PP_Instance instance_id, |
| + PP_Resource config_id, |
| + PPB_Audio_Callback callback, |
| + void* user_data) { |
| + PP_Resource result; |
| + PluginDispatcher::Get()->Send(new PpapiHostMsg_PPBAudio_Create( |
| + INTERFACE_ID_PPB_AUDIO, instance_id, config_id, &result)); |
| + if (!result) |
| + return 0; |
| + |
| + linked_ptr<Audio> object(new Audio(config_id, callback, user_data)); |
| + PluginDispatcher::Get()->plugin_resource_tracker()->AddResource( |
| + result, object); |
| + return result; |
| +} |
| + |
| +PP_Bool IsAudio(PP_Resource resource) { |
| + Audio* object = PluginResource::GetAs<Audio>(resource); |
| + return BoolToPPBool(!!object); |
| +} |
| + |
| +PP_Resource GetCurrentConfiguration(PP_Resource audio_id) { |
| + Audio* object = PluginResource::GetAs<Audio>(audio_id); |
| + if (!object) |
| + return 0; |
| + PP_Resource result = object->config(); |
| + PluginDispatcher::Get()->plugin_resource_tracker()->AddRefResource(result); |
| + return result; |
| +} |
| + |
| +PP_Bool StartPlayback(PP_Resource audio_id) { |
| + Audio* object = PluginResource::GetAs<Audio>(audio_id); |
| + if (!object) |
| + return PP_FALSE; |
| + object->StartPlayback(audio_id); |
| + return PP_TRUE; |
| +} |
| + |
| +PP_Bool StopPlayback(PP_Resource audio_id) { |
| + Audio* object = PluginResource::GetAs<Audio>(audio_id); |
| + if (!object) |
| + return PP_FALSE; |
| + object->StopPlayback(audio_id); |
| + return PP_TRUE; |
| +} |
| + |
| +const PPB_Audio_Dev audio_interface = { |
| + &Create, |
| + &IsAudio, |
| + &GetCurrentConfiguration, |
| + &StartPlayback, |
| + &StopPlayback |
| +}; |
| + |
| +} // namespace |
| + |
| +PPB_Audio_Proxy::PPB_Audio_Proxy(Dispatcher* dispatcher, |
| + const void* target_interface) |
| + : InterfaceProxy(dispatcher, target_interface), |
| + callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
| +} |
| + |
| +PPB_Audio_Proxy::~PPB_Audio_Proxy() { |
| +} |
| + |
| +const void* PPB_Audio_Proxy::GetSourceInterface() const { |
| + return &audio_interface; |
| +} |
| + |
| +InterfaceID PPB_Audio_Proxy::GetInterfaceId() const { |
| + return INTERFACE_ID_PPB_AUDIO; |
| +} |
| + |
| +void PPB_Audio_Proxy::OnMessageReceived(const IPC::Message& msg) { |
| + IPC_BEGIN_MESSAGE_MAP(PPB_Audio_Proxy, msg) |
| + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_Create, OnMsgCreate) |
| + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_StartOrStop, |
| + OnMsgStartOrStop) |
| + |
| + IPC_MESSAGE_HANDLER(PpapiMsg_PPBAudio_NotifyAudioStreamCreated, |
| + OnMsgNotifyAudioStreamCreated) |
| + IPC_END_MESSAGE_MAP() |
| +} |
| + |
| +void PPB_Audio_Proxy::OnMsgCreate(PP_Instance instance_id, |
| + PP_Resource config_id, |
| + PP_Resource* result) { |
| + const PPB_AudioTrusted_Dev* audio_trusted = |
| + reinterpret_cast<const PPB_AudioTrusted_Dev*>( |
| + dispatcher()->GetLocalInterface(PPB_AUDIO_TRUSTED_DEV_INTERFACE)); |
| + if (!audio_trusted) { |
| + *result = 0; |
| + return; |
| + } |
| + |
| + *result = audio_trusted->CreateTrusted(instance_id); |
| + if (!result) |
| + return; |
| + |
| + CompletionCallback callback = callback_factory_.NewCallback( |
| + &PPB_Audio_Proxy::AudioChannelConnected, *result); |
| + int32_t open_error = audio_trusted->Open(*result, config_id, |
| + callback.pp_completion_callback()); |
| + if (open_error != PP_ERROR_WOULDBLOCK) |
| + callback.Run(open_error); |
| +} |
| + |
| +void PPB_Audio_Proxy::OnMsgStartOrStop(PP_Resource audio_id, bool play) { |
| + if (play) |
| + ppb_audio_target()->StartPlayback(audio_id); |
| + else |
| + ppb_audio_target()->StopPlayback(audio_id); |
| +} |
| + |
| +void PPB_Audio_Proxy::OnMsgNotifyAudioStreamCreated( |
| + PP_Resource audio_id, |
| + int32_t result_code, |
| + IPC::PlatformFileForTransit socket_handle, |
| + base::SharedMemoryHandle handle, |
| + uint32_t length) { |
| + Audio* object = PluginResource::GetAs<Audio>(audio_id); |
| + if (!object || result_code != PP_OK) { |
| + // The caller may still have given us these handles in the failure case. |
| + // The easiest way to clean these up is to just put them in the objects |
| + // and then close them. This failure case is not performance critical. |
| + base::SyncSocket temp_socket( |
| + IPC::PlatformFileForTransitToPlatformFile(socket_handle)); |
| + base::SharedMemory temp_mem(handle, false); |
| + return; |
| + } |
| + object->SetStreamInfo( |
| + handle, IPC::PlatformFileForTransitToPlatformFile(socket_handle), length); |
| +} |
| + |
| +void PPB_Audio_Proxy::AudioChannelConnected(int32_t result, |
| + PP_Resource resource) { |
| + IPC::PlatformFileForTransit socket_handle = |
| + IPC::InvalidPlatformFileForTransit(); |
| +#if defined(OS_WIN) |
| + base::SharedMemoryHandle shared_memory = NULL; |
| +#elif defined(OS_POSIX) |
| + base::SharedMemoryHandle shared_memory(-1, false); |
| +#else |
| + #error Not implemented. |
| +#endif |
| + uint32_t shared_memory_length = 0; |
| + |
| + int32_t result_code = result; |
| + if (result_code == PP_OK) { |
| + result_code = GetAudioConnectedHandles(resource, &socket_handle, |
| + &shared_memory, |
| + &shared_memory_length); |
| + } |
| + |
| + // Send all the values, even on error. This simplifies some of our cleanup |
| + // code since the handles will be in the other process and could be |
| + // inconvenient to clean up. Our IPC code will automatically handle this for |
| + // us, as long as the remote side always closes the handles it receives |
| + // (in OnMsgNotifyAudioStreamCreated), even in the failure case. |
| + dispatcher()->Send(new PpapiMsg_PPBAudio_NotifyAudioStreamCreated( |
| + INTERFACE_ID_PPB_AUDIO, resource, result_code, shared_memory, |
| + socket_handle, shared_memory_length)); |
| +} |
| + |
| +int32_t PPB_Audio_Proxy::GetAudioConnectedHandles( |
| + PP_Resource resource, |
| + IPC::PlatformFileForTransit* foreign_socket_handle, |
| + base::SharedMemoryHandle* foreign_shared_memory_handle, |
| + uint32_t* shared_memory_length) { |
| + // Get the trusted audio interface which will give us the handles. |
| + const PPB_AudioTrusted_Dev* audio_trusted = |
| + reinterpret_cast<const PPB_AudioTrusted_Dev*>( |
| + dispatcher()->GetLocalInterface(PPB_AUDIO_TRUSTED_DEV_INTERFACE)); |
| + if (!audio_trusted) |
| + return PP_ERROR_NOINTERFACE; |
| + |
| + // Get the socket handle for signaling. |
| + int32_t socket_handle; |
| + int32_t result = audio_trusted->GetSyncSocket(resource, &socket_handle); |
| + if (result != PP_OK) |
| + return result; |
| + |
| +#if defined(OS_WIN) |
| + // On Windows, duplicate the socket into the plugin process, this will |
| + // automatically close the source handle. |
| + ::DuplicateHandle( |
| + GetCurrentProcess(), |
| + reinterpret_cast<HANDLE>(static_cast<intptr_t>(socket_handle)), |
| + dispatcher()->remote_process_handle(), foreign_socket_handle, |
| + STANDARD_RIGHTS_REQUIRED | FILE_MAP_READ | FILE_MAP_WRITE, |
| + FALSE, DUPLICATE_CLOSE_SOURCE); |
| +#else |
| + // On Posix, the socket handle will be auto-duplicated when we send the |
| + // FileDescriptor. Set AutoClose since we don't need the handle any more. |
| + *foreign_socket_handle = base::FileDescriptor(static_cast<int>(socket_handle), |
|
piman
2010/12/01 23:27:10
I don't think you need this static cast, int32_t->
brettw
2010/12/02 00:00:53
Ah yes, this was left over from when the value use
|
| + true); |
| +#endif |
| + |
| + // Get the shared memory for the buffer. |
| + // TODO(brettw) remove the reinterpret cast when the interface is updated. |
| + int shared_memory_handle; |
| + result = audio_trusted->GetSharedMemory(resource, &shared_memory_handle, |
| + shared_memory_length); |
| + if (result != PP_OK) |
| + return result; |
| + |
| + base::SharedMemory shared_memory( |
| +#if defined(OS_WIN) |
| + reinterpret_cast<HANDLE>(static_cast<intptr_t>(shared_memory_handle)), |
| +#else |
| + base::FileDescriptor(shared_memory_handle, false), |
| +#endif |
| + false); |
| + |
| + // Duplicate the shared memory to the plugin process. This will automatically |
| + // close the source handle. |
| + if (!shared_memory.GiveToProcess(dispatcher()->remote_process_handle(), |
| + foreign_shared_memory_handle)) |
| + return PP_ERROR_FAILED; |
| + |
| + return PP_OK; |
| +} |
| + |
| +} // namespace proxy |
| +} // namespace pp |
| Property changes on: ppapi/proxy/ppb_audio_proxy.cc |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| + LF |