summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormflodman@google.com <mflodman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-07 13:05:20 +0000
committermflodman@google.com <mflodman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-07 13:05:20 +0000
commitaf8b9b1a0afeeb7559ff53cf3fe08f99a32ed4df (patch)
tree6b44b252ccbcc0cfcabd7099a5ad4c502d1f9766
parentaebdd074d36cec14457d72889db06bf210d77909 (diff)
downloadchromium_src-af8b9b1a0afeeb7559ff53cf3fe08f99a32ed4df.zip
chromium_src-af8b9b1a0afeeb7559ff53cf3fe08f99a32ed4df.tar.gz
chromium_src-af8b9b1a0afeeb7559ff53cf3fe08f99a32ed4df.tar.bz2
Adding MediaStreamManager.
MediaStreamManager will get requests to open capture devices, normally from WebKit. MediaStreamManager will ask for user permission and then call the proper device manager to open the user specified device. MediaStreamManager now owns VideoCaptureManager, which introduces changes to VideoCaptureManager and test related to VideoCaptureManager. TODO: Find out who should own MediaStreamManager. Temporary for testing and to not block development, this is now a singleton. This will change... The next MediaStream patch, MediaStreamDispatcherHost, will contain test including MediaStreamManager. Review URL: http://codereview.chromium.org/7284037 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@91696 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/browser/renderer_host/media/media_stream_device_settings.cc5
-rw-r--r--content/browser/renderer_host/media/media_stream_manager.cc426
-rw-r--r--content/browser/renderer_host/media/media_stream_manager.h132
-rw-r--r--content/browser/renderer_host/media/media_stream_requester.h39
-rw-r--r--content/browser/renderer_host/media/media_stream_settings_requester.h5
-rw-r--r--content/browser/renderer_host/media/video_capture_controller.cc10
-rw-r--r--content/browser/renderer_host/media/video_capture_host_unittest.cc15
-rw-r--r--content/browser/renderer_host/media/video_capture_manager.cc7
-rw-r--r--content/browser/renderer_host/media/video_capture_manager.h11
-rw-r--r--content/browser/renderer_host/media/video_capture_manager_unittest.cc87
-rw-r--r--content/common/media/media_stream_options.h3
-rw-r--r--content/content_browser.gypi3
12 files changed, 656 insertions, 87 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
index 86d397d..096e5c8 100644
--- a/content/browser/renderer_host/media/media_stream_device_settings.cc
+++ b/content/browser/renderer_host/media/media_stream_device_settings.cc
@@ -44,7 +44,6 @@ MediaStreamDeviceSettings::MediaStreamDeviceSettings(
}
MediaStreamDeviceSettings::~MediaStreamDeviceSettings() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
STLDeleteValues(&requests_);
}
@@ -55,7 +54,7 @@ void MediaStreamDeviceSettings::RequestCaptureDeviceUsage(
if (requests_.find(label) != requests_.end()) {
// Request with this id already exists.
- requester_->Error(label);
+ requester_->SettingsError(label);
return;
}
@@ -81,7 +80,7 @@ void MediaStreamDeviceSettings::AvailableDevices(
SettingsRequests::iterator request_it = requests_.find(label);
if (request_it == requests_.end()) {
// Request with this id doesn't exist.
- requester_->Error(label);
+ requester_->SettingsError(label);
return;
}
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
new file mode 100644
index 0000000..e9c49f1
--- /dev/null
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -0,0 +1,426 @@
+// Copyright (c) 2011 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_manager.h"
+
+#include <list>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/rand_util.h"
+#include "content/browser/browser_thread.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/video_capture_manager.h"
+#include "content/common/media/media_stream_options.h"
+
+namespace media_stream {
+
+// TODO(mflodman) Find out who should own MediaStreamManager.
+base::LazyInstance<MediaStreamManager> g_media_stream_manager(
+ base::LINKER_INITIALIZED);
+
+// Creates a random label used to identify requests.
+static std::string RandomLabel() {
+ // Alphbet according to WhatWG standard, i.e. containing 36 characters from
+ // range: U+0021, U+0023 to U+0027, U+002A to U+002B, U+002D to U+002E,
+ // U+0030 to U+0039, U+0041 to U+005A, U+005E to U+007E.
+ static const char alphabet[] = "!#$%&\'*+-.0123456789"
+ "abcdefghijklmnopqrstuvwxyz^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~";
+
+ std::string label(36, ' ');
+ for (size_t i = 0; i < label.size(); ++i) {
+ int random_char = base::RandGenerator(sizeof(alphabet) - 1);
+ label[i] = alphabet[random_char];
+ }
+ return label;
+}
+
+// Helper to verify if a media stream type is part of options or not.
+static bool Requested(const StreamOptions& options,
+ MediaStreamType stream_type) {
+ if (stream_type == kVideoCapture &&
+ (options.video_option != StreamOptions::kNoCamera)) {
+ return true;
+ } else if (stream_type == kAudioCapture && options.audio == true) {
+ return true;
+ }
+ return false;
+}
+
+MediaStreamManager* MediaStreamManager::Get() {
+ return g_media_stream_manager.Pointer();
+}
+
+MediaStreamManager::~MediaStreamManager() {
+ delete device_settings_;
+ delete video_capture_manager_;
+}
+
+VideoCaptureManager* MediaStreamManager::video_capture_manager() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ return video_capture_manager_;
+}
+
+void MediaStreamManager::GenerateStream(MediaStreamRequester* requester,
+ int render_process_id,
+ int render_view_id,
+ const StreamOptions& options,
+ const std::string& security_origin,
+ std::string* label) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ // TODO(mflodman) Remove next line when audio is supported.
+ (const_cast<StreamOptions&>(options)).audio = false;
+
+ // Create a new request based on options.
+ DeviceRequest new_request = DeviceRequest(requester, options);
+ if (Requested(new_request.options, kAudioCapture)) {
+ new_request.state[kAudioCapture] = DeviceRequest::kRequested;
+ }
+ if (Requested(new_request.options, kVideoCapture)) {
+ new_request.state[kVideoCapture] = DeviceRequest::kRequested;
+ }
+
+ // Create a label for this request and verify it is unique.
+ std::string request_label;
+ do {
+ request_label = RandomLabel();
+ } while (requests_.find(request_label) != requests_.end());
+
+ requests_.insert(std::make_pair(request_label, new_request));
+
+ // Get user confirmation to use capture devices.
+ device_settings_->RequestCaptureDeviceUsage(request_label, render_process_id,
+ render_view_id, options,
+ security_origin);
+ (*label) = request_label;
+}
+
+void MediaStreamManager::CancelRequests(MediaStreamRequester* requester) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DeviceRequests::iterator it = requests_.begin();
+ while (it != requests_.end()) {
+ if (it->second.requester == requester && !RequestDone(it->second)) {
+ // The request isn't complete, but there might be some devices already
+ // opened -> close them.
+ DeviceRequest* request = &(it->second);
+ if (request->state[kAudioCapture] == DeviceRequest::kOpening) {
+ for (StreamDeviceInfoArray::iterator it =
+ request->audio_devices.begin(); it != request->audio_devices.end();
+ ++it) {
+ if (it->in_use == true) {
+ // TODO(mflodman) Add when audio input device manager is available.
+ }
+ }
+ }
+ if (request->state[kVideoCapture] == DeviceRequest::kOpening) {
+ for (StreamDeviceInfoArray::iterator it =
+ request->video_devices.begin(); it != request->video_devices.end();
+ ++it) {
+ if (it->in_use == true) {
+ video_capture_manager_->Close(it->session_id);
+ }
+ }
+ }
+ requests_.erase(it++);
+ } else {
+ ++it;
+ }
+ }
+}
+
+void MediaStreamManager::StopGeneratedStream(const std::string& label) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // Find the request and close all open devices for the request.
+ DeviceRequests::iterator it = requests_.find(label);
+ if (it != requests_.end()) {
+ for (StreamDeviceInfoArray::iterator audio_it =
+ it->second.audio_devices.begin();
+ audio_it != it->second.audio_devices.end(); ++audio_it) {
+ // TODO(mflodman) Add code when audio input manager exists.
+ NOTREACHED();
+ }
+ for (StreamDeviceInfoArray::iterator video_it =
+ it->second.video_devices.begin();
+ video_it != it->second.video_devices.end(); ++video_it) {
+ video_capture_manager_->Close(video_it->session_id);
+ }
+ requests_.erase(it);
+ return;
+ }
+}
+
+void MediaStreamManager::Opened(MediaStreamType stream_type,
+ int capture_session_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ // Find the request containing this device and mark it as used.
+ DeviceRequest* request = NULL;
+ StreamDeviceInfoArray* devices = NULL;
+ std::string label;
+ for (DeviceRequests::iterator request_it = requests_.begin();
+ request_it != requests_.end() && request == NULL; ++request_it) {
+ if (stream_type == kAudioCapture) {
+ devices = &(request_it->second.audio_devices);
+ } else if (stream_type == kVideoCapture) {
+ devices = &(request_it->second.video_devices);
+ } else {
+ NOTREACHED();
+ }
+
+ for (StreamDeviceInfoArray::iterator device_it = devices->begin();
+ device_it != devices->end(); ++device_it) {
+ if (device_it->session_id == capture_session_id) {
+ // We've found the request.
+ device_it->in_use = true;
+ label = request_it->first;
+ request = &(request_it->second);
+ break;
+ }
+ }
+ }
+ if (request == NULL) {
+ // The request doesn't exist.
+ return;
+ }
+
+ DCHECK_NE(request->state[stream_type], DeviceRequest::kRequested);
+
+ // Check if all devices for this stream type are opened. Update the state if
+ // they are.
+ for (StreamDeviceInfoArray::iterator device_it = devices->begin();
+ device_it != devices->end(); ++device_it) {
+ if (device_it->in_use == false) {
+ // Wait for more devices to be opened before we're done.
+ return;
+ }
+ }
+ request->state[stream_type] = DeviceRequest::kDone;
+
+ if (!RequestDone(*request)) {
+ // This stream_type is done, but not the other type.
+ return;
+ }
+
+ request->requester->StreamGenerated(label, request->audio_devices,
+ request->video_devices);
+}
+
+void MediaStreamManager::Closed(MediaStreamType stream_type,
+ int capture_session_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+}
+
+void MediaStreamManager::DevicesEnumerated(
+ MediaStreamType stream_type, const StreamDeviceInfoArray& devices) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ // Publish the result for all requests waiting for device list(s).
+ // Find the requests waiting for this device list, store their labels and
+ // release the iterator before calling device settings. We might get a call
+ // back from device_settings that will need to iterate through devices.
+ std::list<std::string> label_list;
+ for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end();
+ ++it) {
+ if (it->second.state[stream_type] == DeviceRequest::kRequested &&
+ Requested(it->second.options, stream_type)) {
+ label_list.push_back(it->first);
+ }
+ }
+ for (std::list<std::string>::iterator it = label_list.begin();
+ it != label_list.end(); ++it) {
+ device_settings_->AvailableDevices(*it, stream_type, devices);
+ }
+ label_list.clear();
+ enumeration_in_progress_[stream_type] = false;
+}
+
+void MediaStreamManager::Error(MediaStreamType stream_type,
+ int capture_session_id,
+ MediaStreamProviderError error) {
+ // Find the device for the error call.
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end();
+ ++it) {
+ StreamDeviceInfoArray* devices = NULL;
+ if (stream_type == kAudioCapture) {
+ devices = &(it->second.audio_devices);
+ } else if (stream_type == kVideoCapture) {
+ devices = &(it->second.video_devices);
+ } else {
+ NOTREACHED();
+ }
+
+ int device_idx = 0;
+ for (StreamDeviceInfoArray::iterator device_it = devices->begin();
+ device_it != devices->end(); ++device_it, ++device_idx) {
+ if (device_it->session_id == capture_session_id) {
+ // We've found the failing device. Find the error case:
+ if (it->second.state[stream_type] == DeviceRequest::kDone) {
+ // 1. Already opened -> signal device failure and close device.
+ // Use device_idx to signal which of the devices encountered an
+ // error.
+ if (stream_type == kAudioCapture) {
+ it->second.requester->AudioDeviceFailed(it->first, device_idx);
+ } else if (stream_type == kVideoCapture) {
+ it->second.requester->VideoDeviceFailed(it->first, device_idx);
+ }
+ GetDeviceManager(stream_type)->Close(capture_session_id);
+ devices->erase(device_it);
+ } else if (it->second.audio_devices.size()
+ + it->second.video_devices.size() <= 1) {
+ // 2. Device not opened and no other devices for this request ->
+ // signal stream error and remove the request.
+ it->second.requester->StreamGenerationFailed(it->first);
+ requests_.erase(it);
+ } else {
+ // 3. Not opened but other devices exists for this request -> remove
+ // device from list, but don't signal an error.
+ devices->erase(device_it);
+ }
+ return;
+ }
+ }
+ }
+}
+
+void MediaStreamManager::GetDevices(const std::string& label,
+ MediaStreamType stream_type) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (!enumeration_in_progress_[stream_type]) {
+ enumeration_in_progress_[stream_type] = true;
+ GetDeviceManager(stream_type)->EnumerateDevices();
+ }
+}
+
+void MediaStreamManager::DevicesAccepted(const std::string& label,
+ const StreamDeviceInfoArray& devices) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DeviceRequests::iterator request_it = requests_.find(label);
+ if (request_it != requests_.end()) {
+ if (devices.empty()) {
+ // No available devices or user didn't accept device usage.
+ request_it->second.requester->StreamGenerationFailed(request_it->first);
+ requests_.erase(request_it);
+ return;
+ }
+
+ // Loop through all device types for this request.
+ for (StreamDeviceInfoArray::const_iterator device_it = devices.begin();
+ device_it != devices.end(); ++device_it) {
+ StreamDeviceInfo device_info = *device_it;
+
+ // Set in_use to false to be able to track if this device has been
+ // opened. in_use might be true if the device type can be used in more
+ // than one session.
+ device_info.in_use = false;
+ device_info.session_id =
+ GetDeviceManager(device_info.stream_type)->Open(device_info);
+ request_it->second.state[device_it->stream_type] =
+ DeviceRequest::kOpening;
+ if (device_info.stream_type == kAudioCapture) {
+ request_it->second.audio_devices.push_back(device_info);
+ } else if (device_info.stream_type == kVideoCapture) {
+ request_it->second.video_devices.push_back(device_info);
+ } else {
+ NOTREACHED();
+ }
+ }
+ // Check if we received all stream types requested.
+ if (Requested(request_it->second.options, kAudioCapture) &&
+ request_it->second.audio_devices.size() == 0) {
+ request_it->second.state[kAudioCapture] = DeviceRequest::kError;
+ }
+ if (Requested(request_it->second.options, kVideoCapture) &&
+ request_it->second.video_devices.size() == 0) {
+ request_it->second.state[kVideoCapture] = DeviceRequest::kError;
+ }
+ return;
+ }
+}
+
+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()) {
+ it->second.requester->StreamGenerationFailed(label);
+ requests_.erase(it);
+ return;
+ }
+}
+
+void MediaStreamManager::UseFakeDevice() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ video_capture_manager_->UseFakeDevice();
+ // TODO(mflodman) Add audio manager when available.
+}
+
+bool MediaStreamManager::RequestDone(const DeviceRequest& request) const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // Check if all devices are opened.
+ if (Requested(request.options, kAudioCapture)) {
+ for (StreamDeviceInfoArray::const_iterator it =
+ request.audio_devices.begin(); it != request.audio_devices.end();
+ ++it) {
+ if (it->in_use == false) {
+ return false;
+ }
+ }
+ }
+ if (Requested(request.options, kVideoCapture)) {
+ for (StreamDeviceInfoArray::const_iterator it =
+ request.video_devices.begin(); it != request.video_devices.end();
+ ++it) {
+ if (it->in_use == false) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+// Called to get media capture device manager of specified type.
+MediaStreamProvider* MediaStreamManager::GetDeviceManager(
+ MediaStreamType stream_type) const {
+ if (stream_type == kVideoCapture) {
+ return video_capture_manager_;
+ } else if (stream_type == kAudioCapture) {
+ // TODO(mflodman) Add support when audio input manager is available.
+ NOTREACHED();
+ return NULL;
+ }
+ NOTREACHED();
+ return NULL;
+}
+
+MediaStreamManager::MediaStreamManager()
+ : video_capture_manager_(new VideoCaptureManager()),
+ enumeration_in_progress_(kNumMediaStreamTypes, false),
+ requests_(),
+ device_settings_(NULL) {
+ device_settings_ = new MediaStreamDeviceSettings(this);
+ video_capture_manager_->Register(this);
+ // TODO(mflodman) Add when audio input manager is available.
+}
+
+MediaStreamManager::DeviceRequest::DeviceRequest()
+ : requester(NULL),
+ state(kNumMediaStreamTypes, kNotRequested) {
+ options.audio = false;
+ options.video_option = StreamOptions::kNoCamera;
+}
+
+MediaStreamManager::DeviceRequest::DeviceRequest(
+ MediaStreamRequester* requester, const StreamOptions& request_options)
+ : requester(requester),
+ options(request_options),
+ state(kNumMediaStreamTypes, kNotRequested) {
+ DCHECK(requester);
+}
+
+MediaStreamManager::DeviceRequest::~DeviceRequest() {}
+
+} // namespace media_stream
diff --git a/content/browser/renderer_host/media/media_stream_manager.h b/content/browser/renderer_host/media/media_stream_manager.h
new file mode 100644
index 0000000..108cafe
--- /dev/null
+++ b/content/browser/renderer_host/media/media_stream_manager.h
@@ -0,0 +1,132 @@
+// Copyright (c) 2011 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.
+
+// MediaStreamManager is used to open media capture devices (video 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
+// use devices and for which device to use.
+// 3. MediaStreamDeviceSettings will request list(s) of available devices, the
+// requests will be relayed to the corresponding media device manager and 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.
+// 5. MediaStreamManager will call the proper media device manager to open the
+// device and let the MediaStreamRequester know it has been done.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_MANAGER_H_
+#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_MANAGER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/lazy_instance.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"
+
+namespace media_stream {
+
+class MediaStreamDeviceSettings;
+class MediaStreamRequester;
+class VideoCaptureManager;
+
+// MediaStreamManager is used to generate and close new media devices, not to
+// start the media flow.
+// The classes requesting new media streams are answered using
+// MediaStreamManager::Listener.
+class MediaStreamManager : public MediaStreamProviderListener,
+ public SettingsRequester {
+ public:
+ typedef MediaStreamManager* (AccessorMethod)();
+ static MediaStreamManager* Get();
+ virtual ~MediaStreamManager();
+
+ // Used to access VideoCaptuerManager.
+ VideoCaptureManager* video_capture_manager();
+
+ // GenerateStream opens new media devices according to |components|. The
+ // request is identified using |label|, which is pointing to an already
+ // created std::string.
+ void GenerateStream(MediaStreamRequester* requester, int render_process_id,
+ int render_view_id, const StreamOptions& options,
+ const std::string& security_origin, std::string* label);
+
+ // Cancels all non-finished GenerateStream request, i.e. request for which
+ // StreamGenerated hasn't been called.
+ void CancelRequests(MediaStreamRequester* requester);
+
+ // Closes generated stream.
+ void StopGeneratedStream(const std::string& label);
+
+ // Implements MediaStreamProviderListener.
+ virtual void Opened(MediaStreamType stream_type, int capture_session_id);
+ virtual void Closed(MediaStreamType stream_type, int capture_session_id);
+ virtual void DevicesEnumerated(MediaStreamType stream_type,
+ const StreamDeviceInfoArray& devices);
+ virtual void Error(MediaStreamType stream_type, int capture_session_id,
+ MediaStreamProviderError error);
+
+ // Implements SettingsRequester.
+ virtual void GetDevices(const std::string& label,
+ MediaStreamType stream_type);
+ virtual void DevicesAccepted(const std::string& label,
+ const StreamDeviceInfoArray& devices);
+ virtual void SettingsError(const std::string& label);
+
+ // Used by unit test to make sure fake devices are used instead of a real
+ // devices, which is needed for server based testing.
+ void UseFakeDevice();
+
+ private:
+ // Contains all data needed to keep track of requests.
+ struct DeviceRequest {
+ DeviceRequest();
+ DeviceRequest(MediaStreamRequester* requester,
+ const StreamOptions& request_options);
+ ~DeviceRequest();
+ enum RequestState {
+ kNotRequested = 0,
+ kRequested,
+ kOpening,
+ kDone,
+ kError
+ };
+
+ MediaStreamRequester* requester;
+ StreamOptions options;
+ std::vector<RequestState> state;
+ StreamDeviceInfoArray audio_devices;
+ StreamDeviceInfoArray video_devices;
+ };
+
+ // Helpers.
+ bool RequestDone(const MediaStreamManager::DeviceRequest& request) const;
+ MediaStreamProvider* GetDeviceManager(MediaStreamType stream_type) const;
+
+ // Private constructor to enforce singleton.
+ friend struct base::DefaultLazyInstanceTraits<MediaStreamManager>;
+ MediaStreamManager();
+
+ VideoCaptureManager* video_capture_manager_;
+ // TODO(mflodman) Add AudioInputManager.
+
+ // Keeps track of device types currently being enumerated to not enumerate
+ // when not necessary.
+ std::vector<bool> enumeration_in_progress_;
+
+ // All non-closed request.
+ typedef std::map<std::string, DeviceRequest> DeviceRequests;
+ DeviceRequests requests_;
+
+ MediaStreamDeviceSettings* device_settings_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaStreamManager);
+};
+
+} // namespace media_stream
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_MANAGER_H_
diff --git a/content/browser/renderer_host/media/media_stream_requester.h b/content/browser/renderer_host/media/media_stream_requester.h
new file mode 100644
index 0000000..da879fa5
--- /dev/null
+++ b/content/browser/renderer_host/media/media_stream_requester.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2011 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_REQUESTER_H_
+#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_REQUESTER_H_
+
+#include <string>
+
+#include "content/common/media/media_stream_options.h"
+
+namespace media_stream {
+
+// MediaStreamRequester must be implemented by the class requesting a new media
+// stream to be opened. MediaStreamManager will use this interface to signal
+// success and error for a request.
+class MediaStreamRequester {
+ public:
+ // Called as a reply of a successful call to GenerateStream.
+ virtual void StreamGenerated(const std::string& label,
+ const StreamDeviceInfoArray& audio_devices,
+ const StreamDeviceInfoArray& video_devices) = 0;
+ // Called if GenerateStream failed.
+ virtual void StreamGenerationFailed(const std::string& label) = 0;
+ // AudioDeviceFailed is called if an already opened audio device encounters
+ // an error.
+ virtual void AudioDeviceFailed(const std::string& label, int index) = 0;
+ // VideoDeviceFailed is called if an already opened video device encounters
+ // an error.
+ virtual void VideoDeviceFailed(const std::string& label, int index) = 0;
+
+ protected:
+ virtual ~MediaStreamRequester() {
+ }
+};
+
+} // namespace media_stream
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_REQUESTER_H_
diff --git a/content/browser/renderer_host/media/media_stream_settings_requester.h b/content/browser/renderer_host/media/media_stream_settings_requester.h
index 46e2540..267cc95 100644
--- a/content/browser/renderer_host/media/media_stream_settings_requester.h
+++ b/content/browser/renderer_host/media/media_stream_settings_requester.h
@@ -7,7 +7,6 @@
#include <string>
-#include "base/task.h"
#include "content/common/media/media_stream_options.h"
namespace media_stream {
@@ -27,7 +26,7 @@ class SettingsRequester {
const StreamDeviceInfoArray& devices) = 0;
// An error for specified |request_id| has occurred.
- virtual void Error(const std::string& label) = 0;
+ virtual void SettingsError(const std::string& label) = 0;
protected:
virtual ~SettingsRequester() {}
@@ -35,6 +34,4 @@ class SettingsRequester {
} // namespace media_stream
-DISABLE_RUNNABLE_METHOD_REFCOUNT(media_stream::SettingsRequester);
-
#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_SETTINGS_REQUESTER_H_
diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc
index 8eb4ca5..7d84ea1 100644
--- a/content/browser/renderer_host/media/video_capture_controller.cc
+++ b/content/browser/renderer_host/media/video_capture_controller.cc
@@ -6,6 +6,7 @@
#include "base/stl_util-inl.h"
#include "content/browser/browser_thread.h"
+#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/browser/renderer_host/media/video_capture_manager.h"
#include "media/base/yuv_convert.h"
@@ -34,8 +35,8 @@ void VideoCaptureController::StartCapture(
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
params_ = params;
- media_stream::VideoCaptureManager* manager =
- media_stream::VideoCaptureManager::Get();
+ media_stream::VideoCaptureManager* manager =
+ media_stream::MediaStreamManager::Get()->video_capture_manager();
// Order the manager to start the actual capture.
manager->Start(params, this);
}
@@ -44,7 +45,7 @@ void VideoCaptureController::StopCapture(Task* stopped_task) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
media_stream::VideoCaptureManager* manager =
- media_stream::VideoCaptureManager::Get();
+ media_stream::MediaStreamManager::Get()->video_capture_manager();
manager->Stop(params_.session_id,
NewRunnableMethod(this,
&VideoCaptureController::OnDeviceStopped,
@@ -156,7 +157,8 @@ void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data,
void VideoCaptureController::OnError() {
event_handler_->OnError(id_);
- media_stream::VideoCaptureManager::Get()->Error(params_.session_id);
+ media_stream::MediaStreamManager::Get()->video_capture_manager()->
+ Error(params_.session_id);
}
void VideoCaptureController::OnFrameInfo(
diff --git a/content/browser/renderer_host/media/video_capture_host_unittest.cc b/content/browser/renderer_host/media/video_capture_host_unittest.cc
index 0ba1262..088e2f3 100644
--- a/content/browser/renderer_host/media/video_capture_host_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_host_unittest.cc
@@ -12,6 +12,7 @@
#include "base/stl_util-inl.h"
#include "base/stringprintf.h"
#include "content/browser/browser_thread.h"
+#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/browser/renderer_host/media/video_capture_host.h"
#include "content/browser/renderer_host/media/video_capture_manager.h"
#include "content/common/media/video_capture_messages.h"
@@ -187,15 +188,15 @@ class VideoCaptureHostTest : public testing::Test {
protected:
virtual void SetUp() {
+ // Create a message loop so VideoCaptureHostTest can use it.
+ message_loop_.reset(new MessageLoop(MessageLoop::TYPE_IO));
+ io_thread_.reset(new BrowserThread(BrowserThread::IO, message_loop_.get()));
// Setup the VideoCaptureManager to use fake video capture device.
#ifndef TEST_REAL_CAPTURE_DEVICE
media_stream::VideoCaptureManager* manager =
- media_stream::VideoCaptureManager::Get();
+ media_stream::MediaStreamManager::Get()->video_capture_manager();
manager->UseFakeDevice();
#endif
- // Create a message loop so VideoCaptureHostTest can use it.
- message_loop_.reset(new MessageLoop(MessageLoop::TYPE_IO));
- io_thread_.reset(new BrowserThread(BrowserThread::IO, message_loop_.get()));
host_ = new MockVideoCaptureHost();
// Simulate IPC channel connected.
@@ -231,8 +232,10 @@ class VideoCaptureHostTest : public testing::Test {
// Called on the main thread.
static void PostQuitOnVideoCaptureManagerThread(MessageLoop* message_loop) {
- media_stream::VideoCaptureManager::Get()->GetMessageLoop()->PostTask(
- FROM_HERE, NewRunnableFunction(&PostQuitMessageLoop, message_loop));
+ media_stream::MediaStreamManager::Get()->video_capture_manager()->
+ GetMessageLoop()->PostTask(FROM_HERE,
+ NewRunnableFunction(
+ &PostQuitMessageLoop, message_loop));
}
// SyncWithVideoCaptureManagerThread() waits until all pending tasks on the
diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/video_capture_manager.cc
index a6dafd0..0571b3f 100644
--- a/content/browser/renderer_host/media/video_capture_manager.cc
+++ b/content/browser/renderer_host/media/video_capture_manager.cc
@@ -16,13 +16,6 @@ namespace media_stream {
// explicitly calling open device.
enum { kFirstSessionId = VideoCaptureManager::kStartOpenSessionId + 1 };
-static ::base::LazyInstance<VideoCaptureManager> g_video_capture_manager(
- base::LINKER_INITIALIZED);
-
-VideoCaptureManager* VideoCaptureManager::Get() {
- return g_video_capture_manager.Pointer();
-}
-
VideoCaptureManager::VideoCaptureManager()
: vc_device_thread_("VideoCaptureManagerThread"),
listener_(NULL),
diff --git a/content/browser/renderer_host/media/video_capture_manager.h b/content/browser/renderer_host/media/video_capture_manager.h
index 751a3bf..581efa6 100644
--- a/content/browser/renderer_host/media/video_capture_manager.h
+++ b/content/browser/renderer_host/media/video_capture_manager.h
@@ -12,7 +12,6 @@
#include <map>
-#include "base/lazy_instance.h"
#include "base/threading/thread.h"
#include "content/browser/renderer_host/media/media_stream_provider.h"
#include "content/common/media/media_stream_options.h"
@@ -29,8 +28,8 @@ class VideoCaptureManager : public MediaStreamProvider {
// before MediaStream is implemented in Chrome and WebKit.
enum { kStartOpenSessionId = 1 };
- // Called to get a pointer to the singleton.
- static VideoCaptureManager* Get();
+ VideoCaptureManager();
+ virtual ~VideoCaptureManager();
// Implements MediaStreamProvider.
virtual void Register(MediaStreamProviderListener* listener);
@@ -59,8 +58,6 @@ class VideoCaptureManager : public MediaStreamProvider {
// won't stream any more captured frames.
void Error(const media::VideoCaptureSessionId& capture_session_id);
- virtual ~VideoCaptureManager();
-
// Used by unit test to make sure a fake device is used instead of a real
// video capture device. Due to timing requirements, the function must be
// called before EnumerateDevices and Open.
@@ -68,10 +65,6 @@ class VideoCaptureManager : public MediaStreamProvider {
MessageLoop* GetMessageLoop();
private:
- friend struct base::DefaultLazyInstanceTraits<VideoCaptureManager>;
-
- VideoCaptureManager();
-
// Called by the public functions, executed on vc_device_thread_.
void OnEnumerateDevices();
void OnOpen(int capture_session_id, const StreamDeviceInfo& device);
diff --git a/content/browser/renderer_host/media/video_capture_manager_unittest.cc b/content/browser/renderer_host/media/video_capture_manager_unittest.cc
index 348c2a6..1a4b7a0 100644
--- a/content/browser/renderer_host/media/video_capture_manager_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_manager_unittest.cc
@@ -69,7 +69,8 @@ class MockFrameObserver: public media::VideoCaptureDevice::EventHandler {
class VideoCaptureManagerTest : public testing::Test {
public:
VideoCaptureManagerTest()
- : listener_(),
+ : vcm_(),
+ listener_(),
message_loop_(),
io_thread_(),
frame_observer_() {
@@ -81,6 +82,9 @@ class VideoCaptureManagerTest : public testing::Test {
listener_.reset(new media_stream::MockMediaStreamProviderListener());
message_loop_.reset(new MessageLoop(MessageLoop::TYPE_IO));
io_thread_.reset(new BrowserThread(BrowserThread::IO, message_loop_.get()));
+ vcm_.reset(new media_stream::VideoCaptureManager());
+ vcm_->UseFakeDevice();
+ vcm_->Register(listener_.get());
frame_observer_.reset(new MockFrameObserver());
}
@@ -94,8 +98,9 @@ class VideoCaptureManagerTest : public testing::Test {
}
// Called on the main thread.
- static void PostQuitOnVideoCaptureManagerThread(MessageLoop* message_loop) {
- media_stream::VideoCaptureManager::Get()->GetMessageLoop()->PostTask(
+ static void PostQuitOnVideoCaptureManagerThread(
+ MessageLoop* message_loop, media_stream::VideoCaptureManager* vcm) {
+ vcm->GetMessageLoop()->PostTask(
FROM_HERE, NewRunnableFunction(&PostQuitMessageLoop, message_loop));
}
@@ -107,9 +112,11 @@ class VideoCaptureManagerTest : public testing::Test {
void SyncWithVideoCaptureManagerThread() {
message_loop_->PostTask(
FROM_HERE, NewRunnableFunction(&PostQuitOnVideoCaptureManagerThread,
- message_loop_.get()));
+ message_loop_.get(),
+ vcm_.get()));
message_loop_->Run();
}
+ scoped_ptr<media_stream::VideoCaptureManager> vcm_;
scoped_ptr<media_stream::MockMediaStreamProviderListener> listener_;
scoped_ptr<MessageLoop> message_loop_;
scoped_ptr<BrowserThread> io_thread_;
@@ -131,31 +138,26 @@ TEST_F(VideoCaptureManagerTest, CreateAndClose) {
EXPECT_CALL(*listener_, Closed(media_stream::kVideoCapture, _))
.Times(1);
- media_stream::VideoCaptureManager* vcm =
- media_stream::VideoCaptureManager::Get();
- // Make sure fake devices are used
- vcm->UseFakeDevice();
- vcm->Register(listener_.get());
- vcm->EnumerateDevices();
+ vcm_->EnumerateDevices();
// Wait to get device callback...
SyncWithVideoCaptureManagerThread();
- int video_session_id = vcm->Open(listener_->devices_.front());
+ int video_session_id = vcm_->Open(listener_->devices_.front());
media::VideoCaptureParams capture_params;
capture_params.session_id = video_session_id;
capture_params.width = 320;
capture_params.height = 240;
capture_params.frame_per_second = 30;
- vcm->Start(capture_params, frame_observer_.get());
+ vcm_->Start(capture_params, frame_observer_.get());
- vcm->Stop(video_session_id, NULL);
- vcm->Close(video_session_id);
+ vcm_->Stop(video_session_id, NULL);
+ vcm_->Close(video_session_id);
// Wait to check callbacks before removing the listener
SyncWithVideoCaptureManagerThread();
- vcm->Unregister();
+ vcm_->Unregister();
}
// Open the same device twice, should fail.
@@ -171,26 +173,21 @@ TEST_F(VideoCaptureManagerTest, OpenTwice) {
EXPECT_CALL(*listener_, Closed(media_stream::kVideoCapture, _))
.Times(1);
- media_stream::VideoCaptureManager* vcm =
- media_stream::VideoCaptureManager::Get();
- // Make sure fake devices are used
- vcm->UseFakeDevice();
- vcm->Register(listener_.get());
- vcm->EnumerateDevices();
+ vcm_->EnumerateDevices();
// Wait to get device callback...
SyncWithVideoCaptureManagerThread();
- int video_session_id = vcm->Open(listener_->devices_.front());
+ int video_session_id = vcm_->Open(listener_->devices_.front());
// This should trigger an error callback with error code 'kDeviceAlreadyInUse'
- vcm->Open(listener_->devices_.front());
+ vcm_->Open(listener_->devices_.front());
- vcm->Close(video_session_id);
+ vcm_->Close(video_session_id);
// Wait to check callbacks before removing the listener
SyncWithVideoCaptureManagerThread();
- vcm->Unregister();
+ vcm_->Unregister();
}
// Open two different devices.
@@ -203,12 +200,7 @@ TEST_F(VideoCaptureManagerTest, OpenTwo) {
EXPECT_CALL(*listener_, Closed(media_stream::kVideoCapture, _))
.Times(2);
- media_stream::VideoCaptureManager* vcm =
- media_stream::VideoCaptureManager::Get();
- // Make sure fake devices are used
- vcm->UseFakeDevice();
- vcm->Register(listener_.get());
- vcm->EnumerateDevices();
+ vcm_->EnumerateDevices();
// Wait to get device callback...
SyncWithVideoCaptureManagerThread();
@@ -216,18 +208,18 @@ TEST_F(VideoCaptureManagerTest, OpenTwo) {
media_stream::StreamDeviceInfoArray::iterator it =
listener_->devices_.begin();
- int video_session_id_first = vcm->Open(*it);
+ int video_session_id_first = vcm_->Open(*it);
// This should trigger an error callback with error code 'kDeviceAlreadyInUse'
++it;
- int video_session_id_second = vcm->Open(*it);
+ int video_session_id_second = vcm_->Open(*it);
- vcm->Close(video_session_id_first);
- vcm->Close(video_session_id_second);
+ vcm_->Close(video_session_id_first);
+ vcm_->Close(video_session_id_second);
// Wait to check callbacks before removing the listener
SyncWithVideoCaptureManagerThread();
- vcm->Unregister();
+ vcm_->Unregister();
}
// Try open a non-existing device.
@@ -239,12 +231,7 @@ TEST_F(VideoCaptureManagerTest, OpenNotExisting) {
media_stream::kDeviceNotAvailable))
.Times(1);
- media_stream::VideoCaptureManager* vcm =
- media_stream::VideoCaptureManager::Get();
- // Make sure fake devices are used
- vcm->UseFakeDevice();
- vcm->Register(listener_.get());
- vcm->EnumerateDevices();
+ vcm_->EnumerateDevices();
// Wait to get device callback...
SyncWithVideoCaptureManagerThread();
@@ -256,11 +243,11 @@ TEST_F(VideoCaptureManagerTest, OpenNotExisting) {
device_id, false);
// This should fail with error code 'kDeviceNotAvailable'
- vcm->Open(dummy_device);
+ vcm_->Open(dummy_device);
// Wait to check callbacks before removing the listener
SyncWithVideoCaptureManagerThread();
- vcm->Unregister();
+ vcm_->Unregister();
}
// Start a device using "magic" id, i.e. call Start without calling Open.
@@ -271,12 +258,6 @@ TEST_F(VideoCaptureManagerTest, StartUsingId) {
EXPECT_CALL(*listener_, Closed(media_stream::kVideoCapture, _))
.Times(1);
- media_stream::VideoCaptureManager* vcm =
- media_stream::VideoCaptureManager::Get();
- // Make sure fake devices are used
- vcm->UseFakeDevice();
- vcm->Register(listener_.get());
-
media::VideoCaptureParams capture_params;
capture_params.session_id =
media_stream::VideoCaptureManager::kStartOpenSessionId;
@@ -284,14 +265,14 @@ TEST_F(VideoCaptureManagerTest, StartUsingId) {
capture_params.height = 240;
capture_params.frame_per_second = 30;
// Start shall trigger the Open callback
- vcm->Start(capture_params, frame_observer_.get());
+ vcm_->Start(capture_params, frame_observer_.get());
// Stop shall trigger the Close callback
- vcm->Stop(media_stream::VideoCaptureManager::kStartOpenSessionId, NULL);
+ vcm_->Stop(media_stream::VideoCaptureManager::kStartOpenSessionId, NULL);
// Wait to check callbacks before removing the listener
SyncWithVideoCaptureManagerThread();
- vcm->Unregister();
+ vcm_->Unregister();
}
} // namespace
diff --git a/content/common/media/media_stream_options.h b/content/common/media/media_stream_options.h
index 8ba92f6..7569fdc 100644
--- a/content/common/media/media_stream_options.h
+++ b/content/common/media/media_stream_options.h
@@ -36,7 +36,8 @@ struct StreamOptions {
enum MediaStreamType {
kNoService = 0,
kAudioCapture,
- kVideoCapture
+ kVideoCapture,
+ kNumMediaStreamTypes
};
// StreamDeviceInfo describes information about a device.
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 342722c2..64b635a 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -268,7 +268,10 @@
'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_manager.cc',
+ '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/video_capture_controller.cc',
'browser/renderer_host/media/video_capture_controller.h',