Commit 7fa1329a authored by sergeyu@chromium.org's avatar sergeyu@chromium.org

Replace MediaStreamUIController with MediaStreamUIProxy.

Previously a single object MediaStreamUIController was used to control UI for
all streams. Replaced it with a per-stream MediaStreamUIProxy that simplifies
code in many places.
Also moved media request queueing logic from content layer to chrome. Now
different types of requests may be queued differently (e.g. there is no
reason to block screen capture requests on webcam infobar).

This change was previously landed in 197222 and reverted in 197242

TBR=vrk@chromium.org

Review URL: https://codereview.chromium.org/16342002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@204044 0039d316-1c4b-4281-b951-d872f2087c98
parent 41221d85
......@@ -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();
}
......@@ -87,7 +99,11 @@ MediaCaptureDevicesDispatcher* MediaCaptureDevicesDispatcher::GetInstance() {
MediaCaptureDevicesDispatcher::MediaCaptureDevicesDispatcher()
: devices_enumerated_(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() {}
......@@ -138,6 +154,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,
......@@ -152,8 +180,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);
}
}
......@@ -259,6 +286,49 @@ 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, queue.front());
}
void MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest(
content::WebContents* web_contents,
PendingAccessRequest& request) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
MediaStreamInfoBarDelegate::Create(
web_contents, request.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())
ProcessQueuedAccessRequest(web_contents, queue.front());
callback.Run(devices, ui.Pass());
}
void MediaCaptureDevicesDispatcher::GetDefaultDevicesForProfile(
Profile* profile,
bool audio,
......
......@@ -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:
......@@ -114,9 +119,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,
......@@ -127,6 +147,15 @@ 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,
PendingAccessRequest& request);
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);
......@@ -150,9 +179,15 @@ class MediaCaptureDevicesDispatcher : public content::MediaObserver {
// Only accessed on UI thread.
bool devices_enumerated_;
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_
......@@ -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
......
......@@ -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(),
......
......@@ -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);
};
......
......@@ -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();
}
......
// 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_
// 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_
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/public/browser/browser_thread.h"
#include "media/video/capture/fake_video_capture_device.h"
namespace content {
class MediaStreamUIProxy::Core {
public:
explicit Core(const base::WeakPtr<MediaStreamUIProxy>& proxy);
~Core();
void RequestAccess(const MediaStreamRequest& request);
void OnStarted();
private:
void ProcessAccessRequestResponse(const MediaStreamDevices& devices,
scoped_ptr<MediaStreamUI> stream_ui);
void ProcessStopRequestFromUI();
base::WeakPtr<MediaStreamUIProxy> proxy_;
scoped_ptr<MediaStreamUI> ui_;
DISALLOW_COPY_AND_ASSIGN(Core);
};
MediaStreamUIProxy::Core::Core(const base::WeakPtr<MediaStreamUIProxy>& proxy)
: proxy_(proxy) {
}
MediaStreamUIProxy::Core::~Core() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
void MediaStreamUIProxy::Core::RequestAccess(
const MediaStreamRequest& request) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
RenderViewHostImpl* host = RenderViewHostImpl::FromID(
request.render_process_id, request.render_view_id);
// Tab may have gone away.
if (!host || !host->GetDelegate()) {
ProcessAccessRequestResponse(
MediaStreamDevices(), scoped_ptr<MediaStreamUI>());
return;
}
host->GetDelegate()->RequestMediaAccessPermission(
request, base::Bind(&Core::ProcessAccessRequestResponse,
base::Unretained(this)));
}
void MediaStreamUIProxy::Core::OnStarted() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (ui_) {
ui_->OnStarted(base::Bind(&Core::ProcessStopRequestFromUI,
base::Unretained(this)));
}
}
void MediaStreamUIProxy::Core::ProcessAccessRequestResponse(
const MediaStreamDevices& devices,
scoped_ptr<MediaStreamUI> stream_ui) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
ui_ = stream_ui.Pass();
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse,
proxy_, devices));
}
void MediaStreamUIProxy::Core::ProcessStopRequestFromUI() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&MediaStreamUIProxy::ProcessStopRequestFromUI, proxy_));
}
MediaStreamUIProxy::MediaStreamUIProxy()
: weak_factory_(this) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
core_.reset(new Core(weak_factory_.GetWeakPtr()));
}
MediaStreamUIProxy::~MediaStreamUIProxy() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, core_.release());
}
void MediaStreamUIProxy::RequestAccess(
const MediaStreamRequest& request,
const ResponseCallback& response_callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
response_callback_ = response_callback;
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&Core::RequestAccess, base::Unretained(core_.get()), request));
}
void MediaStreamUIProxy::OnStarted(const base::Closure& stop_callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
stop_callback_ = stop_callback;
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&Core::OnStarted, base::Unretained(core_.get())));
}
void MediaStreamUIProxy::ProcessAccessRequestResponse(
const MediaStreamDevices& devices) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(!response_callback_.is_null());
ResponseCallback cb = response_callback_;
response_callback_.Reset();
cb.Run(devices);
}
void MediaStreamUIProxy::ProcessStopRequestFromUI() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(!stop_callback_.is_null());
base::Closure cb = stop_callback_;
stop_callback_.Reset();
cb.Run();
}
FakeMediaStreamUIProxy::FakeMediaStreamUIProxy() {}
FakeMediaStreamUIProxy::~FakeMediaStreamUIProxy() {}
void FakeMediaStreamUIProxy::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
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_UI_PROXY_H_
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_UI_PROXY_H_
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/public/common/media_stream_request.h"
namespace content {
// MediaStreamUIProxy proxies calls to media stream UI between IO thread and UI
// thread. One instance of this class is create per MediaStream object. It must
// be create, used and destroyed on IO thread.
class CONTENT_EXPORT MediaStreamUIProxy {
public:
typedef base::Callback<
void (const MediaStreamDevices& devices)> ResponseCallback;
MediaStreamUIProxy();
virtual ~MediaStreamUIProxy();
// Requests access for the MediaStream by calling
// WebContentsDelegate::RequestMediaAccessPermission(). The specified
// |response_callback| is called when the WebContentsDelegate approves or
// denies request.
virtual void RequestAccess(const MediaStreamRequest& request,
const ResponseCallback& response_callback);
// Notifies the UI that the MediaStream has been started. Must be called after
// access has been approved using RequestAccess(). |stop_callback| is be
// called on the IO thread after the user has requests the stream to be
// stopped.
virtual void OnStarted(const base::Closure& stop_callback);
private:
class Core;
friend class Core;
friend class FakeMediaStreamUIProxy;
void ProcessAccessRequestResponse(const MediaStreamDevices& devices);
void ProcessStopRequestFromUI();
scoped_ptr<Core> core_;
ResponseCallback response_callback_;
base::Closure stop_callback_;
base::WeakPtrFactory<MediaStreamUIProxy> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(MediaStreamUIProxy);
};
class CONTENT_EXPORT FakeMediaStreamUIProxy : public MediaStreamUIProxy {
public:
explicit FakeMediaStreamUIProxy();
virtual ~FakeMediaStreamUIProxy();
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_
......@@ -21,6 +21,7 @@
namespace content {
class BrowserMainLoop;
class MediaStreamUIProxy;
class SpeechRecognitionManagerDelegate;
class SpeechRecognizer;
......@@ -123,6 +124,7 @@ class CONTENT_EXPORT SpeechRecognitionManagerImpl :
SpeechRecognitionSessionConfig config;
SpeechRecognitionSessionContext context;
scoped_refptr<SpeechRecognizer> recognizer;
scoped_ptr<MediaStreamUIProxy> ui;
};
// Callback issued by the SpeechRecognitionManagerDelegate for reporting
......@@ -131,19 +133,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;
......@@ -153,16 +157,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_;
......
......@@ -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.
......
......@@ -785,9 +785,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',
......
......@@ -317,7 +317,6 @@
'browser/renderer_host/media/audio_renderer_host_unittest.cc',
'browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc',
'browser/renderer_host/media/media_stream_manager_unittest.cc',
'browser/renderer_host/media/media_stream_ui_controller_unittest.cc',
'browser/renderer_host/media/video_capture_buffer_pool_unittest.cc',
'browser/renderer_host/media/video_capture_controller_unittest.cc',
'browser/renderer_host/media/video_capture_host_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment