Home | History | Annotate | Download | only in media
      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.
      4 
      5 #include "content/renderer/media/user_media_client_impl.h"
      6 
      7 #include <utility>
      8 
      9 #include "base/hash.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"
     33 
     34 namespace content {
     35 namespace {
     36 
     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()));
     46   }
     47 
     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()));
     54   }
     55 }
     56 
     57 static int g_next_request_id  = 0;
     58 
     59 }  // namespace
     60 
     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) {}
     73 
     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) {}
     85 
     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;
     90   }
     91 
     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;
    103 };
    104 
    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());
    115 }
    116 
    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
    120   // shutdown.
    121   FrameWillClose();
    122 }
    123 
    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
    128   // webGetUserMedia.
    129   UpdateWebRTCMethodCount(WEBKIT_GET_USER_MEDIA);
    130   DCHECK(CalledOnValidThread());
    131 
    132   if (RenderThreadImpl::current()) {
    133     RenderThreadImpl::current()->peer_connection_tracker()->TrackGetUserMedia(
    134         user_media_request);
    135   }
    136 
    137   int request_id = g_next_request_id++;
    138   StreamOptions options;
    139   GURL security_origin;
    140   bool enable_automatic_output_device_selection = false;
    141 
    142   // |user_media_request| can't be mocked. So in order to test at all we check
    143   // if it isNull.
    144   if (user_media_request.isNull()) {
    145     // We are in a test.
    146     options.audio_requested = true;
    147     options.video_requested = true;
    148   } else {
    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);
    154 
    155       // Check if this input device should be used to select a matching output
    156       // device for audio rendering.
    157       std::string enable;
    158       if (options.GetFirstAudioConstraintByName(
    159               kMediaStreamRenderToAssociatedSink, &enable, NULL) &&
    160           LowerCaseEqualsASCII(enable, "true")) {
    161         enable_automatic_output_device_selection = true;
    162       }
    163     }
    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);
    169     }
    170 
    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()));
    175   }
    176 
    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() << ")";
    183 
    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);
    192 
    193   WebRtcLogMessage(base::StringPrintf(
    194       "MSI::requestUserMedia. request_id=%d"
    195       ", audio source id=%s mandatory= %s "
    196       ", video source id=%s mandatory= %s",
    197       request_id,
    198       audio_device_id.c_str(),
    199       mandatory_audio ? "true":"false",
    200       video_device_id.c_str(),
    201       mandatory_video ? "true":"false"));
    202 
    203   user_media_requests_.push_back(
    204       new UserMediaRequestInfo(request_id, user_media_request,
    205                                enable_automatic_output_device_selection));
    206 
    207   media_stream_dispatcher_->GenerateStream(
    208       request_id,
    209       weak_factory_.GetWeakPtr(),
    210       options,
    211       security_origin);
    212 }
    213 
    214 void UserMediaClientImpl::cancelUserMediaRequest(
    215     const blink::WebUserMediaRequest& user_media_request) {
    216   DCHECK(CalledOnValidThread());
    217   UserMediaRequestInfo* request = FindUserMediaRequestInfo(user_media_request);
    218   if (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);
    224   }
    225 }
    226 
    227 void UserMediaClientImpl::requestMediaDevices(
    228     const blink::WebMediaDevicesRequest& media_devices_request) {
    229   UpdateWebRTCMethodCount(WEBKIT_GET_MEDIA_DEVICES);
    230   DCHECK(CalledOnValidThread());
    231 
    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++;
    235 
    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());
    242 
    243   DVLOG(1) << "UserMediaClientImpl::requestMediaDevices("
    244            << audio_input_request_id
    245            << ", " << video_input_request_id << ", " << audio_output_request_id
    246            << ", " << security_origin.spec() << ")";
    247 
    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));
    253 
    254   media_stream_dispatcher_->EnumerateDevices(
    255       audio_input_request_id,
    256       weak_factory_.GetWeakPtr(),
    257       MEDIA_DEVICE_AUDIO_CAPTURE,
    258       security_origin);
    259 
    260   media_stream_dispatcher_->EnumerateDevices(
    261       video_input_request_id,
    262       weak_factory_.GetWeakPtr(),
    263       MEDIA_DEVICE_VIDEO_CAPTURE,
    264       security_origin);
    265 
    266   media_stream_dispatcher_->EnumerateDevices(
    267       audio_output_request_id,
    268       weak_factory_.GetWeakPtr(),
    269       MEDIA_DEVICE_AUDIO_OUTPUT,
    270       security_origin);
    271 }
    272 
    273 void UserMediaClientImpl::cancelMediaDevicesRequest(
    274     const blink::WebMediaDevicesRequest& media_devices_request) {
    275   DCHECK(CalledOnValidThread());
    276   MediaDevicesRequestInfo* request =
    277       FindMediaDevicesRequestInfo(media_devices_request);
    278   if (!request)
    279     return;
    280   CancelAndDeleteMediaDevicesRequest(request);
    281 }
    282 
    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());
    288 
    289   int audio_input_request_id = g_next_request_id++;
    290   int video_input_request_id = g_next_request_id++;
    291 
    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());
    298 
    299   DVLOG(1) << "UserMediaClientImpl::requestSources("
    300            << audio_input_request_id
    301            << ", " << video_input_request_id
    302            << ", " << security_origin.spec() << ")";
    303 
    304   media_devices_requests_.push_back(new MediaDevicesRequestInfo(
    305       sources_request,
    306       audio_input_request_id,
    307       video_input_request_id));
    308 
    309   media_stream_dispatcher_->EnumerateDevices(
    310       audio_input_request_id,
    311       weak_factory_.GetWeakPtr(),
    312       MEDIA_DEVICE_AUDIO_CAPTURE,
    313       security_origin);
    314 
    315   media_stream_dispatcher_->EnumerateDevices(
    316       video_input_request_id,
    317       weak_factory_.GetWeakPtr(),
    318       MEDIA_DEVICE_VIDEO_CAPTURE,
    319       security_origin);
    320 }
    321 
    322 // Callback from MediaStreamDispatcher.
    323 // The requested stream have been generated by the MediaStreamDispatcher.
    324 void UserMediaClientImpl::OnStreamGenerated(
    325     int request_id,
    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;
    331 
    332   UserMediaRequestInfo* request_info = FindUserMediaRequestInfo(request_id);
    333   if (!request_info) {
    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);
    338     return;
    339   }
    340   request_info->generated = true;
    341 
    342   // WebUserMediaRequest don't have an implementation in unit tests.
    343   // Therefore we need to check for isNull here and initialize the
    344   // constraints.
    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();
    351   } else {
    352     audio_constraints = request->audioConstraints();
    353     video_constraints = request->videoConstraints();
    354   }
    355 
    356   blink::WebVector<blink::WebMediaStreamTrack> audio_track_vector(
    357       audio_array.size());
    358   CreateAudioTracks(audio_array, audio_constraints, &audio_track_vector,
    359                     request_info);
    360 
    361   blink::WebVector<blink::WebMediaStreamTrack> video_track_vector(
    362       video_array.size());
    363   CreateVideoTracks(video_array, video_constraints, &video_track_vector,
    364                     request_info);
    365 
    366   blink::WebString webkit_id = base::UTF8ToUTF16(label);
    367   blink::WebMediaStream* web_stream = &(request_info->web_stream);
    368 
    369   web_stream->initialize(webkit_id, audio_track_vector,
    370                          video_track_vector);
    371   web_stream->setExtraData(
    372       new MediaStream(
    373           *web_stream));
    374 
    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()));
    379 }
    380 
    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);
    389   }
    390 
    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);
    395   }
    396 }
    397 
    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 :
    414             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));
    420   }
    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),
    429         blink::WebString());
    430   }
    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))));
    440   }
    441 
    442   EnumerateDevicesSucceded(&request->media_devices_request, devices);
    443 }
    444 
    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 :
    456             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);
    461   }
    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;
    470         break;
    471       case MEDIA_VIDEO_FACING_ENVIRONMENT:
    472         video_facing = blink::WebSourceInfo::VideoFacingModeEnvironment;
    473         break;
    474       default:
    475         video_facing = blink::WebSourceInfo::VideoFacingModeNone;
    476     }
    477     sources[offset + i].initialize(blink::WebString::fromUTF8(device.id),
    478                                    blink::WebSourceInfo::SourceKindVideo,
    479                                    blink::WebString::fromUTF8(device.name),
    480                                    video_facing);
    481   }
    482 
    483   EnumerateSourcesSucceded(&request->sources_request, sources);
    484 }
    485 
    486 // Callback from MediaStreamDispatcher.
    487 // The requested stream failed to be generated.
    488 void UserMediaClientImpl::OnStreamGenerationFailed(
    489     int request_id,
    490     MediaStreamRequestResult result) {
    491   DCHECK(CalledOnValidThread());
    492   DVLOG(1) << "UserMediaClientImpl::OnStreamGenerationFailed("
    493            << request_id << ")";
    494   UserMediaRequestInfo* request_info = FindUserMediaRequestInfo(request_id);
    495   if (!request_info) {
    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";
    499     return;
    500   }
    501 
    502   GetUserMediaRequestFailed(&request_info->request, result);
    503   DeleteUserMediaRequestInfo(request_info);
    504 }
    505 
    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 << "})";
    514 
    515   const blink::WebMediaStreamSource* source_ptr = FindLocalSource(device_info);
    516   if (!source_ptr) {
    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.
    520     return;
    521   }
    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);
    526 
    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);
    531       break;
    532     }
    533   }
    534 }
    535 
    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();
    547     return;
    548   }
    549 
    550   webkit_source->initialize(
    551       base::UTF8ToUTF16(device.device.id),
    552       type,
    553       base::UTF8ToUTF16(device.device.name));
    554 
    555   DVLOG(1) << "Initialize source object :"
    556            << "id = " << webkit_source->id().utf8()
    557            << ", name = " << webkit_source->name().utf8();
    558 
    559   if (type == blink::WebMediaStreamSource::TypeVideo) {
    560     webkit_source->setExtraData(
    561         CreateVideoSource(
    562             device,
    563             base::Bind(&UserMediaClientImpl::OnLocalSourceStopped,
    564                        weak_factory_.GetWeakPtr())));
    565   } else {
    566     DCHECK_EQ(blink::WebMediaStreamSource::TypeAudio, type);
    567     MediaStreamAudioSource* audio_source(
    568         new MediaStreamAudioSource(
    569             RenderFrameObserver::routing_id(),
    570             device,
    571             base::Bind(&UserMediaClientImpl::OnLocalSourceStopped,
    572                        weak_factory_.GetWeakPtr()),
    573             dependency_factory_));
    574     webkit_source->setExtraData(audio_source);
    575   }
    576   local_sources_.push_back(*webkit_source);
    577 }
    578 
    579 MediaStreamVideoSource* UserMediaClientImpl::CreateVideoSource(
    580     const StreamDeviceInfo& device,
    581     const MediaStreamSource::SourceStoppedCallback& stop_callback) {
    582   return new content::MediaStreamVideoCapturerSource(
    583       device,
    584       stop_callback,
    585       new VideoCapturerDelegate(device));
    586 }
    587 
    588 void UserMediaClientImpl::CreateVideoTracks(
    589     const StreamDeviceInfoArray& devices,
    590     const blink::WebMediaConstraints& constraints,
    591     blink::WebVector<blink::WebMediaStreamTrack>* webkit_tracks,
    592     UserMediaRequestInfo* request) {
    593   DCHECK_EQ(devices.size(), webkit_tracks->size());
    594 
    595   for (size_t i = 0; i < devices.size(); ++i) {
    596     blink::WebMediaStreamSource webkit_source;
    597     InitializeSourceObject(devices[i],
    598                            blink::WebMediaStreamSource::TypeVideo,
    599                            constraints,
    600                            &webkit_source);
    601     (*webkit_tracks)[i] =
    602         request->CreateAndStartVideoTrack(webkit_source, constraints);
    603   }
    604 }
    605 
    606 void UserMediaClientImpl::CreateAudioTracks(
    607     const StreamDeviceInfoArray& devices,
    608     const blink::WebMediaConstraints& constraints,
    609     blink::WebVector<blink::WebMediaStreamTrack>* webkit_tracks,
    610     UserMediaRequestInfo* request) {
    611   DCHECK_EQ(devices.size(), webkit_tracks->size());
    612 
    613   // Log the device names for this request.
    614   for (StreamDeviceInfoArray::const_iterator it = devices.begin();
    615        it != devices.end(); ++it) {
    616     WebRtcLogMessage(base::StringPrintf(
    617         "Generated media stream for request id %d contains audio device name"
    618         " \"%s\"",
    619         request->request_id,
    620         it->device.name.c_str()));
    621   }
    622 
    623   StreamDeviceInfoArray overridden_audio_array = devices;
    624   if (!request->enable_automatic_output_device_selection) {
    625     // If the GetUserMedia request did not explicitly set the constraint
    626     // kMediaStreamRenderToAssociatedSink, the output device parameters must
    627     // be removed.
    628     for (StreamDeviceInfoArray::iterator it = overridden_audio_array.begin();
    629          it != overridden_audio_array.end(); ++it) {
    630       it->device.matched_output_device_id = "";
    631       it->device.matched_output = MediaStreamDevice::AudioDeviceParameters();
    632     }
    633   }
    634 
    635   for (size_t i = 0; i < overridden_audio_array.size(); ++i) {
    636     blink::WebMediaStreamSource webkit_source;
    637     InitializeSourceObject(overridden_audio_array[i],
    638                            blink::WebMediaStreamSource::TypeAudio,
    639                            constraints,
    640                            &webkit_source);
    641     (*webkit_tracks)[i].initialize(webkit_source);
    642     request->StartAudioTrack((*webkit_tracks)[i], constraints);
    643   }
    644 }
    645 
    646 void UserMediaClientImpl::OnCreateNativeTracksCompleted(
    647     UserMediaRequestInfo* request,
    648     MediaStreamRequestResult result,
    649     const blink::WebString& result_name) {
    650   DVLOG(1) << "UserMediaClientImpl::OnCreateNativeTracksComplete("
    651            << "{request_id = " << request->request_id << "} "
    652            << "{result = " << result << "})";
    653   if (result == content::MEDIA_DEVICE_OK)
    654     GetUserMediaRequestSucceeded(request->web_stream, &request->request);
    655   else
    656     GetUserMediaRequestTrackStartedFailed(&request->request,
    657                                           result,
    658                                           result_name);
    659 
    660   DeleteUserMediaRequestInfo(request);
    661 }
    662 
    663 void UserMediaClientImpl::OnDevicesEnumerated(
    664     int request_id,
    665     const StreamDeviceInfoArray& device_array) {
    666   DVLOG(1) << "UserMediaClientImpl::OnDevicesEnumerated(" << request_id << ")";
    667 
    668   MediaDevicesRequestInfo* request = FindMediaDevicesRequestInfo(request_id);
    669   DCHECK(request);
    670 
    671   if (request_id == request->audio_input_request_id) {
    672     request->has_audio_input_returned = true;
    673     DCHECK(request->audio_input_devices.empty());
    674     request->audio_input_devices = device_array;
    675   } else if (request_id == request->video_input_request_id) {
    676     request->has_video_input_returned = true;
    677     DCHECK(request->video_input_devices.empty());
    678     request->video_input_devices = device_array;
    679   } else {
    680     DCHECK_EQ(request->audio_output_request_id, request_id);
    681     request->has_audio_output_returned = true;
    682     DCHECK(request->audio_output_devices.empty());
    683     request->audio_output_devices = device_array;
    684   }
    685 
    686   if (!request->has_audio_input_returned ||
    687       !request->has_video_input_returned ||
    688       (!request->IsSourcesRequest() && !request->has_audio_output_returned)) {
    689     // Wait for the rest of the devices to complete.
    690     return;
    691   }
    692 
    693   if (request->IsSourcesRequest())
    694     FinalizeEnumerateSources(request);
    695   else
    696     FinalizeEnumerateDevices(request);
    697 
    698   CancelAndDeleteMediaDevicesRequest(request);
    699 }
    700 
    701 void UserMediaClientImpl::OnDeviceOpened(
    702     int request_id,
    703     const std::string& label,
    704     const StreamDeviceInfo& video_device) {
    705   DVLOG(1) << "UserMediaClientImpl::OnDeviceOpened("
    706            << request_id << ", " << label << ")";
    707   NOTIMPLEMENTED();
    708 }
    709 
    710 void UserMediaClientImpl::OnDeviceOpenFailed(int request_id) {
    711   DVLOG(1) << "UserMediaClientImpl::VideoDeviceOpenFailed("
    712            << request_id << ")";
    713   NOTIMPLEMENTED();
    714 }
    715 
    716 void UserMediaClientImpl::GetUserMediaRequestSucceeded(
    717     const blink::WebMediaStream& stream,
    718     blink::WebUserMediaRequest* request_info) {
    719   DVLOG(1) << "UserMediaClientImpl::GetUserMediaRequestSucceeded";
    720   LogUserMediaRequestResult(MEDIA_DEVICE_OK);
    721   request_info->requestSucceeded(stream);
    722 }
    723 
    724 void UserMediaClientImpl::GetUserMediaRequestFailed(
    725     blink::WebUserMediaRequest* request_info,
    726     MediaStreamRequestResult result) {
    727   LogUserMediaRequestResult(result);
    728   switch (result) {
    729     case MEDIA_DEVICE_OK:
    730       NOTREACHED();
    731       break;
    732     case MEDIA_DEVICE_PERMISSION_DENIED:
    733       request_info->requestDenied();
    734       break;
    735     case MEDIA_DEVICE_PERMISSION_DISMISSED:
    736       request_info->requestFailedUASpecific("PermissionDismissedError");
    737       break;
    738     case MEDIA_DEVICE_INVALID_STATE:
    739       request_info->requestFailedUASpecific("InvalidStateError");
    740       break;
    741     case MEDIA_DEVICE_NO_HARDWARE:
    742       request_info->requestFailedUASpecific("DevicesNotFoundError");
    743       break;
    744     case MEDIA_DEVICE_INVALID_SECURITY_ORIGIN:
    745       request_info->requestFailedUASpecific("InvalidSecurityOriginError");
    746       break;
    747     case MEDIA_DEVICE_TAB_CAPTURE_FAILURE:
    748       request_info->requestFailedUASpecific("TabCaptureError");
    749       break;
    750     case MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE:
    751       request_info->requestFailedUASpecific("ScreenCaptureError");
    752       break;
    753     case MEDIA_DEVICE_CAPTURE_FAILURE:
    754       request_info->requestFailedUASpecific("DeviceCaptureError");
    755       break;
    756     default:
    757       NOTREACHED();
    758       request_info->requestFailed();
    759       break;
    760   }
    761 }
    762 
    763 void UserMediaClientImpl::GetUserMediaRequestTrackStartedFailed(
    764     blink::WebUserMediaRequest* request_info,
    765     MediaStreamRequestResult result,
    766     const blink::WebString& result_name) {
    767   switch (result) {
    768     case MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED:
    769       request_info->requestFailedConstraint(result_name);
    770       break;
    771     case MEDIA_DEVICE_TRACK_START_FAILURE:
    772       request_info->requestFailedUASpecific("TrackStartError");
    773       break;
    774     default:
    775       NOTREACHED();
    776       request_info->requestFailed();
    777       break;
    778   }
    779 }
    780 
    781 void UserMediaClientImpl::EnumerateDevicesSucceded(
    782     blink::WebMediaDevicesRequest* request,
    783     blink::WebVector<blink::WebMediaDeviceInfo>& devices) {
    784   request->requestSucceeded(devices);
    785 }
    786 
    787 void UserMediaClientImpl::EnumerateSourcesSucceded(
    788     blink::WebMediaStreamTrackSourcesRequest* request,
    789     blink::WebVector<blink::WebSourceInfo>& sources) {
    790   request->requestSucceeded(sources);
    791 }
    792 
    793 const blink::WebMediaStreamSource* UserMediaClientImpl::FindLocalSource(
    794     const StreamDeviceInfo& device) const {
    795   for (LocalStreamSources::const_iterator it = local_sources_.begin();
    796        it != local_sources_.end(); ++it) {
    797     MediaStreamSource* const source =
    798         static_cast<MediaStreamSource*>(it->extraData());
    799     const StreamDeviceInfo& active_device = source->device_info();
    800     if (active_device.device.id == device.device.id &&
    801         active_device.device.type == device.device.type &&
    802         active_device.session_id == device.session_id) {
    803       return &(*it);
    804     }
    805   }
    806   return NULL;
    807 }
    808 
    809 UserMediaClientImpl::UserMediaRequestInfo*
    810 UserMediaClientImpl::FindUserMediaRequestInfo(int request_id) {
    811   UserMediaRequests::iterator it = user_media_requests_.begin();
    812   for (; it != user_media_requests_.end(); ++it) {
    813     if ((*it)->request_id == request_id)
    814       return (*it);
    815   }
    816   return NULL;
    817 }
    818 
    819 UserMediaClientImpl::UserMediaRequestInfo*
    820 UserMediaClientImpl::FindUserMediaRequestInfo(
    821     const blink::WebUserMediaRequest& request) {
    822   UserMediaRequests::iterator it = user_media_requests_.begin();
    823   for (; it != user_media_requests_.end(); ++it) {
    824     if ((*it)->request == request)
    825       return (*it);
    826   }
    827   return NULL;
    828 }
    829 
    830 void UserMediaClientImpl::DeleteUserMediaRequestInfo(
    831     UserMediaRequestInfo* request) {
    832   UserMediaRequests::iterator it = user_media_requests_.begin();
    833   for (; it != user_media_requests_.end(); ++it) {
    834     if ((*it) == request) {
    835       user_media_requests_.erase(it);
    836       return;
    837     }
    838   }
    839   NOTREACHED();
    840 }
    841 
    842 void UserMediaClientImpl::DeleteAllUserMediaRequests() {
    843   UserMediaRequests::iterator request_it = user_media_requests_.begin();
    844   while (request_it != user_media_requests_.end()) {
    845     DVLOG(1) << "UserMediaClientImpl@" << this
    846              << "::DeleteAllUserMediaRequests: "
    847              << "Cancel user media request " << (*request_it)->request_id;
    848     // If the request is not generated, it means that a request
    849     // has been sent to the MediaStreamDispatcher to generate a stream
    850     // but MediaStreamDispatcher has not yet responded and we need to cancel
    851     // the request.
    852     if (!(*request_it)->generated) {
    853       DCHECK(!(*request_it)->HasPendingSources());
    854       media_stream_dispatcher_->CancelGenerateStream(
    855           (*request_it)->request_id, weak_factory_.GetWeakPtr());
    856       LogUserMediaRequestWithNoResult(MEDIA_STREAM_REQUEST_NOT_GENERATED);
    857     } else {
    858       DCHECK((*request_it)->HasPendingSources());
    859       LogUserMediaRequestWithNoResult(
    860           MEDIA_STREAM_REQUEST_PENDING_MEDIA_TRACKS);
    861     }
    862     request_it = user_media_requests_.erase(request_it);
    863   }
    864 }
    865 
    866 UserMediaClientImpl::MediaDevicesRequestInfo*
    867 UserMediaClientImpl::FindMediaDevicesRequestInfo(
    868     int request_id) {
    869   MediaDevicesRequests::iterator it = media_devices_requests_.begin();
    870   for (; it != media_devices_requests_.end(); ++it) {
    871     if ((*it)->audio_input_request_id == request_id ||
    872         (*it)->video_input_request_id == request_id ||
    873         (*it)->audio_output_request_id == request_id) {
    874       return (*it);
    875     }
    876   }
    877   return NULL;
    878 }
    879 
    880 UserMediaClientImpl::MediaDevicesRequestInfo*
    881 UserMediaClientImpl::FindMediaDevicesRequestInfo(
    882     const blink::WebMediaDevicesRequest& request) {
    883   MediaDevicesRequests::iterator it = media_devices_requests_.begin();
    884   for (; it != media_devices_requests_.end(); ++it) {
    885     if ((*it)->media_devices_request == request)
    886       return (*it);
    887   }
    888   return NULL;
    889 }
    890 
    891 void UserMediaClientImpl::CancelAndDeleteMediaDevicesRequest(
    892     MediaDevicesRequestInfo* request) {
    893   MediaDevicesRequests::iterator it = media_devices_requests_.begin();
    894   for (; it != media_devices_requests_.end(); ++it) {
    895     if ((*it) == request) {
    896       // Cancel device enumeration.
    897       media_stream_dispatcher_->StopEnumerateDevices(
    898           request->audio_input_request_id, weak_factory_.GetWeakPtr());
    899       media_stream_dispatcher_->StopEnumerateDevices(
    900           request->video_input_request_id, weak_factory_.GetWeakPtr());
    901       media_stream_dispatcher_->StopEnumerateDevices(
    902           request->audio_output_request_id, weak_factory_.GetWeakPtr());
    903 
    904       media_devices_requests_.erase(it);
    905       return;
    906     }
    907   }
    908   NOTREACHED();
    909 }
    910 
    911 void UserMediaClientImpl::FrameWillClose() {
    912   // Cancel all outstanding UserMediaRequests.
    913   DeleteAllUserMediaRequests();
    914 
    915   // Loop through all current local sources and stop the sources.
    916   LocalStreamSources::iterator sources_it = local_sources_.begin();
    917   while (sources_it != local_sources_.end()) {
    918     StopLocalSource(*sources_it, true);
    919     sources_it = local_sources_.erase(sources_it);
    920   }
    921 }
    922 
    923 void UserMediaClientImpl::OnLocalSourceStopped(
    924     const blink::WebMediaStreamSource& source) {
    925   DCHECK(CalledOnValidThread());
    926   DVLOG(1) << "UserMediaClientImpl::OnLocalSourceStopped";
    927 
    928   bool device_found = false;
    929   for (LocalStreamSources::iterator device_it = local_sources_.begin();
    930        device_it != local_sources_.end(); ++device_it) {
    931     if (device_it->id()  == source.id()) {
    932       device_found = true;
    933       local_sources_.erase(device_it);
    934       break;
    935     }
    936   }
    937   CHECK(device_found);
    938 
    939   MediaStreamSource* source_impl =
    940       static_cast<MediaStreamSource*>(source.extraData());
    941   media_stream_dispatcher_->StopStreamDevice(source_impl->device_info());
    942 }
    943 
    944 void UserMediaClientImpl::StopLocalSource(
    945     const blink::WebMediaStreamSource& source,
    946     bool notify_dispatcher) {
    947   MediaStreamSource* source_impl =
    948       static_cast<MediaStreamSource*>(source.extraData());
    949   DVLOG(1) << "UserMediaClientImpl::StopLocalSource("
    950            << "{device_id = " << source_impl->device_info().device.id << "})";
    951 
    952   if (notify_dispatcher)
    953     media_stream_dispatcher_->StopStreamDevice(source_impl->device_info());
    954 
    955   source_impl->ResetSourceStoppedCallback();
    956   source_impl->StopSource();
    957 }
    958 
    959 UserMediaClientImpl::UserMediaRequestInfo::UserMediaRequestInfo(
    960     int request_id,
    961     const blink::WebUserMediaRequest& request,
    962     bool enable_automatic_output_device_selection)
    963     : request_id(request_id),
    964       generated(false),
    965       enable_automatic_output_device_selection(
    966           enable_automatic_output_device_selection),
    967       request(request),
    968       request_result_(MEDIA_DEVICE_OK),
    969       request_result_name_("") {
    970 }
    971 
    972 UserMediaClientImpl::UserMediaRequestInfo::~UserMediaRequestInfo() {
    973   DVLOG(1) << "~UserMediaRequestInfo";
    974 }
    975 
    976 void UserMediaClientImpl::UserMediaRequestInfo::StartAudioTrack(
    977     const blink::WebMediaStreamTrack& track,
    978     const blink::WebMediaConstraints& constraints) {
    979   DCHECK(track.source().type() == blink::WebMediaStreamSource::TypeAudio);
    980   MediaStreamAudioSource* native_source =
    981       static_cast <MediaStreamAudioSource*>(track.source().extraData());
    982   DCHECK(native_source);
    983 
    984   sources_.push_back(track.source());
    985   sources_waiting_for_callback_.push_back(native_source);
    986   native_source->AddTrack(
    987       track, constraints, base::Bind(
    988           &UserMediaClientImpl::UserMediaRequestInfo::OnTrackStarted,
    989           AsWeakPtr()));
    990 }
    991 
    992 blink::WebMediaStreamTrack
    993 UserMediaClientImpl::UserMediaRequestInfo::CreateAndStartVideoTrack(
    994     const blink::WebMediaStreamSource& source,
    995     const blink::WebMediaConstraints& constraints) {
    996   DCHECK(source.type() == blink::WebMediaStreamSource::TypeVideo);
    997   MediaStreamVideoSource* native_source =
    998       MediaStreamVideoSource::GetVideoSource(source);
    999   DCHECK(native_source);
   1000   sources_.push_back(source);
   1001   sources_waiting_for_callback_.push_back(native_source);
   1002   return MediaStreamVideoTrack::CreateVideoTrack(
   1003       native_source, constraints, base::Bind(
   1004           &UserMediaClientImpl::UserMediaRequestInfo::OnTrackStarted,
   1005           AsWeakPtr()),
   1006       true);
   1007 }
   1008 
   1009 void UserMediaClientImpl::UserMediaRequestInfo::CallbackOnTracksStarted(
   1010     const ResourcesReady& callback) {
   1011   DCHECK(ready_callback_.is_null());
   1012   ready_callback_ = callback;
   1013   CheckAllTracksStarted();
   1014 }
   1015 
   1016 void UserMediaClientImpl::UserMediaRequestInfo::OnTrackStarted(
   1017     MediaStreamSource* source,
   1018     MediaStreamRequestResult result,
   1019     const blink::WebString& result_name) {
   1020   DVLOG(1) << "OnTrackStarted result " << result;
   1021   std::vector<MediaStreamSource*>::iterator it =
   1022       std::find(sources_waiting_for_callback_.begin(),
   1023                 sources_waiting_for_callback_.end(),
   1024                 source);
   1025   DCHECK(it != sources_waiting_for_callback_.end());
   1026   sources_waiting_for_callback_.erase(it);
   1027   // All tracks must be started successfully. Otherwise the request is a
   1028   // failure.
   1029   if (result != MEDIA_DEVICE_OK) {
   1030     request_result_ = result;
   1031     request_result_name_ = result_name;
   1032   }
   1033 
   1034   CheckAllTracksStarted();
   1035 }
   1036 
   1037 void UserMediaClientImpl::UserMediaRequestInfo::CheckAllTracksStarted() {
   1038   if (!ready_callback_.is_null() && sources_waiting_for_callback_.empty()) {
   1039     ready_callback_.Run(this, request_result_, request_result_name_);
   1040   }
   1041 }
   1042 
   1043 bool UserMediaClientImpl::UserMediaRequestInfo::IsSourceUsed(
   1044     const blink::WebMediaStreamSource& source) const {
   1045   for (std::vector<blink::WebMediaStreamSource>::const_iterator source_it =
   1046            sources_.begin();
   1047        source_it != sources_.end(); ++source_it) {
   1048     if (source_it->id() == source.id())
   1049       return true;
   1050   }
   1051   return false;
   1052 }
   1053 
   1054 void UserMediaClientImpl::UserMediaRequestInfo::RemoveSource(
   1055     const blink::WebMediaStreamSource& source) {
   1056   for (std::vector<blink::WebMediaStreamSource>::iterator it =
   1057            sources_.begin();
   1058        it != sources_.end(); ++it) {
   1059     if (source.id() == it->id()) {
   1060       sources_.erase(it);
   1061       return;
   1062     }
   1063   }
   1064 }
   1065 
   1066 bool UserMediaClientImpl::UserMediaRequestInfo::HasPendingSources() const {
   1067   return !sources_waiting_for_callback_.empty();
   1068 }
   1069 
   1070 }  // namespace content
   1071