diff options
18 files changed, 927 insertions, 834 deletions
diff --git a/chrome/browser/media/media_capture_devices_dispatcher.cc b/chrome/browser/media/media_capture_devices_dispatcher.cc index d9229b1..4e96891 100644 --- a/chrome/browser/media/media_capture_devices_dispatcher.cc +++ b/chrome/browser/media/media_capture_devices_dispatcher.cc @@ -25,6 +25,9 @@ #include "components/user_prefs/pref_registry_syncable.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/media_devices_monitor.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_source.h" +#include "content/public/browser/notification_types.h" #include "content/public/browser/web_contents.h" #include "content/public/common/media_stream_request.h" #include "extensions/common/constants.h" @@ -80,6 +83,15 @@ bool IsOriginWhitelistedForScreenCapture(const GURL& origin) { } // namespace +MediaCaptureDevicesDispatcher::PendingAccessRequest::PendingAccessRequest( + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback) + : request(request), + callback(callback) { +} + +MediaCaptureDevicesDispatcher::PendingAccessRequest::~PendingAccessRequest() {} + MediaCaptureDevicesDispatcher* MediaCaptureDevicesDispatcher::GetInstance() { return Singleton<MediaCaptureDevicesDispatcher>::get(); } @@ -88,7 +100,11 @@ MediaCaptureDevicesDispatcher::MediaCaptureDevicesDispatcher() : devices_enumerated_(false), is_device_enumeration_disabled_(false), media_stream_capture_indicator_(new MediaStreamCaptureIndicator()), - audio_stream_indicator_(new AudioStreamIndicator()) {} + audio_stream_indicator_(new AudioStreamIndicator()) { + notifications_registrar_.Add( + this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, + content::NotificationService::AllSources()); +} MediaCaptureDevicesDispatcher::~MediaCaptureDevicesDispatcher() {} @@ -139,6 +155,18 @@ MediaCaptureDevicesDispatcher::GetVideoCaptureDevices() { return video_devices_; } +void MediaCaptureDevicesDispatcher::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) { + content::WebContents* web_contents = + content::Source<content::WebContents>(source).ptr(); + pending_requests_.erase(web_contents); + } +} + void MediaCaptureDevicesDispatcher::ProcessMediaAccessRequest( content::WebContents* web_contents, const content::MediaStreamRequest& request, @@ -153,8 +181,7 @@ void MediaCaptureDevicesDispatcher::ProcessMediaAccessRequest( ProcessMediaAccessRequestFromExtension( web_contents, request, callback, extension); } else { - // For all regular media requests show infobar. - MediaStreamInfoBarDelegate::Create(web_contents, request, callback); + ProcessRegularMediaAccessRequest(web_contents, request, callback); } } @@ -260,6 +287,66 @@ void MediaCaptureDevicesDispatcher::ProcessMediaAccessRequestFromExtension( callback.Run(devices, ui.Pass()); } +void MediaCaptureDevicesDispatcher::ProcessRegularMediaAccessRequest( + content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + RequestsQueue& queue = pending_requests_[web_contents]; + queue.push(PendingAccessRequest(request, callback)); + + // If this is the only request then show the infobar. + if (queue.size() == 1) + ProcessQueuedAccessRequest(web_contents); +} + +void MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest( + content::WebContents* web_contents) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + std::map<content::WebContents*, RequestsQueue>::iterator it = + pending_requests_.find(web_contents); + + if (it == pending_requests_.end() || it->second.empty()) { + // Don't do anything if the tab was was closed. + return; + } + + DCHECK(!it->second.empty()); + + MediaStreamInfoBarDelegate::Create( + web_contents, it->second.front().request, + base::Bind(&MediaCaptureDevicesDispatcher::OnAccessRequestResponse, + base::Unretained(this), web_contents)); +} + +void MediaCaptureDevicesDispatcher::OnAccessRequestResponse( + content::WebContents* web_contents, + const content::MediaStreamDevices& devices, + scoped_ptr<content::MediaStreamUI> ui) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + std::map<content::WebContents*, RequestsQueue>::iterator it = + pending_requests_.find(web_contents); + DCHECK(it != pending_requests_.end()); + RequestsQueue& queue(it->second); + content::MediaResponseCallback callback = queue.front().callback; + queue.pop(); + + if (!queue.empty()) { + // Post a task to process next queued request. It has to be done + // asynchronously to make sure that calling infobar is not destroyed until + // after this function returns. + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest, + base::Unretained(this), web_contents)); + } + + callback.Run(devices, ui.Pass()); +} + void MediaCaptureDevicesDispatcher::GetDefaultDevicesForProfile( Profile* profile, bool audio, diff --git a/chrome/browser/media/media_capture_devices_dispatcher.h b/chrome/browser/media/media_capture_devices_dispatcher.h index 0a704d4..1f0937e 100644 --- a/chrome/browser/media/media_capture_devices_dispatcher.h +++ b/chrome/browser/media/media_capture_devices_dispatcher.h @@ -5,11 +5,15 @@ #ifndef CHROME_BROWSER_MEDIA_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_ #define CHROME_BROWSER_MEDIA_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_ +#include <queue> + #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/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/common/media_stream_request.h" @@ -27,7 +31,8 @@ class PrefRegistrySyncable; // This singleton is used to receive updates about media events from the content // layer. -class MediaCaptureDevicesDispatcher : public content::MediaObserver { +class MediaCaptureDevicesDispatcher : public content::MediaObserver, + public content::NotificationObserver { public: class Observer { public: @@ -119,9 +124,24 @@ class MediaCaptureDevicesDispatcher : public content::MediaObserver { private: friend struct DefaultSingletonTraits<MediaCaptureDevicesDispatcher>; + struct PendingAccessRequest { + PendingAccessRequest(const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback); + ~PendingAccessRequest(); + + content::MediaStreamRequest request; + content::MediaResponseCallback callback; + }; + typedef std::queue<PendingAccessRequest> RequestsQueue; + MediaCaptureDevicesDispatcher(); virtual ~MediaCaptureDevicesDispatcher(); + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + // Helpers for ProcessMediaAccessRequest(). void ProcessScreenCaptureAccessRequest( content::WebContents* web_contents, @@ -132,6 +152,14 @@ class MediaCaptureDevicesDispatcher : public content::MediaObserver { const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback, const extensions::Extension* extension); + void ProcessRegularMediaAccessRequest( + content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback); + void ProcessQueuedAccessRequest(content::WebContents* web_contents); + void OnAccessRequestResponse(content::WebContents* web_contents, + const content::MediaStreamDevices& devices, + scoped_ptr<content::MediaStreamUI> ui); // Called by the MediaObserver() functions, executed on UI thread. void UpdateAudioDevicesOnUIThread(const content::MediaStreamDevices& devices); @@ -158,9 +186,15 @@ class MediaCaptureDevicesDispatcher : public content::MediaObserver { // Flag used by unittests to disable device enumeration. bool is_device_enumeration_disabled_; + std::map<content::WebContents*, RequestsQueue> pending_requests_; + scoped_refptr<MediaStreamCaptureIndicator> media_stream_capture_indicator_; scoped_refptr<AudioStreamIndicator> audio_stream_indicator_; + + content::NotificationRegistrar notifications_registrar_; + + DISALLOW_COPY_AND_ASSIGN(MediaCaptureDevicesDispatcher); }; #endif // CHROME_BROWSER_MEDIA_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_ diff --git a/chrome/browser/media/media_stream_devices_controller.cc b/chrome/browser/media/media_stream_devices_controller.cc index 9ea42f7..5bafcf8 100644 --- a/chrome/browser/media/media_stream_devices_controller.cc +++ b/chrome/browser/media/media_stream_devices_controller.cc @@ -83,7 +83,12 @@ MediaStreamDevicesController::MediaStreamDevicesController( } } -MediaStreamDevicesController::~MediaStreamDevicesController() {} +MediaStreamDevicesController::~MediaStreamDevicesController() { + if (!callback_.is_null()) { + callback_.Run(content::MediaStreamDevices(), + scoped_ptr<content::MediaStreamUI>()); + } +} // static void MediaStreamDevicesController::RegisterUserPrefs( @@ -195,7 +200,9 @@ void MediaStreamDevicesController::Accept(bool update_content_setting) { GetMediaStreamCaptureIndicator()->RegisterMediaStream( web_contents_, devices); } - callback_.Run(devices, ui.Pass()); + content::MediaResponseCallback cb = callback_; + callback_.Reset(); + cb.Run(devices, ui.Pass()); } void MediaStreamDevicesController::Deny(bool update_content_setting) { @@ -210,8 +217,9 @@ void MediaStreamDevicesController::Deny(bool update_content_setting) { if (update_content_setting) SetPermission(false); - callback_.Run(content::MediaStreamDevices(), - scoped_ptr<content::MediaStreamUI>()); + content::MediaResponseCallback cb = callback_; + callback_.Reset(); + cb.Run(content::MediaStreamDevices(), scoped_ptr<content::MediaStreamUI>()); } MediaStreamDevicesController::DevicePolicy diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc index 4724338..fe2c26f3 100644 --- a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc +++ b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc @@ -9,6 +9,7 @@ #include "content/browser/browser_thread_impl.h" #include "content/browser/renderer_host/media/media_stream_dispatcher_host.h" #include "content/browser/renderer_host/media/media_stream_manager.h" +#include "content/browser/renderer_host/media/media_stream_ui_proxy.h" #include "content/browser/renderer_host/media/video_capture_manager.h" #include "content/common/media/media_stream_messages.h" #include "content/common/media/media_stream_options.h" @@ -125,7 +126,7 @@ class MockMediaStreamDispatcherHost : public MediaStreamDispatcherHost, MediaStreamManager* manager_; }; -class MockMediaStreamUI : public MediaStreamUI { +class MockMediaStreamUIProxy : public FakeMediaStreamUIProxy { public: MOCK_METHOD1(OnStarted, void(const base::Closure& stop)); }; @@ -164,11 +165,12 @@ class MediaStreamDispatcherHostTest : public testing::Test { } virtual void SetupFakeUI(bool expect_started) { - scoped_ptr<MockMediaStreamUI> stream_ui(new MockMediaStreamUI()); + scoped_ptr<MockMediaStreamUIProxy> stream_ui(new MockMediaStreamUIProxy()); if (expect_started) { EXPECT_CALL(*stream_ui, OnStarted(_)); } - media_stream_manager_->UseFakeUI(stream_ui.PassAs<MediaStreamUI>()); + media_stream_manager_->UseFakeUI( + stream_ui.PassAs<FakeMediaStreamUIProxy>()); } virtual void TearDown() OVERRIDE { @@ -336,10 +338,10 @@ TEST_F(MediaStreamDispatcherHostTest, CloseFromUI) { StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE); base::Closure close_callback; - scoped_ptr<MockMediaStreamUI> stream_ui(new MockMediaStreamUI()); + scoped_ptr<MockMediaStreamUIProxy> stream_ui(new MockMediaStreamUIProxy()); EXPECT_CALL(*stream_ui, OnStarted(_)) .WillOnce(SaveArg<0>(&close_callback)); - media_stream_manager_->UseFakeUI(stream_ui.PassAs<MediaStreamUI>()); + media_stream_manager_->UseFakeUI(stream_ui.PassAs<FakeMediaStreamUIProxy>()); EXPECT_CALL(*host_.get(), OnStreamGenerated(kRenderId, kPageRequestId, 0, 1)); EXPECT_CALL(*host_.get(), diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc index 84c2dc1..2a52423 100644 --- a/content/browser/renderer_host/media/media_stream_manager.cc +++ b/content/browser/renderer_host/media/media_stream_manager.cc @@ -14,7 +14,7 @@ #include "base/threading/thread.h" #include "content/browser/renderer_host/media/audio_input_device_manager.h" #include "content/browser/renderer_host/media/media_stream_requester.h" -#include "content/browser/renderer_host/media/media_stream_ui_controller.h" +#include "content/browser/renderer_host/media/media_stream_ui_proxy.h" #include "content/browser/renderer_host/media/video_capture_manager.h" #include "content/browser/renderer_host/media/web_contents_capture_util.h" #include "content/public/browser/browser_thread.h" @@ -54,37 +54,19 @@ static std::string RandomLabel() { } // Helper to verify if a media stream type is part of options or not. -static bool Requested(const StreamOptions& options, +static bool Requested(const MediaStreamRequest& request, MediaStreamType stream_type) { - return (options.audio_type == stream_type || - options.video_type == stream_type); + return (request.audio_type == stream_type || + request.video_type == stream_type); } // TODO(xians): Merge DeviceRequest with MediaStreamRequest. class MediaStreamManager::DeviceRequest { public: - DeviceRequest() - : requester(NULL), - type(MEDIA_GENERATE_STREAM), - render_process_id(-1), - render_view_id(-1), - state_(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_NOT_REQUESTED) { - } - DeviceRequest(MediaStreamRequester* requester, - const StreamOptions& request_options, - MediaStreamRequestType request_type, - int render_process_id, - int render_view_id, - const GURL& request_security_origin, - const std::string& requested_device_id) + const MediaStreamRequest& request) : requester(requester), - options(request_options), - type(request_type), - render_process_id(render_process_id), - render_view_id(render_view_id), - security_origin(request_security_origin), - requested_device_id(requested_device_id), + request(request), state_(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_NOT_REQUESTED) { } @@ -94,8 +76,8 @@ class MediaStreamManager::DeviceRequest { void SetState(MediaStreamType stream_type, MediaRequestState new_state) { state_[stream_type] = new_state; - if (options.video_type != MEDIA_TAB_VIDEO_CAPTURE && - options.audio_type != MEDIA_TAB_AUDIO_CAPTURE) { + if (request.video_type != MEDIA_TAB_VIDEO_CAPTURE && + request.audio_type != MEDIA_TAB_AUDIO_CAPTURE) { return; } @@ -109,12 +91,11 @@ class MediaStreamManager::DeviceRequest { // used internally within the content module. std::string device_id = WebContentsCaptureUtil::StripWebContentsDeviceScheme( - requested_device_id); + request.requested_device_id); media_observer->OnMediaRequestStateChanged( - render_process_id, render_view_id, - MediaStreamDevice( - stream_type, device_id, device_id), new_state); + request.render_process_id, request.render_view_id, + MediaStreamDevice(stream_type, device_id, device_id), new_state); } MediaRequestState state(MediaStreamType stream_type) const { @@ -122,18 +103,16 @@ class MediaStreamManager::DeviceRequest { } MediaStreamRequester* const requester; // Can be NULL. - const StreamOptions options; - const MediaStreamRequestType type; - const int render_process_id; - const int render_view_id; - const GURL security_origin; - const std::string requested_device_id; + MediaStreamRequest request; + StreamDeviceInfoArray devices; // Callback to the requester which audio/video devices have been selected. // It can be null if the requester has no interest to know the result. // Currently it is only used by |DEVICE_ACCESS| type. - MediaRequestResponseCallback callback; + MediaStreamManager::MediaRequestResponseCallback callback; + + scoped_ptr<MediaStreamUIProxy> ui_proxy; private: std::vector<MediaRequestState> state_; @@ -147,11 +126,11 @@ MediaStreamManager::EnumerationCache::~EnumerationCache() { } MediaStreamManager::MediaStreamManager(media::AudioManager* audio_manager) - : ui_controller_(new MediaStreamUIController(this)), - audio_manager_(audio_manager), + : audio_manager_(audio_manager), monitoring_started_(false), io_loop_(NULL), - screen_capture_active_(false) { + screen_capture_active_(false), + use_fake_ui_(false) { DCHECK(audio_manager_); memset(active_enumeration_ref_count_, 0, sizeof(active_enumeration_ref_count_)); @@ -194,13 +173,11 @@ std::string MediaStreamManager::MakeMediaAccessRequest( const MediaRequestResponseCallback& callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); // Create a new request based on options. - DeviceRequest* request = new DeviceRequest(NULL, - options, - MEDIA_DEVICE_ACCESS, - render_process_id, - render_view_id, - security_origin, - std::string()); + MediaStreamRequest stream_request( + render_process_id, render_view_id, security_origin, + MEDIA_DEVICE_ACCESS, std::string(), + options.audio_type, options.video_type); + DeviceRequest* request = new DeviceRequest(NULL, stream_request); const std::string& label = AddRequest(request); request->callback = callback; @@ -267,13 +244,11 @@ std::string MediaStreamManager::GenerateStream( } // Create a new request based on options. - DeviceRequest* request = new DeviceRequest(requester, - options, - MEDIA_GENERATE_STREAM, - target_render_process_id, - target_render_view_id, - security_origin, - requested_device_id); + MediaStreamRequest stream_request( + target_render_process_id, target_render_view_id, security_origin, + MEDIA_GENERATE_STREAM, requested_device_id, + options.audio_type, options.video_type); + DeviceRequest* request = new DeviceRequest(requester, stream_request); const std::string& label = AddRequest(request); HandleRequest(label); return label; @@ -284,9 +259,6 @@ void MediaStreamManager::CancelRequest(const std::string& label) { DeviceRequests::iterator it = requests_.find(label); if (it != requests_.end()) { - // The request isn't complete, notify the UI immediately. - ui_controller_->CancelUIRequest(label); - if (!RequestDone(*it->second)) { // TODO(xians): update the |state| to STATE_DONE to trigger a state // changed notification to UI before deleting the request? @@ -320,7 +292,7 @@ void MediaStreamManager::StopGeneratedStream(const std::string& label) { // Find the request and close all open devices for the request. DeviceRequests::iterator it = requests_.find(label); if (it != requests_.end()) { - if (it->second->type == MEDIA_ENUMERATE_DEVICES) { + if (it->second->request.request_type == MEDIA_ENUMERATE_DEVICES) { StopEnumerateDevices(label); return; } @@ -332,7 +304,7 @@ void MediaStreamManager::StopGeneratedStream(const std::string& label) { device_it != request->devices.end(); ++device_it) { GetDeviceManager(device_it->device.type)->Close(device_it->session_id); } - if (request->type == MEDIA_GENERATE_STREAM && + if (request->request.request_type == MEDIA_GENERATE_STREAM && RequestDone(*request)) { // Notify observers that this device is being closed. for (int i = MEDIA_NO_SERVICE + 1; i != NUM_MEDIA_TYPES; ++i) { @@ -342,12 +314,7 @@ void MediaStreamManager::StopGeneratedStream(const std::string& label) { MEDIA_REQUEST_STATE_CLOSING); } } - NotifyUIDevicesClosed(label); } - - // If request isn't complete, notify the UI on the cancellation. And it - // is also safe to call CancelUIRequest if the request has been done. - ui_controller_->CancelUIRequest(label); } } @@ -384,13 +351,11 @@ std::string MediaStreamManager::EnumerateDevices( return std::string(); } - DeviceRequest* request = new DeviceRequest(requester, - options, - MEDIA_ENUMERATE_DEVICES, - render_process_id, - render_view_id, - security_origin, - std::string()); + MediaStreamRequest stream_request( + render_process_id, render_view_id, security_origin, + MEDIA_ENUMERATE_DEVICES, std::string(), + options.audio_type, options.video_type); + DeviceRequest* request = new DeviceRequest(requester, stream_request); const std::string& label = AddRequest(request); if (cache->valid) { @@ -415,7 +380,7 @@ void MediaStreamManager::StopEnumerateDevices(const std::string& label) { DeviceRequests::iterator it = requests_.find(label); if (it != requests_.end()) { - DCHECK_EQ(it->second->type, MEDIA_ENUMERATE_DEVICES); + DCHECK_EQ(it->second->request.request_type, MEDIA_ENUMERATE_DEVICES); // Delete the DeviceRequest. scoped_ptr<DeviceRequest> request(it->second); RemoveRequest(it); @@ -444,29 +409,17 @@ std::string MediaStreamManager::OpenDevice( return std::string(); } - DeviceRequest* request = new DeviceRequest(requester, - options, - MEDIA_OPEN_DEVICE, - render_process_id, - render_view_id, - security_origin, - device_id); + MediaStreamRequest stream_request( + render_process_id, render_view_id, security_origin, + MEDIA_OPEN_DEVICE, device_id, + options.audio_type, options.video_type); + DeviceRequest* request = new DeviceRequest(requester, stream_request); const std::string& label = AddRequest(request); StartEnumeration(request); return label; } -void MediaStreamManager::NotifyUIDevicesOpened(const std::string& label) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - ui_controller_->NotifyUIIndicatorDevicesOpened(label); -} - -void MediaStreamManager::NotifyUIDevicesClosed(const std::string& label) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - ui_controller_->NotifyUIIndicatorDevicesClosed(label); -} - void MediaStreamManager::SendCachedDeviceList( EnumerationCache* cache, const std::string& label) { @@ -523,7 +476,7 @@ void MediaStreamManager::StartEnumeration(DeviceRequest* request) { // Start enumeration for devices of all requested device types. for (int i = MEDIA_NO_SERVICE + 1; i < NUM_MEDIA_TYPES; ++i) { const MediaStreamType stream_type = static_cast<MediaStreamType>(i); - if (Requested(request->options, stream_type)) { + if (Requested(request->request, stream_type)) { request->SetState(stream_type, MEDIA_REQUEST_STATE_REQUESTED); DCHECK_GE(active_enumeration_ref_count_[stream_type], 0); if (active_enumeration_ref_count_[stream_type] == 0) { @@ -549,35 +502,57 @@ std::string MediaStreamManager::AddRequest(DeviceRequest* request) { } void MediaStreamManager::RemoveRequest(DeviceRequests::iterator it) { - if (it->second->options.video_type == MEDIA_SCREEN_VIDEO_CAPTURE) { + if (it->second->request.video_type == MEDIA_SCREEN_VIDEO_CAPTURE) { DCHECK(screen_capture_active_); screen_capture_active_ = false; } - NotifyUIDevicesClosed(it->first); - requests_.erase(it); } void MediaStreamManager::PostRequestToUI(const std::string& label) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DeviceRequest* request = requests_[label]; - // Get user confirmation to use capture devices. - ui_controller_->MakeUIRequest(label, - request->render_process_id, - request->render_view_id, - request->options, - request->security_origin, - request->type, - request->requested_device_id); + + if (use_fake_ui_) { + if (!fake_ui_) + fake_ui_.reset(new FakeMediaStreamUIProxy()); + + MediaStreamDevices devices; + if (audio_enumeration_cache_.valid) { + for (StreamDeviceInfoArray::const_iterator it = + audio_enumeration_cache_.devices.begin(); + it != audio_enumeration_cache_.devices.end(); ++it) { + devices.push_back(it->device); + } + } + if (video_enumeration_cache_.valid) { + for (StreamDeviceInfoArray::const_iterator it = + video_enumeration_cache_.devices.begin(); + it != video_enumeration_cache_.devices.end(); ++it) { + devices.push_back(it->device); + } + } + + fake_ui_->SetAvailableDevices(devices); + + request->ui_proxy = fake_ui_.Pass(); + } else { + request->ui_proxy = MediaStreamUIProxy::Create(); + } + + request->ui_proxy->RequestAccess( + request->request, + base::Bind(&MediaStreamManager::HandleAccessRequestResponse, + base::Unretained(this), label)); } void MediaStreamManager::HandleRequest(const std::string& label) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DeviceRequest* request = requests_[label]; - const MediaStreamType audio_type = request->options.audio_type; - const MediaStreamType video_type = request->options.video_type; + const MediaStreamType audio_type = request->request.audio_type; + const MediaStreamType video_type = request->request.video_type; bool is_web_contents_capture = audio_type == MEDIA_TAB_AUDIO_CAPTURE || @@ -679,7 +654,7 @@ void MediaStreamManager::Opened(MediaStreamType stream_type, return; } - switch (request->type) { + switch (request->request.request_type) { case MEDIA_OPEN_DEVICE: request->requester->DeviceOpened(label, devices->front()); break; @@ -709,7 +684,9 @@ void MediaStreamManager::Opened(MediaStreamType stream_type, } request->requester->StreamGenerated(label, audio_devices, video_devices); - NotifyUIDevicesOpened(label); + request->ui_proxy->OnStarted( + base::Bind(&MediaStreamManager::StopStreamFromUI, + base::Unretained(this), label)); break; } default: @@ -751,10 +728,9 @@ void MediaStreamManager::DevicesEnumerated( std::list<std::string> label_list; for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end(); ++it) { - if (it->second->state(stream_type) == - MEDIA_REQUEST_STATE_REQUESTED && - Requested(it->second->options, stream_type)) { - if (it->second->type != MEDIA_ENUMERATE_DEVICES) + if (it->second->state(stream_type) == MEDIA_REQUEST_STATE_REQUESTED && + Requested(it->second->request, stream_type)) { + if (it->second->request.request_type != MEDIA_ENUMERATE_DEVICES) it->second->SetState(stream_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL); label_list.push_back(it->first); } @@ -762,15 +738,15 @@ void MediaStreamManager::DevicesEnumerated( for (std::list<std::string>::iterator it = label_list.begin(); it != label_list.end(); ++it) { DeviceRequest* request = requests_[*it]; - switch (request->type) { + switch (request->request.request_type) { case MEDIA_ENUMERATE_DEVICES: if (need_update_clients && request->requester) request->requester->DevicesEnumerated(*it, devices); break; default: - if (request->state(request->options.audio_type) == + if (request->state(request->request.audio_type) == MEDIA_REQUEST_STATE_REQUESTED || - request->state(request->options.video_type) == + request->state(request->request.video_type) == MEDIA_REQUEST_STATE_REQUESTED) { // We are doing enumeration for other type of media, wait until it is // all done before posting the request to UI because UI needs @@ -842,28 +818,37 @@ void MediaStreamManager::Error(MediaStreamType stream_type, } } -void MediaStreamManager::DevicesAccepted(const std::string& label, - const StreamDeviceInfoArray& devices) { +void MediaStreamManager::HandleAccessRequestResponse( + const std::string& label, + const MediaStreamDevices& devices) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - DCHECK(!devices.empty()); + DeviceRequests::iterator request_it = requests_.find(label); if (request_it == requests_.end()) { return; } - if (request_it->second->type == MEDIA_DEVICE_ACCESS) { + // Handle the case when the request was denied. + if (devices.empty()) { + // Notify the users about the request result. scoped_ptr<DeviceRequest> request(request_it->second); - if (!request->callback.is_null()) { - // Map the devices to MediaStreamDevices. - MediaStreamDevices selected_devices; - for (StreamDeviceInfoArray::const_iterator it = devices.begin(); - it != devices.end(); ++it) { - selected_devices.push_back(it->device); - } + if (request->requester) + request->requester->StreamGenerationFailed(label); - request->callback.Run(label, selected_devices); + if (request->request.request_type == MEDIA_DEVICE_ACCESS && + !request->callback.is_null()) { + request->callback.Run(MediaStreamDevices(), request->ui_proxy.Pass()); } + RemoveRequest(request_it); + return; + } + + if (request_it->second->request.request_type == MEDIA_DEVICE_ACCESS) { + scoped_ptr<DeviceRequest> request(request_it->second); + if (!request->callback.is_null()) + request->callback.Run(devices, request->ui_proxy.Pass()); + // Delete the request since it is done. RemoveRequest(request_it); return; @@ -871,16 +856,18 @@ void MediaStreamManager::DevicesAccepted(const std::string& label, // Process all newly-accepted devices for this request. DeviceRequest* request = request_it->second; - bool found_audio = false, found_video = false; - for (StreamDeviceInfoArray::const_iterator device_it = devices.begin(); + bool found_audio = false; + bool found_video = false; + for (MediaStreamDevices::const_iterator device_it = devices.begin(); device_it != devices.end(); ++device_it) { - StreamDeviceInfo device_info = *device_it; // Make a copy. + StreamDeviceInfo device_info; + device_info.device = *device_it; // TODO(justinlin): Nicer way to do this? // Re-append the device's id since we lost it when posting request to UI. if (device_info.device.type == content::MEDIA_TAB_VIDEO_CAPTURE || device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) { - device_info.device.id = request->requested_device_id; + device_info.device.id = request->request.requested_device_id; // Initialize the sample_rate and channel_layout here since for audio // mirroring, we don't go through EnumerateDevices where these are usually @@ -902,48 +889,26 @@ void MediaStreamManager::DevicesAccepted(const std::string& label, // Set in_use to false to be able to track if this device has been // opened. in_use might be true if the device type can be used in more // than one session. - DCHECK_EQ(request->state(device_it->device.type), - MEDIA_REQUEST_STATE_PENDING_APPROVAL); device_info.in_use = false; device_info.session_id = GetDeviceManager(device_info.device.type)->Open(device_info); - request->SetState(device_it->device.type, MEDIA_REQUEST_STATE_OPENING); + request->SetState(device_info.device.type, MEDIA_REQUEST_STATE_OPENING); request->devices.push_back(device_info); - if (device_info.device.type == request->options.audio_type) { + if (device_info.device.type == request->request.audio_type) { found_audio = true; - } else if (device_info.device.type == request->options.video_type) { + } else if (device_info.device.type == request->request.video_type) { found_video = true; } } // Check whether we've received all stream types requested. - if (!found_audio && IsAudioMediaType(request->options.audio_type)) - request->SetState(request->options.audio_type, MEDIA_REQUEST_STATE_ERROR); - - if (!found_video && IsVideoMediaType(request->options.video_type)) - request->SetState(request->options.video_type, MEDIA_REQUEST_STATE_ERROR); -} - -void MediaStreamManager::SettingsError(const std::string& label) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - // Erase this request and report an error. - DeviceRequests::iterator it = requests_.find(label); - if (it == requests_.end()) - return; - - // Notify the users about the request result. - scoped_ptr<DeviceRequest> request(it->second); - if (request->requester) - request->requester->StreamGenerationFailed(label); - - if (request->type == MEDIA_DEVICE_ACCESS && - !request->callback.is_null()) { - request->callback.Run(label, MediaStreamDevices()); - } + if (!found_audio && IsAudioMediaType(request->request.audio_type)) + request->SetState(request->request.audio_type, MEDIA_REQUEST_STATE_ERROR); - RemoveRequest(it); + if (!found_video && IsVideoMediaType(request->request.video_type)) + request->SetState(request->request.video_type, MEDIA_REQUEST_STATE_ERROR); } void MediaStreamManager::StopStreamFromUI(const std::string& label) { @@ -960,38 +925,17 @@ void MediaStreamManager::StopStreamFromUI(const std::string& label) { StopGeneratedStream(label); } -void MediaStreamManager::GetAvailableDevices(MediaStreamDevices* devices) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - DCHECK(audio_enumeration_cache_.valid || video_enumeration_cache_.valid); - DCHECK(devices->empty()); - if (audio_enumeration_cache_.valid) { - for (StreamDeviceInfoArray::const_iterator it = - audio_enumeration_cache_.devices.begin(); - it != audio_enumeration_cache_.devices.end(); - ++it) { - devices->push_back(it->device); - } - } - - if (video_enumeration_cache_.valid) { - for (StreamDeviceInfoArray::const_iterator it = - video_enumeration_cache_.devices.begin(); - it != video_enumeration_cache_.devices.end(); - ++it) { - devices->push_back(it->device); - } - } -} - void MediaStreamManager::UseFakeDevice() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); video_capture_manager()->UseFakeDevice(); audio_input_device_manager()->UseFakeDevice(); - UseFakeUI(scoped_ptr<MediaStreamUI>()); + UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy>()); } -void MediaStreamManager::UseFakeUI(scoped_ptr<MediaStreamUI> fake_ui) { - ui_controller_->UseFakeUI(fake_ui.Pass()); +void MediaStreamManager::UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy> fake_ui) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + use_fake_ui_ = true; + fake_ui_ = fake_ui.Pass(); } void MediaStreamManager::WillDestroyCurrentMessageLoop() { @@ -1008,7 +952,6 @@ void MediaStreamManager::WillDestroyCurrentMessageLoop() { audio_input_device_manager_ = NULL; video_capture_manager_ = NULL; io_loop_ = NULL; - ui_controller_.reset(); } void MediaStreamManager::NotifyDevicesChanged( @@ -1039,23 +982,23 @@ void MediaStreamManager::NotifyDevicesChanged( bool MediaStreamManager::RequestDone(const DeviceRequest& request) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - const bool requested_audio = IsAudioMediaType(request.options.audio_type); - const bool requested_video = IsVideoMediaType(request.options.video_type); + const bool requested_audio = IsAudioMediaType(request.request.audio_type); + const bool requested_video = IsVideoMediaType(request.request.video_type); const bool audio_done = !requested_audio || - request.state(request.options.audio_type) == + request.state(request.request.audio_type) == MEDIA_REQUEST_STATE_DONE || - request.state(request.options.audio_type) == + request.state(request.request.audio_type) == MEDIA_REQUEST_STATE_ERROR; if (!audio_done) return false; const bool video_done = !requested_video || - request.state(request.options.video_type) == + request.state(request.request.video_type) == MEDIA_REQUEST_STATE_DONE || - request.state(request.options.video_type) == + request.state(request.request.video_type) == MEDIA_REQUEST_STATE_ERROR; if (!video_done) return false; diff --git a/content/browser/renderer_host/media/media_stream_manager.h b/content/browser/renderer_host/media/media_stream_manager.h index acde644d..ae9fd37 100644 --- a/content/browser/renderer_host/media/media_stream_manager.h +++ b/content/browser/renderer_host/media/media_stream_manager.h @@ -32,7 +32,6 @@ #include "base/message_loop.h" #include "base/system_monitor/system_monitor.h" #include "content/browser/renderer_host/media/media_stream_provider.h" -#include "content/browser/renderer_host/media/media_stream_settings_requester.h" #include "content/common/media/media_stream_options.h" #include "content/common/content_export.h" @@ -47,9 +46,10 @@ class AudioManager; namespace content { class AudioInputDeviceManager; +class FakeMediaStreamUIProxy; class MediaStreamDeviceSettings; class MediaStreamRequester; -class MediaStreamUIController; +class MediaStreamUIProxy; class VideoCaptureManager; // MediaStreamManager is used to generate and close new media devices, not to @@ -59,9 +59,14 @@ class VideoCaptureManager; class CONTENT_EXPORT MediaStreamManager : public MediaStreamProviderListener, public base::MessageLoop::DestructionObserver, - public SettingsRequester, public base::SystemMonitor::DevicesChangedObserver { public: + // Callback to deliver the result of a media request. |label| is the string + // to identify the request, + typedef base::Callback<void(const MediaStreamDevices& devices, + scoped_ptr<MediaStreamUIProxy> ui)> + MediaRequestResponseCallback; + explicit MediaStreamManager(media::AudioManager* audio_manager); virtual ~MediaStreamManager(); @@ -122,14 +127,6 @@ class CONTENT_EXPORT MediaStreamManager MediaStreamType type, const GURL& security_origin); - // Signals the UI that the devices are opened. - // Users are responsible for calling NotifyUIDevicesClosed when the devices - // are not used anymore, otherwise UI will leak. - void NotifyUIDevicesOpened(const std::string& label); - - // Signals the UI that the devices are being closed. - void NotifyUIDevicesClosed(const std::string& label); - // Implements MediaStreamProviderListener. virtual void Opened(MediaStreamType stream_type, int capture_session_id) OVERRIDE; @@ -141,13 +138,6 @@ class CONTENT_EXPORT MediaStreamManager int capture_session_id, MediaStreamProviderError error) OVERRIDE; - // Implements SettingsRequester. - virtual void DevicesAccepted(const std::string& label, - const StreamDeviceInfoArray& devices) OVERRIDE; - virtual void SettingsError(const std::string& label) OVERRIDE; - virtual void StopStreamFromUI(const std::string& label) OVERRIDE; - virtual void GetAvailableDevices(MediaStreamDevices* devices) OVERRIDE; - // Implements base::SystemMonitor::DevicesChangedObserver. virtual void OnDevicesChanged( base::SystemMonitor::DeviceType device_type) OVERRIDE; @@ -158,7 +148,7 @@ class CONTENT_EXPORT MediaStreamManager // Called by the unittests to specify fake UI that should be used for next // generated stream. - void UseFakeUI(scoped_ptr<MediaStreamUI> fake_ui); + void UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy> fake_ui); // This object gets deleted on the UI thread after the IO thread has been // destroyed. So we need to know when IO thread is being destroyed so that @@ -189,6 +179,11 @@ class CONTENT_EXPORT MediaStreamManager void NotifyDevicesChanged(MediaStreamType stream_type, const StreamDeviceInfoArray& devices); + + void HandleAccessRequestResponse(const std::string& label, + const MediaStreamDevices& devices); + void StopStreamFromUI(const std::string& label); + // Helpers. bool RequestDone(const DeviceRequest& request) const; MediaStreamProvider* GetDeviceManager(MediaStreamType stream_type); @@ -210,15 +205,9 @@ class CONTENT_EXPORT MediaStreamManager void StartMonitoring(); void StopMonitoring(); - // Callback for UI called when the user requests stream with the specified - // |label| to be stopped. - void OnStopStreamRequested(const std::string& label); - // Device thread shared by VideoCaptureManager and AudioInputDeviceManager. scoped_ptr<base::Thread> device_thread_; - scoped_ptr<MediaStreamUIController> ui_controller_; - media::AudioManager* const audio_manager_; // not owned scoped_refptr<AudioInputDeviceManager> audio_input_device_manager_; scoped_refptr<VideoCaptureManager> video_capture_manager_; @@ -244,6 +233,9 @@ class CONTENT_EXPORT MediaStreamManager bool screen_capture_active_; + bool use_fake_ui_; + scoped_ptr<FakeMediaStreamUIProxy> fake_ui_; + DISALLOW_COPY_AND_ASSIGN(MediaStreamManager); }; diff --git a/content/browser/renderer_host/media/media_stream_manager_unittest.cc b/content/browser/renderer_host/media/media_stream_manager_unittest.cc index a515a36..b800d75 100644 --- a/content/browser/renderer_host/media/media_stream_manager_unittest.cc +++ b/content/browser/renderer_host/media/media_stream_manager_unittest.cc @@ -8,6 +8,7 @@ #include "base/message_loop.h" #include "content/browser/browser_thread_impl.h" #include "content/browser/renderer_host/media/media_stream_manager.h" +#include "content/browser/renderer_host/media/media_stream_ui_proxy.h" #include "content/common/media/media_stream_options.h" #include "media/audio/audio_manager_base.h" #if defined(OS_ANDROID) @@ -63,10 +64,11 @@ class MediaStreamManagerTest : public ::testing::Test { public: MediaStreamManagerTest() {} - MOCK_METHOD1(Response, void(const std::string&)); - void ResponseCallback(const std::string& label, - const MediaStreamDevices& devices) { - Response(label); + MOCK_METHOD1(Response, void(int index)); + void ResponseCallback(int index, + const MediaStreamDevices& devices, + scoped_ptr<MediaStreamUIProxy> ui_proxy) { + Response(index); message_loop_->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); } @@ -95,15 +97,15 @@ class MediaStreamManagerTest : public ::testing::Test { message_loop_.reset(); } - std::string MakeMediaAccessRequest() { + std::string MakeMediaAccessRequest(int index) { const int render_process_id = 1; const int render_view_id = 1; StreamOptions components(MEDIA_DEVICE_AUDIO_CAPTURE, MEDIA_DEVICE_VIDEO_CAPTURE); const GURL security_origin; - MediaRequestResponseCallback callback = + MediaStreamManager::MediaRequestResponseCallback callback = base::Bind(&MediaStreamManagerTest::ResponseCallback, - base::Unretained(this)); + base::Unretained(this), index); return media_stream_manager_->MakeMediaAccessRequest(render_process_id, render_view_id, components, @@ -122,22 +124,22 @@ class MediaStreamManagerTest : public ::testing::Test { }; TEST_F(MediaStreamManagerTest, MakeMediaAccessRequest) { - std::string label = MakeMediaAccessRequest(); + MakeMediaAccessRequest(0); // Expecting the callback will be triggered and quit the test. - EXPECT_CALL(*this, Response(label)); + EXPECT_CALL(*this, Response(0)); WaitForResult(); } TEST_F(MediaStreamManagerTest, MakeAndCancelMediaAccessRequest) { - std::string label = MakeMediaAccessRequest(); + std::string label = MakeMediaAccessRequest(0); // No callback is expected. media_stream_manager_->CancelRequest(label); } TEST_F(MediaStreamManagerTest, MakeMultipleRequests) { // First request. - std::string label1 = MakeMediaAccessRequest(); + std::string label1 = MakeMediaAccessRequest(0); // Second request. int render_process_id = 2; @@ -145,9 +147,9 @@ TEST_F(MediaStreamManagerTest, MakeMultipleRequests) { StreamOptions components(MEDIA_DEVICE_AUDIO_CAPTURE, MEDIA_DEVICE_VIDEO_CAPTURE); GURL security_origin; - MediaRequestResponseCallback callback = + MediaStreamManager::MediaRequestResponseCallback callback = base::Bind(&MediaStreamManagerTest::ResponseCallback, - base::Unretained(this)); + base::Unretained(this), 1); std::string label2 = media_stream_manager_->MakeMediaAccessRequest( render_process_id, render_view_id, @@ -158,18 +160,19 @@ TEST_F(MediaStreamManagerTest, MakeMultipleRequests) { // Expecting the callbackS from requests will be triggered and quit the test. // Note, the callbacks might come in a different order depending on the // value of labels. - EXPECT_CALL(*this, Response(_)).Times(2); + EXPECT_CALL(*this, Response(0)); + EXPECT_CALL(*this, Response(1)); WaitForResult(); } TEST_F(MediaStreamManagerTest, MakeAndCancelMultipleRequests) { - std::string label1 = MakeMediaAccessRequest(); - std::string label2 = MakeMediaAccessRequest(); + std::string label1 = MakeMediaAccessRequest(0); + std::string label2 = MakeMediaAccessRequest(1); media_stream_manager_->CancelRequest(label1); // Expecting the callback from the second request will be triggered and // quit the test. - EXPECT_CALL(*this, Response(label2)); + EXPECT_CALL(*this, Response(1)); WaitForResult(); } diff --git a/content/browser/renderer_host/media/media_stream_settings_requester.h b/content/browser/renderer_host/media/media_stream_settings_requester.h deleted file mode 100644 index 9aa4f31..0000000 --- a/content/browser/renderer_host/media/media_stream_settings_requester.h +++ /dev/null @@ -1,39 +0,0 @@ -// 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 file. - -#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_SETTINGS_REQUESTER_H_ -#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_SETTINGS_REQUESTER_H_ - -#include <string> - -#include "content/common/content_export.h" -#include "content/common/media/media_stream_options.h" - -namespace content { - -// Implemented by the class requesting media capture device usage. -class CONTENT_EXPORT SettingsRequester { - public: - // If no error occurred, this call will deliver the result and the request - // is considered answered. - virtual void DevicesAccepted(const std::string& label, - const StreamDeviceInfoArray& devices) = 0; - - // An error for specified |request_id| has occurred. - virtual void SettingsError(const std::string& label) = 0; - - // Called when user requested the stream with the specified |label| to be - // stopped. - virtual void StopStreamFromUI(const std::string& label) = 0; - - // Gets a list of available devices stored in the requester. - virtual void GetAvailableDevices(MediaStreamDevices* devices) = 0; - - protected: - virtual ~SettingsRequester() {} -}; - -} // namespace content - -#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_SETTINGS_REQUESTER_H_ diff --git a/content/browser/renderer_host/media/media_stream_ui_controller.cc b/content/browser/renderer_host/media/media_stream_ui_controller.cc deleted file mode 100644 index 115bfd6..0000000 --- a/content/browser/renderer_host/media/media_stream_ui_controller.cc +++ /dev/null @@ -1,336 +0,0 @@ -// 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 file. - -#include "content/browser/renderer_host/media/media_stream_ui_controller.h" - -#include <algorithm> - -#include "base/bind.h" -#include "base/callback.h" -#include "base/logging.h" -#include "base/message_loop_proxy.h" -#include "base/stl_util.h" -#include "content/browser/renderer_host/media/media_stream_settings_requester.h" -#include "content/browser/renderer_host/render_view_host_delegate.h" -#include "content/browser/renderer_host/render_view_host_impl.h" -#include "content/common/media/media_stream_options.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/content_browser_client.h" -#include "content/public/browser/media_observer.h" -#include "content/public/common/media_stream_request.h" -#include "googleurl/src/gurl.h" -#include "media/base/bind_to_loop.h" - -namespace content { - -// UI request contains all data needed to keep track of requests between the -// different calls. -class MediaStreamRequestForUI : public MediaStreamRequest { - public: - MediaStreamRequestForUI(int render_pid, - int render_vid, - const GURL& origin, - const StreamOptions& options, - MediaStreamRequestType request_type, - const std::string& requested_device_id) - : MediaStreamRequest(render_pid, render_vid, origin, - request_type, requested_device_id, - options.audio_type, options.video_type), - posted_task(false) { - DCHECK(IsAudioMediaType(options.audio_type) || - IsVideoMediaType(options.video_type)); - } - - ~MediaStreamRequestForUI() {} - - // Whether or not a task was posted to make the call to - // RequestMediaAccessPermission, to make sure that we never post twice to it. - bool posted_task; -}; - -namespace { - -// Sends the request to the appropriate WebContents. -void ProceedMediaAccessPermission(const MediaStreamRequestForUI& request, - const MediaResponseCallback& callback) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - // Send the permission request to the web contents. - RenderViewHostImpl* host = RenderViewHostImpl::FromID( - request.render_process_id, request.render_view_id); - - // Tab may have gone away. - if (!host || !host->GetDelegate()) { - callback.Run(MediaStreamDevices(), scoped_ptr<MediaStreamUI>()); - return; - } - - host->GetDelegate()->RequestMediaAccessPermission(request, callback); -} - -} // namespace - -MediaStreamUIController::MediaStreamUIController(SettingsRequester* requester) - : requester_(requester), - use_fake_ui_(false) { - DCHECK(requester_); -} - -MediaStreamUIController::~MediaStreamUIController() { - DCHECK(requests_.empty()); - DCHECK(stream_indicators_.empty()); -} - -void MediaStreamUIController::MakeUIRequest( - const std::string& label, - int render_process_id, - int render_view_id, - const StreamOptions& request_options, - const GURL& security_origin, MediaStreamRequestType request_type, - const std::string& requested_device_id) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - - // Create a new request. - if (!requests_.insert( - std::make_pair(label, new MediaStreamRequestForUI( - render_process_id, render_view_id, security_origin, - request_options, request_type, requested_device_id))).second) { - NOTREACHED(); - } - - if (use_fake_ui_) { - PostRequestToFakeUI(label); - return; - } - - // The UI can handle only one request at the time, do not post the - // request to the view if the UI is handling any other request. - if (IsUIBusy(render_process_id, render_view_id)) - return; - - PostRequestToUI(label); -} - -void MediaStreamUIController::CancelUIRequest(const std::string& label) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - UIRequests::iterator request_iter = requests_.find(label); - if (request_iter != requests_.end()) { - // Proceed the next pending request for the same page. - scoped_ptr<MediaStreamRequestForUI> request(request_iter->second); - int render_view_id = request->render_view_id; - int render_process_id = request->render_process_id; - bool was_posted = request->posted_task; - - // TODO(xians): Post a cancel request on UI thread to dismiss the infobar - // if request has been sent to the UI. - // Remove the request from the queue. - requests_.erase(request_iter); - - // Simply return if the canceled request has not been brought to UI. - if (!was_posted) - return; - - // Process the next pending request to replace the old infobar on the same - // page. - ProcessNextRequestForView(render_process_id, render_view_id); - } - - NotifyUIIndicatorDevicesClosed(label); -} - -void MediaStreamUIController::ProcessAccessRequestResponse( - const std::string& label, - const MediaStreamDevices& devices, - scoped_ptr<MediaStreamUI> stream_ui) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - - UIRequests::iterator request_iter = requests_.find(label); - // Return if the request has been removed. - if (request_iter == requests_.end()) { - if (stream_ui) { - BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, - stream_ui.release()); - } - return; - } - - DCHECK(requester_); - scoped_ptr<MediaStreamRequestForUI> request(request_iter->second); - requests_.erase(request_iter); - - // Look for queued requests for the same view. If there is a pending request, - // post it for user approval. - ProcessNextRequestForView(request->render_process_id, - request->render_view_id); - - if (!devices.empty()) { - if (stream_ui) { - DCHECK(stream_indicators_.find(label) == stream_indicators_.end()); - stream_indicators_[label] = stream_ui.release(); - } - - // Build a list of "full" device objects for the accepted devices. - StreamDeviceInfoArray device_list; - // TODO(xians): figure out if it is all right to hard code in_use to false, - // though DevicesAccepted seems to do so. - for (MediaStreamDevices::const_iterator dev = devices.begin(); - dev != devices.end(); ++dev) { - device_list.push_back(StreamDeviceInfo( - dev->type, dev->name, dev->id, - dev->sample_rate, dev->channel_layout, false)); - } - - requester_->DevicesAccepted(label, device_list); - } else { - DCHECK(!stream_ui); - requester_->SettingsError(label); - } -} - -void MediaStreamUIController::NotifyUIIndicatorDevicesOpened( - const std::string& label) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - - IndicatorsMap::iterator it = stream_indicators_.find(label); - if (it != stream_indicators_.end()) { - base::Closure stop_callback = media::BindToLoop( - base::MessageLoopProxy::current(), - base::Bind(&MediaStreamUIController::OnStopStreamFromUI, - base::Unretained(this), label)); - - // base::Unretained is safe here because the target can be deleted only on - // UI thread when posted from IO thread (see - // NotifyUIIndicatorDevicesClosed()). - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&MediaStreamUI::OnStarted, - base::Unretained(it->second), stop_callback)); - } -} - -void MediaStreamUIController::NotifyUIIndicatorDevicesClosed( - const std::string& label) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - - IndicatorsMap::iterator indicator = stream_indicators_.find(label); - if (indicator != stream_indicators_.end()) { - BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, indicator->second); - stream_indicators_.erase(indicator); - } -} - -void MediaStreamUIController::UseFakeUI(scoped_ptr<MediaStreamUI> fake_ui) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - use_fake_ui_ = true; - fake_ui_ = fake_ui.Pass(); -} - -bool MediaStreamUIController::IsUIBusy(int render_process_id, - int render_view_id) { - for (UIRequests::iterator it = requests_.begin(); - it != requests_.end(); ++it) { - if (it->second->render_process_id == render_process_id && - it->second->render_view_id == render_view_id && - it->second->posted_task) { - return true; - } - } - return false; -} - -void MediaStreamUIController::ProcessNextRequestForView( - int render_process_id, - int render_view_id) { - std::string next_request_label; - for (UIRequests::iterator it = requests_.begin(); it != requests_.end(); - ++it) { - if (it->second->render_process_id == render_process_id && - it->second->render_view_id == render_view_id) { - // This request belongs to the given render view. - if (!it->second->posted_task) { - next_request_label = it->first; - break; - } - } - } - - if (next_request_label.empty()) - return; - - if (fake_ui_) { - PostRequestToFakeUI(next_request_label); - } else { - PostRequestToUI(next_request_label); - } -} - -void MediaStreamUIController::PostRequestToUI(const std::string& label) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - UIRequests::iterator request_iter = requests_.find(label); - - if (request_iter == requests_.end()) { - NOTREACHED(); - return; - } - MediaStreamRequestForUI* request = request_iter->second; - DCHECK(request != NULL); - - request->posted_task = true; - - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, base::Bind( - &ProceedMediaAccessPermission, *request, media::BindToLoop( - base::MessageLoopProxy::current(), base::Bind( - &MediaStreamUIController::ProcessAccessRequestResponse, - base::Unretained(this), label)))); -} - -void MediaStreamUIController::PostRequestToFakeUI(const std::string& label) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - DCHECK(requester_); - UIRequests::iterator request_iter = requests_.find(label); - DCHECK(request_iter != requests_.end()); - MediaStreamRequestForUI* request = request_iter->second; - - MediaStreamDevices devices; - requester_->GetAvailableDevices(&devices); - MediaStreamDevices devices_to_use; - bool accepted_audio = false; - bool accepted_video = false; - // Use the first capture device of the same media type in the list for the - // fake UI. - for (MediaStreamDevices::const_iterator it = devices.begin(); - it != devices.end(); ++it) { - if (!accepted_audio && - IsAudioMediaType(request->audio_type) && - IsAudioMediaType(it->type)) { - devices_to_use.push_back(*it); - accepted_audio = true; - } else if (!accepted_video && - IsVideoMediaType(request->video_type) && - IsVideoMediaType(it->type)) { - devices_to_use.push_back(*it); - accepted_video = true; - } - } - - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&MediaStreamUIController::ProcessAccessRequestResponse, - base::Unretained(this), label, devices_to_use, - base::Passed(&fake_ui_))); -} - -void MediaStreamUIController::OnStopStreamFromUI(const std::string& label) { - // It's safe to base::Unretained() here because |requester_| references - // MediaStreamManager which always outlives IO thread. - // - // TODO(sergeyu): Refactor this code to not rely on what |requester_| is. - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&SettingsRequester::StopStreamFromUI, - base::Unretained(requester_), label)); -} - -} // namespace content diff --git a/content/browser/renderer_host/media/media_stream_ui_controller.h b/content/browser/renderer_host/media/media_stream_ui_controller.h deleted file mode 100644 index 6d14e83..0000000 --- a/content/browser/renderer_host/media/media_stream_ui_controller.h +++ /dev/null @@ -1,106 +0,0 @@ -// 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 file. - -// MediaStreamUIController is used to decide which of the available capture -// device to use as well as getting user permission to use the capture device. -// There will be one instance of MediaStreamDeviceSettings handling all -// requests. - -// Expected call flow: -// 1. MakeUIRequest() is called to create a new request to the UI for capture -// device access. -// 2. Pick device and get user confirmation. -// 3. Confirm by calling SettingsRequester::DevicesAccepted(). -// Repeat step 1 - 3 for new device requests. - -#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_UI_CONTROLLER_H_ -#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_UI_CONTROLLER_H_ - -#include <map> -#include <string> - -#include "base/basictypes.h" -#include "content/browser/renderer_host/media/media_stream_provider.h" -#include "content/public/browser/web_contents_delegate.h" - -namespace content { - -class MediaStreamRequestForUI; -class SettingsRequester; - -// MediaStreamUIController is responsible for getting user permission to use -// a media capture device as well as selecting what device to use. -class CONTENT_EXPORT MediaStreamUIController { - public: - explicit MediaStreamUIController(SettingsRequester* requester); - virtual ~MediaStreamUIController(); - - // Called when a new request for the capture device access is made. - // Users are responsible for canceling the pending request if they don't wait - // for the result from the UI. - void MakeUIRequest(const std::string& label, - int render_process_id, - int render_view_id, - const StreamOptions& stream_components, - const GURL& security_origin, - MediaStreamRequestType request_type, - const std::string& requested_device_id); - - // Called to cancel a pending UI request of capture device access when the - // user has no action for the media stream InfoBar. - void CancelUIRequest(const std::string& label); - - // Called to signal the UI indicator that the devices are opened. - void NotifyUIIndicatorDevicesOpened(const std::string& label); - - // Called to signal the UI indicator that the devices are closed. - void NotifyUIIndicatorDevicesClosed(const std::string& label); - - // Used for testing only. This function is called to use faked UI, which is - // needed for server based tests. The first non-opened device(s) will be - // picked. - void UseFakeUI(scoped_ptr<MediaStreamUI> fake_ui); - - private: - typedef std::map<std::string, MediaStreamRequestForUI*> UIRequests; - typedef std::map<std::string, MediaStreamUI*> IndicatorsMap; - - // Returns true if the UI is already processing a request for this render - // view. - bool IsUIBusy(int render_process_id, int render_view_id); - - // Process the next pending request and bring it up to the UI on the given - // page for user approval. - void ProcessNextRequestForView(int render_process_id, int render_view_id); - - // Posts a request to be approved/denied by UI. - void PostRequestToUI(const std::string& label); - - // Posts a request to fake UI which is used for testing purpose. - void PostRequestToFakeUI(const std::string& label); - - // Callback handler for WebContents::RequestMediaAccessPermission(). - void ProcessAccessRequestResponse(const std::string& label, - const MediaStreamDevices& devices, - scoped_ptr<MediaStreamUI> stream_ui); - - // Callback for UI called when user requests a stream to be stopped. - void OnStopStreamFromUI(const std::string& label); - - SettingsRequester* requester_; - UIRequests requests_; - - // See comment above for method UseFakeUI. Used for automated testing. - bool use_fake_ui_; - scoped_ptr<MediaStreamUI> fake_ui_; - - // Container MediaStreamUI objects for currently active streams. - IndicatorsMap stream_indicators_; - - DISALLOW_COPY_AND_ASSIGN(MediaStreamUIController); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_UI_CONTROLLER_H_ diff --git a/content/browser/renderer_host/media/media_stream_ui_proxy.cc b/content/browser/renderer_host/media/media_stream_ui_proxy.cc new file mode 100644 index 0000000..3e4edbc --- /dev/null +++ b/content/browser/renderer_host/media/media_stream_ui_proxy.cc @@ -0,0 +1,216 @@ +// Copyright 2013 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 file. + +#include "content/browser/renderer_host/media/media_stream_ui_proxy.h" + +#include "content/browser/renderer_host/render_view_host_delegate.h" +#include "content/browser/renderer_host/render_view_host_impl.h" +#include "content/public/browser/browser_thread.h" +#include "media/video/capture/fake_video_capture_device.h" + +namespace content { + +class MediaStreamUIProxy::Core { + public: + explicit Core(const base::WeakPtr<MediaStreamUIProxy>& proxy, + RenderViewHostDelegate* test_render_delegate); + ~Core(); + + void RequestAccess(const MediaStreamRequest& request); + void OnStarted(); + + private: + void ProcessAccessRequestResponse(const MediaStreamDevices& devices, + scoped_ptr<MediaStreamUI> stream_ui); + void ProcessStopRequestFromUI(); + + base::WeakPtr<MediaStreamUIProxy> proxy_; + scoped_ptr<MediaStreamUI> ui_; + + RenderViewHostDelegate* const test_render_delegate_; + + // WeakPtr<> is used to RequestMediaAccessPermission() because there is no way + // cancel media requests. + base::WeakPtrFactory<Core> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(Core); +}; + +MediaStreamUIProxy::Core::Core(const base::WeakPtr<MediaStreamUIProxy>& proxy, + RenderViewHostDelegate* test_render_delegate) + : proxy_(proxy), + test_render_delegate_(test_render_delegate), + weak_factory_(this) { +} + +MediaStreamUIProxy::Core::~Core() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +} + +void MediaStreamUIProxy::Core::RequestAccess( + const MediaStreamRequest& request) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + RenderViewHostDelegate* render_delegate; + + if (test_render_delegate_) { + render_delegate = test_render_delegate_; + } else { + RenderViewHostImpl* host = RenderViewHostImpl::FromID( + request.render_process_id, request.render_view_id); + + // Tab may have gone away. + if (!host || !host->GetDelegate()) { + ProcessAccessRequestResponse( + MediaStreamDevices(), scoped_ptr<MediaStreamUI>()); + return; + } + + render_delegate = host->GetDelegate(); + } + + render_delegate->RequestMediaAccessPermission( + request, base::Bind(&Core::ProcessAccessRequestResponse, + weak_factory_.GetWeakPtr())); +} + +void MediaStreamUIProxy::Core::OnStarted() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (ui_) { + ui_->OnStarted(base::Bind(&Core::ProcessStopRequestFromUI, + base::Unretained(this))); + } +} + +void MediaStreamUIProxy::Core::ProcessAccessRequestResponse( + const MediaStreamDevices& devices, + scoped_ptr<MediaStreamUI> stream_ui) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + ui_ = stream_ui.Pass(); + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse, + proxy_, devices)); +} + +void MediaStreamUIProxy::Core::ProcessStopRequestFromUI() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&MediaStreamUIProxy::ProcessStopRequestFromUI, proxy_)); +} + +// static +scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::Create() { + return scoped_ptr<MediaStreamUIProxy>(new MediaStreamUIProxy(NULL)); +} + +// static +scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::CreateForTests( + RenderViewHostDelegate* render_delegate) { + return scoped_ptr<MediaStreamUIProxy>( + new MediaStreamUIProxy(render_delegate)); +} + +MediaStreamUIProxy::MediaStreamUIProxy( + RenderViewHostDelegate* test_render_delegate) + : weak_factory_(this) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + core_.reset(new Core(weak_factory_.GetWeakPtr(), test_render_delegate)); +} + +MediaStreamUIProxy::~MediaStreamUIProxy() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, core_.release()); +} + +void MediaStreamUIProxy::RequestAccess( + const MediaStreamRequest& request, + const ResponseCallback& response_callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + response_callback_ = response_callback; + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&Core::RequestAccess, base::Unretained(core_.get()), request)); +} + +void MediaStreamUIProxy::OnStarted(const base::Closure& stop_callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + stop_callback_ = stop_callback; + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&Core::OnStarted, base::Unretained(core_.get()))); +} + +void MediaStreamUIProxy::ProcessAccessRequestResponse( + const MediaStreamDevices& devices) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK(!response_callback_.is_null()); + + ResponseCallback cb = response_callback_; + response_callback_.Reset(); + cb.Run(devices); +} + +void MediaStreamUIProxy::ProcessStopRequestFromUI() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK(!stop_callback_.is_null()); + + base::Closure cb = stop_callback_; + stop_callback_.Reset(); + cb.Run(); +} + +FakeMediaStreamUIProxy::FakeMediaStreamUIProxy() + : MediaStreamUIProxy(NULL) { +} + +FakeMediaStreamUIProxy::~FakeMediaStreamUIProxy() {} + +void FakeMediaStreamUIProxy::SetAvailableDevices( + const MediaStreamDevices& devices) { + devices_ = devices; +} + +void FakeMediaStreamUIProxy::RequestAccess( + const MediaStreamRequest& request, + const ResponseCallback& response_callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + response_callback_ = response_callback; + + MediaStreamDevices devices_to_use; + bool accepted_audio = false; + bool accepted_video = false; + // Use the first capture device of the same media type in the list for the + // fake UI. + for (MediaStreamDevices::const_iterator it = devices_.begin(); + it != devices_.end(); ++it) { + if (!accepted_audio && + IsAudioMediaType(request.audio_type) && + IsAudioMediaType(it->type)) { + devices_to_use.push_back(*it); + accepted_audio = true; + } else if (!accepted_video && + IsVideoMediaType(request.video_type) && + IsVideoMediaType(it->type)) { + devices_to_use.push_back(*it); + accepted_video = true; + } + } + + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse, + weak_factory_.GetWeakPtr(), devices_to_use)); +} + +void FakeMediaStreamUIProxy::OnStarted(const base::Closure& stop_callback) { +} + +} // namespace content diff --git a/content/browser/renderer_host/media/media_stream_ui_proxy.h b/content/browser/renderer_host/media/media_stream_ui_proxy.h new file mode 100644 index 0000000..62bbeb8 --- /dev/null +++ b/content/browser/renderer_host/media/media_stream_ui_proxy.h @@ -0,0 +1,88 @@ +// Copyright 2013 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 file. + +#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_UI_PROXY_H_ +#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_UI_PROXY_H_ + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "content/public/common/media_stream_request.h" + +namespace content { + +class RenderViewHostDelegate; + +// MediaStreamUIProxy proxies calls to media stream UI between IO thread and UI +// thread. One instance of this class is create per MediaStream object. It must +// be create, used and destroyed on IO thread. +class CONTENT_EXPORT MediaStreamUIProxy { + public: + typedef base::Callback< + void (const MediaStreamDevices& devices)> ResponseCallback; + + static scoped_ptr<MediaStreamUIProxy> Create(); + static scoped_ptr<MediaStreamUIProxy> CreateForTests( + RenderViewHostDelegate* render_delegate); + + virtual ~MediaStreamUIProxy(); + + // Requests access for the MediaStream by calling + // WebContentsDelegate::RequestMediaAccessPermission(). The specified + // |response_callback| is called when the WebContentsDelegate approves or + // denies request. + virtual void RequestAccess(const MediaStreamRequest& request, + const ResponseCallback& response_callback); + + // Notifies the UI that the MediaStream has been started. Must be called after + // access has been approved using RequestAccess(). |stop_callback| is be + // called on the IO thread after the user has requests the stream to be + // stopped. + virtual void OnStarted(const base::Closure& stop_callback); + + void SetRenderViewHostDelegateForTests(RenderViewHostDelegate* delegate); + + protected: + MediaStreamUIProxy(RenderViewHostDelegate* test_render_delegate); + + private: + class Core; + friend class Core; + friend class FakeMediaStreamUIProxy; + + void ProcessAccessRequestResponse(const MediaStreamDevices& devices); + void ProcessStopRequestFromUI(); + + scoped_ptr<Core> core_; + ResponseCallback response_callback_; + base::Closure stop_callback_; + + base::WeakPtrFactory<MediaStreamUIProxy> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(MediaStreamUIProxy); +}; + +class CONTENT_EXPORT FakeMediaStreamUIProxy : public MediaStreamUIProxy { + public: + explicit FakeMediaStreamUIProxy(); + virtual ~FakeMediaStreamUIProxy(); + + void SetAvailableDevices(const MediaStreamDevices& devices); + + // MediaStreamUIProxy overrides. + virtual void RequestAccess( + const MediaStreamRequest& request, + const ResponseCallback& response_callback) OVERRIDE; + virtual void OnStarted(const base::Closure& stop_callback) OVERRIDE; + + private: + MediaStreamDevices devices_; + + DISALLOW_COPY_AND_ASSIGN(FakeMediaStreamUIProxy); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_UI_PROXY_H_ diff --git a/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc b/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc new file mode 100644 index 0000000..1e9b815 --- /dev/null +++ b/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc @@ -0,0 +1,213 @@ +// Copyright 2013 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 file. + +#include "content/browser/renderer_host/media/media_stream_ui_proxy.h" + +#include "base/message_loop.h" +#include "content/browser/renderer_host/render_view_host_delegate.h" +#include "content/public/common/renderer_preferences.h" +#include "content/public/test/test_browser_thread.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/rect.h" + +using testing::_; +using testing::SaveArg; + +namespace content { +namespace { + +class MockRenderViewHostDelegate : public RenderViewHostDelegate { + public: + MOCK_METHOD2(RequestMediaAccessPermission, + void(const MediaStreamRequest& request, + const MediaResponseCallback& callback)); + + // Stubs for pure virtual methods we don't care about. + virtual gfx::Rect GetRootWindowResizerRect() const OVERRIDE { + NOTREACHED(); + return gfx::Rect(); + } + virtual RendererPreferences GetRendererPrefs( + BrowserContext* browser_context) const OVERRIDE { + NOTREACHED(); + return RendererPreferences(); + } +}; + +class MockResponseCallback { + public: + MOCK_METHOD1(OnAccessRequestResponse, + void(const MediaStreamDevices& devices)); +}; + +class MockMediaStreamUI : public MediaStreamUI { + public: + MOCK_METHOD1(OnStarted, void(const base::Closure& stop)); +}; + +class MockStopStreamHandler { + public: + MOCK_METHOD0(OnStop, void()); +}; + + +} // namespace + +class MediaStreamUIProxyTest : public testing::Test { + public: + MediaStreamUIProxyTest() + : ui_thread_(BrowserThread::UI, &message_loop_), + io_thread_(BrowserThread::IO, &message_loop_) { + proxy_ = MediaStreamUIProxy::CreateForTests(&delegate_); + } + + virtual ~MediaStreamUIProxyTest() { + proxy_.reset(); + message_loop_.RunUntilIdle(); + } + + protected: + base::MessageLoop message_loop_; + TestBrowserThread ui_thread_; + TestBrowserThread io_thread_; + + MockRenderViewHostDelegate delegate_; + MockResponseCallback response_callback_; + scoped_ptr<MediaStreamUIProxy> proxy_; +}; + +MATCHER_P(SameRequest, expected, "") { + return + expected.render_process_id == arg.render_process_id && + expected.render_view_id == arg.render_view_id && + expected.security_origin == arg.security_origin && + expected.request_type == arg.request_type && + expected.requested_device_id == arg.requested_device_id && + expected.audio_type == arg.audio_type && + expected.video_type == arg.video_type; +} + +TEST_F(MediaStreamUIProxyTest, Deny) { + MediaStreamRequest request(0, 0, GURL("http://origin/"), + MEDIA_GENERATE_STREAM, std::string(), + MEDIA_DEVICE_AUDIO_CAPTURE, + MEDIA_DEVICE_VIDEO_CAPTURE); + proxy_->RequestAccess( + request, base::Bind(&MockResponseCallback::OnAccessRequestResponse, + base::Unretained(&response_callback_))); + MediaResponseCallback callback; + EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request), _)) + .WillOnce(SaveArg<1>(&callback)); + message_loop_.RunUntilIdle(); + ASSERT_FALSE(callback.is_null()); + + MediaStreamDevices devices; + callback.Run(devices, scoped_ptr<MediaStreamUI>()); + + MediaStreamDevices response; + EXPECT_CALL(response_callback_, OnAccessRequestResponse(_)) + .WillOnce(SaveArg<0>(&response)); + message_loop_.RunUntilIdle(); + + EXPECT_TRUE(response.empty()); +} + +TEST_F(MediaStreamUIProxyTest, AcceptAndStart) { + MediaStreamRequest request(0, 0, GURL("http://origin/"), + MEDIA_GENERATE_STREAM, std::string(), + MEDIA_DEVICE_AUDIO_CAPTURE, + MEDIA_DEVICE_VIDEO_CAPTURE); + proxy_->RequestAccess( + request, base::Bind(&MockResponseCallback::OnAccessRequestResponse, + base::Unretained(&response_callback_))); + MediaResponseCallback callback; + EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request), _)) + .WillOnce(SaveArg<1>(&callback)); + message_loop_.RunUntilIdle(); + ASSERT_FALSE(callback.is_null()); + + MediaStreamDevices devices; + devices.push_back( + MediaStreamDevice(MEDIA_DEVICE_AUDIO_CAPTURE, "Mic", "Mic")); + scoped_ptr<MockMediaStreamUI> ui(new MockMediaStreamUI()); + EXPECT_CALL(*ui, OnStarted(_)); + callback.Run(devices, ui.PassAs<MediaStreamUI>()); + + MediaStreamDevices response; + EXPECT_CALL(response_callback_, OnAccessRequestResponse(_)) + .WillOnce(SaveArg<0>(&response)); + message_loop_.RunUntilIdle(); + + EXPECT_FALSE(response.empty()); + + proxy_->OnStarted(base::Closure()); + message_loop_.RunUntilIdle(); +} + +// Verify that the proxy can be deleted before the request is processed. +TEST_F(MediaStreamUIProxyTest, DeleteBeforeAccepted) { + MediaStreamRequest request(0, 0, GURL("http://origin/"), + MEDIA_GENERATE_STREAM, std::string(), + MEDIA_DEVICE_AUDIO_CAPTURE, + MEDIA_DEVICE_VIDEO_CAPTURE); + proxy_->RequestAccess( + request, base::Bind(&MockResponseCallback::OnAccessRequestResponse, + base::Unretained(&response_callback_))); + MediaResponseCallback callback; + EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request), _)) + .WillOnce(SaveArg<1>(&callback)); + message_loop_.RunUntilIdle(); + ASSERT_FALSE(callback.is_null()); + + proxy_.reset(); + + MediaStreamDevices devices; + scoped_ptr<MediaStreamUI> ui; + callback.Run(devices, ui.Pass()); +} + +TEST_F(MediaStreamUIProxyTest, StopFromUI) { + MediaStreamRequest request(0, 0, GURL("http://origin/"), + MEDIA_GENERATE_STREAM, std::string(), + MEDIA_DEVICE_AUDIO_CAPTURE, + MEDIA_DEVICE_VIDEO_CAPTURE); + proxy_->RequestAccess( + request, base::Bind(&MockResponseCallback::OnAccessRequestResponse, + base::Unretained(&response_callback_))); + MediaResponseCallback callback; + EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request), _)) + .WillOnce(SaveArg<1>(&callback)); + message_loop_.RunUntilIdle(); + ASSERT_FALSE(callback.is_null()); + + base::Closure stop_callback; + + MediaStreamDevices devices; + devices.push_back( + MediaStreamDevice(MEDIA_DEVICE_AUDIO_CAPTURE, "Mic", "Mic")); + scoped_ptr<MockMediaStreamUI> ui(new MockMediaStreamUI()); + EXPECT_CALL(*ui, OnStarted(_)) + .WillOnce(SaveArg<0>(&stop_callback)); + callback.Run(devices, ui.PassAs<MediaStreamUI>()); + + MediaStreamDevices response; + EXPECT_CALL(response_callback_, OnAccessRequestResponse(_)) + .WillOnce(SaveArg<0>(&response)); + message_loop_.RunUntilIdle(); + + EXPECT_FALSE(response.empty()); + + MockStopStreamHandler stop_handler; + proxy_->OnStarted(base::Bind(&MockStopStreamHandler::OnStop, + base::Unretained(&stop_handler))); + message_loop_.RunUntilIdle(); + + ASSERT_FALSE(stop_callback.is_null()); + EXPECT_CALL(stop_handler, OnStop()); + stop_callback.Run(); + message_loop_.RunUntilIdle(); +} + +} // content diff --git a/content/browser/speech/speech_recognition_manager_impl.cc b/content/browser/speech/speech_recognition_manager_impl.cc index c921ed2..33cf503 100644 --- a/content/browser/speech/speech_recognition_manager_impl.cc +++ b/content/browser/speech/speech_recognition_manager_impl.cc @@ -7,6 +7,7 @@ #include "base/bind.h" #include "content/browser/browser_main_loop.h" #include "content/browser/renderer_host/media/media_stream_manager.h" +#include "content/browser/renderer_host/media/media_stream_ui_proxy.h" #include "content/browser/speech/google_one_shot_remote_engine.h" #include "content/browser/speech/google_streaming_remote_engine.h" #include "content/browser/speech/speech_recognition_engine.h" @@ -68,7 +69,14 @@ SpeechRecognitionManagerImpl::SpeechRecognitionManagerImpl() SpeechRecognitionManagerImpl::~SpeechRecognitionManagerImpl() { DCHECK(g_speech_recognition_manager_impl); g_speech_recognition_manager_impl = NULL; - // Recognition sessions will be aborted by the corresponding destructors. + + for (SessionsTable::iterator it = sessions_.begin(); it != sessions_.end(); + ++it) { + // MediaStreamUIProxy must be deleted on the IO thread. + BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, + it->second->ui.release()); + delete it->second; + } sessions_.clear(); } @@ -79,10 +87,11 @@ int SpeechRecognitionManagerImpl::CreateSession( const int session_id = GetNextSessionID(); DCHECK(!SessionExists(session_id)); // Set-up the new session. - Session& session = sessions_[session_id]; - session.id = session_id; - session.config = config; - session.context = config.initial_context; + Session* session = new Session(); + sessions_[session_id] = session; + session->id = session_id; + session->config = config; + session->context = config.initial_context; std::string hardware_info; bool can_report_metrics = false; @@ -126,7 +135,7 @@ int SpeechRecognitionManagerImpl::CreateSession( google_remote_engine->SetConfig(remote_engine_config); - session.recognizer = new SpeechRecognizerImpl( + session->recognizer = new SpeechRecognizerImpl( this, session_id, !config.continuous, @@ -135,7 +144,7 @@ int SpeechRecognitionManagerImpl::CreateSession( // TODO(janx): Implement a SpeechRecognizerImplAndroid with a JNI interface // forwarding calls to Android's platform speech recognition service (see // crbug.com/222352). - session.recognizer = NULL; + session->recognizer = NULL; #endif return session_id; } @@ -177,7 +186,7 @@ void SpeechRecognitionManagerImpl::RecognitionAllowedCallback(int session_id, if (ask_user) { SessionsTable::iterator iter = sessions_.find(session_id); DCHECK(iter != sessions_.end()); - SpeechRecognitionSessionContext& context = iter->second.context; + SpeechRecognitionSessionContext& context = iter->second->context; context.label = BrowserMainLoop::GetMediaStreamManager()->MakeMediaAccessRequest( context.render_process_id, @@ -186,8 +195,7 @@ void SpeechRecognitionManagerImpl::RecognitionAllowedCallback(int session_id, GURL(context.context_name), base::Bind( &SpeechRecognitionManagerImpl::MediaRequestPermissionCallback, - weak_factory_.GetWeakPtr())); - + weak_factory_.GetWeakPtr(), session_id)); return; } #endif // defined(OS_IOS) @@ -212,26 +220,29 @@ void SpeechRecognitionManagerImpl::RecognitionAllowedCallback(int session_id, } void SpeechRecognitionManagerImpl::MediaRequestPermissionCallback( - const std::string& label, const MediaStreamDevices& devices) { + int session_id, + const MediaStreamDevices& devices, + scoped_ptr<MediaStreamUIProxy> stream_ui) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - for (SessionsTable::iterator iter = sessions_.begin(); - iter != sessions_.end(); ++iter) { - if (iter->second.context.label == label) { - bool is_allowed = false; - if (!devices.empty()) { - // Copy the approved devices array to the context for UI indication. - iter->second.context.devices = devices; - is_allowed = true; - } - // Clear the label to indicate the request has been done. - iter->second.context.label.clear(); + SessionsTable::iterator iter = sessions_.find(session_id); + if (iter == sessions_.end()) + return; - // Notify the recognition about the request result. - RecognitionAllowedCallback(iter->first, false, is_allowed); - break; - } + bool is_allowed = !devices.empty(); + if (is_allowed) { + // Copy the approved devices array to the context for UI indication. + iter->second->context.devices = devices; + + // Save the UI object. + iter->second->ui = stream_ui.Pass(); } + + // Clear the label to indicate the request has been done. + iter->second->context.label.clear(); + + // Notify the recognition about the request result. + RecognitionAllowedCallback(iter->first, false, is_allowed); } void SpeechRecognitionManagerImpl::AbortSession(int session_id) { @@ -239,12 +250,8 @@ void SpeechRecognitionManagerImpl::AbortSession(int session_id) { if (!SessionExists(session_id)) return; -#if !defined(OS_IOS) - const SpeechRecognitionSessionContext& context = - GetSessionContext(session_id); - if (!context.label.empty()) - BrowserMainLoop::GetMediaStreamManager()->CancelRequest(context.label); -#endif // !defined(OS_IOS) + SessionsTable::iterator iter = sessions_.find(session_id); + iter->second->ui.reset(); base::MessageLoop::current()->PostTask( FROM_HERE, @@ -259,12 +266,8 @@ void SpeechRecognitionManagerImpl::StopAudioCaptureForSession(int session_id) { if (!SessionExists(session_id)) return; -#if !defined(OS_IOS) - const SpeechRecognitionSessionContext& context = - GetSessionContext(session_id); - if (!context.label.empty()) - BrowserMainLoop::GetMediaStreamManager()->CancelRequest(context.label); -#endif // !defined(OS_IOS) + SessionsTable::iterator iter = sessions_.find(session_id); + iter->second->ui.reset(); base::MessageLoop::current()->PostTask( FROM_HERE, @@ -284,15 +287,11 @@ void SpeechRecognitionManagerImpl::OnRecognitionStart(int session_id) { if (!SessionExists(session_id)) return; -#if !defined(OS_IOS) - const SpeechRecognitionSessionContext& context = - GetSessionContext(session_id); - if (!context.devices.empty()) { - // Notify the UI the devices are being used. - BrowserMainLoop::GetMediaStreamManager()->NotifyUIDevicesOpened( - context.label); + SessionsTable::iterator iter = sessions_.find(session_id); + if (iter->second->ui) { + // Notify the UI that the devices are being used. + iter->second->ui->OnStarted(base::Closure()); } -#endif // !defined(OS_IOS) DCHECK_EQ(primary_session_id_, session_id); if (SpeechRecognitionEventListener* delegate_listener = GetDelegateListener()) @@ -406,15 +405,6 @@ void SpeechRecognitionManagerImpl::OnRecognitionEnd(int session_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); if (!SessionExists(session_id)) return; -#if !defined(OS_IOS) - const SpeechRecognitionSessionContext& context = - GetSessionContext(session_id); - if (!context.devices.empty()) { - // Notify the UI the devices has been closed. - BrowserMainLoop::GetMediaStreamManager()->NotifyUIDevicesClosed( - context.label); - } -#endif // !defined(OS_IOS) if (SpeechRecognitionEventListener* delegate_listener = GetDelegateListener()) delegate_listener->OnRecognitionEnd(session_id); @@ -434,7 +424,7 @@ int SpeechRecognitionManagerImpl::GetSession( SessionsTable::const_iterator iter; for(iter = sessions_.begin(); iter != sessions_.end(); ++iter) { const int session_id = iter->first; - const SpeechRecognitionSessionContext& context = iter->second.context; + const SpeechRecognitionSessionContext& context = iter->second->context; if (context.render_process_id == render_process_id && context.render_view_id == render_view_id && context.request_id == request_id) { @@ -446,7 +436,7 @@ int SpeechRecognitionManagerImpl::GetSession( SpeechRecognitionSessionContext SpeechRecognitionManagerImpl::GetSessionContext(int session_id) const { - return GetSession(session_id).context; + return GetSession(session_id)->context; } void SpeechRecognitionManagerImpl::AbortAllSessionsForListener( @@ -457,10 +447,10 @@ void SpeechRecognitionManagerImpl::AbortAllSessionsForListener( DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); for (SessionsTable::iterator it = sessions_.begin(); it != sessions_.end(); ++it) { - Session& session = it->second; - if (session.config.event_listener == listener) { - AbortSession(session.id); - session.listener_is_active = false; + Session* session = it->second; + if (session->config.event_listener == listener) { + AbortSession(session->id); + session->listener_is_active = false; } } } @@ -471,10 +461,10 @@ void SpeechRecognitionManagerImpl::AbortAllSessionsForRenderView( DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); for (SessionsTable::iterator it = sessions_.begin(); it != sessions_.end(); ++it) { - Session& session = it->second; - if (session.context.render_process_id == render_process_id && - session.context.render_view_id == render_view_id) { - AbortSession(session.id); + Session* session = it->second; + if (session->context.render_process_id == render_process_id && + session->context.render_view_id == render_view_id) { + AbortSession(session->id); } } } @@ -489,7 +479,7 @@ void SpeechRecognitionManagerImpl::DispatchEvent(int session_id, if (!SessionExists(session_id)) return; - const Session& session = GetSession(session_id); + Session* session = GetSession(session_id); FSMState session_state = GetSessionState(session_id); DCHECK_LE(session_state, SESSION_STATE_MAX_VALUE); DCHECK_LE(event, EVENT_MAX_VALUE); @@ -509,7 +499,7 @@ void SpeechRecognitionManagerImpl::DispatchEvent(int session_id, // session) are always routed to the SpeechRecognitionEventListener(s) // regardless the choices taken in this FSM. void SpeechRecognitionManagerImpl::ExecuteTransitionAndGetNextState( - const Session& session, FSMState session_state, FSMEvent event) { + Session* session, FSMState session_state, FSMEvent event) { // Note: since we're not tracking the state of the recognizer object, rather // we're directly retrieving it (through GetSessionState), we see its events // (that are AUDIO_ENDED and RECOGNITION_ENDED) after its state evolution @@ -522,13 +512,13 @@ void SpeechRecognitionManagerImpl::ExecuteTransitionAndGetNextState( case SESSION_STATE_IDLE: switch (event) { case EVENT_START: - return SessionStart(session); + return SessionStart(*session); case EVENT_ABORT: - return SessionAbort(session); + return SessionAbort(*session); case EVENT_RECOGNITION_ENDED: return SessionDelete(session); case EVENT_STOP_CAPTURE: - return SessionStopAudioCapture(session); + return SessionStopAudioCapture(*session); case EVENT_AUDIO_ENDED: return; } @@ -536,39 +526,39 @@ void SpeechRecognitionManagerImpl::ExecuteTransitionAndGetNextState( case SESSION_STATE_CAPTURING_AUDIO: switch (event) { case EVENT_STOP_CAPTURE: - return SessionStopAudioCapture(session); + return SessionStopAudioCapture(*session); case EVENT_ABORT: - return SessionAbort(session); + return SessionAbort(*session); case EVENT_START: return; case EVENT_AUDIO_ENDED: case EVENT_RECOGNITION_ENDED: - return NotFeasible(session, event); + return NotFeasible(*session, event); } break; case SESSION_STATE_WAITING_FOR_RESULT: switch (event) { case EVENT_ABORT: - return SessionAbort(session); + return SessionAbort(*session); case EVENT_AUDIO_ENDED: - return ResetCapturingSessionId(session); + return ResetCapturingSessionId(*session); case EVENT_START: case EVENT_STOP_CAPTURE: return; case EVENT_RECOGNITION_ENDED: - return NotFeasible(session, event); + return NotFeasible(*session, event); } break; } - return NotFeasible(session, event); + return NotFeasible(*session, event); } SpeechRecognitionManagerImpl::FSMState SpeechRecognitionManagerImpl::GetSessionState(int session_id) const { - const Session& session = GetSession(session_id); - if (!session.recognizer.get() || !session.recognizer->IsActive()) + Session* session = GetSession(session_id); + if (!session->recognizer.get() || !session->recognizer->IsActive()) return SESSION_STATE_IDLE; - if (session.recognizer->IsCapturingAudio()) + if (session->recognizer->IsCapturingAudio()) return SESSION_STATE_CAPTURING_AUDIO; return SESSION_STATE_WAITING_FOR_RESULT; } @@ -601,11 +591,12 @@ void SpeechRecognitionManagerImpl::ResetCapturingSessionId( primary_session_id_ = kSessionIDInvalid; } -void SpeechRecognitionManagerImpl::SessionDelete(const Session& session) { - DCHECK(session.recognizer.get() == NULL || !session.recognizer->IsActive()); - if (primary_session_id_ == session.id) +void SpeechRecognitionManagerImpl::SessionDelete(Session* session) { + DCHECK(session->recognizer == NULL || !session->recognizer->IsActive()); + if (primary_session_id_ == session->id) primary_session_id_ = kSessionIDInvalid; - sessions_.erase(session.id); + sessions_.erase(session->id); + delete session; } void SpeechRecognitionManagerImpl::NotFeasible(const Session& session, @@ -627,7 +618,7 @@ bool SpeechRecognitionManagerImpl::SessionExists(int session_id) const { return sessions_.find(session_id) != sessions_.end(); } -const SpeechRecognitionManagerImpl::Session& +SpeechRecognitionManagerImpl::Session* SpeechRecognitionManagerImpl::GetSession(int session_id) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); SessionsTable::const_iterator iter = sessions_.find(session_id); @@ -637,8 +628,8 @@ SpeechRecognitionManagerImpl::GetSession(int session_id) const { SpeechRecognitionEventListener* SpeechRecognitionManagerImpl::GetListener( int session_id) const { - const Session& session = GetSession(session_id); - return session.listener_is_active ? session.config.event_listener : NULL; + Session* session = GetSession(session_id); + return session->listener_is_active ? session->config.event_listener : NULL; } SpeechRecognitionEventListener* @@ -648,7 +639,7 @@ SpeechRecognitionManagerImpl::GetDelegateListener() const { const SpeechRecognitionSessionConfig& SpeechRecognitionManagerImpl::GetSessionConfig(int session_id) const { - return GetSession(session_id).config; + return GetSession(session_id)->config; } bool SpeechRecognitionManagerImpl::HasAudioInputDevices() { diff --git a/content/browser/speech/speech_recognition_manager_impl.h b/content/browser/speech/speech_recognition_manager_impl.h index e9ea5a0..d7cc3c1 100644 --- a/content/browser/speech/speech_recognition_manager_impl.h +++ b/content/browser/speech/speech_recognition_manager_impl.h @@ -21,6 +21,7 @@ namespace content { class BrowserMainLoop; +class MediaStreamUIProxy; class SpeechRecognitionManagerDelegate; class SpeechRecognizer; @@ -122,6 +123,7 @@ class CONTENT_EXPORT SpeechRecognitionManagerImpl : SpeechRecognitionSessionConfig config; SpeechRecognitionSessionContext context; scoped_refptr<SpeechRecognizer> recognizer; + scoped_ptr<MediaStreamUIProxy> ui; }; // Callback issued by the SpeechRecognitionManagerDelegate for reporting @@ -130,19 +132,21 @@ class CONTENT_EXPORT SpeechRecognitionManagerImpl : bool ask_user, bool is_allowed); - // Callback to get back the result of a media request. |label| is the string - // to identify the request; |devices| is an array of devices approved to be - // used for the request, |devices| is empty if the users deny the request. - void MediaRequestPermissionCallback(const std::string& label, - const MediaStreamDevices& devices); + // Callback to get back the result of a media request. |devices| is an array + // of devices approved to be used for the request, |devices| is empty if the + // users deny the request. + void MediaRequestPermissionCallback(int session_id, + const MediaStreamDevices& devices, + scoped_ptr<MediaStreamUIProxy> stream_ui); // Entry point for pushing any external event into the session handling FSM. void DispatchEvent(int session_id, FSMEvent event); // Defines the behavior of the session handling FSM, selecting the appropriate // transition according to the session, its current state and the event. - void ExecuteTransitionAndGetNextState( - const Session& session, FSMState session_state, FSMEvent event); + void ExecuteTransitionAndGetNextState(Session* session, + FSMState session_state, + FSMEvent event); // Retrieves the state of the session, enquiring directly the recognizer. FSMState GetSessionState(int session_id) const; @@ -152,16 +156,16 @@ class CONTENT_EXPORT SpeechRecognitionManagerImpl : void SessionAbort(const Session& session); void SessionStopAudioCapture(const Session& session); void ResetCapturingSessionId(const Session& session); - void SessionDelete(const Session& session); + void SessionDelete(Session* session); void NotFeasible(const Session& session, FSMEvent event); bool SessionExists(int session_id) const; - const Session& GetSession(int session_id) const; + Session* GetSession(int session_id) const; SpeechRecognitionEventListener* GetListener(int session_id) const; SpeechRecognitionEventListener* GetDelegateListener() const; int GetNextSessionID(); - typedef std::map<int, Session> SessionsTable; + typedef std::map<int, Session*> SessionsTable; SessionsTable sessions_; int primary_session_id_; int last_session_id_; diff --git a/content/common/media/media_stream_options.h b/content/common/media/media_stream_options.h index 2868829..18f0379 100644 --- a/content/common/media/media_stream_options.h +++ b/content/common/media/media_stream_options.h @@ -8,7 +8,6 @@ #include <string> #include <vector> -#include "base/callback.h" #include "content/common/content_export.h" #include "content/public/common/media_stream_request.h" @@ -20,11 +19,6 @@ CONTENT_EXPORT extern const char kMediaStreamSourceId[]; CONTENT_EXPORT extern const char kMediaStreamSourceTab[]; CONTENT_EXPORT extern const char kMediaStreamSourceScreen[]; -// Callback to deliver the result of a media request. |label| is the string -// to identify the request, -typedef base::Callback< void(const std::string&, const MediaStreamDevices&) > - MediaRequestResponseCallback; - // StreamOptions is a Chromium representation of WebKit's // WebUserMediaRequest Options. It describes the components // in a request for a new media stream. diff --git a/content/content_browser.gypi b/content/content_browser.gypi index d1fca3b..192f97b 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -783,9 +783,8 @@ 'browser/renderer_host/media/media_stream_manager.h', 'browser/renderer_host/media/media_stream_provider.h', 'browser/renderer_host/media/media_stream_requester.h', - 'browser/renderer_host/media/media_stream_settings_requester.h', - 'browser/renderer_host/media/media_stream_ui_controller.cc', - 'browser/renderer_host/media/media_stream_ui_controller.h', + 'browser/renderer_host/media/media_stream_ui_proxy.cc', + 'browser/renderer_host/media/media_stream_ui_proxy.h', 'browser/renderer_host/media/video_capture_buffer_pool.cc', 'browser/renderer_host/media/video_capture_buffer_pool.h', 'browser/renderer_host/media/video_capture_controller.cc', diff --git a/content/content_tests.gypi b/content/content_tests.gypi index afb8716..01ab60c 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -319,7 +319,7 @@ 'browser/renderer_host/media/audio_renderer_host_unittest.cc', 'browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc', 'browser/renderer_host/media/media_stream_manager_unittest.cc', - 'browser/renderer_host/media/media_stream_ui_controller_unittest.cc', + 'browser/renderer_host/media/media_stream_ui_proxy_unittest.cc', 'browser/renderer_host/media/video_capture_buffer_pool_unittest.cc', 'browser/renderer_host/media/video_capture_controller_unittest.cc', 'browser/renderer_host/media/video_capture_host_unittest.cc', |