mirror of https://bitbucket.org/ausocean/av.git
protocol/rtcp: addressing PR feedback
This commit is contained in:
parent
d34eabcd34
commit
a8e56311c2
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
NAME
|
NAME
|
||||||
client.go
|
Client.go
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
client.go provides an implemntation of a basic RTCP client that will send
|
Client.go provides an implemntation of a basic RTCP Client that will send
|
||||||
receiver reports, and receive sender reports to parse relevant statistics.
|
receiver reports, and receive sender reports to parse relevant statistics.
|
||||||
|
|
||||||
AUTHORS
|
AUTHORS
|
||||||
|
@ -41,44 +41,45 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
senderSSRC = 3605043418
|
senderSSRC = 1 // Any non-zero value will do.
|
||||||
defaultClientName = "client"
|
defaultClientName = "Client"
|
||||||
delayUnit = 1.0 / 65536.0
|
delayUnit = 1.0 / 65536.0
|
||||||
pkg = "rtcp: "
|
pkg = "rtcp: "
|
||||||
rtcpVer = 2
|
rtcpVer = 2
|
||||||
|
receiverBufSize = 200
|
||||||
)
|
)
|
||||||
|
|
||||||
type log func(lvl int8, msg string, args ...interface{})
|
type log func(lvl int8, msg string, args ...interface{})
|
||||||
|
|
||||||
// client is an RTCP client that will hadle receiving SenderReports from a server
|
// Client is an RTCP Client that will handle receiving SenderReports from a server
|
||||||
// and sending out ReceiverReports.
|
// and sending out ReceiverReports.
|
||||||
type client struct {
|
type Client struct {
|
||||||
ErrChan chan error
|
ErrChan chan error // Client will send any errors through this chan.
|
||||||
|
|
||||||
cAddr *net.UDPAddr
|
cAddr *net.UDPAddr // Address of client.
|
||||||
sAddr *net.UDPAddr
|
sAddr *net.UDPAddr // Address of RTSP server.
|
||||||
name string
|
name string // Name of the client for source description purposes.
|
||||||
sourceSSRC uint32
|
sourceSSRC uint32 // Source identifier of this client.
|
||||||
mu sync.Mutex
|
mu sync.Mutex // Will be used to change parameters during operation safely.
|
||||||
sequence uint32
|
sequence uint32 // Last RTP sequence number.
|
||||||
senderTs [64]byte
|
senderTs [8]byte // The timestamp of the last sender report.
|
||||||
interval time.Duration
|
interval time.Duration // Interval between sender report and receiver report.
|
||||||
receiveTime time.Time
|
receiveTime time.Time // Time last sender report was received.
|
||||||
buf [200]byte
|
buf [receiverBufSize]byte // Buf used to store the receiver report and source descriptions.
|
||||||
conn *net.UDPConn
|
conn *net.UDPConn // The UDP connection used for receiving and sending RTSP packets.
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup // This is used to wait for send and recv routines to stop when Client is stopped.
|
||||||
quitSend chan struct{}
|
quitSend chan struct{} // Channel used to communicate quit signal to send routine.
|
||||||
quitRecv chan struct{}
|
quitRecv chan struct{} // Channel used to communicate quit signal to recv routine.
|
||||||
log
|
log // Used to log any messages.
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient returns a pointer to a new client.
|
// NewClient returns a pointer to a new Client.
|
||||||
func NewClient(clientAddress, serverAddress, name string, sendInterval time.Duration, rtpSSRC uint32, l log) (*client, error) {
|
func NewClient(clientAddress, serverAddress, name string, sendInterval time.Duration, rtpSSRC uint32, l log) (*Client, error) {
|
||||||
if name == "" {
|
if name == "" {
|
||||||
name = defaultClientName
|
name = defaultClientName
|
||||||
}
|
}
|
||||||
|
|
||||||
c := &client{
|
c := &Client{
|
||||||
name: name,
|
name: name,
|
||||||
ErrChan: make(chan error, 2),
|
ErrChan: make(chan error, 2),
|
||||||
quitSend: make(chan struct{}),
|
quitSend: make(chan struct{}),
|
||||||
|
@ -91,7 +92,7 @@ func NewClient(clientAddress, serverAddress, name string, sendInterval time.Dura
|
||||||
var err error
|
var err error
|
||||||
c.cAddr, err = net.ResolveUDPAddr("udp", clientAddress)
|
c.cAddr, err = net.ResolveUDPAddr("udp", clientAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New(fmt.Sprintf("can't resolve client address, failed with error: %v\n", err))
|
return nil, errors.New(fmt.Sprintf("can't resolve Client address, failed with error: %v\n", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
c.sAddr, err = net.ResolveUDPAddr("udp", serverAddress)
|
c.sAddr, err = net.ResolveUDPAddr("udp", serverAddress)
|
||||||
|
@ -109,18 +110,17 @@ 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 sender reports, 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() {
|
||||||
c.log(logger.Debug, pkg+"client is starting")
|
c.log(logger.Debug, pkg+"Client is starting")
|
||||||
c.wg.Add(1)
|
c.wg.Add(2)
|
||||||
go c.recv()
|
go c.recv()
|
||||||
c.wg.Add(1)
|
|
||||||
go c.send()
|
go c.send()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop sends a quit signal to the send and receive routines and closes the
|
// Stop sends a quit signal to the send and receive routines and closes the
|
||||||
// UDP connection. It will wait until both routines have returned.
|
// UDP connection. It will wait until both routines have returned.
|
||||||
func (c *client) Stop() {
|
func (c *Client) Stop() {
|
||||||
c.log(logger.Debug, pkg+"client is stopping")
|
c.log(logger.Debug, pkg+"Client is stopping")
|
||||||
close(c.quitSend)
|
close(c.quitSend)
|
||||||
close(c.quitRecv)
|
close(c.quitRecv)
|
||||||
c.conn.Close()
|
c.conn.Close()
|
||||||
|
@ -128,9 +128,9 @@ func (c *client) Stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// recv reads from the UDP connection and parses SenderReports.
|
// recv reads from the UDP connection and parses SenderReports.
|
||||||
func (c *client) recv() {
|
func (c *Client) recv() {
|
||||||
defer c.wg.Done()
|
defer c.wg.Done()
|
||||||
c.log(logger.Debug, pkg+"client is receiving")
|
c.log(logger.Debug, pkg+"Client is receiving")
|
||||||
buf := make([]byte, 4096)
|
buf := make([]byte, 4096)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
@ -149,9 +149,9 @@ func (c *client) recv() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// send writes receiver reports to the server.
|
// send writes receiver reports to the server.
|
||||||
func (c *client) send() {
|
func (c *Client) send() {
|
||||||
defer c.wg.Done()
|
defer c.wg.Done()
|
||||||
c.log(logger.Debug, pkg+"client is sending")
|
c.log(logger.Debug, pkg+"Client is sending")
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-c.quitSend:
|
case <-c.quitSend:
|
||||||
|
@ -211,38 +211,45 @@ func (c *client) send() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// formPayload takes a pointer to a ReceiverReport and a pointer to a
|
// formPayload takes a pointer to a ReceiverReport and a pointer to a
|
||||||
// Source Description and calls Bytes on both, writing to the underlying client
|
// Source Description and calls Bytes on both, writing to the underlying Client
|
||||||
// buf. A slice to the combined writtem memory is returned.
|
// buf. A slice to the combined writtem memory is returned.
|
||||||
func (c *client) formPayload(r *ReceiverReport, d *SourceDescription) []byte {
|
func (c *Client) formPayload(r *ReceiverReport, d *SourceDescription) []byte {
|
||||||
rl := len(r.Bytes(c.buf[:]))
|
rl := len(r.Bytes(c.buf[:]))
|
||||||
dl := len(d.Bytes(c.buf[rl:]))
|
dl := len(d.Bytes(c.buf[rl:]))
|
||||||
t := rl + dl
|
t := rl + dl
|
||||||
if t > cap(c.buf) {
|
if t > cap(c.buf) {
|
||||||
panic("client buf not big enough")
|
panic("Client buf not big enough")
|
||||||
}
|
}
|
||||||
return c.buf[:t]
|
return c.buf[:t]
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse will read important statistics from sender reports.
|
// parse will read important statistics from sender reports.
|
||||||
func (c *client) parse(buf []byte) {
|
func (c *Client) parse(buf []byte) {
|
||||||
c.received()
|
c.markReceivedTime()
|
||||||
msw, lsw, err := Timestamp(buf)
|
msw, lsw, err := Timestamp(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ErrChan <- errors.New(fmt.Sprintf("could not get timestamp from sender report, failed with error: %v", err))
|
c.ErrChan <- errors.New(fmt.Sprintf("could not get timestamp from sender report, failed with error: %v", err))
|
||||||
}
|
}
|
||||||
c.setSenderTs(msw, lsw)
|
c.setSenderTs(
|
||||||
|
struct {
|
||||||
|
msw uint32
|
||||||
|
lsw uint32
|
||||||
|
}{
|
||||||
|
msw,
|
||||||
|
lsw,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateSequence will allow updating of the highest sequence number received
|
// SetSequence will allow updating of the highest sequence number received
|
||||||
// through an RTP stream.
|
// through an RTP stream.
|
||||||
func (c *client) UpdateSequence(s uint32) {
|
func (c *Client) SetSequence(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.
|
// highestSequence will return the highest sequence number received through RTP.
|
||||||
func (c *client) highestSequence() uint32 {
|
func (c *Client) highestSequence() uint32 {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
s := c.sequence
|
s := c.sequence
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
|
@ -251,20 +258,20 @@ func (c *client) highestSequence() uint32 {
|
||||||
|
|
||||||
// jitter returns the interarrival jitter as described by RTCP specifications:
|
// jitter returns the interarrival jitter as described by RTCP specifications:
|
||||||
// https://tools.ietf.org/html/rfc3550
|
// 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.
|
// setSenderTs allows us to safely set the current sender report timestamp.
|
||||||
func (c *client) setSenderTs(msw, lsw uint32) {
|
func (c *Client) setSenderTs(t struct{ msw, lsw uint32 }) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
binary.BigEndian.PutUint32(c.senderTs[:], msw)
|
binary.BigEndian.PutUint32(c.senderTs[:], t.msw)
|
||||||
binary.BigEndian.PutUint32(c.senderTs[4:], lsw)
|
binary.BigEndian.PutUint32(c.senderTs[4:], t.lsw)
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// lastSenderTs returns the timestamp of the most recent sender report.
|
// lastSenderTs returns the timestamp of the most recent sender report.
|
||||||
func (c *client) lastSenderTs() uint32 {
|
func (c *Client) lastSenderTs() uint32 {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
t := binary.BigEndian.Uint32(c.senderTs[2:])
|
t := binary.BigEndian.Uint32(c.senderTs[2:])
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
|
@ -273,7 +280,7 @@ func (c *client) lastSenderTs() uint32 {
|
||||||
|
|
||||||
// delay returns the duration between the receive time of the last sender report
|
// delay returns the duration between the receive time of the last sender report
|
||||||
// and now. This is called when forming a receiver report.
|
// and now. This is called when forming a receiver report.
|
||||||
func (c *client) delay() uint32 {
|
func (c *Client) delay() uint32 {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
t := c.receiveTime
|
t := c.receiveTime
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
|
@ -281,7 +288,7 @@ func (c *client) delay() uint32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// received is called when a sender report is received to mark the receive time.
|
// received is called when a sender report is received to mark the receive time.
|
||||||
func (c *client) received() {
|
func (c *Client) markReceivedTime() {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
c.receiveTime = time.Now()
|
c.receiveTime = time.Now()
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
|
|
|
@ -101,7 +101,7 @@ func TestFormPayload(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
c := &client{}
|
c := &Client{}
|
||||||
p := c.formPayload(&report, &description)
|
p := c.formPayload(&report, &description)
|
||||||
|
|
||||||
if !bytes.Equal(p, expect) {
|
if !bytes.Equal(p, expect) {
|
||||||
|
@ -197,7 +197,7 @@ func TestReceiveAndSend(t *testing.T) {
|
||||||
n, _, _ := conn.ReadFromUDP(buf)
|
n, _, _ := conn.ReadFromUDP(buf)
|
||||||
t.Logf("SERVER: receiver report received: \n%v\n", buf[:n])
|
t.Logf("SERVER: receiver report received: \n%v\n", buf[:n])
|
||||||
|
|
||||||
c.UpdateSequence(uint32(i))
|
c.SetSequence(uint32(i))
|
||||||
|
|
||||||
now := time.Now().Second()
|
now := time.Now().Second()
|
||||||
var time [8]byte
|
var time [8]byte
|
||||||
|
|
|
@ -138,7 +138,7 @@ func (d *SourceDescription) Bytes(buf []byte) []byte {
|
||||||
|
|
||||||
// bodyLen calculates the body length of a source description packet in bytes.
|
// bodyLen calculates the body length of a source description packet in bytes.
|
||||||
func (d *SourceDescription) bodyLen() int {
|
func (d *SourceDescription) bodyLen() int {
|
||||||
l := 0
|
var l int
|
||||||
for _, c := range d.Chunks {
|
for _, c := range d.Chunks {
|
||||||
l += c.len()
|
l += c.len()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue