Chromium Code Reviews| Index: content/renderer/pepper_plugin_delegate_impl.cc |
| diff --git a/content/renderer/pepper_plugin_delegate_impl.cc b/content/renderer/pepper_plugin_delegate_impl.cc |
| index ffc7fc1960c0092dbff193f32dd4a6e2e3198cf1..da10831b0d3434c7af24b850a6b876fa97322c7f 100644 |
| --- a/content/renderer/pepper_plugin_delegate_impl.cc |
| +++ b/content/renderer/pepper_plugin_delegate_impl.cc |
| @@ -5,6 +5,7 @@ |
| #include "content/renderer/pepper_plugin_delegate_impl.h" |
| #include <cmath> |
| +#include <map> |
| #include <queue> |
| #include "base/bind.h" |
| @@ -13,8 +14,6 @@ |
| #include "base/file_path.h" |
| #include "base/file_util_proxy.h" |
| #include "base/logging.h" |
| -#include "base/memory/scoped_ptr.h" |
| -#include "base/memory/weak_ptr.h" |
| #include "base/string_split.h" |
| #include "base/sync_socket.h" |
| #include "base/time.h" |
| @@ -38,6 +37,8 @@ |
| #include "content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.h" |
| #include "content/renderer/media/audio_input_message_filter.h" |
| #include "content/renderer/media/audio_message_filter.h" |
| +#include "content/renderer/media/media_stream_dispatcher.h" |
| +#include "content/renderer/media/media_stream_dispatcher_eventhandler.h" |
| #include "content/renderer/media/video_capture_impl_manager.h" |
| #include "content/renderer/p2p/p2p_transport_impl.h" |
| #include "content/renderer/pepper_platform_context_3d_impl.h" |
| @@ -55,6 +56,7 @@ |
| #include "ppapi/c/private/ppb_flash_net_connector.h" |
| #include "ppapi/proxy/host_dispatcher.h" |
| #include "ppapi/proxy/ppapi_messages.h" |
| +#include "ppapi/shared_impl/ppb_device_ref_shared.h" |
| #include "ppapi/shared_impl/platform_file.h" |
| #include "ppapi/shared_impl/ppapi_preferences.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" |
| @@ -587,62 +589,261 @@ class QuotaCallbackTranslator : public QuotaDispatcher::Callback { |
| }; |
| class PlatformVideoCaptureImpl |
| - : public webkit::ppapi::PluginDelegate::PlatformVideoCapture { |
| + : public webkit::ppapi::PluginDelegate::PlatformVideoCapture, |
| + public media::VideoCapture::EventHandler { |
| public: |
| - PlatformVideoCaptureImpl(media::VideoCapture::EventHandler* handler) |
| - : handler_proxy_(new media::VideoCaptureHandlerProxy( |
| - handler, base::MessageLoopProxy::current())) { |
| - VideoCaptureImplManager* manager = |
| - RenderThreadImpl::current()->video_capture_impl_manager(); |
| - // 1 means the "default" video capture device. |
| - // TODO(piman): Add a way to enumerate devices and pass them through the |
| - // API. |
| - video_capture_ = manager->AddDevice(1, handler_proxy_.get()); |
| + PlatformVideoCaptureImpl( |
| + const base::WeakPtr<PepperPluginDelegateImpl>& plugin_delegate, |
| + const std::string& device_id, |
| + webkit::ppapi::PluginDelegate::PlatformVideoCaptureEventHandler* handler); |
| + virtual ~PlatformVideoCaptureImpl(); |
| + |
| + // webkit::ppapi::PluginDelegate::PlatformVideoCapture implementation. |
| + virtual void StartCapture(EventHandler* handler, |
| + const VideoCaptureCapability& capability) OVERRIDE; |
| + virtual void StopCapture(EventHandler* handler) OVERRIDE; |
| + virtual void FeedBuffer(scoped_refptr<VideoFrameBuffer> buffer) OVERRIDE; |
| + virtual bool CaptureStarted() OVERRIDE; |
| + virtual int CaptureWidth() OVERRIDE; |
| + virtual int CaptureHeight() OVERRIDE; |
| + virtual int CaptureFrameRate() OVERRIDE; |
| + virtual void DetachEventHandler() OVERRIDE; |
| + |
| + // media::VideoCapture::EventHandler implementation |
| + virtual void OnStarted(VideoCapture* capture) OVERRIDE; |
| + virtual void OnStopped(VideoCapture* capture) OVERRIDE; |
| + virtual void OnPaused(VideoCapture* capture) OVERRIDE; |
| + virtual void OnError(VideoCapture* capture, int error_code) OVERRIDE; |
| + virtual void OnRemoved(VideoCapture* capture) OVERRIDE; |
| + virtual void OnBufferReady(VideoCapture* capture, |
| + scoped_refptr<VideoFrameBuffer> buffer) OVERRIDE; |
| + virtual void OnDeviceInfoReceived( |
| + VideoCapture* capture, |
| + const media::VideoCaptureParams& device_info) OVERRIDE; |
| + |
| + private: |
| + void Initialize(); |
| + |
| + void OnDeviceOpened(int request_id, |
| + bool succeeded, |
| + const std::string& label); |
| + |
| + base::WeakPtr<PepperPluginDelegateImpl> plugin_delegate_; |
| + |
| + std::string device_id_; |
| + std::string label_; |
| + int session_id_; |
| + |
| + scoped_ptr<media::VideoCaptureHandlerProxy> handler_proxy_; |
| + |
| + webkit::ppapi::PluginDelegate::PlatformVideoCaptureEventHandler* handler_; |
| + |
| + media::VideoCapture* video_capture_; |
| + |
| + // StartCapture() must be balanced by StopCapture(), otherwise this object |
| + // will leak. |
| + bool unbalanced_start_; |
| + |
| + base::WeakPtrFactory<PlatformVideoCaptureImpl> weak_ptr_factory_; |
| +}; |
| + |
| +PlatformVideoCaptureImpl::PlatformVideoCaptureImpl( |
| + const base::WeakPtr<PepperPluginDelegateImpl>& plugin_delegate, |
| + const std::string& device_id, |
| + webkit::ppapi::PluginDelegate::PlatformVideoCaptureEventHandler* handler) |
| + : plugin_delegate_(plugin_delegate), |
| + device_id_(device_id), |
| + session_id_(0), |
| + ALLOW_THIS_IN_INITIALIZER_LIST( |
| + handler_proxy_(new media::VideoCaptureHandlerProxy( |
| + this, base::MessageLoopProxy::current()))), |
| + handler_(handler), |
| + video_capture_(NULL), |
| + unbalanced_start_(false), |
| + ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { |
| + if (device_id.empty()) { |
| + // "1" is the session ID for the default device. |
| + session_id_ = 1; |
| + Initialize(); |
| + } else { |
| + // We need to open the device and obtain the label and session ID before |
| + // initializing. |
| + if (plugin_delegate_) { |
| + plugin_delegate_->OpenDevice( |
| + PP_DEVICETYPE_DEV_VIDEOCAPTURE, device_id, |
| + base::Bind(&PlatformVideoCaptureImpl::OnDeviceOpened, |
| + weak_ptr_factory_.GetWeakPtr())); |
| + } |
| } |
| +} |
| - // Overrides from media::VideoCapture::EventHandler |
| - virtual ~PlatformVideoCaptureImpl() { |
| +PlatformVideoCaptureImpl::~PlatformVideoCaptureImpl() { |
| + if (video_capture_) { |
| VideoCaptureImplManager* manager = |
| RenderThreadImpl::current()->video_capture_impl_manager(); |
| - manager->RemoveDevice(1, handler_proxy_.get()); |
| + manager->RemoveDevice(session_id_, handler_proxy_.get()); |
| } |
| - virtual void StartCapture( |
| - EventHandler* handler, |
| - const VideoCaptureCapability& capability) OVERRIDE { |
| - DCHECK(handler == handler_proxy_->proxied()); |
| + if (plugin_delegate_ && !label_.empty()) |
| + plugin_delegate_->CloseDevice(label_); |
| +} |
| + |
| +void PlatformVideoCaptureImpl::StartCapture( |
| + EventHandler* handler, |
| + const VideoCaptureCapability& capability) { |
| + DCHECK(handler == handler_); |
| + |
| + if (unbalanced_start_) |
| + return; |
| + |
| + if (video_capture_) { |
| + unbalanced_start_ = true; |
| + AddRef(); // Will be balanced in OnRemoved(). |
| video_capture_->StartCapture(handler_proxy_.get(), capability); |
| } |
| +} |
| + |
| +void PlatformVideoCaptureImpl::StopCapture(EventHandler* handler) { |
| + DCHECK(handler == handler_); |
| + if (!unbalanced_start_) |
| + return; |
| - virtual void StopCapture(EventHandler* handler) OVERRIDE { |
| - DCHECK(handler == handler_proxy_->proxied()); |
| + if (video_capture_) { |
| + unbalanced_start_ = false; |
| video_capture_->StopCapture(handler_proxy_.get()); |
| } |
| +} |
| - virtual void FeedBuffer(scoped_refptr<VideoFrameBuffer> buffer) OVERRIDE { |
| +void PlatformVideoCaptureImpl::FeedBuffer( |
| + scoped_refptr<VideoFrameBuffer> buffer) { |
| + if (video_capture_) |
| video_capture_->FeedBuffer(buffer); |
| - } |
| +} |
| - virtual bool CaptureStarted() OVERRIDE { |
| - return handler_proxy_->state().started; |
| +bool PlatformVideoCaptureImpl::CaptureStarted() { |
| + return handler_proxy_->state().started; |
| +} |
| + |
| +int PlatformVideoCaptureImpl::CaptureWidth() { |
| + return handler_proxy_->state().width; |
| +} |
| + |
| +int PlatformVideoCaptureImpl::CaptureHeight() { |
| + return handler_proxy_->state().height; |
| +} |
| + |
| +int PlatformVideoCaptureImpl::CaptureFrameRate() { |
| + return handler_proxy_->state().frame_rate; |
| +} |
| + |
| +void PlatformVideoCaptureImpl::DetachEventHandler() { |
| + handler_ = NULL; |
| + StopCapture(NULL); |
| +} |
| + |
| +void PlatformVideoCaptureImpl::OnStarted(VideoCapture* capture) { |
| + if (handler_) |
| + handler_->OnStarted(capture); |
| +} |
| + |
| +void PlatformVideoCaptureImpl::OnStopped(VideoCapture* capture) { |
| + if (handler_) |
| + handler_->OnStopped(capture); |
| +} |
| + |
| +void PlatformVideoCaptureImpl::OnPaused(VideoCapture* capture) { |
| + if (handler_) |
| + handler_->OnPaused(capture); |
| +} |
| + |
| +void PlatformVideoCaptureImpl::OnError(VideoCapture* capture, int error_code) { |
| + if (handler_) |
| + handler_->OnError(capture, error_code); |
| +} |
| + |
| +void PlatformVideoCaptureImpl::OnRemoved(VideoCapture* capture) { |
| + if (handler_) |
| + handler_->OnRemoved(capture); |
| + |
| + Release(); // Balance the AddRef() in StartCapture(). |
| +} |
| + |
| +void PlatformVideoCaptureImpl::OnBufferReady( |
| + VideoCapture* capture, |
| + scoped_refptr<VideoFrameBuffer> buffer) { |
| + if (handler_) { |
| + handler_->OnBufferReady(capture, buffer); |
| + } else { |
| + // Even after handler_ is detached, we have to return buffers that are in |
| + // flight to us. Otherwise VideoCaptureController will not tear down. |
| + FeedBuffer(buffer); |
| } |
| +} |
| - virtual int CaptureWidth() OVERRIDE { |
| - return handler_proxy_->state().width; |
| +void PlatformVideoCaptureImpl::OnDeviceInfoReceived( |
| + VideoCapture* capture, |
| + const media::VideoCaptureParams& device_info) { |
| + if (handler_) |
| + handler_->OnDeviceInfoReceived(capture, device_info); |
| +} |
| + |
| +void PlatformVideoCaptureImpl::Initialize() { |
| + VideoCaptureImplManager* manager = |
| + RenderThreadImpl::current()->video_capture_impl_manager(); |
| + video_capture_ = manager->AddDevice(session_id_, handler_proxy_.get()); |
| +} |
| + |
| +void PlatformVideoCaptureImpl::OnDeviceOpened(int request_id, |
| + bool succeeded, |
| + const std::string& label) { |
| + succeeded = succeeded && plugin_delegate_; |
| + if (succeeded) { |
| + label_ = label; |
| + session_id_ = plugin_delegate_->GetSessionID(PP_DEVICETYPE_DEV_VIDEOCAPTURE, |
| + label); |
| + Initialize(); |
| } |
| - virtual int CaptureHeight() OVERRIDE { |
| - return handler_proxy_->state().height; |
| + if (handler_) |
| + handler_->OnInitialized(this, succeeded); |
| +} |
| + |
| +media_stream::MediaStreamType FromPepperDeviceType(PP_DeviceType_Dev type) { |
| + switch (type) { |
| + case PP_DEVICETYPE_DEV_INVALID: |
| + return media_stream::kNoService; |
| + case PP_DEVICETYPE_DEV_AUDIOCAPTURE: |
| + return media_stream::kAudioCapture; |
| + case PP_DEVICETYPE_DEV_VIDEOCAPTURE: |
| + return media_stream::kVideoCapture; |
| + default: |
| + NOTREACHED(); |
| + return media_stream::kNoService; |
| } |
| +} |
| - virtual int CaptureFrameRate() OVERRIDE { |
| - return handler_proxy_->state().frame_rate; |
| +PP_DeviceType_Dev FromMediaStreamType(media_stream::MediaStreamType type) { |
| + switch (type) { |
| + case media_stream::kNoService: |
| + return PP_DEVICETYPE_DEV_INVALID; |
| + case media_stream::kAudioCapture: |
| + return PP_DEVICETYPE_DEV_AUDIOCAPTURE; |
| + case media_stream::kVideoCapture: |
| + return PP_DEVICETYPE_DEV_VIDEOCAPTURE; |
| + default: |
| + NOTREACHED(); |
| + return PP_DEVICETYPE_DEV_INVALID; |
| } |
| +} |
| - private: |
| - scoped_ptr<media::VideoCaptureHandlerProxy> handler_proxy_; |
| - media::VideoCapture* video_capture_; |
| -}; |
| +ppapi::DeviceRefData FromStreamDeviceInfo( |
| + const media_stream::StreamDeviceInfo& info) { |
| + ppapi::DeviceRefData data; |
| + data.id = info.device_id; |
| + data.name = info.name; |
| + data.type = FromMediaStreamType(info.stream_type); |
| + return data; |
| +} |
| } // namespace |
| @@ -844,6 +1045,122 @@ void PpapiBrokerImpl::ConnectPluginToBroker( |
| client->BrokerConnected(ppapi::PlatformFileToInt(plugin_handle), result); |
| } |
| +class PepperPluginDelegateImpl::DeviceEnumerationEventHandler |
| + : public MediaStreamDispatcherEventHandler { |
| + public: |
| + DeviceEnumerationEventHandler() { |
| + } |
| + |
| + virtual ~DeviceEnumerationEventHandler() { |
| + DCHECK(enumerate_callbacks_.empty()); |
| + DCHECK(open_callbacks_.empty()); |
| + } |
| + |
| + int RegisterEnumerateDevicesCallback( |
| + const EnumerateDevicesCallback& callback) { |
| + enumerate_callbacks_[next_id_] = callback; |
| + return next_id_++; |
| + } |
| + |
| + int RegisterOpenDeviceCallback(const OpenDeviceCallback& callback) { |
| + open_callbacks_[next_id_] = callback; |
| + return next_id_++; |
| + } |
| + |
| + // MediaStreamDispatcherEventHandler implementation. |
| + virtual void OnStreamGenerated( |
| + int request_id, |
| + const std::string& label, |
| + const media_stream::StreamDeviceInfoArray& audio_device_array, |
| + const media_stream::StreamDeviceInfoArray& video_device_array) OVERRIDE { |
| + } |
| + |
| + virtual void OnStreamGenerationFailed(int request_id) OVERRIDE { |
| + } |
| + |
| + virtual void OnVideoDeviceFailed(const std::string& label, |
| + int index) OVERRIDE { |
| + } |
| + |
| + virtual void OnAudioDeviceFailed(const std::string& label, |
| + int index) OVERRIDE { |
| + } |
| + |
| + virtual void OnDevicesEnumerated( |
| + int request_id, |
| + const media_stream::StreamDeviceInfoArray& device_array) OVERRIDE { |
| + NotifyDevicesEnumerated(request_id, true, device_array); |
| + } |
| + |
| + virtual void OnDevicesEnumerationFailed(int request_id) OVERRIDE { |
| + NotifyDevicesEnumerated(request_id, false, |
| + media_stream::StreamDeviceInfoArray()); |
| + } |
| + |
| + virtual void OnDeviceOpened( |
| + int request_id, |
| + const std::string& label, |
| + const media_stream::StreamDeviceInfo& device_info) OVERRIDE { |
| + NotifyDeviceOpened(request_id, true, label); |
| + } |
| + |
| + virtual void OnDeviceOpenFailed(int request_id) OVERRIDE { |
| + NotifyDeviceOpened(request_id, false, ""); |
| + } |
| + |
| + private: |
| + void NotifyDevicesEnumerated( |
| + int request_id, |
| + bool succeeded, |
| + const media_stream::StreamDeviceInfoArray& device_array) { |
| + EnumerateCallbackMap::iterator iter = enumerate_callbacks_.find(request_id); |
| + if (iter == enumerate_callbacks_.end()) { |
| + NOTREACHED(); |
| + return; |
| + } |
| + |
| + EnumerateDevicesCallback callback = iter->second; |
| + enumerate_callbacks_.erase(iter); |
| + |
| + std::vector<ppapi::DeviceRefData> devices; |
| + if (succeeded) { |
| + devices.reserve(device_array.size()); |
| + for (media_stream::StreamDeviceInfoArray::const_iterator info = |
| + device_array.begin(); info != device_array.end(); ++info) { |
| + devices.push_back(FromStreamDeviceInfo(*info)); |
| + } |
| + } |
| + callback.Run(request_id, succeeded, devices); |
| + } |
| + |
| + void NotifyDeviceOpened(int request_id, |
| + bool succeeded, |
| + const std::string& label) { |
| + OpenCallbackMap::iterator iter = open_callbacks_.find(request_id); |
| + if (iter == open_callbacks_.end()) { |
| + NOTREACHED(); |
| + return; |
| + } |
| + |
| + OpenDeviceCallback callback = iter->second; |
| + open_callbacks_.erase(iter); |
| + |
| + callback.Run(request_id, succeeded, label); |
| + } |
| + |
| + static int next_id_; |
|
viettrungluu
2012/01/27 18:54:34
Why does this need to be static?
yzshen1
2012/01/27 19:20:40
You are right. It doesn't need to be. Changed.
On
|
| + |
| + typedef std::map<int, EnumerateDevicesCallback> EnumerateCallbackMap; |
| + EnumerateCallbackMap enumerate_callbacks_; |
| + |
| + typedef std::map<int, OpenDeviceCallback> OpenCallbackMap; |
| + OpenCallbackMap open_callbacks_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(DeviceEnumerationEventHandler); |
| +}; |
| + |
| +int PepperPluginDelegateImpl::DeviceEnumerationEventHandler::next_id_ = 1; |
| + |
| PepperPluginDelegateImpl::PepperPluginDelegateImpl(RenderViewImpl* render_view) |
| : content::RenderViewObserver(render_view), |
| render_view_(render_view), |
| @@ -854,7 +1171,8 @@ PepperPluginDelegateImpl::PepperPluginDelegateImpl(RenderViewImpl* render_view) |
| mouse_locked_(false), |
| pending_lock_request_(false), |
| pending_unlock_request_(false), |
| - last_mouse_event_target_(NULL) { |
| + last_mouse_event_target_(NULL), |
| + device_enumeration_event_handler_(new DeviceEnumerationEventHandler()) { |
| } |
| PepperPluginDelegateImpl::~PepperPluginDelegateImpl() { |
| @@ -1228,8 +1546,9 @@ webkit::ppapi::PluginDelegate::PlatformContext3D* |
| webkit::ppapi::PluginDelegate::PlatformVideoCapture* |
| PepperPluginDelegateImpl::CreateVideoCapture( |
| - media::VideoCapture::EventHandler* handler) { |
| - return new PlatformVideoCaptureImpl(handler); |
| + const std::string& device_id, |
| + PlatformVideoCaptureEventHandler* handler) { |
| + return new PlatformVideoCaptureImpl(AsWeakPtr(), device_id, handler); |
| } |
| webkit::ppapi::PluginDelegate::PlatformVideoDecoder* |
| @@ -2044,6 +2363,18 @@ bool PepperPluginDelegateImpl::IsPageVisible() const { |
| return !render_view_->is_hidden(); |
| } |
| +int PepperPluginDelegateImpl::EnumerateDevices( |
| + PP_DeviceType_Dev type, |
| + const EnumerateDevicesCallback& callback) { |
| + int request_id = |
| + device_enumeration_event_handler_->RegisterEnumerateDevicesCallback( |
| + callback); |
| + render_view_->media_stream_dispatcher()->EnumerateDevices( |
| + request_id, device_enumeration_event_handler_.get(), |
| + FromPepperDeviceType(type), ""); |
| + return request_id; |
| +} |
| + |
| bool PepperPluginDelegateImpl::OnMessageReceived(const IPC::Message& message) { |
| bool handled = true; |
| IPC_BEGIN_MESSAGE_MAP(PepperPluginDelegateImpl, message) |
| @@ -2145,6 +2476,36 @@ int PepperPluginDelegateImpl::GetRoutingId() const { |
| return render_view_->routing_id(); |
| } |
| +int PepperPluginDelegateImpl::OpenDevice(PP_DeviceType_Dev type, |
| + const std::string& device_id, |
| + const OpenDeviceCallback& callback) { |
| + int request_id = |
| + device_enumeration_event_handler_->RegisterOpenDeviceCallback(callback); |
| + render_view_->media_stream_dispatcher()->OpenDevice( |
| + request_id, device_enumeration_event_handler_.get(), device_id, |
| + FromPepperDeviceType(type), ""); |
| + return request_id; |
| +} |
| + |
| +void PepperPluginDelegateImpl::CloseDevice(const std::string& label) { |
| + render_view_->media_stream_dispatcher()->CloseDevice(label); |
| +} |
| + |
| +int PepperPluginDelegateImpl::GetSessionID(PP_DeviceType_Dev type, |
| + const std::string& label) { |
| + switch (type) { |
| + case PP_DEVICETYPE_DEV_AUDIOCAPTURE: |
| + return render_view_->media_stream_dispatcher()->audio_session_id(label, |
| + 0); |
| + case PP_DEVICETYPE_DEV_VIDEOCAPTURE: |
| + return render_view_->media_stream_dispatcher()->video_session_id(label, |
| + 0); |
| + default: |
| + NOTREACHED(); |
| + return 0; |
| + } |
| +} |
| + |
| RendererGLContext* |
| PepperPluginDelegateImpl::GetParentContextForPlatformContext3D() { |
| WebGraphicsContext3DCommandBufferImpl* context = |