Home | History | Annotate | Download | only in media
      1 // Copyright 2014 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_renderer_factory.h"
      6 
      7 #include "base/strings/utf_string_conversions.h"
      8 #include "content/renderer/media/media_stream.h"
      9 #include "content/renderer/media/media_stream_video_track.h"
     10 #include "content/renderer/media/rtc_video_renderer.h"
     11 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
     12 #include "content/renderer/media/webrtc_audio_renderer.h"
     13 #include "content/renderer/media/webrtc_local_audio_renderer.h"
     14 #include "content/renderer/render_thread_impl.h"
     15 #include "media/base/audio_hardware_config.h"
     16 #include "third_party/WebKit/public/platform/WebMediaStream.h"
     17 #include "third_party/WebKit/public/platform/WebURL.h"
     18 #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
     19 #include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h"
     20 
     21 namespace content {
     22 
     23 namespace {
     24 
     25 PeerConnectionDependencyFactory* GetPeerConnectionDependencyFactory() {
     26   return RenderThreadImpl::current()->GetPeerConnectionDependencyFactory();
     27 }
     28 
     29 void GetDefaultOutputDeviceParams(
     30     int* output_sample_rate, int* output_buffer_size) {
     31   // Fetch the default audio output hardware config.
     32   media::AudioHardwareConfig* hardware_config =
     33       RenderThreadImpl::current()->GetAudioHardwareConfig();
     34   *output_sample_rate = hardware_config->GetOutputSampleRate();
     35   *output_buffer_size = hardware_config->GetOutputBufferSize();
     36 }
     37 
     38 
     39 // Returns a valid session id if a single capture device is currently open
     40 // (and then the matching session_id), otherwise -1.
     41 // This is used to pass on a session id to a webrtc audio renderer (either
     42 // local or remote), so that audio will be rendered to a matching output
     43 // device, should one exist.
     44 // Note that if there are more than one open capture devices the function
     45 // will not be able to pick an appropriate device and return false.
     46 bool GetAuthorizedDeviceInfoForAudioRenderer(
     47     int* session_id,
     48     int* output_sample_rate,
     49     int* output_frames_per_buffer) {
     50   WebRtcAudioDeviceImpl* audio_device =
     51       GetPeerConnectionDependencyFactory()->GetWebRtcAudioDevice();
     52   if (!audio_device)
     53     return false;
     54 
     55   return audio_device->GetAuthorizedDeviceInfoForAudioRenderer(
     56       session_id, output_sample_rate, output_frames_per_buffer);
     57 }
     58 
     59 scoped_refptr<WebRtcAudioRenderer> CreateRemoteAudioRenderer(
     60     webrtc::MediaStreamInterface* stream,
     61     int routing_id,
     62     int render_frame_id) {
     63   if (stream->GetAudioTracks().empty())
     64     return NULL;
     65 
     66   DVLOG(1) << "MediaStreamRendererFactory::CreateRemoteAudioRenderer label:"
     67            << stream->label();
     68 
     69   // TODO(tommi): Change the default value of session_id to be
     70   // StreamDeviceInfo::kNoId.  Also update AudioOutputDevice etc.
     71   int session_id = 0, sample_rate = 0, buffer_size = 0;
     72   if (!GetAuthorizedDeviceInfoForAudioRenderer(&session_id,
     73                                                &sample_rate,
     74                                                &buffer_size)) {
     75     GetDefaultOutputDeviceParams(&sample_rate, &buffer_size);
     76   }
     77 
     78   return new WebRtcAudioRenderer(
     79       stream, routing_id, render_frame_id,  session_id,
     80       sample_rate, buffer_size);
     81 }
     82 
     83 
     84 scoped_refptr<WebRtcLocalAudioRenderer> CreateLocalAudioRenderer(
     85     const blink::WebMediaStreamTrack& audio_track,
     86     int routing_id,
     87     int render_frame_id) {
     88   DVLOG(1) << "MediaStreamRendererFactory::CreateLocalAudioRenderer";
     89 
     90   int session_id = 0, sample_rate = 0, buffer_size = 0;
     91   if (!GetAuthorizedDeviceInfoForAudioRenderer(&session_id,
     92                                                &sample_rate,
     93                                                &buffer_size)) {
     94     GetDefaultOutputDeviceParams(&sample_rate, &buffer_size);
     95   }
     96 
     97   // Create a new WebRtcLocalAudioRenderer instance and connect it to the
     98   // existing WebRtcAudioCapturer so that the renderer can use it as source.
     99   return new WebRtcLocalAudioRenderer(
    100       audio_track,
    101       routing_id,
    102       render_frame_id,
    103       session_id,
    104       buffer_size);
    105 }
    106 
    107 }  // namespace
    108 
    109 
    110 MediaStreamRendererFactory::MediaStreamRendererFactory() {
    111 }
    112 
    113 MediaStreamRendererFactory::~MediaStreamRendererFactory() {
    114 }
    115 
    116 scoped_refptr<VideoFrameProvider>
    117 MediaStreamRendererFactory::GetVideoFrameProvider(
    118     const GURL& url,
    119     const base::Closure& error_cb,
    120     const VideoFrameProvider::RepaintCB& repaint_cb) {
    121   blink::WebMediaStream web_stream =
    122       blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url);
    123   DCHECK(!web_stream.isNull());
    124 
    125   DVLOG(1) << "MediaStreamRendererFactory::GetVideoFrameProvider stream:"
    126            << base::UTF16ToUTF8(web_stream.id());
    127 
    128   blink::WebVector<blink::WebMediaStreamTrack> video_tracks;
    129   web_stream.videoTracks(video_tracks);
    130   if (video_tracks.isEmpty() ||
    131       !MediaStreamVideoTrack::GetTrack(video_tracks[0])) {
    132     return NULL;
    133   }
    134 
    135   return new RTCVideoRenderer(video_tracks[0], error_cb, repaint_cb);
    136 }
    137 
    138 scoped_refptr<MediaStreamAudioRenderer>
    139 MediaStreamRendererFactory::GetAudioRenderer(
    140     const GURL& url, int render_view_id, int render_frame_id) {
    141   blink::WebMediaStream web_stream =
    142       blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url);
    143 
    144   if (web_stream.isNull() || !web_stream.extraData())
    145     return NULL;  // This is not a valid stream.
    146 
    147   DVLOG(1) << "MediaStreamRendererFactory::GetAudioRenderer stream:"
    148            << base::UTF16ToUTF8(web_stream.id());
    149 
    150   MediaStream* native_stream = MediaStream::GetMediaStream(web_stream);
    151 
    152   // TODO(tommi): MediaStreams do not have a 'local or not' concept.
    153   // Tracks _might_, but even so, we need to fix the data flow so that
    154   // it works the same way for all track implementations, local, remote or what
    155   // have you.
    156   // In this function, we should simply create a renderer object that receives
    157   // and mixes audio from all the tracks that belong to the media stream.
    158   // We need to remove the |is_local| property from MediaStreamExtraData since
    159   // this concept is peerconnection specific (is a previously recorded stream
    160   // local or remote?).
    161   if (native_stream->is_local()) {
    162     // Create the local audio renderer if the stream contains audio tracks.
    163     blink::WebVector<blink::WebMediaStreamTrack> audio_tracks;
    164     web_stream.audioTracks(audio_tracks);
    165     if (audio_tracks.isEmpty())
    166       return NULL;
    167 
    168     // TODO(xians): Add support for the case where the media stream contains
    169     // multiple audio tracks.
    170     return CreateLocalAudioRenderer(audio_tracks[0], render_view_id,
    171                                     render_frame_id);
    172   }
    173 
    174   webrtc::MediaStreamInterface* stream =
    175       MediaStream::GetAdapter(web_stream);
    176   if (stream->GetAudioTracks().empty())
    177     return NULL;
    178 
    179   // This is a remote WebRTC media stream.
    180   WebRtcAudioDeviceImpl* audio_device =
    181       GetPeerConnectionDependencyFactory()->GetWebRtcAudioDevice();
    182 
    183   // Share the existing renderer if any, otherwise create a new one.
    184   scoped_refptr<WebRtcAudioRenderer> renderer(audio_device->renderer());
    185   if (!renderer.get()) {
    186     renderer = CreateRemoteAudioRenderer(stream, render_view_id,
    187                                          render_frame_id);
    188 
    189     if (renderer.get() && !audio_device->SetAudioRenderer(renderer.get()))
    190       renderer = NULL;
    191   }
    192 
    193   return renderer.get() ?
    194       renderer->CreateSharedAudioRendererProxy(stream) : NULL;
    195 }
    196 
    197 }  // namespace content
    198