Update browser/media/* for Chrome 30

I took the latest versions of these files from chrome/browser/media,
then pared them down to remove all Chrome-isms and uses of UI to prompt
the user about allowing access to devices.
This commit is contained in:
Adam Roben 2013-10-07 16:13:01 -04:00
parent aa4f991659
commit d1623535e8
4 changed files with 211 additions and 96 deletions

View file

@ -4,9 +4,10 @@
#include "browser/media/media_capture_devices_dispatcher.h" #include "browser/media/media_capture_devices_dispatcher.h"
#include "base/prefs/pref_service.h" #include "base/logging.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/media_devices_monitor.h" #include "content/public/browser/media_devices_monitor.h"
#include "content/public/common/desktop_media_id.h"
#include "content/public/common/media_stream_request.h" #include "content/public/common/media_stream_request.h"
namespace brightray { namespace brightray {
@ -16,41 +17,40 @@ using content::MediaStreamDevices;
namespace { namespace {
const content::MediaStreamDevice* FindDefaultDeviceWithId( // Finds a device in |devices| that has |device_id|, or NULL if not found.
const content::MediaStreamDevice* FindDeviceWithId(
const content::MediaStreamDevices& devices, const content::MediaStreamDevices& devices,
const std::string& device_id) { const std::string& device_id) {
if (devices.empty())
return NULL;
content::MediaStreamDevices::const_iterator iter = devices.begin(); content::MediaStreamDevices::const_iterator iter = devices.begin();
for (; iter != devices.end(); ++iter) { for (; iter != devices.end(); ++iter) {
if (iter->id == device_id) { if (iter->id == device_id) {
return &(*iter); return &(*iter);
} }
} }
return NULL;
return &(*devices.begin());
}; };
} // namespace } // namespace
MediaCaptureDevicesDispatcher* MediaCaptureDevicesDispatcher::GetInstance() { MediaCaptureDevicesDispatcher* MediaCaptureDevicesDispatcher::GetInstance() {
return Singleton<MediaCaptureDevicesDispatcher>::get(); return Singleton<MediaCaptureDevicesDispatcher>::get();
} }
MediaCaptureDevicesDispatcher::MediaCaptureDevicesDispatcher() MediaCaptureDevicesDispatcher::MediaCaptureDevicesDispatcher()
: devices_enumerated_(false) {} : devices_enumerated_(false),
is_device_enumeration_disabled_(false) {
// MediaCaptureDevicesDispatcher is a singleton. It should be created on
// UI thread.
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
MediaCaptureDevicesDispatcher::~MediaCaptureDevicesDispatcher() {} MediaCaptureDevicesDispatcher::~MediaCaptureDevicesDispatcher() {}
const MediaStreamDevices& const MediaStreamDevices&
MediaCaptureDevicesDispatcher::GetAudioCaptureDevices() { MediaCaptureDevicesDispatcher::GetAudioCaptureDevices() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!devices_enumerated_) { if (!is_device_enumeration_disabled_ && !devices_enumerated_) {
BrowserThread::PostTask( content::EnsureMonitorCaptureDevices();
BrowserThread::IO, FROM_HERE,
base::Bind(&content::EnsureMonitorCaptureDevices));
devices_enumerated_ = true; devices_enumerated_ = true;
} }
return audio_devices_; return audio_devices_;
@ -59,17 +59,14 @@ MediaCaptureDevicesDispatcher::GetAudioCaptureDevices() {
const MediaStreamDevices& const MediaStreamDevices&
MediaCaptureDevicesDispatcher::GetVideoCaptureDevices() { MediaCaptureDevicesDispatcher::GetVideoCaptureDevices() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!devices_enumerated_) { if (!is_device_enumeration_disabled_ && !devices_enumerated_) {
BrowserThread::PostTask( content::EnsureMonitorCaptureDevices();
BrowserThread::IO, FROM_HERE,
base::Bind(&content::EnsureMonitorCaptureDevices));
devices_enumerated_ = true; devices_enumerated_ = true;
} }
return video_devices_; return video_devices_;
} }
void MediaCaptureDevicesDispatcher::GetRequestedDevice( void MediaCaptureDevicesDispatcher::GetDefaultDevices(
const std::string& requested_device_id,
bool audio, bool audio,
bool video, bool video,
content::MediaStreamDevices* devices) { content::MediaStreamDevices* devices) {
@ -77,32 +74,58 @@ void MediaCaptureDevicesDispatcher::GetRequestedDevice(
DCHECK(audio || video); DCHECK(audio || video);
if (audio) { if (audio) {
const content::MediaStreamDevices& audio_devices = GetAudioCaptureDevices(); const content::MediaStreamDevice* device = GetFirstAvailableAudioDevice();
const content::MediaStreamDevice* const device =
FindDefaultDeviceWithId(audio_devices, requested_device_id);
if (device) if (device)
devices->push_back(*device); devices->push_back(*device);
} }
if (video) { if (video) {
const content::MediaStreamDevices& video_devices = GetVideoCaptureDevices(); const content::MediaStreamDevice* device = GetFirstAvailableVideoDevice();
const content::MediaStreamDevice* const device =
FindDefaultDeviceWithId(video_devices, requested_device_id);
if (device) if (device)
devices->push_back(*device); devices->push_back(*device);
} }
} }
void MediaCaptureDevicesDispatcher::GetDefaultDevices( const content::MediaStreamDevice*
bool audio, MediaCaptureDevicesDispatcher::GetRequestedAudioDevice(
bool video, const std::string& requested_audio_device_id) {
content::MediaStreamDevices* devices) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (audio) { const content::MediaStreamDevices& audio_devices = GetAudioCaptureDevices();
GetRequestedDevice(std::string(), true, false, devices); const content::MediaStreamDevice* const device =
} FindDeviceWithId(audio_devices, requested_audio_device_id);
return device;
}
if (video) { const content::MediaStreamDevice*
GetRequestedDevice(std::string(), false, true, devices); MediaCaptureDevicesDispatcher::GetFirstAvailableAudioDevice() {
} DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
const content::MediaStreamDevices& audio_devices = GetAudioCaptureDevices();
if (audio_devices.empty())
return NULL;
return &(*audio_devices.begin());
}
const content::MediaStreamDevice*
MediaCaptureDevicesDispatcher::GetRequestedVideoDevice(
const std::string& requested_video_device_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
const content::MediaStreamDevices& video_devices = GetVideoCaptureDevices();
const content::MediaStreamDevice* const device =
FindDeviceWithId(video_devices, requested_video_device_id);
return device;
}
const content::MediaStreamDevice*
MediaCaptureDevicesDispatcher::GetFirstAvailableVideoDevice() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
const content::MediaStreamDevices& video_devices = GetVideoCaptureDevices();
if (video_devices.empty())
return NULL;
return &(*video_devices.begin());
}
void MediaCaptureDevicesDispatcher::DisableDeviceEnumerationForTesting() {
is_device_enumeration_disabled_ = true;
} }
void MediaCaptureDevicesDispatcher::OnAudioCaptureDevicesChanged( void MediaCaptureDevicesDispatcher::OnAudioCaptureDevicesChanged(
@ -126,15 +149,22 @@ void MediaCaptureDevicesDispatcher::OnVideoCaptureDevicesChanged(
void MediaCaptureDevicesDispatcher::OnMediaRequestStateChanged( void MediaCaptureDevicesDispatcher::OnMediaRequestStateChanged(
int render_process_id, int render_process_id,
int render_view_id, int render_view_id,
int page_request_id,
const content::MediaStreamDevice& device, const content::MediaStreamDevice& device,
content::MediaRequestState state) { content::MediaRequestState state) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE, }
base::Bind(
&MediaCaptureDevicesDispatcher::UpdateMediaRequestStateOnUIThread, void MediaCaptureDevicesDispatcher::OnAudioStreamPlayingChanged(
base::Unretained(this), render_process_id, render_view_id, device, int render_process_id, int render_view_id, int stream_id,
state)); bool is_playing, float power_dbfs, bool clipped) {
}
void MediaCaptureDevicesDispatcher::OnCreatingAudioStream(
int render_process_id,
int render_view_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
} }
void MediaCaptureDevicesDispatcher::UpdateAudioDevicesOnUIThread( void MediaCaptureDevicesDispatcher::UpdateAudioDevicesOnUIThread(
@ -145,17 +175,10 @@ void MediaCaptureDevicesDispatcher::UpdateAudioDevicesOnUIThread(
} }
void MediaCaptureDevicesDispatcher::UpdateVideoDevicesOnUIThread( void MediaCaptureDevicesDispatcher::UpdateVideoDevicesOnUIThread(
const content::MediaStreamDevices& devices) { const content::MediaStreamDevices& devices){
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
devices_enumerated_ = true; devices_enumerated_ = true;
video_devices_ = devices; video_devices_ = devices;
} }
void MediaCaptureDevicesDispatcher::UpdateMediaRequestStateOnUIThread( } // namespace brightray
int render_process_id,
int render_view_id,
const content::MediaStreamDevice& device,
content::MediaRequestState state) {
}
}

View file

@ -8,8 +8,8 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
#include "base/observer_list.h"
#include "content/public/browser/media_observer.h" #include "content/public/browser/media_observer.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/media_stream_request.h" #include "content/public/common/media_stream_request.h"
namespace brightray { namespace brightray {
@ -20,20 +20,35 @@ class MediaCaptureDevicesDispatcher : public content::MediaObserver {
public: public:
static MediaCaptureDevicesDispatcher* GetInstance(); static MediaCaptureDevicesDispatcher* GetInstance();
// Helper for picking the device that was requested for an OpenDevice request. // Methods for observers. Called on UI thread.
// If the device requested is not available it will revert to using the first const content::MediaStreamDevices& GetAudioCaptureDevices();
// available one instead or will return an empty list if no devices of the const content::MediaStreamDevices& GetVideoCaptureDevices();
// requested kind are present.
void GetRequestedDevice(const std::string& requested_device_id, // Helper to get the default devices which can be used by the media request.
bool audio, // Uses the first available devices if the default devices are not available.
bool video, // If the return list is empty, it means there is no available device on the
content::MediaStreamDevices* devices); // OS.
// Called on the UI thread.
void GetDefaultDevices(bool audio, void GetDefaultDevices(bool audio,
bool video, bool video,
content::MediaStreamDevices* devices); content::MediaStreamDevices* devices);
const content::MediaStreamDevices& GetAudioCaptureDevices(); // Helpers for picking particular requested devices, identified by raw id.
const content::MediaStreamDevices& GetVideoCaptureDevices(); // If the device requested is not available it will return NULL.
const content::MediaStreamDevice*
GetRequestedAudioDevice(const std::string& requested_audio_device_id);
const content::MediaStreamDevice*
GetRequestedVideoDevice(const std::string& requested_video_device_id);
// Returns the first available audio or video device, or NULL if no devices
// are available.
const content::MediaStreamDevice* GetFirstAvailableAudioDevice();
const content::MediaStreamDevice* GetFirstAvailableVideoDevice();
// Unittests that do not require actual device enumeration should call this
// API on the singleton. It is safe to call this multiple times on the
// signleton.
void DisableDeviceEnumerationForTesting();
// Overridden from content::MediaObserver: // Overridden from content::MediaObserver:
virtual void OnAudioCaptureDevicesChanged( virtual void OnAudioCaptureDevicesChanged(
@ -43,13 +58,18 @@ class MediaCaptureDevicesDispatcher : public content::MediaObserver {
virtual void OnMediaRequestStateChanged( virtual void OnMediaRequestStateChanged(
int render_process_id, int render_process_id,
int render_view_id, int render_view_id,
int page_request_id,
const content::MediaStreamDevice& device, const content::MediaStreamDevice& device,
content::MediaRequestState state) OVERRIDE; content::MediaRequestState state) OVERRIDE;
virtual void OnAudioStreamPlayingChanged( virtual void OnAudioStreamPlayingChanged(
int render_process_id, int render_process_id,
int render_view_id, int render_view_id,
int stream_id, int stream_id,
bool playing) OVERRIDE {} bool is_playing,
float power_dBFS,
bool clipped) OVERRIDE;
virtual void OnCreatingAudioStream(int render_process_id,
int render_view_id) OVERRIDE;
private: private:
friend struct DefaultSingletonTraits<MediaCaptureDevicesDispatcher>; friend struct DefaultSingletonTraits<MediaCaptureDevicesDispatcher>;
@ -60,11 +80,6 @@ class MediaCaptureDevicesDispatcher : public content::MediaObserver {
// Called by the MediaObserver() functions, executed on UI thread. // Called by the MediaObserver() functions, executed on UI thread.
void UpdateAudioDevicesOnUIThread(const content::MediaStreamDevices& devices); void UpdateAudioDevicesOnUIThread(const content::MediaStreamDevices& devices);
void UpdateVideoDevicesOnUIThread(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. // A list of cached audio capture devices.
content::MediaStreamDevices audio_devices_; content::MediaStreamDevices audio_devices_;
@ -75,8 +90,13 @@ class MediaCaptureDevicesDispatcher : public content::MediaObserver {
// Flag to indicate if device enumeration has been done/doing. // Flag to indicate if device enumeration has been done/doing.
// Only accessed on UI thread. // Only accessed on UI thread.
bool devices_enumerated_; bool devices_enumerated_;
// Flag used by unittests to disable device enumeration.
bool is_device_enumeration_disabled_;
DISALLOW_COPY_AND_ASSIGN(MediaCaptureDevicesDispatcher);
}; };
} } // namespace brightray
#endif // BRIGHTRAY_BROWSER_MEDIA_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_ #endif // BRIGHTRAY_BROWSER_MEDIA_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_

View file

@ -4,9 +4,8 @@
#include "browser/media/media_stream_devices_controller.h" #include "browser/media/media_stream_devices_controller.h"
#include "base/values.h"
#include "browser/media/media_capture_devices_dispatcher.h" #include "browser/media/media_capture_devices_dispatcher.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/media_stream_request.h" #include "content/public/common/media_stream_request.h"
namespace brightray { namespace brightray {
@ -20,7 +19,7 @@ bool HasAnyAvailableDevice() {
MediaCaptureDevicesDispatcher::GetInstance()->GetVideoCaptureDevices(); MediaCaptureDevicesDispatcher::GetInstance()->GetVideoCaptureDevices();
return !audio_devices.empty() || !video_devices.empty(); return !audio_devices.empty() || !video_devices.empty();
}; }
} // namespace } // namespace
@ -29,15 +28,39 @@ MediaStreamDevicesController::MediaStreamDevicesController(
const content::MediaResponseCallback& callback) const content::MediaResponseCallback& callback)
: request_(request), : request_(request),
callback_(callback), callback_(callback),
// For MEDIA_OPEN_DEVICE requests (Pepper) we always request both webcam
// and microphone to avoid popping two infobars.
microphone_requested_( microphone_requested_(
request_.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE), request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
request.request_type == content::MEDIA_OPEN_DEVICE),
webcam_requested_( webcam_requested_(
request_.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) { request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE ||
request.request_type == content::MEDIA_OPEN_DEVICE) {
} }
MediaStreamDevicesController::~MediaStreamDevicesController() {} MediaStreamDevicesController::~MediaStreamDevicesController() {
if (!callback_.is_null()) {
callback_.Run(content::MediaStreamDevices(),
scoped_ptr<content::MediaStreamUI>());
}
}
bool MediaStreamDevicesController::TakeAction() { bool MediaStreamDevicesController::TakeAction() {
// Tab capture is allowed for extensions only and infobar is not shown for
// extensions.
if (request_.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE ||
request_.video_type == content::MEDIA_TAB_VIDEO_CAPTURE) {
Deny();
return true;
}
// Deny the request if the security origin is empty, this happens with
// file access without |--allow-file-access-from-files| flag.
if (request_.security_origin.is_empty()) {
Deny();
return true;
}
// Deny the request if there is no device attached to the OS. // Deny the request if there is no device attached to the OS.
if (!HasAnyAvailableDevice()) { if (!HasAnyAvailableDevice()) {
Deny(); Deny();
@ -53,34 +76,87 @@ void MediaStreamDevicesController::Accept() {
content::MediaStreamDevices devices; content::MediaStreamDevices devices;
if (microphone_requested_ || webcam_requested_) { if (microphone_requested_ || webcam_requested_) {
switch (request_.request_type) { switch (request_.request_type) {
case content::MEDIA_OPEN_DEVICE: case content::MEDIA_OPEN_DEVICE: {
const content::MediaStreamDevice* device = NULL;
// For open device request pick the desired device or fall back to the // For open device request pick the desired device or fall back to the
// first available of the given type. // first available of the given type.
MediaCaptureDevicesDispatcher::GetInstance()->GetRequestedDevice( if (request_.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE) {
request_.requested_device_id, device = MediaCaptureDevicesDispatcher::GetInstance()->
microphone_requested_, GetRequestedAudioDevice(request_.requested_audio_device_id);
webcam_requested_, // TODO(wjia): Confirm this is the intended behavior.
&devices); if (!device) {
device = MediaCaptureDevicesDispatcher::GetInstance()->
GetFirstAvailableAudioDevice();
}
} else if (request_.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) {
// Pepper API opens only one device at a time.
device = MediaCaptureDevicesDispatcher::GetInstance()->
GetRequestedVideoDevice(request_.requested_video_device_id);
// TODO(wjia): Confirm this is the intended behavior.
if (!device) {
device = MediaCaptureDevicesDispatcher::GetInstance()->
GetFirstAvailableVideoDevice();
}
}
if (device)
devices.push_back(*device);
break; break;
case content::MEDIA_DEVICE_ACCESS: } case content::MEDIA_GENERATE_STREAM: {
case content::MEDIA_GENERATE_STREAM: bool needs_audio_device = microphone_requested_;
case content::MEDIA_ENUMERATE_DEVICES: bool needs_video_device = webcam_requested_;
// Get the exact audio or video device if an id is specified.
if (!request_.requested_audio_device_id.empty()) {
const content::MediaStreamDevice* audio_device =
MediaCaptureDevicesDispatcher::GetInstance()->
GetRequestedAudioDevice(request_.requested_audio_device_id);
if (audio_device) {
devices.push_back(*audio_device);
needs_audio_device = false;
}
}
if (!request_.requested_video_device_id.empty()) {
const content::MediaStreamDevice* video_device =
MediaCaptureDevicesDispatcher::GetInstance()->
GetRequestedVideoDevice(request_.requested_video_device_id);
if (video_device) {
devices.push_back(*video_device);
needs_video_device = false;
}
}
// If either or both audio and video devices were requested but not
// specified by id, get the default devices.
if (needs_audio_device || needs_video_device) {
MediaCaptureDevicesDispatcher::GetInstance()->
GetDefaultDevices(needs_audio_device,
needs_video_device,
&devices);
}
break;
} case content::MEDIA_DEVICE_ACCESS:
// Get the default devices for the request. // Get the default devices for the request.
MediaCaptureDevicesDispatcher::GetInstance()-> MediaCaptureDevicesDispatcher::GetInstance()->
GetDefaultDevices(microphone_requested_, GetDefaultDevices(microphone_requested_,
webcam_requested_, webcam_requested_,
&devices); &devices);
break; break;
case content::MEDIA_ENUMERATE_DEVICES:
// Do nothing.
NOTREACHED();
break;
} }
} }
LOG(ERROR) << "Accept"; content::MediaResponseCallback cb = callback_;
callback_.Run(devices, scoped_ptr<content::MediaStreamUI>()); callback_.Reset();
cb.Run(devices, scoped_ptr<content::MediaStreamUI>());
} }
void MediaStreamDevicesController::Deny() { void MediaStreamDevicesController::Deny() {
callback_.Run(content::MediaStreamDevices(), content::MediaResponseCallback cb = callback_;
scoped_ptr<content::MediaStreamUI>()); callback_.Reset();
cb.Run(content::MediaStreamDevices(), scoped_ptr<content::MediaStreamUI>());
} }
} // namespace brightray } // namespace brightray

View file

@ -5,6 +5,8 @@
#ifndef BRIGHTRAY_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_ #ifndef BRIGHTRAY_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_
#define BRIGHTRAY_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_ #define BRIGHTRAY_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_
#include <string>
#include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_delegate.h"
namespace brightray { namespace brightray {
@ -16,18 +18,12 @@ class MediaStreamDevicesController {
virtual ~MediaStreamDevicesController(); 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(); bool TakeAction();
// Public methods to be called by MediaStreamInfoBarDelegate; private:
bool has_audio() const { return microphone_requested_; }
bool has_video() const { return webcam_requested_; }
void Accept(); void Accept();
void Deny(); void Deny();
private:
// The original request for access to devices. // The original request for access to devices.
const content::MediaStreamRequest request_; const content::MediaStreamRequest request_;
@ -41,6 +37,6 @@ class MediaStreamDevicesController {
DISALLOW_COPY_AND_ASSIGN(MediaStreamDevicesController); DISALLOW_COPY_AND_ASSIGN(MediaStreamDevicesController);
}; };
} // namespace brightray } // namespace brightray
#endif // BRIGHTRAY_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_ #endif // BRIGHTRAY_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_