diff --git a/protocol/rtp/parse.go b/protocol/rtp/parse.go new file mode 100644 index 00000000..d1ee487b --- /dev/null +++ b/protocol/rtp/parse.go @@ -0,0 +1,88 @@ +/* +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 + along with revid in gpl.txt. If not, see [GNU licenses](http://www.gnu.org/licenses). +*/ + +package rtp + +import ( + "encoding/binary" + "errors" +) + +const badVer = "incompatible RTP version" + +// Payload returns the payload from an RTP packet provided the version is +// compatible, otherwise an error is returned. +func Payload(d []byte) ([]byte, error) { + if version(d) != rtpVer { + return nil, errors.New(badVer) + } + extLen := 0 + if hasExt(d) { + extLen = 4 + 4*extHeaderLen(d) + } + payloadIdx := optionalFieldIdx + 4*csrcCount(d) + extLen + return d[payloadIdx:], nil +} + +// extHeaderLen returns the extension header length. The RTP packet must have +// a compatible version, and must have an extension field, otherwise we panic. +func extHeaderLen(d []byte) int { + if version(d) != rtpVer { + panic(badVer) + } + if !hasExt(d) { + panic("RTP packet does not have extension") + } + extIdx := optionalFieldIdx + 4*csrcCount(d) + return int(binary.BigEndian.Uint16(d[extIdx+2 : extIdx+4])) +} + +// hasExt returns true if an extension is present in the RTP packet. The version +// must be compatible otherwise we panic. +func hasExt(d []byte) bool { + if version(d) != rtpVer { + panic(badVer) + } + if (d[0] & 0x10 >> 4) == 1 { + return true + } + return false +} + +// csrcCount returns the number of CSRC fields. If the version is not compatible +// we panic. +func csrcCount(d []byte) int { + if version(d) != rtpVer { + panic(badVer) + } + return int(d[0] & 0x0f) +} + +// version returns the version of the RTP packet. +func version(d []byte) int { + return int(d[0] & 0xb0 >> 4) +} diff --git a/protocol/rtp/rtp.go b/protocol/rtp/rtp.go index 8b18d4ca..6550a647 100644 --- a/protocol/rtp/rtp.go +++ b/protocol/rtp/rtp.go @@ -37,10 +37,11 @@ import ( ) const ( - rtpVer = 2 - defaultHeadSize = 3 * 4 // Header size of an rtp packet. - defPayloadSize = sendSize // Default payload size for the rtp packet. - defPktSize = defaultHeadSize + defPayloadSize // Default packet size is header size + payload size. + rtpVer = 2 + defaultHeadSize = 3 * 4 // Header size of an rtp packet. + defPayloadSize = sendSize // Default payload size for the rtp packet. + defPktSize = defaultHeadSize + defPayloadSize // Default packet size is header size + payload size. + optionalFieldIdx = 12 // This is the idx of optional fields including CSRC and extension header in an RTP packet. ) // Pkt provides fields consistent with RFC3550 definition of an rtp packet