/*
NAME
  rtp.go - provides a data structure intended to encapsulate the properties
  of an rtp packet and also functions to allow manipulation of these packets.

DESCRIPTION
  See Readme.md

AUTHOR
  Saxon A. Nelson-Milton <saxon@ausocean.org>

LICENSE
  rtp.go is Copyright (C) 2018 the Australian Ocean Lab (AusOcean)

  It is free software: you can redistribute it and/or modify them
  under the terms of the GNU General Public License as published by the
  Free Software Foundation, either version 3 of the License, or (at your
  option) any later version.

  It is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 for more details.

  You should have received a copy of the GNU General Public License
  along with revid in gpl.txt.  If not, see [GNU licenses](http://www.gnu.org/licenses).
*/

/*
See https://tools.ietf.org/html/rfc6184 and https://tools.ietf.org/html/rfc3550
for rtp-h264 and rtp standards.
*/
package rtp

const (
	rtpVer = 2
)

// Pkt provides fields consistent with RFC3550 definition of an rtp packet
// The padding indicator does not need to be set manually, only the padding length
type Pkt struct {
	V       byte   // Version (currently 2)
	p       byte   // Padding indicator (0 => padding, 1 => padding)
	X       byte   // Extension header indicator
	CC      byte   // CSRC count
	M       byte   // Marker bit
	PT      byte   // Packet type
	SN      uint16 // Synch number
	TS      uint32 // Timestamp
	SSRC    uint32 // Synchronisation source identifier
	Payload []byte // H264 Payload data
	Padding byte   // No of bytes of padding
}

// Bytes provides a byte slice of the packet
func (p *Pkt) Bytes() []byte {
	if p.V == 0 {
		p.V = rtpVer
	}

	if p.Padding > 0 {
		p.p = 1
	}

	if p.CC != 0 {
		panic("CC has been set to something other than 0 - this is not supported yet.")
	}

	if p.X != 0 {
		panic("rtp: X (extension header indicator) not 0, but extensiion headers not currently supported.")
	}

	if p.CC != 0 {
		panic("rtp: CC (CSRC count) not 0, but CSRC headers not yet supported.")
	}

	const headSize = 3 * 4 // bytes
	buf := make([]byte, headSize, headSize+len(p.Payload)+int(p.Padding))

	buf[0] = p.V<<6 | p.p<<5 | p.CC
	buf[1] = p.M<<7 | p.PT
	buf[2] = byte(p.SN >> 8)
	buf[3] = byte(p.SN)
	buf[4] = byte(p.TS >> 24)
	buf[5] = byte(p.TS >> 16)
	buf[6] = byte(p.TS >> 8)
	buf[7] = byte(p.TS)
	buf[8] = byte(p.SSRC >> 24)
	buf[9] = byte(p.SSRC >> 16)
	buf[10] = byte(p.SSRC >> 8)
	buf[11] = byte(p.SSRC)

	buf = append(buf, p.Payload...)
	// see https://tools.ietf.org/html/rfc3550 section 5.1 (padding). At end of
	// rtp packet, padding may exist, with the last octet being the length of the
	// padding including itself.
	if p.Padding != 0 {
		buf = buf[:cap(buf)]
		buf[len(buf)-1] = byte(p.Padding)
	}
	return buf
}