diff --git a/protocol/rtcp/client.go b/protocol/rtcp/client.go index 534636cd..0e083d94 100644 --- a/protocol/rtcp/client.go +++ b/protocol/rtcp/client.go @@ -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 -// 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. func (c *client) Start() { go c.listen() 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() { conn, err := net.ListenUDP("udp", c.cAddr) 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() { conn, err := net.DialUDP("udp", c.cAddr, c.sAddr) if err != nil { @@ -154,12 +154,15 @@ func (c *client) parse(buf []byte) { c.setSenderTs(msw, lsw) } +// UpdateSequence will allow updating of the highest sequence number received +// through an rtp stream. func (c *client) UpdateSequence(s uint32) { c.mu.Lock() c.sequence = s c.mu.Unlock() } +// highestSequence will return the highest sequence number received through rtp. func (c *client) highestSequence() uint32 { var s uint32 c.mu.Lock() @@ -168,10 +171,13 @@ func (c *client) highestSequence() uint32 { return s } +// jitter returns the interarrival jitter as described by RTCP specifications: +// https://tools.ietf.org/html/rfc3550 func (c *client) jitter() uint32 { return 0 } +// setSenderTs allows us to safely set the current sender report timestamp. func (c *client) setSenderTs(msw, lsw uint32) { c.mu.Lock() binary.BigEndian.PutUint32(c.senderTs[:], msw) @@ -179,6 +185,7 @@ func (c *client) setSenderTs(msw, lsw uint32) { c.mu.Unlock() } +// lastSenderTs returns the timestamp of the most recent sender report. func (c *client) lastSenderTs() uint32 { var ts uint32 c.mu.Lock() @@ -187,6 +194,8 @@ func (c *client) lastSenderTs() uint32 { 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 { var receiveTime time.Time c.mu.Lock() @@ -196,6 +205,7 @@ func (c *client) delay() uint32 { 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() { c.mu.Lock() c.receiveTime = time.Now() diff --git a/protocol/rtcp/client_test.go b/protocol/rtcp/client_test.go new file mode 100644 index 00000000..26b54307 --- /dev/null +++ b/protocol/rtcp/client_test.go @@ -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: + } +} diff --git a/protocol/rtcp/parse.go b/protocol/rtcp/parse.go index 9795bbf6..1a7b6541 100644 --- a/protocol/rtcp/parse.go +++ b/protocol/rtcp/parse.go @@ -7,14 +7,12 @@ import ( // 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 -// 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) { - // First check version of rtcp if (buf[0] & 0xc0 >> 6) != 2 { return 0, 0, errors.New("incompatible RTCP version") } - // Check type of packet if buf[1] != typeSenderReport { return 0, 0, errors.New("rtcp packet is not of sender report type") } diff --git a/protocol/rtcp/rtcp.go b/protocol/rtcp/rtcp.go index f1da3409..adb6eeb8 100644 --- a/protocol/rtcp/rtcp.go +++ b/protocol/rtcp/rtcp.go @@ -16,18 +16,20 @@ const ( typeCName = 1 ) +// MISC. const ( reportBlockSize = 6 ) +// ReceiverReport describes an RTCP receiver report packet. type ReceiverReport struct { - Header - - SenderSSRC uint32 - Blocks []ReportBlock - Extensions [][4]byte + Header // Standard RTCP packet header. + SenderSSRC uint32 // SSRC of the sender of this report. + Blocks []ReportBlock // Report blocks. + Extensions [][4]byte // Contains any extensions to the packet. } +// Bytes returns a []byte of the ReceiverReport r. func (r *ReceiverReport) Bytes() []byte { l := 8 + 4*reportBlockSize*len(r.Blocks) + 4*len(r.Extensions) buf := make([]byte, l) @@ -61,6 +63,7 @@ func (r *ReceiverReport) Bytes() []byte { return buf } +// ReportBlock describes an RTCP report block used in Sender/Receiver Reports. type ReportBlock struct { SSRC uint32 // Source identifier. FractionLost uint8 // Fraction of packets lost. @@ -71,12 +74,13 @@ type ReportBlock struct { DLSR uint32 // Delay since last sender report. } +// SourceDescription describes a source description RTCP packet. type SourceDescription struct { - Header - - Chunks []Chunk + Header // Standard RTCP packet header. + Chunks []Chunk // Chunks to describe items of each SSRC. } +// Bytes returns an []byte of the SourceDescription d. func (d *SourceDescription) Bytes() []byte { bodyLen := d.bodyLen() rem := bodyLen % 4 @@ -102,6 +106,7 @@ func (d *SourceDescription) Bytes() []byte { return buf } +// bodyLen calculates the body length of a source description packet in bytes. func (d *SourceDescription) bodyLen() int { l := 0 for _, c := range d.Chunks { @@ -110,6 +115,7 @@ func (d *SourceDescription) bodyLen() int { return l } +// Header describes a standard RTCP packet header. type Header struct { Version uint8 // RTCP version. Padding bool // Padding indicator. @@ -117,16 +123,19 @@ type Header struct { Type uint8 // Type of RTCP packet. } +// SDESItem describes a source description item. type SDESItem struct { - Type uint8 - Text []byte + Type uint8 // Type of item. + Text []byte // Item text. } +// Chunk describes a source description chunk for a given SSRC. type Chunk struct { - SSRC uint32 - Items []SDESItem + SSRC uint32 // SSRC of the source being described by the below items. + Items []SDESItem // Items describing the source. } +// len returns the len of a chunk in bytes. func (c *Chunk) len() int { tot := 4 for _, i := range c.Items { @@ -135,6 +144,8 @@ func (c *Chunk) len() int { 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) { buf[0] = h.Version<<6 | asByte(h.Padding)<<5 | 0x1f&h.ReportCount buf[1] = h.Type diff --git a/protocol/rtcp/rtcp_test.go b/protocol/rtcp/rtcp_test.go index bafa59eb..6c0220dc 100644 --- a/protocol/rtcp/rtcp_test.go +++ b/protocol/rtcp/rtcp_test.go @@ -6,6 +6,8 @@ import ( "testing" ) +// TestReceiverReportBytes checks that we can correctly obtain a []byte of an +// RTCP receiver report from the struct representation. func TestReceiverReportBytes(t *testing.T) { expect := []byte{ 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) { expect := []byte{ 0x81, 0xca, 0x00, 0x04,