// Copyright 2019 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.

#ifndef CAST_STREAMING_RTP_PACKETIZER_H_
#define CAST_STREAMING_RTP_PACKETIZER_H_

#include <stdint.h>

#include "absl/types/span.h"
#include "cast/streaming/frame_crypto.h"
#include "cast/streaming/rtp_defines.h"
#include "cast/streaming/ssrc.h"

namespace openscreen {
namespace cast {

// Transforms a logical sequence of EncryptedFrames into RTP packets for
// transmission. A single instance of RtpPacketizer should be used for all the
// frames in a Cast RTP stream having the same SSRC.
class RtpPacketizer {
 public:
  // |payload_type| describes the type of the media content for the RTP stream
  // from the sender having the given |sender_ssrc|.
  //
  // The |max_packet_size| argument depends on the optimal over-the-wire size of
  // packets for the network medium being used. See discussion in rtp_defines.h
  // for further info.
  RtpPacketizer(RtpPayloadType payload_type,
                Ssrc sender_ssrc,
                int max_packet_size);

  ~RtpPacketizer();

  // Wire-format one of the RTP packets for the given frame, which must only be
  // transmitted once. This method should be called in the same sequence that
  // packets will be transmitted. This also means that, if a packet needs to be
  // re-transmitted, this method should be called to generate it again. Returns
  // the subspan of |buffer| that contains the packet. |buffer| must be at least
  // as large as the |max_packet_size| passed to the constructor.
  absl::Span<uint8_t> GeneratePacket(const EncryptedFrame& frame,
                                     FramePacketId packet_id,
                                     absl::Span<uint8_t> buffer);

  // Given |frame|, compute the total number of packets over which the whole
  // frame will be split-up. Returns -1 if the frame is too large and cannot be
  // packetized.
  int ComputeNumberOfPackets(const EncryptedFrame& frame) const;

  // See rtp_defines.h for wire-format diagram.
  static constexpr int kBaseRtpHeaderSize =
      // Plus one byte, because this implementation always includes the 8-bit
      // Reference Frame ID field.
      kRtpPacketMinValidSize + 1;
  static constexpr int kAdaptiveLatencyHeaderSize = 4;
  static constexpr int kMaxRtpHeaderSize =
      kBaseRtpHeaderSize + kAdaptiveLatencyHeaderSize;

 private:
  int max_payload_size() const {
    // Start with the configured max packet size, then subtract reserved space
    // for packet header fields. The rest can be allocated to the payload.
    return max_packet_size_ - kMaxRtpHeaderSize;
  }

  // The validated ctor RtpPayloadType arg, in wire-format form.
  const uint8_t payload_type_7bits_;

  const Ssrc sender_ssrc_;
  const int max_packet_size_;

  // Incremented each time GeneratePacket() is called. Every packet, even those
  // re-transmitted, must have different sequence numbers (within wrap-around
  // concerns) per the RTP spec.
  uint16_t sequence_number_;
};

}  // namespace cast
}  // namespace openscreen

#endif  // CAST_STREAMING_RTP_PACKETIZER_H_
