Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / media / cast / receiver / cast_receiver_impl.cc
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.
4
5 #include "media/cast/receiver/cast_receiver_impl.h"
6
7 #include "base/bind.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"
16
17 namespace media {
18 namespace cast {
19
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));
27 }
28
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(),
37              packet_sender,
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) {}
47
48 CastReceiverImpl::~CastReceiverImpl() {}
49
50 void CastReceiverImpl::DispatchReceivedPacket(scoped_ptr<Packet> packet) {
51   const uint8_t* const data = &packet->front();
52   const size_t length = packet->size();
53
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.";
59     return;
60   }
61
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();
67   } else {
68     VLOG(1) << "Dropping packet with a non matching sender SSRC: "
69             << ssrc_of_sender;
70     return;
71   }
72   cast_environment_->PostTask(
73       CastEnvironment::MAIN,
74       FROM_HERE,
75       base::Bind(base::IgnoreResult(&FrameReceiver::ProcessPacket),
76                  target,
77                  base::Passed(&packet)));
78 }
79
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));
86 }
87
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),
97       callback));
98 }
99
100 void CastReceiverImpl::RequestEncodedAudioFrame(
101     const ReceiveEncodedFrameCallback& callback) {
102   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
103   audio_receiver_.RequestEncodedFrame(callback);
104 }
105
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),
115       callback));
116 }
117
118 void CastReceiverImpl::RequestEncodedVideoFrame(
119     const ReceiveEncodedFrameCallback& callback) {
120   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
121   video_receiver_.RequestEncodedFrame(callback);
122 }
123
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);
130     return;
131   }
132
133   if (!audio_decoder_) {
134     audio_decoder_.reset(new AudioDecoder(cast_environment_,
135                                           num_audio_channels_,
136                                           audio_sampling_rate_,
137                                           audio_codec_));
138   }
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,
145                  cast_environment_,
146                  callback,
147                  frame_id,
148                  rtp_timestamp,
149                  playout_time));
150 }
151
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) {
157     callback.Run(
158         make_scoped_refptr<VideoFrame>(NULL), base::TimeTicks(), false);
159     return;
160   }
161
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());
168
169   if (!video_decoder_)
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,
177                  cast_environment_,
178                  callback,
179                  frame_id,
180                  rtp_timestamp,
181                  playout_time));
182 }
183
184 // static
185 void CastReceiverImpl::EmitDecodedAudioFrame(
186     const scoped_refptr<CastEnvironment>& cast_environment,
187     const AudioFrameDecodedCallback& callback,
188     uint32 frame_id,
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,
200         playout_time - now);
201   }
202   callback.Run(audio_bus.Pass(), playout_time, is_continuous);
203 }
204
205 // static
206 void CastReceiverImpl::EmitDecodedVideoFrame(
207     const scoped_refptr<CastEnvironment>& cast_environment,
208     const VideoFrameDecodedCallback& callback,
209     uint32 frame_id,
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));
215   if (video_frame) {
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,
221         playout_time - now);
222
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);
228   }
229   callback.Run(video_frame, playout_time, is_continuous);
230 }
231
232 }  // namespace cast
233 }  // namespace media