summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-05 07:10:58 +0000
committeryzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-05 07:10:58 +0000
commit7ac673b55f9c2334d531c280f907e2d0edaed68b (patch)
tree1dbb373bcfb3cd61836fe17a3f1807f7aaf36ec5
parent88f11549025ad46da215d208a016387619d7271d (diff)
downloadchromium_src-7ac673b55f9c2334d531c280f907e2d0edaed68b.zip
chromium_src-7ac673b55f9c2334d531c280f907e2d0edaed68b.tar.gz
chromium_src-7ac673b55f9c2334d531c280f907e2d0edaed68b.tar.bz2
Change the cpp wrappers of audio input/video capture to use CompletionCallbackWithOutput.
And also fix a few bugs in the PP_ArrayOutput and CallbackWithOutput code. - Make sure POD members of Dispatcher\.* are properly initialized. - Avoid leaking var/resource references in DispatcherWithOutput\.*::operator(). BUG=None TEST=None Review URL: http://codereview.chromium.org/9965080 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@130849 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--ppapi/cpp/array_output.cc7
-rw-r--r--ppapi/cpp/array_output.h8
-rw-r--r--ppapi/cpp/dev/audio_input_dev.cc107
-rw-r--r--ppapi/cpp/dev/audio_input_dev.h33
-rw-r--r--ppapi/cpp/dev/resource_array_dev.cc30
-rw-r--r--ppapi/cpp/dev/resource_array_dev.h33
-rw-r--r--ppapi/cpp/dev/video_capture_dev.cc100
-rw-r--r--ppapi/cpp/dev/video_capture_dev.h25
-rw-r--r--ppapi/cpp/output_traits.h6
-rw-r--r--ppapi/examples/audio_input/audio_input.cc11
-rw-r--r--ppapi/examples/video_capture/video_capture.cc15
-rw-r--r--ppapi/utility/completion_callback_factory.h108
12 files changed, 220 insertions, 263 deletions
diff --git a/ppapi/cpp/array_output.cc b/ppapi/cpp/array_output.cc
index 4cb8c85..62252f7 100644
--- a/ppapi/cpp/array_output.cc
+++ b/ppapi/cpp/array_output.cc
@@ -21,6 +21,13 @@ VarArrayOutputAdapterWithStorage::VarArrayOutputAdapterWithStorage()
set_output(&temp_storage_);
}
+VarArrayOutputAdapterWithStorage::~VarArrayOutputAdapterWithStorage() {
+ if (!temp_storage_.empty()) {
+ // An easy way to release the var references held by this object.
+ output();
+ }
+}
+
std::vector<Var>& VarArrayOutputAdapterWithStorage::output() {
PP_DCHECK(output_storage_.empty());
diff --git a/ppapi/cpp/array_output.h b/ppapi/cpp/array_output.h
index 7081507..57fa790 100644
--- a/ppapi/cpp/array_output.h
+++ b/ppapi/cpp/array_output.h
@@ -201,6 +201,7 @@ class ArrayOutputAdapterWithStorage : public ArrayOutputAdapter<T> {
class VarArrayOutputAdapterWithStorage : public ArrayOutputAdapter<PP_Var> {
public:
VarArrayOutputAdapterWithStorage();
+ virtual ~VarArrayOutputAdapterWithStorage();
// Returns the final array of resource objects, converting the PP_Vars
// written by the browser to pp::Var objects.
@@ -237,6 +238,13 @@ class ResourceArrayOutputAdapterWithStorage
set_output(&temp_storage_);
}
+ virtual ~ResourceArrayOutputAdapterWithStorage() {
+ if (!temp_storage_.empty()) {
+ // An easy way to release the resource references held by this object.
+ output();
+ }
+ }
+
// Returns the final array of resource objects, converting the PP_Resources
// written by the browser to resource objects.
//
diff --git a/ppapi/cpp/dev/audio_input_dev.cc b/ppapi/cpp/dev/audio_input_dev.cc
index 2429259..92ad838 100644
--- a/ppapi/cpp/dev/audio_input_dev.cc
+++ b/ppapi/cpp/dev/audio_input_dev.cc
@@ -4,14 +4,10 @@
#include "ppapi/cpp/dev/audio_input_dev.h"
-#include "ppapi/c/dev/ppb_audio_input_dev.h"
#include "ppapi/c/pp_bool.h"
#include "ppapi/c/pp_errors.h"
-#include "ppapi/cpp/completion_callback.h"
-#include "ppapi/cpp/dev/device_ref_dev.h"
#include "ppapi/cpp/dev/resource_array_dev.h"
#include "ppapi/cpp/instance_handle.h"
-#include "ppapi/cpp/module.h"
#include "ppapi/cpp/module_impl.h"
namespace pp {
@@ -28,25 +24,7 @@ template <> const char* interface_name<PPB_AudioInput_Dev_0_1>() {
} // namespace
-struct AudioInput_Dev::EnumerateDevicesState {
- EnumerateDevicesState(std::vector<DeviceRef_Dev>* in_devices,
- const CompletionCallback& in_callback,
- AudioInput_Dev* in_audio_input)
- : devices_resource(0),
- devices(in_devices),
- callback(in_callback),
- audio_input(in_audio_input) {
- }
-
- PP_Resource devices_resource;
- // This is owned by the user of AudioInput_Dev::EnumerateDevices().
- std::vector<DeviceRef_Dev>* devices;
- CompletionCallback callback;
- AudioInput_Dev* audio_input;
-};
-
-AudioInput_Dev::AudioInput_Dev() : enum_state_(NULL),
- audio_input_callback_(NULL),
+AudioInput_Dev::AudioInput_Dev() : audio_input_callback_(NULL),
user_data_(NULL) {
}
@@ -55,7 +33,6 @@ AudioInput_Dev::AudioInput_Dev(const InstanceHandle& instance,
PPB_AudioInput_Callback callback,
void* user_data)
: config_(config),
- enum_state_(NULL),
audio_input_callback_(callback),
user_data_(user_data) {
if (has_interface<PPB_AudioInput_Dev_0_2>()) {
@@ -68,8 +45,7 @@ AudioInput_Dev::AudioInput_Dev(const InstanceHandle& instance,
}
AudioInput_Dev::AudioInput_Dev(const InstanceHandle& instance)
- : enum_state_(NULL),
- audio_input_callback_(NULL),
+ : audio_input_callback_(NULL),
user_data_(NULL) {
if (has_interface<PPB_AudioInput_Dev_0_2>()) {
PassRefFromConstructor(get_interface<PPB_AudioInput_Dev_0_2>()->Create(
@@ -77,26 +53,7 @@ AudioInput_Dev::AudioInput_Dev(const InstanceHandle& instance)
}
}
-AudioInput_Dev::AudioInput_Dev(const AudioInput_Dev& other)
- : Resource(other),
- config_(other.config_),
- enum_state_(NULL),
- audio_input_callback_(other.audio_input_callback_),
- user_data_(other.user_data_) {
-}
-
AudioInput_Dev::~AudioInput_Dev() {
- AbortEnumerateDevices();
-}
-
-AudioInput_Dev& AudioInput_Dev::operator=(const AudioInput_Dev& other) {
- AbortEnumerateDevices();
-
- Resource::operator=(other);
- config_ = other.config_;
- audio_input_callback_ = other.audio_input_callback_;
- user_data_ = other.user_data_;
- return *this;
}
// static
@@ -105,23 +62,21 @@ bool AudioInput_Dev::IsAvailable() {
has_interface<PPB_AudioInput_Dev_0_1>();
}
-int32_t AudioInput_Dev::EnumerateDevices(std::vector<DeviceRef_Dev>* devices,
- const CompletionCallback& callback) {
+int32_t AudioInput_Dev::EnumerateDevices(
+ const CompletionCallbackWithOutput<std::vector<DeviceRef_Dev> >& callback) {
if (!has_interface<PPB_AudioInput_Dev_0_2>())
return callback.MayForce(PP_ERROR_NOINTERFACE);
- if (!devices)
- return callback.MayForce(PP_ERROR_BADARGUMENT);
if (!callback.pp_completion_callback().func)
return callback.MayForce(PP_ERROR_BLOCKS_MAIN_THREAD);
- if (enum_state_)
- return callback.MayForce(PP_ERROR_INPROGRESS);
- // It will be deleted in OnEnumerateDevicesComplete().
- enum_state_ = new EnumerateDevicesState(devices, callback, this);
+ // ArrayOutputCallbackConverter is responsible to delete it.
+ ResourceArray_Dev::ArrayOutputCallbackData* data =
+ new ResourceArray_Dev::ArrayOutputCallbackData(
+ callback.output(), callback.pp_completion_callback());
return get_interface<PPB_AudioInput_Dev_0_2>()->EnumerateDevices(
- pp_resource(), &enum_state_->devices_resource,
- PP_MakeCompletionCallback(&AudioInput_Dev::OnEnumerateDevicesComplete,
- enum_state_));
+ pp_resource(), &data->resource_array_output,
+ PP_MakeCompletionCallback(
+ &ResourceArray_Dev::ArrayOutputCallbackConverter, data));
}
int32_t AudioInput_Dev::Open(const DeviceRef_Dev& device_ref,
@@ -196,44 +151,4 @@ void AudioInput_Dev::Close() {
get_interface<PPB_AudioInput_Dev_0_2>()->Close(pp_resource());
}
-void AudioInput_Dev::AbortEnumerateDevices() {
- if (enum_state_) {
- enum_state_->devices = NULL;
- Module::Get()->core()->CallOnMainThread(0, enum_state_->callback,
- PP_ERROR_ABORTED);
- enum_state_->audio_input = NULL;
- enum_state_ = NULL;
- }
-}
-
-// static
-void AudioInput_Dev::OnEnumerateDevicesComplete(void* user_data,
- int32_t result) {
- EnumerateDevicesState* enum_state =
- static_cast<EnumerateDevicesState*>(user_data);
-
- bool need_to_callback = !!enum_state->audio_input;
-
- if (result == PP_OK) {
- // It will take care of releasing the reference.
- ResourceArray_Dev resources(pp::PASS_REF,
- enum_state->devices_resource);
-
- if (need_to_callback) {
- enum_state->devices->clear();
- for (uint32_t index = 0; index < resources.size(); ++index) {
- DeviceRef_Dev device(resources[index]);
- enum_state->devices->push_back(device);
- }
- }
- }
-
- if (need_to_callback) {
- enum_state->audio_input->enum_state_ = NULL;
- enum_state->callback.Run(result);
- }
-
- delete enum_state;
-}
-
} // namespace pp
diff --git a/ppapi/cpp/dev/audio_input_dev.h b/ppapi/cpp/dev/audio_input_dev.h
index 2bcccc3..2b2b6bb 100644
--- a/ppapi/cpp/dev/audio_input_dev.h
+++ b/ppapi/cpp/dev/audio_input_dev.h
@@ -9,12 +9,12 @@
#include "ppapi/c/dev/ppb_audio_input_dev.h"
#include "ppapi/cpp/audio_config.h"
+#include "ppapi/cpp/completion_callback.h"
+#include "ppapi/cpp/dev/device_ref_dev.h"
#include "ppapi/cpp/resource.h"
namespace pp {
-class CompletionCallback;
-class DeviceRef_Dev;
class InstanceHandle;
class AudioInput_Dev : public Resource {
@@ -38,12 +38,8 @@ class AudioInput_Dev : public Resource {
/// resource. Please use the 5-parameter Open() if you used this constructor.
explicit AudioInput_Dev(const InstanceHandle& instance);
- AudioInput_Dev(const AudioInput_Dev& other);
-
virtual ~AudioInput_Dev();
- AudioInput_Dev& operator=(const AudioInput_Dev& other);
-
/// Static function for determining whether the browser supports the required
/// AudioInput interface.
///
@@ -63,10 +59,14 @@ class AudioInput_Dev : public Resource {
/// struct.
const AudioConfig& config() const { return config_; }
- /// |devices| must stay alive until either this AudioInput_Dev object goes
- /// away or |callback| is run, if this method returns PP_OK_COMPLETIONPENDING.
- int32_t EnumerateDevices(std::vector<DeviceRef_Dev>* devices,
- const CompletionCallback& callback);
+ // TODO(yzshen, brettw): If we forward declare DeviceRef_Dev (as opposed to
+ // including its .h file), it still compiles. However, it is not recognized as
+ // a derived class of Resource and does the wrong thing!
+ // This is due to the limitation of IsBaseOf in ppapi/cpp/output_traits.h. We
+ // need to figure out a way to overcome this problem.
+ int32_t EnumerateDevices(
+ const CompletionCallbackWithOutput<std::vector<DeviceRef_Dev> >&
+ callback);
/// If |device_ref| is null (i.e., is_null() returns true), the default device
/// will be used.
@@ -91,21 +91,8 @@ class AudioInput_Dev : public Resource {
void Close();
private:
- struct EnumerateDevicesState;
-
- void AbortEnumerateDevices();
-
- // |user_data| is an EnumerateDevicesState object. It is this method's
- // responsibility to delete it.
- static void OnEnumerateDevicesComplete(void* user_data, int32_t result);
-
AudioConfig config_;
- // It is set in EnumerateDevices(), and cleared in AbortEnumerateDevices() or
- // OnEnumerateDevicesComplete(). The object will be deleted by
- // OnEnumerateDevicesComplete().
- EnumerateDevicesState* enum_state_;
-
// Used to store the arguments of Open() for the v0.2 interface.
PPB_AudioInput_Callback audio_input_callback_;
void* user_data_;
diff --git a/ppapi/cpp/dev/resource_array_dev.cc b/ppapi/cpp/dev/resource_array_dev.cc
index 6a8493f..5bd2549 100644
--- a/ppapi/cpp/dev/resource_array_dev.cc
+++ b/ppapi/cpp/dev/resource_array_dev.cc
@@ -5,7 +5,10 @@
#include "ppapi/cpp/dev/resource_array_dev.h"
#include "ppapi/c/dev/ppb_resource_array_dev.h"
+#include "ppapi/c/pp_errors.h"
#include "ppapi/cpp/instance_handle.h"
+#include "ppapi/cpp/logging.h"
+#include "ppapi/cpp/module.h"
#include "ppapi/cpp/module_impl.h"
namespace pp {
@@ -59,4 +62,31 @@ PP_Resource ResourceArray_Dev::operator[](uint32_t index) const {
return get_interface<PPB_ResourceArray_Dev>()->GetAt(pp_resource(), index);
}
+// static
+void ResourceArray_Dev::ArrayOutputCallbackConverter(void* user_data,
+ int32_t result) {
+ ArrayOutputCallbackData* data =
+ static_cast<ArrayOutputCallbackData*>(user_data);
+
+ // data->resource_array_output should remain 0 if the call failed.
+ ResourceArray_Dev resources(PASS_REF, data->resource_array_output);
+ PP_DCHECK(resources.is_null() || result == PP_OK);
+
+ // Need to issue the "GetDataBuffer" even for error cases and when the number
+ // of items is 0.
+ PP_Resource* output_buf = static_cast<PP_Resource*>(
+ data->output.GetDataBuffer(
+ data->output.user_data, resources.is_null() ? 0 : resources.size(),
+ sizeof(PP_Resource)));
+ if (output_buf) {
+ for (uint32_t index = 0; index < resources.size(); ++index) {
+ output_buf[index] = resources[index];
+ Module::Get()->core()->AddRefResource(output_buf[index]);
+ }
+ }
+
+ PP_RunCompletionCallback(&data->original_callback, result);
+ delete data;
+}
+
} // namespace pp
diff --git a/ppapi/cpp/dev/resource_array_dev.h b/ppapi/cpp/dev/resource_array_dev.h
index 9d9635c..f9daf5f 100644
--- a/ppapi/cpp/dev/resource_array_dev.h
+++ b/ppapi/cpp/dev/resource_array_dev.h
@@ -5,6 +5,8 @@
#ifndef PPAPI_CPP_DEV_RESOURCE_ARRAY_DEV_H_
#define PPAPI_CPP_DEV_RESOURCE_ARRAY_DEV_H_
+#include "ppapi/c/pp_array_output.h"
+#include "ppapi/c/pp_completion_callback.h"
#include "ppapi/c/pp_stdint.h"
#include "ppapi/cpp/resource.h"
@@ -14,6 +16,21 @@ class InstanceHandle;
class ResourceArray_Dev : public Resource {
public:
+ // Heap-allocated data passed to ArrayOutputCallbackConverter(). Please see
+ // the comment of ArrayOutputCallbackConverter() for more details.
+ struct ArrayOutputCallbackData {
+ ArrayOutputCallbackData(const PP_ArrayOutput& array_output,
+ const PP_CompletionCallback& callback)
+ : resource_array_output(0),
+ output(array_output),
+ original_callback(callback) {
+ }
+
+ PP_Resource resource_array_output;
+ PP_ArrayOutput output;
+ PP_CompletionCallback original_callback;
+ };
+
ResourceArray_Dev();
ResourceArray_Dev(PassRef, PP_Resource resource);
@@ -31,6 +48,22 @@ class ResourceArray_Dev : public Resource {
uint32_t size() const;
PP_Resource operator[](uint32_t index) const;
+
+ // This is an adapter for backward compatibility. It works with those APIs
+ // which take a PPB_ResourceArray_Dev resource as output parameter, and
+ // returns results using PP_ArrayOutput. For example:
+ //
+ // ResourceArray_Dev::ArrayOutputCallbackData* data =
+ // new ResourceArray_Dev::ArrayOutputCallbackData(
+ // pp_array_output, callback);
+ // ppb_foo->Bar(
+ // foo_resource, &data->resource_array_output,
+ // PP_MakeCompletionCallback(
+ // &ResourceArray_Dev::ArrayOutputCallbackConverter, data));
+ //
+ // It takes a heap-allocated ArrayOutputCallbackData struct passed as the user
+ // data, and deletes it when the call completes.
+ static void ArrayOutputCallbackConverter(void* user_data, int32_t result);
};
} // namespace pp
diff --git a/ppapi/cpp/dev/video_capture_dev.cc b/ppapi/cpp/dev/video_capture_dev.cc
index 94ed933..4fc11d5 100644
--- a/ppapi/cpp/dev/video_capture_dev.cc
+++ b/ppapi/cpp/dev/video_capture_dev.cc
@@ -6,11 +6,8 @@
#include "ppapi/c/dev/ppb_video_capture_dev.h"
#include "ppapi/c/pp_errors.h"
-#include "ppapi/cpp/completion_callback.h"
-#include "ppapi/cpp/dev/device_ref_dev.h"
#include "ppapi/cpp/dev/resource_array_dev.h"
#include "ppapi/cpp/instance_handle.h"
-#include "ppapi/cpp/module.h"
#include "ppapi/cpp/module_impl.h"
namespace pp {
@@ -27,25 +24,8 @@ template <> const char* interface_name<PPB_VideoCapture_Dev_0_1>() {
} // namespace
-struct VideoCapture_Dev::EnumerateDevicesState {
- EnumerateDevicesState(std::vector<DeviceRef_Dev>* in_devices,
- const CompletionCallback& in_callback,
- VideoCapture_Dev* in_video_capture)
- : devices_resource(0),
- devices(in_devices),
- callback(in_callback),
- video_capture(in_video_capture) {
- }
-
- PP_Resource devices_resource;
- std::vector<DeviceRef_Dev>* devices;
- CompletionCallback callback;
- VideoCapture_Dev* video_capture;
-};
-
VideoCapture_Dev::VideoCapture_Dev(const InstanceHandle& instance)
- : enum_state_(NULL),
- requested_info_(),
+ : requested_info_(),
buffer_count_(0) {
if (has_interface<PPB_VideoCapture_Dev_0_2>()) {
PassRefFromConstructor(get_interface<PPB_VideoCapture_Dev_0_2>()->Create(
@@ -58,30 +38,11 @@ VideoCapture_Dev::VideoCapture_Dev(const InstanceHandle& instance)
VideoCapture_Dev::VideoCapture_Dev(PP_Resource resource)
: Resource(resource),
- enum_state_(NULL),
requested_info_(),
buffer_count_(0) {
}
-VideoCapture_Dev::VideoCapture_Dev(const VideoCapture_Dev& other)
- : Resource(other),
- enum_state_(NULL),
- requested_info_(other.requested_info_),
- buffer_count_(other.buffer_count_) {
-}
-
VideoCapture_Dev::~VideoCapture_Dev() {
- AbortEnumerateDevices();
-}
-
-VideoCapture_Dev& VideoCapture_Dev::operator=(
- const VideoCapture_Dev& other) {
- AbortEnumerateDevices();
-
- Resource::operator=(other);
- requested_info_ = other.requested_info_;
- buffer_count_ = other.buffer_count_;
- return *this;
}
// static
@@ -90,23 +51,21 @@ bool VideoCapture_Dev::IsAvailable() {
has_interface<PPB_VideoCapture_Dev_0_1>();
}
-int32_t VideoCapture_Dev::EnumerateDevices(std::vector<DeviceRef_Dev>* devices,
- const CompletionCallback& callback) {
+int32_t VideoCapture_Dev::EnumerateDevices(
+ const CompletionCallbackWithOutput<std::vector<DeviceRef_Dev> >& callback) {
if (!has_interface<PPB_VideoCapture_Dev_0_2>())
return callback.MayForce(PP_ERROR_NOINTERFACE);
- if (!devices)
- return callback.MayForce(PP_ERROR_BADARGUMENT);
if (!callback.pp_completion_callback().func)
return callback.MayForce(PP_ERROR_BLOCKS_MAIN_THREAD);
- if (enum_state_)
- return callback.MayForce(PP_ERROR_INPROGRESS);
- // It will be deleted in OnEnumerateDevicesComplete().
- enum_state_ = new EnumerateDevicesState(devices, callback, this);
+ // ArrayOutputCallbackConverter is responsible to delete it.
+ ResourceArray_Dev::ArrayOutputCallbackData* data =
+ new ResourceArray_Dev::ArrayOutputCallbackData(
+ callback.output(), callback.pp_completion_callback());
return get_interface<PPB_VideoCapture_Dev_0_2>()->EnumerateDevices(
- pp_resource(), &enum_state_->devices_resource,
- PP_MakeCompletionCallback(&VideoCapture_Dev::OnEnumerateDevicesComplete,
- enum_state_));
+ pp_resource(), &data->resource_array_output,
+ PP_MakeCompletionCallback(
+ &ResourceArray_Dev::ArrayOutputCallbackConverter, data));
}
int32_t VideoCapture_Dev::Open(
@@ -179,43 +138,4 @@ void VideoCapture_Dev::Close() {
get_interface<PPB_VideoCapture_Dev_0_2>()->Close(pp_resource());
}
-void VideoCapture_Dev::AbortEnumerateDevices() {
- if (enum_state_) {
- enum_state_->devices = NULL;
- Module::Get()->core()->CallOnMainThread(0, enum_state_->callback,
- PP_ERROR_ABORTED);
- enum_state_->video_capture = NULL;
- enum_state_ = NULL;
- }
-}
-
-// static
-void VideoCapture_Dev::OnEnumerateDevicesComplete(void* user_data,
- int32_t result) {
- EnumerateDevicesState* enum_state =
- static_cast<EnumerateDevicesState*>(user_data);
-
- bool need_to_callback = !!enum_state->video_capture;
-
- if (result == PP_OK) {
- // It will take care of releasing the reference.
- ResourceArray_Dev resources(pp::PASS_REF, enum_state->devices_resource);
-
- if (need_to_callback) {
- enum_state->devices->clear();
- for (uint32_t index = 0; index < resources.size(); ++index) {
- DeviceRef_Dev device(resources[index]);
- enum_state->devices->push_back(device);
- }
- }
- }
-
- if (need_to_callback) {
- enum_state->video_capture->enum_state_ = NULL;
- enum_state->callback.Run(result);
- }
-
- delete enum_state;
-}
-
} // namespace pp
diff --git a/ppapi/cpp/dev/video_capture_dev.h b/ppapi/cpp/dev/video_capture_dev.h
index 57f6e1d..87ce50d 100644
--- a/ppapi/cpp/dev/video_capture_dev.h
+++ b/ppapi/cpp/dev/video_capture_dev.h
@@ -8,31 +8,27 @@
#include <vector>
#include "ppapi/c/dev/pp_video_capture_dev.h"
+#include "ppapi/cpp/completion_callback.h"
+#include "ppapi/cpp/dev/device_ref_dev.h"
#include "ppapi/cpp/resource.h"
namespace pp {
-class CompletionCallback;
-class DeviceRef_Dev;
class InstanceHandle;
class VideoCapture_Dev : public Resource {
public:
explicit VideoCapture_Dev(const InstanceHandle& instance);
VideoCapture_Dev(PP_Resource resource);
- VideoCapture_Dev(const VideoCapture_Dev& other);
virtual ~VideoCapture_Dev();
- VideoCapture_Dev& operator=(const VideoCapture_Dev& other);
-
// Returns true if the required interface is available.
static bool IsAvailable();
- // |devices| must stay alive until either this VideoCapture_Dev object goes
- // away or |callback| is run.
- int32_t EnumerateDevices(std::vector<DeviceRef_Dev>* devices,
- const CompletionCallback& callback);
+ int32_t EnumerateDevices(
+ const CompletionCallbackWithOutput<std::vector<DeviceRef_Dev> >&
+ callback);
int32_t Open(const DeviceRef_Dev& device_ref,
const PP_VideoCaptureDeviceInfo_Dev& requested_info,
uint32_t buffer_count,
@@ -43,17 +39,6 @@ class VideoCapture_Dev : public Resource {
void Close();
private:
- struct EnumerateDevicesState;
-
- void AbortEnumerateDevices();
-
- // |user_data| is an EnumerateDevicesState object. It is this method's
- // responsibility to delete it.
- static void OnEnumerateDevicesComplete(void* user_data, int32_t result);
-
- // Not owned by this object.
- EnumerateDevicesState* enum_state_;
-
// Used to store the arguments of Open() when using the v0.1 interface.
PP_VideoCaptureDeviceInfo_Dev requested_info_;
uint32_t buffer_count_;
diff --git a/ppapi/cpp/output_traits.h b/ppapi/cpp/output_traits.h
index 237b0bc..963f296 100644
--- a/ppapi/cpp/output_traits.h
+++ b/ppapi/cpp/output_traits.h
@@ -168,8 +168,8 @@ struct GenericVectorCallbackOutputTraits {
};
// Output traits for all vectors of resource types. It is implemented to pass
-// a PP_Resource* as an output parameter to the browser, and convert to the
-// given resource object type T when passing to the plugin.
+// a PP_ArrayOutput parameter to the browser, and convert the returned resources
+// to a vector of the given resource object type T when passing to the plugin.
//
// Note that this class is parameterized by the resource object, for example
// ResourceVectorCallbackOutputTraits<pp::FileRef>. This is used as a base
@@ -192,7 +192,7 @@ struct ResourceVectorCallbackOutputTraits {
// arrays of resources and arrays of POD (ints, structs, etc.) by inheriting
// from the appropriate base class depending on whether the given type derives
// from pp::Resource. This trick allows us to do this once rather than writing
-// specilalizations for every resource object type.
+// specializations for every resource object type.
template<typename T>
struct CallbackOutputTraits< std::vector<T> >
: public InheritIf<GenericVectorCallbackOutputTraits<T>,
diff --git a/ppapi/examples/audio_input/audio_input.cc b/ppapi/examples/audio_input/audio_input.cc
index 7d156b7..62bf299 100644
--- a/ppapi/examples/audio_input/audio_input.cc
+++ b/ppapi/examples/audio_input/audio_input.cc
@@ -93,9 +93,10 @@ class MyInstance : public pp::Instance {
if (message_data.is_string()) {
std::string event = message_data.AsString();
if (event == "PageInitialized") {
- pp::CompletionCallback callback = callback_factory_.NewCallback(
- &MyInstance::EnumerateDevicesFinished);
- int32_t result = audio_input_.EnumerateDevices(&devices_, callback);
+ pp::CompletionCallbackWithOutput<std::vector<pp::DeviceRef_Dev> >
+ callback = callback_factory_.NewCallbackWithOutput(
+ &MyInstance::EnumerateDevicesFinished);
+ int32_t result = audio_input_.EnumerateDevices(callback);
if (result != PP_OK_COMPLETIONPENDING)
PostMessage(pp::Var("EnumerationFailed"));
} else if (event == "UseDefault") {
@@ -241,10 +242,12 @@ class MyInstance : public pp::Instance {
}
}
- void EnumerateDevicesFinished(int32_t result) {
+ void EnumerateDevicesFinished(int32_t result,
+ std::vector<pp::DeviceRef_Dev>& devices) {
static const char* const kDelimiter = "#__#";
if (result == PP_OK) {
+ devices_.swap(devices);
std::string device_names;
for (size_t index = 0; index < devices_.size(); ++index) {
pp::Var name = devices_[index].GetName();
diff --git a/ppapi/examples/video_capture/video_capture.cc b/ppapi/examples/video_capture/video_capture.cc
index 20c0c75..07239c6 100644
--- a/ppapi/examples/video_capture/video_capture.cc
+++ b/ppapi/examples/video_capture/video_capture.cc
@@ -118,7 +118,8 @@ class VCDemoInstance : public pp::Instance,
void CreateYUVTextures();
void Open(const pp::DeviceRef_Dev& device);
- void EnumerateDevicesFinished(int32_t result);
+ void EnumerateDevicesFinished(int32_t result,
+ std::vector<pp::DeviceRef_Dev>& devices);
void OpenFinished(int32_t result);
pp::Size position_size_;
@@ -185,9 +186,10 @@ void VCDemoInstance::HandleMessage(const pp::Var& message_data) {
if (message_data.is_string()) {
std::string event = message_data.AsString();
if (event == "PageInitialized") {
- pp::CompletionCallback callback = callback_factory_.NewCallback(
- &VCDemoInstance::EnumerateDevicesFinished);
- video_capture_.EnumerateDevices(&devices_, callback);
+ pp::CompletionCallbackWithOutput<std::vector<pp::DeviceRef_Dev> >
+ callback = callback_factory_.NewCallbackWithOutput(
+ &VCDemoInstance::EnumerateDevicesFinished);
+ video_capture_.EnumerateDevices(callback);
} else if (event == "UseDefault") {
Open(pp::DeviceRef_Dev());
} else if (event == "UseDefault(v0.1)") {
@@ -403,10 +405,13 @@ void VCDemoInstance::Open(const pp::DeviceRef_Dev& device) {
video_capture_.Open(device, capture_info_, 4, callback);
}
-void VCDemoInstance::EnumerateDevicesFinished(int32_t result) {
+void VCDemoInstance::EnumerateDevicesFinished(
+ int32_t result,
+ std::vector<pp::DeviceRef_Dev>& devices) {
static const char* const kDelimiter = "#__#";
if (result == PP_OK) {
+ devices_.swap(devices);
std::string device_names;
for (size_t index = 0; index < devices_.size(); ++index) {
pp::Var name = devices_[index].GetName();
diff --git a/ppapi/utility/completion_callback_factory.h b/ppapi/utility/completion_callback_factory.h
index e7e7c86..d521f4b 100644
--- a/ppapi/utility/completion_callback_factory.h
+++ b/ppapi/utility/completion_callback_factory.h
@@ -570,8 +570,12 @@ class CompletionCallbackFactory {
static void Thunk(void* user_data, int32_t result) {
Self* self = static_cast<Self*>(user_data);
T* object = self->back_pointer_->GetObject();
- if (object)
- (*self->dispatcher_)(object, result);
+
+ // Please note that |object| may be NULL at this point. But we still need
+ // to call into Dispatcher::operator() in that case, so that it can do
+ // necessary cleanup.
+ (*self->dispatcher_)(object, result);
+
delete self;
}
@@ -592,7 +596,8 @@ class CompletionCallbackFactory {
explicit Dispatcher0(Method method) : method_(method) {
}
void operator()(T* object, int32_t result) {
- (object->*method_)(result);
+ if (object)
+ (object->*method_)(result);
}
private:
Method method_;
@@ -604,11 +609,21 @@ class CompletionCallbackFactory {
typedef Output OutputType;
typedef internal::CallbackOutputTraits<Output> Traits;
- DispatcherWithOutput0() : method_(NULL) {}
- DispatcherWithOutput0(Method method) : method_(method) {
+ DispatcherWithOutput0()
+ : method_(NULL),
+ output_() {
+ }
+ DispatcherWithOutput0(Method method)
+ : method_(method),
+ output_() {
}
void operator()(T* object, int32_t result) {
- (object->*method_)(result, Traits::StorageToPluginArg(output_));
+ // We must call Traits::StorageToPluginArg() even if we don't need to call
+ // the callback anymore, otherwise we may leak resource or var references.
+ if (object)
+ (object->*method_)(result, Traits::StorageToPluginArg(output_));
+ else
+ Traits::StorageToPluginArg(output_);
}
typename Traits::StorageType* output() {
return &output_;
@@ -622,13 +637,17 @@ class CompletionCallbackFactory {
template <typename Method, typename A>
class Dispatcher1 {
public:
- Dispatcher1() : method_(NULL) {}
+ Dispatcher1()
+ : method_(NULL),
+ a_() {
+ }
Dispatcher1(Method method, const A& a)
: method_(method),
a_(a) {
}
void operator()(T* object, int32_t result) {
- (object->*method_)(result, a_);
+ if (object)
+ (object->*method_)(result, a_);
}
private:
Method method_;
@@ -641,13 +660,23 @@ class CompletionCallbackFactory {
typedef Output OutputType;
typedef internal::CallbackOutputTraits<Output> Traits;
- DispatcherWithOutput1() : method_(NULL) {}
+ DispatcherWithOutput1()
+ : method_(NULL),
+ a_(),
+ output_() {
+ }
DispatcherWithOutput1(Method method, const A& a)
: method_(method),
- a_(a) {
+ a_(a),
+ output_() {
}
void operator()(T* object, int32_t result) {
- (object->*method_)(result, Traits::StorageToPluginArg(output_), a_);
+ // We must call Traits::StorageToPluginArg() even if we don't need to call
+ // the callback anymore, otherwise we may leak resource or var references.
+ if (object)
+ (object->*method_)(result, Traits::StorageToPluginArg(output_), a_);
+ else
+ Traits::StorageToPluginArg(output_);
}
typename Traits::StorageType* output() {
return &output_;
@@ -662,14 +691,19 @@ class CompletionCallbackFactory {
template <typename Method, typename A, typename B>
class Dispatcher2 {
public:
- Dispatcher2() : method_(NULL) {}
+ Dispatcher2()
+ : method_(NULL),
+ a_(),
+ b_() {
+ }
Dispatcher2(Method method, const A& a, const B& b)
: method_(method),
a_(a),
b_(b) {
}
void operator()(T* object, int32_t result) {
- (object->*method_)(result, a_, b_);
+ if (object)
+ (object->*method_)(result, a_, b_);
}
private:
Method method_;
@@ -683,14 +717,25 @@ class CompletionCallbackFactory {
typedef Output OutputType;
typedef internal::CallbackOutputTraits<Output> Traits;
- DispatcherWithOutput2() : method_(NULL) {}
+ DispatcherWithOutput2()
+ : method_(NULL),
+ a_(),
+ b_(),
+ output_() {
+ }
DispatcherWithOutput2(Method method, const A& a, const B& b)
: method_(method),
a_(a),
- b_(b) {
+ b_(b),
+ output_() {
}
void operator()(T* object, int32_t result) {
- (object->*method_)(result, Traits::StorageToPluginArg(output_), a_, b_);
+ // We must call Traits::StorageToPluginArg() even if we don't need to call
+ // the callback anymore, otherwise we may leak resource or var references.
+ if (object)
+ (object->*method_)(result, Traits::StorageToPluginArg(output_), a_, b_);
+ else
+ Traits::StorageToPluginArg(output_);
}
typename Traits::StorageType* output() {
return &output_;
@@ -706,7 +751,12 @@ class CompletionCallbackFactory {
template <typename Method, typename A, typename B, typename C>
class Dispatcher3 {
public:
- Dispatcher3() : method_(NULL) {}
+ Dispatcher3()
+ : method_(NULL),
+ a_(),
+ b_(),
+ c_() {
+ }
Dispatcher3(Method method, const A& a, const B& b, const C& c)
: method_(method),
a_(a),
@@ -714,7 +764,8 @@ class CompletionCallbackFactory {
c_(c) {
}
void operator()(T* object, int32_t result) {
- (object->*method_)(result, a_, b_, c_);
+ if (object)
+ (object->*method_)(result, a_, b_, c_);
}
private:
Method method_;
@@ -730,16 +781,29 @@ class CompletionCallbackFactory {
typedef Output OutputType;
typedef internal::CallbackOutputTraits<Output> Traits;
- DispatcherWithOutput3() : method_(NULL) {}
+ DispatcherWithOutput3()
+ : method_(NULL),
+ a_(),
+ b_(),
+ c_(),
+ output_() {
+ }
DispatcherWithOutput3(Method method, const A& a, const B& b, const C& c)
: method_(method),
a_(a),
b_(b),
- c_(c) {
+ c_(c),
+ output_() {
}
void operator()(T* object, int32_t result) {
- (object->*method_)(result, Traits::StorageToPluginArg(output_),
- a_, b_, c_);
+ // We must call Traits::StorageToPluginArg() even if we don't need to call
+ // the callback anymore, otherwise we may leak resource or var references.
+ if (object) {
+ (object->*method_)(result, Traits::StorageToPluginArg(output_),
+ a_, b_, c_);
+ } else {
+ Traits::StorageToPluginArg(output_);
+ }
}
typename Traits::StorageType* output() {
return &output_;