/* NAME parse.go DESCRIPTION parse.go provides functionality for parsing RTP packets. AUTHOR Saxon A. Nelson-Milton LICENSE Copyright (C) 2019 the Australian Ocean Lab (AusOcean) This 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 in gpl.txt. If not, see http://www.gnu.org/licenses. */ package rtp import ( "encoding/binary" "errors" ) const badVer = "incompatible RTP version" // Marker returns the state of the RTP marker bit, and an error if parsing fails. func Marker(d []byte) (bool, error) { if len(d) < defaultHeadSize { panic("invalid RTP packet length") } if version(d) != rtpVer { return false, errors.New(badVer) } return d[1]&0x80 != 0, nil } // Payload returns the payload from an RTP packet provided the version is // compatible, otherwise an error is returned. func Payload(d []byte) ([]byte, error) { err := checkPacket(d) if err != nil { return nil, err } extLen := 0 if hasExt(d) { extLen = 4 + 4*(int(binary.BigEndian.Uint16(d[optionalFieldIdx+4*csrcCount(d)+2:]))) } payloadIdx := optionalFieldIdx + 4*csrcCount(d) + extLen return d[payloadIdx:], nil } // SSRC returns the source identifier from an RTP packet. An error is return if // the packet is not valid. func SSRC(d []byte) (uint32, error) { err := checkPacket(d) if err != nil { return 0, err } return binary.BigEndian.Uint32(d[8:]), nil } // Sequence returns the sequence number of an RTP packet. An error is returned // if the packet is not valid. func Sequence(d []byte) (uint16, error) { err := checkPacket(d) if err != nil { return 0, err } return binary.BigEndian.Uint16(d[2:]), nil } // Timestamp returns the RTP timestamp of an RTP packet. An error is returned // if the packet is not valid. func Timestamp(d []byte) (uint32, error) { err := checkPacket(d) if err != nil { return 0, err } return binary.BigEndian.Uint32(d[4:]), nil } // checkPacket checks the validity of the packet, firstly by checking size and // then also checking that version is compatible with these utilities. func checkPacket(d []byte) error { if len(d) < defaultHeadSize { return errors.New("invalid RTP packet length") } if version(d) != rtpVer { return errors.New(badVer) } return nil } // hasExt returns true if an extension is present in the RTP packet. func hasExt(d []byte) bool { return (d[0] & 0x10 >> 4) == 1 } // csrcCount returns the number of CSRC fields. func csrcCount(d []byte) int { return int(d[0] & 0x0f) } // version returns the version of the RTP packet. func version(d []byte) int { return int(d[0] & 0xc0 >> 6) }