Home | History | Annotate | Download | only in receiver
      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     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     PacketSender* const packet_sender)
     33     : cast_environment_(cast_environment),
     34       pacer_(kTargetBurstSize,
     35              kMaxBurstSize,
     36              cast_environment->Clock(),
     37              cast_environment->Logging(),
     38              packet_sender,
     39              cast_environment->GetTaskRunner(CastEnvironment::MAIN)),
     40       audio_receiver_(cast_environment, audio_config, AUDIO_EVENT, &pacer_),
     41       video_receiver_(cast_environment, video_config, VIDEO_EVENT, &pacer_),
     42       ssrc_of_audio_sender_(audio_config.incoming_ssrc),
     43       ssrc_of_video_sender_(video_config.incoming_ssrc),
     44       num_audio_channels_(audio_config.channels),
     45       audio_sampling_rate_(audio_config.frequency),
     46       audio_codec_(audio_config.codec),
     47       video_codec_(video_config.codec) {}
     48 
     49 CastReceiverImpl::~CastReceiverImpl() {}
     50 
     51 void CastReceiverImpl::DispatchReceivedPacket(scoped_ptr<Packet> packet) {
     52   const uint8_t* const data = &packet->front();
     53   const size_t length = packet->size();
     54 
     55   uint32 ssrc_of_sender;
     56   if (Rtcp::IsRtcpPacket(data, length)) {
     57     ssrc_of_sender = Rtcp::GetSsrcOfSender(data, length);
     58   } else if (!FrameReceiver::ParseSenderSsrc(data, length, &ssrc_of_sender)) {
     59     VLOG(1) << "Invalid RTP packet.";
     60     return;
     61   }
     62 
     63   base::WeakPtr<FrameReceiver> target;
     64   if (ssrc_of_sender == ssrc_of_video_sender_) {
     65     target = video_receiver_.AsWeakPtr();
     66   } else if (ssrc_of_sender == ssrc_of_audio_sender_) {
     67     target = audio_receiver_.AsWeakPtr();
     68   } else {
     69     VLOG(1) << "Dropping packet with a non matching sender SSRC: "
     70             << ssrc_of_sender;
     71     return;
     72   }
     73   cast_environment_->PostTask(
     74       CastEnvironment::MAIN,
     75       FROM_HERE,
     76       base::Bind(base::IgnoreResult(&FrameReceiver::ProcessPacket),
     77                  target,
     78                  base::Passed(&packet)));
     79 }
     80 
     81 PacketReceiverCallback CastReceiverImpl::packet_receiver() {
     82   return base::Bind(&CastReceiverImpl::DispatchReceivedPacket,
     83                     // TODO(miu): This code structure is dangerous, since the
     84                     // callback could be stored and then invoked after
     85                     // destruction of |this|.
     86                     base::Unretained(this));
     87 }
     88 
     89 void CastReceiverImpl::RequestDecodedAudioFrame(
     90     const AudioFrameDecodedCallback& callback) {
     91   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
     92   DCHECK(!callback.is_null());
     93   audio_receiver_.RequestEncodedFrame(base::Bind(
     94       &CastReceiverImpl::DecodeEncodedAudioFrame,
     95       // Note: Use of Unretained is safe since this Closure is guaranteed to be
     96       // invoked or discarded by |audio_receiver_| before destruction of |this|.
     97       base::Unretained(this),
     98       callback));
     99 }
    100 
    101 void CastReceiverImpl::RequestEncodedAudioFrame(
    102     const ReceiveEncodedFrameCallback& callback) {
    103   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
    104   audio_receiver_.RequestEncodedFrame(callback);
    105 }
    106 
    107 void CastReceiverImpl::RequestDecodedVideoFrame(
    108     const VideoFrameDecodedCallback& callback) {
    109   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
    110   DCHECK(!callback.is_null());
    111   video_receiver_.RequestEncodedFrame(base::Bind(
    112       &CastReceiverImpl::DecodeEncodedVideoFrame,
    113       // Note: Use of Unretained is safe since this Closure is guaranteed to be
    114       // invoked or discarded by |video_receiver_| before destruction of |this|.
    115       base::Unretained(this),
    116       callback));
    117 }
    118 
    119 void CastReceiverImpl::RequestEncodedVideoFrame(
    120     const ReceiveEncodedFrameCallback& callback) {
    121   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
    122   video_receiver_.RequestEncodedFrame(callback);
    123 }
    124 
    125 void CastReceiverImpl::DecodeEncodedAudioFrame(
    126     const AudioFrameDecodedCallback& callback,
    127     scoped_ptr<EncodedFrame> encoded_frame) {
    128   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
    129   if (!encoded_frame) {
    130     callback.Run(make_scoped_ptr<AudioBus>(NULL), base::TimeTicks(), false);
    131     return;
    132   }
    133 
    134   if (!audio_decoder_) {
    135     audio_decoder_.reset(new AudioDecoder(cast_environment_,
    136                                           num_audio_channels_,
    137                                           audio_sampling_rate_,
    138                                           audio_codec_));
    139   }
    140   const uint32 frame_id = encoded_frame->frame_id;
    141   const uint32 rtp_timestamp = encoded_frame->rtp_timestamp;
    142   const base::TimeTicks playout_time = encoded_frame->reference_time;
    143   audio_decoder_->DecodeFrame(
    144       encoded_frame.Pass(),
    145       base::Bind(&CastReceiverImpl::EmitDecodedAudioFrame,
    146                  cast_environment_,
    147                  callback,
    148                  frame_id,
    149                  rtp_timestamp,
    150                  playout_time));
    151 }
    152 
    153 void CastReceiverImpl::DecodeEncodedVideoFrame(
    154     const VideoFrameDecodedCallback& callback,
    155     scoped_ptr<EncodedFrame> encoded_frame) {
    156   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
    157   if (!encoded_frame) {
    158     callback.Run(
    159         make_scoped_refptr<VideoFrame>(NULL), base::TimeTicks(), false);
    160     return;
    161   }
    162 
    163   // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc
    164   TRACE_EVENT_INSTANT2(
    165       "cast_perf_test", "PullEncodedVideoFrame",
    166       TRACE_EVENT_SCOPE_THREAD,
    167       "rtp_timestamp", encoded_frame->rtp_timestamp,
    168       "render_time", encoded_frame->reference_time.ToInternalValue());
    169 
    170   if (!video_decoder_)
    171     video_decoder_.reset(new VideoDecoder(cast_environment_, video_codec_));
    172   const uint32 frame_id = encoded_frame->frame_id;
    173   const uint32 rtp_timestamp = encoded_frame->rtp_timestamp;
    174   const base::TimeTicks playout_time = encoded_frame->reference_time;
    175   video_decoder_->DecodeFrame(
    176       encoded_frame.Pass(),
    177       base::Bind(&CastReceiverImpl::EmitDecodedVideoFrame,
    178                  cast_environment_,
    179                  callback,
    180                  frame_id,
    181                  rtp_timestamp,
    182                  playout_time));
    183 }
    184 
    185 // static
    186 void CastReceiverImpl::EmitDecodedAudioFrame(
    187     const scoped_refptr<CastEnvironment>& cast_environment,
    188     const AudioFrameDecodedCallback& callback,
    189     uint32 frame_id,
    190     uint32 rtp_timestamp,
    191     const base::TimeTicks& playout_time,
    192     scoped_ptr<AudioBus> audio_bus,
    193     bool is_continuous) {
    194   DCHECK(cast_environment->CurrentlyOn(CastEnvironment::MAIN));
    195   if (audio_bus.get()) {
    196     const base::TimeTicks now = cast_environment->Clock()->NowTicks();
    197     cast_environment->Logging()->InsertFrameEvent(
    198         now, FRAME_DECODED, AUDIO_EVENT, rtp_timestamp, frame_id);
    199     cast_environment->Logging()->InsertFrameEventWithDelay(
    200         now, FRAME_PLAYOUT, AUDIO_EVENT, rtp_timestamp, frame_id,
    201         playout_time - now);
    202   }
    203   callback.Run(audio_bus.Pass(), playout_time, is_continuous);
    204 }
    205 
    206 // static
    207 void CastReceiverImpl::EmitDecodedVideoFrame(
    208     const scoped_refptr<CastEnvironment>& cast_environment,
    209     const VideoFrameDecodedCallback& callback,
    210     uint32 frame_id,
    211     uint32 rtp_timestamp,
    212     const base::TimeTicks& playout_time,
    213     const scoped_refptr<VideoFrame>& video_frame,
    214     bool is_continuous) {
    215   DCHECK(cast_environment->CurrentlyOn(CastEnvironment::MAIN));
    216   if (video_frame.get()) {
    217     const base::TimeTicks now = cast_environment->Clock()->NowTicks();
    218     cast_environment->Logging()->InsertFrameEvent(
    219         now, FRAME_DECODED, VIDEO_EVENT, rtp_timestamp, frame_id);
    220     cast_environment->Logging()->InsertFrameEventWithDelay(
    221         now, FRAME_PLAYOUT, VIDEO_EVENT, rtp_timestamp, frame_id,
    222         playout_time - now);
    223 
    224     // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc
    225     TRACE_EVENT_INSTANT1(
    226         "cast_perf_test", "FrameDecoded",
    227         TRACE_EVENT_SCOPE_THREAD,
    228         "rtp_timestamp", rtp_timestamp);
    229   }
    230   callback.Run(video_frame, playout_time, is_continuous);
    231 }
    232 
    233 }  // namespace cast
    234 }  // namespace media
    235