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