From 354a1c555bfaff7320b167c6cb065a0b1444c349 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 21 Jun 2013 12:28:23 +0800 Subject: [PATCH 1/2] Update node to v0.10.12. --- script/update | 2 +- vendor/node | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/script/update b/script/update index 444b289611..4688600e2e 100755 --- a/script/update +++ b/script/update @@ -5,7 +5,7 @@ set -e cd "$(dirname "$0")/.." ./script/update-frameworks -./script/update-node v0.10.9 +./script/update-node v0.10.12 gyp --depth . atom.gyp \ -Ivendor/brightray/brightray.gypi \ diff --git a/vendor/node b/vendor/node index 1ab526aa02..1f85e7fa2d 160000 --- a/vendor/node +++ b/vendor/node @@ -1 +1 @@ -Subproject commit 1ab526aa029e5af2dff3248f42bfa9d4c404fe12 +Subproject commit 1f85e7fa2d66522ce145dd76cf3a4b6eb62a802d From f26db5c7a1c6328549d1bb884b051f03b1786494 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 21 Jun 2013 16:05:28 +0800 Subject: [PATCH 2/2] Enable getUserMedia(). Part of fixes for #31. --- atom.gyp | 4 + browser/atom_browser_client.cc | 5 + browser/atom_browser_client.h | 1 + .../media/media_capture_devices_dispatcher.cc | 157 ++++++++++++++++++ .../media/media_capture_devices_dispatcher.h | 78 +++++++++ .../media/media_stream_devices_controller.cc | 86 ++++++++++ .../media/media_stream_devices_controller.h | 46 +++++ browser/native_window.cc | 9 + browser/native_window.h | 4 + 9 files changed, 390 insertions(+) create mode 100644 browser/media/media_capture_devices_dispatcher.cc create mode 100644 browser/media/media_capture_devices_dispatcher.h create mode 100644 browser/media/media_stream_devices_controller.cc create mode 100644 browser/media/media_stream_devices_controller.h diff --git a/atom.gyp b/atom.gyp index 82e2affb49..e7488016a1 100644 --- a/atom.gyp +++ b/atom.gyp @@ -82,6 +82,10 @@ 'browser/browser_observer.h', 'browser/file_dialog.h', 'browser/file_dialog_mac.mm', + '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/message_box.h', 'browser/message_box_mac.mm', 'browser/native_window.cc', diff --git a/browser/atom_browser_client.cc b/browser/atom_browser_client.cc index b3a04a1553..ab8da5db12 100644 --- a/browser/atom_browser_client.cc +++ b/browser/atom_browser_client.cc @@ -5,6 +5,7 @@ #include "browser/atom_browser_client.h" #include "browser/atom_browser_main_parts.h" +#include "browser/media/media_capture_devices_dispatcher.h" #include "webkit/glue/webpreferences.h" namespace atom { @@ -37,6 +38,10 @@ void AtomBrowserClient::OverrideWebkitPrefs( prefs->allow_running_insecure_content = true; } +content::MediaObserver* AtomBrowserClient::GetMediaObserver() { + return MediaCaptureDevicesDispatcher::GetInstance(); +} + bool AtomBrowserClient::ShouldSwapProcessesForNavigation( content::SiteInstance* site_instance, const GURL& current_url, diff --git a/browser/atom_browser_client.h b/browser/atom_browser_client.h index 16fcbe3b9d..55c9960923 100644 --- a/browser/atom_browser_client.h +++ b/browser/atom_browser_client.h @@ -18,6 +18,7 @@ class AtomBrowserClient : public brightray::BrowserClient { virtual void OverrideWebkitPrefs(content::RenderViewHost* render_view_host, const GURL& url, WebPreferences* prefs) OVERRIDE; + virtual content::MediaObserver* GetMediaObserver() OVERRIDE; virtual bool ShouldSwapProcessesForNavigation( content::SiteInstance* site_instance, const GURL& current_url, diff --git a/browser/media/media_capture_devices_dispatcher.cc b/browser/media/media_capture_devices_dispatcher.cc new file mode 100644 index 0000000000..91b7bb2582 --- /dev/null +++ b/browser/media/media_capture_devices_dispatcher.cc @@ -0,0 +1,157 @@ +// Copyright (c) 2013 GitHub, Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE 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" + +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/browser/media/media_capture_devices_dispatcher.h b/browser/media/media_capture_devices_dispatcher.h new file mode 100644 index 0000000000..962b376515 --- /dev/null +++ b/browser/media/media_capture_devices_dispatcher.h @@ -0,0 +1,78 @@ +// Copyright (c) 2013 GitHub, Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_MEDIA_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_ +#define CHROME_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" + +// 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 // CHROME_BROWSER_MEDIA_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_ diff --git a/browser/media/media_stream_devices_controller.cc b/browser/media/media_stream_devices_controller.cc new file mode 100644 index 0000000000..a7db3056d8 --- /dev/null +++ b/browser/media/media_stream_devices_controller.cc @@ -0,0 +1,86 @@ +// Copyright (c) 2013 GitHub, Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE 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 atom { + +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 atom diff --git a/browser/media/media_stream_devices_controller.h b/browser/media/media_stream_devices_controller.h new file mode 100644 index 0000000000..e2ff28d6ae --- /dev/null +++ b/browser/media/media_stream_devices_controller.h @@ -0,0 +1,46 @@ +// Copyright (c) 2013 GitHub, Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_ +#define ATOM_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_ + +#include "content/public/browser/web_contents_delegate.h" + +namespace atom { + +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 atom + +#endif // ATOM_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_ diff --git a/browser/native_window.cc b/browser/native_window.cc index fe00c100c9..fe0b5d273f 100644 --- a/browser/native_window.cc +++ b/browser/native_window.cc @@ -14,6 +14,7 @@ #include "browser/atom_browser_context.h" #include "browser/atom_browser_main_parts.h" #include "browser/atom_javascript_dialog_manager.h" +#include "browser/media/media_stream_devices_controller.h" #include "browser/window_list.h" #include "content/public/browser/invalidate_type.h" #include "content/public/browser/navigation_entry.h" @@ -219,6 +220,14 @@ void NativeWindow::RequestToLockMouse(content::WebContents* web_contents, GetWebContents()->GotResponseToLockMouseRequest(true); } +void NativeWindow::RequestMediaAccessPermission( + content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback) { + MediaStreamDevicesController controller(request, callback); + controller.TakeAction(); +} + bool NativeWindow::CanOverscrollContent() const { return false; } diff --git a/browser/native_window.h b/browser/native_window.h index d14d70a593..b87c0a9d15 100644 --- a/browser/native_window.h +++ b/browser/native_window.h @@ -139,6 +139,10 @@ class NativeWindow : public content::WebContentsDelegate, virtual void RequestToLockMouse(content::WebContents* web_contents, bool user_gesture, bool last_unlocked_by_target) OVERRIDE; + virtual void RequestMediaAccessPermission( + content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback) OVERRIDE; virtual bool CanOverscrollContent() const OVERRIDE; virtual void ActivateContents(content::WebContents* contents) OVERRIDE; virtual void DeactivateContents(content::WebContents* contents) OVERRIDE;