diff options
author | yzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-05 02:44:18 +0000 |
---|---|---|
committer | yzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-05 02:44:18 +0000 |
commit | 4f01c76ed760e674cb86f2b0a17a779431e2aa71 (patch) | |
tree | a2d874fb3f21b65e07f0d75db567487f6bd4a38a /content/renderer/pepper | |
parent | 4afef6e27ecbcf6430c5d37881eca04c6b1f8d78 (diff) | |
download | chromium_src-4f01c76ed760e674cb86f2b0a17a779431e2aa71.zip chromium_src-4f01c76ed760e674cb86f2b0a17a779431e2aa71.tar.gz chromium_src-4f01c76ed760e674cb86f2b0a17a779431e2aa71.tar.bz2 |
Introduce PPB_AudioInput_Dev v0.3 and refactor the device enumeration code:
- Add MonitorDeviceChange() for PPB_AudioInput_Dev.
- Change EnumerateDevices() to use PP_ArrayOutput.
- Move device enumeration code out of the audio input implementation, so that it can be shared by video capture.
- Update the audio_input manual test.
- Add unittests for the device enumeration code.
TEST=None
BUG=137799
Review URL: https://chromiumcodereview.appspot.com/11411047
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@171132 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/renderer/pepper')
8 files changed, 590 insertions, 69 deletions
diff --git a/content/renderer/pepper/pepper_audio_input_host.cc b/content/renderer/pepper/pepper_audio_input_host.cc index 7e334b4..89a08f1 100644 --- a/content/renderer/pepper/pepper_audio_input_host.cc +++ b/content/renderer/pepper/pepper_audio_input_host.cc @@ -4,7 +4,6 @@ #include "content/renderer/pepper/pepper_audio_input_host.h" -#include "base/bind.h" #include "base/logging.h" #include "build/build_config.h" #include "content/public/renderer/renderer_ppapi_host.h" @@ -15,7 +14,6 @@ #include "ppapi/host/ppapi_host.h" #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/proxy/serialized_structs.h" -#include "ppapi/shared_impl/ppb_device_ref_shared.h" #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" namespace content { @@ -45,7 +43,9 @@ PepperAudioInputHost::PepperAudioInputHost( PP_Resource resource) : ResourceHost(host->GetPpapiHost(), instance, resource), renderer_ppapi_host_(host), - audio_input_(NULL) { + audio_input_(NULL), + ALLOW_THIS_IN_INITIALIZER_LIST( + enumeration_helper_(this, this, PP_DEVICETYPE_DEV_AUDIOCAPTURE)) { } PepperAudioInputHost::~PepperAudioInputHost() { @@ -55,9 +55,11 @@ PepperAudioInputHost::~PepperAudioInputHost() { int32_t PepperAudioInputHost::OnResourceMessageReceived( const IPC::Message& msg, ppapi::host::HostMessageContext* context) { + int32_t result = PP_ERROR_FAILED; + if (enumeration_helper_.HandleResourceMessage(msg, context, &result)) + return result; + IPC_BEGIN_MESSAGE_MAP(PepperAudioInputHost, msg) - PPAPI_DISPATCH_HOST_RESOURCE_CALL_0( - PpapiHostMsg_AudioInput_EnumerateDevices, OnMsgEnumerateDevices) PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioInput_Open, OnMsgOpen) PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioInput_StartOrStop, OnMsgStartOrStop); @@ -79,23 +81,12 @@ void PepperAudioInputHost::StreamCreationFailed() { base::SyncSocket::kInvalidHandle); } -int32_t PepperAudioInputHost::OnMsgEnumerateDevices( - ppapi::host::HostMessageContext* context) { - if (enumerate_devices_context_.get()) - return PP_ERROR_INPROGRESS; - - webkit::ppapi::PluginDelegate* plugin_delegate = GetDelegate(); - if (!plugin_delegate) - return PP_ERROR_FAILED; - - enumerate_devices_context_.reset( - new ppapi::host::ReplyMessageContext(context->MakeReplyMessageContext())); - // Note that the callback may be called synchronously. - plugin_delegate->EnumerateDevices( - PP_DEVICETYPE_DEV_AUDIOCAPTURE, - base::Bind(&PepperAudioInputHost::EnumerateDevicesCallbackFunc, - AsWeakPtr())); - return PP_OK_COMPLETIONPENDING; +webkit::ppapi::PluginDelegate* PepperAudioInputHost::GetPluginDelegate() { + webkit::ppapi::PluginInstance* instance = + renderer_ppapi_host_->GetPluginInstance(pp_instance()); + if (instance) + return instance->delegate(); + return NULL; } int32_t PepperAudioInputHost::OnMsgOpen( @@ -108,7 +99,7 @@ int32_t PepperAudioInputHost::OnMsgOpen( if (audio_input_) return PP_ERROR_FAILED; - webkit::ppapi::PluginDelegate* plugin_delegate = GetDelegate(); + webkit::ppapi::PluginDelegate* plugin_delegate = GetPluginDelegate(); if (!plugin_delegate) return PP_ERROR_FAILED; @@ -143,25 +134,6 @@ int32_t PepperAudioInputHost::OnMsgClose( return PP_OK; } -void PepperAudioInputHost::EnumerateDevicesCallbackFunc( - int request_id, - bool succeeded, - const std::vector<ppapi::DeviceRefData>& devices) { - DCHECK(enumerate_devices_context_.get()); - - webkit::ppapi::PluginDelegate* plugin_delegate = GetDelegate(); - if (plugin_delegate) - plugin_delegate->StopEnumerateDevices(request_id); - - enumerate_devices_context_->params.set_result( - succeeded ? PP_OK : PP_ERROR_FAILED); - host()->SendReply( - *enumerate_devices_context_, - PpapiPluginMsg_AudioInput_EnumerateDevicesReply( - succeeded ? devices : std::vector<ppapi::DeviceRefData>())); - enumerate_devices_context_.reset(); -} - void PepperAudioInputHost::OnOpenComplete( int32_t result, base::SharedMemoryHandle shared_memory_handle, @@ -243,13 +215,5 @@ void PepperAudioInputHost::Close() { } } -webkit::ppapi::PluginDelegate* PepperAudioInputHost::GetDelegate() const { - webkit::ppapi::PluginInstance* instance = - renderer_ppapi_host_->GetPluginInstance(pp_instance()); - if (instance) - return instance->delegate(); - return NULL; -} - } // namespace content diff --git a/content/renderer/pepper/pepper_audio_input_host.h b/content/renderer/pepper/pepper_audio_input_host.h index c6f6bd9..70228f0 100644 --- a/content/renderer/pepper/pepper_audio_input_host.h +++ b/content/renderer/pepper/pepper_audio_input_host.h @@ -6,24 +6,19 @@ #define CONTENT_RENDERER_PEPPER_PEPPER_AUDIO_INPUT_HOST_H_ #include <string> -#include <vector> #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" #include "base/shared_memory.h" #include "base/sync_socket.h" +#include "content/renderer/pepper/pepper_device_enumeration_host_helper.h" #include "ipc/ipc_platform_file.h" #include "ppapi/c/ppb_audio_config.h" #include "ppapi/host/host_message_context.h" #include "ppapi/host/resource_host.h" #include "webkit/plugins/ppapi/plugin_delegate.h" -namespace ppapi { -struct DeviceRefData; -} - namespace content { class RendererPpapiHost; @@ -31,7 +26,7 @@ class RendererPpapiHost; class PepperAudioInputHost : public ppapi::host::ResourceHost, public webkit::ppapi::PluginDelegate::PlatformAudioInputClient, - public base::SupportsWeakPtr<PepperAudioInputHost> { + public PepperDeviceEnumerationHostHelper::Delegate { public: PepperAudioInputHost(RendererPpapiHost* host, PP_Instance instance, @@ -48,8 +43,10 @@ class PepperAudioInputHost base::SyncSocket::Handle socket) OVERRIDE; virtual void StreamCreationFailed() OVERRIDE; + // PepperDeviceEnumerationHostHelper::Delegate implementation. + virtual webkit::ppapi::PluginDelegate* GetPluginDelegate() OVERRIDE; + private: - int32_t OnMsgEnumerateDevices(ppapi::host::HostMessageContext* context); int32_t OnMsgOpen(ppapi::host::HostMessageContext* context, const std::string& device_id, PP_AudioSampleRate sample_rate, @@ -58,11 +55,6 @@ class PepperAudioInputHost bool capture); int32_t OnMsgClose(ppapi::host::HostMessageContext* context); - void EnumerateDevicesCallbackFunc( - int request_id, - bool succeeded, - const std::vector<ppapi::DeviceRefData>& devices); - void OnOpenComplete(int32_t result, base::SharedMemoryHandle shared_memory_handle, size_t shared_memory_size, @@ -76,20 +68,17 @@ class PepperAudioInputHost void Close(); - // TODO(yzshen): Move the relevant functionality out of PluginDelegate and get - // rid of this method. - webkit::ppapi::PluginDelegate* GetDelegate() const; - // Non-owning pointer. RendererPpapiHost* renderer_ppapi_host_; - scoped_ptr<ppapi::host::ReplyMessageContext> enumerate_devices_context_; scoped_ptr<ppapi::host::ReplyMessageContext> open_context_; // PluginDelegate audio input object that we delegate audio IPC through. // We don't own this pointer but are responsible for calling Shutdown on it. webkit::ppapi::PluginDelegate::PlatformAudioInput* audio_input_; + PepperDeviceEnumerationHostHelper enumeration_helper_; + DISALLOW_COPY_AND_ASSIGN(PepperAudioInputHost); }; diff --git a/content/renderer/pepper/pepper_device_enumeration_event_handler.cc b/content/renderer/pepper/pepper_device_enumeration_event_handler.cc index ff58e2d..42634df 100644 --- a/content/renderer/pepper/pepper_device_enumeration_event_handler.cc +++ b/content/renderer/pepper/pepper_device_enumeration_event_handler.cc @@ -37,6 +37,11 @@ int PepperDeviceEnumerationEventHandler::RegisterEnumerateDevicesCallback( return next_id_++; } +void PepperDeviceEnumerationEventHandler::UnregisterEnumerateDevicesCallback( + int request_id) { + enumerate_callbacks_.erase(request_id); +} + int PepperDeviceEnumerationEventHandler::RegisterOpenDeviceCallback( const PepperPluginDelegateImpl::OpenDeviceCallback& callback) { open_callbacks_[next_id_] = callback; @@ -121,7 +126,6 @@ void PepperDeviceEnumerationEventHandler::NotifyDevicesEnumerated( webkit::ppapi::PluginDelegate::EnumerateDevicesCallback callback = iter->second; - enumerate_callbacks_.erase(iter); std::vector<ppapi::DeviceRefData> devices; if (succeeded) { diff --git a/content/renderer/pepper/pepper_device_enumeration_event_handler.h b/content/renderer/pepper/pepper_device_enumeration_event_handler.h index 01370b1..7ce3436 100644 --- a/content/renderer/pepper/pepper_device_enumeration_event_handler.h +++ b/content/renderer/pepper/pepper_device_enumeration_event_handler.h @@ -23,6 +23,7 @@ class PepperDeviceEnumerationEventHandler int RegisterEnumerateDevicesCallback( const webkit::ppapi::PluginDelegate::EnumerateDevicesCallback& callback); + void UnregisterEnumerateDevicesCallback(int request_id); int RegisterOpenDeviceCallback( const PepperPluginDelegateImpl::OpenDeviceCallback& callback); diff --git a/content/renderer/pepper/pepper_device_enumeration_host_helper.cc b/content/renderer/pepper/pepper_device_enumeration_host_helper.cc new file mode 100644 index 0000000..1550737 --- /dev/null +++ b/content/renderer/pepper/pepper_device_enumeration_host_helper.cc @@ -0,0 +1,197 @@ +// Copyright (c) 2012 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 "content/renderer/pepper/pepper_device_enumeration_host_helper.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "base/memory/weak_ptr.h" +#include "base/message_loop.h" +#include "ipc/ipc_message.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/host/dispatch_host_message.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/host/resource_host.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/ppb_device_ref_shared.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" + +using ppapi::host::HostMessageContext; +using webkit::ppapi::PluginDelegate; + +namespace content { + +// Makes sure that StopEnumerateDevices() is called for each EnumerateDevices(). +class PepperDeviceEnumerationHostHelper::ScopedRequest + : public base::SupportsWeakPtr<ScopedRequest> { + public: + // |owner| must outlive this object. + ScopedRequest(PepperDeviceEnumerationHostHelper* owner, + const PluginDelegate::EnumerateDevicesCallback& callback) + : owner_(owner), + callback_(callback), + requested_(false), + request_id_(0), + sync_call_(false) { + PluginDelegate* plugin_delegate = owner_->delegate_->GetPluginDelegate(); + if (!plugin_delegate) + return; + + requested_ = true; + + // Note that the callback passed into PluginDelegate::EnumerateDevices() may + // be called synchronously. In that case, |request_id_| hasn't been updated + // when the callback is called. Moreover, |callback| may destroy this + // object. So we don't pass in |callback| directly. Instead, we use + // EnumerateDevicesCallbackBody() to ensure that we always call |callback| + // asynchronously. + sync_call_ = true; + request_id_ = plugin_delegate->EnumerateDevices( + owner_->device_type_, + base::Bind(&ScopedRequest::EnumerateDevicesCallbackBody, AsWeakPtr())); + sync_call_ = false; + } + + ~ScopedRequest() { + if (requested_) { + PluginDelegate* plugin_delegate = owner_->delegate_->GetPluginDelegate(); + if (plugin_delegate) + plugin_delegate->StopEnumerateDevices(request_id_); + } + } + + bool requested() const { return requested_; } + + private: + void EnumerateDevicesCallbackBody( + int request_id, + bool succeeded, + const std::vector<ppapi::DeviceRefData>& devices) { + if (sync_call_) { + MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&ScopedRequest::EnumerateDevicesCallbackBody, AsWeakPtr(), + request_id, succeeded, devices)); + } else { + DCHECK_EQ(request_id_, request_id); + callback_.Run(request_id, succeeded, devices); + // This object may have been destroyed at this point. + } + } + + PepperDeviceEnumerationHostHelper* owner_; + PluginDelegate::EnumerateDevicesCallback callback_; + bool requested_; + int request_id_; + bool sync_call_; + + DISALLOW_COPY_AND_ASSIGN(ScopedRequest); +}; + +PepperDeviceEnumerationHostHelper::PepperDeviceEnumerationHostHelper( + ppapi::host::ResourceHost* resource_host, + Delegate* delegate, + PP_DeviceType_Dev device_type) + : resource_host_(resource_host), + delegate_(delegate), + device_type_(device_type) { +} + +PepperDeviceEnumerationHostHelper::~PepperDeviceEnumerationHostHelper() { +} + +bool PepperDeviceEnumerationHostHelper::HandleResourceMessage( + const IPC::Message& msg, + HostMessageContext* context, + int32_t* result) { + bool return_value = false; + *result = InternalHandleResourceMessage(msg, context, &return_value); + return return_value; +} + +int32_t PepperDeviceEnumerationHostHelper::InternalHandleResourceMessage( + const IPC::Message& msg, + HostMessageContext* context, + bool* handled) { + *handled = true; + IPC_BEGIN_MESSAGE_MAP(PepperDeviceEnumerationHostHelper, msg) + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0( + PpapiHostMsg_DeviceEnumeration_EnumerateDevices, OnMsgEnumerateDevices) + PPAPI_DISPATCH_HOST_RESOURCE_CALL( + PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange, + OnMsgMonitorDeviceChange) + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0( + PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange, + OnMsgStopMonitoringDeviceChange) + IPC_END_MESSAGE_MAP() + + *handled = false; + return PP_ERROR_FAILED; +} + +int32_t PepperDeviceEnumerationHostHelper::OnMsgEnumerateDevices( + HostMessageContext* context) { + if (enumerate_devices_context_.get()) + return PP_ERROR_INPROGRESS; + + enumerate_.reset(new ScopedRequest( + this, + base::Bind(&PepperDeviceEnumerationHostHelper::OnEnumerateDevicesComplete, + base::Unretained(this)))); + if (!enumerate_->requested()) + return PP_ERROR_FAILED; + + enumerate_devices_context_.reset( + new ppapi::host::ReplyMessageContext(context->MakeReplyMessageContext())); + return PP_OK_COMPLETIONPENDING; +} + +int32_t PepperDeviceEnumerationHostHelper::OnMsgMonitorDeviceChange( + HostMessageContext* /* context */, + uint32_t callback_id) { + monitor_.reset(new ScopedRequest( + this, + base::Bind(&PepperDeviceEnumerationHostHelper::OnNotifyDeviceChange, + base::Unretained(this), callback_id))); + + return monitor_->requested() ? PP_OK : PP_ERROR_FAILED; +} + +int32_t PepperDeviceEnumerationHostHelper::OnMsgStopMonitoringDeviceChange( + HostMessageContext* /* context */) { + monitor_.reset(NULL); + return PP_OK; +} + +void PepperDeviceEnumerationHostHelper::OnEnumerateDevicesComplete( + int /* request_id */, + bool succeeded, + const std::vector<ppapi::DeviceRefData>& devices) { + DCHECK(enumerate_devices_context_.get()); + + enumerate_.reset(NULL); + + enumerate_devices_context_->params.set_result( + succeeded ? PP_OK : PP_ERROR_FAILED); + resource_host_->host()->SendReply( + *enumerate_devices_context_, + PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply( + succeeded ? devices : std::vector<ppapi::DeviceRefData>())); + enumerate_devices_context_.reset(); +} + +void PepperDeviceEnumerationHostHelper::OnNotifyDeviceChange( + uint32_t callback_id, + int /* request_id */, + bool succeeded, + const std::vector<ppapi::DeviceRefData>& devices) { + resource_host_->host()->SendUnsolicitedReply( + resource_host_->pp_resource(), + PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange( + callback_id, + succeeded ? devices : std::vector<ppapi::DeviceRefData>())); +} + +} // namespace content diff --git a/content/renderer/pepper/pepper_device_enumeration_host_helper.h b/content/renderer/pepper/pepper_device_enumeration_host_helper.h new file mode 100644 index 0000000..db0af2d --- /dev/null +++ b/content/renderer/pepper/pepper_device_enumeration_host_helper.h @@ -0,0 +1,106 @@ +// Copyright (c) 2012 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. + +#ifndef CONTENT_RENDERER_PEPPER_PEPPER_DEVICE_ENUMERATION_HOST_HELPER_H_ +#define CONTENT_RENDERER_PEPPER_PEPPER_DEVICE_ENUMERATION_HOST_HELPER_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "content/common/content_export.h" +#include "ppapi/c/dev/ppb_device_ref_dev.h" + +namespace ppapi { +struct DeviceRefData; + +namespace host { +struct HostMessageContext; +struct ReplyMessageContext; +class ResourceHost; +} +} + +namespace IPC { +class Message; +} + +namespace webkit { +namespace ppapi { +class PluginDelegate; +} +} + +namespace content { + +// Resource hosts that support device enumeration can use this class to filter +// and process PpapiHostMsg_DeviceEnumeration_* messages. +// TODO(yzshen): Refactor ppapi::host::ResourceMessageFilter to support message +// handling on the same thread, and then derive this class from the filter +// class. +class CONTENT_EXPORT PepperDeviceEnumerationHostHelper { + public: + class Delegate { + public: + virtual ~Delegate() {} + + // TODO(yzshen): Move the relevant functionality out of PluginDelegate and + // get rid of this method. + virtual webkit::ppapi::PluginDelegate* GetPluginDelegate() = 0; + }; + + // |resource_host| and |delegate| must outlive this object. + PepperDeviceEnumerationHostHelper(ppapi::host::ResourceHost* resource_host, + Delegate* delegate, + PP_DeviceType_Dev device_type); + ~PepperDeviceEnumerationHostHelper(); + + // Returns true if the message has been handled. + bool HandleResourceMessage(const IPC::Message& msg, + ppapi::host::HostMessageContext* context, + int32_t* result); + + private: + class ScopedRequest; + + // Has a different signature than HandleResourceMessage() in order to utilize + // message dispatching macros. + int32_t InternalHandleResourceMessage( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context, + bool* handled); + + int32_t OnMsgEnumerateDevices(ppapi::host::HostMessageContext* context); + int32_t OnMsgMonitorDeviceChange(ppapi::host::HostMessageContext* context, + uint32_t callback_id); + int32_t OnMsgStopMonitoringDeviceChange( + ppapi::host::HostMessageContext* context); + + void OnEnumerateDevicesComplete( + int request_id, + bool succeeded, + const std::vector<ppapi::DeviceRefData>& devices); + void OnNotifyDeviceChange( + uint32_t callback_id, + int request_id, + bool succeeded, + const std::vector<ppapi::DeviceRefData>& devices); + + // Non-owning pointers. + ppapi::host::ResourceHost* resource_host_; + Delegate* delegate_; + + PP_DeviceType_Dev device_type_; + + scoped_ptr<ScopedRequest> enumerate_; + scoped_ptr<ScopedRequest> monitor_; + + scoped_ptr<ppapi::host::ReplyMessageContext> enumerate_devices_context_; + + DISALLOW_COPY_AND_ASSIGN(PepperDeviceEnumerationHostHelper); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_PEPPER_PEPPER_DEVICE_ENUMERATION_HOST_HELPER_H_ diff --git a/content/renderer/pepper/pepper_device_enumeration_host_helper_unittest.cc b/content/renderer/pepper/pepper_device_enumeration_host_helper_unittest.cc new file mode 100644 index 0000000..c5616f5 --- /dev/null +++ b/content/renderer/pepper/pepper_device_enumeration_host_helper_unittest.cc @@ -0,0 +1,257 @@ +// Copyright (c) 2012 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 <map> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "content/renderer/pepper/pepper_device_enumeration_host_helper.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/host/resource_host.h" +#include "ppapi/proxy/ppapi_message_utils.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/proxy/resource_message_test_sink.h" +#include "ppapi/shared_impl/ppapi_permissions.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "webkit/plugins/ppapi/mock_plugin_delegate.h" + +namespace content { + +namespace { + +class TestPluginDelegate : public webkit::ppapi::MockPluginDelegate { + public: + TestPluginDelegate() : last_used_id_(0) { + } + + virtual ~TestPluginDelegate() { + CHECK(callbacks_.empty()); + } + + virtual int EnumerateDevices( + PP_DeviceType_Dev /* type */, + const EnumerateDevicesCallback& callback) OVERRIDE { + last_used_id_++; + callbacks_[last_used_id_] = callback; + return last_used_id_; + } + + virtual void StopEnumerateDevices(int request_id) OVERRIDE { + std::map<int, EnumerateDevicesCallback>::iterator iter = + callbacks_.find(request_id); + CHECK(iter != callbacks_.end()); + callbacks_.erase(iter); + } + + // Returns false if |request_id| is not found. + bool SimulateEnumerateResult( + int request_id, + bool succeeded, + const std::vector<ppapi::DeviceRefData>& devices) { + std::map<int, EnumerateDevicesCallback>::iterator iter = + callbacks_.find(request_id); + if (iter == callbacks_.end()) + return false; + + iter->second.Run(request_id, succeeded, devices); + return true; + } + + size_t GetRegisteredCallbackCount() const { return callbacks_.size(); } + + int last_used_id() const { return last_used_id_; } + + private: + std::map<int, EnumerateDevicesCallback> callbacks_; + int last_used_id_; + + DISALLOW_COPY_AND_ASSIGN(TestPluginDelegate); +}; + +class TestResourceHost : public ppapi::host::ResourceHost, + public PepperDeviceEnumerationHostHelper::Delegate { + public: + TestResourceHost(ppapi::host::PpapiHost* host, + PP_Instance instance, + PP_Resource resource, + webkit::ppapi::PluginDelegate* delegate) + : ResourceHost(host, instance, resource), + delegate_(delegate) { + } + + virtual ~TestResourceHost() {} + + virtual webkit::ppapi::PluginDelegate* GetPluginDelegate() OVERRIDE { + return delegate_; + } + + private: + webkit::ppapi::PluginDelegate* delegate_; + + DISALLOW_COPY_AND_ASSIGN(TestResourceHost); +}; + +class PepperDeviceEnumerationHostHelperTest : public testing::Test { + protected: + PepperDeviceEnumerationHostHelperTest() + : ppapi_host_(&sink_, ppapi::PpapiPermissions()), + resource_host_(&ppapi_host_, 12345, 67890, &delegate_), + device_enumeration_(&resource_host_, &resource_host_, + PP_DEVICETYPE_DEV_AUDIOCAPTURE) { + } + + virtual ~PepperDeviceEnumerationHostHelperTest() {} + + void SimulateMonitorDeviceChangeReceived(uint32_t callback_id) { + PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange msg(callback_id); + ppapi::proxy::ResourceMessageCallParams call_params( + resource_host_.pp_resource(), 123); + ppapi::host::HostMessageContext context(call_params); + int32_t result = PP_ERROR_FAILED; + ASSERT_TRUE(device_enumeration_.HandleResourceMessage( + msg, &context, &result)); + EXPECT_EQ(PP_OK, result); + } + + void CheckNotifyDeviceChangeMessage( + uint32_t callback_id, + const std::vector<ppapi::DeviceRefData>& expected) { + ppapi::proxy::ResourceMessageReplyParams reply_params; + IPC::Message reply_msg; + ASSERT_TRUE(sink_.GetFirstResourceReplyMatching( + PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange::ID, + &reply_params, &reply_msg)); + sink_.ClearMessages(); + + EXPECT_EQ(PP_OK, reply_params.result()); + + uint32_t reply_callback_id = 0; + std::vector<ppapi::DeviceRefData> reply_data; + ASSERT_TRUE(ppapi::UnpackMessage< + PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange>( + reply_msg, &reply_callback_id, &reply_data)); + EXPECT_EQ(callback_id, reply_callback_id); + EXPECT_EQ(expected, reply_data); + } + + TestPluginDelegate delegate_; + ppapi::proxy::ResourceMessageTestSink sink_; + ppapi::host::PpapiHost ppapi_host_; + TestResourceHost resource_host_; + PepperDeviceEnumerationHostHelper device_enumeration_; + + private: + DISALLOW_COPY_AND_ASSIGN(PepperDeviceEnumerationHostHelperTest); +}; + +} // namespace + +TEST_F(PepperDeviceEnumerationHostHelperTest, EnumerateDevices) { + PpapiHostMsg_DeviceEnumeration_EnumerateDevices msg; + ppapi::proxy::ResourceMessageCallParams call_params( + resource_host_.pp_resource(), 123); + ppapi::host::HostMessageContext context(call_params); + int32_t result = PP_ERROR_FAILED; + ASSERT_TRUE(device_enumeration_.HandleResourceMessage(msg, &context, + &result)); + EXPECT_EQ(PP_OK_COMPLETIONPENDING, result); + + EXPECT_EQ(1U, delegate_.GetRegisteredCallbackCount()); + int request_id = delegate_.last_used_id(); + + std::vector<ppapi::DeviceRefData> data; + ppapi::DeviceRefData data_item; + data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE; + data_item.name = "name_1"; + data_item.id = "id_1"; + data.push_back(data_item); + data_item.type = PP_DEVICETYPE_DEV_VIDEOCAPTURE; + data_item.name = "name_2"; + data_item.id = "id_2"; + data.push_back(data_item); + ASSERT_TRUE(delegate_.SimulateEnumerateResult(request_id, true, data)); + + // StopEnumerateDevices() should have been called since the EnumerateDevices + // message is not a persistent request. + EXPECT_EQ(0U, delegate_.GetRegisteredCallbackCount()); + + // A reply message should have been sent to the test sink. + ppapi::proxy::ResourceMessageReplyParams reply_params; + IPC::Message reply_msg; + ASSERT_TRUE(sink_.GetFirstResourceReplyMatching( + PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply::ID, + &reply_params, &reply_msg)); + + EXPECT_EQ(call_params.sequence(), reply_params.sequence()); + EXPECT_EQ(PP_OK, reply_params.result()); + + std::vector<ppapi::DeviceRefData> reply_data; + ASSERT_TRUE(ppapi::UnpackMessage< + PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>( + reply_msg, &reply_data)); + EXPECT_EQ(data, reply_data); +} + +TEST_F(PepperDeviceEnumerationHostHelperTest, MonitorDeviceChange) { + uint32_t callback_id = 456; + SimulateMonitorDeviceChangeReceived(callback_id); + + EXPECT_EQ(1U, delegate_.GetRegisteredCallbackCount()); + int request_id = delegate_.last_used_id(); + + std::vector<ppapi::DeviceRefData> data; + ASSERT_TRUE(delegate_.SimulateEnumerateResult(request_id, true, data)); + + // StopEnumerateDevices() shouldn't be called because the MonitorDeviceChange + // message is a persistent request. + EXPECT_EQ(1U, delegate_.GetRegisteredCallbackCount()); + + CheckNotifyDeviceChangeMessage(callback_id, data); + + ppapi::DeviceRefData data_item; + data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE; + data_item.name = "name_1"; + data_item.id = "id_1"; + data.push_back(data_item); + data_item.type = PP_DEVICETYPE_DEV_VIDEOCAPTURE; + data_item.name = "name_2"; + data_item.id = "id_2"; + data.push_back(data_item); + ASSERT_TRUE(delegate_.SimulateEnumerateResult(request_id, true, data)); + EXPECT_EQ(1U, delegate_.GetRegisteredCallbackCount()); + + CheckNotifyDeviceChangeMessage(callback_id, data); + + uint32_t callback_id2 = 789; + SimulateMonitorDeviceChangeReceived(callback_id2); + + // StopEnumerateDevice() should have been called for the previous request. + EXPECT_EQ(1U, delegate_.GetRegisteredCallbackCount()); + int request_id2 = delegate_.last_used_id(); + + data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE; + data_item.name = "name_3"; + data_item.id = "id_3"; + data.push_back(data_item); + ASSERT_TRUE(delegate_.SimulateEnumerateResult(request_id2, true, data)); + + CheckNotifyDeviceChangeMessage(callback_id2, data); + + PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange msg; + ppapi::proxy::ResourceMessageCallParams call_params( + resource_host_.pp_resource(), 123); + ppapi::host::HostMessageContext context(call_params); + int32_t result = PP_ERROR_FAILED; + ASSERT_TRUE(device_enumeration_.HandleResourceMessage( + msg, &context, &result)); + EXPECT_EQ(PP_OK, result); + + EXPECT_EQ(0U, delegate_.GetRegisteredCallbackCount()); +} + +} // namespace content diff --git a/content/renderer/pepper/pepper_plugin_delegate_impl.cc b/content/renderer/pepper/pepper_plugin_delegate_impl.cc index 2500754..744631c 100644 --- a/content/renderer/pepper/pepper_plugin_delegate_impl.cc +++ b/content/renderer/pepper/pepper_plugin_delegate_impl.cc @@ -1450,6 +1450,9 @@ int PepperPluginDelegateImpl::EnumerateDevices( } void PepperPluginDelegateImpl::StopEnumerateDevices(int request_id) { + device_enumeration_event_handler_->UnregisterEnumerateDevicesCallback( + request_id); + #if defined(ENABLE_WEBRTC) // Need to post task since this function might be called inside the callback // of EnumerateDevices. |