• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "media/cast/receiver/cast_receiver_impl.h"
6 
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/debug/trace_event.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop.h"
13 #include "media/cast/receiver/audio_decoder.h"
14 #include "media/cast/receiver/video_decoder.h"
15 
16 namespace media {
17 namespace cast {
18 
Create(scoped_refptr<CastEnvironment> cast_environment,const FrameReceiverConfig & audio_config,const FrameReceiverConfig & video_config,PacketSender * const packet_sender)19 scoped_ptr<CastReceiver> CastReceiver::Create(
20     scoped_refptr<CastEnvironment> cast_environment,
21     const FrameReceiverConfig& audio_config,
22     const FrameReceiverConfig& video_config,
23     PacketSender* const packet_sender) {
24   return scoped_ptr<CastReceiver>(new CastReceiverImpl(
25       cast_environment, audio_config, video_config, packet_sender));
26 }
27 
CastReceiverImpl(scoped_refptr<CastEnvironment> cast_environment,const FrameReceiverConfig & audio_config,const FrameReceiverConfig & video_config,PacketSender * const packet_sender)28 CastReceiverImpl::CastReceiverImpl(
29     scoped_refptr<CastEnvironment> cast_environment,
30     const FrameReceiverConfig& audio_config,
31     const FrameReceiverConfig& video_config,
32     PacketSender* const packet_sender)
33     : cast_environment_(cast_environment),
34       pacer_(kTargetBurstSize,
35              kMaxBurstSize,
36              cast_environment->Clock(),
37              cast_environment->Logging(),
38              packet_sender,
39              cast_environment->GetTaskRunner(CastEnvironment::MAIN)),
40       audio_receiver_(cast_environment, audio_config, AUDIO_EVENT, &pacer_),
41       video_receiver_(cast_environment, video_config, VIDEO_EVENT, &pacer_),
42       ssrc_of_audio_sender_(audio_config.incoming_ssrc),
43       ssrc_of_video_sender_(video_config.incoming_ssrc),
44       num_audio_channels_(audio_config.channels),
45       audio_sampling_rate_(audio_config.frequency),
46       audio_codec_(audio_config.codec),
47       video_codec_(video_config.codec) {}
48 
~CastReceiverImpl()49 CastReceiverImpl::~CastReceiverImpl() {}
50 
DispatchReceivedPacket(scoped_ptr<Packet> packet)51 void CastReceiverImpl::DispatchReceivedPacket(scoped_ptr<Packet> packet) {
52   const uint8_t* const data = &packet->front();
53   const size_t length = packet->size();
54 
55   uint32 ssrc_of_sender;
56   if (Rtcp::IsRtcpPacket(data, length)) {
57     ssrc_of_sender = Rtcp::GetSsrcOfSender(data, length);
58   } else if (!FrameReceiver::ParseSenderSsrc(data, length, &ssrc_of_sender)) {
59     VLOG(1) << "Invalid RTP packet.";
60     return;
61   }
62 
63   base::WeakPtr<FrameReceiver> target;
64   if (ssrc_of_sender == ssrc_of_video_sender_) {
65     target = video_receiver_.AsWeakPtr();
66   } else if (ssrc_of_sender == ssrc_of_audio_sender_) {
67     target = audio_receiver_.AsWeakPtr();
68   } else {
69     VLOG(1) << "Dropping packet with a non matching sender SSRC: "
70             << ssrc_of_sender;
71     return;
72   }
73   cast_environment_->PostTask(
74       CastEnvironment::MAIN,
75       FROM_HERE,
76       base::Bind(base::IgnoreResult(&FrameReceiver::ProcessPacket),
77                  target,
78                  base::Passed(&packet)));
79 }
80 
packet_receiver()81 PacketReceiverCallback CastReceiverImpl::packet_receiver() {
82   return base::Bind(&CastReceiverImpl::DispatchReceivedPacket,
83                     // TODO(miu): This code structure is dangerous, since the
84                     // callback could be stored and then invoked after
85                     // destruction of |this|.
86                     base::Unretained(this));
87 }
88 
RequestDecodedAudioFrame(const AudioFrameDecodedCallback & callback)89 void CastReceiverImpl::RequestDecodedAudioFrame(
90     const AudioFrameDecodedCallback& callback) {
91   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
92   DCHECK(!callback.is_null());
93   audio_receiver_.RequestEncodedFrame(base::Bind(
94       &CastReceiverImpl::DecodeEncodedAudioFrame,
95       // Note: Use of Unretained is safe since this Closure is guaranteed to be
96       // invoked or discarded by |audio_receiver_| before destruction of |this|.
97       base::Unretained(this),
98       callback));
99 }
100 
RequestEncodedAudioFrame(const ReceiveEncodedFrameCallback & callback)101 void CastReceiverImpl::RequestEncodedAudioFrame(
102     const ReceiveEncodedFrameCallback& callback) {
103   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
104   audio_receiver_.RequestEncodedFrame(callback);
105 }
106 
RequestDecodedVideoFrame(const VideoFrameDecodedCallback & callback)107 void CastReceiverImpl::RequestDecodedVideoFrame(
108     const VideoFrameDecodedCallback& callback) {
109   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
110   DCHECK(!callback.is_null());
111   video_receiver_.RequestEncodedFrame(base::Bind(
112       &CastReceiverImpl::DecodeEncodedVideoFrame,
113       // Note: Use of Unretained is safe since this Closure is guaranteed to be
114       // invoked or discarded by |video_receiver_| before destruction of |this|.
115       base::Unretained(this),
116       callback));
117 }
118 
RequestEncodedVideoFrame(const ReceiveEncodedFrameCallback & callback)119 void CastReceiverImpl::RequestEncodedVideoFrame(
120     const ReceiveEncodedFrameCallback& callback) {
121   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
122   video_receiver_.RequestEncodedFrame(callback);
123 }
124 
DecodeEncodedAudioFrame(const AudioFrameDecodedCallback & callback,scoped_ptr<EncodedFrame> encoded_frame)125 void CastReceiverImpl::DecodeEncodedAudioFrame(
126     const AudioFrameDecodedCallback& callback,
127     scoped_ptr<EncodedFrame> encoded_frame) {
128   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
129   if (!encoded_frame) {
130     callback.Run(make_scoped_ptr<AudioBus>(NULL), base::TimeTicks(), false);
131     return;
132   }
133 
134   if (!audio_decoder_) {
135     audio_decoder_.reset(new AudioDecoder(cast_environment_,
136                                           num_audio_channels_,
137                                           audio_sampling_rate_,
138                                           audio_codec_));
139   }
140   const uint32 frame_id = encoded_frame->frame_id;
141   const uint32 rtp_timestamp = encoded_frame->rtp_timestamp;
142   const base::TimeTicks playout_time = encoded_frame->reference_time;
143   audio_decoder_->DecodeFrame(
144       encoded_frame.Pass(),
145       base::Bind(&CastReceiverImpl::EmitDecodedAudioFrame,
146                  cast_environment_,
147                  callback,
148                  frame_id,
149                  rtp_timestamp,
150                  playout_time));
151 }
152 
DecodeEncodedVideoFrame(const VideoFrameDecodedCallback & callback,scoped_ptr<EncodedFrame> encoded_frame)153 void CastReceiverImpl::DecodeEncodedVideoFrame(
154     const VideoFrameDecodedCallback& callback,
155     scoped_ptr<EncodedFrame> encoded_frame) {
156   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
157   if (!encoded_frame) {
158     callback.Run(
159         make_scoped_refptr<VideoFrame>(NULL), base::TimeTicks(), false);
160     return;
161   }
162 
163   // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc
164   TRACE_EVENT_INSTANT2(
165       "cast_perf_test", "PullEncodedVideoFrame",
166       TRACE_EVENT_SCOPE_THREAD,
167       "rtp_timestamp", encoded_frame->rtp_timestamp,
168       "render_time", encoded_frame->reference_time.ToInternalValue());
169 
170   if (!video_decoder_)
171     video_decoder_.reset(new VideoDecoder(cast_environment_, video_codec_));
172   const uint32 frame_id = encoded_frame->frame_id;
173   const uint32 rtp_timestamp = encoded_frame->rtp_timestamp;
174   const base::TimeTicks playout_time = encoded_frame->reference_time;
175   video_decoder_->DecodeFrame(
176       encoded_frame.Pass(),
177       base::Bind(&CastReceiverImpl::EmitDecodedVideoFrame,
178                  cast_environment_,
179                  callback,
180                  frame_id,
181                  rtp_timestamp,
182                  playout_time));
183 }
184 
185 // static
EmitDecodedAudioFrame(const scoped_refptr<CastEnvironment> & cast_environment,const AudioFrameDecodedCallback & callback,uint32 frame_id,uint32 rtp_timestamp,const base::TimeTicks & playout_time,scoped_ptr<AudioBus> audio_bus,bool is_continuous)186 void CastReceiverImpl::EmitDecodedAudioFrame(
187     const scoped_refptr<CastEnvironment>& cast_environment,
188     const AudioFrameDecodedCallback& callback,
189     uint32 frame_id,
190     uint32 rtp_timestamp,
191     const base::TimeTicks& playout_time,
192     scoped_ptr<AudioBus> audio_bus,
193     bool is_continuous) {
194   DCHECK(cast_environment->CurrentlyOn(CastEnvironment::MAIN));
195   if (audio_bus.get()) {
196     const base::TimeTicks now = cast_environment->Clock()->NowTicks();
197     cast_environment->Logging()->InsertFrameEvent(
198         now, FRAME_DECODED, AUDIO_EVENT, rtp_timestamp, frame_id);
199     cast_environment->Logging()->InsertFrameEventWithDelay(
200         now, FRAME_PLAYOUT, AUDIO_EVENT, rtp_timestamp, frame_id,
201         playout_time - now);
202   }
203   callback.Run(audio_bus.Pass(), playout_time, is_continuous);
204 }
205 
206 // static
EmitDecodedVideoFrame(const scoped_refptr<CastEnvironment> & cast_environment,const VideoFrameDecodedCallback & callback,uint32 frame_id,uint32 rtp_timestamp,const base::TimeTicks & playout_time,const scoped_refptr<VideoFrame> & video_frame,bool is_continuous)207 void CastReceiverImpl::EmitDecodedVideoFrame(
208     const scoped_refptr<CastEnvironment>& cast_environment,
209     const VideoFrameDecodedCallback& callback,
210     uint32 frame_id,
211     uint32 rtp_timestamp,
212     const base::TimeTicks& playout_time,
213     const scoped_refptr<VideoFrame>& video_frame,
214     bool is_continuous) {
215   DCHECK(cast_environment->CurrentlyOn(CastEnvironment::MAIN));
216   if (video_frame.get()) {
217     const base::TimeTicks now = cast_environment->Clock()->NowTicks();
218     cast_environment->Logging()->InsertFrameEvent(
219         now, FRAME_DECODED, VIDEO_EVENT, rtp_timestamp, frame_id);
220     cast_environment->Logging()->InsertFrameEventWithDelay(
221         now, FRAME_PLAYOUT, VIDEO_EVENT, rtp_timestamp, frame_id,
222         playout_time - now);
223 
224     // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc
225     TRACE_EVENT_INSTANT1(
226         "cast_perf_test", "FrameDecoded",
227         TRACE_EVENT_SCOPE_THREAD,
228         "rtp_timestamp", rtp_timestamp);
229   }
230   callback.Run(video_frame, playout_time, is_continuous);
231 }
232 
233 }  // namespace cast
234 }  // namespace media
235