Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / media / cast / receiver / cast_receiver_impl.cc
blob5a01bb0890f05e824b18e6be17d0630671c5acee
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"
7 #include "base/bind.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"
16 namespace media {
17 namespace cast {
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.";
54 return;
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();
62 } else {
63 VLOG(1) << "Dropping packet with a non matching sender SSRC: "
64 << ssrc_of_sender;
65 return;
67 cast_environment_->PostTask(
68 CastEnvironment::MAIN,
69 FROM_HERE,
70 base::Bind(base::IgnoreResult(&FrameReceiver::ProcessPacket),
71 target,
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),
84 callback));
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),
102 callback));
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);
117 return;
120 if (!audio_decoder_) {
121 audio_decoder_.reset(new AudioDecoder(cast_environment_,
122 num_audio_channels_,
123 audio_sampling_rate_,
124 audio_codec_));
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,
132 cast_environment_,
133 callback,
134 frame_id,
135 rtp_timestamp,
136 playout_time));
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) {
144 callback.Run(
145 make_scoped_refptr<VideoFrame>(NULL), base::TimeTicks(), false);
146 return;
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());
156 if (!video_decoder_)
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,
164 cast_environment_,
165 callback,
166 frame_id,
167 rtp_timestamp,
168 playout_time));
171 // static
172 void CastReceiverImpl::EmitDecodedAudioFrame(
173 const scoped_refptr<CastEnvironment>& cast_environment,
174 const AudioFrameDecodedCallback& callback,
175 uint32 frame_id,
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,
187 playout_time - now);
189 callback.Run(audio_bus.Pass(), playout_time, is_continuous);
192 // static
193 void CastReceiverImpl::EmitDecodedVideoFrame(
194 const scoped_refptr<CastEnvironment>& cast_environment,
195 const VideoFrameDecodedCallback& callback,
196 uint32 frame_id,
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,
208 playout_time - now);
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);
219 } // namespace cast
220 } // namespace media