• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/renderer/media/cast_rtp_stream.h"
6 
7 #include "base/bind.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 "third_party/WebKit/public/platform/WebMediaStreamSource.h"
19 
20 using media::cast::AudioSenderConfig;
21 using media::cast::VideoSenderConfig;
22 
23 namespace {
24 const char kCodecNameOpus[] = "OPUS";
25 const char kCodecNameVp8[] = "VP8";
26 
DefaultOpusPayload()27 CastRtpPayloadParams DefaultOpusPayload() {
28   CastRtpPayloadParams payload;
29   payload.payload_type = 111;
30   payload.codec_name = kCodecNameOpus;
31   payload.clock_rate = 48000;
32   payload.channels = 2;
33   payload.min_bitrate = payload.max_bitrate =
34       media::cast::kDefaultAudioEncoderBitrate;
35   return payload;
36 }
37 
DefaultVp8Payload()38 CastRtpPayloadParams DefaultVp8Payload() {
39   CastRtpPayloadParams payload;
40   payload.payload_type = 100;
41   payload.codec_name = kCodecNameVp8;
42   payload.clock_rate = 90000;
43   payload.width = 1280;
44   payload.height = 720;
45   payload.min_bitrate = 50 * 1000;
46   payload.max_bitrate = 2000 * 1000;
47   return payload;
48 }
49 
DefaultAudioCaps()50 CastRtpCaps DefaultAudioCaps() {
51   CastRtpCaps caps;
52   caps.payloads.push_back(DefaultOpusPayload());
53   // TODO(hclam): Fill in |rtcp_features| and |fec_mechanisms|.
54   return caps;
55 }
56 
DefaultVideoCaps()57 CastRtpCaps DefaultVideoCaps() {
58   CastRtpCaps caps;
59   caps.payloads.push_back(DefaultVp8Payload());
60   // TODO(hclam): Fill in |rtcp_features| and |fec_mechanisms|.
61   return caps;
62 }
63 
ToAudioSenderConfig(const CastRtpParams & params,AudioSenderConfig * config)64 bool ToAudioSenderConfig(const CastRtpParams& params,
65                          AudioSenderConfig* config) {
66   if (params.payloads.empty())
67     return false;
68   const CastRtpPayloadParams& payload_params = params.payloads[0];
69   config->sender_ssrc = payload_params.ssrc;
70   config->use_external_encoder = false;
71   config->frequency = payload_params.clock_rate;
72   config->channels = payload_params.channels;
73   config->bitrate = payload_params.max_bitrate;
74   config->codec = media::cast::kPcm16;
75   if (payload_params.codec_name == kCodecNameOpus)
76     config->codec = media::cast::kOpus;
77   else
78     return false;
79   return true;
80 }
81 
ToVideoSenderConfig(const CastRtpParams & params,VideoSenderConfig * config)82 bool ToVideoSenderConfig(const CastRtpParams& params,
83                          VideoSenderConfig* config) {
84   if (params.payloads.empty())
85     return false;
86   const CastRtpPayloadParams& payload_params = params.payloads[0];
87   config->sender_ssrc = payload_params.ssrc;
88   config->use_external_encoder = false;
89   config->width = payload_params.width;
90   config->height = payload_params.height;
91   config->min_bitrate = config->start_bitrate = payload_params.min_bitrate;
92   config->max_bitrate = payload_params.max_bitrate;
93   if (payload_params.codec_name == kCodecNameVp8)
94     config->codec = media::cast::kVp8;
95   else
96     return false;
97   return true;
98 }
99 
DeleteAudioBus(scoped_ptr<media::AudioBus> audio_bus)100 void DeleteAudioBus(scoped_ptr<media::AudioBus> audio_bus) {
101   // Do nothing as |audio_bus| will be deleted.
102 }
103 
104 }  // namespace
105 
106 // This class receives MediaStreamTrack events and video frames from a
107 // MediaStreamTrack. Video frames are submitted to media::cast::FrameInput.
108 //
109 // Threading: Video frames are received on the render thread.
110 class CastVideoSink : public base::SupportsWeakPtr<CastVideoSink>,
111                       public content::MediaStreamVideoSink {
112  public:
CastVideoSink(const blink::WebMediaStreamTrack & track)113   explicit CastVideoSink(const blink::WebMediaStreamTrack& track)
114       : track_(track), sink_added_(false) {
115   }
116 
~CastVideoSink()117   virtual ~CastVideoSink() {
118     if (sink_added_)
119       RemoveFromVideoTrack(this, track_);
120   }
121 
122   // content::MediaStreamVideoSink implementation.
OnVideoFrame(const scoped_refptr<media::VideoFrame> & frame)123   virtual void OnVideoFrame(
124       const scoped_refptr<media::VideoFrame>& frame) OVERRIDE {
125     // TODO(hclam): Pass in the accurate capture time to have good
126     // audio/video sync.
127     frame_input_->InsertRawVideoFrame(frame,
128                                       base::TimeTicks::Now());
129   }
130 
131   // Attach this sink to MediaStreamTrack. This method call must
132   // be made on the render thread. Incoming data can then be
133   // passed to media::cast::FrameInput on any thread.
AddToTrack(const scoped_refptr<media::cast::FrameInput> & frame_input)134   void AddToTrack(
135       const scoped_refptr<media::cast::FrameInput>& frame_input) {
136     DCHECK(!sink_added_);
137     frame_input_ = frame_input;
138     AddToVideoTrack(this, track_);
139     sink_added_ = true;
140   }
141 
142  private:
143   blink::WebMediaStreamTrack track_;
144   scoped_refptr<media::cast::FrameInput> frame_input_;
145   bool sink_added_;
146 
147   DISALLOW_COPY_AND_ASSIGN(CastVideoSink);
148 };
149 
150 // Receives audio data from a MediaStreamTrack. Data is submitted to
151 // media::cast::FrameInput.
152 //
153 // Threading: Audio frames are received on the real-time audio thread.
154 class CastAudioSink : public base::SupportsWeakPtr<CastAudioSink>,
155                       public content::MediaStreamAudioSink {
156  public:
CastAudioSink(const blink::WebMediaStreamTrack & track)157   explicit CastAudioSink(const blink::WebMediaStreamTrack& track)
158       : track_(track), sink_added_(false) {
159   }
160 
~CastAudioSink()161   virtual ~CastAudioSink() {
162     if (sink_added_)
163       RemoveFromAudioTrack(this, track_);
164   }
165 
166   // content::MediaStreamAudioSink implementation.
OnData(const int16 * audio_data,int sample_rate,int number_of_channels,int number_of_frames)167   virtual void OnData(const int16* audio_data,
168                       int sample_rate,
169                       int number_of_channels,
170                       int number_of_frames) OVERRIDE {
171     scoped_ptr<media::AudioBus> audio_bus(
172         media::AudioBus::Create(number_of_channels,
173                                 number_of_frames));
174     audio_bus->FromInterleaved(audio_data, number_of_frames, 2);
175 
176     // TODO(hclam): Pass in the accurate capture time to have good
177     // audio/video sync.
178     media::AudioBus* audio_bus_ptr = audio_bus.get();
179     frame_input_->InsertAudio(
180         audio_bus_ptr,
181         base::TimeTicks::Now(),
182         base::Bind(&DeleteAudioBus, base::Passed(&audio_bus)));
183   }
184 
OnSetFormat(const media::AudioParameters & params)185   virtual void OnSetFormat(
186       const media::AudioParameters& params) OVERRIDE{
187     NOTIMPLEMENTED();
188   }
189 
190   // See CastVideoSink for details.
AddToTrack(const scoped_refptr<media::cast::FrameInput> & frame_input)191   void AddToTrack(
192       const scoped_refptr<media::cast::FrameInput>& frame_input) {
193     DCHECK(!sink_added_);
194     frame_input_ = frame_input;
195     AddToAudioTrack(this, track_);
196     sink_added_ = true;
197   }
198 
199  private:
200   blink::WebMediaStreamTrack track_;
201   scoped_refptr<media::cast::FrameInput> frame_input_;
202   bool sink_added_;
203 
204   DISALLOW_COPY_AND_ASSIGN(CastAudioSink);
205 };
206 
CastCodecSpecificParams()207 CastCodecSpecificParams::CastCodecSpecificParams() {
208 }
209 
~CastCodecSpecificParams()210 CastCodecSpecificParams::~CastCodecSpecificParams() {
211 }
212 
CastRtpPayloadParams()213 CastRtpPayloadParams::CastRtpPayloadParams()
214     : payload_type(0),
215       ssrc(0),
216       clock_rate(0),
217       max_bitrate(0),
218       min_bitrate(0),
219       channels(0),
220       width(0),
221       height(0) {
222 }
223 
~CastRtpPayloadParams()224 CastRtpPayloadParams::~CastRtpPayloadParams() {
225 }
226 
CastRtpCaps()227 CastRtpCaps::CastRtpCaps() {
228 }
229 
~CastRtpCaps()230 CastRtpCaps::~CastRtpCaps() {
231 }
232 
CastRtpStream(const blink::WebMediaStreamTrack & track,const scoped_refptr<CastSession> & session)233 CastRtpStream::CastRtpStream(
234     const blink::WebMediaStreamTrack& track,
235     const scoped_refptr<CastSession>& session)
236     : track_(track),
237       cast_session_(session) {
238 }
239 
~CastRtpStream()240 CastRtpStream::~CastRtpStream() {
241 }
242 
GetCaps()243 CastRtpCaps CastRtpStream::GetCaps() {
244   if (IsAudio())
245     return DefaultAudioCaps();
246   else
247     return DefaultVideoCaps();
248 }
249 
GetParams()250 CastRtpParams CastRtpStream::GetParams() {
251   return params_;
252 }
253 
Start(const CastRtpParams & params)254 void CastRtpStream::Start(const CastRtpParams& params) {
255   if (IsAudio()) {
256     AudioSenderConfig config;
257     if (!ToAudioSenderConfig(params, &config)) {
258       DVLOG(1) << "Invalid parameters for audio.";
259     }
260     audio_sink_.reset(new CastAudioSink(track_));
261     cast_session_->StartAudio(
262         config,
263         base::Bind(&CastAudioSink::AddToTrack,
264                    audio_sink_->AsWeakPtr()));
265   } else {
266     VideoSenderConfig config;
267     if (!ToVideoSenderConfig(params, &config)) {
268       DVLOG(1) << "Invalid parameters for video.";
269     }
270     video_sink_.reset(new CastVideoSink(track_));
271     cast_session_->StartVideo(
272         config,
273         base::Bind(&CastVideoSink::AddToTrack,
274                    video_sink_->AsWeakPtr()));
275   }
276 }
277 
Stop()278 void CastRtpStream::Stop() {
279   audio_sink_.reset();
280   video_sink_.reset();
281 }
282 
IsAudio() const283 bool CastRtpStream::IsAudio() const {
284   return track_.source().type() == blink::WebMediaStreamSource::TypeAudio;
285 }
286