summaryrefslogtreecommitdiffstats
path: root/content/renderer/pepper
diff options
context:
space:
mode:
authoryzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-05 02:44:18 +0000
committeryzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-05 02:44:18 +0000
commit4f01c76ed760e674cb86f2b0a17a779431e2aa71 (patch)
treea2d874fb3f21b65e07f0d75db567487f6bd4a38a /content/renderer/pepper
parent4afef6e27ecbcf6430c5d37881eca04c6b1f8d78 (diff)
downloadchromium_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')
-rw-r--r--content/renderer/pepper/pepper_audio_input_host.cc64
-rw-r--r--content/renderer/pepper/pepper_audio_input_host.h25
-rw-r--r--content/renderer/pepper/pepper_device_enumeration_event_handler.cc6
-rw-r--r--content/renderer/pepper/pepper_device_enumeration_event_handler.h1
-rw-r--r--content/renderer/pepper/pepper_device_enumeration_host_helper.cc197
-rw-r--r--content/renderer/pepper/pepper_device_enumeration_host_helper.h106
-rw-r--r--content/renderer/pepper/pepper_device_enumeration_host_helper_unittest.cc257
-rw-r--r--content/renderer/pepper/pepper_plugin_delegate_impl.cc3
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.