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 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 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 49 CastReceiverImpl::~CastReceiverImpl() {} 50 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 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 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 101 void CastReceiverImpl::RequestEncodedAudioFrame( 102 const ReceiveEncodedFrameCallback& callback) { 103 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 104 audio_receiver_.RequestEncodedFrame(callback); 105 } 106 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 119 void CastReceiverImpl::RequestEncodedVideoFrame( 120 const ReceiveEncodedFrameCallback& callback) { 121 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 122 video_receiver_.RequestEncodedFrame(callback); 123 } 124 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 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 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 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