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