// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This class maintains a transport for audio and video in a Cast Streaming
// session.
// Audio, video frames and RTCP messages are submitted to this object
// and then packetized and paced to the underlying UDP socket.
//
// The hierarchy of send transport in a Cast Streaming session:
//
// CastTransport              RTP                      RTCP
// ------------------------------------------------------------------
//                      TransportEncryptionHandler (A/V)
//                      RtpSender (A/V)                   Rtcp (A/V)
//                                      PacedSender (Shared)
//                                      UdpTransport (Shared)
//
// There are objects of TransportEncryptionHandler, RtpSender and Rtcp
// for each audio and video stream.
// PacedSender and UdpTransport are shared between all RTP and RTCP
// streams.

#ifndef MEDIA_CAST_NET_CAST_TRANSPORT_IMPL_H_
#define MEDIA_CAST_NET_CAST_TRANSPORT_IMPL_H_

#include <stdint.h>

#include <memory>
#include <set>
#include <vector>

#include "base/callback.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "media/cast/common/transport_encryption_handler.h"
#include "media/cast/logging/logging_defines.h"
#include "media/cast/net/cast_transport.h"
#include "media/cast/net/cast_transport_config.h"
#include "media/cast/net/pacing/paced_sender.h"
#include "media/cast/net/rtcp/rtcp_builder.h"
#include "media/cast/net/rtcp/sender_rtcp_session.h"
#include "media/cast/net/rtp/rtp_parser.h"
#include "media/cast/net/rtp/rtp_sender.h"
#include "net/base/network_interfaces.h"

namespace media {
namespace cast {

class UdpTransport;

class CastTransportImpl final : public CastTransport {
 public:
  CastTransportImpl(
      base::TickClock* clock,  // Owned by the caller.
      base::TimeDelta logging_flush_interval,
      std::unique_ptr<Client> client,
      std::unique_ptr<PacketTransport> transport,
      const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner);

  ~CastTransportImpl() final;

  // CastTransport implementation for sending.
  void InitializeAudio(const CastTransportRtpConfig& config,
                       std::unique_ptr<RtcpObserver> rtcp_observer) final;
  void InitializeVideo(const CastTransportRtpConfig& config,
                       std::unique_ptr<RtcpObserver> rtcp_observer) final;
  void InsertFrame(uint32_t ssrc, const EncodedFrame& frame) final;

  void SendSenderReport(uint32_t ssrc,
                        base::TimeTicks current_time,
                        RtpTimeTicks current_time_as_rtp_timestamp) final;

  void CancelSendingFrames(uint32_t ssrc,
                           const std::vector<FrameId>& frame_ids) final;

  void ResendFrameForKickstart(uint32_t ssrc, FrameId frame_id) final;

  PacketReceiverCallback PacketReceiverForTesting() final;

  // Possible keys of |options| handled here are:
  //   "pacer_target_burst_size": int
  //        - Specifies how many packets to send per 10 ms ideally.
  //   "pacer_max_burst_size": int
  //        - Specifies how many pakcets to send per 10 ms, maximum.
  //   "send_buffer_min_size": int
  //        - Specifies the minimum socket send buffer size.
  //   "disable_wifi_scan" (value ignored)
  //        - Disable wifi scans while streaming.
  //   "media_streaming_mode" (value ignored)
  //        - Turn media streaming mode on.
  // Note, these options may be ignored on some platforms.
  void SetOptions(const base::DictionaryValue& options) final;

  // CastTransport implementation for receiving.
  void AddValidRtpReceiver(uint32_t rtp_sender_ssrc,
                           uint32_t rtp_receiver_ssrc) final;

  // Building and sending RTCP packet from RTP receiver implementation.
  void InitializeRtpReceiverRtcpBuilder(uint32_t rtp_receiver_ssrc,
                                        const RtcpTimeData& time_data) final;
  void AddCastFeedback(const RtcpCastMessage& cast_message,
                       base::TimeDelta target_delay) final;
  void AddPli(const RtcpPliMessage& pli_message) final;
  void AddRtcpEvents(
      const ReceiverRtcpEventSubscriber::RtcpEvents& rtcp_events) final;
  void AddRtpReceiverReport(
      const RtcpReportBlock& rtp_receiver_report_block) final;
  void SendRtcpFromRtpReceiver() final;

 private:
  // Handle received RTCP messages on RTP sender.
  class RtcpClient;

  FRIEND_TEST_ALL_PREFIXES(CastTransportImplTest, NacksCancelRetransmits);
  FRIEND_TEST_ALL_PREFIXES(CastTransportImplTest, CancelRetransmits);
  FRIEND_TEST_ALL_PREFIXES(CastTransportImplTest, Kickstart);
  FRIEND_TEST_ALL_PREFIXES(CastTransportImplTest, DedupRetransmissionWithAudio);

  // Resend packets for the stream identified by |ssrc|.
  // If |cancel_rtx_if_not_in_list| is true then transmission of packets for the
  // frames but not in the list will be dropped.
  // See PacedSender::ResendPackets() to see how |dedup_info| works.
  void ResendPackets(uint32_t ssrc,
                     const MissingFramesAndPacketsMap& missing_packets,
                     bool cancel_rtx_if_not_in_list,
                     const DedupInfo& dedup_info);

  // If |logging_flush_interval| is set, this is called at approximate periodic
  // intervals.
  void SendRawEvents();

  // Called when a packet is received.
  bool OnReceivedPacket(std::unique_ptr<Packet> packet);

  // Called when a log message is received.
  void OnReceivedLogMessage(EventMediaType media_type,
                            const RtcpReceiverLogMessage& log);

  // Called when a RTCP Cast message is received.
  void OnReceivedCastMessage(uint32_t ssrc,
                             const RtcpCastMessage& cast_message);

  base::TickClock* const clock_;  // Not owned by this class.
  const base::TimeDelta logging_flush_interval_;
  const std::unique_ptr<Client> transport_client_;
  const std::unique_ptr<PacketTransport> transport_;
  const scoped_refptr<base::SingleThreadTaskRunner> transport_task_runner_;

  // FrameEvents and PacketEvents pending delivery via raw events callback.
  // Do not add elements to these when |logging_flush_interval| is
  // |base::TimeDelta()|.
  std::vector<FrameEvent> recent_frame_events_;
  std::vector<PacketEvent> recent_packet_events_;

  // Packet sender that performs pacing.
  PacedSender pacer_;

  // Packetizer for audio and video frames.
  std::unique_ptr<RtpSender> audio_sender_;
  std::unique_ptr<RtpSender> video_sender_;

  // Maintains RTCP session for audio and video.
  std::unique_ptr<SenderRtcpSession> audio_rtcp_session_;
  std::unique_ptr<SenderRtcpSession> video_rtcp_session_;

  // RTCP observer for SenderRtcpSession.
  std::unique_ptr<RtcpObserver> audio_rtcp_observer_;
  std::unique_ptr<RtcpObserver> video_rtcp_observer_;

  // Encrypts data in EncodedFrames before they are sent.  Note that it's
  // important for the encryption to happen here, in code that would execute in
  // the main browser process, for security reasons.  This helps to mitigate
  // the damage that could be caused by a compromised renderer process.
  TransportEncryptionHandler audio_encryptor_;
  TransportEncryptionHandler video_encryptor_;

  // Right after a frame is sent we record the number of bytes sent to the
  // socket. We record the corresponding bytes sent for the most recent ACKed
  // audio packet.
  int64_t last_byte_acked_for_audio_;

  // Packets that don't match these sender ssrcs are ignored.
  std::set<uint32_t> valid_sender_ssrcs_;

  // While non-null, global WiFi behavior modifications are in effect. This is
  // used, for example, to turn off WiFi scanning that tends to interfere with
  // the reliability of UDP packet transmission.
  std::unique_ptr<net::ScopedWifiOptions> wifi_options_autoreset_;

  // Do not initialize the |rtcp_builder_at_rtp_receiver_| if the RTP receiver
  // SSRC does not match these ssrcs. Only RTP receiver needs to register its
  // SSRC in this set.
  std::set<uint32_t> valid_rtp_receiver_ssrcs_;

  std::unique_ptr<RtcpBuilder> rtcp_builder_at_rtp_receiver_;

  base::WeakPtrFactory<CastTransportImpl> weak_factory_;

  DISALLOW_COPY_AND_ASSIGN(CastTransportImpl);
};

}  // namespace cast
}  // namespace media

#endif  // MEDIA_CAST_NET_CAST_TRANSPORT_IMPL_H_
