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.
5 #include "media/cast/receiver/cast_receiver_impl.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/net/rtcp/rtcp_receiver.h"
14 #include "media/cast/receiver/audio_decoder.h"
15 #include "media/cast/receiver/video_decoder.h"
20 scoped_ptr<CastReceiver> CastReceiver::Create(
21 scoped_refptr<CastEnvironment> cast_environment,
22 const FrameReceiverConfig& audio_config,
23 const FrameReceiverConfig& video_config,
24 PacketSender* const packet_sender) {
25 return scoped_ptr<CastReceiver>(new CastReceiverImpl(
26 cast_environment, audio_config, video_config, packet_sender));
29 CastReceiverImpl::CastReceiverImpl(
30 scoped_refptr<CastEnvironment> cast_environment,
31 const FrameReceiverConfig& audio_config,
32 const FrameReceiverConfig& video_config,
33 PacketSender* const packet_sender)
34 : cast_environment_(cast_environment),
35 pacer_(cast_environment->Clock(),
36 cast_environment->Logging(),
38 cast_environment->GetTaskRunner(CastEnvironment::MAIN)),
39 audio_receiver_(cast_environment, audio_config, AUDIO_EVENT, &pacer_),
40 video_receiver_(cast_environment, video_config, VIDEO_EVENT, &pacer_),
41 ssrc_of_audio_sender_(audio_config.incoming_ssrc),
42 ssrc_of_video_sender_(video_config.incoming_ssrc),
43 num_audio_channels_(audio_config.channels),
44 audio_sampling_rate_(audio_config.frequency),
45 audio_codec_(audio_config.codec),
46 video_codec_(video_config.codec) {}
48 CastReceiverImpl::~CastReceiverImpl() {}
50 void CastReceiverImpl::DispatchReceivedPacket(scoped_ptr<Packet> packet) {
51 const uint8_t* const data = &packet->front();
52 const size_t length = packet->size();
54 uint32 ssrc_of_sender;
55 if (RtcpReceiver::IsRtcpPacket(data, length)) {
56 ssrc_of_sender = RtcpReceiver::GetSsrcOfSender(data, length);
57 } else if (!FrameReceiver::ParseSenderSsrc(data, length, &ssrc_of_sender)) {
58 VLOG(1) << "Invalid RTP packet.";
62 base::WeakPtr<FrameReceiver> target;
63 if (ssrc_of_sender == ssrc_of_video_sender_) {
64 target = video_receiver_.AsWeakPtr();
65 } else if (ssrc_of_sender == ssrc_of_audio_sender_) {
66 target = audio_receiver_.AsWeakPtr();
68 VLOG(1) << "Dropping packet with a non matching sender SSRC: "
72 cast_environment_->PostTask(
73 CastEnvironment::MAIN,
75 base::Bind(base::IgnoreResult(&FrameReceiver::ProcessPacket),
77 base::Passed(&packet)));
80 PacketReceiverCallback CastReceiverImpl::packet_receiver() {
81 return base::Bind(&CastReceiverImpl::DispatchReceivedPacket,
82 // TODO(miu): This code structure is dangerous, since the
83 // callback could be stored and then invoked after
84 // destruction of |this|.
85 base::Unretained(this));
88 void CastReceiverImpl::RequestDecodedAudioFrame(
89 const AudioFrameDecodedCallback& callback) {
90 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
91 DCHECK(!callback.is_null());
92 audio_receiver_.RequestEncodedFrame(base::Bind(
93 &CastReceiverImpl::DecodeEncodedAudioFrame,
94 // Note: Use of Unretained is safe since this Closure is guaranteed to be
95 // invoked or discarded by |audio_receiver_| before destruction of |this|.
96 base::Unretained(this),
100 void CastReceiverImpl::RequestEncodedAudioFrame(
101 const ReceiveEncodedFrameCallback& callback) {
102 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
103 audio_receiver_.RequestEncodedFrame(callback);
106 void CastReceiverImpl::RequestDecodedVideoFrame(
107 const VideoFrameDecodedCallback& callback) {
108 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
109 DCHECK(!callback.is_null());
110 video_receiver_.RequestEncodedFrame(base::Bind(
111 &CastReceiverImpl::DecodeEncodedVideoFrame,
112 // Note: Use of Unretained is safe since this Closure is guaranteed to be
113 // invoked or discarded by |video_receiver_| before destruction of |this|.
114 base::Unretained(this),
118 void CastReceiverImpl::RequestEncodedVideoFrame(
119 const ReceiveEncodedFrameCallback& callback) {
120 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
121 video_receiver_.RequestEncodedFrame(callback);
124 void CastReceiverImpl::DecodeEncodedAudioFrame(
125 const AudioFrameDecodedCallback& callback,
126 scoped_ptr<EncodedFrame> encoded_frame) {
127 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
128 if (!encoded_frame) {
129 callback.Run(make_scoped_ptr<AudioBus>(NULL), base::TimeTicks(), false);
133 if (!audio_decoder_) {
134 audio_decoder_.reset(new AudioDecoder(cast_environment_,
136 audio_sampling_rate_,
139 const uint32 frame_id = encoded_frame->frame_id;
140 const uint32 rtp_timestamp = encoded_frame->rtp_timestamp;
141 const base::TimeTicks playout_time = encoded_frame->reference_time;
142 audio_decoder_->DecodeFrame(
143 encoded_frame.Pass(),
144 base::Bind(&CastReceiverImpl::EmitDecodedAudioFrame,
152 void CastReceiverImpl::DecodeEncodedVideoFrame(
153 const VideoFrameDecodedCallback& callback,
154 scoped_ptr<EncodedFrame> encoded_frame) {
155 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
156 if (!encoded_frame) {
158 make_scoped_refptr<VideoFrame>(NULL), base::TimeTicks(), false);
162 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc
163 TRACE_EVENT_INSTANT2(
164 "cast_perf_test", "PullEncodedVideoFrame",
165 TRACE_EVENT_SCOPE_THREAD,
166 "rtp_timestamp", encoded_frame->rtp_timestamp,
167 "render_time", encoded_frame->reference_time.ToInternalValue());
170 video_decoder_.reset(new VideoDecoder(cast_environment_, video_codec_));
171 const uint32 frame_id = encoded_frame->frame_id;
172 const uint32 rtp_timestamp = encoded_frame->rtp_timestamp;
173 const base::TimeTicks playout_time = encoded_frame->reference_time;
174 video_decoder_->DecodeFrame(
175 encoded_frame.Pass(),
176 base::Bind(&CastReceiverImpl::EmitDecodedVideoFrame,
185 void CastReceiverImpl::EmitDecodedAudioFrame(
186 const scoped_refptr<CastEnvironment>& cast_environment,
187 const AudioFrameDecodedCallback& callback,
189 uint32 rtp_timestamp,
190 const base::TimeTicks& playout_time,
191 scoped_ptr<AudioBus> audio_bus,
192 bool is_continuous) {
193 DCHECK(cast_environment->CurrentlyOn(CastEnvironment::MAIN));
194 if (audio_bus.get()) {
195 const base::TimeTicks now = cast_environment->Clock()->NowTicks();
196 cast_environment->Logging()->InsertFrameEvent(
197 now, FRAME_DECODED, AUDIO_EVENT, rtp_timestamp, frame_id);
198 cast_environment->Logging()->InsertFrameEventWithDelay(
199 now, FRAME_PLAYOUT, AUDIO_EVENT, rtp_timestamp, frame_id,
202 callback.Run(audio_bus.Pass(), playout_time, is_continuous);
206 void CastReceiverImpl::EmitDecodedVideoFrame(
207 const scoped_refptr<CastEnvironment>& cast_environment,
208 const VideoFrameDecodedCallback& callback,
210 uint32 rtp_timestamp,
211 const base::TimeTicks& playout_time,
212 const scoped_refptr<VideoFrame>& video_frame,
213 bool is_continuous) {
214 DCHECK(cast_environment->CurrentlyOn(CastEnvironment::MAIN));
216 const base::TimeTicks now = cast_environment->Clock()->NowTicks();
217 cast_environment->Logging()->InsertFrameEvent(
218 now, FRAME_DECODED, VIDEO_EVENT, rtp_timestamp, frame_id);
219 cast_environment->Logging()->InsertFrameEventWithDelay(
220 now, FRAME_PLAYOUT, VIDEO_EVENT, rtp_timestamp, frame_id,
223 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc
224 TRACE_EVENT_INSTANT1(
225 "cast_perf_test", "FrameDecoded",
226 TRACE_EVENT_SCOPE_THREAD,
227 "rtp_timestamp", rtp_timestamp);
229 callback.Run(video_frame, playout_time, is_continuous);