mirror of https://bitbucket.org/ausocean/av.git
protocol/rtsp: more commenting and started writing client_test.go to check the behaviour of the rtcp client
This commit is contained in:
parent
5fa0969530
commit
af664b0661
|
@ -59,14 +59,14 @@ func NewClient(clientAddress, serverAddress, name string, sendInterval time.Dura
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start starts the listen and send routines. This will start the process of
|
// Start starts the listen and send routines. This will start the process of
|
||||||
// receiving and parsing SenderReports, and the process of sending receiver
|
// receiving and parsing sender reports, and the process of sending receiver
|
||||||
// reports to the server.
|
// reports to the server.
|
||||||
func (c *client) Start() {
|
func (c *client) Start() {
|
||||||
go c.listen()
|
go c.listen()
|
||||||
go c.send()
|
go c.send()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen reads from the UDP connection and parses SenderReports.
|
// listen reads from the UDP connection and parses SenderReports.
|
||||||
func (c *client) listen() {
|
func (c *client) listen() {
|
||||||
conn, err := net.ListenUDP("udp", c.cAddr)
|
conn, err := net.ListenUDP("udp", c.cAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -79,7 +79,7 @@ func (c *client) listen() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// send write sender reports to the server.
|
// send writes receiver reports to the server.
|
||||||
func (c *client) send() {
|
func (c *client) send() {
|
||||||
conn, err := net.DialUDP("udp", c.cAddr, c.sAddr)
|
conn, err := net.DialUDP("udp", c.cAddr, c.sAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -154,12 +154,15 @@ func (c *client) parse(buf []byte) {
|
||||||
c.setSenderTs(msw, lsw)
|
c.setSenderTs(msw, lsw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateSequence will allow updating of the highest sequence number received
|
||||||
|
// through an rtp stream.
|
||||||
func (c *client) UpdateSequence(s uint32) {
|
func (c *client) UpdateSequence(s uint32) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
c.sequence = s
|
c.sequence = s
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// highestSequence will return the highest sequence number received through rtp.
|
||||||
func (c *client) highestSequence() uint32 {
|
func (c *client) highestSequence() uint32 {
|
||||||
var s uint32
|
var s uint32
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
|
@ -168,10 +171,13 @@ func (c *client) highestSequence() uint32 {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// jitter returns the interarrival jitter as described by RTCP specifications:
|
||||||
|
// https://tools.ietf.org/html/rfc3550
|
||||||
func (c *client) jitter() uint32 {
|
func (c *client) jitter() uint32 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setSenderTs allows us to safely set the current sender report timestamp.
|
||||||
func (c *client) setSenderTs(msw, lsw uint32) {
|
func (c *client) setSenderTs(msw, lsw uint32) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
binary.BigEndian.PutUint32(c.senderTs[:], msw)
|
binary.BigEndian.PutUint32(c.senderTs[:], msw)
|
||||||
|
@ -179,6 +185,7 @@ func (c *client) setSenderTs(msw, lsw uint32) {
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lastSenderTs returns the timestamp of the most recent sender report.
|
||||||
func (c *client) lastSenderTs() uint32 {
|
func (c *client) lastSenderTs() uint32 {
|
||||||
var ts uint32
|
var ts uint32
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
|
@ -187,6 +194,8 @@ func (c *client) lastSenderTs() uint32 {
|
||||||
return ts
|
return ts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// delay returns the duration between the receive time of the last sender report
|
||||||
|
// and now. This is called when forming a receiver report.
|
||||||
func (c *client) delay() uint32 {
|
func (c *client) delay() uint32 {
|
||||||
var receiveTime time.Time
|
var receiveTime time.Time
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
|
@ -196,6 +205,7 @@ func (c *client) delay() uint32 {
|
||||||
return uint32(now.Sub(receiveTime).Seconds() / delayUnit)
|
return uint32(now.Sub(receiveTime).Seconds() / delayUnit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// received is called when a sender report is received to mark the receive time.
|
||||||
func (c *client) received() {
|
func (c *client) received() {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
c.receiveTime = time.Now()
|
c.receiveTime = time.Now()
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package rtcp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReceiveAndSend(t *testing.T) {
|
||||||
|
quit := make(chan struct{})
|
||||||
|
go testServer(quit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testServer(quit chan struct{}, t *testing.T) {
|
||||||
|
const testServerAddr = "localhost:8000"
|
||||||
|
sAddr, err := net.ResolveUDPAddr("udp", testServerAddr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not resolve test server address, failed with error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := net.DialUDP("udp", nil, sAddr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not dial, failed with error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-quit:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,14 +7,12 @@ import (
|
||||||
|
|
||||||
// Timestamp gets the timestamp from a receiver report and returns as the most
|
// Timestamp gets the timestamp from a receiver report and returns as the most
|
||||||
// significant word, and the least significant word. If the given bytes do not
|
// significant word, and the least significant word. If the given bytes do not
|
||||||
// represent a valid receiver report, and error is returned.
|
// represent a valid receiver report, an error is returned.
|
||||||
func Timestamp(buf []byte) (msw, lsw uint32, err error) {
|
func Timestamp(buf []byte) (msw, lsw uint32, err error) {
|
||||||
// First check version of rtcp
|
|
||||||
if (buf[0] & 0xc0 >> 6) != 2 {
|
if (buf[0] & 0xc0 >> 6) != 2 {
|
||||||
return 0, 0, errors.New("incompatible RTCP version")
|
return 0, 0, errors.New("incompatible RTCP version")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check type of packet
|
|
||||||
if buf[1] != typeSenderReport {
|
if buf[1] != typeSenderReport {
|
||||||
return 0, 0, errors.New("rtcp packet is not of sender report type")
|
return 0, 0, errors.New("rtcp packet is not of sender report type")
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,18 +16,20 @@ const (
|
||||||
typeCName = 1
|
typeCName = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// MISC.
|
||||||
const (
|
const (
|
||||||
reportBlockSize = 6
|
reportBlockSize = 6
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ReceiverReport describes an RTCP receiver report packet.
|
||||||
type ReceiverReport struct {
|
type ReceiverReport struct {
|
||||||
Header
|
Header // Standard RTCP packet header.
|
||||||
|
SenderSSRC uint32 // SSRC of the sender of this report.
|
||||||
SenderSSRC uint32
|
Blocks []ReportBlock // Report blocks.
|
||||||
Blocks []ReportBlock
|
Extensions [][4]byte // Contains any extensions to the packet.
|
||||||
Extensions [][4]byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bytes returns a []byte of the ReceiverReport r.
|
||||||
func (r *ReceiverReport) Bytes() []byte {
|
func (r *ReceiverReport) Bytes() []byte {
|
||||||
l := 8 + 4*reportBlockSize*len(r.Blocks) + 4*len(r.Extensions)
|
l := 8 + 4*reportBlockSize*len(r.Blocks) + 4*len(r.Extensions)
|
||||||
buf := make([]byte, l)
|
buf := make([]byte, l)
|
||||||
|
@ -61,6 +63,7 @@ func (r *ReceiverReport) Bytes() []byte {
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReportBlock describes an RTCP report block used in Sender/Receiver Reports.
|
||||||
type ReportBlock struct {
|
type ReportBlock struct {
|
||||||
SSRC uint32 // Source identifier.
|
SSRC uint32 // Source identifier.
|
||||||
FractionLost uint8 // Fraction of packets lost.
|
FractionLost uint8 // Fraction of packets lost.
|
||||||
|
@ -71,12 +74,13 @@ type ReportBlock struct {
|
||||||
DLSR uint32 // Delay since last sender report.
|
DLSR uint32 // Delay since last sender report.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SourceDescription describes a source description RTCP packet.
|
||||||
type SourceDescription struct {
|
type SourceDescription struct {
|
||||||
Header
|
Header // Standard RTCP packet header.
|
||||||
|
Chunks []Chunk // Chunks to describe items of each SSRC.
|
||||||
Chunks []Chunk
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bytes returns an []byte of the SourceDescription d.
|
||||||
func (d *SourceDescription) Bytes() []byte {
|
func (d *SourceDescription) Bytes() []byte {
|
||||||
bodyLen := d.bodyLen()
|
bodyLen := d.bodyLen()
|
||||||
rem := bodyLen % 4
|
rem := bodyLen % 4
|
||||||
|
@ -102,6 +106,7 @@ func (d *SourceDescription) Bytes() []byte {
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bodyLen calculates the body length of a source description packet in bytes.
|
||||||
func (d *SourceDescription) bodyLen() int {
|
func (d *SourceDescription) bodyLen() int {
|
||||||
l := 0
|
l := 0
|
||||||
for _, c := range d.Chunks {
|
for _, c := range d.Chunks {
|
||||||
|
@ -110,6 +115,7 @@ func (d *SourceDescription) bodyLen() int {
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Header describes a standard RTCP packet header.
|
||||||
type Header struct {
|
type Header struct {
|
||||||
Version uint8 // RTCP version.
|
Version uint8 // RTCP version.
|
||||||
Padding bool // Padding indicator.
|
Padding bool // Padding indicator.
|
||||||
|
@ -117,16 +123,19 @@ type Header struct {
|
||||||
Type uint8 // Type of RTCP packet.
|
Type uint8 // Type of RTCP packet.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SDESItem describes a source description item.
|
||||||
type SDESItem struct {
|
type SDESItem struct {
|
||||||
Type uint8
|
Type uint8 // Type of item.
|
||||||
Text []byte
|
Text []byte // Item text.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Chunk describes a source description chunk for a given SSRC.
|
||||||
type Chunk struct {
|
type Chunk struct {
|
||||||
SSRC uint32
|
SSRC uint32 // SSRC of the source being described by the below items.
|
||||||
Items []SDESItem
|
Items []SDESItem // Items describing the source.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// len returns the len of a chunk in bytes.
|
||||||
func (c *Chunk) len() int {
|
func (c *Chunk) len() int {
|
||||||
tot := 4
|
tot := 4
|
||||||
for _, i := range c.Items {
|
for _, i := range c.Items {
|
||||||
|
@ -135,6 +144,8 @@ func (c *Chunk) len() int {
|
||||||
return tot
|
return tot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// writeHeader writes the standard RTCP header given a buffer to write to and l
|
||||||
|
// the RTCP body length that needs to be encoded into the header.
|
||||||
func (h Header) writeHeader(buf []byte, l int) {
|
func (h Header) writeHeader(buf []byte, l int) {
|
||||||
buf[0] = h.Version<<6 | asByte(h.Padding)<<5 | 0x1f&h.ReportCount
|
buf[0] = h.Version<<6 | asByte(h.Padding)<<5 | 0x1f&h.ReportCount
|
||||||
buf[1] = h.Type
|
buf[1] = h.Type
|
||||||
|
|
|
@ -6,6 +6,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TestReceiverReportBytes checks that we can correctly obtain a []byte of an
|
||||||
|
// RTCP receiver report from the struct representation.
|
||||||
func TestReceiverReportBytes(t *testing.T) {
|
func TestReceiverReportBytes(t *testing.T) {
|
||||||
expect := []byte{
|
expect := []byte{
|
||||||
0x81, 0xc9, 0x00, 0x07,
|
0x81, 0xc9, 0x00, 0x07,
|
||||||
|
@ -48,6 +50,8 @@ func TestReceiverReportBytes(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestSourceDescriptionBytes checks that we can correctly obtain a []byte of an
|
||||||
|
// RTCP source description from the struct representation.
|
||||||
func TestSourceDescriptionBytes(t *testing.T) {
|
func TestSourceDescriptionBytes(t *testing.T) {
|
||||||
expect := []byte{
|
expect := []byte{
|
||||||
0x81, 0xca, 0x00, 0x04,
|
0x81, 0xca, 0x00, 0x04,
|
||||||
|
|
Loading…
Reference in New Issue