diff options
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', |