summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorxians@chromium.org <xians@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-19 14:16:26 +0000
committerxians@chromium.org <xians@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-19 14:16:26 +0000
commitc84ec38fc74f478c481d2e4ceb1c5fc5ff55b976 (patch)
tree8deb8cf27eb393de891e555a7f958624292f3264 /content
parent9950f28346a3e36f498324951609a192dfec5415 (diff)
downloadchromium_src-c84ec38fc74f478c481d2e4ceb1c5fc5ff55b976.zip
chromium_src-c84ec38fc74f478c481d2e4ceb1c5fc5ff55b976.tar.gz
chromium_src-c84ec38fc74f478c481d2e4ceb1c5fc5ff55b976.tar.bz2
> Refactor media_stream_device_settings into media_stream_ui_controller.
> media_stream_ui_controller is responsible for posting the request to UI and send the result back. > Use MediaRequstResponseCallback (will be used by speech) > Added unittests for the media_stream_manager::MakeMediaAccessRequest BUG=146306,154286 TEST=pyauto test: chrome/test/functional/webrtc_*; content_unittests; Review URL: https://codereview.chromium.org/11060005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@162990 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r--content/browser/renderer_host/media/media_stream_device_settings.cc386
-rw-r--r--content/browser/renderer_host/media/media_stream_device_settings.h100
-rw-r--r--content/browser/renderer_host/media/media_stream_dispatcher_host.cc6
-rw-r--r--content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc3
-rw-r--r--content/browser/renderer_host/media/media_stream_manager.cc215
-rw-r--r--content/browser/renderer_host/media/media_stream_manager.h53
-rw-r--r--content/browser/renderer_host/media/media_stream_manager_unittest.cc187
-rw-r--r--content/browser/renderer_host/media/media_stream_ui_controller.cc389
-rw-r--r--content/browser/renderer_host/media/media_stream_ui_controller.h123
-rw-r--r--content/browser/renderer_host/media/media_stream_ui_controller_unittest.cc (renamed from content/browser/renderer_host/media/media_stream_device_settings_unittest.cc)70
-rw-r--r--content/browser/speech/speech_recognition_manager_impl.cc2
-rw-r--r--content/common/media/media_stream_options.h7
-rw-r--r--content/content_browser.gypi4
-rw-r--r--content/content_tests.gypi3
14 files changed, 944 insertions, 604 deletions
diff --git a/content/browser/renderer_host/media/media_stream_device_settings.cc b/content/browser/renderer_host/media/media_stream_device_settings.cc
deleted file mode 100644
index d208508..0000000
--- a/content/browser/renderer_host/media/media_stream_device_settings.cc
+++ /dev/null
@@ -1,386 +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_device_settings.h"
-
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/logging.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/common/media_stream_request.h"
-#include "googleurl/src/gurl.h"
-
-using content::BrowserThread;
-using content::MediaStreamDevice;
-using content::MediaStreamRequest;
-
-namespace {
-
-// Helper class to handle the callbacks to a MediaStreamDeviceSettings instance.
-// This class will make sure that the call to PostResponse is executed on the IO
-// thread (and that the instance of MediaStreamDeviceSettings still exists).
-// This allows us to pass a simple base::Callback object to any class that needs
-// to post a response to the MediaStreamDeviceSettings object. This logic cannot
-// be implemented inside MediaStreamDeviceSettings::PostResponse since that
-// would imply that the WeakPtr<MediaStreamDeviceSettings> pointer has been
-// dereferenced already (which would cause an error in the ThreadChecker before
-// we even get there).
-class ResponseCallbackHelper
- : public base::RefCountedThreadSafe<ResponseCallbackHelper> {
- public:
- explicit ResponseCallbackHelper(
- base::WeakPtr<media_stream::MediaStreamDeviceSettings> settings)
- : settings_(settings) {
- }
-
- void PostResponse(const std::string& label,
- const content::MediaStreamDevices& devices) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&media_stream::MediaStreamDeviceSettings::PostResponse,
- settings_, label, devices));
- return;
- } else if (settings_) {
- settings_->PostResponse(label, devices);
- }
- }
-
- private:
- friend class base::RefCountedThreadSafe<ResponseCallbackHelper>;
- ~ResponseCallbackHelper() {}
-
- base::WeakPtr<media_stream::MediaStreamDeviceSettings> settings_;
-
- DISALLOW_COPY_AND_ASSIGN(ResponseCallbackHelper);
-};
-
-// Predicate used in find_if below to find a device with a given ID.
-class DeviceIdEquals {
- public:
- explicit DeviceIdEquals(const std::string& device_id)
- : device_id_(device_id) {
- }
-
- bool operator() (const media_stream::StreamDeviceInfo& device) {
- return (device.device_id == device_id_);
- }
-
- private:
- std::string device_id_;
-};
-
-} // namespace
-
-namespace media_stream {
-
-typedef std::map<MediaStreamType, StreamDeviceInfoArray> DeviceMap;
-
-// Device request contains all data needed to keep track of requests between the
-// different calls.
-struct MediaStreamDeviceSettingsRequest : public MediaStreamRequest {
- public:
- MediaStreamDeviceSettingsRequest(
- int render_pid,
- int render_vid,
- const GURL& origin,
- const StreamOptions& request_options)
- : MediaStreamRequest(render_pid, render_vid, origin),
- options(request_options),
- posted_task(false) {}
-
- ~MediaStreamDeviceSettingsRequest() {}
-
- // Request options.
- StreamOptions options;
- // Map containing available devices for the requested capture types.
- // Note, never call devices_full[stream_type].empty() before making sure
- // that type of device has existed on the map, otherwise it will create an
- // empty device entry on the map.
- DeviceMap devices_full;
- // 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 DoDeviceRequest(const MediaStreamDeviceSettingsRequest& request,
- const content::MediaResponseCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // Send the permission request to the web contents.
- content::RenderViewHostImpl* host =
- content::RenderViewHostImpl::FromID(request.render_process_id,
- request.render_view_id);
-
- // Tab may have gone away.
- if (!host || !host->GetDelegate()) {
- callback.Run(content::MediaStreamDevices());
- return;
- }
-
- host->GetDelegate()->RequestMediaAccessPermission(&request, callback);
-}
-
-bool IsRequestReadyForView(
- media_stream::MediaStreamDeviceSettingsRequest* request) {
- if ((content::IsAudioMediaType(request->options.audio_type) &&
- request->devices_full.count(request->options.audio_type) == 0) ||
- (content::IsVideoMediaType(request->options.video_type) &&
- request->devices_full.count(request->options.video_type) == 0)) {
- return false;
- }
-
- // We have got all the requested devices, it is ready if it has not
- // been posted for UI yet.
- return !request->posted_task;
-}
-
-} // namespace
-
-MediaStreamDeviceSettings::MediaStreamDeviceSettings(
- SettingsRequester* requester)
- : requester_(requester),
- use_fake_ui_(false),
- weak_ptr_factory_(this) {
- DCHECK(requester_);
-}
-
-MediaStreamDeviceSettings::~MediaStreamDeviceSettings() {
- STLDeleteValues(&requests_);
-}
-
-void MediaStreamDeviceSettings::RequestCaptureDeviceUsage(
- const std::string& label, int render_process_id, int render_view_id,
- const StreamOptions& request_options, const GURL& security_origin) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- // Create a new request.
- if (!requests_.insert(std::make_pair(label,
- new MediaStreamDeviceSettingsRequest(
- render_process_id,
- render_view_id,
- security_origin,
- request_options))).second) {
- NOTREACHED();
- }
-}
-
-void MediaStreamDeviceSettings::RemovePendingCaptureRequest(
- const std::string& label) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- SettingsRequests::iterator request_it = requests_.find(label);
- if (request_it != requests_.end()) {
- // Proceed the next pending request for the same page.
- MediaStreamDeviceSettingsRequest* request = request_it->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_it);
- delete request;
-
- // 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_view_id, render_process_id);
- }
-}
-
-void MediaStreamDeviceSettings::AvailableDevices(
- const std::string& label,
- MediaStreamType stream_type,
- const StreamDeviceInfoArray& devices) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- SettingsRequests::iterator request_it = requests_.find(label);
- if (request_it == requests_.end()) {
- NOTREACHED();
- return;
- }
-
- // Add the answer for the request.
- MediaStreamDeviceSettingsRequest* request = request_it->second;
- DCHECK_EQ(request->devices_full.count(stream_type), static_cast<size_t>(0))
- << "This request already has a list of devices for this stream type.";
- request->devices_full[stream_type] = devices;
-
- if (IsRequestReadyForView(request)) {
- if (use_fake_ui_) {
- PostRequestToFakeUI(label);
- return;
- }
-
- if (IsUIBusy(request->render_view_id, request->render_process_id)) {
- // 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.
- return;
- }
-
- PostRequestToUI(label);
- }
-}
-
-void MediaStreamDeviceSettings::PostResponse(
- const std::string& label,
- const content::MediaStreamDevices& devices) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- SettingsRequests::iterator req = requests_.find(label);
- // Return if the request has been removed.
- if (req == requests_.end())
- return;
-
- DCHECK(requester_);
- scoped_ptr<MediaStreamDeviceSettingsRequest> request(req->second);
- requests_.erase(req);
-
- // Look for queued requests for the same view. If there is a pending request,
- // post it for user approval.
- ProcessNextRequestForView(request->render_view_id,
- request->render_process_id);
-
- if (devices.size() > 0) {
- // Build a list of "full" device objects for the accepted devices.
- StreamDeviceInfoArray deviceList;
- for (content::MediaStreamDevices::const_iterator dev = devices.begin();
- dev != devices.end(); ++dev) {
- DeviceMap::iterator subList = request->devices_full.find(dev->type);
- DCHECK(subList != request->devices_full.end());
-
- deviceList.push_back(*std::find_if(subList->second.begin(),
- subList->second.end(), DeviceIdEquals(dev->device_id)));
- }
- requester_->DevicesAccepted(label, deviceList);
- } else {
- requester_->SettingsError(label);
- }
-}
-
-void MediaStreamDeviceSettings::UseFakeUI() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- use_fake_ui_ = true;
-}
-
-bool MediaStreamDeviceSettings::IsUIBusy(int render_view_id,
- int render_process_id) {
- for (SettingsRequests::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 MediaStreamDeviceSettings::ProcessNextRequestForView(
- int render_view_id, int render_process_id) {
- std::string new_label;
- for (SettingsRequests::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.
- MediaStreamDeviceSettingsRequest* request = it->second;
- if (IsRequestReadyForView(request)) {
- new_label = it->first;
- break;
- }
- }
- }
-
- if (new_label.empty())
- return;
-
- if (use_fake_ui_)
- PostRequestToFakeUI(new_label);
- else
- PostRequestToUI(new_label);
-}
-
-void MediaStreamDeviceSettings::PostRequestToUI(const std::string& label) {
- SettingsRequests::iterator request_it = requests_.find(label);
- if (request_it == requests_.end()) {
- NOTREACHED();
- return;
- }
- MediaStreamDeviceSettingsRequest* request = request_it->second;
- DCHECK(request != NULL);
-
- request->posted_task = true;
-
- // Create the simplified list of devices.
- for (DeviceMap::iterator it = request->devices_full.begin();
- it != request->devices_full.end(); ++it) {
- request->devices[it->first].clear();
- for (StreamDeviceInfoArray::iterator device = it->second.begin();
- device != it->second.end(); ++device) {
- request->devices[it->first].push_back(MediaStreamDevice(
- it->first, device->device_id, device->name));
- }
- }
-
- scoped_refptr<ResponseCallbackHelper> helper =
- new ResponseCallbackHelper(weak_ptr_factory_.GetWeakPtr());
- content::MediaResponseCallback callback =
- base::Bind(&ResponseCallbackHelper::PostResponse,
- helper.get(), label);
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&DoDeviceRequest, *request, callback));
-}
-
-void MediaStreamDeviceSettings::PostRequestToFakeUI(const std::string& label) {
- SettingsRequests::iterator request_it = requests_.find(label);
- DCHECK(request_it != requests_.end());
- MediaStreamDeviceSettingsRequest* request = request_it->second;
- // Used to fake UI, which is needed for server based testing.
- // Choose first non-opened device for each media type.
- content::MediaStreamDevices devices_to_use;
- for (DeviceMap::iterator it = request->devices_full.begin();
- it != request->devices_full.end(); ++it) {
- StreamDeviceInfoArray::iterator device_it = it->second.begin();
- for (; device_it != it->second.end(); ++device_it) {
- if (!device_it->in_use) {
- devices_to_use.push_back(content::MediaStreamDevice(
- device_it->stream_type, device_it->device_id, device_it->name));
- break;
- }
- }
-
- if (it->second.size() != 0 && device_it == it->second.end()) {
- // Use the first capture device in the list if all the devices are
- // being used.
- devices_to_use.push_back(
- content::MediaStreamDevice(it->second.begin()->stream_type,
- it->second.begin()->device_id,
- it->second.begin()->name));
- }
- }
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&MediaStreamDeviceSettings::PostResponse,
- weak_ptr_factory_.GetWeakPtr(), label, devices_to_use));
-}
-
-} // namespace media_stream
diff --git a/content/browser/renderer_host/media/media_stream_device_settings.h b/content/browser/renderer_host/media/media_stream_device_settings.h
deleted file mode 100644
index 4a3bd6d..0000000
--- a/content/browser/renderer_host/media/media_stream_device_settings.h
+++ /dev/null
@@ -1,100 +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.
-
-// MediaStreamDeviceSettings 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. RequestCaptureDeviceUsage() is called to create a new request for capture
-// device usage.
-// 2. AvailableDevices() is called with a list of currently available devices.
-// 3. Pick device and get user confirmation.
-// 4. Confirm by calling SettingsRequester::DevicesAccepted().
-// Repeat step 1 - 4 for new device requests.
-
-#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_DEVICE_SETTINGS_H_
-#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_DEVICE_SETTINGS_H_
-
-#include <map>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/memory/weak_ptr.h"
-#include "content/browser/renderer_host/media/media_stream_provider.h"
-
-namespace media_stream {
-
-class SettingsRequester;
-struct MediaStreamDeviceSettingsRequest;
-
-// MediaStreamDeviceSettings is responsible for getting user permission to use
-// a media capture device as well as selecting what device to use.
-class CONTENT_EXPORT MediaStreamDeviceSettings {
- public:
- explicit MediaStreamDeviceSettings(SettingsRequester* requester);
- virtual ~MediaStreamDeviceSettings();
-
- // Called when a new request of capture device usage is made.
- void RequestCaptureDeviceUsage(const std::string& label,
- int render_process_id,
- int render_view_id,
- const StreamOptions& stream_components,
- const GURL& security_origin);
-
- // Called to remove a pending request of capture device usage when the user
- // has no action for the media stream InfoBar.
- void RemovePendingCaptureRequest(const std::string& label);
-
- // Called to pass in an array of available devices for a request represented
- // by |label|. There could be multiple calls for a request.
- void AvailableDevices(const std::string& label, MediaStreamType stream_type,
- const StreamDeviceInfoArray& devices);
-
- // Called by the InfoBar when the user grants/denies access to some devices
- // to the webpage. This is placed here, so the request can be cleared from the
- // list of pending requests, instead of letting the InfoBar itself respond to
- // the requester. An empty list of devices means that access has been denied.
- // This method must be called on the IO thread.
- void PostResponse(const std::string& label,
- const content::MediaStreamDevices& devices);
-
- // 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();
-
- private:
- typedef std::map<std::string, MediaStreamDeviceSettingsRequest*>
- SettingsRequests;
-
- // Returns true if the UI is already processing a request for this render
- // view.
- bool IsUIBusy(int render_view_id, int render_process_id);
-
- // Process the next pending request and bring it up to the UI on the given
- // page for user approval.
- void ProcessNextRequestForView(int render_view_id, int render_process_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);
-
- SettingsRequester* requester_;
- SettingsRequests requests_;
-
- // See comment above for method UseFakeUI. Used for automated testing.
- bool use_fake_ui_;
-
- base::WeakPtrFactory<MediaStreamDeviceSettings> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(MediaStreamDeviceSettings);
-};
-
-} // namespace media_stream
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_DEVICE_SETTINGS_H_
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
index 6124adc..9ef1a2d 100644
--- a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
+++ b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
@@ -169,7 +169,7 @@ void MediaStreamDispatcherHost::OnCancelGenerateStream(int render_view_id,
for (StreamMap::iterator it = streams_.begin(); it != streams_.end(); ++it) {
if (it->second.render_view_id == render_view_id &&
it->second.page_request_id == page_request_id) {
- GetManager()->CancelGenerateStream(it->first);
+ GetManager()->CancelRequest(it->first);
}
}
}
@@ -197,7 +197,7 @@ void MediaStreamDispatcherHost::OnEnumerateDevices(
std::string label;
GetManager()->EnumerateDevices(this, render_process_id_, render_view_id,
- type, security_origin, &label);
+ type, security_origin, &label);
DCHECK(!label.empty());
streams_[label] = StreamRequest(render_view_id, page_request_id);
}
@@ -217,7 +217,7 @@ void MediaStreamDispatcherHost::OnOpenDevice(
std::string label;
GetManager()->OpenDevice(this, render_process_id_, render_view_id,
- device_id, type, security_origin, &label);
+ device_id, type, security_origin, &label);
DCHECK(!label.empty());
streams_[label] = StreamRequest(render_view_id, page_request_id);
}
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 9f8f502..ee5c0df 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
@@ -251,7 +251,7 @@ TEST_F(MediaStreamDispatcherHostTest, GenerateThreeStreams) {
EXPECT_EQ(host_->video_devices_.size(), 1u);
std::string label2 = host_->label_;
std::string device_id2 = host_->video_devices_.front().device_id;
- EXPECT_NE(device_id1, device_id2);
+ EXPECT_EQ(device_id1, device_id2);
EXPECT_NE(label1, label2);
// Check that we now have two opened streams.
@@ -273,7 +273,6 @@ TEST_F(MediaStreamDispatcherHostTest, GenerateThreeStreams) {
std::string label3 = host_->label_;
std::string device_id3 = host_->video_devices_.front().device_id;
EXPECT_EQ(device_id1, device_id3);
- EXPECT_NE(device_id2, device_id3);
EXPECT_NE(label1, label3);
EXPECT_NE(label2, label3);
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 6bf60c9..c3245c8 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -11,14 +11,15 @@
#include "base/logging.h"
#include "base/rand_util.h"
#include "content/browser/renderer_host/media/audio_input_device_manager.h"
-#include "content/browser/renderer_host/media/media_stream_device_settings.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/video_capture_manager.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/browser/media_request_state.h"
+#include "content/public/common/media_stream_request.h"
#include "googleurl/src/gurl.h"
#if defined(OS_WIN)
@@ -82,7 +83,8 @@ void DeviceThread::CleanUp() {
class MediaStreamManager::DeviceRequest {
public:
enum RequestType {
- GENERATE_STREAM = 0,
+ DEVICE_ACCESS = 0,
+ GENERATE_STREAM,
ENUMERATE_DEVICES,
OPEN_DEVICE
};
@@ -98,31 +100,22 @@ class MediaStreamManager::DeviceRequest {
DeviceRequest(MediaStreamRequester* requester,
const StreamOptions& request_options,
+ RequestType request_type,
int render_process_id,
int render_view_id,
const GURL& request_security_origin)
: requester(requester),
options(request_options),
- type(GENERATE_STREAM),
+ type(request_type),
render_process_id(render_process_id),
render_view_id(render_view_id),
security_origin(request_security_origin),
state_(content::NUM_MEDIA_TYPES,
content::MEDIA_REQUEST_STATE_NOT_REQUESTED) {
- DCHECK(requester);
}
~DeviceRequest() {}
- MediaStreamRequester* requester;
- StreamOptions options;
- RequestType type;
- int render_process_id;
- int render_view_id;
- GURL security_origin;
- std::string requested_device_id;
- StreamDeviceInfoArray devices;
-
// Update the request state and notify observers.
void setState(MediaStreamType stream_type,
content::MediaRequestState new_state) {
@@ -149,6 +142,20 @@ class MediaStreamManager::DeviceRequest {
return state_[stream_type];
}
+ MediaStreamRequester* requester; // Can be NULL.
+ StreamOptions options;
+ RequestType type;
+ int render_process_id;
+ int render_view_id;
+ GURL security_origin;
+ std::string requested_device_id;
+ StreamDeviceInfoArray devices;
+
+ // Callback to the requester which audio/video devices have been selected.
+ // It can be null if the requester has no interest to know the result.
+ // Currently it is only used by |DEVICE_ACCESS| type.
+ media_stream::MediaRequestResponseCallback callback;
+
private:
std::vector<content::MediaRequestState> state_;
};
@@ -169,7 +176,7 @@ void MediaStreamManager::AlwaysUseFakeDevice() {
MediaStreamManager::MediaStreamManager(media::AudioManager* audio_manager)
: ALLOW_THIS_IN_INITIALIZER_LIST(
- device_settings_(new MediaStreamDeviceSettings(this))),
+ ui_controller_(new content::MediaStreamUIController(this))),
audio_manager_(audio_manager),
monitoring_started_(false),
io_loop_(NULL) {
@@ -198,6 +205,31 @@ AudioInputDeviceManager* MediaStreamManager::audio_input_device_manager() {
return audio_input_device_manager_;
}
+void MediaStreamManager::MakeMediaAccessRequest(
+ int render_process_id,
+ int render_view_id,
+ const StreamOptions& options,
+ const GURL& security_origin,
+ const MediaRequestResponseCallback& callback,
+ std::string* label) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // Create a new request based on options.
+ DeviceRequest new_request(NULL,
+ options,
+ DeviceRequest::DEVICE_ACCESS,
+ render_process_id,
+ render_view_id,
+ security_origin);
+ StartEnumeration(&new_request, label);
+
+ // TODO(xians), remove this silly code after AddRequest does not copy
+ // the struct by value.
+ DeviceRequest& request = requests_[*label];
+ request.callback = callback;
+
+ PostRequestToUI(*label);
+}
+
void MediaStreamManager::GenerateStream(MediaStreamRequester* requester,
int render_process_id,
int render_view_id,
@@ -210,17 +242,14 @@ void MediaStreamManager::GenerateStream(MediaStreamRequester* requester,
// Create a new request based on options.
DeviceRequest new_request(requester, options,
+ DeviceRequest::GENERATE_STREAM,
render_process_id,
render_view_id,
security_origin);
StartEnumeration(&new_request, label);
// Get user confirmation to use capture devices.
- device_settings_->RequestCaptureDeviceUsage(*label,
- render_process_id,
- render_view_id,
- options,
- security_origin);
+ PostRequestToUI(*label);
}
void MediaStreamManager::GenerateStreamForDevice(
@@ -231,6 +260,7 @@ void MediaStreamManager::GenerateStreamForDevice(
// Create a new request based on options.
AddRequest(DeviceRequest(requester, options,
+ DeviceRequest::GENERATE_STREAM,
render_process_id, render_view_id,
security_origin),
label);
@@ -238,11 +268,7 @@ void MediaStreamManager::GenerateStreamForDevice(
request.requested_device_id = device_id;
// Get user confirmation to use the capture device.
- device_settings_->RequestCaptureDeviceUsage(*label,
- render_process_id,
- render_view_id,
- options,
- security_origin);
+ PostRequestToUI(*label);
if (!security_origin.SchemeIs(kExtensionScheme) ||
(options.audio_type != content::MEDIA_TAB_AUDIO_CAPTURE &&
@@ -251,7 +277,7 @@ void MediaStreamManager::GenerateStreamForDevice(
options.video_type != content::MEDIA_NO_SERVICE)) {
LOG(ERROR) << "Invalid request or used tab capture outside extension API.";
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
- base::Bind(&MediaStreamManager::CancelGenerateStream,
+ base::Bind(&MediaStreamManager::CancelRequest,
base::Unretained(this), *label));
return;
}
@@ -287,13 +313,17 @@ void MediaStreamManager::GenerateStreamForDevice(
base::Unretained(this), *label, devices));
}
-void MediaStreamManager::CancelGenerateStream(const std::string& label) {
+void MediaStreamManager::CancelRequest(const std::string& label) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DeviceRequests::iterator it = requests_.find(label);
if (it != requests_.end()) {
- // The request isn't complete.
+ // 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?
DeviceRequest& request = it->second;
for (int i = content::MEDIA_NO_SERVICE + 1; i < content::NUM_MEDIA_TYPES;
++i) {
@@ -310,11 +340,12 @@ void MediaStreamManager::CancelGenerateStream(const std::string& label) {
}
}
}
+
+ // Delete the request.
requests_.erase(it);
} else {
StopGeneratedStream(label);
}
- device_settings_->RemovePendingCaptureRequest(label);
}
}
@@ -342,8 +373,14 @@ void MediaStreamManager::StopGeneratedStream(const std::string& label) {
it->second.setState(static_cast<MediaStreamType>(i),
content::MEDIA_REQUEST_STATE_CLOSING);
}
- NotifyObserverDevicesClosed(&(it->second));
+ NotifyDevicesClosed(it->second);
}
+
+ // 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);
+
+ // Delete the request now.
requests_.erase(it);
}
}
@@ -374,10 +411,10 @@ void MediaStreamManager::EnumerateDevices(
}
DeviceRequest new_request(requester, options,
+ DeviceRequest::ENUMERATE_DEVICES,
render_process_id,
render_view_id,
security_origin);
- new_request.type = DeviceRequest::ENUMERATE_DEVICES;
if (cache->valid) {
// Cached device list of this type exists. Just send it out.
@@ -432,15 +469,35 @@ void MediaStreamManager::OpenDevice(
}
DeviceRequest new_request(requester, options,
+ DeviceRequest::OPEN_DEVICE,
render_process_id,
render_view_id,
security_origin);
- new_request.type = DeviceRequest::OPEN_DEVICE;
new_request.requested_device_id = device_id;
StartEnumeration(&new_request, label);
}
+void MediaStreamManager::NotifyUIDevicesOpened(
+ int render_process_id,
+ int render_view_id,
+ const content::MediaStreamDevices& devices) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ ui_controller_->NotifyUIIndicatorDevicesOpened(render_process_id,
+ render_view_id,
+ devices);
+}
+
+void MediaStreamManager::NotifyUIDevicesClosed(
+ int render_process_id,
+ int render_view_id,
+ const content::MediaStreamDevices& devices) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ ui_controller_->NotifyUIIndicatorDevicesClosed(render_process_id,
+ render_view_id,
+ devices);
+}
+
void MediaStreamManager::SendCachedDeviceList(
EnumerationCache* cache,
const std::string& label) {
@@ -514,6 +571,18 @@ void MediaStreamManager::AddRequest(
(*label) = request_label;
}
+void MediaStreamManager::PostRequestToUI(const std::string& label) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ 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);
+}
+
void MediaStreamManager::EnsureDeviceManagersStarted() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (device_thread_.get())
@@ -607,7 +676,7 @@ void MediaStreamManager::Opened(MediaStreamType stream_type,
}
request->requester->StreamGenerated(label, audio_devices, video_devices);
- NotifyObserverDevicesOpened(request);
+ NotifyDevicesOpened(*request);
break;
}
default:
@@ -682,7 +751,8 @@ void MediaStreamManager::DevicesEnumerated(
}
break;
default:
- device_settings_->AvailableDevices(*it, stream_type, devices);
+ ui_controller_->AddAvailableDevicesToRequest(*it, stream_type,
+ devices);
break;
}
}
@@ -731,7 +801,9 @@ void MediaStreamManager::Error(MediaStreamType stream_type,
if (devices.size() <= 1) {
// 1. Device not opened and no other devices for this request ->
// signal stream error and remove the request.
- it->second.requester->StreamGenerationFailed(it->first);
+ if (it->second.requester)
+ it->second.requester->StreamGenerationFailed(it->first);
+
requests_.erase(it);
} else {
// 2. Not opened but other devices exists for this request -> remove
@@ -747,6 +819,7 @@ void MediaStreamManager::Error(MediaStreamType stream_type,
void MediaStreamManager::DevicesAccepted(const std::string& label,
const StreamDeviceInfoArray& devices) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(!devices.empty());
DeviceRequests::iterator request_it = requests_.find(label);
if (request_it == requests_.end()) {
return;
@@ -754,9 +827,20 @@ void MediaStreamManager::DevicesAccepted(const std::string& label,
DeviceRequest& request = request_it->second;
- if (devices.empty()) {
- // No available devices or user didn't accept device usage.
- request.requester->StreamGenerationFailed(request_it->first);
+ if (request.type == DeviceRequest::DEVICE_ACCESS) {
+ if (!request.callback.is_null()) {
+ // Map the devices to MediaStreamDevices.
+ content::MediaStreamDevices selected_devices;
+ for (StreamDeviceInfoArray::const_iterator it = devices.begin();
+ it != devices.end(); ++it) {
+ selected_devices.push_back(content::MediaStreamDevice(
+ it->stream_type, it->device_id, it->name));
+ }
+
+ request.callback.Run(label, selected_devices);
+ }
+
+ // Delete the request since it is done.
requests_.erase(request_it);
return;
}
@@ -802,18 +886,24 @@ 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()) {
- DCHECK_EQ(it->second.type, DeviceRequest::GENERATE_STREAM);
- it->second.requester->StreamGenerationFailed(label);
- requests_.erase(it);
+ if (it == requests_.end())
return;
- }
+
+ // Notify the users about the request result.
+ DeviceRequest& request = it->second;
+ if (request.requester)
+ it->second.requester->StreamGenerationFailed(label);
+
+ if (request.type == DeviceRequest::DEVICE_ACCESS)
+ request.callback.Run(label, content::MediaStreamDevices());
+
+ requests_.erase(it);
}
void MediaStreamManager::UseFakeDevice() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
video_capture_manager()->UseFakeDevice();
- device_settings_->UseFakeUI();
+ ui_controller_->UseFakeUI();
}
void MediaStreamManager::WillDestroyCurrentMessageLoop() {
@@ -830,40 +920,37 @@ void MediaStreamManager::WillDestroyCurrentMessageLoop() {
audio_input_device_manager_ = NULL;
video_capture_manager_ = NULL;
io_loop_ = NULL;
- device_settings_.reset();
+ ui_controller_.reset();
}
-void MediaStreamManager::NotifyObserverDevicesOpened(DeviceRequest* request) {
- content::MediaObserver* media_observer =
- content::GetContentClient()->browser()->GetMediaObserver();
- if (media_observer == NULL)
- return;
+void MediaStreamManager::NotifyDevicesOpened(const DeviceRequest& request) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
content::MediaStreamDevices opened_devices;
DevicesFromRequest(request, &opened_devices);
- DCHECK(!opened_devices.empty());
- media_observer->OnCaptureDevicesOpened(request->render_process_id,
- request->render_view_id,
- opened_devices);
+ if (opened_devices.empty())
+ return;
+
+ NotifyUIDevicesOpened(request.render_process_id,
+ request.render_view_id,
+ opened_devices);
}
-void MediaStreamManager::NotifyObserverDevicesClosed(DeviceRequest* request) {
- content::MediaObserver* media_observer =
- content::GetContentClient()->browser()->GetMediaObserver();
- if (media_observer == NULL)
- return;
+void MediaStreamManager::NotifyDevicesClosed(const DeviceRequest& request) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
content::MediaStreamDevices closed_devices;
DevicesFromRequest(request, &closed_devices);
if (closed_devices.empty())
return;
- media_observer->OnCaptureDevicesClosed(request->render_process_id,
- request->render_view_id,
- closed_devices);
+
+ NotifyUIDevicesClosed(request.render_process_id,
+ request.render_view_id,
+ closed_devices);
}
void MediaStreamManager::DevicesFromRequest(
- DeviceRequest* request, content::MediaStreamDevices* devices) {
- for (StreamDeviceInfoArray::const_iterator it = request->devices.begin();
- it != request->devices.end(); ++it) {
+ const DeviceRequest& request, content::MediaStreamDevices* devices) {
+ for (StreamDeviceInfoArray::const_iterator it = request.devices.begin();
+ it != request.devices.end(); ++it) {
devices->push_back(content::MediaStreamDevice(
it->stream_type, it->device_id, it->name));
}
diff --git a/content/browser/renderer_host/media/media_stream_manager.h b/content/browser/renderer_host/media/media_stream_manager.h
index 5faa780..7db8a37 100644
--- a/content/browser/renderer_host/media/media_stream_manager.h
+++ b/content/browser/renderer_host/media/media_stream_manager.h
@@ -6,18 +6,19 @@
// supported now). Call flow:
// 1. GenerateStream is called when a render process wants to use a capture
// device.
-// 2. MediaStreamManager will ask MediaStreamDeviceSettings for permission to
+// 2. MediaStreamManager will ask MediaStreamUIController for permission to
// use devices and for which device to use.
// 3. MediaStreamManager will request the corresponding media device manager(s)
// to enumerate available devices. The result will be given to
-// MediaStreamDeviceSettings.
-// 4. MediaStreamDeviceSettings will, by using user settings, pick devices which
-// devices to use and let MediaStreamManager know the result.
+// MediaStreamUIController.
+// 4. MediaStreamUIController will, by posting the request to UI, let the
+// users to select which devices to use and send callback to
+// MediaStreamManager with the result.
// 5. MediaStreamManager will call the proper media device manager to open the
// device and let the MediaStreamRequester know it has been done.
// When enumeration and open are done in separate operations,
-// MediaStreamDeviceSettings is not involved as in steps.
+// MediaStreamUIController is not involved as in steps.
#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_MANAGER_H_
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_MANAGER_H_
@@ -45,6 +46,10 @@ class ScopedCOMInitializer;
}
#endif
+namespace content {
+class MediaStreamUIController;
+}
+
namespace media {
class AudioManager;
}
@@ -95,6 +100,20 @@ class CONTENT_EXPORT MediaStreamManager
// Used to access AudioInputDeviceManager.
AudioInputDeviceManager* audio_input_device_manager();
+ // Creates a new media access request which is identified by a unique |label|
+ // that's returned to the caller. This will trigger the infobar and ask users
+ // for access to the device. |render_process_id| and |render_view_id| refer
+ // to the view where the infobar will appear to the user. |callback| is
+ // used to send the selected device to the clients. An empty list of device
+ // will be returned if the users deny the access.
+ void MakeMediaAccessRequest(
+ int render_process_id,
+ int render_view_id,
+ const StreamOptions& components,
+ const GURL& security_origin,
+ const MediaRequestResponseCallback& callback,
+ std::string* label);
+
// GenerateStream opens new media devices according to |components|. It
// creates a new request which is identified by a unique |label| that's
// returned to the caller. |render_process_id| and |render_view_id| refer to
@@ -111,8 +130,7 @@ class CONTENT_EXPORT MediaStreamManager
const std::string& device_id,
const GURL& security_origin, std::string* label);
- // Cancel generate stream.
- void CancelGenerateStream(const std::string& label);
+ void CancelRequest(const std::string& label);
// Closes generated stream.
void StopGeneratedStream(const std::string& label);
@@ -143,6 +161,18 @@ class CONTENT_EXPORT MediaStreamManager
const GURL& security_origin,
std::string* label);
+ // 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(int render_process_id,
+ int render_view_id,
+ const content::MediaStreamDevices& devices);
+
+ // Signals the UI that the devices are being closed.
+ void NotifyUIDevicesClosed(int render_process_id,
+ int render_view_id,
+ const content::MediaStreamDevices& devices);
+
// Implements MediaStreamProviderListener.
virtual void Opened(MediaStreamType stream_type,
int capture_session_id) OVERRIDE;
@@ -191,9 +221,9 @@ class CONTENT_EXPORT MediaStreamManager
// Helpers for signaling the media observer that new capture devices are
// opened/closed.
- void NotifyObserverDevicesOpened(DeviceRequest* request);
- void NotifyObserverDevicesClosed(DeviceRequest* request);
- void DevicesFromRequest(DeviceRequest* request,
+ void NotifyDevicesOpened(const DeviceRequest& request);
+ void NotifyDevicesClosed(const DeviceRequest& request);
+ void DevicesFromRequest(const DeviceRequest& request,
content::MediaStreamDevices* devices);
// Helpers.
@@ -205,6 +235,7 @@ class CONTENT_EXPORT MediaStreamManager
bool HasEnumerationRequest(MediaStreamType type);
bool HasEnumerationRequest();
void ClearEnumerationCache(EnumerationCache* cache);
+ void PostRequestToUI(const std::string& label);
// Helper to create the device managers, if needed. Auto-starts the device
// thread and registers this as a listener with the device managers.
@@ -224,7 +255,7 @@ class CONTENT_EXPORT MediaStreamManager
// Device thread shared by VideoCaptureManager and AudioInputDeviceManager.
scoped_ptr<DeviceThread> device_thread_;
- scoped_ptr<MediaStreamDeviceSettings> device_settings_;
+ scoped_ptr<content::MediaStreamUIController> ui_controller_;
media::AudioManager* const audio_manager_; // not owned
scoped_refptr<AudioInputDeviceManager> audio_input_device_manager_;
diff --git a/content/browser/renderer_host/media/media_stream_manager_unittest.cc b/content/browser/renderer_host/media/media_stream_manager_unittest.cc
new file mode 100644
index 0000000..9ad4c87
--- /dev/null
+++ b/content/browser/renderer_host/media/media_stream_manager_unittest.cc
@@ -0,0 +1,187 @@
+// 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 <string>
+
+#include "base/bind.h"
+#include "base/message_loop.h"
+#include "content/browser/browser_thread_impl.h"
+#include "content/browser/renderer_host/media/media_stream_manager.h"
+#include "content/common/media/media_stream_options.h"
+#include "media/audio/audio_manager_base.h"
+#if defined(OS_ANDROID)
+#include "media/audio/android/audio_manager_android.h"
+#elif defined(OS_LINUX) || defined(OS_OPENBSD)
+#include "media/audio/linux/audio_manager_linux.h"
+#elif defined(OS_MACOSX)
+#include "media/audio/mac/audio_manager_mac.h"
+#elif defined(OS_WIN)
+#include "media/audio/win/audio_manager_win.h"
+#endif
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using content::BrowserThread;
+using content::BrowserThreadImpl;
+using testing::_;
+
+namespace content {
+
+#if defined(OS_LINUX) || defined(OS_OPENBSD)
+typedef media::AudioManagerLinux AudioManagerPlatform;
+#elif defined(OS_MACOSX)
+typedef media::AudioManagerMac AudioManagerPlatform;
+#elif defined(OS_WIN)
+typedef media::AudioManagerWin AudioManagerPlatform;
+#elif defined(OS_ANDROID)
+typedef media::AudioManagerAndroid AudioManagerPlatform;
+#endif
+
+
+// This class mocks the audio manager and overrides the
+// GetAudioInputDeviceNames() method to ensure that we can run our tests on
+// the buildbots. media::AudioManagerBase
+class MockAudioManager : public AudioManagerPlatform {
+ public:
+ MockAudioManager() {
+ Init();
+ }
+
+ virtual ~MockAudioManager() {}
+
+ virtual void GetAudioInputDeviceNames(
+ media::AudioDeviceNames* device_names) OVERRIDE {
+ if (HasAudioInputDevices()) {
+ AudioManagerBase::GetAudioInputDeviceNames(device_names);
+ } else {
+ device_names->push_back(media::AudioDeviceName("fake_device_name",
+ "fake_device_id"));
+ }
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockAudioManager);
+};
+
+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);
+ message_loop_->PostTask(FROM_HERE, MessageLoop::QuitClosure());
+ }
+
+ void WaitForResult() { message_loop_->Run(); }
+
+ protected:
+ virtual void SetUp() {
+ message_loop_.reset(new MessageLoop(MessageLoop::TYPE_IO));
+ ui_thread_.reset(new BrowserThreadImpl(BrowserThread::UI,
+ message_loop_.get()));
+ io_thread_.reset(new BrowserThreadImpl(BrowserThread::IO,
+ message_loop_.get()));
+
+ // Create our own MediaStreamManager.
+ audio_manager_.reset(new MockAudioManager());
+ media_stream_manager_.reset(
+ new media_stream::MediaStreamManager(audio_manager_.get()));
+
+ // Use fake devices in order to run on the bots.
+ media_stream_manager_->UseFakeDevice();
+ }
+
+ virtual void TearDown() {
+ message_loop_->RunAllPending();
+
+ // Delete the IO message loop to clean up the MediaStreamManager.
+ message_loop_.reset();
+ }
+
+ void MakeMediaAccessRequest(std::string* label) {
+ const int render_process_id = 1;
+ const int render_view_id = 1;
+ media_stream::StreamOptions components(true, true);
+ const GURL security_origin;
+ media_stream::MediaRequestResponseCallback callback =
+ base::Bind(&MediaStreamManagerTest::ResponseCallback,
+ base::Unretained(this));
+ media_stream_manager_->MakeMediaAccessRequest(render_process_id,
+ render_view_id,
+ components,
+ security_origin,
+ callback,
+ label);
+ }
+
+ scoped_ptr<MessageLoop> message_loop_;
+ scoped_ptr<BrowserThreadImpl> ui_thread_;
+ scoped_ptr<BrowserThreadImpl> io_thread_;
+ scoped_ptr<media::AudioManager> audio_manager_;
+ scoped_ptr<media_stream::MediaStreamManager> media_stream_manager_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MediaStreamManagerTest);
+};
+
+TEST_F(MediaStreamManagerTest, MakeMediaAccessRequest) {
+ std::string label;
+ MakeMediaAccessRequest(&label);
+
+ // Expecting the callback will be triggered and quit the test.
+ EXPECT_CALL(*this, Response(label));
+ WaitForResult();
+}
+
+TEST_F(MediaStreamManagerTest, MakeAndCancelMediaAccessRequest) {
+ std::string label;
+ MakeMediaAccessRequest(&label);
+ // No callback is expected.
+ media_stream_manager_->CancelRequest(label);
+}
+
+TEST_F(MediaStreamManagerTest, MakeMultipleRequests) {
+ // First request.
+ std::string label1;
+ MakeMediaAccessRequest(&label1);
+
+ // Second request.
+ std::string label2;
+ int render_process_id = 2;
+ int render_view_id = 2;
+ media_stream::StreamOptions components(true, true);
+ GURL security_origin;
+ media_stream::MediaRequestResponseCallback callback =
+ base::Bind(&MediaStreamManagerTest::ResponseCallback,
+ base::Unretained(this));
+ media_stream_manager_->MakeMediaAccessRequest(render_process_id,
+ render_view_id,
+ components,
+ security_origin,
+ callback,
+ &label2);
+
+ // 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);
+ WaitForResult();
+}
+
+TEST_F(MediaStreamManagerTest, MakeAndCancelMultipleRequests) {
+ std::string label1;
+ MakeMediaAccessRequest(&label1);
+ std::string label2;
+ MakeMediaAccessRequest(&label2);
+ media_stream_manager_->CancelRequest(label1);
+
+ // Expecting the callback from the second request will be triggered and
+ // quit the test.
+ EXPECT_CALL(*this, Response(label2));
+ WaitForResult();
+}
+
+} // namespace content
diff --git a/content/browser/renderer_host/media/media_stream_ui_controller.cc b/content/browser/renderer_host/media/media_stream_ui_controller.cc
new file mode 100644
index 0000000..4c99f11
--- /dev/null
+++ b/content/browser/renderer_host/media/media_stream_ui_controller.cc
@@ -0,0 +1,389 @@
+// 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/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"
+
+using content::BrowserThread;
+using content::MediaStreamDevice;
+using content::MediaStreamRequest;
+
+namespace {
+
+// Helper class to handle the callbacks to a MediaStreamUIController instance.
+// This class will make sure that the call to PostResponse is executed on the IO
+// thread (and that the instance of MediaStreamUIController still exists).
+// This allows us to pass a simple base::Callback object to any class that needs
+// to post a response to the MediaStreamUIController object. This logic cannot
+// be implemented inside MediaStreamUIController::PostResponse since that
+// would imply that the WeakPtr<MediaStreamUIController> pointer has been
+// dereferenced already (which would cause an error in the ThreadChecker before
+// we even get there).
+class ResponseCallbackHelper
+ : public base::RefCountedThreadSafe<ResponseCallbackHelper> {
+ public:
+ explicit ResponseCallbackHelper(
+ base::WeakPtr<content::MediaStreamUIController> controller)
+ : controller_(controller) {
+ }
+
+ void PostResponse(const std::string& label,
+ const content::MediaStreamDevices& devices) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&content::MediaStreamUIController::PostResponse,
+ controller_, label, devices));
+ return;
+ } else if (controller_) {
+ controller_->PostResponse(label, devices);
+ }
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<ResponseCallbackHelper>;
+ ~ResponseCallbackHelper() {}
+
+ base::WeakPtr<content::MediaStreamUIController> controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResponseCallbackHelper);
+};
+
+} // namespace
+
+namespace content {
+
+// UI request contains all data needed to keep track of requests between the
+// different calls.
+class MediaStreamRequestForUI : public content::MediaStreamRequest {
+ public:
+ MediaStreamRequestForUI(
+ int render_pid,
+ int render_vid,
+ const GURL& origin,
+ const media_stream::StreamOptions& options)
+ : MediaStreamRequest(render_pid, render_vid, origin),
+ wait_for_audio(IsAudioMediaType(options.audio_type)),
+ wait_for_video(IsVideoMediaType(options.video_type)),
+ posted_task(false) {
+ DCHECK(wait_for_audio || wait_for_video);
+ }
+
+ ~MediaStreamRequestForUI() {}
+
+ bool IsRequestReadyForView() const {
+ if (wait_for_audio || wait_for_video)
+ return false;
+
+ // We have got all the requested devices, it is ready if it has not
+ // been posted for UI yet.
+ return !posted_task;
+ }
+
+ // Flags to indicate if we should wait for enumerated device lists.
+ bool wait_for_audio;
+ bool wait_for_video;
+
+ // 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.
+ content::RenderViewHostImpl* host =
+ content::RenderViewHostImpl::FromID(request.render_process_id,
+ request.render_view_id);
+
+ // Tab may have gone away.
+ if (!host || !host->GetDelegate()) {
+ callback.Run(content::MediaStreamDevices());
+ return;
+ }
+
+ host->GetDelegate()->RequestMediaAccessPermission(&request, callback);
+}
+
+} // namespace
+
+MediaStreamUIController::MediaStreamUIController(
+ media_stream::SettingsRequester* requester)
+ : requester_(requester),
+ use_fake_ui_(false),
+ weak_ptr_factory_(this) {
+ DCHECK(requester_);
+}
+
+MediaStreamUIController::~MediaStreamUIController() {
+ DCHECK(requests_.empty());
+}
+
+void MediaStreamUIController::MakeUIRequest(
+ const std::string& label, int render_process_id, int render_view_id,
+ const media_stream::StreamOptions& request_options,
+ const GURL& security_origin) {
+ 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))).second) {
+ NOTREACHED();
+ }
+}
+
+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);
+ }
+}
+
+void MediaStreamUIController::AddAvailableDevicesToRequest(
+ const std::string& label,
+ MediaStreamDeviceType stream_type,
+ const media_stream::StreamDeviceInfoArray& devices) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ UIRequests::const_iterator request_iter = requests_.find(label);
+ if (request_iter == requests_.end()) {
+ NOTREACHED();
+ return;
+ }
+
+ // Add the available devices to the request.
+ MediaStreamRequestForUI* request = request_iter->second;
+
+ // Create the simplified list of devices.
+ content::MediaStreamDevices& requested_devices =
+ request->devices[stream_type];
+ DCHECK(requested_devices.empty());
+ for (media_stream::StreamDeviceInfoArray::const_iterator it = devices.begin();
+ it != devices.end();
+ ++it) {
+ requested_devices.push_back(MediaStreamDevice(stream_type,
+ it->device_id,
+ it->name));
+ }
+
+ if (IsAudioMediaType(stream_type)) {
+ DCHECK(request->wait_for_audio);
+ request->wait_for_audio = false;
+ } else if (IsVideoMediaType(stream_type)) {
+ DCHECK(request->wait_for_video);
+ request->wait_for_video = false;
+ } else {
+ NOTREACHED();
+ }
+
+ if (request->IsRequestReadyForView()) {
+ 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(request->render_process_id, request->render_view_id))
+ return;
+
+ PostRequestToUI(label);
+ }
+}
+
+void MediaStreamUIController::PostResponse(
+ const std::string& label,
+ const content::MediaStreamDevices& devices) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ UIRequests::iterator request_iter = requests_.find(label);
+ // Return if the request has been removed.
+ if (request_iter == requests_.end())
+ 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.size() > 0) {
+ // Build a list of "full" device objects for the accepted devices.
+ media_stream::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(media_stream::StreamDeviceInfo(
+ dev->type, dev->name, dev->device_id, false));
+ }
+
+ requester_->DevicesAccepted(label, device_list);
+ } else {
+ requester_->SettingsError(label);
+ }
+}
+
+void MediaStreamUIController::NotifyUIIndicatorDevicesOpened(
+ int render_process_id,
+ int render_view_id,
+ const content::MediaStreamDevices& devices) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(!devices.empty());
+ content::MediaObserver* media_observer =
+ content::GetContentClient()->browser()->GetMediaObserver();
+ if (media_observer == NULL)
+ return;
+
+ media_observer->OnCaptureDevicesOpened(render_process_id,
+ render_view_id,
+ devices);
+}
+
+void MediaStreamUIController::NotifyUIIndicatorDevicesClosed(
+ int render_process_id,
+ int render_view_id,
+ const content::MediaStreamDevices& devices) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(!devices.empty());
+ content::MediaObserver* media_observer =
+ content::GetContentClient()->browser()->GetMediaObserver();
+ if (media_observer == NULL)
+ return;
+
+ media_observer->OnCaptureDevicesClosed(render_process_id,
+ render_view_id,
+ devices);
+}
+
+void MediaStreamUIController::UseFakeUI() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ use_fake_ui_ = true;
+}
+
+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->IsRequestReadyForView()) {
+ next_request_label = it->first;
+ break;
+ }
+ }
+ }
+
+ if (next_request_label.empty())
+ return;
+
+ if (use_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;
+
+ scoped_refptr<ResponseCallbackHelper> helper =
+ new ResponseCallbackHelper(weak_ptr_factory_.GetWeakPtr());
+ content::MediaResponseCallback callback =
+ base::Bind(&ResponseCallbackHelper::PostResponse,
+ helper.get(), label);
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&ProceedMediaAccessPermission, *request, callback));
+}
+
+void MediaStreamUIController::PostRequestToFakeUI(const std::string& label) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ UIRequests::iterator request_iter = requests_.find(label);
+ DCHECK(request_iter != requests_.end());
+ MediaStreamRequestForUI* request = request_iter->second;
+ // Used to fake UI, which is needed for server based testing.
+ // Use first device for each media type.
+ MediaStreamDevices devices_to_use;
+ for (MediaStreamDeviceMap::const_iterator it = request->devices.begin();
+ it != request->devices.end(); ++it) {
+ // Use the first capture device in the list for the fake UI.
+ if (!it->second.empty()) {
+ devices_to_use.push_back(it->second.front());
+ }
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&MediaStreamUIController::PostResponse,
+ weak_ptr_factory_.GetWeakPtr(), label, devices_to_use));
+}
+
+} // namespace media_stream
diff --git a/content/browser/renderer_host/media/media_stream_ui_controller.h b/content/browser/renderer_host/media/media_stream_ui_controller.h
new file mode 100644
index 0000000..a7d68dc
--- /dev/null
+++ b/content/browser/renderer_host/media/media_stream_ui_controller.h
@@ -0,0 +1,123 @@
+// 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. AddAvailableDevicesToRequest() is called with a list of currently
+// available devices.
+// 3. Pick device and get user confirmation.
+// 4. Confirm by calling SettingsRequester::DevicesAccepted().
+// Repeat step 1 - 4 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 "base/memory/weak_ptr.h"
+#include "content/browser/renderer_host/media/media_stream_provider.h"
+#include "content/public/browser/web_contents_delegate.h"
+
+
+namespace media_stream {
+class SettingsRequester;
+}
+
+namespace content {
+
+class MediaStreamRequestForUI;
+
+// 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(media_stream::SettingsRequester* requester);
+ virtual ~MediaStreamUIController();
+
+ // Called when a new request for the capture device access is made.
+ // Users are responsbile for cancel 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 media_stream::StreamOptions& stream_components,
+ const GURL& security_origin);
+
+ // 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 pass in an array of available devices for a request represented
+ // by |label|. There could be multiple calls for a request.
+ // TODO(xians): use the monitor to get a up-to-date device list and remove
+ // this API.
+ void AddAvailableDevicesToRequest(
+ const std::string& label,
+ MediaStreamDeviceType stream_type,
+ const media_stream::StreamDeviceInfoArray& devices);
+
+ // Called by the InfoBar when the user grants/denies access to some devices
+ // to the webpage. This is placed here, so the request can be cleared from the
+ // list of pending requests, instead of letting the InfoBar itself respond to
+ // the requester. An empty list of devices means that access has been denied.
+ // This method must be called on the IO thread.
+ void PostResponse(const std::string& label,
+ const content::MediaStreamDevices& devices);
+
+ // Called to signal the UI indicator that the devices are opened.
+ void NotifyUIIndicatorDevicesOpened(
+ int render_process_id,
+ int render_view_id,
+ const content::MediaStreamDevices& devices);
+
+ // Called to signal the UI indicator that the devices are closed.
+ void NotifyUIIndicatorDevicesClosed(
+ int render_process_id,
+ int render_view_id,
+ const content::MediaStreamDevices& devices);
+
+ // 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();
+
+ private:
+ typedef std::map<std::string, MediaStreamRequestForUI*> UIRequests;
+
+ // 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);
+
+ media_stream::SettingsRequester* requester_;
+ UIRequests requests_;
+
+ // See comment above for method UseFakeUI. Used for automated testing.
+ bool use_fake_ui_;
+
+ base::WeakPtrFactory<MediaStreamUIController> weak_ptr_factory_;
+
+ 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_device_settings_unittest.cc b/content/browser/renderer_host/media/media_stream_ui_controller_unittest.cc
index 090a489..214ef16 100644
--- a/content/browser/renderer_host/media/media_stream_device_settings_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_ui_controller_unittest.cc
@@ -7,9 +7,10 @@
#include "base/bind.h"
#include "base/message_loop.h"
#include "content/browser/browser_thread_impl.h"
-#include "content/browser/renderer_host/media/media_stream_device_settings.h"
+#include "content/browser/renderer_host/media/media_stream_ui_controller.h"
#include "content/browser/renderer_host/media/media_stream_settings_requester.h"
#include "content/common/media/media_stream_options.h"
+#include "content/public/common/media_stream_request.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -17,18 +18,17 @@ using content::BrowserThread;
using content::BrowserThreadImpl;
using testing::_;
-namespace media_stream {
+namespace content {
-// Test class.
-class MediaStreamDeviceSettingsTest
+class MediaStreamDeviceUIControllerTest
: public ::testing::Test,
- public SettingsRequester {
+ public media_stream::SettingsRequester {
public:
- MediaStreamDeviceSettingsTest() {}
+ MediaStreamDeviceUIControllerTest() {}
// Mock implementation of SettingsRequester;
- MOCK_METHOD2(DevicesAccepted, void(const std::string&,
- const StreamDeviceInfoArray&));
+ MOCK_METHOD2(DevicesAccepted, void(
+ const std::string&, const media_stream::StreamDeviceInfoArray&));
MOCK_METHOD1(SettingsError, void(const std::string&));
protected:
@@ -38,7 +38,7 @@ class MediaStreamDeviceSettingsTest
message_loop_.get()));
io_thread_.reset(new BrowserThreadImpl(BrowserThread::IO,
message_loop_.get()));
- device_settings_.reset(new MediaStreamDeviceSettings(this));
+ ui_controller_.reset(new content::MediaStreamUIController(this));
}
virtual void TearDown() {
@@ -48,13 +48,13 @@ class MediaStreamDeviceSettingsTest
void CreateDummyRequest(const std::string& label, bool audio, bool video) {
int dummy_render_process_id = 1;
int dummy_render_view_id = 1;
- StreamOptions components(audio, video);
+ media_stream::StreamOptions components(audio, video);
GURL security_origin;
- device_settings_->RequestCaptureDeviceUsage(label,
- dummy_render_process_id,
- dummy_render_view_id,
- components,
- security_origin);
+ ui_controller_->MakeUIRequest(label,
+ dummy_render_process_id,
+ dummy_render_view_id,
+ components,
+ security_origin);
if (audio)
CreateAudioDeviceForRequset(label);
@@ -70,9 +70,10 @@ class MediaStreamDeviceSettingsTest
dummy_audio_device.stream_type = content::MEDIA_DEVICE_AUDIO_CAPTURE;
dummy_audio_device.session_id = 1;
audio_device_array[0] = dummy_audio_device;
- device_settings_->AvailableDevices(label,
- dummy_audio_device.stream_type,
- audio_device_array);
+ ui_controller_->AddAvailableDevicesToRequest(
+ label,
+ dummy_audio_device.stream_type,
+ audio_device_array);
}
void CreateVideoDeviceForRequset(const std::string& label) {
@@ -83,21 +84,22 @@ class MediaStreamDeviceSettingsTest
dummy_video_device.stream_type = content::MEDIA_DEVICE_VIDEO_CAPTURE;
dummy_video_device.session_id = 1;
video_device_array[0] = dummy_video_device;
- device_settings_->AvailableDevices(label,
- dummy_video_device.stream_type,
- video_device_array);
+ ui_controller_->AddAvailableDevicesToRequest(
+ label,
+ dummy_video_device.stream_type,
+ video_device_array);
}
scoped_ptr<MessageLoop> message_loop_;
scoped_ptr<BrowserThreadImpl> ui_thread_;
scoped_ptr<BrowserThreadImpl> io_thread_;
- scoped_ptr<MediaStreamDeviceSettings> device_settings_;
+ scoped_ptr<MediaStreamUIController> ui_controller_;
private:
- DISALLOW_COPY_AND_ASSIGN(MediaStreamDeviceSettingsTest);
+ DISALLOW_COPY_AND_ASSIGN(MediaStreamDeviceUIControllerTest);
};
-TEST_F(MediaStreamDeviceSettingsTest, GenerateRequest) {
+TEST_F(MediaStreamDeviceUIControllerTest, GenerateRequest) {
const std::string label = "dummy_label";
CreateDummyRequest(label, true, false);
@@ -106,16 +108,16 @@ TEST_F(MediaStreamDeviceSettingsTest, GenerateRequest) {
EXPECT_CALL(*this, SettingsError(label));
}
-TEST_F(MediaStreamDeviceSettingsTest, GenerateAndRemoveRequest) {
+TEST_F(MediaStreamDeviceUIControllerTest, GenerateAndRemoveRequest) {
const std::string label = "label";
CreateDummyRequest(label, true, false);
// Remove the current request, it should not crash.
- device_settings_->RemovePendingCaptureRequest(label);
+ ui_controller_->CancelUIRequest(label);
}
-TEST_F(MediaStreamDeviceSettingsTest, HandleRequestUsingFakeUI) {
- device_settings_->UseFakeUI();
+TEST_F(MediaStreamDeviceUIControllerTest, HandleRequestUsingFakeUI) {
+ ui_controller_->UseFakeUI();
const std::string label = "label";
CreateDummyRequest(label, true, true);
@@ -124,8 +126,8 @@ TEST_F(MediaStreamDeviceSettingsTest, HandleRequestUsingFakeUI) {
EXPECT_CALL(*this, DevicesAccepted(label, _));
}
-TEST_F(MediaStreamDeviceSettingsTest, CreateMultipleRequestsAndCancelTheFirst) {
- device_settings_->UseFakeUI();
+TEST_F(MediaStreamDeviceUIControllerTest, CreateRequestsAndCancelTheFirst) {
+ ui_controller_->UseFakeUI();
// Create the first audio request.
const std::string label_1 = "label_1";
@@ -140,15 +142,15 @@ TEST_F(MediaStreamDeviceSettingsTest, CreateMultipleRequestsAndCancelTheFirst) {
CreateDummyRequest(label_3, true, true);
// Remove the first request which has been brought to the UI.
- device_settings_->RemovePendingCaptureRequest(label_1);
+ ui_controller_->CancelUIRequest(label_1);
// We should get callbacks from the rest of the requests.
EXPECT_CALL(*this, DevicesAccepted(label_2, _));
EXPECT_CALL(*this, DevicesAccepted(label_3, _));
}
-TEST_F(MediaStreamDeviceSettingsTest, CreateMultipleRequestsAndCancelTheLast) {
- device_settings_->UseFakeUI();
+TEST_F(MediaStreamDeviceUIControllerTest, CreateRequestsAndCancelTheLast) {
+ ui_controller_->UseFakeUI();
// Create the first audio request.
const std::string label_1 = "label_1";
@@ -163,7 +165,7 @@ TEST_F(MediaStreamDeviceSettingsTest, CreateMultipleRequestsAndCancelTheLast) {
CreateDummyRequest(label_3, true, true);
// Remove the last request which is pending in the queue.
- device_settings_->RemovePendingCaptureRequest(label_3);
+ ui_controller_->CancelUIRequest(label_3);
// We should get callbacks from the rest of the requests.
EXPECT_CALL(*this, DevicesAccepted(label_1, _));
diff --git a/content/browser/speech/speech_recognition_manager_impl.cc b/content/browser/speech/speech_recognition_manager_impl.cc
index 27fda13..16c85a8 100644
--- a/content/browser/speech/speech_recognition_manager_impl.cc
+++ b/content/browser/speech/speech_recognition_manager_impl.cc
@@ -81,7 +81,7 @@ class SpeechRecognitionManagerImpl::PermissionRequest
void Abort() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
started_ = false;
- BrowserMainLoop::GetMediaStreamManager()->CancelGenerateStream(label_);
+ BrowserMainLoop::GetMediaStreamManager()->CancelRequest(label_);
}
int Session() const { return session_id_; }
diff --git a/content/common/media/media_stream_options.h b/content/common/media/media_stream_options.h
index 5c7d2ac..0256dd1 100644
--- a/content/common/media/media_stream_options.h
+++ b/content/common/media/media_stream_options.h
@@ -8,6 +8,7 @@
#include <string>
#include <vector>
+#include "base/callback.h"
#include "content/common/content_export.h"
#include "content/public/common/media_stream_request.h"
@@ -20,6 +21,12 @@ CONTENT_EXPORT extern const char kMediaStreamSourceTab[];
typedef content::MediaStreamDeviceType MediaStreamType;
+// 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 content::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 735c847..640d5c3 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -603,8 +603,6 @@
'browser/renderer_host/media/audio_renderer_host.h',
'browser/renderer_host/media/audio_sync_reader.cc',
'browser/renderer_host/media/audio_sync_reader.h',
- 'browser/renderer_host/media/media_stream_device_settings.cc',
- 'browser/renderer_host/media/media_stream_device_settings.h',
'browser/renderer_host/media/media_stream_dispatcher_host.cc',
'browser/renderer_host/media/media_stream_dispatcher_host.h',
'browser/renderer_host/media/media_stream_manager.cc',
@@ -612,6 +610,8 @@
'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/video_capture_controller.cc',
'browser/renderer_host/media/video_capture_controller_event_handler.cc',
'browser/renderer_host/media/video_capture_controller_event_handler.h',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 5a34ae6..6d1e64f 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -293,8 +293,9 @@
'browser/renderer_host/gtk_key_bindings_handler_unittest.cc',
'browser/renderer_host/media/audio_input_device_manager_unittest.cc',
'browser/renderer_host/media/audio_renderer_host_unittest.cc',
- 'browser/renderer_host/media/media_stream_device_settings_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_controller_unittest.cc',
'browser/renderer_host/media/video_capture_host_unittest.cc',
'browser/renderer_host/media/video_capture_manager_unittest.cc',