av/protocol/rtp/parse.go

89 lines
2.2 KiB
Go
Raw Normal View History

/*
NAME
parse.go
DESCRIPTION
parse.go provides functionality for parsing RTP packets.
AUTHOR
Saxon A. Nelson-Milton <saxon@ausocean.org>
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 [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] & 0xc0 >> 6)
}