1 // Copyright (c) 2012 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.
5 #include "content/renderer/media/user_media_client_impl.h"
10 #include "base/logging.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "content/public/renderer/render_frame.h"
16 #include "content/renderer/media/media_stream.h"
17 #include "content/renderer/media/media_stream_audio_source.h"
18 #include "content/renderer/media/media_stream_dispatcher.h"
19 #include "content/renderer/media/media_stream_video_capturer_source.h"
20 #include "content/renderer/media/media_stream_video_track.h"
21 #include "content/renderer/media/peer_connection_tracker.h"
22 #include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.h"
23 #include "content/renderer/media/webrtc_audio_capturer.h"
24 #include "content/renderer/media/webrtc_logging.h"
25 #include "content/renderer/media/webrtc_uma_histograms.h"
26 #include "content/renderer/render_thread_impl.h"
27 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
28 #include "third_party/WebKit/public/platform/WebMediaDeviceInfo.h"
29 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
30 #include "third_party/WebKit/public/platform/WebMediaStreamTrackSourcesRequest.h"
31 #include "third_party/WebKit/public/web/WebDocument.h"
32 #include "third_party/WebKit/public/web/WebLocalFrame.h"
37 void CopyStreamConstraints(const blink::WebMediaConstraints
& constraints
,
38 StreamOptions::Constraints
* mandatory
,
39 StreamOptions::Constraints
* optional
) {
40 blink::WebVector
<blink::WebMediaConstraint
> mandatory_constraints
;
41 constraints
.getMandatoryConstraints(mandatory_constraints
);
42 for (size_t i
= 0; i
< mandatory_constraints
.size(); i
++) {
43 mandatory
->push_back(StreamOptions::Constraint(
44 mandatory_constraints
[i
].m_name
.utf8(),
45 mandatory_constraints
[i
].m_value
.utf8()));
48 blink::WebVector
<blink::WebMediaConstraint
> optional_constraints
;
49 constraints
.getOptionalConstraints(optional_constraints
);
50 for (size_t i
= 0; i
< optional_constraints
.size(); i
++) {
51 optional
->push_back(StreamOptions::Constraint(
52 optional_constraints
[i
].m_name
.utf8(),
53 optional_constraints
[i
].m_value
.utf8()));
57 static int g_next_request_id
= 0;
61 struct UserMediaClientImpl::MediaDevicesRequestInfo
{
62 MediaDevicesRequestInfo(const blink::WebMediaDevicesRequest
& request
,
63 int audio_input_request_id
,
64 int video_input_request_id
,
65 int audio_output_request_id
)
66 : media_devices_request(request
),
67 audio_input_request_id(audio_input_request_id
),
68 video_input_request_id(video_input_request_id
),
69 audio_output_request_id(audio_output_request_id
),
70 has_audio_input_returned(false),
71 has_video_input_returned(false),
72 has_audio_output_returned(false) {}
74 MediaDevicesRequestInfo(
75 const blink::WebMediaStreamTrackSourcesRequest
& request
,
76 int audio_input_request_id
,
77 int video_input_request_id
)
78 : sources_request(request
),
79 audio_input_request_id(audio_input_request_id
),
80 video_input_request_id(video_input_request_id
),
81 audio_output_request_id(-1),
82 has_audio_input_returned(false),
83 has_video_input_returned(false),
84 has_audio_output_returned(false) {}
86 bool IsSourcesRequest() {
87 // We can't check isNull() on |media_devices_request| and |sources_request|,
88 // because in unit tests they will always be null.
89 return audio_output_request_id
== -1;
92 blink::WebMediaDevicesRequest media_devices_request
;
93 blink::WebMediaStreamTrackSourcesRequest sources_request
;
94 int audio_input_request_id
;
95 int video_input_request_id
;
96 int audio_output_request_id
;
97 bool has_audio_input_returned
;
98 bool has_video_input_returned
;
99 bool has_audio_output_returned
;
100 StreamDeviceInfoArray audio_input_devices
;
101 StreamDeviceInfoArray video_input_devices
;
102 StreamDeviceInfoArray audio_output_devices
;
105 UserMediaClientImpl::UserMediaClientImpl(
106 RenderFrame
* render_frame
,
107 PeerConnectionDependencyFactory
* dependency_factory
,
108 scoped_ptr
<MediaStreamDispatcher
> media_stream_dispatcher
)
109 : RenderFrameObserver(render_frame
),
110 dependency_factory_(dependency_factory
),
111 media_stream_dispatcher_(media_stream_dispatcher
.Pass()),
112 weak_factory_(this) {
113 DCHECK(dependency_factory_
);
114 DCHECK(media_stream_dispatcher_
.get());
117 UserMediaClientImpl::~UserMediaClientImpl() {
118 // Force-close all outstanding user media requests and local sources here,
119 // before the outstanding WeakPtrs are invalidated, to ensure a clean
124 void UserMediaClientImpl::requestUserMedia(
125 const blink::WebUserMediaRequest
& user_media_request
) {
126 // Save histogram data so we can see how much GetUserMedia is used.
127 // The histogram counts the number of calls to the JS API
129 UpdateWebRTCMethodCount(WEBKIT_GET_USER_MEDIA
);
130 DCHECK(CalledOnValidThread());
132 if (RenderThreadImpl::current()) {
133 RenderThreadImpl::current()->peer_connection_tracker()->TrackGetUserMedia(
137 int request_id
= g_next_request_id
++;
138 StreamOptions options
;
139 GURL security_origin
;
140 bool enable_automatic_output_device_selection
= false;
142 // |user_media_request| can't be mocked. So in order to test at all we check
144 if (user_media_request
.isNull()) {
146 options
.audio_requested
= true;
147 options
.video_requested
= true;
149 if (user_media_request
.audio()) {
150 options
.audio_requested
= true;
151 CopyStreamConstraints(user_media_request
.audioConstraints(),
152 &options
.mandatory_audio
,
153 &options
.optional_audio
);
155 // Check if this input device should be used to select a matching output
156 // device for audio rendering.
158 if (options
.GetFirstAudioConstraintByName(
159 kMediaStreamRenderToAssociatedSink
, &enable
, NULL
) &&
160 LowerCaseEqualsASCII(enable
, "true")) {
161 enable_automatic_output_device_selection
= true;
164 if (user_media_request
.video()) {
165 options
.video_requested
= true;
166 CopyStreamConstraints(user_media_request
.videoConstraints(),
167 &options
.mandatory_video
,
168 &options
.optional_video
);
171 security_origin
= GURL(user_media_request
.securityOrigin().toString());
172 DCHECK(render_frame()->GetWebFrame() ==
173 static_cast<blink::WebFrame
*>(
174 user_media_request
.ownerDocument().frame()));
177 DVLOG(1) << "UserMediaClientImpl::requestUserMedia(" << request_id
<< ", [ "
178 << "audio=" << (options
.audio_requested
)
179 << " select associated sink: "
180 << enable_automatic_output_device_selection
181 << ", video=" << (options
.video_requested
) << " ], "
182 << security_origin
.spec() << ")";
184 std::string audio_device_id
;
185 bool mandatory_audio
;
186 options
.GetFirstAudioConstraintByName(kMediaStreamSourceInfoId
,
187 &audio_device_id
, &mandatory_audio
);
188 std::string video_device_id
;
189 bool mandatory_video
;
190 options
.GetFirstVideoConstraintByName(kMediaStreamSourceInfoId
,
191 &video_device_id
, &mandatory_video
);
193 WebRtcLogMessage(base::StringPrintf(
194 "MSI::requestUserMedia. request_id=%d"
195 ", audio source id=%s mandatory= %s "
196 ", video source id=%s mandatory= %s",
198 audio_device_id
.c_str(),
199 mandatory_audio
? "true":"false",
200 video_device_id
.c_str(),
201 mandatory_video
? "true":"false"));
203 user_media_requests_
.push_back(
204 new UserMediaRequestInfo(request_id
, user_media_request
,
205 enable_automatic_output_device_selection
));
207 media_stream_dispatcher_
->GenerateStream(
209 weak_factory_
.GetWeakPtr(),
214 void UserMediaClientImpl::cancelUserMediaRequest(
215 const blink::WebUserMediaRequest
& user_media_request
) {
216 DCHECK(CalledOnValidThread());
217 UserMediaRequestInfo
* request
= FindUserMediaRequestInfo(user_media_request
);
219 // We can't abort the stream generation process.
220 // Instead, erase the request. Once the stream is generated we will stop the
221 // stream if the request does not exist.
222 LogUserMediaRequestWithNoResult(MEDIA_STREAM_REQUEST_EXPLICITLY_CANCELLED
);
223 DeleteUserMediaRequestInfo(request
);
227 void UserMediaClientImpl::requestMediaDevices(
228 const blink::WebMediaDevicesRequest
& media_devices_request
) {
229 UpdateWebRTCMethodCount(WEBKIT_GET_MEDIA_DEVICES
);
230 DCHECK(CalledOnValidThread());
232 int audio_input_request_id
= g_next_request_id
++;
233 int video_input_request_id
= g_next_request_id
++;
234 int audio_output_request_id
= g_next_request_id
++;
236 // |media_devices_request| can't be mocked, so in tests it will be empty (the
237 // underlying pointer is null). In order to use this function in a test we
238 // need to check if it isNull.
239 GURL security_origin
;
240 if (!media_devices_request
.isNull())
241 security_origin
= GURL(media_devices_request
.securityOrigin().toString());
243 DVLOG(1) << "UserMediaClientImpl::requestMediaDevices("
244 << audio_input_request_id
245 << ", " << video_input_request_id
<< ", " << audio_output_request_id
246 << ", " << security_origin
.spec() << ")";
248 media_devices_requests_
.push_back(new MediaDevicesRequestInfo(
249 media_devices_request
,
250 audio_input_request_id
,
251 video_input_request_id
,
252 audio_output_request_id
));
254 media_stream_dispatcher_
->EnumerateDevices(
255 audio_input_request_id
,
256 weak_factory_
.GetWeakPtr(),
257 MEDIA_DEVICE_AUDIO_CAPTURE
,
260 media_stream_dispatcher_
->EnumerateDevices(
261 video_input_request_id
,
262 weak_factory_
.GetWeakPtr(),
263 MEDIA_DEVICE_VIDEO_CAPTURE
,
266 media_stream_dispatcher_
->EnumerateDevices(
267 audio_output_request_id
,
268 weak_factory_
.GetWeakPtr(),
269 MEDIA_DEVICE_AUDIO_OUTPUT
,
273 void UserMediaClientImpl::cancelMediaDevicesRequest(
274 const blink::WebMediaDevicesRequest
& media_devices_request
) {
275 DCHECK(CalledOnValidThread());
276 MediaDevicesRequestInfo
* request
=
277 FindMediaDevicesRequestInfo(media_devices_request
);
280 CancelAndDeleteMediaDevicesRequest(request
);
283 void UserMediaClientImpl::requestSources(
284 const blink::WebMediaStreamTrackSourcesRequest
& sources_request
) {
285 // We don't call UpdateWebRTCMethodCount() here to track the API count in UMA
286 // stats. This is instead counted in MediaStreamTrack::getSources in blink.
287 DCHECK(CalledOnValidThread());
289 int audio_input_request_id
= g_next_request_id
++;
290 int video_input_request_id
= g_next_request_id
++;
292 // |sources_request| can't be mocked, so in tests it will be empty (the
293 // underlying pointer is null). In order to use this function in a test we
294 // need to check if it isNull.
295 GURL security_origin
;
296 if (!sources_request
.isNull())
297 security_origin
= GURL(sources_request
.origin().utf8());
299 DVLOG(1) << "UserMediaClientImpl::requestSources("
300 << audio_input_request_id
301 << ", " << video_input_request_id
302 << ", " << security_origin
.spec() << ")";
304 media_devices_requests_
.push_back(new MediaDevicesRequestInfo(
306 audio_input_request_id
,
307 video_input_request_id
));
309 media_stream_dispatcher_
->EnumerateDevices(
310 audio_input_request_id
,
311 weak_factory_
.GetWeakPtr(),
312 MEDIA_DEVICE_AUDIO_CAPTURE
,
315 media_stream_dispatcher_
->EnumerateDevices(
316 video_input_request_id
,
317 weak_factory_
.GetWeakPtr(),
318 MEDIA_DEVICE_VIDEO_CAPTURE
,
322 // Callback from MediaStreamDispatcher.
323 // The requested stream have been generated by the MediaStreamDispatcher.
324 void UserMediaClientImpl::OnStreamGenerated(
326 const std::string
& label
,
327 const StreamDeviceInfoArray
& audio_array
,
328 const StreamDeviceInfoArray
& video_array
) {
329 DCHECK(CalledOnValidThread());
330 DVLOG(1) << "UserMediaClientImpl::OnStreamGenerated stream:" << label
;
332 UserMediaRequestInfo
* request_info
= FindUserMediaRequestInfo(request_id
);
334 // This can happen if the request is canceled or the frame reloads while
335 // MediaStreamDispatcher is processing the request.
336 DVLOG(1) << "Request ID not found";
337 OnStreamGeneratedForCancelledRequest(audio_array
, video_array
);
340 request_info
->generated
= true;
342 // WebUserMediaRequest don't have an implementation in unit tests.
343 // Therefore we need to check for isNull here and initialize the
345 blink::WebUserMediaRequest
* request
= &(request_info
->request
);
346 blink::WebMediaConstraints audio_constraints
;
347 blink::WebMediaConstraints video_constraints
;
348 if (request
->isNull()) {
349 audio_constraints
.initialize();
350 video_constraints
.initialize();
352 audio_constraints
= request
->audioConstraints();
353 video_constraints
= request
->videoConstraints();
356 blink::WebVector
<blink::WebMediaStreamTrack
> audio_track_vector(
358 CreateAudioTracks(audio_array
, audio_constraints
, &audio_track_vector
,
361 blink::WebVector
<blink::WebMediaStreamTrack
> video_track_vector(
363 CreateVideoTracks(video_array
, video_constraints
, &video_track_vector
,
366 blink::WebString webkit_id
= base::UTF8ToUTF16(label
);
367 blink::WebMediaStream
* web_stream
= &(request_info
->web_stream
);
369 web_stream
->initialize(webkit_id
, audio_track_vector
,
371 web_stream
->setExtraData(
375 // Wait for the tracks to be started successfully or to fail.
376 request_info
->CallbackOnTracksStarted(
377 base::Bind(&UserMediaClientImpl::OnCreateNativeTracksCompleted
,
378 weak_factory_
.GetWeakPtr()));
381 void UserMediaClientImpl::OnStreamGeneratedForCancelledRequest(
382 const StreamDeviceInfoArray
& audio_array
,
383 const StreamDeviceInfoArray
& video_array
) {
384 // Only stop the device if the device is not used in another MediaStream.
385 for (StreamDeviceInfoArray::const_iterator device_it
= audio_array
.begin();
386 device_it
!= audio_array
.end(); ++device_it
) {
387 if (!FindLocalSource(*device_it
))
388 media_stream_dispatcher_
->StopStreamDevice(*device_it
);
391 for (StreamDeviceInfoArray::const_iterator device_it
= video_array
.begin();
392 device_it
!= video_array
.end(); ++device_it
) {
393 if (!FindLocalSource(*device_it
))
394 media_stream_dispatcher_
->StopStreamDevice(*device_it
);
398 void UserMediaClientImpl::FinalizeEnumerateDevices(
399 MediaDevicesRequestInfo
* request
) {
400 // All devices are ready for copying. We use a hashed audio output device id
401 // as the group id for input and output audio devices. If an input device
402 // doesn't have an associated output device, we use the input device's own id.
403 // We don't support group id for video devices, that's left empty.
404 blink::WebVector
<blink::WebMediaDeviceInfo
>
405 devices(request
->audio_input_devices
.size() +
406 request
->video_input_devices
.size() +
407 request
->audio_output_devices
.size());
408 for (size_t i
= 0; i
< request
->audio_input_devices
.size(); ++i
) {
409 const MediaStreamDevice
& device
= request
->audio_input_devices
[i
].device
;
410 DCHECK_EQ(device
.type
, MEDIA_DEVICE_AUDIO_CAPTURE
);
411 std::string group_id
= base::UintToString(base::Hash(
412 !device
.matched_output_device_id
.empty() ?
413 device
.matched_output_device_id
:
415 devices
[i
].initialize(
416 blink::WebString::fromUTF8(device
.id
),
417 blink::WebMediaDeviceInfo::MediaDeviceKindAudioInput
,
418 blink::WebString::fromUTF8(device
.name
),
419 blink::WebString::fromUTF8(group_id
));
421 size_t offset
= request
->audio_input_devices
.size();
422 for (size_t i
= 0; i
< request
->video_input_devices
.size(); ++i
) {
423 const MediaStreamDevice
& device
= request
->video_input_devices
[i
].device
;
424 DCHECK_EQ(device
.type
, MEDIA_DEVICE_VIDEO_CAPTURE
);
425 devices
[offset
+ i
].initialize(
426 blink::WebString::fromUTF8(device
.id
),
427 blink::WebMediaDeviceInfo::MediaDeviceKindVideoInput
,
428 blink::WebString::fromUTF8(device
.name
),
431 offset
+= request
->video_input_devices
.size();
432 for (size_t i
= 0; i
< request
->audio_output_devices
.size(); ++i
) {
433 const MediaStreamDevice
& device
= request
->audio_output_devices
[i
].device
;
434 DCHECK_EQ(device
.type
, MEDIA_DEVICE_AUDIO_OUTPUT
);
435 devices
[offset
+ i
].initialize(
436 blink::WebString::fromUTF8(device
.id
),
437 blink::WebMediaDeviceInfo::MediaDeviceKindAudioOutput
,
438 blink::WebString::fromUTF8(device
.name
),
439 blink::WebString::fromUTF8(base::UintToString(base::Hash(device
.id
))));
442 EnumerateDevicesSucceded(&request
->media_devices_request
, devices
);
445 void UserMediaClientImpl::FinalizeEnumerateSources(
446 MediaDevicesRequestInfo
* request
) {
447 blink::WebVector
<blink::WebSourceInfo
>
448 sources(request
->audio_input_devices
.size() +
449 request
->video_input_devices
.size());
450 for (size_t i
= 0; i
< request
->audio_input_devices
.size(); ++i
) {
451 const MediaStreamDevice
& device
= request
->audio_input_devices
[i
].device
;
452 DCHECK_EQ(device
.type
, MEDIA_DEVICE_AUDIO_CAPTURE
);
453 std::string group_id
= base::UintToString(base::Hash(
454 !device
.matched_output_device_id
.empty() ?
455 device
.matched_output_device_id
:
457 sources
[i
].initialize(blink::WebString::fromUTF8(device
.id
),
458 blink::WebSourceInfo::SourceKindAudio
,
459 blink::WebString::fromUTF8(device
.name
),
460 blink::WebSourceInfo::VideoFacingModeNone
);
462 size_t offset
= request
->audio_input_devices
.size();
463 for (size_t i
= 0; i
< request
->video_input_devices
.size(); ++i
) {
464 const MediaStreamDevice
& device
= request
->video_input_devices
[i
].device
;
465 DCHECK_EQ(device
.type
, MEDIA_DEVICE_VIDEO_CAPTURE
);
466 blink::WebSourceInfo::VideoFacingMode video_facing
;
467 switch (device
.video_facing
) {
468 case MEDIA_VIDEO_FACING_USER
:
469 video_facing
= blink::WebSourceInfo::VideoFacingModeUser
;
471 case MEDIA_VIDEO_FACING_ENVIRONMENT
:
472 video_facing
= blink::WebSourceInfo::VideoFacingModeEnvironment
;
475 video_facing
= blink::WebSourceInfo::VideoFacingModeNone
;
477 sources
[offset
+ i
].initialize(blink::WebString::fromUTF8(device
.id
),
478 blink::WebSourceInfo::SourceKindVideo
,
479 blink::WebString::fromUTF8(device
.name
),
483 EnumerateSourcesSucceded(&request
->sources_request
, sources
);
486 // Callback from MediaStreamDispatcher.
487 // The requested stream failed to be generated.
488 void UserMediaClientImpl::OnStreamGenerationFailed(
490 MediaStreamRequestResult result
) {
491 DCHECK(CalledOnValidThread());
492 DVLOG(1) << "UserMediaClientImpl::OnStreamGenerationFailed("
493 << request_id
<< ")";
494 UserMediaRequestInfo
* request_info
= FindUserMediaRequestInfo(request_id
);
496 // This can happen if the request is canceled or the frame reloads while
497 // MediaStreamDispatcher is processing the request.
498 DVLOG(1) << "Request ID not found";
502 GetUserMediaRequestFailed(&request_info
->request
, result
, "");
503 DeleteUserMediaRequestInfo(request_info
);
506 // Callback from MediaStreamDispatcher.
507 // The browser process has stopped a device used by a MediaStream.
508 void UserMediaClientImpl::OnDeviceStopped(
509 const std::string
& label
,
510 const StreamDeviceInfo
& device_info
) {
511 DCHECK(CalledOnValidThread());
512 DVLOG(1) << "UserMediaClientImpl::OnDeviceStopped("
513 << "{device_id = " << device_info
.device
.id
<< "})";
515 const blink::WebMediaStreamSource
* source_ptr
= FindLocalSource(device_info
);
517 // This happens if the same device is used in several guM requests or
518 // if a user happen stop a track from JS at the same time
519 // as the underlying media device is unplugged from the system.
522 // By creating |source| it is guaranteed that the blink::WebMediaStreamSource
523 // object is valid during the cleanup.
524 blink::WebMediaStreamSource
source(*source_ptr
);
525 StopLocalSource(source
, false);
527 for (LocalStreamSources::iterator device_it
= local_sources_
.begin();
528 device_it
!= local_sources_
.end(); ++device_it
) {
529 if (device_it
->id() == source
.id()) {
530 local_sources_
.erase(device_it
);
536 void UserMediaClientImpl::InitializeSourceObject(
537 const StreamDeviceInfo
& device
,
538 blink::WebMediaStreamSource::Type type
,
539 const blink::WebMediaConstraints
& constraints
,
540 blink::WebMediaStreamSource
* webkit_source
) {
541 const blink::WebMediaStreamSource
* existing_source
=
542 FindLocalSource(device
);
543 if (existing_source
) {
544 *webkit_source
= *existing_source
;
545 DVLOG(1) << "Source already exist. Reusing source with id "
546 << webkit_source
->id().utf8();
550 webkit_source
->initialize(
551 base::UTF8ToUTF16(device
.device
.id
),
553 base::UTF8ToUTF16(device
.device
.name
),
554 false /* remote */, true /* readonly */);
556 DVLOG(1) << "Initialize source object :"
557 << "id = " << webkit_source
->id().utf8()
558 << ", name = " << webkit_source
->name().utf8();
560 if (type
== blink::WebMediaStreamSource::TypeVideo
) {
561 webkit_source
->setExtraData(
564 base::Bind(&UserMediaClientImpl::OnLocalSourceStopped
,
565 weak_factory_
.GetWeakPtr())));
567 DCHECK_EQ(blink::WebMediaStreamSource::TypeAudio
, type
);
568 MediaStreamAudioSource
* audio_source(
569 new MediaStreamAudioSource(
570 RenderFrameObserver::routing_id(),
572 base::Bind(&UserMediaClientImpl::OnLocalSourceStopped
,
573 weak_factory_
.GetWeakPtr()),
574 dependency_factory_
));
575 webkit_source
->setExtraData(audio_source
);
577 local_sources_
.push_back(*webkit_source
);
580 MediaStreamVideoSource
* UserMediaClientImpl::CreateVideoSource(
581 const StreamDeviceInfo
& device
,
582 const MediaStreamSource::SourceStoppedCallback
& stop_callback
) {
583 content::MediaStreamVideoCapturerSource
* ret
=
584 new content::MediaStreamVideoCapturerSource(
586 make_scoped_ptr(new VideoCapturerDelegate(device
)));
587 ret
->SetDeviceInfo(device
);
591 void UserMediaClientImpl::CreateVideoTracks(
592 const StreamDeviceInfoArray
& devices
,
593 const blink::WebMediaConstraints
& constraints
,
594 blink::WebVector
<blink::WebMediaStreamTrack
>* webkit_tracks
,
595 UserMediaRequestInfo
* request
) {
596 DCHECK_EQ(devices
.size(), webkit_tracks
->size());
598 for (size_t i
= 0; i
< devices
.size(); ++i
) {
599 blink::WebMediaStreamSource webkit_source
;
600 InitializeSourceObject(devices
[i
],
601 blink::WebMediaStreamSource::TypeVideo
,
604 (*webkit_tracks
)[i
] =
605 request
->CreateAndStartVideoTrack(webkit_source
, constraints
);
609 void UserMediaClientImpl::CreateAudioTracks(
610 const StreamDeviceInfoArray
& devices
,
611 const blink::WebMediaConstraints
& constraints
,
612 blink::WebVector
<blink::WebMediaStreamTrack
>* webkit_tracks
,
613 UserMediaRequestInfo
* request
) {
614 DCHECK_EQ(devices
.size(), webkit_tracks
->size());
616 // Log the device names for this request.
617 for (StreamDeviceInfoArray::const_iterator it
= devices
.begin();
618 it
!= devices
.end(); ++it
) {
619 WebRtcLogMessage(base::StringPrintf(
620 "Generated media stream for request id %d contains audio device name"
623 it
->device
.name
.c_str()));
626 StreamDeviceInfoArray overridden_audio_array
= devices
;
627 if (!request
->enable_automatic_output_device_selection
) {
628 // If the GetUserMedia request did not explicitly set the constraint
629 // kMediaStreamRenderToAssociatedSink, the output device parameters must
631 for (StreamDeviceInfoArray::iterator it
= overridden_audio_array
.begin();
632 it
!= overridden_audio_array
.end(); ++it
) {
633 it
->device
.matched_output_device_id
= "";
634 it
->device
.matched_output
= MediaStreamDevice::AudioDeviceParameters();
638 for (size_t i
= 0; i
< overridden_audio_array
.size(); ++i
) {
639 blink::WebMediaStreamSource webkit_source
;
640 InitializeSourceObject(overridden_audio_array
[i
],
641 blink::WebMediaStreamSource::TypeAudio
,
644 (*webkit_tracks
)[i
].initialize(webkit_source
);
645 request
->StartAudioTrack((*webkit_tracks
)[i
], constraints
);
649 void UserMediaClientImpl::OnCreateNativeTracksCompleted(
650 UserMediaRequestInfo
* request
,
651 MediaStreamRequestResult result
,
652 const blink::WebString
& result_name
) {
653 DVLOG(1) << "UserMediaClientImpl::OnCreateNativeTracksComplete("
654 << "{request_id = " << request
->request_id
<< "} "
655 << "{result = " << result
<< "})";
656 if (result
== content::MEDIA_DEVICE_OK
)
657 GetUserMediaRequestSucceeded(request
->web_stream
, &request
->request
);
659 GetUserMediaRequestFailed(&request
->request
, result
, result_name
);
661 DeleteUserMediaRequestInfo(request
);
664 void UserMediaClientImpl::OnDevicesEnumerated(
666 const StreamDeviceInfoArray
& device_array
) {
667 DVLOG(1) << "UserMediaClientImpl::OnDevicesEnumerated(" << request_id
<< ")";
669 MediaDevicesRequestInfo
* request
= FindMediaDevicesRequestInfo(request_id
);
672 if (request_id
== request
->audio_input_request_id
) {
673 request
->has_audio_input_returned
= true;
674 DCHECK(request
->audio_input_devices
.empty());
675 request
->audio_input_devices
= device_array
;
676 } else if (request_id
== request
->video_input_request_id
) {
677 request
->has_video_input_returned
= true;
678 DCHECK(request
->video_input_devices
.empty());
679 request
->video_input_devices
= device_array
;
681 DCHECK_EQ(request
->audio_output_request_id
, request_id
);
682 request
->has_audio_output_returned
= true;
683 DCHECK(request
->audio_output_devices
.empty());
684 request
->audio_output_devices
= device_array
;
687 if (!request
->has_audio_input_returned
||
688 !request
->has_video_input_returned
||
689 (!request
->IsSourcesRequest() && !request
->has_audio_output_returned
)) {
690 // Wait for the rest of the devices to complete.
694 if (request
->IsSourcesRequest())
695 FinalizeEnumerateSources(request
);
697 FinalizeEnumerateDevices(request
);
699 CancelAndDeleteMediaDevicesRequest(request
);
702 void UserMediaClientImpl::OnDeviceOpened(
704 const std::string
& label
,
705 const StreamDeviceInfo
& video_device
) {
706 DVLOG(1) << "UserMediaClientImpl::OnDeviceOpened("
707 << request_id
<< ", " << label
<< ")";
711 void UserMediaClientImpl::OnDeviceOpenFailed(int request_id
) {
712 DVLOG(1) << "UserMediaClientImpl::VideoDeviceOpenFailed("
713 << request_id
<< ")";
717 void UserMediaClientImpl::GetUserMediaRequestSucceeded(
718 const blink::WebMediaStream
& stream
,
719 blink::WebUserMediaRequest
* request_info
) {
720 DVLOG(1) << "UserMediaClientImpl::GetUserMediaRequestSucceeded";
721 LogUserMediaRequestResult(MEDIA_DEVICE_OK
);
722 request_info
->requestSucceeded(stream
);
725 void UserMediaClientImpl::GetUserMediaRequestFailed(
726 blink::WebUserMediaRequest
* request_info
,
727 MediaStreamRequestResult result
,
728 const blink::WebString
& result_name
) {
729 LogUserMediaRequestResult(result
);
731 case MEDIA_DEVICE_OK
:
732 case NUM_MEDIA_REQUEST_RESULTS
:
735 case MEDIA_DEVICE_PERMISSION_DENIED
:
736 request_info
->requestDenied();
738 case MEDIA_DEVICE_PERMISSION_DISMISSED
:
739 request_info
->requestFailedUASpecific("PermissionDismissedError");
741 case MEDIA_DEVICE_INVALID_STATE
:
742 request_info
->requestFailedUASpecific("InvalidStateError");
744 case MEDIA_DEVICE_NO_HARDWARE
:
745 request_info
->requestFailedUASpecific("DevicesNotFoundError");
747 case MEDIA_DEVICE_INVALID_SECURITY_ORIGIN
:
748 request_info
->requestFailedUASpecific("InvalidSecurityOriginError");
750 case MEDIA_DEVICE_TAB_CAPTURE_FAILURE
:
751 request_info
->requestFailedUASpecific("TabCaptureError");
753 case MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE
:
754 request_info
->requestFailedUASpecific("ScreenCaptureError");
756 case MEDIA_DEVICE_CAPTURE_FAILURE
:
757 request_info
->requestFailedUASpecific("DeviceCaptureError");
759 case MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED
:
760 request_info
->requestFailedConstraint(result_name
);
762 case MEDIA_DEVICE_TRACK_START_FAILURE
:
763 request_info
->requestFailedUASpecific("TrackStartError");
765 case MEDIA_DEVICE_NOT_SUPPORTED
:
766 request_info
->requestFailedUASpecific("MediaDeviceNotSupported");
768 case MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN
:
769 request_info
->requestFailedUASpecific("MediaDeviceFailedDueToShutdown");
773 request_info
->requestFailed();
776 void UserMediaClientImpl::EnumerateDevicesSucceded(
777 blink::WebMediaDevicesRequest
* request
,
778 blink::WebVector
<blink::WebMediaDeviceInfo
>& devices
) {
779 request
->requestSucceeded(devices
);
782 void UserMediaClientImpl::EnumerateSourcesSucceded(
783 blink::WebMediaStreamTrackSourcesRequest
* request
,
784 blink::WebVector
<blink::WebSourceInfo
>& sources
) {
785 request
->requestSucceeded(sources
);
788 const blink::WebMediaStreamSource
* UserMediaClientImpl::FindLocalSource(
789 const StreamDeviceInfo
& device
) const {
790 for (LocalStreamSources::const_iterator it
= local_sources_
.begin();
791 it
!= local_sources_
.end(); ++it
) {
792 MediaStreamSource
* const source
=
793 static_cast<MediaStreamSource
*>(it
->extraData());
794 const StreamDeviceInfo
& active_device
= source
->device_info();
795 if (active_device
.device
.id
== device
.device
.id
&&
796 active_device
.device
.type
== device
.device
.type
&&
797 active_device
.session_id
== device
.session_id
) {
804 UserMediaClientImpl::UserMediaRequestInfo
*
805 UserMediaClientImpl::FindUserMediaRequestInfo(int request_id
) {
806 UserMediaRequests::iterator it
= user_media_requests_
.begin();
807 for (; it
!= user_media_requests_
.end(); ++it
) {
808 if ((*it
)->request_id
== request_id
)
814 UserMediaClientImpl::UserMediaRequestInfo
*
815 UserMediaClientImpl::FindUserMediaRequestInfo(
816 const blink::WebUserMediaRequest
& request
) {
817 UserMediaRequests::iterator it
= user_media_requests_
.begin();
818 for (; it
!= user_media_requests_
.end(); ++it
) {
819 if ((*it
)->request
== request
)
825 void UserMediaClientImpl::DeleteUserMediaRequestInfo(
826 UserMediaRequestInfo
* request
) {
827 UserMediaRequests::iterator it
= user_media_requests_
.begin();
828 for (; it
!= user_media_requests_
.end(); ++it
) {
829 if ((*it
) == request
) {
830 user_media_requests_
.erase(it
);
837 void UserMediaClientImpl::DeleteAllUserMediaRequests() {
838 UserMediaRequests::iterator request_it
= user_media_requests_
.begin();
839 while (request_it
!= user_media_requests_
.end()) {
840 DVLOG(1) << "UserMediaClientImpl@" << this
841 << "::DeleteAllUserMediaRequests: "
842 << "Cancel user media request " << (*request_it
)->request_id
;
843 // If the request is not generated, it means that a request
844 // has been sent to the MediaStreamDispatcher to generate a stream
845 // but MediaStreamDispatcher has not yet responded and we need to cancel
847 if (!(*request_it
)->generated
) {
848 DCHECK(!(*request_it
)->HasPendingSources());
849 media_stream_dispatcher_
->CancelGenerateStream(
850 (*request_it
)->request_id
, weak_factory_
.GetWeakPtr());
851 LogUserMediaRequestWithNoResult(MEDIA_STREAM_REQUEST_NOT_GENERATED
);
853 DCHECK((*request_it
)->HasPendingSources());
854 LogUserMediaRequestWithNoResult(
855 MEDIA_STREAM_REQUEST_PENDING_MEDIA_TRACKS
);
857 request_it
= user_media_requests_
.erase(request_it
);
861 UserMediaClientImpl::MediaDevicesRequestInfo
*
862 UserMediaClientImpl::FindMediaDevicesRequestInfo(
864 MediaDevicesRequests::iterator it
= media_devices_requests_
.begin();
865 for (; it
!= media_devices_requests_
.end(); ++it
) {
866 if ((*it
)->audio_input_request_id
== request_id
||
867 (*it
)->video_input_request_id
== request_id
||
868 (*it
)->audio_output_request_id
== request_id
) {
875 UserMediaClientImpl::MediaDevicesRequestInfo
*
876 UserMediaClientImpl::FindMediaDevicesRequestInfo(
877 const blink::WebMediaDevicesRequest
& request
) {
878 MediaDevicesRequests::iterator it
= media_devices_requests_
.begin();
879 for (; it
!= media_devices_requests_
.end(); ++it
) {
880 if ((*it
)->media_devices_request
== request
)
886 void UserMediaClientImpl::CancelAndDeleteMediaDevicesRequest(
887 MediaDevicesRequestInfo
* request
) {
888 MediaDevicesRequests::iterator it
= media_devices_requests_
.begin();
889 for (; it
!= media_devices_requests_
.end(); ++it
) {
890 if ((*it
) == request
) {
891 // Cancel device enumeration.
892 media_stream_dispatcher_
->StopEnumerateDevices(
893 request
->audio_input_request_id
, weak_factory_
.GetWeakPtr());
894 media_stream_dispatcher_
->StopEnumerateDevices(
895 request
->video_input_request_id
, weak_factory_
.GetWeakPtr());
896 media_stream_dispatcher_
->StopEnumerateDevices(
897 request
->audio_output_request_id
, weak_factory_
.GetWeakPtr());
899 media_devices_requests_
.erase(it
);
906 void UserMediaClientImpl::FrameWillClose() {
907 // Cancel all outstanding UserMediaRequests.
908 DeleteAllUserMediaRequests();
910 // Loop through all current local sources and stop the sources.
911 LocalStreamSources::iterator sources_it
= local_sources_
.begin();
912 while (sources_it
!= local_sources_
.end()) {
913 StopLocalSource(*sources_it
, true);
914 sources_it
= local_sources_
.erase(sources_it
);
918 void UserMediaClientImpl::OnLocalSourceStopped(
919 const blink::WebMediaStreamSource
& source
) {
920 DCHECK(CalledOnValidThread());
921 DVLOG(1) << "UserMediaClientImpl::OnLocalSourceStopped";
923 bool device_found
= false;
924 for (LocalStreamSources::iterator device_it
= local_sources_
.begin();
925 device_it
!= local_sources_
.end(); ++device_it
) {
926 if (device_it
->id() == source
.id()) {
928 local_sources_
.erase(device_it
);
934 MediaStreamSource
* source_impl
=
935 static_cast<MediaStreamSource
*>(source
.extraData());
936 media_stream_dispatcher_
->StopStreamDevice(source_impl
->device_info());
939 void UserMediaClientImpl::StopLocalSource(
940 const blink::WebMediaStreamSource
& source
,
941 bool notify_dispatcher
) {
942 MediaStreamSource
* source_impl
=
943 static_cast<MediaStreamSource
*>(source
.extraData());
944 DVLOG(1) << "UserMediaClientImpl::StopLocalSource("
945 << "{device_id = " << source_impl
->device_info().device
.id
<< "})";
947 if (notify_dispatcher
)
948 media_stream_dispatcher_
->StopStreamDevice(source_impl
->device_info());
950 source_impl
->ResetSourceStoppedCallback();
951 source_impl
->StopSource();
954 UserMediaClientImpl::UserMediaRequestInfo::UserMediaRequestInfo(
956 const blink::WebUserMediaRequest
& request
,
957 bool enable_automatic_output_device_selection
)
958 : request_id(request_id
),
960 enable_automatic_output_device_selection(
961 enable_automatic_output_device_selection
),
963 request_result_(MEDIA_DEVICE_OK
),
964 request_result_name_("") {
967 UserMediaClientImpl::UserMediaRequestInfo::~UserMediaRequestInfo() {
968 DVLOG(1) << "~UserMediaRequestInfo";
971 void UserMediaClientImpl::UserMediaRequestInfo::StartAudioTrack(
972 const blink::WebMediaStreamTrack
& track
,
973 const blink::WebMediaConstraints
& constraints
) {
974 DCHECK(track
.source().type() == blink::WebMediaStreamSource::TypeAudio
);
975 MediaStreamAudioSource
* native_source
=
976 static_cast <MediaStreamAudioSource
*>(track
.source().extraData());
977 DCHECK(native_source
);
979 sources_
.push_back(track
.source());
980 sources_waiting_for_callback_
.push_back(native_source
);
981 native_source
->AddTrack(
982 track
, constraints
, base::Bind(
983 &UserMediaClientImpl::UserMediaRequestInfo::OnTrackStarted
,
987 blink::WebMediaStreamTrack
988 UserMediaClientImpl::UserMediaRequestInfo::CreateAndStartVideoTrack(
989 const blink::WebMediaStreamSource
& source
,
990 const blink::WebMediaConstraints
& constraints
) {
991 DCHECK(source
.type() == blink::WebMediaStreamSource::TypeVideo
);
992 MediaStreamVideoSource
* native_source
=
993 MediaStreamVideoSource::GetVideoSource(source
);
994 DCHECK(native_source
);
995 sources_
.push_back(source
);
996 sources_waiting_for_callback_
.push_back(native_source
);
997 return MediaStreamVideoTrack::CreateVideoTrack(
998 native_source
, constraints
, base::Bind(
999 &UserMediaClientImpl::UserMediaRequestInfo::OnTrackStarted
,
1004 void UserMediaClientImpl::UserMediaRequestInfo::CallbackOnTracksStarted(
1005 const ResourcesReady
& callback
) {
1006 DCHECK(ready_callback_
.is_null());
1007 ready_callback_
= callback
;
1008 CheckAllTracksStarted();
1011 void UserMediaClientImpl::UserMediaRequestInfo::OnTrackStarted(
1012 MediaStreamSource
* source
,
1013 MediaStreamRequestResult result
,
1014 const blink::WebString
& result_name
) {
1015 DVLOG(1) << "OnTrackStarted result " << result
;
1016 std::vector
<MediaStreamSource
*>::iterator it
=
1017 std::find(sources_waiting_for_callback_
.begin(),
1018 sources_waiting_for_callback_
.end(),
1020 DCHECK(it
!= sources_waiting_for_callback_
.end());
1021 sources_waiting_for_callback_
.erase(it
);
1022 // All tracks must be started successfully. Otherwise the request is a
1024 if (result
!= MEDIA_DEVICE_OK
) {
1025 request_result_
= result
;
1026 request_result_name_
= result_name
;
1029 CheckAllTracksStarted();
1032 void UserMediaClientImpl::UserMediaRequestInfo::CheckAllTracksStarted() {
1033 if (!ready_callback_
.is_null() && sources_waiting_for_callback_
.empty()) {
1034 ready_callback_
.Run(this, request_result_
, request_result_name_
);
1038 bool UserMediaClientImpl::UserMediaRequestInfo::IsSourceUsed(
1039 const blink::WebMediaStreamSource
& source
) const {
1040 for (std::vector
<blink::WebMediaStreamSource
>::const_iterator source_it
=
1042 source_it
!= sources_
.end(); ++source_it
) {
1043 if (source_it
->id() == source
.id())
1049 void UserMediaClientImpl::UserMediaRequestInfo::RemoveSource(
1050 const blink::WebMediaStreamSource
& source
) {
1051 for (std::vector
<blink::WebMediaStreamSource
>::iterator it
=
1053 it
!= sources_
.end(); ++it
) {
1054 if (source
.id() == it
->id()) {
1061 bool UserMediaClientImpl::UserMediaRequestInfo::HasPendingSources() const {
1062 return !sources_waiting_for_callback_
.empty();
1065 } // namespace content