Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1046)

Unified Diff: content/browser/renderer_host/media/media_stream_manager.cc

Issue 7284037: Adding MediaStreamManager. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/renderer_host/media/media_stream_manager.cc
===================================================================
--- content/browser/renderer_host/media/media_stream_manager.cc (revision 0)
+++ content/browser/renderer_host/media/media_stream_manager.cc (revision 0)
@@ -0,0 +1,379 @@
+// 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 "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() {
+ static const char alphabet[] = "0123456789"
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ std::string label(63, ' ');
+ for (size_t i = 0; i < label.size(); ++i) {
+ int random_char = base::RandGenerator(sizeof(alphabet - 1));
wjia(left Chromium) 2011/07/01 03:58:34 would it be "sizeof(alphabet) - 1"?
mflodman1 2011/07/01 09:37:10 Yes, you're right. Otherwise we'll end up with onl
+ 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::GetVideoCaptureManager() {
+ 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.
+ new_request.label = RandomLabel();
+ for (DeviceRequestList::iterator it = requests_.begin();
+ it != requests_.end(); ++it) {
+ if (new_request.label == it->label) {
+ new_request.label = RandomLabel();
+ it = requests_.begin();
+ }
+ }
+ requests_.push_back(new_request);
+
+ // Get user confirmation to use capture devices.
+ device_settings_->RequestCaptureDeviceUsage(new_request.label,
+ render_process_id, render_view_id,
+ options, security_origin);
+ (*label) = new_request.label;
+}
+
+void MediaStreamManager::CancelRequests(MediaStreamRequester* requester) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ DeviceRequestList::iterator it = requests_.begin();
+ while (it != requests_.end()) {
+ if (it->requester == requester && !RequestDone(*it)) {
+ it = requests_.erase(it);
+ it = requests_.begin();
+ } 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.
+ for (DeviceRequestList::iterator it = requests_.begin();
+ it != requests_.end(); ++it) {
+ if (it->label == label) {
+ for (StreamDeviceInfoArray::iterator audio_it = it->audio_devices.begin();
+ audio_it != it->audio_devices.end(); ++audio_it) {
+ // TODO(mflodman) Add code when audio input manager exists.
+ DCHECK(false);
+ }
+ for (StreamDeviceInfoArray::iterator video_it = it->video_devices.begin();
+ video_it != it->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;
+ StreamDeviceInfo* device = NULL;
+ for (DeviceRequestList::iterator request_it = requests_.begin();
+ request_it != requests_.end() && request == NULL; ++request_it) {
+ StreamDeviceInfoArray* devices = NULL;
+ if (stream_type == kAudioCapture) {
+ devices = &(request_it->audio_devices);
+ } else if (stream_type == kVideoCapture) {
+ devices = &(request_it->video_devices);
+ } else {
+ DCHECK(false);
+ }
+
+ 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.
+
+ request = &(*request_it);
+ device = &(*device_it);
+ break;
+ }
+ }
+ }
+ if (request == NULL) {
+ // The request doesn't exist.
+ return;
+ }
+
+ device->in_use = true;
+ if (!RequestDone(*request)) {
+ // Wait for more devices to be opened before we're done.
+ return;
+ }
+
+ if (request->state[kAudioCapture] == DeviceRequest::kOpening) {
+ request->state[kAudioCapture] = DeviceRequest::kDone;
+ }
+ if (request->state[kVideoCapture] == DeviceRequest::kOpening) {
+ request->state[kVideoCapture] = DeviceRequest::kDone;
+ }
+
+ request->requester->StreamGenerated(request->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 (DeviceRequestList::iterator it = requests_.begin();
+ it != requests_.end(); ++it) {
+ if (it->state[stream_type] == DeviceRequest::kRequested
+ && Requested(it->options, stream_type)) {
+ label_list.push_back(it->label);
+ }
+ }
+ while (label_list.size()) {
+ device_settings_->AvailableDevices(label_list.front(), stream_type,
+ devices);
+ label_list.pop_front();
+ }
+ 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 (DeviceRequestList::iterator it = requests_.begin();
+ it != requests_.end(); ++it) {
+ StreamDeviceInfoArray* devices = NULL;
+ if (stream_type == kAudioCapture) {
+ devices = &(it->audio_devices);
+ } else if (stream_type == kVideoCapture) {
+ devices = &(it->video_devices);
+ } else {
+ DCHECK(false);
+ }
+
+ 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->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->requester->AudioDeviceFailed(it->label, device_idx);
+ } else if (stream_type == kVideoCapture) {
+ it->requester->VideoDeviceFailed(it->label, device_idx);
+ }
+ GetDeviceManager(stream_type)->Close(capture_session_id);
+ devices->erase(device_it);
+ } else if (it->audio_devices.size() + it->video_devices.size() <= 1) {
+ // 2. Device not opened and no other devices for this request ->
+ // signal stream error and remove the request.
+ it->requester->StreamGenerationFailed(it->label);
+ 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));
+ for (DeviceRequestList::iterator request_it = requests_.begin();
+ request_it != requests_.end(); ++request_it) {
+ if (request_it->label == label) {
+ // We've found our request.
+ if (devices.empty()) {
+ // No available devices or user didn't accept device usage.
+ request_it->requester->StreamGenerationFailed(request_it->label);
+ 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->state[device_it->stream_type] = DeviceRequest::kOpening;
+ if (device_info.stream_type == kAudioCapture) {
+ request_it->audio_devices.push_back(device_info);
+ } else if (device_info.stream_type == kVideoCapture) {
+ request_it->video_devices.push_back(device_info);
+ } else {
+ DCHECK(false);
+ }
+ }
+ return;
+ }
+ }
+}
+
+void MediaStreamManager::Error(const std::string& label) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // Erase this request and report an error.
+ for (DeviceRequestList::iterator it = requests_.begin();
+ it != requests_.end(); ++it) {
+ if (it->label == label) {
+ // We've found our request. erase it and report error.
+ it->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.
+ DCHECK(false);
+ return NULL;
+ }
+ DCHECK(false);
+ 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.
+}
+
+} // namespace media_stream

Powered by Google App Engine
This is Rietveld 408576698