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

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: Changed DeviceRequestList to map and changed random label according to new specification. 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(
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)) {
wjia(left Chromium) 2011/07/06 02:58:42 "&&" should be at the end of previous line.
mflodman1 2011/07/06 11:31:45 Done.
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_;
58 delete video_capture_manager_;
59 }
60
61 VideoCaptureManager* MediaStreamManager::GetVideoCaptureManager() {
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)) {
wjia(left Chromium) 2011/07/06 02:58:42 looks like a request can be cancelled if any reque
mflodman1 2011/07/06 11:31:45 Very good point! I added code here to close open d
106 requests_.erase(it);
107 it = requests_.begin();
wjia(left Chromium) 2011/07/06 02:58:42 do you have to go from the beginning again? are yo
mflodman1 2011/07/06 11:31:45 You're right, there is no need to start from 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 DeviceRequests::iterator it = requests_.find(label);
118 if (it != requests_.end()) {
119 for (StreamDeviceInfoArray::iterator audio_it =
120 it->second.audio_devices.begin();
121 audio_it != it->second.audio_devices.end(); ++audio_it) {
122 // TODO(mflodman) Add code when audio input manager exists.
123 NOTREACHED();
124 }
125 for (StreamDeviceInfoArray::iterator video_it =
126 it->second.video_devices.begin();
127 video_it != it->second.video_devices.end(); ++video_it) {
128 video_capture_manager_->Close(video_it->session_id);
129 }
130 requests_.erase(it);
131 return;
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 std::string label;
143 for (DeviceRequests::iterator request_it = requests_.begin();
144 request_it != requests_.end() && request == NULL; ++request_it) {
145 StreamDeviceInfoArray* devices = NULL;
146 if (stream_type == kAudioCapture) {
147 devices = &(request_it->second.audio_devices);
148 } else if (stream_type == kVideoCapture) {
149 devices = &(request_it->second.video_devices);
150 } else {
151 NOTREACHED();
152 }
153
154 for (StreamDeviceInfoArray::iterator device_it = devices->begin();
155 device_it != devices->end(); ++device_it) {
156 if (device_it->session_id == capture_session_id) {
157 // We've found the request.
158 label = request_it->first;
159 request = &(request_it->second);
160 device = &(*device_it);
161 break;
162 }
163 }
164 }
165 if (request == NULL) {
166 // The request doesn't exist.
167 return;
168 }
169
170 DCHECK_NE(request->state[stream_type], DeviceRequest::kRequested);
171
172 device->in_use = true;
173 if (!RequestDone(*request)) {
174 // Wait for more devices to be opened before we're done.
175 return;
176 }
177
178 if (request->state[kAudioCapture] == DeviceRequest::kOpening) {
179 request->state[kAudioCapture] = DeviceRequest::kDone;
180 }
181 if (request->state[kVideoCapture] == DeviceRequest::kOpening) {
182 request->state[kVideoCapture] = DeviceRequest::kDone;
183 }
184
185 request->requester->StreamGenerated(label, request->audio_devices,
186 request->video_devices);
187 }
188
189 void MediaStreamManager::Closed(MediaStreamType stream_type,
190 int capture_session_id) {
191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
192 }
193
194 void MediaStreamManager::DevicesEnumerated(
195 MediaStreamType stream_type, const StreamDeviceInfoArray& devices) {
196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
197
198 // Publish the result for all requests waiting for device list(s).
199 // Find the requests waiting for this device list, store their labels and
200 // release the iterator before calling device settings. We might get a call
201 // back from device_settings that will need to iterate through devices.
202 std::list<std::string> label_list;
203 for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end();
204 ++it) {
205 if (it->second.state[stream_type] == DeviceRequest::kRequested
206 && Requested(it->second.options, stream_type)) {
207 label_list.push_back(it->first);
208 }
209 }
210 for (std::list<std::string>::iterator it = label_list.begin();
211 it != label_list.end(); ++it) {
212 device_settings_->AvailableDevices(*it, stream_type, devices);
wjia(left Chromium) 2011/07/06 02:58:42 the label_list and 2nd for loop are not needed if
mflodman1 2011/07/06 11:31:45 I had it like that originally, but the problem was
213 }
214 label_list.clear();
215 enumeration_in_progress_[stream_type] = false;
216 }
217
218 void MediaStreamManager::Error(MediaStreamType stream_type,
219 int capture_session_id,
220 MediaStreamProviderError error) {
221 // Find the device for the error call.
222 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
223 for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end();
224 ++it) {
225 StreamDeviceInfoArray* devices = NULL;
226 if (stream_type == kAudioCapture) {
227 devices = &(it->second.audio_devices);
228 } else if (stream_type == kVideoCapture) {
229 devices = &(it->second.video_devices);
230 } else {
231 NOTREACHED();
232 }
233
234 int device_idx = 0;
235 for (StreamDeviceInfoArray::iterator device_it = devices->begin();
236 device_it != devices->end(); ++device_it, ++device_idx) {
237 if (device_it->session_id == capture_session_id) {
238 // We've found the failing device. Find the error case:
239 if (it->second.state[stream_type] == DeviceRequest::kDone) {
240 // 1. Already opened -> signal device failure and close device.
241 // Use device_idx to signal which of the devices encountered an
242 // error.
243 if (stream_type == kAudioCapture) {
244 it->second.requester->AudioDeviceFailed(it->first, device_idx);
245 } else if (stream_type == kVideoCapture) {
246 it->second.requester->VideoDeviceFailed(it->first, device_idx);
247 }
248 GetDeviceManager(stream_type)->Close(capture_session_id);
249 devices->erase(device_it);
250 } else if (it->second.audio_devices.size()
251 + it->second.video_devices.size() <= 1) {
252 // 2. Device not opened and no other devices for this request ->
253 // signal stream error and remove the request.
254 it->second.requester->StreamGenerationFailed(it->first);
255 requests_.erase(it);
256 } else {
257 // 3. Not opened but other devices exists for this request -> remove
258 // device from list, but don't signal an error.
259 devices->erase(device_it);
260 }
261 return;
262 }
263 }
264 }
265 }
266
267 void MediaStreamManager::GetDevices(const std::string& label,
268 MediaStreamType stream_type) {
269 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
270 if (!enumeration_in_progress_[stream_type]) {
271 enumeration_in_progress_[stream_type] = true;
272 GetDeviceManager(stream_type)->EnumerateDevices();
273 }
274 }
275
276 void MediaStreamManager::DevicesAccepted(const std::string& label,
277 const StreamDeviceInfoArray& devices) {
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
279 DeviceRequests::iterator request_it = requests_.find(label);
280 if (request_it != requests_.end()) {
wjia(left Chromium) 2011/07/06 02:58:42 is it possible only partial request is accepted? e
mflodman1 2011/07/06 11:31:45 Yes. No error is signalled to the requester if thi
281 if (devices.empty()) {
282 // No available devices or user didn't accept device usage.
283 request_it->second.requester->StreamGenerationFailed(request_it->first);
284 requests_.erase(request_it);
285 return;
286 }
287
288 // Loop through all device types for this request.
289 for (StreamDeviceInfoArray::const_iterator device_it = devices.begin();
290 device_it != devices.end(); ++device_it) {
291 StreamDeviceInfo device_info = *device_it;
292
293 // Set in_use to false to be able to track if this device has been
294 // opened. in_use might be true if the device type can be used in more
295 // than one session.
296 device_info.in_use = false;
297 device_info.session_id =
298 GetDeviceManager(device_info.stream_type)->Open(device_info);
299 request_it->second.state[device_it->stream_type] =
300 DeviceRequest::kOpening;
301 if (device_info.stream_type == kAudioCapture) {
302 request_it->second.audio_devices.push_back(device_info);
303 } else if (device_info.stream_type == kVideoCapture) {
304 request_it->second.video_devices.push_back(device_info);
305 } else {
306 NOTREACHED();
307 }
308 }
309 return;
310 }
311 }
312
313 void MediaStreamManager::SettingsError(const std::string& label) {
314 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
315 // Erase this request and report an error.
316 DeviceRequests::iterator it = requests_.find(label);
317 if (it != requests_.end()) {
318 it->second.requester->StreamGenerationFailed(label);
319 requests_.erase(it);
320 return;
321 }
322 }
323
324 void MediaStreamManager::UseFakeDevice() {
325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
326 video_capture_manager_->UseFakeDevice();
327 // TODO(mflodman) Add audio manager when available.
328 }
329
330 bool MediaStreamManager::RequestDone(const DeviceRequest& request) const {
331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
332 // Check if all devices are opened.
333 if (Requested(request.options, kAudioCapture)) {
334 for (StreamDeviceInfoArray::const_iterator it =
335 request.audio_devices.begin(); it != request.audio_devices.end();
336 ++it) {
337 if (it->in_use == false) {
338 return false;
339 }
340 }
341 }
342 if (Requested(request.options, kVideoCapture)) {
343 for (StreamDeviceInfoArray::const_iterator it =
wjia(left Chromium) 2011/07/06 02:58:42 indentation.
mflodman1 2011/07/06 11:31:45 Done.
344 request.video_devices.begin(); it != request.video_devices.end();
345 ++it) {
346 if (it->in_use == false) {
347 return false;
348 }
349 }
350 }
351 return true;
352 }
353
354 // Called to get media capture device manager of specified type.
355 MediaStreamProvider* MediaStreamManager::GetDeviceManager(
356 MediaStreamType stream_type) const {
357 if (stream_type == kVideoCapture) {
358 return video_capture_manager_;
359 } else if (stream_type == kAudioCapture) {
360 // TODO(mflodman) Add support when audio input manager is available.
361 NOTREACHED();
362 return NULL;
363 }
364 NOTREACHED();
365 return NULL;
366 }
367
368 MediaStreamManager::MediaStreamManager()
369 : video_capture_manager_(new VideoCaptureManager()),
370 enumeration_in_progress_(kNumMediaStreamTypes, false),
371 requests_(),
372 device_settings_(NULL) {
373 device_settings_ = new MediaStreamDeviceSettings(this);
374 video_capture_manager_->Register(this);
375 // TODO(mflodman) Add when audio input manager is available.
376 }
377
378 MediaStreamManager::DeviceRequest::DeviceRequest()
379 : requester(NULL),
380 state(kNumMediaStreamTypes, kNotRequested) {
381 options.audio = false;
382 options.video_option = StreamOptions::kNoCamera;
383 }
384
385 MediaStreamManager::DeviceRequest::DeviceRequest(
386 MediaStreamRequester* requester, const StreamOptions& request_options)
387 : requester(requester),
388 options(request_options),
389 state(kNumMediaStreamTypes, kNotRequested) {
390 DCHECK(requester);
391 }
392
393 } // namespace media_stream
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698