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