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/media_stream_impl.h"
      6 
      7 #include <utility>
      8 
      9 #include "base/logging.h"
     10 #include "base/strings/string_util.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "content/renderer/media/media_stream_audio_renderer.h"
     14 #include "content/renderer/media/media_stream_dependency_factory.h"
     15 #include "content/renderer/media/media_stream_dispatcher.h"
     16 #include "content/renderer/media/media_stream_extra_data.h"
     17 #include "content/renderer/media/media_stream_source_extra_data.h"
     18 #include "content/renderer/media/rtc_video_renderer.h"
     19 #include "content/renderer/media/webrtc_audio_capturer.h"
     20 #include "content/renderer/media/webrtc_audio_renderer.h"
     21 #include "content/renderer/media/webrtc_local_audio_renderer.h"
     22 #include "content/renderer/media/webrtc_logging.h"
     23 #include "content/renderer/media/webrtc_uma_histograms.h"
     24 #include "content/renderer/render_thread_impl.h"
     25 #include "media/base/audio_hardware_config.h"
     26 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
     27 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
     28 #include "third_party/WebKit/public/web/WebDocument.h"
     29 #include "third_party/WebKit/public/web/WebFrame.h"
     30 #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
     31 
     32 namespace content {
     33 namespace {
     34 
     35 void CopyStreamConstraints(const blink::WebMediaConstraints& constraints,
     36                            StreamOptions::Constraints* mandatory,
     37                            StreamOptions::Constraints* optional) {
     38   blink::WebVector<blink::WebMediaConstraint> mandatory_constraints;
     39   constraints.getMandatoryConstraints(mandatory_constraints);
     40   for (size_t i = 0; i < mandatory_constraints.size(); i++) {
     41     mandatory->push_back(StreamOptions::Constraint(
     42         mandatory_constraints[i].m_name.utf8(),
     43         mandatory_constraints[i].m_value.utf8()));
     44   }
     45 
     46   blink::WebVector<blink::WebMediaConstraint> optional_constraints;
     47   constraints.getOptionalConstraints(optional_constraints);
     48   for (size_t i = 0; i < optional_constraints.size(); i++) {
     49     optional->push_back(StreamOptions::Constraint(
     50         optional_constraints[i].m_name.utf8(),
     51         optional_constraints[i].m_value.utf8()));
     52   }
     53 }
     54 
     55 static int g_next_request_id  = 0;
     56 
     57 webrtc::MediaStreamInterface* GetNativeMediaStream(
     58     const blink::WebMediaStream& web_stream) {
     59   content::MediaStreamExtraData* extra_data =
     60       static_cast<content::MediaStreamExtraData*>(web_stream.extraData());
     61   if (!extra_data)
     62     return NULL;
     63   return extra_data->stream().get();
     64 }
     65 
     66 void GetDefaultOutputDeviceParams(
     67     int* output_sample_rate, int* output_buffer_size) {
     68   // Fetch the default audio output hardware config.
     69   media::AudioHardwareConfig* hardware_config =
     70       RenderThreadImpl::current()->GetAudioHardwareConfig();
     71   *output_sample_rate = hardware_config->GetOutputSampleRate();
     72   *output_buffer_size = hardware_config->GetOutputBufferSize();
     73 }
     74 
     75 void RemoveSource(const blink::WebMediaStreamSource& source,
     76                   std::vector<blink::WebMediaStreamSource>* sources) {
     77   for (std::vector<blink::WebMediaStreamSource>::iterator it =
     78            sources->begin();
     79        it != sources->end(); ++it) {
     80     if (source.id() == it->id()) {
     81       sources->erase(it);
     82       return;
     83     }
     84   }
     85 }
     86 
     87 }  // namespace
     88 
     89 MediaStreamImpl::MediaStreamImpl(
     90     RenderView* render_view,
     91     MediaStreamDispatcher* media_stream_dispatcher,
     92     MediaStreamDependencyFactory* dependency_factory)
     93     : RenderViewObserver(render_view),
     94       dependency_factory_(dependency_factory),
     95       media_stream_dispatcher_(media_stream_dispatcher) {
     96 }
     97 
     98 MediaStreamImpl::~MediaStreamImpl() {
     99 }
    100 
    101 void MediaStreamImpl::requestUserMedia(
    102     const blink::WebUserMediaRequest& user_media_request) {
    103   // Save histogram data so we can see how much GetUserMedia is used.
    104   // The histogram counts the number of calls to the JS API
    105   // webGetUserMedia.
    106   UpdateWebRTCMethodCount(WEBKIT_GET_USER_MEDIA);
    107   DCHECK(CalledOnValidThread());
    108   int request_id = g_next_request_id++;
    109   StreamOptions options;
    110   blink::WebFrame* frame = NULL;
    111   GURL security_origin;
    112   bool enable_automatic_output_device_selection = false;
    113 
    114   // |user_media_request| can't be mocked. So in order to test at all we check
    115   // if it isNull.
    116   if (user_media_request.isNull()) {
    117     // We are in a test.
    118     options.audio_requested = true;
    119     options.video_requested = true;
    120   } else {
    121     if (user_media_request.audio()) {
    122       options.audio_requested = true;
    123       CopyStreamConstraints(user_media_request.audioConstraints(),
    124                             &options.mandatory_audio,
    125                             &options.optional_audio);
    126 
    127       // Check if this input device should be used to select a matching output
    128       // device for audio rendering.
    129       std::string enable;
    130       if (options.GetFirstAudioConstraintByName(
    131               kMediaStreamRenderToAssociatedSink, &enable, NULL) &&
    132           LowerCaseEqualsASCII(enable, "true")) {
    133         enable_automatic_output_device_selection = true;
    134       }
    135     }
    136     if (user_media_request.video()) {
    137       options.video_requested = true;
    138       CopyStreamConstraints(user_media_request.videoConstraints(),
    139                             &options.mandatory_video,
    140                             &options.optional_video);
    141     }
    142 
    143     security_origin = GURL(user_media_request.securityOrigin().toString());
    144     // Get the WebFrame that requested a MediaStream.
    145     // The frame is needed to tell the MediaStreamDispatcher when a stream goes
    146     // out of scope.
    147     frame = user_media_request.ownerDocument().frame();
    148     DCHECK(frame);
    149   }
    150 
    151   DVLOG(1) << "MediaStreamImpl::requestUserMedia(" << request_id << ", [ "
    152            << "audio=" << (options.audio_requested)
    153            << " select associated sink: "
    154            << enable_automatic_output_device_selection
    155            << ", video=" << (options.video_requested) << " ], "
    156            << security_origin.spec() << ")";
    157 
    158   std::string audio_device_id;
    159   bool mandatory_audio;
    160   options.GetFirstAudioConstraintByName(kMediaStreamSourceInfoId,
    161                                         &audio_device_id, &mandatory_audio);
    162   std::string video_device_id;
    163   bool mandatory_video;
    164   options.GetFirstVideoConstraintByName(kMediaStreamSourceInfoId,
    165                                         &video_device_id, &mandatory_video);
    166 
    167   WebRtcLogMessage(base::StringPrintf(
    168       "MSI::requestUserMedia. request_id=%d"
    169       ", audio source id=%s mandatory= %s "
    170       ", video source id=%s mandatory= %s",
    171       request_id,
    172       audio_device_id.c_str(),
    173       mandatory_audio ? "true":"false",
    174       video_device_id.c_str(),
    175       mandatory_video ? "true":"false"));
    176 
    177   user_media_requests_.push_back(
    178       new UserMediaRequestInfo(request_id, frame, user_media_request,
    179           enable_automatic_output_device_selection));
    180 
    181   media_stream_dispatcher_->GenerateStream(
    182       request_id,
    183       AsWeakPtr(),
    184       options,
    185       security_origin);
    186 }
    187 
    188 void MediaStreamImpl::cancelUserMediaRequest(
    189     const blink::WebUserMediaRequest& user_media_request) {
    190   DCHECK(CalledOnValidThread());
    191   UserMediaRequestInfo* request = FindUserMediaRequestInfo(user_media_request);
    192   if (request) {
    193     // We can't abort the stream generation process.
    194     // Instead, erase the request. Once the stream is generated we will stop the
    195     // stream if the request does not exist.
    196     DeleteUserMediaRequestInfo(request);
    197   }
    198 }
    199 
    200 blink::WebMediaStream MediaStreamImpl::GetMediaStream(
    201     const GURL& url) {
    202   return blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url);
    203 }
    204 
    205 bool MediaStreamImpl::IsMediaStream(const GURL& url) {
    206   blink::WebMediaStream web_stream(
    207       blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url));
    208 
    209   if (web_stream.isNull() || !web_stream.extraData())
    210     return false;  // This is not a valid stream.
    211 
    212   webrtc::MediaStreamInterface* stream = GetNativeMediaStream(web_stream);
    213   return (stream &&
    214       (!stream->GetVideoTracks().empty() || !stream->GetAudioTracks().empty()));
    215 }
    216 
    217 scoped_refptr<VideoFrameProvider>
    218 MediaStreamImpl::GetVideoFrameProvider(
    219     const GURL& url,
    220     const base::Closure& error_cb,
    221     const VideoFrameProvider::RepaintCB& repaint_cb) {
    222   DCHECK(CalledOnValidThread());
    223   blink::WebMediaStream web_stream(GetMediaStream(url));
    224 
    225   if (web_stream.isNull() || !web_stream.extraData())
    226     return NULL;  // This is not a valid stream.
    227 
    228   DVLOG(1) << "MediaStreamImpl::GetVideoFrameProvider stream:"
    229            << UTF16ToUTF8(web_stream.id());
    230 
    231   blink::WebVector<blink::WebMediaStreamTrack> video_tracks;
    232   web_stream.videoTracks(video_tracks);
    233   if (video_tracks.isEmpty())
    234     return NULL;
    235 
    236   return new RTCVideoRenderer(video_tracks[0], error_cb, repaint_cb);
    237 }
    238 
    239 scoped_refptr<MediaStreamAudioRenderer>
    240 MediaStreamImpl::GetAudioRenderer(const GURL& url) {
    241   DCHECK(CalledOnValidThread());
    242   blink::WebMediaStream web_stream(GetMediaStream(url));
    243 
    244   if (web_stream.isNull() || !web_stream.extraData())
    245     return NULL;  // This is not a valid stream.
    246 
    247   DVLOG(1) << "MediaStreamImpl::GetAudioRenderer stream:"
    248            << UTF16ToUTF8(web_stream.id());
    249 
    250   MediaStreamExtraData* extra_data =
    251       static_cast<MediaStreamExtraData*>(web_stream.extraData());
    252 
    253   if (extra_data->is_local()) {
    254     // Create the local audio renderer if the stream contains audio tracks.
    255     blink::WebVector<blink::WebMediaStreamTrack> audio_tracks;
    256     web_stream.audioTracks(audio_tracks);
    257     if (audio_tracks.isEmpty())
    258       return NULL;
    259 
    260     // TODO(xians): Add support for the case that the media stream contains
    261     // multiple audio tracks.
    262     return CreateLocalAudioRenderer(audio_tracks[0]);
    263   }
    264 
    265   webrtc::MediaStreamInterface* stream = extra_data->stream().get();
    266   if (!stream || stream->GetAudioTracks().empty())
    267     return NULL;
    268 
    269   // This is a remote media stream.
    270   WebRtcAudioDeviceImpl* audio_device =
    271       dependency_factory_->GetWebRtcAudioDevice();
    272 
    273   // Share the existing renderer if any, otherwise create a new one.
    274   scoped_refptr<WebRtcAudioRenderer> renderer(audio_device->renderer());
    275   if (!renderer.get()) {
    276     renderer = CreateRemoteAudioRenderer(extra_data->stream().get());
    277 
    278     if (renderer.get() && !audio_device->SetAudioRenderer(renderer.get()))
    279       renderer = NULL;
    280   }
    281 
    282   return renderer.get() ? renderer->CreateSharedAudioRendererProxy() : NULL;
    283 }
    284 
    285 // Callback from MediaStreamDispatcher.
    286 // The requested stream have been generated by the MediaStreamDispatcher.
    287 void MediaStreamImpl::OnStreamGenerated(
    288     int request_id,
    289     const std::string& label,
    290     const StreamDeviceInfoArray& audio_array,
    291     const StreamDeviceInfoArray& video_array) {
    292   DCHECK(CalledOnValidThread());
    293   DVLOG(1) << "MediaStreamImpl::OnStreamGenerated stream:" << label;
    294 
    295   UserMediaRequestInfo* request_info = FindUserMediaRequestInfo(request_id);
    296   if (!request_info) {
    297     // This can happen if the request is canceled or the frame reloads while
    298     // MediaStreamDispatcher is processing the request.
    299     // Only stop the device if the device is not used in another MediaStream.
    300     for (StreamDeviceInfoArray::const_iterator device_it = audio_array.begin();
    301          device_it != audio_array.end(); ++device_it) {
    302       if (!FindLocalSource(*device_it))
    303         media_stream_dispatcher_->StopStreamDevice(*device_it);
    304     }
    305 
    306     for (StreamDeviceInfoArray::const_iterator device_it = video_array.begin();
    307          device_it != video_array.end(); ++device_it) {
    308       if (!FindLocalSource(*device_it))
    309         media_stream_dispatcher_->StopStreamDevice(*device_it);
    310     }
    311 
    312     DVLOG(1) << "Request ID not found";
    313     return;
    314   }
    315   request_info->generated = true;
    316 
    317   blink::WebVector<blink::WebMediaStreamSource> audio_source_vector(
    318         audio_array.size());
    319 
    320   // Log the device names for this request.
    321   for (StreamDeviceInfoArray::const_iterator it = audio_array.begin();
    322        it != audio_array.end(); ++it) {
    323     WebRtcLogMessage(base::StringPrintf(
    324         "Generated media stream for request id %d contains audio device name"
    325         " \"%s\"",
    326         request_id,
    327         it->device.name.c_str()));
    328   }
    329 
    330   StreamDeviceInfoArray overridden_audio_array = audio_array;
    331   if (!request_info->enable_automatic_output_device_selection) {
    332     // If the GetUserMedia request did not explicitly set the constraint
    333     // kMediaStreamRenderToAssociatedSink, the output device parameters must
    334     // be removed.
    335     for (StreamDeviceInfoArray::iterator it = overridden_audio_array.begin();
    336          it != overridden_audio_array.end(); ++it) {
    337       it->device.matched_output_device_id = "";
    338       it->device.matched_output = MediaStreamDevice::AudioDeviceParameters();
    339     }
    340   }
    341   CreateWebKitSourceVector(label, overridden_audio_array,
    342                            blink::WebMediaStreamSource::TypeAudio,
    343                            request_info->frame,
    344                            audio_source_vector);
    345 
    346   blink::WebVector<blink::WebMediaStreamSource> video_source_vector(
    347       video_array.size());
    348   CreateWebKitSourceVector(label, video_array,
    349                            blink::WebMediaStreamSource::TypeVideo,
    350                            request_info->frame,
    351                            video_source_vector);
    352   blink::WebUserMediaRequest* request = &(request_info->request);
    353   blink::WebString webkit_id = UTF8ToUTF16(label);
    354   blink::WebMediaStream* web_stream = &(request_info->web_stream);
    355 
    356   blink::WebVector<blink::WebMediaStreamTrack> audio_track_vector(
    357       audio_array.size());
    358   for (size_t i = 0; i < audio_track_vector.size(); ++i) {
    359     audio_track_vector[i].initialize(audio_source_vector[i]);
    360     request_info->sources.push_back(audio_source_vector[i]);
    361   }
    362 
    363   blink::WebVector<blink::WebMediaStreamTrack> video_track_vector(
    364       video_array.size());
    365   for (size_t i = 0; i < video_track_vector.size(); ++i) {
    366     video_track_vector[i].initialize(video_source_vector[i]);
    367     request_info->sources.push_back(video_source_vector[i]);
    368   }
    369 
    370   web_stream->initialize(webkit_id, audio_track_vector,
    371                          video_track_vector);
    372 
    373   // WebUserMediaRequest don't have an implementation in unit tests.
    374   // Therefore we need to check for isNull here.
    375   blink::WebMediaConstraints audio_constraints = request->isNull() ?
    376       blink::WebMediaConstraints() : request->audioConstraints();
    377   blink::WebMediaConstraints video_constraints = request->isNull() ?
    378       blink::WebMediaConstraints() : request->videoConstraints();
    379 
    380   dependency_factory_->CreateNativeMediaSources(
    381       RenderViewObserver::routing_id(),
    382       audio_constraints, video_constraints, web_stream,
    383       base::Bind(&MediaStreamImpl::OnCreateNativeSourcesComplete, AsWeakPtr()));
    384 }
    385 
    386 // Callback from MediaStreamDispatcher.
    387 // The requested stream failed to be generated.
    388 void MediaStreamImpl::OnStreamGenerationFailed(int request_id) {
    389   DCHECK(CalledOnValidThread());
    390   DVLOG(1) << "MediaStreamImpl::OnStreamGenerationFailed("
    391            << request_id << ")";
    392   UserMediaRequestInfo* request_info = FindUserMediaRequestInfo(request_id);
    393   if (!request_info) {
    394     // This can happen if the request is canceled or the frame reloads while
    395     // MediaStreamDispatcher is processing the request.
    396     DVLOG(1) << "Request ID not found";
    397     return;
    398   }
    399   CompleteGetUserMediaRequest(request_info->web_stream,
    400                               &request_info->request,
    401                               false);
    402   DeleteUserMediaRequestInfo(request_info);
    403 }
    404 
    405 // Callback from MediaStreamDispatcher.
    406 // The browser process has stopped a device used by a MediaStream.
    407 void MediaStreamImpl::OnDeviceStopped(
    408     const std::string& label,
    409     const StreamDeviceInfo& device_info) {
    410   DCHECK(CalledOnValidThread());
    411   DVLOG(1) << "MediaStreamImpl::OnDeviceStopped("
    412            << "{device_id = " << device_info.device.id << "})";
    413 
    414   const blink::WebMediaStreamSource* source_ptr = FindLocalSource(device_info);
    415   if (!source_ptr) {
    416     // This happens if the same device is used in several guM requests or
    417     // if a user happen stop a track from JS at the same time
    418     // as the underlying media device is unplugged from the system.
    419     return;
    420   }
    421   // By creating |source| it is guaranteed that the blink::WebMediaStreamSource
    422   // object is valid during the cleanup.
    423   blink::WebMediaStreamSource source(*source_ptr);
    424   StopLocalSource(source, false);
    425 
    426   for (LocalStreamSources::iterator device_it = local_sources_.begin();
    427        device_it != local_sources_.end(); ++device_it) {
    428     if (device_it->source.id() == source.id()) {
    429       local_sources_.erase(device_it);
    430       break;
    431     }
    432   }
    433 
    434   // Remove the reference to this source from all |user_media_requests_|.
    435   // TODO(perkj): The below is not necessary once we don't need to support
    436   // MediaStream::Stop().
    437   UserMediaRequests::iterator it = user_media_requests_.begin();
    438   while (it != user_media_requests_.end()) {
    439     RemoveSource(source, &(*it)->sources);
    440     if ((*it)->sources.empty()) {
    441       it = user_media_requests_.erase(it);
    442     } else {
    443       ++it;
    444     }
    445   }
    446 }
    447 
    448 void MediaStreamImpl::CreateWebKitSourceVector(
    449     const std::string& label,
    450     const StreamDeviceInfoArray& devices,
    451     blink::WebMediaStreamSource::Type type,
    452     blink::WebFrame* frame,
    453     blink::WebVector<blink::WebMediaStreamSource>& webkit_sources) {
    454   CHECK_EQ(devices.size(), webkit_sources.size());
    455   for (size_t i = 0; i < devices.size(); ++i) {
    456     const blink::WebMediaStreamSource* existing_source =
    457         FindLocalSource(devices[i]);
    458     if (existing_source) {
    459       webkit_sources[i] = *existing_source;
    460       DVLOG(1) << "Source already exist. Reusing source with id "
    461                << webkit_sources[i]. id().utf8();
    462       continue;
    463     }
    464     webkit_sources[i].initialize(
    465         UTF8ToUTF16(devices[i].device.id),
    466         type,
    467         UTF8ToUTF16(devices[i].device.name));
    468     MediaStreamSourceExtraData* source_extra_data(
    469         new content::MediaStreamSourceExtraData(
    470             devices[i],
    471             base::Bind(&MediaStreamImpl::OnLocalSourceStop, AsWeakPtr())));
    472     // |source_extra_data| is owned by webkit_sources[i].
    473     webkit_sources[i].setExtraData(source_extra_data);
    474     local_sources_.push_back(LocalStreamSource(frame, webkit_sources[i]));
    475   }
    476 }
    477 
    478 // Callback from MediaStreamDependencyFactory when the sources in |web_stream|
    479 // have been generated.
    480 void MediaStreamImpl::OnCreateNativeSourcesComplete(
    481     blink::WebMediaStream* web_stream,
    482     bool request_succeeded) {
    483   UserMediaRequestInfo* request_info = FindUserMediaRequestInfo(web_stream);
    484   if (!request_info) {
    485     // This can happen if the request is canceled or the frame reloads while
    486     // MediaStreamDependencyFactory is creating the sources.
    487     DVLOG(1) << "Request ID not found";
    488     return;
    489   }
    490 
    491   // Create a native representation of the stream.
    492   if (request_succeeded) {
    493     dependency_factory_->CreateNativeLocalMediaStream(
    494         web_stream,
    495         base::Bind(&MediaStreamImpl::OnLocalMediaStreamStop, AsWeakPtr()));
    496   }
    497   DVLOG(1) << "MediaStreamImpl::OnCreateNativeSourcesComplete("
    498            << "{request_id = " << request_info->request_id << "} "
    499            << "{request_succeeded = " << request_succeeded << "})";
    500   CompleteGetUserMediaRequest(request_info->web_stream, &request_info->request,
    501                               request_succeeded);
    502   if (!request_succeeded) {
    503     // TODO(perkj): Once we don't support MediaStream::Stop the |request_info|
    504     // can be deleted even if the request succeeds.
    505     DeleteUserMediaRequestInfo(request_info);
    506     StopUnreferencedSources(true);
    507   }
    508 }
    509 
    510 void MediaStreamImpl::OnDevicesEnumerated(
    511     int request_id,
    512     const StreamDeviceInfoArray& device_array) {
    513   DVLOG(1) << "MediaStreamImpl::OnDevicesEnumerated("
    514            << request_id << ")";
    515   NOTIMPLEMENTED();
    516 }
    517 
    518 void MediaStreamImpl::OnDeviceOpened(
    519     int request_id,
    520     const std::string& label,
    521     const StreamDeviceInfo& video_device) {
    522   DVLOG(1) << "MediaStreamImpl::OnDeviceOpened("
    523            << request_id << ", " << label << ")";
    524   NOTIMPLEMENTED();
    525 }
    526 
    527 void MediaStreamImpl::OnDeviceOpenFailed(int request_id) {
    528   DVLOG(1) << "MediaStreamImpl::VideoDeviceOpenFailed("
    529            << request_id << ")";
    530   NOTIMPLEMENTED();
    531 }
    532 
    533 void MediaStreamImpl::CompleteGetUserMediaRequest(
    534     const blink::WebMediaStream& stream,
    535     blink::WebUserMediaRequest* request_info,
    536     bool request_succeeded) {
    537   if (request_succeeded) {
    538     request_info->requestSucceeded(stream);
    539   } else {
    540     request_info->requestFailed();
    541   }
    542 }
    543 
    544 const blink::WebMediaStreamSource* MediaStreamImpl::FindLocalSource(
    545     const StreamDeviceInfo& device) const {
    546   for (LocalStreamSources::const_iterator it = local_sources_.begin();
    547        it != local_sources_.end(); ++it) {
    548     MediaStreamSourceExtraData* extra_data =
    549         static_cast<MediaStreamSourceExtraData*>(
    550             it->source.extraData());
    551     const StreamDeviceInfo& active_device = extra_data->device_info();
    552     if (active_device.device.id == device.device.id &&
    553         active_device.device.type == device.device.type &&
    554         active_device.session_id == device.session_id) {
    555       return &it->source;
    556     }
    557   }
    558   return NULL;
    559 }
    560 
    561 bool MediaStreamImpl::FindSourceInRequests(
    562     const blink::WebMediaStreamSource& source) const {
    563   for (UserMediaRequests::const_iterator req_it = user_media_requests_.begin();
    564        req_it != user_media_requests_.end(); ++req_it) {
    565     const std::vector<blink::WebMediaStreamSource>& sources =
    566         (*req_it)->sources;
    567     for (std::vector<blink::WebMediaStreamSource>::const_iterator source_it =
    568              sources.begin();
    569          source_it != sources.end(); ++source_it) {
    570       if (source_it->id() == source.id()) {
    571         return true;
    572       }
    573     }
    574   }
    575   return false;
    576 }
    577 
    578 MediaStreamImpl::UserMediaRequestInfo*
    579 MediaStreamImpl::FindUserMediaRequestInfo(int request_id) {
    580   UserMediaRequests::iterator it = user_media_requests_.begin();
    581   for (; it != user_media_requests_.end(); ++it) {
    582     if ((*it)->request_id == request_id)
    583       return (*it);
    584   }
    585   return NULL;
    586 }
    587 
    588 MediaStreamImpl::UserMediaRequestInfo*
    589 MediaStreamImpl::FindUserMediaRequestInfo(
    590     const blink::WebUserMediaRequest& request) {
    591   UserMediaRequests::iterator it = user_media_requests_.begin();
    592   for (; it != user_media_requests_.end(); ++it) {
    593     if ((*it)->request == request)
    594       return (*it);
    595   }
    596   return NULL;
    597 }
    598 
    599 MediaStreamImpl::UserMediaRequestInfo*
    600 MediaStreamImpl::FindUserMediaRequestInfo(const std::string& label) {
    601   UserMediaRequests::iterator it = user_media_requests_.begin();
    602   for (; it != user_media_requests_.end(); ++it) {
    603     if ((*it)->generated && (*it)->web_stream.id() == UTF8ToUTF16(label))
    604       return (*it);
    605   }
    606   return NULL;
    607 }
    608 
    609 MediaStreamImpl::UserMediaRequestInfo*
    610 MediaStreamImpl::FindUserMediaRequestInfo(
    611     blink::WebMediaStream* web_stream) {
    612   UserMediaRequests::iterator it = user_media_requests_.begin();
    613   for (; it != user_media_requests_.end(); ++it) {
    614     if (&((*it)->web_stream) == web_stream)
    615       return  (*it);
    616   }
    617   return NULL;
    618 }
    619 
    620 void MediaStreamImpl::DeleteUserMediaRequestInfo(
    621     UserMediaRequestInfo* request) {
    622   UserMediaRequests::iterator it = user_media_requests_.begin();
    623   for (; it != user_media_requests_.end(); ++it) {
    624     if ((*it) == request) {
    625       user_media_requests_.erase(it);
    626       return;
    627     }
    628   }
    629   NOTREACHED();
    630 }
    631 
    632 void MediaStreamImpl::FrameDetached(blink::WebFrame* frame) {
    633   // Do same thing as FrameWillClose.
    634   FrameWillClose(frame);
    635 }
    636 
    637 void MediaStreamImpl::FrameWillClose(blink::WebFrame* frame) {
    638   // Loop through all UserMediaRequests and find the requests that belong to the
    639   // frame that is being closed.
    640   UserMediaRequests::iterator request_it = user_media_requests_.begin();
    641   while (request_it != user_media_requests_.end()) {
    642     if ((*request_it)->frame == frame) {
    643       DVLOG(1) << "MediaStreamImpl::FrameWillClose: "
    644                << "Cancel user media request " << (*request_it)->request_id;
    645       // If the request is not generated, it means that a request
    646       // has been sent to the MediaStreamDispatcher to generate a stream
    647       // but MediaStreamDispatcher has not yet responded and we need to cancel
    648       // the request.
    649       if (!(*request_it)->generated) {
    650         media_stream_dispatcher_->CancelGenerateStream(
    651             (*request_it)->request_id, AsWeakPtr());
    652       }
    653       request_it = user_media_requests_.erase(request_it);
    654     } else {
    655       ++request_it;
    656     }
    657   }
    658 
    659   // Loop through all current local sources and stop the sources that were
    660   // created by the frame that will be closed.
    661   LocalStreamSources::iterator sources_it = local_sources_.begin();
    662   while (sources_it != local_sources_.end()) {
    663     if (sources_it->frame == frame) {
    664       StopLocalSource(sources_it->source, true);
    665       sources_it = local_sources_.erase(sources_it);
    666     } else {
    667       ++sources_it;
    668     }
    669   }
    670 }
    671 
    672 void MediaStreamImpl::OnLocalMediaStreamStop(
    673     const std::string& label) {
    674   DVLOG(1) << "MediaStreamImpl::OnLocalMediaStreamStop(" << label << ")";
    675 
    676   UserMediaRequestInfo* user_media_request = FindUserMediaRequestInfo(label);
    677   if (user_media_request) {
    678     DeleteUserMediaRequestInfo(user_media_request);
    679   }
    680   StopUnreferencedSources(true);
    681 }
    682 
    683 void MediaStreamImpl::OnLocalSourceStop(
    684     const blink::WebMediaStreamSource& source) {
    685   DCHECK(CalledOnValidThread());
    686 
    687   StopLocalSource(source, true);
    688 
    689   bool device_found = false;
    690   for (LocalStreamSources::iterator device_it = local_sources_.begin();
    691        device_it != local_sources_.end(); ++device_it) {
    692     if (device_it->source.id()  == source.id()) {
    693       device_found = true;
    694       local_sources_.erase(device_it);
    695       break;
    696     }
    697   }
    698   CHECK(device_found);
    699 
    700   // Remove the reference to this source from all |user_media_requests_|.
    701   // TODO(perkj): The below is not necessary once we don't need to support
    702   // MediaStream::Stop().
    703   UserMediaRequests::iterator it = user_media_requests_.begin();
    704   while (it != user_media_requests_.end()) {
    705     RemoveSource(source, &(*it)->sources);
    706     if ((*it)->sources.empty()) {
    707       it = user_media_requests_.erase(it);
    708     } else {
    709       ++it;
    710     }
    711   }
    712 }
    713 
    714 void MediaStreamImpl::StopLocalSource(
    715     const blink::WebMediaStreamSource& source,
    716     bool notify_dispatcher) {
    717   MediaStreamSourceExtraData* extra_data =
    718         static_cast<MediaStreamSourceExtraData*> (source.extraData());
    719   CHECK(extra_data);
    720   DVLOG(1) << "MediaStreamImpl::StopLocalSource("
    721            << "{device_id = " << extra_data->device_info().device.id << "})";
    722 
    723   if (source.type() == blink::WebMediaStreamSource::TypeAudio) {
    724     if (extra_data->GetAudioCapturer()) {
    725       extra_data->GetAudioCapturer()->Stop();
    726     }
    727   }
    728 
    729   if (notify_dispatcher)
    730     media_stream_dispatcher_->StopStreamDevice(extra_data->device_info());
    731 
    732   blink::WebMediaStreamSource writable_source(source);
    733   writable_source.setReadyState(
    734       blink::WebMediaStreamSource::ReadyStateEnded);
    735   writable_source.setExtraData(NULL);
    736 }
    737 
    738 void MediaStreamImpl::StopUnreferencedSources(bool notify_dispatcher) {
    739   LocalStreamSources::iterator source_it = local_sources_.begin();
    740   while (source_it != local_sources_.end()) {
    741     if (!FindSourceInRequests(source_it->source)) {
    742       StopLocalSource(source_it->source, notify_dispatcher);
    743       source_it = local_sources_.erase(source_it);
    744     } else {
    745       ++source_it;
    746     }
    747   }
    748 }
    749 
    750 scoped_refptr<WebRtcAudioRenderer> MediaStreamImpl::CreateRemoteAudioRenderer(
    751     webrtc::MediaStreamInterface* stream) {
    752   if (stream->GetAudioTracks().empty())
    753     return NULL;
    754 
    755   DVLOG(1) << "MediaStreamImpl::CreateRemoteAudioRenderer label:"
    756            << stream->label();
    757 
    758   // TODO(tommi): Change the default value of session_id to be
    759   // StreamDeviceInfo::kNoId.  Also update AudioOutputDevice etc.
    760   int session_id = 0, sample_rate = 0, buffer_size = 0;
    761   if (!GetAuthorizedDeviceInfoForAudioRenderer(&session_id,
    762                                                &sample_rate,
    763                                                &buffer_size)) {
    764     GetDefaultOutputDeviceParams(&sample_rate, &buffer_size);
    765   }
    766 
    767   return new WebRtcAudioRenderer(RenderViewObserver::routing_id(),
    768       session_id, sample_rate, buffer_size);
    769 }
    770 
    771 scoped_refptr<WebRtcLocalAudioRenderer>
    772 MediaStreamImpl::CreateLocalAudioRenderer(
    773     const blink::WebMediaStreamTrack& audio_track) {
    774   DVLOG(1) << "MediaStreamImpl::CreateLocalAudioRenderer";
    775 
    776   int session_id = 0, sample_rate = 0, buffer_size = 0;
    777   if (!GetAuthorizedDeviceInfoForAudioRenderer(&session_id,
    778                                                &sample_rate,
    779                                                &buffer_size)) {
    780     GetDefaultOutputDeviceParams(&sample_rate, &buffer_size);
    781   }
    782 
    783   // Create a new WebRtcLocalAudioRenderer instance and connect it to the
    784   // existing WebRtcAudioCapturer so that the renderer can use it as source.
    785   return new WebRtcLocalAudioRenderer(
    786       audio_track,
    787       RenderViewObserver::routing_id(),
    788       session_id,
    789       buffer_size);
    790 }
    791 
    792 bool MediaStreamImpl::GetAuthorizedDeviceInfoForAudioRenderer(
    793     int* session_id,
    794     int* output_sample_rate,
    795     int* output_frames_per_buffer) {
    796   DCHECK(CalledOnValidThread());
    797 
    798   WebRtcAudioDeviceImpl* audio_device =
    799       dependency_factory_->GetWebRtcAudioDevice();
    800   if (!audio_device)
    801     return false;
    802 
    803   if (!audio_device->GetDefaultCapturer())
    804     return false;
    805 
    806   return audio_device->GetDefaultCapturer()->GetPairedOutputParameters(
    807       session_id,
    808       output_sample_rate,
    809       output_frames_per_buffer);
    810 }
    811 
    812 MediaStreamSourceExtraData::MediaStreamSourceExtraData(
    813     const StreamDeviceInfo& device_info,
    814     const SourceStopCallback& stop_callback)
    815     : device_info_(device_info),
    816       stop_callback_(stop_callback) {
    817 }
    818 
    819 MediaStreamSourceExtraData::MediaStreamSourceExtraData() {
    820 }
    821 
    822 MediaStreamSourceExtraData::~MediaStreamSourceExtraData() {}
    823 
    824 void MediaStreamSourceExtraData::OnLocalSourceStop() {
    825   if (!stop_callback_.is_null())
    826     stop_callback_.Run(owner());
    827 }
    828 
    829 MediaStreamExtraData::MediaStreamExtraData(
    830     webrtc::MediaStreamInterface* stream, bool is_local)
    831     : stream_(stream),
    832       is_local_(is_local) {
    833 }
    834 
    835 MediaStreamExtraData::~MediaStreamExtraData() {
    836 }
    837 
    838 void MediaStreamExtraData::SetLocalStreamStopCallback(
    839     const StreamStopCallback& stop_callback) {
    840   stream_stop_callback_ = stop_callback;
    841 }
    842 
    843 void MediaStreamExtraData::OnLocalStreamStop() {
    844   if (!stream_stop_callback_.is_null())
    845     stream_stop_callback_.Run(stream_->label());
    846 }
    847 
    848 MediaStreamImpl::UserMediaRequestInfo::UserMediaRequestInfo(
    849     int request_id,
    850     blink::WebFrame* frame,
    851     const blink::WebUserMediaRequest& request,
    852     bool enable_automatic_output_device_selection)
    853     : request_id(request_id),
    854       generated(false),
    855       enable_automatic_output_device_selection(
    856           enable_automatic_output_device_selection),
    857       frame(frame),
    858       request(request) {
    859 }
    860 
    861 MediaStreamImpl::UserMediaRequestInfo::~UserMediaRequestInfo() {
    862 }
    863 
    864 }  // namespace content
    865