diff options
author | yzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-05 07:10:58 +0000 |
---|---|---|
committer | yzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-05 07:10:58 +0000 |
commit | 7ac673b55f9c2334d531c280f907e2d0edaed68b (patch) | |
tree | 1dbb373bcfb3cd61836fe17a3f1807f7aaf36ec5 | |
parent | 88f11549025ad46da215d208a016387619d7271d (diff) | |
download | chromium_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.cc | 7 | ||||
-rw-r--r-- | ppapi/cpp/array_output.h | 8 | ||||
-rw-r--r-- | ppapi/cpp/dev/audio_input_dev.cc | 107 | ||||
-rw-r--r-- | ppapi/cpp/dev/audio_input_dev.h | 33 | ||||
-rw-r--r-- | ppapi/cpp/dev/resource_array_dev.cc | 30 | ||||
-rw-r--r-- | ppapi/cpp/dev/resource_array_dev.h | 33 | ||||
-rw-r--r-- | ppapi/cpp/dev/video_capture_dev.cc | 100 | ||||
-rw-r--r-- | ppapi/cpp/dev/video_capture_dev.h | 25 | ||||
-rw-r--r-- | ppapi/cpp/output_traits.h | 6 | ||||
-rw-r--r-- | ppapi/examples/audio_input/audio_input.cc | 11 | ||||
-rw-r--r-- | ppapi/examples/video_capture/video_capture.cc | 15 | ||||
-rw-r--r-- | ppapi/utility/completion_callback_factory.h | 108 |
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_; |