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

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: Changes based on review by wjia 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 "base/lazy_instance.h"
8 #include "base/logging.h"
9 #include "base/rand_util.h"
10 #include "content/browser/browser_thread.h"
11 #include "content/browser/renderer_host/media/media_stream_device_settings.h"
12 #include "content/browser/renderer_host/media/media_stream_requester.h"
13 #include "content/browser/renderer_host/media/video_capture_manager.h"
14 #include "content/common/media/media_stream_options.h"
15
16 namespace media_stream {
17
18 // TODO(mflodman) Find out who should own MediaStreamManager.
19 base::LazyInstance<MediaStreamManager> g_media_stream_manager(
20 base::LINKER_INITIALIZED);
21
22 // Creates a random label used to identify requests.
23 static std::string RandomLabel() {
24 static const char alphabet[] = "0123456789"
Leandro Graciá Gil 2011/07/01 11:31:35 I think this comes from the old demo code (and hen
mflodman1 2011/07/01 14:07:23 Length updated. The label is used in Chrome intern
mflodman1 2011/07/04 21:43:14 Updated according to WhatWG spec.
25 "abcdefghijklmnopqrstuvwxyz"
26 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
27
28 std::string label(63, ' ');
29 for (size_t i = 0; i < label.size(); ++i) {
30 int random_char = base::RandGenerator(sizeof(alphabet) - 1);
31 label[i] = alphabet[random_char];
32 }
33 return label;
34 }
35
36 // Helper to verify if a media stream type is part of options or not.
37 static bool Requested(const StreamOptions& options,
38 MediaStreamType stream_type) {
39 if (stream_type == kVideoCapture
40 && (options.video_option != StreamOptions::kNoCamera)) {
Leandro Graciá Gil 2011/07/01 11:31:35 What if stream_type asks for video but options don
mflodman1 2011/07/01 14:07:23 This is just a helper to see if the stream type is
41 return true;
42 } else if (stream_type == kAudioCapture && options.audio == true) {
43 return true;
44 }
45 return false;
46 }
47
48 MediaStreamManager* MediaStreamManager::Get() {
49 return g_media_stream_manager.Pointer();
50 }
51
52 MediaStreamManager::~MediaStreamManager() {
53 delete device_settings_;
54 delete video_capture_manager_;
55 }
56
57 VideoCaptureManager* MediaStreamManager::GetVideoCaptureManager() {
58 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
59 return video_capture_manager_;
60 }
61
62 void MediaStreamManager::GenerateStream(MediaStreamRequester* requester,
63 int render_process_id,
64 int render_view_id,
65 const StreamOptions& options,
66 const std::string& security_origin,
67 std::string* label) {
68 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
69
70 // TODO(mflodman) Remove next line when audio is supported.
71 (const_cast<StreamOptions&>(options)).audio = false;
72
73 // Create a new request based on options.
74 DeviceRequest new_request = DeviceRequest(requester, options);
75 if (Requested(new_request.options, kAudioCapture)) {
76 new_request.state[kAudioCapture] = DeviceRequest::kRequested;
77 }
78 if (Requested(new_request.options, kVideoCapture)) {
79 new_request.state[kVideoCapture] = DeviceRequest::kRequested;
80 }
81
82 // Create a label for this request and verify it is unique.
83 new_request.label = RandomLabel();
84 for (DeviceRequestList::iterator it = requests_.begin();
85 it != requests_.end(); ++it) {
86 if (new_request.label == it->label) {
Leandro Graciá Gil 2011/07/01 11:31:35 Does the request list contain the labels of existi
mflodman1 2011/07/01 14:07:23 A request is stored until the stream is either clo
mflodman1 2011/07/04 21:43:14 Done.
87 new_request.label = RandomLabel();
88 it = requests_.begin();
89 }
90 }
91 requests_.push_back(new_request);
92
93 // Get user confirmation to use capture devices.
94 device_settings_->RequestCaptureDeviceUsage(new_request.label,
95 render_process_id, render_view_id,
96 options, security_origin);
97 (*label) = new_request.label;
98 }
99
100 void MediaStreamManager::CancelRequests(MediaStreamRequester* requester) {
101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
102
103 DeviceRequestList::iterator it = requests_.begin();
104 while (it != requests_.end()) {
105 if (it->requester == requester && !RequestDone(*it)) {
106 it = requests_.erase(it);
107 it = requests_.begin();
108 } else {
109 ++it;
110 }
111 }
112 }
113
114 void MediaStreamManager::StopGeneratedStream(const std::string& label) {
115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
116 // Find the request and close all open devices for the request.
117 for (DeviceRequestList::iterator it = requests_.begin();
118 it != requests_.end(); ++it) {
119 if (it->label == label) {
120 for (StreamDeviceInfoArray::iterator audio_it = it->audio_devices.begin();
121 audio_it != it->audio_devices.end(); ++audio_it) {
122 // TODO(mflodman) Add code when audio input manager exists.
123 DCHECK(false);
124 }
125 for (StreamDeviceInfoArray::iterator video_it = it->video_devices.begin();
126 video_it != it->video_devices.end(); ++video_it) {
127 video_capture_manager_->Close(video_it->session_id);
128 }
129 requests_.erase(it);
130 return;
131 }
132 }
133 }
134
135 void MediaStreamManager::Opened(MediaStreamType stream_type,
136 int capture_session_id) {
137 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
138
139 // Find the request containing this device and mark it as used.
140 DeviceRequest* request = NULL;
141 StreamDeviceInfo* device = NULL;
142 for (DeviceRequestList::iterator request_it = requests_.begin();
143 request_it != requests_.end() && request == NULL; ++request_it) {
144 StreamDeviceInfoArray* devices = NULL;
145 if (stream_type == kAudioCapture) {
146 devices = &(request_it->audio_devices);
147 } else if (stream_type == kVideoCapture) {
148 devices = &(request_it->video_devices);
149 } else {
150 DCHECK(false);
151 }
152
153 for (StreamDeviceInfoArray::iterator device_it = devices->begin();
154 device_it != devices->end(); ++device_it) {
155 if (device_it->session_id == capture_session_id) {
156 // We've found the request.
157
158 request = &(*request_it);
159 device = &(*device_it);
160 break;
161 }
162 }
163 }
164 if (request == NULL) {
165 // The request doesn't exist.
Leandro Graciá Gil 2011/07/01 11:31:35 Can this happen in legitimate situations without b
mflodman1 2011/07/01 14:07:23 Yes, the request can be canceled during the time t
166 return;
167 }
168
169 device->in_use = true;
Leandro Graciá Gil 2011/07/01 11:31:35 Is there a possibility that the device is already
mflodman1 2011/07/01 14:07:23 A device is marked as in_use by the VideoCaptureMa
170 if (!RequestDone(*request)) {
171 // Wait for more devices to be opened before we're done.
172 return;
173 }
174
175 if (request->state[kAudioCapture] == DeviceRequest::kOpening) {
Leandro Graciá Gil 2011/07/01 11:31:35 Which other states are valid here? Maybe it's wort
mflodman1 2011/07/01 14:07:23 It should only be kRequested that is invalid, mean
176 request->state[kAudioCapture] = DeviceRequest::kDone;
177 }
178 if (request->state[kVideoCapture] == DeviceRequest::kOpening) {
179 request->state[kVideoCapture] = DeviceRequest::kDone;
180 }
181
182 request->requester->StreamGenerated(request->label, request->audio_devices,
183 request->video_devices);
184 }
185
186 void MediaStreamManager::Closed(MediaStreamType stream_type,
187 int capture_session_id) {
188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
189 }
190
191 void MediaStreamManager::DevicesEnumerated(
192 MediaStreamType stream_type, const StreamDeviceInfoArray& devices) {
193 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
194
195 // Publish the result for all requests waiting for device list(s).
196 // Find the requests waiting for this device list, store their labels and
197 // release the iterator before calling device settings. We might get a call
198 // back from device_settings that will need to iterate through devices.
199 std::list<std::string> label_list;
200 for (DeviceRequestList::iterator it = requests_.begin();
201 it != requests_.end(); ++it) {
202 if (it->state[stream_type] == DeviceRequest::kRequested
203 && Requested(it->options, stream_type)) {
204 label_list.push_back(it->label);
205 }
206 }
207 while (label_list.size()) {
208 device_settings_->AvailableDevices(label_list.front(), stream_type,
209 devices);
210 label_list.pop_front();
Leandro Graciá Gil 2011/07/01 11:31:35 Since label_list is local and you always pop the f
mflodman1 2011/07/01 14:07:23 I changed to iterate the list and then do clear wh
211 }
212 enumeration_in_progress_[stream_type] = false;
213 }
214
215 void MediaStreamManager::Error(MediaStreamType stream_type,
216 int capture_session_id,
217 MediaStreamProviderError error) {
218 // Find the device for the error call.
219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
220 for (DeviceRequestList::iterator it = requests_.begin();
221 it != requests_.end(); ++it) {
222 StreamDeviceInfoArray* devices = NULL;
223 if (stream_type == kAudioCapture) {
224 devices = &(it->audio_devices);
225 } else if (stream_type == kVideoCapture) {
226 devices = &(it->video_devices);
227 } else {
228 DCHECK(false);
Leandro Graciá Gil 2011/07/01 11:31:35 Use NOTREACHED().
mflodman1 2011/07/01 14:07:23 Done.
229 }
230
231 int device_idx = 0;
232 for (StreamDeviceInfoArray::iterator device_it = devices->begin();
233 device_it != devices->end(); ++device_it, ++device_idx) {
234 if (device_it->session_id == capture_session_id) {
235 // We've found the failing device. Find the error case:
236 if (it->state[stream_type] == DeviceRequest::kDone) {
237 // 1. Already opened -> signal device failure and close device.
238 // Use device_idx to signal which of the devices encountered an
239 // error.
240 if (stream_type == kAudioCapture) {
241 it->requester->AudioDeviceFailed(it->label, device_idx);
242 } else if (stream_type == kVideoCapture) {
243 it->requester->VideoDeviceFailed(it->label, device_idx);
244 }
245 GetDeviceManager(stream_type)->Close(capture_session_id);
246 devices->erase(device_it);
Leandro Graciá Gil 2011/07/01 11:31:35 This will move all the elements after it in the de
mflodman1 2011/07/01 14:07:23 It won't happen often and it's likely the vector c
247 } else if (it->audio_devices.size() + it->video_devices.size() <= 1) {
248 // 2. Device not opened and no other devices for this request ->
249 // signal stream error and remove the request.
250 it->requester->StreamGenerationFailed(it->label);
251 requests_.erase(it);
252 } else {
253 // 3. Not opened but other devices exists for this request -> remove
254 // device from list, but don't signal an error.
255 devices->erase(device_it);
256 }
257 return;
258 }
259 }
260 }
261 }
262
263 void MediaStreamManager::GetDevices(const std::string& label,
264 MediaStreamType stream_type) {
265 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
266 if (!enumeration_in_progress_[stream_type]) {
267 enumeration_in_progress_[stream_type] = true;
268 GetDeviceManager(stream_type)->EnumerateDevices();
269 }
270 }
271
272 void MediaStreamManager::DevicesAccepted(const std::string& label,
273 const StreamDeviceInfoArray& devices) {
274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
275 for (DeviceRequestList::iterator request_it = requests_.begin();
276 request_it != requests_.end(); ++request_it) {
277 if (request_it->label == label) {
278 // We've found our request.
279 if (devices.empty()) {
280 // No available devices or user didn't accept device usage.
281 request_it->requester->StreamGenerationFailed(request_it->label);
282 requests_.erase(request_it);
283 return;
284 }
285
286 // Loop through all device types for this request.
287 for (StreamDeviceInfoArray::const_iterator device_it = devices.begin();
288 device_it != devices.end(); ++device_it) {
289 StreamDeviceInfo device_info = *device_it;
290
291 // Set in_use to false to be able to track if this device has been
292 // opened. in_use might be true if the device type can be used in more
293 // than one session.
294 device_info.in_use = false;
295 device_info.session_id =
296 GetDeviceManager(device_info.stream_type)->Open(device_info);
297 request_it->state[device_it->stream_type] = DeviceRequest::kOpening;
298 if (device_info.stream_type == kAudioCapture) {
299 request_it->audio_devices.push_back(device_info);
300 } else if (device_info.stream_type == kVideoCapture) {
301 request_it->video_devices.push_back(device_info);
302 } else {
303 DCHECK(false);
Leandro Graciá Gil 2011/07/01 11:31:35 NOTREACHED()
mflodman1 2011/07/01 14:07:23 Done.
304 }
305 }
306 return;
307 }
308 }
309 }
310
311 void MediaStreamManager::SettingsError(const std::string& label) {
312 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
313 // Erase this request and report an error.
314 for (DeviceRequestList::iterator it = requests_.begin();
315 it != requests_.end(); ++it) {
316 if (it->label == label) {
317 // We've found our request. erase it and report error.
318 it->requester->StreamGenerationFailed(label);
319 requests_.erase(it);
320 return;
321 }
322 }
323 }
324
325 void MediaStreamManager::UseFakeDevice() {
326 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
327 video_capture_manager_->UseFakeDevice();
328 // TODO(mflodman) Add audio manager when available.
329 }
330
331 bool MediaStreamManager::RequestDone(const DeviceRequest& request) const {
332 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
333 // Check if all devices are opened.
334 if (Requested(request.options, kAudioCapture)) {
335 for (StreamDeviceInfoArray::const_iterator it =
336 request.audio_devices.begin(); it != request.audio_devices.end();
337 ++it) {
338 if (it->in_use == false) {
339 return false;
340 }
341 }
342 }
343 if (Requested(request.options, kVideoCapture)) {
344 for (StreamDeviceInfoArray::const_iterator it =
345 request.video_devices.begin(); it != request.video_devices.end();
346 ++it) {
347 if (it->in_use == false) {
348 return false;
349 }
350 }
351 }
352 return true;
353 }
354
355 // Called to get media capture device manager of specified type.
356 MediaStreamProvider* MediaStreamManager::GetDeviceManager(
357 MediaStreamType stream_type) const {
358 if (stream_type == kVideoCapture) {
359 return video_capture_manager_;
360 } else if (stream_type == kAudioCapture) {
361 // TODO(mflodman) Add support when audio input manager is available.
362 DCHECK(false);
363 return NULL;
364 }
365 DCHECK(false);
366 return NULL;
367 }
368
369 MediaStreamManager::MediaStreamManager()
370 : video_capture_manager_(new VideoCaptureManager()),
371 enumeration_in_progress_(kNumMediaStreamTypes, false),
372 requests_(),
373 device_settings_(NULL) {
374 device_settings_ = new MediaStreamDeviceSettings(this);
375 video_capture_manager_->Register(this);
376 // TODO(mflodman) Add when audio input manager is available.
377 }
378
379 } // namespace media_stream
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698