diff options
author | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-30 03:08:40 +0000 |
---|---|---|
committer | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-30 03:08:40 +0000 |
commit | ac3d8f48f8342442de6423f0bc48a069fb0e892c (patch) | |
tree | d6386212995c94e591d897f8a1d1a2d04150929a /content | |
parent | d5a4c9efa5f476c7b103992acdf22770ca19a57c (diff) | |
download | chromium_src-ac3d8f48f8342442de6423f0bc48a069fb0e892c.zip chromium_src-ac3d8f48f8342442de6423f0bc48a069fb0e892c.tar.gz chromium_src-ac3d8f48f8342442de6423f0bc48a069fb0e892c.tar.bz2 |
Revert 197222 "Replace MediaStreamUIController with MediaStreamU..."
> Replace MediaStreamUIController with MediaStreamUIProxy.
>
> Previously a single object MediaStreamUIController was used to control UI for
> all streams. Replaced it with a per-stream MediaStreamUIProxy that simplifies
> code in many places.
> Also moved media request queueing logic from content layer to chrome. Now
> different types of requests may be queued differently (e.g. there is no
> reason to block screen capture requests on webcam infobar).
>
> TBR=tommi@chromium.org
>
> Review URL: https://codereview.chromium.org/13989003
TBR=sergeyu@chromium.org
Review URL: https://codereview.chromium.org/14599002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@197242 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
14 files changed, 825 insertions, 497 deletions
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 8557f57..abd600b 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,7 +9,6 @@ #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" @@ -126,7 +125,7 @@ class MockMediaStreamDispatcherHost : public MediaStreamDispatcherHost, MediaStreamManager* manager_; }; -class MockMediaStreamUIProxy : public FakeMediaStreamUIProxy { +class MockMediaStreamUI : public MediaStreamUI { public: MOCK_METHOD1(OnStarted, void(const base::Closure& stop)); }; @@ -165,11 +164,11 @@ class MediaStreamDispatcherHostTest : public testing::Test { } virtual void SetupFakeUI(bool expect_started) { - scoped_ptr<MockMediaStreamUIProxy> stream_ui(new MockMediaStreamUIProxy()); + scoped_ptr<MockMediaStreamUI> stream_ui(new MockMediaStreamUI()); if (expect_started) { EXPECT_CALL(*stream_ui, OnStarted(_)); } - media_stream_manager_->UseFakeUI(stream_ui.PassAs<MediaStreamUIProxy>()); + media_stream_manager_->UseFakeUI(stream_ui.PassAs<MediaStreamUI>()); } virtual void TearDown() OVERRIDE { @@ -334,10 +333,10 @@ TEST_F(MediaStreamDispatcherHostTest, CloseFromUI) { StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE); base::Closure close_callback; - scoped_ptr<MockMediaStreamUIProxy> stream_ui(new MockMediaStreamUIProxy()); + scoped_ptr<MockMediaStreamUI> stream_ui(new MockMediaStreamUI()); EXPECT_CALL(*stream_ui, OnStarted(_)) .WillOnce(SaveArg<0>(&close_callback)); - media_stream_manager_->UseFakeUI(stream_ui.PassAs<MediaStreamUIProxy>()); + media_stream_manager_->UseFakeUI(stream_ui.PassAs<MediaStreamUI>()); EXPECT_CALL(*host_, OnStreamGenerated(kRenderId, kPageRequestId, 0, 1)); EXPECT_CALL(*host_, OnStreamGenerationFailed(kRenderId, kPageRequestId)); diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc index 4be7d31..1d63262 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_proxy.h" +#include "content/browser/renderer_host/media/media_stream_ui_controller.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,19 +54,37 @@ static std::string RandomLabel() { } // Helper to verify if a media stream type is part of options or not. -static bool Requested(const MediaStreamRequest& request, +static bool Requested(const StreamOptions& options, MediaStreamType stream_type) { - return (request.audio_type == stream_type || - request.video_type == stream_type); + return (options.audio_type == stream_type || + options.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 MediaStreamRequest& request) + 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) : requester(requester), - request(request), + 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), state_(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_NOT_REQUESTED) { } @@ -76,8 +94,8 @@ class MediaStreamManager::DeviceRequest { void SetState(MediaStreamType stream_type, MediaRequestState new_state) { state_[stream_type] = new_state; - if (request.video_type != MEDIA_TAB_VIDEO_CAPTURE && - request.audio_type != MEDIA_TAB_AUDIO_CAPTURE) { + if (options.video_type != MEDIA_TAB_VIDEO_CAPTURE && + options.audio_type != MEDIA_TAB_AUDIO_CAPTURE) { return; } @@ -91,11 +109,12 @@ class MediaStreamManager::DeviceRequest { // used internally within the content module. std::string device_id = WebContentsCaptureUtil::StripWebContentsDeviceScheme( - request.requested_device_id); + requested_device_id); media_observer->OnMediaRequestStateChanged( - request.render_process_id, request.render_view_id, - MediaStreamDevice(stream_type, device_id, device_id), new_state); + render_process_id, render_view_id, + MediaStreamDevice( + stream_type, device_id, device_id), new_state); } MediaRequestState state(MediaStreamType stream_type) const { @@ -103,16 +122,18 @@ class MediaStreamManager::DeviceRequest { } MediaStreamRequester* const requester; // Can be NULL. - MediaStreamRequest request; - + 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; 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. - MediaStreamManager::MediaRequestResponseCallback callback; - - scoped_ptr<MediaStreamUIProxy> ui_proxy; + MediaRequestResponseCallback callback; private: std::vector<MediaRequestState> state_; @@ -126,11 +147,11 @@ MediaStreamManager::EnumerationCache::~EnumerationCache() { } MediaStreamManager::MediaStreamManager(media::AudioManager* audio_manager) - : audio_manager_(audio_manager), + : ui_controller_(new MediaStreamUIController(this)), + audio_manager_(audio_manager), monitoring_started_(false), io_loop_(NULL), - screen_capture_active_(false), - use_fake_ui_(false) { + screen_capture_active_(false) { DCHECK(audio_manager_); memset(active_enumeration_ref_count_, 0, sizeof(active_enumeration_ref_count_)); @@ -173,11 +194,13 @@ std::string MediaStreamManager::MakeMediaAccessRequest( const MediaRequestResponseCallback& callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); // Create a new request based on options. - 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); + DeviceRequest* request = new DeviceRequest(NULL, + options, + MEDIA_DEVICE_ACCESS, + render_process_id, + render_view_id, + security_origin, + std::string()); const std::string& label = AddRequest(request); request->callback = callback; @@ -244,11 +267,13 @@ std::string MediaStreamManager::GenerateStream( } // Create a new request based on options. - 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); + DeviceRequest* request = new DeviceRequest(requester, + options, + MEDIA_GENERATE_STREAM, + target_render_process_id, + target_render_view_id, + security_origin, + requested_device_id); const std::string& label = AddRequest(request); HandleRequest(label); return label; @@ -259,6 +284,9 @@ 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? @@ -292,7 +320,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->request.request_type == MEDIA_ENUMERATE_DEVICES) { + if (it->second->type == MEDIA_ENUMERATE_DEVICES) { StopEnumerateDevices(label); return; } @@ -304,7 +332,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->request.request_type == MEDIA_GENERATE_STREAM && + if (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) { @@ -314,7 +342,12 @@ 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); } } @@ -351,11 +384,13 @@ std::string MediaStreamManager::EnumerateDevices( return 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); + DeviceRequest* request = new DeviceRequest(requester, + options, + MEDIA_ENUMERATE_DEVICES, + render_process_id, + render_view_id, + security_origin, + std::string()); const std::string& label = AddRequest(request); if (cache->valid) { @@ -380,7 +415,7 @@ void MediaStreamManager::StopEnumerateDevices(const std::string& label) { DeviceRequests::iterator it = requests_.find(label); if (it != requests_.end()) { - DCHECK_EQ(it->second->request.request_type, MEDIA_ENUMERATE_DEVICES); + DCHECK_EQ(it->second->type, MEDIA_ENUMERATE_DEVICES); // Delete the DeviceRequest. scoped_ptr<DeviceRequest> request(it->second); RemoveRequest(it); @@ -409,17 +444,29 @@ std::string MediaStreamManager::OpenDevice( return std::string(); } - 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); + DeviceRequest* request = new DeviceRequest(requester, + options, + MEDIA_OPEN_DEVICE, + render_process_id, + render_view_id, + security_origin, + device_id); 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) { @@ -476,7 +523,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->request, stream_type)) { + if (Requested(request->options, 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) { @@ -502,38 +549,35 @@ std::string MediaStreamManager::AddRequest(DeviceRequest* request) { } void MediaStreamManager::RemoveRequest(DeviceRequests::iterator it) { - if (it->second->request.video_type == MEDIA_SCREEN_VIDEO_CAPTURE) { + if (it->second->options.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]; - - if (use_fake_ui_) { - if (!fake_ui_) - fake_ui_.reset(new FakeMediaStreamUIProxy()); - request->ui_proxy = fake_ui_.Pass(); - } else { - request->ui_proxy.reset(new MediaStreamUIProxy()); - } - - request->ui_proxy->RequestAccess( - request->request, - base::Bind(&MediaStreamManager::HandleAccessRequestResponse, - base::Unretained(this), 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); } void MediaStreamManager::HandleRequest(const std::string& label) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DeviceRequest* request = requests_[label]; - const MediaStreamType audio_type = request->request.audio_type; - const MediaStreamType video_type = request->request.video_type; + const MediaStreamType audio_type = request->options.audio_type; + const MediaStreamType video_type = request->options.video_type; bool is_web_contents_capture = audio_type == MEDIA_TAB_AUDIO_CAPTURE || @@ -635,7 +679,7 @@ void MediaStreamManager::Opened(MediaStreamType stream_type, return; } - switch (request->request.request_type) { + switch (request->type) { case MEDIA_OPEN_DEVICE: request->requester->DeviceOpened(label, devices->front()); break; @@ -665,9 +709,7 @@ void MediaStreamManager::Opened(MediaStreamType stream_type, } request->requester->StreamGenerated(label, audio_devices, video_devices); - request->ui_proxy->OnStarted( - base::Bind(&MediaStreamManager::StopStreamFromUI, - base::Unretained(this), label)); + NotifyUIDevicesOpened(label); break; } default: @@ -709,9 +751,10 @@ 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->request, stream_type)) { - if (it->second->request.request_type != MEDIA_ENUMERATE_DEVICES) + if (it->second->state(stream_type) == + MEDIA_REQUEST_STATE_REQUESTED && + Requested(it->second->options, stream_type)) { + if (it->second->type != MEDIA_ENUMERATE_DEVICES) it->second->SetState(stream_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL); label_list.push_back(it->first); } @@ -719,15 +762,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->request.request_type) { + switch (request->type) { case MEDIA_ENUMERATE_DEVICES: if (need_update_clients && request->requester) request->requester->DevicesEnumerated(*it, devices); break; default: - if (request->state(request->request.audio_type) == + if (request->state(request->options.audio_type) == MEDIA_REQUEST_STATE_REQUESTED || - request->state(request->request.video_type) == + request->state(request->options.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 @@ -799,37 +842,28 @@ void MediaStreamManager::Error(MediaStreamType stream_type, } } -void MediaStreamManager::HandleAccessRequestResponse( - const std::string& label, - const MediaStreamDevices& devices) { +void MediaStreamManager::DevicesAccepted(const std::string& label, + const StreamDeviceInfoArray& devices) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - + DCHECK(!devices.empty()); DeviceRequests::iterator request_it = requests_.find(label); if (request_it == requests_.end()) { return; } - // Handle the case when the request was denied. - if (devices.empty()) { - // Notify the users about the request result. + if (request_it->second->type == MEDIA_DEVICE_ACCESS) { scoped_ptr<DeviceRequest> request(request_it->second); - if (request->requester) - request->requester->StreamGenerationFailed(label); + 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->request.request_type == MEDIA_DEVICE_ACCESS && - !request->callback.is_null()) { - request->callback.Run(MediaStreamDevices(), request->ui_proxy.Pass()); + request->callback.Run(label, selected_devices); } - 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; @@ -837,18 +871,16 @@ void MediaStreamManager::HandleAccessRequestResponse( // Process all newly-accepted devices for this request. DeviceRequest* request = request_it->second; - bool found_audio = false; - bool found_video = false; - for (MediaStreamDevices::const_iterator device_it = devices.begin(); + bool found_audio = false, found_video = false; + for (StreamDeviceInfoArray::const_iterator device_it = devices.begin(); device_it != devices.end(); ++device_it) { - StreamDeviceInfo device_info; - device_info.device = *device_it; + StreamDeviceInfo device_info = *device_it; // Make a copy. // 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->request.requested_device_id; + device_info.device.id = 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 @@ -870,26 +902,48 @@ void MediaStreamManager::HandleAccessRequestResponse( // 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_info.device.type, MEDIA_REQUEST_STATE_OPENING); + request->SetState(device_it->device.type, MEDIA_REQUEST_STATE_OPENING); request->devices.push_back(device_info); - if (device_info.device.type == request->request.audio_type) { + if (device_info.device.type == request->options.audio_type) { found_audio = true; - } else if (device_info.device.type == request->request.video_type) { + } else if (device_info.device.type == request->options.video_type) { found_video = true; } } // Check whether we've received all stream types requested. - if (!found_audio && IsAudioMediaType(request->request.audio_type)) - request->SetState(request->request.audio_type, MEDIA_REQUEST_STATE_ERROR); + 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 (!found_video && IsVideoMediaType(request->request.video_type)) - request->SetState(request->request.video_type, MEDIA_REQUEST_STATE_ERROR); + if (request->type == MEDIA_DEVICE_ACCESS && + !request->callback.is_null()) { + request->callback.Run(label, MediaStreamDevices()); + } + + RemoveRequest(it); } void MediaStreamManager::StopStreamFromUI(const std::string& label) { @@ -906,17 +960,38 @@ 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<MediaStreamUIProxy>()); + UseFakeUI(scoped_ptr<MediaStreamUI>()); } -void MediaStreamManager::UseFakeUI(scoped_ptr<MediaStreamUIProxy> fake_ui) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - use_fake_ui_ = true; - fake_ui_ = fake_ui.Pass(); +void MediaStreamManager::UseFakeUI(scoped_ptr<MediaStreamUI> fake_ui) { + ui_controller_->UseFakeUI(fake_ui.Pass()); } void MediaStreamManager::WillDestroyCurrentMessageLoop() { @@ -933,6 +1008,7 @@ void MediaStreamManager::WillDestroyCurrentMessageLoop() { audio_input_device_manager_ = NULL; video_capture_manager_ = NULL; io_loop_ = NULL; + ui_controller_.reset(); } void MediaStreamManager::NotifyDevicesChanged( @@ -963,23 +1039,23 @@ void MediaStreamManager::NotifyDevicesChanged( bool MediaStreamManager::RequestDone(const DeviceRequest& request) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - const bool requested_audio = IsAudioMediaType(request.request.audio_type); - const bool requested_video = IsVideoMediaType(request.request.video_type); + const bool requested_audio = IsAudioMediaType(request.options.audio_type); + const bool requested_video = IsVideoMediaType(request.options.video_type); const bool audio_done = !requested_audio || - request.state(request.request.audio_type) == + request.state(request.options.audio_type) == MEDIA_REQUEST_STATE_DONE || - request.state(request.request.audio_type) == + request.state(request.options.audio_type) == MEDIA_REQUEST_STATE_ERROR; if (!audio_done) return false; const bool video_done = !requested_video || - request.state(request.request.video_type) == + request.state(request.options.video_type) == MEDIA_REQUEST_STATE_DONE || - request.state(request.request.video_type) == + request.state(request.options.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 3db08c4..acde644d 100644 --- a/content/browser/renderer_host/media/media_stream_manager.h +++ b/content/browser/renderer_host/media/media_stream_manager.h @@ -32,6 +32,7 @@ #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" @@ -48,7 +49,7 @@ namespace content { class AudioInputDeviceManager; class MediaStreamDeviceSettings; class MediaStreamRequester; -class MediaStreamUIProxy; +class MediaStreamUIController; class VideoCaptureManager; // MediaStreamManager is used to generate and close new media devices, not to @@ -58,14 +59,9 @@ 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(); @@ -126,6 +122,14 @@ 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; @@ -137,6 +141,13 @@ 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; @@ -147,7 +158,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<MediaStreamUIProxy> fake_ui); + void UseFakeUI(scoped_ptr<MediaStreamUI> 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 @@ -178,11 +189,6 @@ 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); @@ -204,9 +210,15 @@ 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_; @@ -232,9 +244,6 @@ class CONTENT_EXPORT MediaStreamManager bool screen_capture_active_; - bool use_fake_ui_; - scoped_ptr<MediaStreamUIProxy> 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 b800d75..a515a36 100644 --- a/content/browser/renderer_host/media/media_stream_manager_unittest.cc +++ b/content/browser/renderer_host/media/media_stream_manager_unittest.cc @@ -8,7 +8,6 @@ #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) @@ -64,11 +63,10 @@ class MediaStreamManagerTest : public ::testing::Test { public: MediaStreamManagerTest() {} - MOCK_METHOD1(Response, void(int index)); - void ResponseCallback(int index, - const MediaStreamDevices& devices, - scoped_ptr<MediaStreamUIProxy> ui_proxy) { - Response(index); + MOCK_METHOD1(Response, void(const std::string&)); + void ResponseCallback(const std::string& label, + const MediaStreamDevices& devices) { + Response(label); message_loop_->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); } @@ -97,15 +95,15 @@ class MediaStreamManagerTest : public ::testing::Test { message_loop_.reset(); } - std::string MakeMediaAccessRequest(int index) { + std::string MakeMediaAccessRequest() { 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; - MediaStreamManager::MediaRequestResponseCallback callback = + MediaRequestResponseCallback callback = base::Bind(&MediaStreamManagerTest::ResponseCallback, - base::Unretained(this), index); + base::Unretained(this)); return media_stream_manager_->MakeMediaAccessRequest(render_process_id, render_view_id, components, @@ -124,22 +122,22 @@ class MediaStreamManagerTest : public ::testing::Test { }; TEST_F(MediaStreamManagerTest, MakeMediaAccessRequest) { - MakeMediaAccessRequest(0); + std::string label = MakeMediaAccessRequest(); // Expecting the callback will be triggered and quit the test. - EXPECT_CALL(*this, Response(0)); + EXPECT_CALL(*this, Response(label)); WaitForResult(); } TEST_F(MediaStreamManagerTest, MakeAndCancelMediaAccessRequest) { - std::string label = MakeMediaAccessRequest(0); + std::string label = MakeMediaAccessRequest(); // No callback is expected. media_stream_manager_->CancelRequest(label); } TEST_F(MediaStreamManagerTest, MakeMultipleRequests) { // First request. - std::string label1 = MakeMediaAccessRequest(0); + std::string label1 = MakeMediaAccessRequest(); // Second request. int render_process_id = 2; @@ -147,9 +145,9 @@ TEST_F(MediaStreamManagerTest, MakeMultipleRequests) { StreamOptions components(MEDIA_DEVICE_AUDIO_CAPTURE, MEDIA_DEVICE_VIDEO_CAPTURE); GURL security_origin; - MediaStreamManager::MediaRequestResponseCallback callback = + MediaRequestResponseCallback callback = base::Bind(&MediaStreamManagerTest::ResponseCallback, - base::Unretained(this), 1); + base::Unretained(this)); std::string label2 = media_stream_manager_->MakeMediaAccessRequest( render_process_id, render_view_id, @@ -160,19 +158,18 @@ 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(0)); - EXPECT_CALL(*this, Response(1)); + EXPECT_CALL(*this, Response(_)).Times(2); WaitForResult(); } TEST_F(MediaStreamManagerTest, MakeAndCancelMultipleRequests) { - std::string label1 = MakeMediaAccessRequest(0); - std::string label2 = MakeMediaAccessRequest(1); + std::string label1 = MakeMediaAccessRequest(); + std::string label2 = MakeMediaAccessRequest(); media_stream_manager_->CancelRequest(label1); // Expecting the callback from the second request will be triggered and // quit the test. - EXPECT_CALL(*this, Response(1)); + EXPECT_CALL(*this, Response(label2)); 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 new file mode 100644 index 0000000..9aa4f31 --- /dev/null +++ b/content/browser/renderer_host/media/media_stream_settings_requester.h @@ -0,0 +1,39 @@ +// 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 new file mode 100644 index 0000000..115bfd6 --- /dev/null +++ b/content/browser/renderer_host/media/media_stream_ui_controller.cc @@ -0,0 +1,336 @@ +// 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 new file mode 100644 index 0000000..6d14e83 --- /dev/null +++ b/content/browser/renderer_host/media/media_stream_ui_controller.h @@ -0,0 +1,106 @@ +// 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 deleted file mode 100644 index d8395ec..0000000 --- a/content/browser/renderer_host/media/media_stream_ui_proxy.cc +++ /dev/null @@ -1,174 +0,0 @@ -// 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); - ~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_; - - DISALLOW_COPY_AND_ASSIGN(Core); -}; - -MediaStreamUIProxy::Core::Core(const base::WeakPtr<MediaStreamUIProxy>& proxy) - : proxy_(proxy) { -} - -MediaStreamUIProxy::Core::~Core() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); -} - -void MediaStreamUIProxy::Core::RequestAccess( - const MediaStreamRequest& request) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - 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; - } - - host->GetDelegate()->RequestMediaAccessPermission( - request, base::Bind(&Core::ProcessAccessRequestResponse, - base::Unretained(this))); -} - -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_)); -} - -MediaStreamUIProxy::MediaStreamUIProxy() - : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - core_.reset(new Core(weak_factory_.GetWeakPtr())); -} - -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() {} -FakeMediaStreamUIProxy::~FakeMediaStreamUIProxy() {} - -void FakeMediaStreamUIProxy::RequestAccess( - const MediaStreamRequest& request, - const ResponseCallback& response_callback) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - - MediaStreamDevices devices; - - if (IsAudioMediaType(request.audio_type)) { - devices.push_back(MediaStreamDevice(request.audio_type, "Mic", "Mic")); - } - - if (IsVideoMediaType(request.video_type)) { - media::VideoCaptureDevice::Names device_names; - media::FakeVideoCaptureDevice::GetDeviceNames(&device_names); - if (!device_names.empty()) { - devices.push_back(MediaStreamDevice( - request.video_type, - device_names.front().unique_id, - device_names.front().device_name)); - } - } - - response_callback_ = response_callback; - - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse, - weak_factory_.GetWeakPtr(), devices)); -} - -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 deleted file mode 100644 index b0e30c5..0000000 --- a/content/browser/renderer_host/media/media_stream_ui_proxy.h +++ /dev/null @@ -1,73 +0,0 @@ -// 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 { - -// 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; - - MediaStreamUIProxy(); - 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); - - 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(); - - virtual void RequestAccess( - const MediaStreamRequest& request, - const ResponseCallback& response_callback) OVERRIDE; - virtual void OnStarted(const base::Closure& stop_callback) OVERRIDE; - - private: - DISALLOW_COPY_AND_ASSIGN(FakeMediaStreamUIProxy); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_UI_PROXY_H_ diff --git a/content/browser/speech/speech_recognition_manager_impl.cc b/content/browser/speech/speech_recognition_manager_impl.cc index e246535..d8faf9d 100644 --- a/content/browser/speech/speech_recognition_manager_impl.cc +++ b/content/browser/speech/speech_recognition_manager_impl.cc @@ -7,7 +7,6 @@ #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" @@ -69,14 +68,7 @@ SpeechRecognitionManagerImpl::SpeechRecognitionManagerImpl() SpeechRecognitionManagerImpl::~SpeechRecognitionManagerImpl() { DCHECK(g_speech_recognition_manager_impl); g_speech_recognition_manager_impl = NULL; - - 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; - } + // Recognition sessions will be aborted by the corresponding destructors. sessions_.clear(); } @@ -87,11 +79,10 @@ int SpeechRecognitionManagerImpl::CreateSession( const int session_id = GetNextSessionID(); DCHECK(!SessionExists(session_id)); // Set-up the new session. - Session* session = new Session(); - sessions_[session_id] = session; - session->id = session_id; - session->config = config; - session->context = config.initial_context; + Session& session = sessions_[session_id]; + session.id = session_id; + session.config = config; + session.context = config.initial_context; std::string hardware_info; bool can_report_metrics = false; @@ -126,7 +117,7 @@ int SpeechRecognitionManagerImpl::CreateSession( // The legacy api cannot use continuous mode. DCHECK(!config.is_legacy_api || !config.continuous); - session->recognizer = new SpeechRecognizer( + session.recognizer = new SpeechRecognizer( this, session_id, !config.continuous, @@ -171,7 +162,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, @@ -180,7 +171,8 @@ void SpeechRecognitionManagerImpl::RecognitionAllowedCallback(int session_id, GURL(context.context_name), base::Bind( &SpeechRecognitionManagerImpl::MediaRequestPermissionCallback, - weak_factory_.GetWeakPtr(), session_id)); + weak_factory_.GetWeakPtr())); + return; } #endif // defined(OS_IOS) @@ -199,29 +191,26 @@ void SpeechRecognitionManagerImpl::RecognitionAllowedCallback(int session_id, } void SpeechRecognitionManagerImpl::MediaRequestPermissionCallback( - int session_id, - const MediaStreamDevices& devices, - scoped_ptr<MediaStreamUIProxy> stream_ui) { + const std::string& label, const MediaStreamDevices& devices) { 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; + } - SessionsTable::iterator iter = sessions_.find(session_id); - if (iter == sessions_.end()) - return; + // Clear the label to indicate the request has been done. + iter->second.context.label.clear(); - 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(); + // Notify the recognition about the request result. + RecognitionAllowedCallback(iter->first, false, is_allowed); + break; + } } - - // 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) { @@ -229,8 +218,12 @@ void SpeechRecognitionManagerImpl::AbortSession(int session_id) { if (!SessionExists(session_id)) return; - SessionsTable::iterator iter = sessions_.find(session_id); - iter->second->ui.reset(); +#if !defined(OS_IOS) + const SpeechRecognitionSessionContext& context = + GetSessionContext(session_id); + if (!context.label.empty()) + BrowserMainLoop::GetMediaStreamManager()->CancelRequest(context.label); +#endif // !defined(OS_IOS) MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&SpeechRecognitionManagerImpl::DispatchEvent, @@ -242,8 +235,12 @@ void SpeechRecognitionManagerImpl::StopAudioCaptureForSession(int session_id) { if (!SessionExists(session_id)) return; - SessionsTable::iterator iter = sessions_.find(session_id); - iter->second->ui.reset(); +#if !defined(OS_IOS) + const SpeechRecognitionSessionContext& context = + GetSessionContext(session_id); + if (!context.label.empty()) + BrowserMainLoop::GetMediaStreamManager()->CancelRequest(context.label); +#endif // !defined(OS_IOS) MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&SpeechRecognitionManagerImpl::DispatchEvent, @@ -260,11 +257,15 @@ void SpeechRecognitionManagerImpl::OnRecognitionStart(int session_id) { if (!SessionExists(session_id)) return; - 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()); +#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); } +#endif // !defined(OS_IOS) DCHECK_EQ(primary_session_id_, session_id); if (SpeechRecognitionEventListener* delegate_listener = GetDelegateListener()) @@ -375,6 +376,15 @@ 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); @@ -393,7 +403,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) { @@ -405,7 +415,7 @@ int SpeechRecognitionManagerImpl::GetSession( SpeechRecognitionSessionContext SpeechRecognitionManagerImpl::GetSessionContext(int session_id) const { - return GetSession(session_id)->context; + return GetSession(session_id).context; } void SpeechRecognitionManagerImpl::AbortAllSessionsForListener( @@ -416,10 +426,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; } } } @@ -430,10 +440,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); } } } @@ -448,7 +458,7 @@ void SpeechRecognitionManagerImpl::DispatchEvent(int session_id, if (!SessionExists(session_id)) return; - Session* session = GetSession(session_id); + const 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); @@ -468,7 +478,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( - Session* session, FSMState session_state, FSMEvent event) { + const 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 @@ -481,13 +491,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; } @@ -495,39 +505,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 { - Session* session = GetSession(session_id); - if (!session->recognizer.get() || !session->recognizer->IsActive()) + const 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; } @@ -560,12 +570,11 @@ void SpeechRecognitionManagerImpl::ResetCapturingSessionId( primary_session_id_ = kSessionIDInvalid; } -void SpeechRecognitionManagerImpl::SessionDelete(Session* session) { - DCHECK(session->recognizer == NULL || !session->recognizer->IsActive()); - if (primary_session_id_ == session->id) +void SpeechRecognitionManagerImpl::SessionDelete(const Session& session) { + DCHECK(session.recognizer == NULL || !session.recognizer->IsActive()); + if (primary_session_id_ == session.id) primary_session_id_ = kSessionIDInvalid; - sessions_.erase(session->id); - delete session; + sessions_.erase(session.id); } void SpeechRecognitionManagerImpl::NotFeasible(const Session& session, @@ -587,7 +596,7 @@ bool SpeechRecognitionManagerImpl::SessionExists(int session_id) const { return sessions_.find(session_id) != sessions_.end(); } -SpeechRecognitionManagerImpl::Session* +const SpeechRecognitionManagerImpl::Session& SpeechRecognitionManagerImpl::GetSession(int session_id) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); SessionsTable::const_iterator iter = sessions_.find(session_id); @@ -597,8 +606,8 @@ SpeechRecognitionManagerImpl::GetSession(int session_id) const { SpeechRecognitionEventListener* SpeechRecognitionManagerImpl::GetListener( int session_id) const { - Session* session = GetSession(session_id); - return session->listener_is_active ? session->config.event_listener : NULL; + const Session& session = GetSession(session_id); + return session.listener_is_active ? session.config.event_listener : NULL; } SpeechRecognitionEventListener* @@ -608,7 +617,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 af2dbda..5f4a3d3 100644 --- a/content/browser/speech/speech_recognition_manager_impl.h +++ b/content/browser/speech/speech_recognition_manager_impl.h @@ -21,7 +21,6 @@ namespace content { class BrowserMainLoop; -class MediaStreamUIProxy; class SpeechRecognitionManagerDelegate; class SpeechRecognizer; @@ -124,7 +123,6 @@ class CONTENT_EXPORT SpeechRecognitionManagerImpl : SpeechRecognitionSessionConfig config; SpeechRecognitionSessionContext context; scoped_refptr<SpeechRecognizer> recognizer; - scoped_ptr<MediaStreamUIProxy> ui; }; // Callback issued by the SpeechRecognitionManagerDelegate for reporting @@ -133,21 +131,19 @@ class CONTENT_EXPORT SpeechRecognitionManagerImpl : bool ask_user, bool is_allowed); - // 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); + // 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); // 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(Session* session, - FSMState session_state, - FSMEvent event); + void ExecuteTransitionAndGetNextState( + const Session& session, FSMState session_state, FSMEvent event); // Retrieves the state of the session, enquiring directly the recognizer. FSMState GetSessionState(int session_id) const; @@ -157,16 +153,16 @@ class CONTENT_EXPORT SpeechRecognitionManagerImpl : void SessionAbort(const Session& session); void SessionStopAudioCapture(const Session& session); void ResetCapturingSessionId(const Session& session); - void SessionDelete(Session* session); + void SessionDelete(const Session& session); void NotFeasible(const Session& session, FSMEvent event); bool SessionExists(int session_id) const; - Session* GetSession(int session_id) const; + 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 18f0379..2868829 100644 --- a/content/common/media/media_stream_options.h +++ b/content/common/media/media_stream_options.h @@ -8,6 +8,7 @@ #include <string> #include <vector> +#include "base/callback.h" #include "content/common/content_export.h" #include "content/public/common/media_stream_request.h" @@ -19,6 +20,11 @@ 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 28fe7ed..f76c986 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -731,8 +731,9 @@ '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_ui_proxy.cc', - 'browser/renderer_host/media/media_stream_ui_proxy.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/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 f84b74b6..791efc5 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -322,6 +322,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/video_capture_buffer_pool_unittest.cc', 'browser/renderer_host/media/video_capture_controller_unittest.cc', 'browser/renderer_host/media/video_capture_host_unittest.cc', |