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_number_conversions.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "content/public/common/desktop_media_id.h"
     14 #include "content/renderer/media/media_stream_audio_renderer.h"
     15 #include "content/renderer/media/media_stream_dependency_factory.h"
     16 #include "content/renderer/media/media_stream_dispatcher.h"
     17 #include "content/renderer/media/media_stream_extra_data.h"
     18 #include "content/renderer/media/media_stream_source_extra_data.h"
     19 #include "content/renderer/media/rtc_video_renderer.h"
     20 #include "content/renderer/media/webrtc_audio_capturer.h"
     21 #include "content/renderer/media/webrtc_audio_renderer.h"
     22 #include "content/renderer/media/webrtc_local_audio_renderer.h"
     23 #include "content/renderer/media/webrtc_uma_histograms.h"
     24 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
     25 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
     26 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
     27 #include "third_party/WebKit/public/platform/WebVector.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 std::string GetStreamConstraint(
     36     const WebKit::WebMediaConstraints& constraints, const std::string& key,
     37     bool is_mandatory) {
     38   if (constraints.isNull())
     39     return std::string();
     40 
     41   WebKit::WebString value;
     42   if (is_mandatory) {
     43     constraints.getMandatoryConstraintValue(UTF8ToUTF16(key), value);
     44   } else {
     45     constraints.getOptionalConstraintValue(UTF8ToUTF16(key), value);
     46   }
     47   return UTF16ToUTF8(value);
     48 }
     49 
     50 void UpdateRequestOptions(
     51     const WebKit::WebUserMediaRequest& user_media_request,
     52     StreamOptions* options) {
     53   if (options->audio_type != content::MEDIA_NO_SERVICE) {
     54     std::string audio_stream_source = GetStreamConstraint(
     55         user_media_request.audioConstraints(), kMediaStreamSource, true);
     56     if (audio_stream_source == kMediaStreamSourceTab) {
     57       options->audio_type = content::MEDIA_TAB_AUDIO_CAPTURE;
     58       options->audio_device_id = GetStreamConstraint(
     59           user_media_request.audioConstraints(),
     60           kMediaStreamSourceId, true);
     61     } else if (audio_stream_source == kMediaStreamSourceSystem) {
     62       options->audio_type = content::MEDIA_SYSTEM_AUDIO_CAPTURE;
     63     }
     64   }
     65 
     66   if (options->video_type != content::MEDIA_NO_SERVICE) {
     67     std::string video_stream_source = GetStreamConstraint(
     68         user_media_request.videoConstraints(), kMediaStreamSource, true);
     69     if (video_stream_source == kMediaStreamSourceTab) {
     70       options->video_type = content::MEDIA_TAB_VIDEO_CAPTURE;
     71       options->video_device_id = GetStreamConstraint(
     72           user_media_request.videoConstraints(),
     73           kMediaStreamSourceId, true);
     74     } else if (video_stream_source == kMediaStreamSourceScreen) {
     75       options->video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE;
     76       options->video_device_id =
     77           DesktopMediaID(DesktopMediaID::TYPE_SCREEN, 0).ToString();
     78     }
     79   }
     80 }
     81 
     82 static int g_next_request_id  = 0;
     83 
     84 // Creates a WebKit representation of a stream sources based on
     85 // |devices| from the MediaStreamDispatcher.
     86 void CreateWebKitSourceVector(
     87     const std::string& label,
     88     const StreamDeviceInfoArray& devices,
     89     WebKit::WebMediaStreamSource::Type type,
     90     WebKit::WebVector<WebKit::WebMediaStreamSource>& webkit_sources) {
     91   CHECK_EQ(devices.size(), webkit_sources.size());
     92   for (size_t i = 0; i < devices.size(); ++i) {
     93     const char* track_type =
     94         (type == WebKit::WebMediaStreamSource::TypeAudio) ? "a" : "v";
     95     std::string source_id = base::StringPrintf("%s%s%u", label.c_str(),
     96                                                track_type,
     97                                                static_cast<unsigned int>(i));
     98     webkit_sources[i].initialize(
     99           UTF8ToUTF16(source_id),
    100           type,
    101           UTF8ToUTF16(devices[i].device.name));
    102     webkit_sources[i].setExtraData(
    103         new content::MediaStreamSourceExtraData(devices[i], webkit_sources[i]));
    104     webkit_sources[i].setDeviceId(UTF8ToUTF16(
    105         base::IntToString(devices[i].session_id)));
    106   }
    107 }
    108 
    109 webrtc::MediaStreamInterface* GetNativeMediaStream(
    110     const WebKit::WebMediaStream& web_stream) {
    111   content::MediaStreamExtraData* extra_data =
    112       static_cast<content::MediaStreamExtraData*>(web_stream.extraData());
    113   if (!extra_data)
    114     return NULL;
    115   return extra_data->stream().get();
    116 }
    117 
    118 }  // namespace
    119 
    120 MediaStreamImpl::MediaStreamImpl(
    121     RenderView* render_view,
    122     MediaStreamDispatcher* media_stream_dispatcher,
    123     MediaStreamDependencyFactory* dependency_factory)
    124     : RenderViewObserver(render_view),
    125       dependency_factory_(dependency_factory),
    126       media_stream_dispatcher_(media_stream_dispatcher) {
    127 }
    128 
    129 MediaStreamImpl::~MediaStreamImpl() {
    130 }
    131 
    132 void MediaStreamImpl::OnLocalMediaStreamStop(
    133     const std::string& label) {
    134   DVLOG(1) << "MediaStreamImpl::OnLocalMediaStreamStop(" << label << ")";
    135 
    136   UserMediaRequestInfo* user_media_request = FindUserMediaRequestInfo(label);
    137   if (user_media_request) {
    138     StopLocalAudioTrack(user_media_request->web_stream);
    139     media_stream_dispatcher_->StopStream(label);
    140     DeleteUserMediaRequestInfo(user_media_request);
    141   } else {
    142     DVLOG(1) << "MediaStreamImpl::OnLocalMediaStreamStop: the stream has "
    143              << "already been stopped.";
    144   }
    145 }
    146 
    147 void MediaStreamImpl::requestUserMedia(
    148     const WebKit::WebUserMediaRequest& user_media_request) {
    149   // Save histogram data so we can see how much GetUserMedia is used.
    150   // The histogram counts the number of calls to the JS API
    151   // webGetUserMedia.
    152   UpdateWebRTCMethodCount(WEBKIT_GET_USER_MEDIA);
    153   DCHECK(CalledOnValidThread());
    154   int request_id = g_next_request_id++;
    155   StreamOptions options(MEDIA_NO_SERVICE, MEDIA_NO_SERVICE);
    156   WebKit::WebFrame* frame = NULL;
    157   GURL security_origin;
    158 
    159   // |user_media_request| can't be mocked. So in order to test at all we check
    160   // if it isNull.
    161   if (user_media_request.isNull()) {
    162     // We are in a test.
    163     options.audio_type = MEDIA_DEVICE_AUDIO_CAPTURE;
    164     options.video_type = MEDIA_DEVICE_VIDEO_CAPTURE;
    165   } else {
    166     if (user_media_request.audio()) {
    167       options.audio_type = MEDIA_DEVICE_AUDIO_CAPTURE;
    168       options.audio_device_id = GetStreamConstraint(
    169           user_media_request.audioConstraints(),
    170           kMediaStreamSourceInfoId, false);
    171     }
    172     if (user_media_request.video()) {
    173       options.video_type = MEDIA_DEVICE_VIDEO_CAPTURE;
    174       options.video_device_id = GetStreamConstraint(
    175           user_media_request.videoConstraints(),
    176           kMediaStreamSourceInfoId, false);
    177     }
    178 
    179     security_origin = GURL(user_media_request.securityOrigin().toString());
    180     // Get the WebFrame that requested a MediaStream.
    181     // The frame is needed to tell the MediaStreamDispatcher when a stream goes
    182     // out of scope.
    183     frame = user_media_request.ownerDocument().frame();
    184     DCHECK(frame);
    185 
    186     UpdateRequestOptions(user_media_request, &options);
    187   }
    188 
    189   DVLOG(1) << "MediaStreamImpl::requestUserMedia(" << request_id << ", [ "
    190            << "audio=" << (options.audio_type)
    191            << ", video=" << (options.video_type) << " ], "
    192            << security_origin.spec() << ")";
    193 
    194   user_media_requests_.push_back(
    195       new UserMediaRequestInfo(request_id, frame, user_media_request));
    196 
    197   media_stream_dispatcher_->GenerateStream(
    198       request_id,
    199       AsWeakPtr(),
    200       options,
    201       security_origin);
    202 }
    203 
    204 void MediaStreamImpl::cancelUserMediaRequest(
    205     const WebKit::WebUserMediaRequest& user_media_request) {
    206   DCHECK(CalledOnValidThread());
    207   UserMediaRequestInfo* request = FindUserMediaRequestInfo(user_media_request);
    208   if (request) {
    209     // We can't abort the stream generation process.
    210     // Instead, erase the request. Once the stream is generated we will stop the
    211     // stream if the request does not exist.
    212     DeleteUserMediaRequestInfo(request);
    213   }
    214 }
    215 
    216 WebKit::WebMediaStream MediaStreamImpl::GetMediaStream(
    217     const GURL& url) {
    218   return WebKit::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url);
    219 }
    220 
    221 bool MediaStreamImpl::IsMediaStream(const GURL& url) {
    222   WebKit::WebMediaStream web_stream(
    223       WebKit::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url));
    224 
    225   if (web_stream.isNull() || !web_stream.extraData())
    226     return false;  // This is not a valid stream.
    227 
    228   webrtc::MediaStreamInterface* stream = GetNativeMediaStream(web_stream);
    229   return (stream &&
    230       (!stream->GetVideoTracks().empty() || !stream->GetAudioTracks().empty()));
    231 }
    232 
    233 scoped_refptr<VideoFrameProvider>
    234 MediaStreamImpl::GetVideoFrameProvider(
    235     const GURL& url,
    236     const base::Closure& error_cb,
    237     const VideoFrameProvider::RepaintCB& repaint_cb) {
    238   DCHECK(CalledOnValidThread());
    239   WebKit::WebMediaStream web_stream(GetMediaStream(url));
    240 
    241   if (web_stream.isNull() || !web_stream.extraData())
    242     return NULL;  // This is not a valid stream.
    243 
    244   DVLOG(1) << "MediaStreamImpl::GetVideoFrameProvider stream:"
    245            << UTF16ToUTF8(web_stream.id());
    246 
    247   webrtc::MediaStreamInterface* stream = GetNativeMediaStream(web_stream);
    248   if (stream)
    249     return CreateVideoFrameProvider(stream, error_cb, repaint_cb);
    250   NOTREACHED();
    251   return NULL;
    252 }
    253 
    254 scoped_refptr<MediaStreamAudioRenderer>
    255 MediaStreamImpl::GetAudioRenderer(const GURL& url) {
    256   DCHECK(CalledOnValidThread());
    257   WebKit::WebMediaStream web_stream(GetMediaStream(url));
    258 
    259   if (web_stream.isNull() || !web_stream.extraData())
    260     return NULL;  // This is not a valid stream.
    261 
    262   DVLOG(1) << "MediaStreamImpl::GetAudioRenderer stream:"
    263            << UTF16ToUTF8(web_stream.id());
    264 
    265   MediaStreamExtraData* extra_data =
    266       static_cast<MediaStreamExtraData*>(web_stream.extraData());
    267 
    268   if (extra_data->is_local()) {
    269     // Create the local audio renderer if the stream contains audio tracks.
    270     return CreateLocalAudioRenderer(extra_data->stream().get());
    271   }
    272 
    273   webrtc::MediaStreamInterface* stream = extra_data->stream().get();
    274   if (!stream || stream->GetAudioTracks().empty())
    275     return NULL;
    276 
    277   // This is a remote media stream.
    278   WebRtcAudioDeviceImpl* audio_device =
    279       dependency_factory_->GetWebRtcAudioDevice();
    280 
    281   // Share the existing renderer if any, otherwise create a new one.
    282   scoped_refptr<WebRtcAudioRenderer> renderer(audio_device->renderer());
    283   if (!renderer.get()) {
    284     renderer = CreateRemoteAudioRenderer(extra_data->stream().get());
    285 
    286     if (renderer.get() && !audio_device->SetAudioRenderer(renderer.get()))
    287       renderer = NULL;
    288   }
    289   return renderer;
    290 }
    291 
    292 // Callback from MediaStreamDispatcher.
    293 // The requested stream have been generated by the MediaStreamDispatcher.
    294 void MediaStreamImpl::OnStreamGenerated(
    295     int request_id,
    296     const std::string& label,
    297     const StreamDeviceInfoArray& audio_array,
    298     const StreamDeviceInfoArray& video_array) {
    299   DCHECK(CalledOnValidThread());
    300   DVLOG(1) << "MediaStreamImpl::OnStreamGenerated stream:" << label;
    301 
    302   UserMediaRequestInfo* request_info = FindUserMediaRequestInfo(request_id);
    303   if (!request_info) {
    304     // This can happen if the request is canceled or the frame reloads while
    305     // MediaStreamDispatcher is processing the request.
    306     // We need to tell the dispatcher to stop the stream.
    307     media_stream_dispatcher_->StopStream(label);
    308     DVLOG(1) << "Request ID not found";
    309     return;
    310   }
    311   request_info->generated = true;
    312 
    313   WebKit::WebVector<WebKit::WebMediaStreamSource> audio_source_vector(
    314       audio_array.size());
    315   CreateWebKitSourceVector(label, audio_array,
    316                            WebKit::WebMediaStreamSource::TypeAudio,
    317                            audio_source_vector);
    318   request_info->audio_sources.assign(audio_source_vector);
    319   WebKit::WebVector<WebKit::WebMediaStreamSource> video_source_vector(
    320       video_array.size());
    321   CreateWebKitSourceVector(label, video_array,
    322                            WebKit::WebMediaStreamSource::TypeVideo,
    323                            video_source_vector);
    324   request_info->video_sources.assign(video_source_vector);
    325 
    326   WebKit::WebUserMediaRequest* request = &(request_info->request);
    327   WebKit::WebString webkit_id = UTF8ToUTF16(label);
    328   WebKit::WebMediaStream* web_stream = &(request_info->web_stream);
    329 
    330   WebKit::WebVector<WebKit::WebMediaStreamTrack> audio_track_vector(
    331       audio_array.size());
    332   for (size_t i = 0; i < audio_track_vector.size(); ++i) {
    333     audio_track_vector[i].initialize(audio_source_vector[i].id(),
    334                                      audio_source_vector[i]);
    335   }
    336 
    337   WebKit::WebVector<WebKit::WebMediaStreamTrack> video_track_vector(
    338       video_array.size());
    339   for (size_t i = 0; i < video_track_vector.size(); ++i) {
    340     video_track_vector[i].initialize(video_source_vector[i].id(),
    341                                      video_source_vector[i]);
    342   }
    343 
    344   web_stream->initialize(webkit_id, audio_track_vector,
    345                          video_track_vector);
    346 
    347   // WebUserMediaRequest don't have an implementation in unit tests.
    348   // Therefore we need to check for isNull here.
    349   WebKit::WebMediaConstraints audio_constraints = request->isNull() ?
    350       WebKit::WebMediaConstraints() : request->audioConstraints();
    351   WebKit::WebMediaConstraints video_constraints = request->isNull() ?
    352       WebKit::WebMediaConstraints() : request->videoConstraints();
    353 
    354   dependency_factory_->CreateNativeMediaSources(
    355       RenderViewObserver::routing_id(),
    356       audio_constraints, video_constraints, web_stream,
    357       base::Bind(&MediaStreamImpl::OnCreateNativeSourcesComplete, AsWeakPtr()));
    358 }
    359 
    360 // Callback from MediaStreamDispatcher.
    361 // The requested stream failed to be generated.
    362 void MediaStreamImpl::OnStreamGenerationFailed(int request_id) {
    363   DCHECK(CalledOnValidThread());
    364   DVLOG(1) << "MediaStreamImpl::OnStreamGenerationFailed("
    365            << request_id << ")";
    366   UserMediaRequestInfo* request_info = FindUserMediaRequestInfo(request_id);
    367   if (!request_info) {
    368     // This can happen if the request is canceled or the frame reloads while
    369     // MediaStreamDispatcher is processing the request.
    370     DVLOG(1) << "Request ID not found";
    371     return;
    372   }
    373   CompleteGetUserMediaRequest(request_info->web_stream,
    374                               &request_info->request,
    375                               false);
    376   DeleteUserMediaRequestInfo(request_info);
    377 }
    378 
    379 // Callback from MediaStreamDispatcher.
    380 // The user has requested to stop the media stream.
    381 void MediaStreamImpl::OnStopGeneratedStream(const std::string& label) {
    382   DCHECK(CalledOnValidThread());
    383   DVLOG(1) << "MediaStreamImpl::OnStopGeneratedStream(" << label << ")";
    384 
    385   UserMediaRequestInfo* user_media_request = FindUserMediaRequestInfo(label);
    386   if (user_media_request) {
    387     // No need to call media_stream_dispatcher_->StopStream() because the
    388     // request has come from the browser process.
    389     StopLocalAudioTrack(user_media_request->web_stream);
    390     DeleteUserMediaRequestInfo(user_media_request);
    391   } else {
    392     DVLOG(1) << "MediaStreamImpl::OnStopGeneratedStream: the stream has "
    393              << "already been stopped.";
    394   }
    395 }
    396 
    397 // Callback from MediaStreamDependencyFactory when the sources in |web_stream|
    398 // have been generated.
    399 void MediaStreamImpl::OnCreateNativeSourcesComplete(
    400     WebKit::WebMediaStream* web_stream,
    401     bool request_succeeded) {
    402   UserMediaRequestInfo* request_info = FindUserMediaRequestInfo(web_stream);
    403   if (!request_info) {
    404     // This can happen if the request is canceled or the frame reloads while
    405     // MediaStreamDependencyFactory is creating the sources.
    406     DVLOG(1) << "Request ID not found";
    407     return;
    408   }
    409 
    410   // Create a native representation of the stream.
    411   if (request_succeeded) {
    412     dependency_factory_->CreateNativeLocalMediaStream(
    413         web_stream,
    414         base::Bind(&MediaStreamImpl::OnLocalMediaStreamStop, AsWeakPtr()));
    415   }
    416   CompleteGetUserMediaRequest(request_info->web_stream, &request_info->request,
    417                               request_succeeded);
    418   if (!request_succeeded) {
    419     OnLocalMediaStreamStop(UTF16ToUTF8(web_stream->id()));
    420   }
    421 }
    422 
    423 void MediaStreamImpl::OnDevicesEnumerated(
    424     int request_id,
    425     const StreamDeviceInfoArray& device_array) {
    426   DVLOG(1) << "MediaStreamImpl::OnDevicesEnumerated("
    427            << request_id << ")";
    428   NOTIMPLEMENTED();
    429 }
    430 
    431 void MediaStreamImpl::OnDevicesEnumerationFailed(int request_id) {
    432   DVLOG(1) << "MediaStreamImpl::OnDevicesEnumerationFailed("
    433            << request_id << ")";
    434   NOTIMPLEMENTED();
    435 }
    436 
    437 void MediaStreamImpl::OnDeviceOpened(
    438     int request_id,
    439     const std::string& label,
    440     const StreamDeviceInfo& video_device) {
    441   DVLOG(1) << "MediaStreamImpl::OnDeviceOpened("
    442            << request_id << ", " << label << ")";
    443   NOTIMPLEMENTED();
    444 }
    445 
    446 void MediaStreamImpl::OnDeviceOpenFailed(int request_id) {
    447   DVLOG(1) << "MediaStreamImpl::VideoDeviceOpenFailed("
    448            << request_id << ")";
    449   NOTIMPLEMENTED();
    450 }
    451 
    452 void MediaStreamImpl::CompleteGetUserMediaRequest(
    453     const WebKit::WebMediaStream& stream,
    454     WebKit::WebUserMediaRequest* request_info,
    455     bool request_succeeded) {
    456   if (request_succeeded) {
    457     request_info->requestSucceeded(stream);
    458   } else {
    459     request_info->requestFailed();
    460   }
    461 }
    462 
    463 MediaStreamImpl::UserMediaRequestInfo*
    464 MediaStreamImpl::FindUserMediaRequestInfo(int request_id) {
    465   UserMediaRequests::iterator it = user_media_requests_.begin();
    466   for (; it != user_media_requests_.end(); ++it) {
    467     if ((*it)->request_id == request_id)
    468       return (*it);
    469   }
    470   return NULL;
    471 }
    472 
    473 MediaStreamImpl::UserMediaRequestInfo*
    474 MediaStreamImpl::FindUserMediaRequestInfo(
    475     const WebKit::WebUserMediaRequest& request) {
    476   UserMediaRequests::iterator it = user_media_requests_.begin();
    477   for (; it != user_media_requests_.end(); ++it) {
    478     if ((*it)->request == request)
    479       return (*it);
    480   }
    481   return NULL;
    482 }
    483 
    484 MediaStreamImpl::UserMediaRequestInfo*
    485 MediaStreamImpl::FindUserMediaRequestInfo(const std::string& label) {
    486   UserMediaRequests::iterator it = user_media_requests_.begin();
    487   for (; it != user_media_requests_.end(); ++it) {
    488     if ((*it)->generated && (*it)->web_stream.id() == UTF8ToUTF16(label))
    489       return (*it);
    490   }
    491   return NULL;
    492 }
    493 
    494 MediaStreamImpl::UserMediaRequestInfo*
    495 MediaStreamImpl::FindUserMediaRequestInfo(
    496     WebKit::WebMediaStream* web_stream) {
    497   UserMediaRequests::iterator it = user_media_requests_.begin();
    498   for (; it != user_media_requests_.end(); ++it) {
    499     if (&((*it)->web_stream) == web_stream)
    500       return  (*it);
    501   }
    502   return NULL;
    503 }
    504 
    505 void MediaStreamImpl::DeleteUserMediaRequestInfo(
    506     UserMediaRequestInfo* request) {
    507   UserMediaRequests::iterator it = user_media_requests_.begin();
    508   for (; it != user_media_requests_.end(); ++it) {
    509     if ((*it) == request) {
    510       user_media_requests_.erase(it);
    511       return;
    512     }
    513   }
    514   NOTREACHED();
    515 }
    516 
    517 void MediaStreamImpl::FrameDetached(WebKit::WebFrame* frame) {
    518   // Do same thing as FrameWillClose.
    519   FrameWillClose(frame);
    520 }
    521 
    522 void MediaStreamImpl::FrameWillClose(WebKit::WebFrame* frame) {
    523   // Loop through all UserMediaRequests and find the requests that belong to the
    524   // frame that is being closed.
    525   UserMediaRequests::iterator request_it = user_media_requests_.begin();
    526 
    527   while (request_it != user_media_requests_.end()) {
    528     if ((*request_it)->frame == frame) {
    529       DVLOG(1) << "MediaStreamImpl::FrameWillClose: "
    530                << "Cancel user media request " << (*request_it)->request_id;
    531       // If the request is generated, it means that the MediaStreamDispatcher
    532       // has generated a stream for us and we need to let the
    533       // MediaStreamDispatcher know that the stream is no longer wanted.
    534       // If not, we cancel the request and delete the request object.
    535       if ((*request_it)->generated) {
    536         // Stop the local audio track before closing the device in the browser.
    537         StopLocalAudioTrack((*request_it)->web_stream);
    538 
    539         media_stream_dispatcher_->StopStream(
    540             UTF16ToUTF8((*request_it)->web_stream.id()));
    541       } else {
    542         media_stream_dispatcher_->CancelGenerateStream(
    543             (*request_it)->request_id, AsWeakPtr());
    544       }
    545       request_it = user_media_requests_.erase(request_it);
    546     } else {
    547       ++request_it;
    548     }
    549   }
    550 }
    551 
    552 scoped_refptr<VideoFrameProvider>
    553 MediaStreamImpl::CreateVideoFrameProvider(
    554     webrtc::MediaStreamInterface* stream,
    555     const base::Closure& error_cb,
    556     const VideoFrameProvider::RepaintCB& repaint_cb) {
    557   if (stream->GetVideoTracks().empty())
    558     return NULL;
    559 
    560   DVLOG(1) << "MediaStreamImpl::CreateRemoteVideoFrameProvider label:"
    561            << stream->label();
    562 
    563   return new RTCVideoRenderer(
    564       stream->GetVideoTracks()[0],
    565       error_cb,
    566       repaint_cb);
    567 }
    568 
    569 scoped_refptr<WebRtcAudioRenderer> MediaStreamImpl::CreateRemoteAudioRenderer(
    570     webrtc::MediaStreamInterface* stream) {
    571   if (stream->GetAudioTracks().empty())
    572     return NULL;
    573 
    574   DVLOG(1) << "MediaStreamImpl::CreateRemoteAudioRenderer label:"
    575            << stream->label();
    576 
    577   return new WebRtcAudioRenderer(RenderViewObserver::routing_id());
    578 }
    579 
    580 scoped_refptr<WebRtcLocalAudioRenderer>
    581 MediaStreamImpl::CreateLocalAudioRenderer(
    582     webrtc::MediaStreamInterface* stream) {
    583   if (stream->GetAudioTracks().empty())
    584     return NULL;
    585 
    586   DVLOG(1) << "MediaStreamImpl::CreateLocalAudioRenderer label:"
    587            << stream->label();
    588 
    589   webrtc::AudioTrackVector audio_tracks = stream->GetAudioTracks();
    590   DCHECK_EQ(audio_tracks.size(), 1u);
    591   webrtc::AudioTrackInterface* audio_track = audio_tracks[0];
    592   DVLOG(1) << "audio_track.kind   : " << audio_track->kind()
    593            << "audio_track.id     : " << audio_track->id()
    594            << "audio_track.enabled: " << audio_track->enabled();
    595 
    596   // Create a new WebRtcLocalAudioRenderer instance and connect it to the
    597   // existing WebRtcAudioCapturer so that the renderer can use it as source.
    598   return new WebRtcLocalAudioRenderer(
    599       static_cast<WebRtcLocalAudioTrack*>(audio_track),
    600       RenderViewObserver::routing_id());
    601 }
    602 
    603 void MediaStreamImpl::StopLocalAudioTrack(
    604     const WebKit::WebMediaStream& web_stream) {
    605   MediaStreamExtraData* extra_data = static_cast<MediaStreamExtraData*>(
    606       web_stream.extraData());
    607   if (extra_data && extra_data->is_local() && extra_data->stream().get() &&
    608       !extra_data->stream()->GetAudioTracks().empty()) {
    609     webrtc::AudioTrackVector audio_tracks =
    610         extra_data->stream()->GetAudioTracks();
    611     for (size_t i = 0; i < audio_tracks.size(); ++i) {
    612       WebRtcLocalAudioTrack* audio_track = static_cast<WebRtcLocalAudioTrack*>(
    613           audio_tracks[i].get());
    614       // Remove the WebRtcAudioDevice as the sink to the local audio track.
    615       audio_track->RemoveSink(dependency_factory_->GetWebRtcAudioDevice());
    616       // Stop the audio track. This will unhook the audio track from the
    617       // capturer and will shutdown the source of the capturer if it is the
    618       // last audio track connecting to the capturer.
    619       audio_track->Stop();
    620     }
    621   }
    622 }
    623 
    624 MediaStreamSourceExtraData::MediaStreamSourceExtraData(
    625     const StreamDeviceInfo& device_info,
    626     const WebKit::WebMediaStreamSource& webkit_source)
    627     : device_info_(device_info),
    628       webkit_source_(webkit_source) {
    629 }
    630 
    631 MediaStreamSourceExtraData::MediaStreamSourceExtraData(
    632     media::AudioCapturerSource* source)
    633     : audio_source_(source)  {
    634 }
    635 
    636 MediaStreamSourceExtraData::~MediaStreamSourceExtraData() {}
    637 
    638 MediaStreamExtraData::MediaStreamExtraData(
    639     webrtc::MediaStreamInterface* stream, bool is_local)
    640     : stream_(stream),
    641       is_local_(is_local) {
    642 }
    643 
    644 MediaStreamExtraData::~MediaStreamExtraData() {
    645 }
    646 
    647 void MediaStreamExtraData::SetLocalStreamStopCallback(
    648     const StreamStopCallback& stop_callback) {
    649   stream_stop_callback_ = stop_callback;
    650 }
    651 
    652 void MediaStreamExtraData::OnLocalStreamStop() {
    653   if (!stream_stop_callback_.is_null())
    654     stream_stop_callback_.Run(stream_->label());
    655 }
    656 
    657 MediaStreamImpl::UserMediaRequestInfo::UserMediaRequestInfo()
    658     : request_id(0), generated(false), frame(NULL), request() {
    659 }
    660 
    661 MediaStreamImpl::UserMediaRequestInfo::UserMediaRequestInfo(
    662     int request_id,
    663     WebKit::WebFrame* frame,
    664     const WebKit::WebUserMediaRequest& request)
    665     : request_id(request_id), generated(false), frame(frame),
    666       request(request) {
    667 }
    668 
    669 MediaStreamImpl::UserMediaRequestInfo::~UserMediaRequestInfo() {
    670   // Release the extra data field of all sources created by
    671   // MediaStreamImpl for this request. This breaks the circular reference to
    672   // WebKit::MediaStreamSource.
    673   // TODO(tommyw): Remove this once WebKit::MediaStreamSource::Owner has been
    674   // implemented to fully avoid a circular dependency.
    675   for (size_t i = 0; i < audio_sources.size(); ++i) {
    676     audio_sources[i].setReadyState(
    677         WebKit::WebMediaStreamSource::ReadyStateEnded);
    678     audio_sources[i].setExtraData(NULL);
    679   }
    680 
    681   for (size_t i = 0; i < video_sources.size(); ++i) {
    682     video_sources[i].setReadyState(
    683             WebKit::WebMediaStreamSource::ReadyStateEnded);
    684     video_sources[i].setExtraData(NULL);
    685   }
    686 }
    687 
    688 }  // namespace content
    689