diff --git a/brightray/brightray.gyp b/brightray/brightray.gyp index 85174cab8729..b576b273ec75 100644 --- a/brightray/brightray.gyp +++ b/brightray/brightray.gyp @@ -51,6 +51,10 @@ 'browser/mac/bry_inspectable_web_contents_view.h', 'browser/mac/bry_inspectable_web_contents_view.mm', 'browser/mac/bry_inspectable_web_contents_view_private.h', + 'browser/media/media_capture_devices_dispatcher.cc', + 'browser/media/media_capture_devices_dispatcher.h', + 'browser/media/media_stream_devices_controller.cc', + 'browser/media/media_stream_devices_controller.h', 'browser/network_delegate.cc', 'browser/network_delegate.h', 'browser/notification_presenter.h', diff --git a/brightray/browser/browser_client.cc b/brightray/browser/browser_client.cc index a42fcea4ccf3..1c19f622ef0a 100644 --- a/brightray/browser/browser_client.cc +++ b/brightray/browser/browser_client.cc @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE-CHROMIUM file. -#include "browser_client.h" +#include "browser/browser_client.h" -#include "browser_context.h" -#include "browser_main_parts.h" -#include "notification_presenter.h" +#include "browser/browser_context.h" +#include "browser/browser_main_parts.h" +#include "browser/media/media_capture_devices_dispatcher.h" +#include "browser/notification_presenter.h" namespace brightray { @@ -76,4 +77,8 @@ void BrowserClient::CancelDesktopNotification( presenter->CancelNotification(render_process_id, render_view_id, notification_id); } +content::MediaObserver* BrowserClient::GetMediaObserver() { + return MediaCaptureDevicesDispatcher::GetInstance(); +} + } diff --git a/brightray/browser/browser_client.h b/brightray/browser/browser_client.h index cb8143b71c98..f5bc9d618fe3 100644 --- a/brightray/browser/browser_client.h +++ b/brightray/browser/browser_client.h @@ -44,6 +44,7 @@ private: int render_process_id, int render_view_id, int notification_id) OVERRIDE; + virtual content::MediaObserver* GetMediaObserver() OVERRIDE; BrowserMainParts* browser_main_parts_; scoped_ptr notification_presenter_; diff --git a/brightray/browser/default_web_contents_delegate.cc b/brightray/browser/default_web_contents_delegate.cc index 967881efb7a2..f4e08b840986 100644 --- a/brightray/browser/default_web_contents_delegate.cc +++ b/brightray/browser/default_web_contents_delegate.cc @@ -1,5 +1,7 @@ #include "browser/default_web_contents_delegate.h" +#include "browser/media/media_stream_devices_controller.h" + namespace brightray { DefaultWebContentsDelegate::DefaultWebContentsDelegate() { @@ -8,4 +10,12 @@ DefaultWebContentsDelegate::DefaultWebContentsDelegate() { DefaultWebContentsDelegate::~DefaultWebContentsDelegate() { } +void DefaultWebContentsDelegate::RequestMediaAccessPermission( + content::WebContents*, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback) { + MediaStreamDevicesController controller(request, callback); + controller.TakeAction(); +} + } diff --git a/brightray/browser/default_web_contents_delegate.h b/brightray/browser/default_web_contents_delegate.h index c6ce2ee23ff1..b4dabdd03b81 100644 --- a/brightray/browser/default_web_contents_delegate.h +++ b/brightray/browser/default_web_contents_delegate.h @@ -13,6 +13,9 @@ public: ~DefaultWebContentsDelegate(); protected: + virtual void RequestMediaAccessPermission(content::WebContents*, + const content::MediaStreamRequest&, + const content::MediaResponseCallback&) OVERRIDE; #if defined(OS_MACOSX) virtual void HandleKeyboardEvent(content::WebContents*, const content::NativeWebKeyboardEvent&) OVERRIDE; #endif diff --git a/brightray/browser/media/media_capture_devices_dispatcher.cc b/brightray/browser/media/media_capture_devices_dispatcher.cc new file mode 100644 index 000000000000..3c15841c1644 --- /dev/null +++ b/brightray/browser/media/media_capture_devices_dispatcher.cc @@ -0,0 +1,161 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-CHROMIUM file. + +#include "browser/media/media_capture_devices_dispatcher.h" + +#include "base/prefs/pref_service.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/media_devices_monitor.h" +#include "content/public/common/media_stream_request.h" + +namespace brightray { + +using content::BrowserThread; +using content::MediaStreamDevices; + +namespace { + +const content::MediaStreamDevice* FindDefaultDeviceWithId( + const content::MediaStreamDevices& devices, + const std::string& device_id) { + if (devices.empty()) + return NULL; + + content::MediaStreamDevices::const_iterator iter = devices.begin(); + for (; iter != devices.end(); ++iter) { + if (iter->id == device_id) { + return &(*iter); + } + } + + return &(*devices.begin()); +}; + +} // namespace + + +MediaCaptureDevicesDispatcher* MediaCaptureDevicesDispatcher::GetInstance() { + return Singleton::get(); +} + +MediaCaptureDevicesDispatcher::MediaCaptureDevicesDispatcher() + : devices_enumerated_(false) {} + +MediaCaptureDevicesDispatcher::~MediaCaptureDevicesDispatcher() {} + +const MediaStreamDevices& +MediaCaptureDevicesDispatcher::GetAudioCaptureDevices() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (!devices_enumerated_) { + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&content::EnsureMonitorCaptureDevices)); + devices_enumerated_ = true; + } + return audio_devices_; +} + +const MediaStreamDevices& +MediaCaptureDevicesDispatcher::GetVideoCaptureDevices() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (!devices_enumerated_) { + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&content::EnsureMonitorCaptureDevices)); + devices_enumerated_ = true; + } + return video_devices_; +} + +void MediaCaptureDevicesDispatcher::GetRequestedDevice( + const std::string& requested_device_id, + bool audio, + bool video, + content::MediaStreamDevices* devices) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(audio || video); + + if (audio) { + const content::MediaStreamDevices& audio_devices = GetAudioCaptureDevices(); + const content::MediaStreamDevice* const device = + FindDefaultDeviceWithId(audio_devices, requested_device_id); + if (device) + devices->push_back(*device); + } + if (video) { + const content::MediaStreamDevices& video_devices = GetVideoCaptureDevices(); + const content::MediaStreamDevice* const device = + FindDefaultDeviceWithId(video_devices, requested_device_id); + if (device) + devices->push_back(*device); + } +} + +void MediaCaptureDevicesDispatcher::GetDefaultDevices( + bool audio, + bool video, + content::MediaStreamDevices* devices) { + if (audio) { + GetRequestedDevice(std::string(), true, false, devices); + } + + if (video) { + GetRequestedDevice(std::string(), false, true, devices); + } +} + +void MediaCaptureDevicesDispatcher::OnAudioCaptureDevicesChanged( + const content::MediaStreamDevices& devices) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&MediaCaptureDevicesDispatcher::UpdateAudioDevicesOnUIThread, + base::Unretained(this), devices)); +} + +void MediaCaptureDevicesDispatcher::OnVideoCaptureDevicesChanged( + const content::MediaStreamDevices& devices) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&MediaCaptureDevicesDispatcher::UpdateVideoDevicesOnUIThread, + base::Unretained(this), devices)); +} + +void MediaCaptureDevicesDispatcher::OnMediaRequestStateChanged( + int render_process_id, + int render_view_id, + const content::MediaStreamDevice& device, + content::MediaRequestState state) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind( + &MediaCaptureDevicesDispatcher::UpdateMediaRequestStateOnUIThread, + base::Unretained(this), render_process_id, render_view_id, device, + state)); +} + +void MediaCaptureDevicesDispatcher::UpdateAudioDevicesOnUIThread( + const content::MediaStreamDevices& devices) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + devices_enumerated_ = true; + audio_devices_ = devices; +} + +void MediaCaptureDevicesDispatcher::UpdateVideoDevicesOnUIThread( + const content::MediaStreamDevices& devices) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + devices_enumerated_ = true; + video_devices_ = devices; +} + +void MediaCaptureDevicesDispatcher::UpdateMediaRequestStateOnUIThread( + int render_process_id, + int render_view_id, + const content::MediaStreamDevice& device, + content::MediaRequestState state) { +} + +} diff --git a/brightray/browser/media/media_capture_devices_dispatcher.h b/brightray/browser/media/media_capture_devices_dispatcher.h new file mode 100644 index 000000000000..6edb12b5cf0c --- /dev/null +++ b/brightray/browser/media/media_capture_devices_dispatcher.h @@ -0,0 +1,82 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-CHROMIUM file. + +#ifndef BRIGHTRAY_BROWSER_MEDIA_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_ +#define BRIGHTRAY_BROWSER_MEDIA_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_ + +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/singleton.h" +#include "base/observer_list.h" +#include "content/public/browser/media_observer.h" +#include "content/public/common/media_stream_request.h" + +namespace brightray { + +// This singleton is used to receive updates about media events from the content +// layer. +class MediaCaptureDevicesDispatcher : public content::MediaObserver { + public: + static MediaCaptureDevicesDispatcher* GetInstance(); + + // Helper for picking the device that was requested for an OpenDevice request. + // If the device requested is not available it will revert to using the first + // available one instead or will return an empty list if no devices of the + // requested kind are present. + void GetRequestedDevice(const std::string& requested_device_id, + bool audio, + bool video, + content::MediaStreamDevices* devices); + void GetDefaultDevices(bool audio, + bool video, + content::MediaStreamDevices* devices); + + const content::MediaStreamDevices& GetAudioCaptureDevices(); + const content::MediaStreamDevices& GetVideoCaptureDevices(); + + // Overridden from content::MediaObserver: + virtual void OnAudioCaptureDevicesChanged( + const content::MediaStreamDevices& devices) OVERRIDE; + virtual void OnVideoCaptureDevicesChanged( + const content::MediaStreamDevices& devices) OVERRIDE; + virtual void OnMediaRequestStateChanged( + int render_process_id, + int render_view_id, + const content::MediaStreamDevice& device, + content::MediaRequestState state) OVERRIDE; + virtual void OnAudioStreamPlayingChanged( + int render_process_id, + int render_view_id, + int stream_id, + bool playing) OVERRIDE {} + + private: + friend struct DefaultSingletonTraits; + + MediaCaptureDevicesDispatcher(); + virtual ~MediaCaptureDevicesDispatcher(); + + // Called by the MediaObserver() functions, executed on UI thread. + void UpdateAudioDevicesOnUIThread(const content::MediaStreamDevices& devices); + void UpdateVideoDevicesOnUIThread(const content::MediaStreamDevices& devices); + void UpdateMediaRequestStateOnUIThread( + int render_process_id, + int render_view_id, + const content::MediaStreamDevice& device, + content::MediaRequestState state); + + // A list of cached audio capture devices. + content::MediaStreamDevices audio_devices_; + + // A list of cached video capture devices. + content::MediaStreamDevices video_devices_; + + // Flag to indicate if device enumeration has been done/doing. + // Only accessed on UI thread. + bool devices_enumerated_; +}; + +} + +#endif // BRIGHTRAY_BROWSER_MEDIA_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_ diff --git a/brightray/browser/media/media_stream_devices_controller.cc b/brightray/browser/media/media_stream_devices_controller.cc new file mode 100644 index 000000000000..ea53c20fd29d --- /dev/null +++ b/brightray/browser/media/media_stream_devices_controller.cc @@ -0,0 +1,86 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-CHROMIUM file. + +#include "browser/media/media_stream_devices_controller.h" + +#include "base/values.h" +#include "browser/media/media_capture_devices_dispatcher.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/common/media_stream_request.h" + +namespace brightray { + +namespace { + +bool HasAnyAvailableDevice() { + const content::MediaStreamDevices& audio_devices = + MediaCaptureDevicesDispatcher::GetInstance()->GetAudioCaptureDevices(); + const content::MediaStreamDevices& video_devices = + MediaCaptureDevicesDispatcher::GetInstance()->GetVideoCaptureDevices(); + + return !audio_devices.empty() || !video_devices.empty(); +}; + +} // namespace + +MediaStreamDevicesController::MediaStreamDevicesController( + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback) + : request_(request), + callback_(callback), + microphone_requested_( + request_.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE), + webcam_requested_( + request_.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) { +} + +MediaStreamDevicesController::~MediaStreamDevicesController() {} + +bool MediaStreamDevicesController::TakeAction() { + // Deny the request if there is no device attached to the OS. + if (!HasAnyAvailableDevice()) { + Deny(); + return true; + } + + Accept(); + return true; +} + +void MediaStreamDevicesController::Accept() { + // Get the default devices for the request. + content::MediaStreamDevices devices; + if (microphone_requested_ || webcam_requested_) { + switch (request_.request_type) { + case content::MEDIA_OPEN_DEVICE: + // For open device request pick the desired device or fall back to the + // first available of the given type. + MediaCaptureDevicesDispatcher::GetInstance()->GetRequestedDevice( + request_.requested_device_id, + microphone_requested_, + webcam_requested_, + &devices); + break; + case content::MEDIA_DEVICE_ACCESS: + case content::MEDIA_GENERATE_STREAM: + case content::MEDIA_ENUMERATE_DEVICES: + // Get the default devices for the request. + MediaCaptureDevicesDispatcher::GetInstance()-> + GetDefaultDevices(microphone_requested_, + webcam_requested_, + &devices); + break; + } + } + + LOG(ERROR) << "Accept"; + callback_.Run(devices, scoped_ptr()); +} + +void MediaStreamDevicesController::Deny() { + callback_.Run(content::MediaStreamDevices(), + scoped_ptr()); +} + +} // namespace brightray diff --git a/brightray/browser/media/media_stream_devices_controller.h b/brightray/browser/media/media_stream_devices_controller.h new file mode 100644 index 000000000000..bcf4a0f0049e --- /dev/null +++ b/brightray/browser/media/media_stream_devices_controller.h @@ -0,0 +1,46 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-CHROMIUM file. + +#ifndef BRIGHTRAY_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_ +#define BRIGHTRAY_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_ + +#include "content/public/browser/web_contents_delegate.h" + +namespace brightray { + +class MediaStreamDevicesController { + public: + MediaStreamDevicesController(const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback); + + virtual ~MediaStreamDevicesController(); + + // Public method to be called before creating the MediaStreamInfoBarDelegate. + // This function will check the content settings exceptions and take the + // corresponding action on exception which matches the request. + bool TakeAction(); + + // Public methods to be called by MediaStreamInfoBarDelegate; + bool has_audio() const { return microphone_requested_; } + bool has_video() const { return webcam_requested_; } + void Accept(); + void Deny(); + + private: + // The original request for access to devices. + const content::MediaStreamRequest request_; + + // The callback that needs to be Run to notify WebRTC of whether access to + // audio/video devices was granted or not. + content::MediaResponseCallback callback_; + + bool microphone_requested_; + bool webcam_requested_; + + DISALLOW_COPY_AND_ASSIGN(MediaStreamDevicesController); +}; + +} // namespace brightray + +#endif // BRIGHTRAY_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_