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

Side by Side 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: Added DeviceRequest dtor, needed for clang. Created 9 years, 5 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/renderer_host/media/media_stream_manager.h"
6
7 #include <list>
8
9 #include "base/lazy_instance.h"
10 #include "base/logging.h"
11 #include "base/rand_util.h"
12 #include "content/browser/browser_thread.h"
13 #include "content/browser/renderer_host/media/media_stream_device_settings.h"
14 #include "content/browser/renderer_host/media/media_stream_requester.h"
15 #include "content/browser/renderer_host/media/video_capture_manager.h"
16 #include "content/common/media/media_stream_options.h"
17
18 namespace media_stream {
19
20 // TODO(mflodman) Find out who should own MediaStreamManager.
21 base::LazyInstance<MediaStreamManager> g_media_stream_manager(
scherkus (not reviewing) 2011/07/08 20:56:11 drive by... can you address this soon? this is on
22 base::LINKER_INITIALIZED);
23
24 // Creates a random label used to identify requests.
25 static std::string RandomLabel() {
26 // Alphbet according to WhatWG standard, i.e. containing 36 characters from
27 // range: U+0021, U+0023 to U+0027, U+002A to U+002B, U+002D to U+002E,
28 // U+0030 to U+0039, U+0041 to U+005A, U+005E to U+007E.
29 static const char alphabet[] = "!#$%&\'*+-.0123456789"
30 "abcdefghijklmnopqrstuvwxyz^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~";
31
32 std::string label(36, ' ');
33 for (size_t i = 0; i < label.size(); ++i) {
34 int random_char = base::RandGenerator(sizeof(alphabet) - 1);
35 label[i] = alphabet[random_char];
36 }
37 return label;
38 }
39
40 // Helper to verify if a media stream type is part of options or not.
41 static bool Requested(const StreamOptions& options,
42 MediaStreamType stream_type) {
43 if (stream_type == kVideoCapture &&
44 (options.video_option != StreamOptions::kNoCamera)) {
45 return true;
46 } else if (stream_type == kAudioCapture && options.audio == true) {
47 return true;
48 }
49 return false;
50 }
51
52 MediaStreamManager* MediaStreamManager::Get() {
53 return g_media_stream_manager.Pointer();
54 }
55
56 MediaStreamManager::~MediaStreamManager() {
57 delete device_settings_;
scherkus (not reviewing) 2011/07/08 20:56:11 use scoped_ptr<> in .h
58 delete video_capture_manager_;
scherkus (not reviewing) 2011/07/08 20:56:11 use scoped_ptr<> in .h
59 }
60
61 VideoCaptureManager* MediaStreamManager::video_capture_manager() {
62 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
63 return video_capture_manager_;
64 }
65
66 void MediaStreamManager::GenerateStream(MediaStreamRequester* requester,
67 int render_process_id,
68 int render_view_id,
69 const StreamOptions& options,
70 const std::string& security_origin,
71 std::string* label) {
72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
73
74 // TODO(mflodman) Remove next line when audio is supported.
75 (const_cast<StreamOptions&>(options)).audio = false;
76
77 // Create a new request based on options.
78 DeviceRequest new_request = DeviceRequest(requester, options);
79 if (Requested(new_request.options, kAudioCapture)) {
80 new_request.state[kAudioCapture] = DeviceRequest::kRequested;
81 }
82 if (Requested(new_request.options, kVideoCapture)) {
83 new_request.state[kVideoCapture] = DeviceRequest::kRequested;
84 }
85
86 // Create a label for this request and verify it is unique.
87 std::string request_label;
88 do {
89 request_label = RandomLabel();
90 } while (requests_.find(request_label) != requests_.end());
91
92 requests_.insert(std::make_pair(request_label, new_request));
93
94 // Get user confirmation to use capture devices.
95 device_settings_->RequestCaptureDeviceUsage(request_label, render_process_id,
96 render_view_id, options,
97 security_origin);
98 (*label) = request_label;
99 }
100
101 void MediaStreamManager::CancelRequests(MediaStreamRequester* requester) {
102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
103 DeviceRequests::iterator it = requests_.begin();
104 while (it != requests_.end()) {
105 if (it->second.requester == requester && !RequestDone(it->second)) {
106 // The request isn't complete, but there might be some devices already
107 // opened -> close them.
108 DeviceRequest* request = &(it->second);
109 if (request->state[kAudioCapture] == DeviceRequest::kOpening) {
110 for (StreamDeviceInfoArray::iterator it =
111 request->audio_devices.begin(); it != request->audio_devices.end();
112 ++it) {
113 if (it->in_use == true) {
114 // TODO(mflodman) Add when audio input device manager is available.
115 }
116 }
117 }
118 if (request->state[kVideoCapture] == DeviceRequest::kOpening) {
119 for (StreamDeviceInfoArray::iterator it =
120 request->video_devices.begin(); it != request->video_devices.end();
121 ++it) {
122 if (it->in_use == true) {
123 video_capture_manager_->Close(it->session_id);
124 }
125 }
126 }
127 requests_.erase(it++);
128 } else {
129 ++it;
130 }
131 }
132 }
133
134 void MediaStreamManager::StopGeneratedStream(const std::string& label) {
135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
136 // Find the request and close all open devices for the request.
137 DeviceRequests::iterator it = requests_.find(label);
138 if (it != requests_.end()) {
139 for (StreamDeviceInfoArray::iterator audio_it =
140 it->second.audio_devices.begin();
141 audio_it != it->second.audio_devices.end(); ++audio_it) {
142 // TODO(mflodman) Add code when audio input manager exists.
143 NOTREACHED();
144 }
145 for (StreamDeviceInfoArray::iterator video_it =
146 it->second.video_devices.begin();
147 video_it != it->second.video_devices.end(); ++video_it) {
148 video_capture_manager_->Close(video_it->session_id);
149 }
150 requests_.erase(it);
151 return;
152 }
153 }
154
155 void MediaStreamManager::Opened(MediaStreamType stream_type,
156 int capture_session_id) {
157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
158
159 // Find the request containing this device and mark it as used.
160 DeviceRequest* request = NULL;
161 StreamDeviceInfoArray* devices = NULL;
162 std::string label;
163 for (DeviceRequests::iterator request_it = requests_.begin();
164 request_it != requests_.end() && request == NULL; ++request_it) {
165 if (stream_type == kAudioCapture) {
166 devices = &(request_it->second.audio_devices);
167 } else if (stream_type == kVideoCapture) {
168 devices = &(request_it->second.video_devices);
169 } else {
170 NOTREACHED();
171 }
172
173 for (StreamDeviceInfoArray::iterator device_it = devices->begin();
174 device_it != devices->end(); ++device_it) {
175 if (device_it->session_id == capture_session_id) {
176 // We've found the request.
177 device_it->in_use = true;
178 label = request_it->first;
179 request = &(request_it->second);
180 break;
181 }
182 }
183 }
184 if (request == NULL) {
185 // The request doesn't exist.
186 return;
187 }
188
189 DCHECK_NE(request->state[stream_type], DeviceRequest::kRequested);
190
191 // Check if all devices for this stream type are opened. Update the state if
192 // they are.
193 for (StreamDeviceInfoArray::iterator device_it = devices->begin();
194 device_it != devices->end(); ++device_it) {
195 if (device_it->in_use == false) {
196 // Wait for more devices to be opened before we're done.
197 return;
198 }
199 }
200 request->state[stream_type] = DeviceRequest::kDone;
201
202 if (!RequestDone(*request)) {
203 // This stream_type is done, but not the other type.
204 return;
205 }
206
207 request->requester->StreamGenerated(label, request->audio_devices,
208 request->video_devices);
209 }
210
211 void MediaStreamManager::Closed(MediaStreamType stream_type,
212 int capture_session_id) {
213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
214 }
215
216 void MediaStreamManager::DevicesEnumerated(
217 MediaStreamType stream_type, const StreamDeviceInfoArray& devices) {
218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
219
220 // Publish the result for all requests waiting for device list(s).
221 // Find the requests waiting for this device list, store their labels and
222 // release the iterator before calling device settings. We might get a call
223 // back from device_settings that will need to iterate through devices.
224 std::list<std::string> label_list;
225 for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end();
226 ++it) {
227 if (it->second.state[stream_type] == DeviceRequest::kRequested &&
228 Requested(it->second.options, stream_type)) {
229 label_list.push_back(it->first);
230 }
231 }
232 for (std::list<std::string>::iterator it = label_list.begin();
233 it != label_list.end(); ++it) {
234 device_settings_->AvailableDevices(*it, stream_type, devices);
235 }
236 label_list.clear();
237 enumeration_in_progress_[stream_type] = false;
238 }
239
240 void MediaStreamManager::Error(MediaStreamType stream_type,
241 int capture_session_id,
242 MediaStreamProviderError error) {
243 // Find the device for the error call.
244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
245 for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end();
246 ++it) {
247 StreamDeviceInfoArray* devices = NULL;
248 if (stream_type == kAudioCapture) {
249 devices = &(it->second.audio_devices);
250 } else if (stream_type == kVideoCapture) {
251 devices = &(it->second.video_devices);
252 } else {
253 NOTREACHED();
254 }
255
256 int device_idx = 0;
257 for (StreamDeviceInfoArray::iterator device_it = devices->begin();
258 device_it != devices->end(); ++device_it, ++device_idx) {
259 if (device_it->session_id == capture_session_id) {
260 // We've found the failing device. Find the error case:
261 if (it->second.state[stream_type] == DeviceRequest::kDone) {
262 // 1. Already opened -> signal device failure and close device.
263 // Use device_idx to signal which of the devices encountered an
264 // error.
265 if (stream_type == kAudioCapture) {
266 it->second.requester->AudioDeviceFailed(it->first, device_idx);
267 } else if (stream_type == kVideoCapture) {
268 it->second.requester->VideoDeviceFailed(it->first, device_idx);
269 }
270 GetDeviceManager(stream_type)->Close(capture_session_id);
271 devices->erase(device_it);
272 } else if (it->second.audio_devices.size()
273 + it->second.video_devices.size() <= 1) {
274 // 2. Device not opened and no other devices for this request ->
275 // signal stream error and remove the request.
276 it->second.requester->StreamGenerationFailed(it->first);
277 requests_.erase(it);
278 } else {
279 // 3. Not opened but other devices exists for this request -> remove
280 // device from list, but don't signal an error.
281 devices->erase(device_it);
282 }
283 return;
284 }
285 }
286 }
287 }
288
289 void MediaStreamManager::GetDevices(const std::string& label,
290 MediaStreamType stream_type) {
291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
292 if (!enumeration_in_progress_[stream_type]) {
293 enumeration_in_progress_[stream_type] = true;
294 GetDeviceManager(stream_type)->EnumerateDevices();
295 }
296 }
297
298 void MediaStreamManager::DevicesAccepted(const std::string& label,
299 const StreamDeviceInfoArray& devices) {
300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
301 DeviceRequests::iterator request_it = requests_.find(label);
302 if (request_it != requests_.end()) {
303 if (devices.empty()) {
304 // No available devices or user didn't accept device usage.
305 request_it->second.requester->StreamGenerationFailed(request_it->first);
306 requests_.erase(request_it);
307 return;
308 }
309
310 // Loop through all device types for this request.
311 for (StreamDeviceInfoArray::const_iterator device_it = devices.begin();
312 device_it != devices.end(); ++device_it) {
313 StreamDeviceInfo device_info = *device_it;
314
315 // Set in_use to false to be able to track if this device has been
316 // opened. in_use might be true if the device type can be used in more
317 // than one session.
318 device_info.in_use = false;
319 device_info.session_id =
320 GetDeviceManager(device_info.stream_type)->Open(device_info);
321 request_it->second.state[device_it->stream_type] =
322 DeviceRequest::kOpening;
323 if (device_info.stream_type == kAudioCapture) {
324 request_it->second.audio_devices.push_back(device_info);
325 } else if (device_info.stream_type == kVideoCapture) {
326 request_it->second.video_devices.push_back(device_info);
327 } else {
328 NOTREACHED();
329 }
330 }
331 // Check if we received all stream types requested.
332 if (Requested(request_it->second.options, kAudioCapture) &&
333 request_it->second.audio_devices.size() == 0) {
334 request_it->second.state[kAudioCapture] = DeviceRequest::kError;
335 }
336 if (Requested(request_it->second.options, kVideoCapture) &&
337 request_it->second.video_devices.size() == 0) {
338 request_it->second.state[kVideoCapture] = DeviceRequest::kError;
339 }
340 return;
341 }
342 }
343
344 void MediaStreamManager::SettingsError(const std::string& label) {
345 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
346 // Erase this request and report an error.
347 DeviceRequests::iterator it = requests_.find(label);
348 if (it != requests_.end()) {
349 it->second.requester->StreamGenerationFailed(label);
350 requests_.erase(it);
351 return;
352 }
353 }
354
355 void MediaStreamManager::UseFakeDevice() {
356 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
357 video_capture_manager_->UseFakeDevice();
358 // TODO(mflodman) Add audio manager when available.
359 }
360
361 bool MediaStreamManager::RequestDone(const DeviceRequest& request) const {
362 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
363 // Check if all devices are opened.
364 if (Requested(request.options, kAudioCapture)) {
365 for (StreamDeviceInfoArray::const_iterator it =
366 request.audio_devices.begin(); it != request.audio_devices.end();
367 ++it) {
368 if (it->in_use == false) {
369 return false;
370 }
371 }
372 }
373 if (Requested(request.options, kVideoCapture)) {
374 for (StreamDeviceInfoArray::const_iterator it =
375 request.video_devices.begin(); it != request.video_devices.end();
376 ++it) {
377 if (it->in_use == false) {
378 return false;
379 }
380 }
381 }
382 return true;
383 }
384
385 // Called to get media capture device manager of specified type.
386 MediaStreamProvider* MediaStreamManager::GetDeviceManager(
387 MediaStreamType stream_type) const {
388 if (stream_type == kVideoCapture) {
389 return video_capture_manager_;
390 } else if (stream_type == kAudioCapture) {
391 // TODO(mflodman) Add support when audio input manager is available.
392 NOTREACHED();
393 return NULL;
394 }
395 NOTREACHED();
396 return NULL;
397 }
398
399 MediaStreamManager::MediaStreamManager()
400 : video_capture_manager_(new VideoCaptureManager()),
401 enumeration_in_progress_(kNumMediaStreamTypes, false),
402 requests_(),
403 device_settings_(NULL) {
404 device_settings_ = new MediaStreamDeviceSettings(this);
405 video_capture_manager_->Register(this);
406 // TODO(mflodman) Add when audio input manager is available.
407 }
408
409 MediaStreamManager::DeviceRequest::DeviceRequest()
410 : requester(NULL),
411 state(kNumMediaStreamTypes, kNotRequested) {
412 options.audio = false;
413 options.video_option = StreamOptions::kNoCamera;
414 }
415
416 MediaStreamManager::DeviceRequest::DeviceRequest(
417 MediaStreamRequester* requester, const StreamOptions& request_options)
418 : requester(requester),
419 options(request_options),
420 state(kNumMediaStreamTypes, kNotRequested) {
421 DCHECK(requester);
422 }
423
424 MediaStreamManager::DeviceRequest::~DeviceRequest() {}
425
426 } // namespace media_stream
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698