mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			120 lines
		
	
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			120 lines
		
	
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package rtcp
 | |
| 
 | |
| // Packet represents an RTCP packet, a protocol used for out-of-band statistics and control information for an RTP session
 | |
| type Packet interface {
 | |
| 	// DestinationSSRC returns an array of SSRC values that this packet refers to.
 | |
| 	DestinationSSRC() []uint32
 | |
| 
 | |
| 	Marshal() ([]byte, error)
 | |
| 	Unmarshal(rawPacket []byte) error
 | |
| }
 | |
| 
 | |
| // Unmarshal takes an entire udp datagram (which may consist of multiple RTCP packets) and
 | |
| // returns the unmarshaled packets it contains.
 | |
| //
 | |
| // If this is a reduced-size RTCP packet a feedback packet (Goodbye, SliceLossIndication, etc)
 | |
| // will be returned. Otherwise, the underlying type of the returned packet will be
 | |
| // CompoundPacket.
 | |
| func Unmarshal(rawData []byte) ([]Packet, error) {
 | |
| 	var packets []Packet
 | |
| 	for len(rawData) != 0 {
 | |
| 		p, processed, err := unmarshal(rawData)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 
 | |
| 		packets = append(packets, p)
 | |
| 		rawData = rawData[processed:]
 | |
| 	}
 | |
| 
 | |
| 	switch len(packets) {
 | |
| 	// Empty packet
 | |
| 	case 0:
 | |
| 		return nil, errInvalidHeader
 | |
| 	// Multiple Packets
 | |
| 	default:
 | |
| 		return packets, nil
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Marshal takes an array of Packets and serializes them to a single buffer
 | |
| func Marshal(packets []Packet) ([]byte, error) {
 | |
| 	out := make([]byte, 0)
 | |
| 	for _, p := range packets {
 | |
| 		data, err := p.Marshal()
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		out = append(out, data...)
 | |
| 	}
 | |
| 	return out, nil
 | |
| }
 | |
| 
 | |
| // unmarshal is a factory which pulls the first RTCP packet from a bytestream,
 | |
| // and returns it's parsed representation, and the amount of data that was processed.
 | |
| func unmarshal(rawData []byte) (packet Packet, bytesprocessed int, err error) {
 | |
| 	var h Header
 | |
| 
 | |
| 	err = h.Unmarshal(rawData)
 | |
| 	if err != nil {
 | |
| 		return nil, 0, err
 | |
| 	}
 | |
| 
 | |
| 	bytesprocessed = int(h.Length+1) * 4
 | |
| 	if bytesprocessed > len(rawData) {
 | |
| 		return nil, 0, errPacketTooShort
 | |
| 	}
 | |
| 	inPacket := rawData[:bytesprocessed]
 | |
| 
 | |
| 	switch h.Type {
 | |
| 	case TypeSenderReport:
 | |
| 		packet = new(SenderReport)
 | |
| 
 | |
| 	case TypeReceiverReport:
 | |
| 		packet = new(ReceiverReport)
 | |
| 
 | |
| 	case TypeSourceDescription:
 | |
| 		packet = new(SourceDescription)
 | |
| 
 | |
| 	case TypeGoodbye:
 | |
| 		packet = new(Goodbye)
 | |
| 
 | |
| 	case TypeTransportSpecificFeedback:
 | |
| 		switch h.Count {
 | |
| 		case FormatTLN:
 | |
| 			packet = new(TransportLayerNack)
 | |
| 		case FormatRRR:
 | |
| 			packet = new(RapidResynchronizationRequest)
 | |
| 		case FormatTCC:
 | |
| 			packet = new(TransportLayerCC)
 | |
| 		case FormatCCFB:
 | |
| 			packet = new(CCFeedbackReport)
 | |
| 		default:
 | |
| 			packet = new(RawPacket)
 | |
| 		}
 | |
| 
 | |
| 	case TypePayloadSpecificFeedback:
 | |
| 		switch h.Count {
 | |
| 		case FormatPLI:
 | |
| 			packet = new(PictureLossIndication)
 | |
| 		case FormatSLI:
 | |
| 			packet = new(SliceLossIndication)
 | |
| 		case FormatREMB:
 | |
| 			packet = new(ReceiverEstimatedMaximumBitrate)
 | |
| 		case FormatFIR:
 | |
| 			packet = new(FullIntraRequest)
 | |
| 		default:
 | |
| 			packet = new(RawPacket)
 | |
| 		}
 | |
| 
 | |
| 	case TypeExtendedReport:
 | |
| 		packet = new(ExtendedReport)
 | |
| 
 | |
| 	default:
 | |
| 		packet = new(RawPacket)
 | |
| 	}
 | |
| 
 | |
| 	err = packet.Unmarshal(inPacket)
 | |
| 
 | |
| 	return packet, bytesprocessed, err
 | |
| }
 |