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/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/trace_event/trace_event.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 CastTransportSender
* const transport
) {
24 return scoped_ptr
<CastReceiver
>(new CastReceiverImpl(
25 cast_environment
, audio_config
, video_config
, transport
));
28 CastReceiverImpl::CastReceiverImpl(
29 scoped_refptr
<CastEnvironment
> cast_environment
,
30 const FrameReceiverConfig
& audio_config
,
31 const FrameReceiverConfig
& video_config
,
32 CastTransportSender
* const transport
)
33 : cast_environment_(cast_environment
),
34 audio_receiver_(cast_environment
, audio_config
, AUDIO_EVENT
, transport
),
35 video_receiver_(cast_environment
, video_config
, VIDEO_EVENT
, transport
),
36 ssrc_of_audio_sender_(audio_config
.sender_ssrc
),
37 ssrc_of_video_sender_(video_config
.sender_ssrc
),
38 num_audio_channels_(audio_config
.channels
),
39 audio_sampling_rate_(audio_config
.rtp_timebase
),
40 audio_codec_(audio_config
.codec
),
41 video_codec_(video_config
.codec
) {}
43 CastReceiverImpl::~CastReceiverImpl() {}
45 void CastReceiverImpl::ReceivePacket(scoped_ptr
<Packet
> packet
) {
46 const uint8_t* const data
= &packet
->front();
47 const size_t length
= packet
->size();
49 uint32 ssrc_of_sender
;
50 if (Rtcp::IsRtcpPacket(data
, length
)) {
51 ssrc_of_sender
= Rtcp::GetSsrcOfSender(data
, length
);
52 } else if (!RtpParser::ParseSsrc(data
, length
, &ssrc_of_sender
)) {
53 VLOG(1) << "Invalid RTP packet.";
57 base::WeakPtr
<FrameReceiver
> target
;
58 if (ssrc_of_sender
== ssrc_of_video_sender_
) {
59 target
= video_receiver_
.AsWeakPtr();
60 } else if (ssrc_of_sender
== ssrc_of_audio_sender_
) {
61 target
= audio_receiver_
.AsWeakPtr();
63 VLOG(1) << "Dropping packet with a non matching sender SSRC: "
67 cast_environment_
->PostTask(
68 CastEnvironment::MAIN
,
70 base::Bind(base::IgnoreResult(&FrameReceiver::ProcessPacket
),
72 base::Passed(&packet
)));
75 void CastReceiverImpl::RequestDecodedAudioFrame(
76 const AudioFrameDecodedCallback
& callback
) {
77 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
78 DCHECK(!callback
.is_null());
79 audio_receiver_
.RequestEncodedFrame(base::Bind(
80 &CastReceiverImpl::DecodeEncodedAudioFrame
,
81 // Note: Use of Unretained is safe since this Closure is guaranteed to be
82 // invoked or discarded by |audio_receiver_| before destruction of |this|.
83 base::Unretained(this),
87 void CastReceiverImpl::RequestEncodedAudioFrame(
88 const ReceiveEncodedFrameCallback
& callback
) {
89 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
90 audio_receiver_
.RequestEncodedFrame(callback
);
93 void CastReceiverImpl::RequestDecodedVideoFrame(
94 const VideoFrameDecodedCallback
& callback
) {
95 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
96 DCHECK(!callback
.is_null());
97 video_receiver_
.RequestEncodedFrame(base::Bind(
98 &CastReceiverImpl::DecodeEncodedVideoFrame
,
99 // Note: Use of Unretained is safe since this Closure is guaranteed to be
100 // invoked or discarded by |video_receiver_| before destruction of |this|.
101 base::Unretained(this),
105 void CastReceiverImpl::RequestEncodedVideoFrame(
106 const ReceiveEncodedFrameCallback
& callback
) {
107 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
108 video_receiver_
.RequestEncodedFrame(callback
);
111 void CastReceiverImpl::DecodeEncodedAudioFrame(
112 const AudioFrameDecodedCallback
& callback
,
113 scoped_ptr
<EncodedFrame
> encoded_frame
) {
114 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
115 if (!encoded_frame
) {
116 callback
.Run(make_scoped_ptr
<AudioBus
>(NULL
), base::TimeTicks(), false);
120 if (!audio_decoder_
) {
121 audio_decoder_
.reset(new AudioDecoder(cast_environment_
,
123 audio_sampling_rate_
,
126 const uint32 frame_id
= encoded_frame
->frame_id
;
127 const uint32 rtp_timestamp
= encoded_frame
->rtp_timestamp
;
128 const base::TimeTicks playout_time
= encoded_frame
->reference_time
;
129 audio_decoder_
->DecodeFrame(
130 encoded_frame
.Pass(),
131 base::Bind(&CastReceiverImpl::EmitDecodedAudioFrame
,
139 void CastReceiverImpl::DecodeEncodedVideoFrame(
140 const VideoFrameDecodedCallback
& callback
,
141 scoped_ptr
<EncodedFrame
> encoded_frame
) {
142 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
143 if (!encoded_frame
) {
145 make_scoped_refptr
<VideoFrame
>(NULL
), base::TimeTicks(), false);
149 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc
150 TRACE_EVENT_INSTANT2(
151 "cast_perf_test", "PullEncodedVideoFrame",
152 TRACE_EVENT_SCOPE_THREAD
,
153 "rtp_timestamp", encoded_frame
->rtp_timestamp
,
154 "render_time", encoded_frame
->reference_time
.ToInternalValue());
157 video_decoder_
.reset(new VideoDecoder(cast_environment_
, video_codec_
));
158 const uint32 frame_id
= encoded_frame
->frame_id
;
159 const uint32 rtp_timestamp
= encoded_frame
->rtp_timestamp
;
160 const base::TimeTicks playout_time
= encoded_frame
->reference_time
;
161 video_decoder_
->DecodeFrame(
162 encoded_frame
.Pass(),
163 base::Bind(&CastReceiverImpl::EmitDecodedVideoFrame
,
172 void CastReceiverImpl::EmitDecodedAudioFrame(
173 const scoped_refptr
<CastEnvironment
>& cast_environment
,
174 const AudioFrameDecodedCallback
& callback
,
176 uint32 rtp_timestamp
,
177 const base::TimeTicks
& playout_time
,
178 scoped_ptr
<AudioBus
> audio_bus
,
179 bool is_continuous
) {
180 DCHECK(cast_environment
->CurrentlyOn(CastEnvironment::MAIN
));
181 if (audio_bus
.get()) {
182 const base::TimeTicks now
= cast_environment
->Clock()->NowTicks();
183 cast_environment
->Logging()->InsertFrameEvent(
184 now
, FRAME_DECODED
, AUDIO_EVENT
, rtp_timestamp
, frame_id
);
185 cast_environment
->Logging()->InsertFrameEventWithDelay(
186 now
, FRAME_PLAYOUT
, AUDIO_EVENT
, rtp_timestamp
, frame_id
,
189 callback
.Run(audio_bus
.Pass(), playout_time
, is_continuous
);
193 void CastReceiverImpl::EmitDecodedVideoFrame(
194 const scoped_refptr
<CastEnvironment
>& cast_environment
,
195 const VideoFrameDecodedCallback
& callback
,
197 uint32 rtp_timestamp
,
198 const base::TimeTicks
& playout_time
,
199 const scoped_refptr
<VideoFrame
>& video_frame
,
200 bool is_continuous
) {
201 DCHECK(cast_environment
->CurrentlyOn(CastEnvironment::MAIN
));
202 if (video_frame
.get()) {
203 const base::TimeTicks now
= cast_environment
->Clock()->NowTicks();
204 cast_environment
->Logging()->InsertFrameEvent(
205 now
, FRAME_DECODED
, VIDEO_EVENT
, rtp_timestamp
, frame_id
);
206 cast_environment
->Logging()->InsertFrameEventWithDelay(
207 now
, FRAME_PLAYOUT
, VIDEO_EVENT
, rtp_timestamp
, frame_id
,
210 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc
211 TRACE_EVENT_INSTANT1(
212 "cast_perf_test", "FrameDecoded",
213 TRACE_EVENT_SCOPE_THREAD
,
214 "rtp_timestamp", rtp_timestamp
);
216 callback
.Run(video_frame
, playout_time
, is_continuous
);