mirror of https://bitbucket.org/ausocean/av.git
Merged in rtp-parsing (pull request #179)
protocol/rtp: can parse payload from RTP packet Approved-by: Alan Noble <anoble@gmail.com> Approved-by: kortschak <dan@kortschak.io>
This commit is contained in:
commit
6ee286e988
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
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 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 len(d) < defaultHeadSize {
|
||||
panic("invalid RTP packet length")
|
||||
}
|
||||
if version(d) != rtpVer {
|
||||
return nil, errors.New(badVer)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
NAME
|
||||
parse_test.go
|
||||
|
||||
DESCRIPTION
|
||||
parse_test.go provides testing for behaviour of functionality in parse.go.
|
||||
|
||||
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 http://www.gnu.org/licenses.
|
||||
*/
|
||||
|
||||
package rtp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestVersion checks that we can correctly get the version from an RTP packet.
|
||||
func TestVersion(t *testing.T) {
|
||||
const expect = 1
|
||||
got := version((&Pkt{V: expect}).Bytes(nil))
|
||||
if got != expect {
|
||||
t.Errorf("unexpected version for RTP packet. Got: %v\n Want: %v\n", got, expect)
|
||||
}
|
||||
}
|
||||
|
||||
// TestCsrcCount checks that we can correctly obtain the csrc count from an
|
||||
// RTP packet.
|
||||
func TestCsrcCount(t *testing.T) {
|
||||
const ver, expect = 2, 2
|
||||
|
||||
pkt := (&Pkt{
|
||||
V: ver,
|
||||
CC: expect,
|
||||
CSRC: make([][4]byte, expect),
|
||||
}).Bytes(nil)
|
||||
|
||||
got := csrcCount(pkt)
|
||||
if got != expect {
|
||||
t.Errorf("unexpected csrc count for RTP packet. Got: %v\n Want: %v\n", got, expect)
|
||||
}
|
||||
}
|
||||
|
||||
// TestHasExt checks the behaviour of hasExt with an RTP packet that has the
|
||||
// extension indicator true, and one with the extension indicator set to false.
|
||||
func TestHasExt(t *testing.T) {
|
||||
const ver = 2
|
||||
|
||||
// First check for when there is an extension field.
|
||||
pkt := &Pkt{
|
||||
V: ver,
|
||||
X: true,
|
||||
Extension: ExtensionHeader{
|
||||
ID: 0,
|
||||
Header: make([][4]byte, 0),
|
||||
},
|
||||
}
|
||||
|
||||
got := hasExt(pkt.Bytes(nil))
|
||||
if !got {
|
||||
t.Error("RTP packet did not have true extension indicator as expected")
|
||||
}
|
||||
|
||||
// Now check when there is not an extension field.
|
||||
pkt.X = false
|
||||
got = hasExt(pkt.Bytes(nil))
|
||||
if got {
|
||||
t.Error("did not expect to have extension indicator as true")
|
||||
}
|
||||
}
|
||||
|
||||
// TestPayload checks that we can correctly get the payload of an RTP packet
|
||||
// using Payload for a variety of RTP packet configurations.
|
||||
func TestPayload(t *testing.T) {
|
||||
const ver = 2
|
||||
expect := []byte{0x01, 0x02, 0x03, 0x04, 0x05}
|
||||
|
||||
testPkts := [][]byte{
|
||||
(&Pkt{
|
||||
V: ver,
|
||||
Payload: expect,
|
||||
}).Bytes(nil),
|
||||
|
||||
(&Pkt{
|
||||
V: ver,
|
||||
CC: 3,
|
||||
CSRC: make([][4]byte, 3),
|
||||
Payload: expect,
|
||||
}).Bytes(nil),
|
||||
|
||||
(&Pkt{
|
||||
V: ver,
|
||||
X: true,
|
||||
Extension: ExtensionHeader{
|
||||
ID: 0,
|
||||
Header: make([][4]byte, 3),
|
||||
},
|
||||
Payload: expect,
|
||||
}).Bytes(nil),
|
||||
|
||||
(&Pkt{
|
||||
V: ver,
|
||||
CC: 3,
|
||||
CSRC: make([][4]byte, 3),
|
||||
Extension: ExtensionHeader{
|
||||
ID: 0,
|
||||
Header: make([][4]byte, 3),
|
||||
},
|
||||
Payload: expect,
|
||||
}).Bytes(nil),
|
||||
}
|
||||
|
||||
for i, p := range testPkts {
|
||||
got, err := Payload(p)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error from Payload with pkt: %v", i)
|
||||
}
|
||||
|
||||
if !bytes.Equal(got, expect) {
|
||||
t.Errorf("unexpected payload data from RTP packet: %v.\n Got: %v\n Want: %v\n", i, got, expect)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,10 +37,11 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
rtpVer = 2
|
||||
defaultHeadSize = 3 * 4 // Header size of an rtp packet.
|
||||
rtpVer = 2 // Version of RTP that this package is compatible with.
|
||||
defaultHeadSize = 12 // 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
|
||||
|
|
Loading…
Reference in New Issue