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     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
    233