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  }