mirror of
				https://github.com/pion/webrtc.git
				synced 2025-10-31 10:46:39 +08:00 
			
		
		
		
	| @@ -33,6 +33,13 @@ type Header struct { | ||||
| 	Length uint16 | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	errInvalidVersion     = errors.New("invalid version") | ||||
| 	errInvalidReportCount = errors.New("invalid report count") | ||||
| 	errInvalidTotalLost   = errors.New("invalid total lost count") | ||||
| 	errPacketTooShort     = errors.New("packet too short") | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	headerLength     = 4 | ||||
| 	versionShift     = 6 | ||||
| @@ -43,12 +50,6 @@ const ( | ||||
| 	reportCountMask  = 0x1f | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	errInvalidVersion     = errors.New("invalid version") | ||||
| 	errInvalidReportCount = errors.New("invalid report count") | ||||
| 	errHeaderTooShort     = errors.New("rtcp header too short") | ||||
| ) | ||||
| 
 | ||||
| // Marshal encodes the Header in binary | ||||
| func (h Header) Marshal() ([]byte, error) { | ||||
| 	/* | ||||
| @@ -84,7 +85,7 @@ func (h Header) Marshal() ([]byte, error) { | ||||
| // Unmarshal decodes the Header from binary | ||||
| func (h *Header) Unmarshal(rawPacket []byte) error { | ||||
| 	if len(rawPacket) < headerLength { | ||||
| 		return errHeaderTooShort | ||||
| 		return errPacketTooShort | ||||
| 	} | ||||
| 
 | ||||
| 	/* | ||||
| @@ -33,8 +33,8 @@ func TestHeaderUnmarshal(t *testing.T) { | ||||
| func TestHeaderUnmarshalNil(t *testing.T) { | ||||
| 	var header Header | ||||
| 	err := header.Unmarshal(nil) | ||||
| 	if got, want := err, errHeaderTooShort; got != want { | ||||
| 		t.Errorf("unmarshal nil header: err = %v, want %v", got, want) | ||||
| 	if got, want := err, errPacketTooShort; got != want { | ||||
| 		t.Fatalf("unmarshal nil header: err = %v, want %v", got, want) | ||||
| 	} | ||||
| } | ||||
| func TestHeaderRoundTrip(t *testing.T) { | ||||
							
								
								
									
										50
									
								
								pkg/rtcp/receiver_report.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								pkg/rtcp/receiver_report.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| package rtcp | ||||
|  | ||||
| import "encoding/binary" | ||||
|  | ||||
| // A ReceiverReport (RR) packet provides reception quality feedback for an RTP stream | ||||
| type ReceiverReport struct { | ||||
| 	// The synchronization source identifier for the originator of this RR packet. | ||||
| 	SSRC uint32 | ||||
| 	// Zero or more reception report blocks depending on the number of other | ||||
| 	// sources heard by this sender since the last report. Each reception report | ||||
| 	// block conveys statistics on the reception of RTP packets from a | ||||
| 	// single synchronization source. | ||||
| 	Reports []ReceptionReport | ||||
| } | ||||
|  | ||||
| // Marshal encodes the ReceiverReport in binary | ||||
| func (r ReceiverReport) Marshal() ([]byte, error) { | ||||
| 	rawPacket := make([]byte, 4) | ||||
|  | ||||
| 	binary.BigEndian.PutUint32(rawPacket, r.SSRC) | ||||
|  | ||||
| 	for _, rp := range r.Reports { | ||||
| 		data, err := rp.Marshal() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		rawPacket = append(rawPacket, data...) | ||||
| 	} | ||||
|  | ||||
| 	return rawPacket, nil | ||||
| } | ||||
|  | ||||
| // Unmarshal decodes the ReceiverReport from binary | ||||
| func (r *ReceiverReport) Unmarshal(rawPacket []byte) error { | ||||
| 	if len(rawPacket) < 4 { | ||||
| 		return errPacketTooShort | ||||
| 	} | ||||
|  | ||||
| 	r.SSRC = binary.BigEndian.Uint32(rawPacket) | ||||
|  | ||||
| 	for i := 4; i < len(rawPacket); i += receptionReportLength { | ||||
| 		var rr ReceptionReport | ||||
| 		if err := rr.Unmarshal(rawPacket[i:]); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		r.Reports = append(r.Reports, rr) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										87
									
								
								pkg/rtcp/receiver_report_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								pkg/rtcp/receiver_report_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| package rtcp | ||||
|  | ||||
| import ( | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestReceiverReportUnmarshalNil(t *testing.T) { | ||||
| 	var rr ReceiverReport | ||||
| 	err := rr.Unmarshal(nil) | ||||
| 	if got, want := err, errPacketTooShort; got != want { | ||||
| 		t.Fatalf("unmarshal nil rr: err = %v, want %v", got, want) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestReceiverReportRoundTrip(t *testing.T) { | ||||
| 	for _, test := range []struct { | ||||
| 		Name      string | ||||
| 		Report    ReceiverReport | ||||
| 		WantError error | ||||
| 	}{ | ||||
| 		{ | ||||
| 			Name: "valid", | ||||
| 			Report: ReceiverReport{ | ||||
| 				SSRC: 1, | ||||
| 				Reports: []ReceptionReport{ | ||||
| 					{ | ||||
| 						SSRC:         2, | ||||
| 						FractionLost: 2, | ||||
| 						TotalLost:    3, | ||||
| 						LastSeq:      4, | ||||
| 						Jitter:       5, | ||||
| 						LastSR:       6, | ||||
| 						Delay:        7, | ||||
| 					}, | ||||
| 					{ | ||||
| 						SSRC: 0, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name: "also valid", | ||||
| 			Report: ReceiverReport{ | ||||
| 				SSRC: 2, | ||||
| 				Reports: []ReceptionReport{ | ||||
| 					{ | ||||
| 						SSRC:         999, | ||||
| 						FractionLost: 30, | ||||
| 						TotalLost:    12345, | ||||
| 						LastSeq:      99, | ||||
| 						Jitter:       22, | ||||
| 						LastSR:       92, | ||||
| 						Delay:        46, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name: "totallost overflow", | ||||
| 			Report: ReceiverReport{ | ||||
| 				SSRC: 1, | ||||
| 				Reports: []ReceptionReport{{ | ||||
| 					TotalLost: 1 << 25, | ||||
| 				}}, | ||||
| 			}, | ||||
| 			WantError: errInvalidTotalLost, | ||||
| 		}, | ||||
| 	} { | ||||
| 		data, err := test.Report.Marshal() | ||||
| 		if got, want := err, test.WantError; got != want { | ||||
| 			t.Fatalf("Marshal %q: err = %v, want %v", test.Name, got, want) | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		var decoded ReceiverReport | ||||
| 		if err := decoded.Unmarshal(data); err != nil { | ||||
| 			t.Fatalf("Unmarshal %q: %v", test.Name, err) | ||||
| 		} | ||||
|  | ||||
| 		if got, want := decoded, test.Report; !reflect.DeepEqual(got, want) { | ||||
| 			t.Fatalf("%q rr round trip: got %#v, want %#v", test.Name, got, want) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										126
									
								
								pkg/rtcp/reception_report.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								pkg/rtcp/reception_report.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | ||||
| package rtcp | ||||
|  | ||||
| import "encoding/binary" | ||||
|  | ||||
| // A ReceptionReport block conveys statistics on the reception of RTP packets | ||||
| // from a single synchronization source. | ||||
| type ReceptionReport struct { | ||||
| 	// The SSRC identifier of the source to which the information in this | ||||
| 	// reception report block pertains. | ||||
| 	SSRC uint32 | ||||
| 	// The fraction of RTP data packets from source SSRC lost since the | ||||
| 	// previous SR or RR packet was sent, expressed as a fixed point | ||||
| 	// number with the binary point at the left edge of the field. | ||||
| 	FractionLost uint8 | ||||
| 	// The total number of RTP data packets from source SSRC that have | ||||
| 	// been lost since the beginning of reception. | ||||
| 	TotalLost uint32 | ||||
| 	// The low 16 bits contain the highest sequence number received in an | ||||
| 	// RTP data packet from source SSRC, and the most significant 16 | ||||
| 	// bits extend that sequence number with the corresponding count of | ||||
| 	// sequence number cycles. | ||||
| 	LastSeq uint32 | ||||
| 	// An estimate of the statistical variance of the RTP data packet | ||||
| 	// interarrival time, measured in timestamp units and expressed as an | ||||
| 	// unsigned integer. | ||||
| 	Jitter uint32 | ||||
| 	// The middle 32 bits out of 64 in the NTP timestamp received as part of | ||||
| 	// the most recent RTCP sender report (SR) packet from source SSRC. If no | ||||
| 	// SR has been received yet, the field is set to zero. | ||||
| 	LastSR uint32 | ||||
| 	// The delay, expressed in units of 1/65536 seconds, between receiving the | ||||
| 	// last SR packet from source SSRC and sending this reception report block. | ||||
| 	// If no SR packet has been received yet from SSRC, the field is set to zero. | ||||
| 	Delay uint32 | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	receptionReportLength = 24 | ||||
| 	fractionLostOffset    = 4 | ||||
| 	totalLostOffset       = 5 | ||||
| 	lastSeqOffset         = 8 | ||||
| 	jitterOffset          = 12 | ||||
| 	lastSROffset          = 16 | ||||
| 	delayOffset           = 20 | ||||
| ) | ||||
|  | ||||
| // Marshal encodes the ReceptionReport in binary | ||||
| func (r ReceptionReport) Marshal() ([]byte, error) { | ||||
| 	/* | ||||
| 	 *  0                   1                   2                   3 | ||||
| 	 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | ||||
| 	 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | ||||
| 	 * |                              SSRC                             | | ||||
| 	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||||
| 	 * | fraction lost |       cumulative number of packets lost       | | ||||
| 	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||||
| 	 * |           extended highest sequence number received           | | ||||
| 	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||||
| 	 * |                      interarrival jitter                      | | ||||
| 	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||||
| 	 * |                         last SR (LSR)                         | | ||||
| 	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||||
| 	 * |                   delay since last SR (DLSR)                  | | ||||
| 	 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | ||||
| 	 */ | ||||
|  | ||||
| 	rawPacket := make([]byte, receptionReportLength) | ||||
|  | ||||
| 	binary.BigEndian.PutUint32(rawPacket, r.SSRC) | ||||
|  | ||||
| 	rawPacket[fractionLostOffset] = r.FractionLost | ||||
|  | ||||
| 	// pack TotalLost into 24 bits | ||||
| 	if r.TotalLost >= (1 << 25) { | ||||
| 		return nil, errInvalidTotalLost | ||||
| 	} | ||||
| 	tlBytes := rawPacket[totalLostOffset:] | ||||
| 	tlBytes[0] = byte(r.TotalLost >> 16) | ||||
| 	tlBytes[1] = byte(r.TotalLost >> 8) | ||||
| 	tlBytes[2] = byte(r.TotalLost) | ||||
|  | ||||
| 	binary.BigEndian.PutUint32(rawPacket[lastSeqOffset:], r.LastSeq) | ||||
| 	binary.BigEndian.PutUint32(rawPacket[jitterOffset:], r.Jitter) | ||||
| 	binary.BigEndian.PutUint32(rawPacket[lastSROffset:], r.LastSR) | ||||
| 	binary.BigEndian.PutUint32(rawPacket[delayOffset:], r.Delay) | ||||
|  | ||||
| 	return rawPacket, nil | ||||
| } | ||||
|  | ||||
| // Unmarshal decodes the ReceptionReport from binary | ||||
| func (r *ReceptionReport) Unmarshal(rawPacket []byte) error { | ||||
| 	if len(rawPacket) < receptionReportLength { | ||||
| 		return errPacketTooShort | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 *  0                   1                   2                   3 | ||||
| 	 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | ||||
| 	 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | ||||
| 	 * |                              SSRC                             | | ||||
| 	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||||
| 	 * | fraction lost |       cumulative number of packets lost       | | ||||
| 	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||||
| 	 * |           extended highest sequence number received           | | ||||
| 	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||||
| 	 * |                      interarrival jitter                      | | ||||
| 	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||||
| 	 * |                         last SR (LSR)                         | | ||||
| 	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||||
| 	 * |                   delay since last SR (DLSR)                  | | ||||
| 	 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | ||||
| 	 */ | ||||
|  | ||||
| 	r.SSRC = binary.BigEndian.Uint32(rawPacket) | ||||
| 	r.FractionLost = rawPacket[fractionLostOffset] | ||||
|  | ||||
| 	tlBytes := rawPacket[totalLostOffset:] | ||||
| 	r.TotalLost = uint32(tlBytes[2]) | uint32(tlBytes[1])<<8 | uint32(tlBytes[0])<<16 | ||||
|  | ||||
| 	r.LastSeq = binary.BigEndian.Uint32(rawPacket[lastSeqOffset:]) | ||||
| 	r.Jitter = binary.BigEndian.Uint32(rawPacket[jitterOffset:]) | ||||
| 	r.LastSR = binary.BigEndian.Uint32(rawPacket[lastSROffset:]) | ||||
| 	r.Delay = binary.BigEndian.Uint32(rawPacket[delayOffset:]) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										86
									
								
								pkg/rtcp/sender_report.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								pkg/rtcp/sender_report.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| package rtcp | ||||
|  | ||||
| import "encoding/binary" | ||||
|  | ||||
| // A SenderReport (SR) packet provides reception quality feedback for an RTP stream | ||||
| type SenderReport struct { | ||||
| 	// The synchronization source identifier for the originator of this SR packet. | ||||
| 	SSRC uint32 | ||||
| 	// The wallclock time when this report was sent so that it may be used in | ||||
| 	// combination with timestamps returned in reception reports from other | ||||
| 	// receivers to measure round-trip propagation to those receivers. | ||||
| 	NTPTime uint64 | ||||
| 	// Corresponds to the same time as the NTP timestamp (above), but in | ||||
| 	// the same units and with the same random offset as the RTP | ||||
| 	// timestamps in data packets. This correspondence may be used for | ||||
| 	// intra- and inter-media synchronization for sources whose NTP | ||||
| 	// timestamps are synchronized, and may be used by media-independent | ||||
| 	// receivers to estimate the nominal RTP clock frequency. | ||||
| 	RTPTime uint32 | ||||
| 	// The total number of RTP data packets transmitted by the sender | ||||
| 	// since starting transmission up until the time this SR packet was | ||||
| 	// generated. | ||||
| 	PacketCount uint32 | ||||
| 	// The total number of payload octets (i.e., not including header or | ||||
| 	// padding) transmitted in RTP data packets by the sender since | ||||
| 	// starting transmission up until the time this SR packet was | ||||
| 	// generated. | ||||
| 	OctetCount uint32 | ||||
| 	// Zero or more reception report blocks depending on the number of other | ||||
| 	// sources heard by this sender since the last report. Each reception report | ||||
| 	// block conveys statistics on the reception of RTP packets from a | ||||
| 	// single synchronization source. | ||||
| 	Reports []ReceptionReport | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	senderReportLength = 24 | ||||
| 	ntpTimeOffset      = 4 | ||||
| 	rtpTimeOffset      = 12 | ||||
| 	packetCountOffset  = 16 | ||||
| 	octetCountOffset   = 20 | ||||
| ) | ||||
|  | ||||
| // Marshal encodes the SenderReport in binary | ||||
| func (r SenderReport) Marshal() ([]byte, error) { | ||||
| 	rawPacket := make([]byte, senderReportLength) | ||||
|  | ||||
| 	binary.BigEndian.PutUint32(rawPacket, r.SSRC) | ||||
| 	binary.BigEndian.PutUint64(rawPacket[ntpTimeOffset:], r.NTPTime) | ||||
| 	binary.BigEndian.PutUint32(rawPacket[rtpTimeOffset:], r.RTPTime) | ||||
| 	binary.BigEndian.PutUint32(rawPacket[packetCountOffset:], r.PacketCount) | ||||
| 	binary.BigEndian.PutUint32(rawPacket[octetCountOffset:], r.OctetCount) | ||||
|  | ||||
| 	for _, rp := range r.Reports { | ||||
| 		data, err := rp.Marshal() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		rawPacket = append(rawPacket, data...) | ||||
| 	} | ||||
|  | ||||
| 	return rawPacket, nil | ||||
| } | ||||
|  | ||||
| // Unmarshal decodes the SenderReport from binary | ||||
| func (r *SenderReport) Unmarshal(rawPacket []byte) error { | ||||
| 	if len(rawPacket) < senderReportLength { | ||||
| 		return errPacketTooShort | ||||
| 	} | ||||
|  | ||||
| 	r.SSRC = binary.BigEndian.Uint32(rawPacket) | ||||
| 	r.NTPTime = binary.BigEndian.Uint64(rawPacket[ntpTimeOffset:]) | ||||
| 	r.RTPTime = binary.BigEndian.Uint32(rawPacket[rtpTimeOffset:]) | ||||
| 	r.PacketCount = binary.BigEndian.Uint32(rawPacket[packetCountOffset:]) | ||||
| 	r.OctetCount = binary.BigEndian.Uint32(rawPacket[octetCountOffset:]) | ||||
|  | ||||
| 	for i := senderReportLength; i < len(rawPacket); i += receptionReportLength { | ||||
| 		var rr ReceptionReport | ||||
| 		if err := rr.Unmarshal(rawPacket[i:]); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		r.Reports = append(r.Reports, rr) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										81
									
								
								pkg/rtcp/sender_report_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								pkg/rtcp/sender_report_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| package rtcp | ||||
|  | ||||
| import ( | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestSenderReportUnmarshalNil(t *testing.T) { | ||||
| 	var sr SenderReport | ||||
| 	err := sr.Unmarshal(nil) | ||||
| 	if got, want := err, errPacketTooShort; got != want { | ||||
| 		t.Fatalf("unmarshal nil sr: err = %v, want %v", got, want) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSenderReportRoundTrip(t *testing.T) { | ||||
| 	for _, test := range []struct { | ||||
| 		Name      string | ||||
| 		Report    SenderReport | ||||
| 		WantError error | ||||
| 	}{ | ||||
| 		{ | ||||
| 			Name: "valid", | ||||
| 			Report: SenderReport{ | ||||
| 				SSRC:        1, | ||||
| 				NTPTime:     999, | ||||
| 				RTPTime:     555, | ||||
| 				PacketCount: 32, | ||||
| 				OctetCount:  11, | ||||
| 				Reports: []ReceptionReport{ | ||||
| 					{ | ||||
| 						SSRC:         2, | ||||
| 						FractionLost: 2, | ||||
| 						TotalLost:    3, | ||||
| 						LastSeq:      4, | ||||
| 						Jitter:       5, | ||||
| 						LastSR:       6, | ||||
| 						Delay:        7, | ||||
| 					}, | ||||
| 					{ | ||||
| 						SSRC: 0, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name: "also valid", | ||||
| 			Report: SenderReport{ | ||||
| 				SSRC: 2, | ||||
| 				Reports: []ReceptionReport{ | ||||
| 					{ | ||||
| 						SSRC:         999, | ||||
| 						FractionLost: 30, | ||||
| 						TotalLost:    12345, | ||||
| 						LastSeq:      99, | ||||
| 						Jitter:       22, | ||||
| 						LastSR:       92, | ||||
| 						Delay:        46, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} { | ||||
| 		data, err := test.Report.Marshal() | ||||
| 		if got, want := err, test.WantError; got != want { | ||||
| 			t.Fatalf("Marshal %q: err = %v, want %v", test.Name, got, want) | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		var decoded SenderReport | ||||
| 		if err := decoded.Unmarshal(data); err != nil { | ||||
| 			t.Fatalf("Unmarshal %q: %v", test.Name, err) | ||||
| 		} | ||||
|  | ||||
| 		if got, want := decoded, test.Report; !reflect.DeepEqual(got, want) { | ||||
| 			t.Fatalf("%q sr round trip: got %#v, want %#v", test.Name, got, want) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Max Hawkins
					Max Hawkins