streaming

Media streaming and broadcast systems in Go
Log | Files | Refs | README | LICENSE

session_test.go (3071B)


      1 package rtp
      2 
      3 import (
      4 	"errors"
      5 	"fmt"
      6 	"net"
      7 	"testing"
      8 	"time"
      9 )
     10 
     11 // fakePlayer is a basic RTP packet receiver which discards packet
     12 // payloads. It verifies the stream of packets by inspecting the packet header,
     13 // thought it requires packets are received in order.
     14 type fakePlayer struct {
     15 	conn       net.PacketConn
     16 	decoded    chan *Packet
     17 	clock      int
     18 	typ        PayloadType
     19 	syncSource uint32
     20 }
     21 
     22 func (fp *fakePlayer) render(ch chan error) {
     23 	var prev Packet
     24 	for p := range fp.decoded {
     25 		if prev.Payload == nil {
     26 			fp.typ = p.Header.Type
     27 			fp.syncSource = p.Header.SyncSource
     28 			prev = *p
     29 			continue
     30 		}
     31 		if p.Header.Version != VersionRFC3550 {
     32 			ch <- fmt.Errorf("bad version %d, want %d", p.Header.Version, VersionRFC3550)
     33 		}
     34 		if p.Header.Type != fp.typ {
     35 			ch <- fmt.Errorf("unexpected payload type %d, want %d", p.Header.Type, fp.typ)
     36 		}
     37 		if p.Header.Sequence != prev.Header.Sequence+1 {
     38 			ch <- fmt.Errorf("bad packet sequence: previous %d, current %d", prev.Header.Sequence, p.Header.Sequence)
     39 		}
     40 		// TODO(otl): check timestamp is expected based on fp.clock.
     41 		if p.Header.SyncSource != fp.syncSource {
     42 			ch <- fmt.Errorf("unexpected sync source %d, want %d", p.Header.SyncSource, fp.syncSource)
     43 		}
     44 		// TODO(otl): check payload is expected? non-nil?
     45 		prev = *p
     46 	}
     47 }
     48 
     49 func (fp *fakePlayer) receive(ch chan error) {
     50 	go fp.render(ch)
     51 	buf := make([]byte, 1492)
     52 	for {
     53 		if err := fp.conn.SetDeadline(time.Now().Add(2 * time.Second)); err != nil {
     54 			ch <- err
     55 		}
     56 		n, _, err := fp.conn.ReadFrom(buf)
     57 		if errors.Is(err, net.ErrClosed) {
     58 			break
     59 		} else if err != nil {
     60 			ch <- err
     61 			continue
     62 		}
     63 		var p Packet
     64 		if err := Unmarshal(buf[:n], &p); err != nil {
     65 			ch <- fmt.Errorf("unmarshal packet: %w", err)
     66 			continue
     67 		}
     68 		fp.decoded <- &p
     69 	}
     70 	close(fp.decoded)
     71 }
     72 
     73 func (fp *fakePlayer) stop() error {
     74 	return fp.conn.Close()
     75 }
     76 
     77 // textPackets returns a channel that sends count Packets through ch every dur...
     78 func textPackets(dur time.Duration, count int) chan Packet {
     79 	ch := make(chan Packet)
     80 	go func() {
     81 		typ := DynamicPayloadType()
     82 		ticker := time.NewTicker(dur)
     83 		var i int
     84 		for t := range ticker.C {
     85 			ch <- Packet{
     86 				Header{Type: typ},
     87 				[]byte(t.Format(time.RFC3339Nano)),
     88 			}
     89 			i++
     90 			if i == count {
     91 				ticker.Stop()
     92 				close(ch)
     93 				break
     94 			}
     95 		}
     96 	}()
     97 	return ch
     98 }
     99 
    100 func TestSession(t *testing.T) {
    101 	ln, err := net.ListenPacket("udp", "[::1]:0")
    102 	if err != nil {
    103 		t.Fatal(err)
    104 	}
    105 	player := fakePlayer{
    106 		conn:    ln,
    107 		decoded: make(chan *Packet),
    108 		clock:   ClockText,
    109 	}
    110 
    111 	errs := make(chan error)
    112 	go player.receive(errs)
    113 
    114 	session, err := Dial("udp", ln.LocalAddr().String())
    115 	if err != nil {
    116 		t.Fatal(err)
    117 	}
    118 	session.Clock = ClockText
    119 	pchan := textPackets(40*time.Millisecond, 25)
    120 	for {
    121 		select {
    122 		case err := <-errs:
    123 			t.Error(err)
    124 		case p, ok := <-pchan:
    125 			if !ok {
    126 				if err := player.stop(); err != nil {
    127 					t.Errorf("stop fake player: %v", err)
    128 				}
    129 				return
    130 			}
    131 			if err := session.Transmit(&p); err != nil {
    132 				t.Errorf("transmit: %v", err)
    133 				continue
    134 			}
    135 		}
    136 	}
    137 }