summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorsergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-30 03:08:40 +0000
committersergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-30 03:08:40 +0000
commitac3d8f48f8342442de6423f0bc48a069fb0e892c (patch)
treed6386212995c94e591d897f8a1d1a2d04150929a /content
parentd5a4c9efa5f476c7b103992acdf22770ca19a57c (diff)
downloadchromium_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')
-rw-r--r--content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc11
-rw-r--r--content/browser/renderer_host/media/media_stream_manager.cc304
-rw-r--r--content/browser/renderer_host/media/media_stream_manager.h41
-rw-r--r--content/browser/renderer_host/media/media_stream_manager_unittest.cc37
-rw-r--r--content/browser/renderer_host/media/media_stream_settings_requester.h39
-rw-r--r--content/browser/renderer_host/media/media_stream_ui_controller.cc336
-rw-r--r--content/browser/renderer_host/media/media_stream_ui_controller.h106
-rw-r--r--content/browser/renderer_host/media/media_stream_ui_proxy.cc174
-rw-r--r--content/browser/renderer_host/media/media_stream_ui_proxy.h73
-rw-r--r--content/browser/speech/speech_recognition_manager_impl.cc165
-rw-r--r--content/browser/speech/speech_recognition_manager_impl.h24
-rw-r--r--content/common/media/media_stream_options.h6
-rw-r--r--content/content_browser.gypi5
-rw-r--r--content/content_tests.gypi1
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',