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