1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
|
package rtpdump
import (
"bufio"
"errors"
"io"
"regexp"
"sync"
)
// Reader reads the RTPDump file format
type Reader struct {
readerMu sync.Mutex
reader io.Reader
}
// NewReader opens a new Reader and immediately reads the Header from the start
// of the input stream.
func NewReader(r io.Reader) (*Reader, Header, error) {
var hdr Header
bio := bufio.NewReader(r)
// Look ahead to see if there's a valid preamble
peek, err := bio.Peek(preambleLen)
if errors.Is(err, io.EOF) {
return nil, hdr, errMalformed
}
if err != nil {
return nil, hdr, err
}
// The file starts with #!rtpplay1.0 address/port\n
preambleRegexp := regexp.MustCompile(`#\!rtpplay1\.0 \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,5}\n`)
if !preambleRegexp.Match(peek) {
return nil, hdr, errMalformed
}
// consume the preamble
_, _, err = bio.ReadLine()
if errors.Is(err, io.EOF) {
return nil, hdr, errMalformed
}
if err != nil {
return nil, hdr, err
}
hBuf := make([]byte, headerLen)
_, err = io.ReadFull(bio, hBuf)
if errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF) {
return nil, hdr, errMalformed
}
if err != nil {
return nil, hdr, err
}
if err := hdr.Unmarshal(hBuf); err != nil {
return nil, hdr, err
}
return &Reader{
reader: bio,
}, hdr, nil
}
// Next returns the next Packet in the Reader input stream
func (r *Reader) Next() (Packet, error) {
r.readerMu.Lock()
defer r.readerMu.Unlock()
hBuf := make([]byte, pktHeaderLen)
_, err := io.ReadFull(r.reader, hBuf)
if errors.Is(err, io.ErrUnexpectedEOF) {
return Packet{}, errMalformed
}
if err != nil {
return Packet{}, err
}
var h packetHeader
if err = h.Unmarshal(hBuf); err != nil {
return Packet{}, err
}
if h.Length == 0 {
return Packet{}, errMalformed
}
payload := make([]byte, h.Length-pktHeaderLen)
_, err = io.ReadFull(r.reader, payload)
if errors.Is(err, io.ErrUnexpectedEOF) {
return Packet{}, errMalformed
}
if err != nil {
return Packet{}, err
}
return Packet{
Offset: h.offset(),
IsRTCP: h.PacketLength == 0,
Payload: payload,
}, nil
}
|