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/receiver/audio_decoder.h"
14 #include "media/cast/receiver/video_decoder.h"
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
));
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
,
36 cast_environment
->Clock(),
37 cast_environment
->Logging(),
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
) {}
49 CastReceiverImpl::~CastReceiverImpl() {}
51 void CastReceiverImpl::DispatchReceivedPacket(scoped_ptr
<Packet
> packet
) {
52 const uint8_t* const data
= &packet
->front();
53 const size_t length
= packet
->size();
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.";
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();
69 VLOG(1) << "Dropping packet with a non matching sender SSRC: "
73 cast_environment_
->PostTask(
74 CastEnvironment::MAIN
,
76 base::Bind(base::IgnoreResult(&FrameReceiver::ProcessPacket
),
78 base::Passed(&packet
)));
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));
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),
101 void CastReceiverImpl::RequestEncodedAudioFrame(
102 const ReceiveEncodedFrameCallback
& callback
) {
103 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
104 audio_receiver_
.RequestEncodedFrame(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),
119 void CastReceiverImpl::RequestEncodedVideoFrame(
120 const ReceiveEncodedFrameCallback
& callback
) {
121 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
122 video_receiver_
.RequestEncodedFrame(callback
);
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);
134 if (!audio_decoder_
) {
135 audio_decoder_
.reset(new AudioDecoder(cast_environment_
,
137 audio_sampling_rate_
,
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
,
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
) {
159 make_scoped_refptr
<VideoFrame
>(NULL
), base::TimeTicks(), false);
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());
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
,
186 void CastReceiverImpl::EmitDecodedAudioFrame(
187 const scoped_refptr
<CastEnvironment
>& cast_environment
,
188 const AudioFrameDecodedCallback
& callback
,
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
,
203 callback
.Run(audio_bus
.Pass(), playout_time
, is_continuous
);
207 void CastReceiverImpl::EmitDecodedVideoFrame(
208 const scoped_refptr
<CastEnvironment
>& cast_environment
,
209 const VideoFrameDecodedCallback
& callback
,
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
,
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
);
230 callback
.Run(video_frame
, playout_time
, is_continuous
);