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..c166db0608f142a128da03e3d3c9ff6f2082cb2a 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,257 @@ class QuotaCallbackTranslator : public QuotaDispatcher::Callback { |
}; |
class PlatformVideoCaptureImpl |
brettw
2012/02/10 23:46:23
Do you think you can move this to its own file? It
yzshen1
2012/02/13 20:55:41
Done.
|
- : 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_; |
+}; |
+ |
+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) { |
+ 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, this)); |
+ } |
} |
+} |
- // 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); |
- } |
+} |
+ |
+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); |
+} |
- virtual bool CaptureStarted() OVERRIDE { |
- return handler_proxy_->state().started; |
+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 +1041,120 @@ void PpapiBrokerImpl::ConnectPluginToBroker( |
client->BrokerConnected(ppapi::PlatformFileToInt(plugin_handle), result); |
} |
+class PepperPluginDelegateImpl::DeviceEnumerationEventHandler |
+ : public MediaStreamDispatcherEventHandler { |
+ public: |
+ DeviceEnumerationEventHandler() : next_id_(1) { |
+ } |
+ |
+ 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); |
+ } |
+ |
+ int next_id_; |
+ |
+ typedef std::map<int, EnumerateDevicesCallback> EnumerateCallbackMap; |
+ EnumerateCallbackMap enumerate_callbacks_; |
+ |
+ typedef std::map<int, OpenDeviceCallback> OpenCallbackMap; |
+ OpenCallbackMap open_callbacks_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(DeviceEnumerationEventHandler); |
+}; |
+ |
PepperPluginDelegateImpl::PepperPluginDelegateImpl(RenderViewImpl* render_view) |
: content::RenderViewObserver(render_view), |
render_view_(render_view), |
@@ -854,7 +1165,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 +1540,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 +2357,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 +2470,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 = |