1 // Copyright 2013 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.
5 #include "chrome/renderer/media/cast_rtp_stream.h"
8 #include "base/logging.h"
9 #include "base/memory/weak_ptr.h"
10 #include "chrome/renderer/media/cast_session.h"
11 #include "chrome/renderer/media/cast_udp_transport.h"
12 #include "content/public/renderer/media_stream_audio_sink.h"
13 #include "content/public/renderer/media_stream_video_sink.h"
14 #include "media/base/audio_bus.h"
15 #include "media/cast/cast_config.h"
16 #include "media/cast/cast_defines.h"
17 #include "media/cast/cast_sender.h"
18 #include "media/cast/transport/cast_transport_config.h"
19 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
21 using media::cast::AudioSenderConfig
;
22 using media::cast::VideoSenderConfig
;
25 const char kCodecNameOpus
[] = "OPUS";
26 const char kCodecNameVp8
[] = "VP8";
28 CastRtpPayloadParams
DefaultOpusPayload() {
29 CastRtpPayloadParams payload
;
31 payload
.feedback_ssrc
= 1;
32 payload
.payload_type
= 127;
33 payload
.codec_name
= kCodecNameOpus
;
34 payload
.clock_rate
= 48000;
36 payload
.min_bitrate
= payload
.max_bitrate
=
37 media::cast::kDefaultAudioEncoderBitrate
;
41 CastRtpPayloadParams
DefaultVp8Payload() {
42 CastRtpPayloadParams payload
;
44 payload
.feedback_ssrc
= 12;
45 payload
.payload_type
= 96;
46 payload
.codec_name
= kCodecNameVp8
;
47 payload
.clock_rate
= 90000;
50 payload
.min_bitrate
= 50 * 1000;
51 payload
.max_bitrate
= 2000 * 1000;
55 std::vector
<CastRtpParams
> SupportedAudioParams() {
56 // TODO(hclam): Fill in more codecs here.
57 std::vector
<CastRtpParams
> supported_params
;
58 supported_params
.push_back(CastRtpParams(DefaultOpusPayload()));
59 return supported_params
;
62 std::vector
<CastRtpParams
> SupportedVideoParams() {
63 // TODO(hclam): Fill in H264 here.
64 std::vector
<CastRtpParams
> supported_params
;
65 supported_params
.push_back(CastRtpParams(DefaultVp8Payload()));
66 return supported_params
;
69 bool ToAudioSenderConfig(const CastRtpParams
& params
,
70 AudioSenderConfig
* config
) {
71 config
->sender_ssrc
= params
.payload
.ssrc
;
72 config
->incoming_feedback_ssrc
= params
.payload
.feedback_ssrc
;
73 config
->rtp_payload_type
= params
.payload
.payload_type
;
74 config
->use_external_encoder
= false;
75 config
->frequency
= params
.payload
.clock_rate
;
76 config
->channels
= params
.payload
.channels
;
77 config
->bitrate
= params
.payload
.max_bitrate
;
78 config
->codec
= media::cast::transport::kPcm16
;
79 if (params
.payload
.codec_name
== kCodecNameOpus
)
80 config
->codec
= media::cast::transport::kOpus
;
86 bool ToVideoSenderConfig(const CastRtpParams
& params
,
87 VideoSenderConfig
* config
) {
88 config
->sender_ssrc
= params
.payload
.ssrc
;
89 config
->incoming_feedback_ssrc
= params
.payload
.feedback_ssrc
;
90 config
->rtp_payload_type
= params
.payload
.payload_type
;
91 config
->use_external_encoder
= false;
92 config
->width
= params
.payload
.width
;
93 config
->height
= params
.payload
.height
;
94 config
->min_bitrate
= config
->start_bitrate
= params
.payload
.min_bitrate
;
95 config
->max_bitrate
= params
.payload
.max_bitrate
;
96 if (params
.payload
.codec_name
== kCodecNameVp8
)
97 config
->codec
= media::cast::transport::kVp8
;
103 void DeleteAudioBus(scoped_ptr
<media::AudioBus
> audio_bus
) {
104 // Do nothing as |audio_bus| will be deleted.
109 // This class receives MediaStreamTrack events and video frames from a
110 // MediaStreamTrack. Video frames are submitted to media::cast::FrameInput.
112 // Threading: Video frames are received on the render thread.
113 class CastVideoSink
: public base::SupportsWeakPtr
<CastVideoSink
>,
114 public content::MediaStreamVideoSink
{
116 explicit CastVideoSink(const blink::WebMediaStreamTrack
& track
)
117 : track_(track
), sink_added_(false) {
120 virtual ~CastVideoSink() {
122 RemoveFromVideoTrack(this, track_
);
125 // content::MediaStreamVideoSink implementation.
126 virtual void OnVideoFrame(
127 const scoped_refptr
<media::VideoFrame
>& frame
) OVERRIDE
{
128 // TODO(hclam): Pass in the accurate capture time to have good
130 frame_input_
->InsertRawVideoFrame(frame
,
131 base::TimeTicks::Now());
134 // Attach this sink to MediaStreamTrack. This method call must
135 // be made on the render thread. Incoming data can then be
136 // passed to media::cast::FrameInput on any thread.
138 const scoped_refptr
<media::cast::FrameInput
>& frame_input
) {
139 DCHECK(!sink_added_
);
140 frame_input_
= frame_input
;
141 AddToVideoTrack(this, track_
);
146 blink::WebMediaStreamTrack track_
;
147 scoped_refptr
<media::cast::FrameInput
> frame_input_
;
150 DISALLOW_COPY_AND_ASSIGN(CastVideoSink
);
153 // Receives audio data from a MediaStreamTrack. Data is submitted to
154 // media::cast::FrameInput.
156 // Threading: Audio frames are received on the real-time audio thread.
157 class CastAudioSink
: public base::SupportsWeakPtr
<CastAudioSink
>,
158 public content::MediaStreamAudioSink
{
160 explicit CastAudioSink(const blink::WebMediaStreamTrack
& track
)
161 : track_(track
), sink_added_(false) {
164 virtual ~CastAudioSink() {
166 RemoveFromAudioTrack(this, track_
);
169 // content::MediaStreamAudioSink implementation.
170 virtual void OnData(const int16
* audio_data
,
172 int number_of_channels
,
173 int number_of_frames
) OVERRIDE
{
174 scoped_ptr
<media::AudioBus
> audio_bus(
175 media::AudioBus::Create(number_of_channels
,
177 audio_bus
->FromInterleaved(audio_data
, number_of_frames
, 2);
179 // TODO(hclam): Pass in the accurate capture time to have good
181 media::AudioBus
* audio_bus_ptr
= audio_bus
.get();
182 frame_input_
->InsertAudio(
184 base::TimeTicks::Now(),
185 base::Bind(&DeleteAudioBus
, base::Passed(&audio_bus
)));
188 virtual void OnSetFormat(
189 const media::AudioParameters
& params
) OVERRIDE
{
193 // See CastVideoSink for details.
195 const scoped_refptr
<media::cast::FrameInput
>& frame_input
) {
196 DCHECK(!sink_added_
);
197 frame_input_
= frame_input
;
198 AddToAudioTrack(this, track_
);
203 blink::WebMediaStreamTrack track_
;
204 scoped_refptr
<media::cast::FrameInput
> frame_input_
;
207 DISALLOW_COPY_AND_ASSIGN(CastAudioSink
);
210 CastRtpParams::CastRtpParams(const CastRtpPayloadParams
& payload_params
)
211 : payload(payload_params
) {
214 CastCodecSpecificParams::CastCodecSpecificParams() {
217 CastCodecSpecificParams::~CastCodecSpecificParams() {
220 CastRtpPayloadParams::CastRtpPayloadParams()
232 CastRtpPayloadParams::~CastRtpPayloadParams() {
235 CastRtpParams::CastRtpParams() {
238 CastRtpParams::~CastRtpParams() {
241 CastRtpStream::CastRtpStream(
242 const blink::WebMediaStreamTrack
& track
,
243 const scoped_refptr
<CastSession
>& session
)
245 cast_session_(session
) {
248 CastRtpStream::~CastRtpStream() {
251 std::vector
<CastRtpParams
> CastRtpStream::GetSupportedParams() {
253 return SupportedAudioParams();
255 return SupportedVideoParams();
258 CastRtpParams
CastRtpStream::GetParams() {
262 void CastRtpStream::Start(const CastRtpParams
& params
) {
264 AudioSenderConfig config
;
265 if (!ToAudioSenderConfig(params
, &config
)) {
266 DVLOG(1) << "Invalid parameters for audio.";
268 audio_sink_
.reset(new CastAudioSink(track_
));
269 cast_session_
->StartAudio(
271 base::Bind(&CastAudioSink::AddToTrack
,
272 audio_sink_
->AsWeakPtr()));
274 VideoSenderConfig config
;
275 if (!ToVideoSenderConfig(params
, &config
)) {
276 DVLOG(1) << "Invalid parameters for video.";
278 video_sink_
.reset(new CastVideoSink(track_
));
279 cast_session_
->StartVideo(
281 base::Bind(&CastVideoSink::AddToTrack
,
282 video_sink_
->AsWeakPtr()));
286 void CastRtpStream::Stop() {
291 bool CastRtpStream::IsAudio() const {
292 return track_
.source().type() == blink::WebMediaStreamSource::TypeAudio
;