blob: 628364465aa447c2757cd02654ba07a44360a0c5 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/media/media_stream_renderer_factory.h"
#include "base/strings/utf_string_conversions.h"
#include "content/renderer/media/media_stream.h"
#include "content/renderer/media/media_stream_video_track.h"
#include "content/renderer/media/rtc_video_renderer.h"
#include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
#include "content/renderer/media/webrtc_audio_renderer.h"
#include "content/renderer/media/webrtc_local_audio_renderer.h"
#include "content/renderer/render_thread_impl.h"
#include "media/base/audio_hardware_config.h"
#include "third_party/WebKit/public/platform/WebMediaStream.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
#include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h"
namespace content {
namespace {
PeerConnectionDependencyFactory* GetPeerConnectionDependencyFactory() {
return RenderThreadImpl::current()->GetPeerConnectionDependencyFactory();
}
void GetDefaultOutputDeviceParams(
int* output_sample_rate, int* output_buffer_size) {
// Fetch the default audio output hardware config.
media::AudioHardwareConfig* hardware_config =
RenderThreadImpl::current()->GetAudioHardwareConfig();
*output_sample_rate = hardware_config->GetOutputSampleRate();
*output_buffer_size = hardware_config->GetOutputBufferSize();
}
// Returns a valid session id if a single capture device is currently open
// (and then the matching session_id), otherwise -1.
// This is used to pass on a session id to a webrtc audio renderer (either
// local or remote), so that audio will be rendered to a matching output
// device, should one exist.
// Note that if there are more than one open capture devices the function
// will not be able to pick an appropriate device and return false.
bool GetAuthorizedDeviceInfoForAudioRenderer(
int* session_id,
int* output_sample_rate,
int* output_frames_per_buffer) {
WebRtcAudioDeviceImpl* audio_device =
GetPeerConnectionDependencyFactory()->GetWebRtcAudioDevice();
if (!audio_device)
return false;
return audio_device->GetAuthorizedDeviceInfoForAudioRenderer(
session_id, output_sample_rate, output_frames_per_buffer);
}
scoped_refptr<WebRtcAudioRenderer> CreateRemoteAudioRenderer(
webrtc::MediaStreamInterface* stream,
int routing_id,
int render_frame_id) {
if (stream->GetAudioTracks().empty())
return NULL;
DVLOG(1) << "MediaStreamRendererFactory::CreateRemoteAudioRenderer label:"
<< stream->label();
// TODO(tommi): Change the default value of session_id to be
// StreamDeviceInfo::kNoId. Also update AudioOutputDevice etc.
int session_id = 0, sample_rate = 0, buffer_size = 0;
if (!GetAuthorizedDeviceInfoForAudioRenderer(&session_id,
&sample_rate,
&buffer_size)) {
GetDefaultOutputDeviceParams(&sample_rate, &buffer_size);
}
return new WebRtcAudioRenderer(
stream, routing_id, render_frame_id, session_id,
sample_rate, buffer_size);
}
scoped_refptr<WebRtcLocalAudioRenderer> CreateLocalAudioRenderer(
const blink::WebMediaStreamTrack& audio_track,
int routing_id,
int render_frame_id) {
DVLOG(1) << "MediaStreamRendererFactory::CreateLocalAudioRenderer";
int session_id = 0, sample_rate = 0, buffer_size = 0;
if (!GetAuthorizedDeviceInfoForAudioRenderer(&session_id,
&sample_rate,
&buffer_size)) {
GetDefaultOutputDeviceParams(&sample_rate, &buffer_size);
}
// Create a new WebRtcLocalAudioRenderer instance and connect it to the
// existing WebRtcAudioCapturer so that the renderer can use it as source.
return new WebRtcLocalAudioRenderer(
audio_track,
routing_id,
render_frame_id,
session_id,
buffer_size);
}
} // namespace
MediaStreamRendererFactory::MediaStreamRendererFactory() {
}
MediaStreamRendererFactory::~MediaStreamRendererFactory() {
}
scoped_refptr<VideoFrameProvider>
MediaStreamRendererFactory::GetVideoFrameProvider(
const GURL& url,
const base::Closure& error_cb,
const VideoFrameProvider::RepaintCB& repaint_cb) {
blink::WebMediaStream web_stream =
blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url);
DCHECK(!web_stream.isNull());
DVLOG(1) << "MediaStreamRendererFactory::GetVideoFrameProvider stream:"
<< base::UTF16ToUTF8(web_stream.id());
blink::WebVector<blink::WebMediaStreamTrack> video_tracks;
web_stream.videoTracks(video_tracks);
if (video_tracks.isEmpty() ||
!MediaStreamVideoTrack::GetTrack(video_tracks[0])) {
return NULL;
}
return new RTCVideoRenderer(video_tracks[0], error_cb, repaint_cb);
}
scoped_refptr<MediaStreamAudioRenderer>
MediaStreamRendererFactory::GetAudioRenderer(
const GURL& url, int render_view_id, int render_frame_id) {
blink::WebMediaStream web_stream =
blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url);
if (web_stream.isNull() || !web_stream.extraData())
return NULL; // This is not a valid stream.
DVLOG(1) << "MediaStreamRendererFactory::GetAudioRenderer stream:"
<< base::UTF16ToUTF8(web_stream.id());
MediaStream* native_stream = MediaStream::GetMediaStream(web_stream);
// TODO(tommi): MediaStreams do not have a 'local or not' concept.
// Tracks _might_, but even so, we need to fix the data flow so that
// it works the same way for all track implementations, local, remote or what
// have you.
// In this function, we should simply create a renderer object that receives
// and mixes audio from all the tracks that belong to the media stream.
// We need to remove the |is_local| property from MediaStreamExtraData since
// this concept is peerconnection specific (is a previously recorded stream
// local or remote?).
if (native_stream->is_local()) {
// Create the local audio renderer if the stream contains audio tracks.
blink::WebVector<blink::WebMediaStreamTrack> audio_tracks;
web_stream.audioTracks(audio_tracks);
if (audio_tracks.isEmpty())
return NULL;
// TODO(xians): Add support for the case where the media stream contains
// multiple audio tracks.
return CreateLocalAudioRenderer(audio_tracks[0], render_view_id,
render_frame_id);
}
webrtc::MediaStreamInterface* stream =
MediaStream::GetAdapter(web_stream);
if (stream->GetAudioTracks().empty())
return NULL;
// This is a remote WebRTC media stream.
WebRtcAudioDeviceImpl* audio_device =
GetPeerConnectionDependencyFactory()->GetWebRtcAudioDevice();
// Share the existing renderer if any, otherwise create a new one.
scoped_refptr<WebRtcAudioRenderer> renderer(audio_device->renderer());
if (!renderer.get()) {
renderer = CreateRemoteAudioRenderer(stream, render_view_id,
render_frame_id);
if (renderer.get() && !audio_device->SetAudioRenderer(renderer.get()))
renderer = NULL;
}
return renderer.get() ?
renderer->CreateSharedAudioRendererProxy(stream) : NULL;
}
} // namespace content