7cff354c1467220ce970324a879f321e059b6ade
[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/receiver/audio_decoder.h"
14 #include "media/cast/receiver/video_decoder.h"
15
16 namespace media {
17 namespace cast {
18
19 scoped_ptr<CastReceiver> CastReceiver::Create(
20     scoped_refptr<CastEnvironment> cast_environment,
21     const FrameReceiverConfig& audio_config,
22     const FrameReceiverConfig& video_config,
23     transport::PacketSender* const packet_sender) {
24   return scoped_ptr<CastReceiver>(new CastReceiverImpl(
25       cast_environment, audio_config, video_config, packet_sender));
26 }
27
28 CastReceiverImpl::CastReceiverImpl(
29     scoped_refptr<CastEnvironment> cast_environment,
30     const FrameReceiverConfig& audio_config,
31     const FrameReceiverConfig& video_config,
32     transport::PacketSender* const packet_sender)
33     : cast_environment_(cast_environment),
34       pacer_(cast_environment->Clock(),
35              cast_environment->Logging(),
36              packet_sender,
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.audio),
45       video_codec_(video_config.codec.video) {}
46
47 CastReceiverImpl::~CastReceiverImpl() {}
48
49 void CastReceiverImpl::DispatchReceivedPacket(scoped_ptr<Packet> packet) {
50   const uint8_t* const data = &packet->front();
51   const size_t length = packet->size();
52
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.";
58     return;
59   }
60
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();
66   } else {
67     VLOG(1) << "Dropping packet with a non matching sender SSRC: "
68             << ssrc_of_sender;
69     return;
70   }
71   cast_environment_->PostTask(
72       CastEnvironment::MAIN,
73       FROM_HERE,
74       base::Bind(base::IgnoreResult(&FrameReceiver::ProcessPacket),
75                  target,
76                  base::Passed(&packet)));
77 }
78
79 transport::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));
85 }
86
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),
96       callback));
97 }
98
99 void CastReceiverImpl::RequestEncodedAudioFrame(
100     const ReceiveEncodedFrameCallback& callback) {
101   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
102   audio_receiver_.RequestEncodedFrame(callback);
103 }
104
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),
114       callback));
115 }
116
117 void CastReceiverImpl::RequestEncodedVideoFrame(
118     const ReceiveEncodedFrameCallback& callback) {
119   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
120   video_receiver_.RequestEncodedFrame(callback);
121 }
122
123 void CastReceiverImpl::DecodeEncodedAudioFrame(
124     const AudioFrameDecodedCallback& callback,
125     scoped_ptr<transport::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);
129     return;
130   }
131
132   if (!audio_decoder_) {
133     audio_decoder_.reset(new AudioDecoder(cast_environment_,
134                                           num_audio_channels_,
135                                           audio_sampling_rate_,
136                                           audio_codec_));
137   }
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,
144                  cast_environment_,
145                  callback,
146                  frame_id,
147                  rtp_timestamp,
148                  playout_time));
149 }
150
151 void CastReceiverImpl::DecodeEncodedVideoFrame(
152     const VideoFrameDecodedCallback& callback,
153     scoped_ptr<transport::EncodedFrame> encoded_frame) {
154   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
155   if (!encoded_frame) {
156     callback.Run(
157         make_scoped_refptr<VideoFrame>(NULL), base::TimeTicks(), false);
158     return;
159   }
160
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());
167
168   if (!video_decoder_)
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,
176                  cast_environment_,
177                  callback,
178                  frame_id,
179                  rtp_timestamp,
180                  playout_time));
181 }
182
183 // static
184 void CastReceiverImpl::EmitDecodedAudioFrame(
185     const scoped_refptr<CastEnvironment>& cast_environment,
186     const AudioFrameDecodedCallback& callback,
187     uint32 frame_id,
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,
199         playout_time - now);
200   }
201   callback.Run(audio_bus.Pass(), playout_time, is_continuous);
202 }
203
204 // static
205 void CastReceiverImpl::EmitDecodedVideoFrame(
206     const scoped_refptr<CastEnvironment>& cast_environment,
207     const VideoFrameDecodedCallback& callback,
208     uint32 frame_id,
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) {
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,
220         playout_time - now);
221
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);
227   }
228   callback.Run(video_frame, playout_time, is_continuous);
229 }
230
231 }  // namespace cast
232 }  // namespace media