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_(cast_environment
->Clock(),
35 cast_environment
->Logging(),
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
),
45 video_codec_(video_config
.codec
) {}
47 CastReceiverImpl::~CastReceiverImpl() {}
49 void CastReceiverImpl::DispatchReceivedPacket(scoped_ptr
<Packet
> packet
) {
50 const uint8_t* const data
= &packet
->front();
51 const size_t length
= packet
->size();
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.";
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();
67 VLOG(1) << "Dropping packet with a non matching sender SSRC: "
71 cast_environment_
->PostTask(
72 CastEnvironment::MAIN
,
74 base::Bind(base::IgnoreResult(&FrameReceiver::ProcessPacket
),
76 base::Passed(&packet
)));
79 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));
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),
99 void CastReceiverImpl::RequestEncodedAudioFrame(
100 const ReceiveEncodedFrameCallback
& callback
) {
101 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
102 audio_receiver_
.RequestEncodedFrame(callback
);
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),
117 void CastReceiverImpl::RequestEncodedVideoFrame(
118 const ReceiveEncodedFrameCallback
& callback
) {
119 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
120 video_receiver_
.RequestEncodedFrame(callback
);
123 void CastReceiverImpl::DecodeEncodedAudioFrame(
124 const AudioFrameDecodedCallback
& callback
,
125 scoped_ptr
<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);
132 if (!audio_decoder_
) {
133 audio_decoder_
.reset(new AudioDecoder(cast_environment_
,
135 audio_sampling_rate_
,
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
,
151 void CastReceiverImpl::DecodeEncodedVideoFrame(
152 const VideoFrameDecodedCallback
& callback
,
153 scoped_ptr
<EncodedFrame
> encoded_frame
) {
154 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
155 if (!encoded_frame
) {
157 make_scoped_refptr
<VideoFrame
>(NULL
), base::TimeTicks(), false);
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());
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
,
184 void CastReceiverImpl::EmitDecodedAudioFrame(
185 const scoped_refptr
<CastEnvironment
>& cast_environment
,
186 const AudioFrameDecodedCallback
& callback
,
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
,
201 callback
.Run(audio_bus
.Pass(), playout_time
, is_continuous
);
205 void CastReceiverImpl::EmitDecodedVideoFrame(
206 const scoped_refptr
<CastEnvironment
>& cast_environment
,
207 const VideoFrameDecodedCallback
& callback
,
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
.get()) {
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
,
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
);
228 callback
.Run(video_frame
, playout_time
, is_continuous
);