| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347 |
- // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
- // SPDX-License-Identifier: MIT
- //go:build !js
- // +build !js
- package webrtc
- import (
- "encoding/json"
- "fmt"
- "sync"
- "testing"
- "time"
- "github.com/pion/ice/v2"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- )
- var errReceiveOfferTimeout = fmt.Errorf("timed out waiting to receive offer")
- func TestStatsTimestampTime(t *testing.T) {
- for _, test := range []struct {
- Timestamp StatsTimestamp
- WantTime time.Time
- }{
- {
- Timestamp: 0,
- WantTime: time.Unix(0, 0),
- },
- {
- Timestamp: 1,
- WantTime: time.Unix(0, 1e6),
- },
- {
- Timestamp: 0.001,
- WantTime: time.Unix(0, 1e3),
- },
- } {
- if got, want := test.Timestamp.Time(), test.WantTime.UTC(); got != want {
- t.Fatalf("StatsTimestamp(%v).Time() = %v, want %v", test.Timestamp, got, want)
- }
- }
- }
- type statSample struct {
- name string
- stats Stats
- json string
- }
- func getStatsSamples() []statSample {
- codecStats := CodecStats{
- Timestamp: 1688978831527.718,
- Type: StatsTypeCodec,
- ID: "COT01_111_minptime=10;useinbandfec=1",
- PayloadType: 111,
- CodecType: CodecTypeEncode,
- TransportID: "T01",
- MimeType: "audio/opus",
- ClockRate: 48000,
- Channels: 2,
- SDPFmtpLine: "minptime=10;useinbandfec=1",
- Implementation: "libvpx",
- }
- codecStatsJSON := `
- {
- "timestamp": 1688978831527.718,
- "type": "codec",
- "id": "COT01_111_minptime=10;useinbandfec=1",
- "payloadType": 111,
- "codecType": "encode",
- "transportId": "T01",
- "mimeType": "audio/opus",
- "clockRate": 48000,
- "channels": 2,
- "sdpFmtpLine": "minptime=10;useinbandfec=1",
- "implementation": "libvpx"
- }
- `
- inboundRTPStreamStats := InboundRTPStreamStats{
- Timestamp: 1688978831527.718,
- ID: "IT01A2184088143",
- Type: StatsTypeInboundRTP,
- SSRC: 2184088143,
- Kind: "audio",
- TransportID: "T01",
- CodecID: "CIT01_111_minptime=10;useinbandfec=1",
- FIRCount: 1,
- PLICount: 2,
- NACKCount: 3,
- SLICount: 4,
- QPSum: 5,
- PacketsReceived: 6,
- PacketsLost: 7,
- Jitter: 8,
- PacketsDiscarded: 9,
- PacketsRepaired: 10,
- BurstPacketsLost: 11,
- BurstPacketsDiscarded: 12,
- BurstLossCount: 13,
- BurstDiscardCount: 14,
- BurstLossRate: 15,
- BurstDiscardRate: 16,
- GapLossRate: 17,
- GapDiscardRate: 18,
- TrackID: "d57dbc4b-484b-4b40-9088-d3150e3a2010",
- ReceiverID: "R01",
- RemoteID: "ROA2184088143",
- FramesDecoded: 17,
- LastPacketReceivedTimestamp: 1689668364374.181,
- AverageRTCPInterval: 18,
- FECPacketsReceived: 19,
- BytesReceived: 20,
- PacketsFailedDecryption: 21,
- PacketsDuplicated: 22,
- PerDSCPPacketsReceived: map[string]uint32{
- "123": 23,
- },
- }
- inboundRTPStreamStatsJSON := `
- {
- "timestamp": 1688978831527.718,
- "id": "IT01A2184088143",
- "type": "inbound-rtp",
- "ssrc": 2184088143,
- "kind": "audio",
- "transportId": "T01",
- "codecId": "CIT01_111_minptime=10;useinbandfec=1",
- "firCount": 1,
- "pliCount": 2,
- "nackCount": 3,
- "sliCount": 4,
- "qpSum": 5,
- "packetsReceived": 6,
- "packetsLost": 7,
- "jitter": 8,
- "packetsDiscarded": 9,
- "packetsRepaired": 10,
- "burstPacketsLost": 11,
- "burstPacketsDiscarded": 12,
- "burstLossCount": 13,
- "burstDiscardCount": 14,
- "burstLossRate": 15,
- "burstDiscardRate": 16,
- "gapLossRate": 17,
- "gapDiscardRate": 18,
- "trackId": "d57dbc4b-484b-4b40-9088-d3150e3a2010",
- "receiverId": "R01",
- "remoteId": "ROA2184088143",
- "framesDecoded": 17,
- "lastPacketReceivedTimestamp": 1689668364374.181,
- "averageRtcpInterval": 18,
- "fecPacketsReceived": 19,
- "bytesReceived": 20,
- "packetsFailedDecryption": 21,
- "packetsDuplicated": 22,
- "perDscpPacketsReceived": {
- "123": 23
- }
- }
- `
- outboundRTPStreamStats := OutboundRTPStreamStats{
- Timestamp: 1688978831527.718,
- Type: StatsTypeOutboundRTP,
- ID: "OT01A2184088143",
- SSRC: 2184088143,
- Kind: "audio",
- TransportID: "T01",
- CodecID: "COT01_111_minptime=10;useinbandfec=1",
- FIRCount: 1,
- PLICount: 2,
- NACKCount: 3,
- SLICount: 4,
- QPSum: 5,
- PacketsSent: 6,
- PacketsDiscardedOnSend: 7,
- FECPacketsSent: 8,
- BytesSent: 9,
- BytesDiscardedOnSend: 10,
- TrackID: "d57dbc4b-484b-4b40-9088-d3150e3a2010",
- SenderID: "S01",
- RemoteID: "ROA2184088143",
- LastPacketSentTimestamp: 11,
- TargetBitrate: 12,
- FramesEncoded: 13,
- TotalEncodeTime: 14,
- AverageRTCPInterval: 15,
- QualityLimitationReason: "cpu",
- QualityLimitationDurations: map[string]float64{
- "none": 16,
- "cpu": 17,
- "bandwidth": 18,
- "other": 19,
- },
- PerDSCPPacketsSent: map[string]uint32{
- "123": 23,
- },
- }
- outboundRTPStreamStatsJSON := `
- {
- "timestamp": 1688978831527.718,
- "type": "outbound-rtp",
- "id": "OT01A2184088143",
- "ssrc": 2184088143,
- "kind": "audio",
- "transportId": "T01",
- "codecId": "COT01_111_minptime=10;useinbandfec=1",
- "firCount": 1,
- "pliCount": 2,
- "nackCount": 3,
- "sliCount": 4,
- "qpSum": 5,
- "packetsSent": 6,
- "packetsDiscardedOnSend": 7,
- "fecPacketsSent": 8,
- "bytesSent": 9,
- "bytesDiscardedOnSend": 10,
- "trackId": "d57dbc4b-484b-4b40-9088-d3150e3a2010",
- "senderId": "S01",
- "remoteId": "ROA2184088143",
- "lastPacketSentTimestamp": 11,
- "targetBitrate": 12,
- "framesEncoded": 13,
- "totalEncodeTime": 14,
- "averageRtcpInterval": 15,
- "qualityLimitationReason": "cpu",
- "qualityLimitationDurations": {
- "none": 16,
- "cpu": 17,
- "bandwidth": 18,
- "other": 19
- },
- "perDscpPacketsSent": {
- "123": 23
- }
- }
- `
- remoteInboundRTPStreamStats := RemoteInboundRTPStreamStats{
- Timestamp: 1688978831527.718,
- Type: StatsTypeRemoteInboundRTP,
- ID: "RIA2184088143",
- SSRC: 2184088143,
- Kind: "audio",
- TransportID: "T01",
- CodecID: "COT01_111_minptime=10;useinbandfec=1",
- FIRCount: 1,
- PLICount: 2,
- NACKCount: 3,
- SLICount: 4,
- QPSum: 5,
- PacketsReceived: 6,
- PacketsLost: 7,
- Jitter: 8,
- PacketsDiscarded: 9,
- PacketsRepaired: 10,
- BurstPacketsLost: 11,
- BurstPacketsDiscarded: 12,
- BurstLossCount: 13,
- BurstDiscardCount: 14,
- BurstLossRate: 15,
- BurstDiscardRate: 16,
- GapLossRate: 17,
- GapDiscardRate: 18,
- LocalID: "RIA2184088143",
- RoundTripTime: 19,
- FractionLost: 20,
- }
- remoteInboundRTPStreamStatsJSON := `
- {
- "timestamp": 1688978831527.718,
- "type": "remote-inbound-rtp",
- "id": "RIA2184088143",
- "ssrc": 2184088143,
- "kind": "audio",
- "transportId": "T01",
- "codecId": "COT01_111_minptime=10;useinbandfec=1",
- "firCount": 1,
- "pliCount": 2,
- "nackCount": 3,
- "sliCount": 4,
- "qpSum": 5,
- "packetsReceived": 6,
- "packetsLost": 7,
- "jitter": 8,
- "packetsDiscarded": 9,
- "packetsRepaired": 10,
- "burstPacketsLost": 11,
- "burstPacketsDiscarded": 12,
- "burstLossCount": 13,
- "burstDiscardCount": 14,
- "burstLossRate": 15,
- "burstDiscardRate": 16,
- "gapLossRate": 17,
- "gapDiscardRate": 18,
- "localId": "RIA2184088143",
- "roundTripTime": 19,
- "fractionLost": 20
- }
- `
- remoteOutboundRTPStreamStats := RemoteOutboundRTPStreamStats{
- Timestamp: 1688978831527.718,
- Type: StatsTypeRemoteOutboundRTP,
- ID: "ROA2184088143",
- SSRC: 2184088143,
- Kind: "audio",
- TransportID: "T01",
- CodecID: "CIT01_111_minptime=10;useinbandfec=1",
- FIRCount: 1,
- PLICount: 2,
- NACKCount: 3,
- SLICount: 4,
- QPSum: 5,
- PacketsSent: 1259,
- PacketsDiscardedOnSend: 6,
- FECPacketsSent: 7,
- BytesSent: 92654,
- BytesDiscardedOnSend: 8,
- LocalID: "IT01A2184088143",
- RemoteTimestamp: 1689668361298,
- }
- remoteOutboundRTPStreamStatsJSON := `
- {
- "timestamp": 1688978831527.718,
- "type": "remote-outbound-rtp",
- "id": "ROA2184088143",
- "ssrc": 2184088143,
- "kind": "audio",
- "transportId": "T01",
- "codecId": "CIT01_111_minptime=10;useinbandfec=1",
- "firCount": 1,
- "pliCount": 2,
- "nackCount": 3,
- "sliCount": 4,
- "qpSum": 5,
- "packetsSent": 1259,
- "packetsDiscardedOnSend": 6,
- "fecPacketsSent": 7,
- "bytesSent": 92654,
- "bytesDiscardedOnSend": 8,
- "localId": "IT01A2184088143",
- "remoteTimestamp": 1689668361298
- }
- `
- csrcStats := RTPContributingSourceStats{
- Timestamp: 1688978831527.718,
- Type: StatsTypeCSRC,
- ID: "ROA2184088143",
- ContributorSSRC: 2184088143,
- InboundRTPStreamID: "IT01A2184088143",
- PacketsContributedTo: 5,
- AudioLevel: 0.3,
- }
- csrcStatsJSON := `
- {
- "timestamp": 1688978831527.718,
- "type": "csrc",
- "id": "ROA2184088143",
- "contributorSsrc": 2184088143,
- "inboundRtpStreamId": "IT01A2184088143",
- "packetsContributedTo": 5,
- "audioLevel": 0.3
- }
- `
- audioSourceStats := AudioSourceStats{
- Timestamp: 1689668364374.479,
- Type: StatsTypeMediaSource,
- ID: "SA5",
- TrackIdentifier: "d57dbc4b-484b-4b40-9088-d3150e3a2010",
- Kind: "audio",
- AudioLevel: 0.0030518509475997192,
- TotalAudioEnergy: 0.0024927631236904358,
- TotalSamplesDuration: 28.360000000001634,
- EchoReturnLoss: -30,
- EchoReturnLossEnhancement: 0.17551203072071075,
- DroppedSamplesDuration: 0.1,
- DroppedSamplesEvents: 2,
- TotalCaptureDelay: 0.3,
- TotalSamplesCaptured: 4,
- }
- audioSourceStatsJSON := `
- {
- "timestamp": 1689668364374.479,
- "type": "media-source",
- "id": "SA5",
- "trackIdentifier": "d57dbc4b-484b-4b40-9088-d3150e3a2010",
- "kind": "audio",
- "audioLevel": 0.0030518509475997192,
- "totalAudioEnergy": 0.0024927631236904358,
- "totalSamplesDuration": 28.360000000001634,
- "echoReturnLoss": -30,
- "echoReturnLossEnhancement": 0.17551203072071075,
- "droppedSamplesDuration": 0.1,
- "droppedSamplesEvents": 2,
- "totalCaptureDelay": 0.3,
- "totalSamplesCaptured": 4
- }
- `
- videoSourceStats := VideoSourceStats{
- Timestamp: 1689668364374.479,
- Type: StatsTypeMediaSource,
- ID: "SV6",
- TrackIdentifier: "d7f11739-d395-42e9-af87-5dfa1cc10ee0",
- Kind: "video",
- Width: 640,
- Height: 480,
- Frames: 850,
- FramesPerSecond: 30,
- }
- videoSourceStatsJSON := `
- {
- "timestamp": 1689668364374.479,
- "type": "media-source",
- "id": "SV6",
- "trackIdentifier": "d7f11739-d395-42e9-af87-5dfa1cc10ee0",
- "kind": "video",
- "width": 640,
- "height": 480,
- "frames": 850,
- "framesPerSecond": 30
- }
- `
- audioPlayoutStats := AudioPlayoutStats{
- Timestamp: 1689668364374.181,
- Type: StatsTypeMediaPlayout,
- ID: "AP",
- Kind: "audio",
- SynthesizedSamplesDuration: 1,
- SynthesizedSamplesEvents: 2,
- TotalSamplesDuration: 593.5,
- TotalPlayoutDelay: 1062194.11536,
- TotalSamplesCount: 28488000,
- }
- audioPlayoutStatsJSON := `
- {
- "timestamp": 1689668364374.181,
- "type": "media-playout",
- "id": "AP",
- "kind": "audio",
- "synthesizedSamplesDuration": 1,
- "synthesizedSamplesEvents": 2,
- "totalSamplesDuration": 593.5,
- "totalPlayoutDelay": 1062194.11536,
- "totalSamplesCount": 28488000
- }
- `
- peerConnectionStats := PeerConnectionStats{
- Timestamp: 1688978831527.718,
- Type: StatsTypePeerConnection,
- ID: "P",
- DataChannelsOpened: 1,
- DataChannelsClosed: 2,
- DataChannelsRequested: 3,
- DataChannelsAccepted: 4,
- }
- peerConnectionStatsJSON := `
- {
- "timestamp": 1688978831527.718,
- "type": "peer-connection",
- "id": "P",
- "dataChannelsOpened": 1,
- "dataChannelsClosed": 2,
- "dataChannelsRequested": 3,
- "dataChannelsAccepted": 4
- }
- `
- dataChannelStats := DataChannelStats{
- Timestamp: 1688978831527.718,
- Type: StatsTypeDataChannel,
- ID: "D1",
- Label: "display",
- Protocol: "protocol",
- DataChannelIdentifier: 1,
- TransportID: "T1",
- State: DataChannelStateOpen,
- MessagesSent: 1,
- BytesSent: 16,
- MessagesReceived: 2,
- BytesReceived: 20,
- }
- dataChannelStatsJSON := `
- {
- "timestamp": 1688978831527.718,
- "type": "data-channel",
- "id": "D1",
- "label": "display",
- "protocol": "protocol",
- "dataChannelIdentifier": 1,
- "transportId": "T1",
- "state": "open",
- "messagesSent": 1,
- "bytesSent": 16,
- "messagesReceived": 2,
- "bytesReceived": 20
- }
- `
- streamStats := MediaStreamStats{
- Timestamp: 1688978831527.718,
- Type: StatsTypeStream,
- ID: "ROA2184088143",
- StreamIdentifier: "S1",
- TrackIDs: []string{"d57dbc4b-484b-4b40-9088-d3150e3a2010"},
- }
- streamStatsJSON := `
- {
- "timestamp": 1688978831527.718,
- "type": "stream",
- "id": "ROA2184088143",
- "streamIdentifier": "S1",
- "trackIds": [
- "d57dbc4b-484b-4b40-9088-d3150e3a2010"
- ]
- }
- `
- senderVideoTrackAttachmentStats := SenderVideoTrackAttachmentStats{
- Timestamp: 1688978831527.718,
- Type: StatsTypeTrack,
- ID: "S2",
- Kind: "video",
- FramesCaptured: 1,
- FramesSent: 2,
- HugeFramesSent: 3,
- KeyFramesSent: 4,
- }
- senderVideoTrackAttachmentStatsJSON := `
- {
- "timestamp": 1688978831527.718,
- "type": "track",
- "id": "S2",
- "kind": "video",
- "framesCaptured": 1,
- "framesSent": 2,
- "hugeFramesSent": 3,
- "keyFramesSent": 4
- }
- `
- senderAudioTrackAttachmentStats := SenderAudioTrackAttachmentStats{
- Timestamp: 1688978831527.718,
- Type: StatsTypeTrack,
- ID: "S1",
- TrackIdentifier: "audio",
- RemoteSource: true,
- Ended: true,
- Kind: "audio",
- AudioLevel: 0.1,
- TotalAudioEnergy: 0.2,
- VoiceActivityFlag: true,
- TotalSamplesDuration: 0.3,
- EchoReturnLoss: 0.4,
- EchoReturnLossEnhancement: 0.5,
- TotalSamplesSent: 200,
- }
- senderAudioTrackAttachmentStatsJSON := `
- {
- "timestamp": 1688978831527.718,
- "type": "track",
- "id": "S1",
- "trackIdentifier": "audio",
- "remoteSource": true,
- "ended": true,
- "kind": "audio",
- "audioLevel": 0.1,
- "totalAudioEnergy": 0.2,
- "voiceActivityFlag": true,
- "totalSamplesDuration": 0.3,
- "echoReturnLoss": 0.4,
- "echoReturnLossEnhancement": 0.5,
- "totalSamplesSent": 200
- }
- `
- videoSenderStats := VideoSenderStats{
- Timestamp: 1688978831527.718,
- Type: StatsTypeSender,
- ID: "S2",
- Kind: "video",
- FramesCaptured: 1,
- FramesSent: 2,
- HugeFramesSent: 3,
- KeyFramesSent: 4,
- }
- videoSenderStatsJSON := `
- {
- "timestamp": 1688978831527.718,
- "type": "sender",
- "id": "S2",
- "kind": "video",
- "framesCaptured": 1,
- "framesSent": 2,
- "hugeFramesSent": 3,
- "keyFramesSent": 4
- }
- `
- audioSenderStats := AudioSenderStats{
- Timestamp: 1688978831527.718,
- Type: StatsTypeSender,
- ID: "S1",
- TrackIdentifier: "audio",
- RemoteSource: true,
- Ended: true,
- Kind: "audio",
- AudioLevel: 0.1,
- TotalAudioEnergy: 0.2,
- VoiceActivityFlag: true,
- TotalSamplesDuration: 0.3,
- EchoReturnLoss: 0.4,
- EchoReturnLossEnhancement: 0.5,
- TotalSamplesSent: 200,
- }
- audioSenderStatsJSON := `
- {
- "timestamp": 1688978831527.718,
- "type": "sender",
- "id": "S1",
- "trackIdentifier": "audio",
- "remoteSource": true,
- "ended": true,
- "kind": "audio",
- "audioLevel": 0.1,
- "totalAudioEnergy": 0.2,
- "voiceActivityFlag": true,
- "totalSamplesDuration": 0.3,
- "echoReturnLoss": 0.4,
- "echoReturnLossEnhancement": 0.5,
- "totalSamplesSent": 200
- }
- `
- videoReceiverStats := VideoReceiverStats{
- Timestamp: 1688978831527.718,
- Type: StatsTypeReceiver,
- ID: "ROA2184088143",
- Kind: "video",
- FrameWidth: 720,
- FrameHeight: 480,
- FramesPerSecond: 30.0,
- EstimatedPlayoutTimestamp: 1688978831527.718,
- JitterBufferDelay: 0.1,
- JitterBufferEmittedCount: 1,
- FramesReceived: 79,
- KeyFramesReceived: 10,
- FramesDecoded: 10,
- FramesDropped: 10,
- PartialFramesLost: 5,
- FullFramesLost: 5,
- }
- videoReceiverStatsJSON := `
- {
- "timestamp": 1688978831527.718,
- "type": "receiver",
- "id": "ROA2184088143",
- "kind": "video",
- "frameWidth": 720,
- "frameHeight": 480,
- "framesPerSecond": 30.0,
- "estimatedPlayoutTimestamp": 1688978831527.718,
- "jitterBufferDelay": 0.1,
- "jitterBufferEmittedCount": 1,
- "framesReceived": 79,
- "keyFramesReceived": 10,
- "framesDecoded": 10,
- "framesDropped": 10,
- "partialFramesLost": 5,
- "fullFramesLost": 5
- }
- `
- audioReceiverStats := AudioReceiverStats{
- Timestamp: 1688978831527.718,
- Type: StatsTypeReceiver,
- ID: "R1",
- Kind: "audio",
- AudioLevel: 0.1,
- TotalAudioEnergy: 0.2,
- VoiceActivityFlag: true,
- TotalSamplesDuration: 0.3,
- EstimatedPlayoutTimestamp: 1688978831527.718,
- JitterBufferDelay: 0.5,
- JitterBufferEmittedCount: 6,
- TotalSamplesReceived: 7,
- ConcealedSamples: 8,
- ConcealmentEvents: 9,
- }
- audioReceiverStatsJSON := `
- {
- "timestamp": 1688978831527.718,
- "type": "receiver",
- "id": "R1",
- "kind": "audio",
- "audioLevel": 0.1,
- "totalAudioEnergy": 0.2,
- "voiceActivityFlag": true,
- "totalSamplesDuration": 0.3,
- "estimatedPlayoutTimestamp": 1688978831527.718,
- "jitterBufferDelay": 0.5,
- "jitterBufferEmittedCount": 6,
- "totalSamplesReceived": 7,
- "concealedSamples": 8,
- "concealmentEvents": 9
- }
- `
- transportStats := TransportStats{
- Timestamp: 1688978831527.718,
- Type: StatsTypeTransport,
- ID: "T01",
- PacketsSent: 60,
- PacketsReceived: 8,
- BytesSent: 6517,
- BytesReceived: 1159,
- RTCPTransportStatsID: "T01",
- ICERole: ICERoleControlling,
- DTLSState: DTLSTransportStateConnected,
- SelectedCandidatePairID: "CPxIhBDNnT_sPDhy1TB",
- LocalCertificateID: "CFF4:4F:C4:C7:F3:31:6C:B9:D5:AD:19:64:05:9F:2F:E9:00:70:56:1E:BA:92:29:3A:08:CE:1B:27:CF:2D:AB:24",
- RemoteCertificateID: "CF62:AF:88:F7:F3:0F:D6:C4:93:91:1E:AD:52:F0:A4:12:04:F9:48:E7:06:16:BA:A3:86:26:8F:1E:38:1C:48:49",
- DTLSCipher: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
- SRTPCipher: "AES_CM_128_HMAC_SHA1_80",
- }
- transportStatsJSON := `
- {
- "timestamp": 1688978831527.718,
- "type": "transport",
- "id": "T01",
- "packetsSent": 60,
- "packetsReceived": 8,
- "bytesSent": 6517,
- "bytesReceived": 1159,
- "rtcpTransportStatsId": "T01",
- "iceRole": "controlling",
- "dtlsState": "connected",
- "selectedCandidatePairId": "CPxIhBDNnT_sPDhy1TB",
- "localCertificateId": "CFF4:4F:C4:C7:F3:31:6C:B9:D5:AD:19:64:05:9F:2F:E9:00:70:56:1E:BA:92:29:3A:08:CE:1B:27:CF:2D:AB:24",
- "remoteCertificateId": "CF62:AF:88:F7:F3:0F:D6:C4:93:91:1E:AD:52:F0:A4:12:04:F9:48:E7:06:16:BA:A3:86:26:8F:1E:38:1C:48:49",
- "dtlsCipher": "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
- "srtpCipher": "AES_CM_128_HMAC_SHA1_80"
- }
- `
- iceCandidatePairStats := ICECandidatePairStats{
- Timestamp: 1688978831527.718,
- Type: StatsTypeCandidatePair,
- ID: "CPxIhBDNnT_LlMJOnBv",
- TransportID: "T01",
- LocalCandidateID: "IxIhBDNnT",
- RemoteCandidateID: "ILlMJOnBv",
- State: "waiting",
- Nominated: true,
- PacketsSent: 1,
- PacketsReceived: 2,
- BytesSent: 3,
- BytesReceived: 4,
- LastPacketSentTimestamp: 5,
- LastPacketReceivedTimestamp: 6,
- FirstRequestTimestamp: 7,
- LastRequestTimestamp: 8,
- LastResponseTimestamp: 9,
- TotalRoundTripTime: 10,
- CurrentRoundTripTime: 11,
- AvailableOutgoingBitrate: 12,
- AvailableIncomingBitrate: 13,
- CircuitBreakerTriggerCount: 14,
- RequestsReceived: 15,
- RequestsSent: 16,
- ResponsesReceived: 17,
- ResponsesSent: 18,
- RetransmissionsReceived: 19,
- RetransmissionsSent: 20,
- ConsentRequestsSent: 21,
- ConsentExpiredTimestamp: 22,
- }
- iceCandidatePairStatsJSON := `
- {
- "timestamp": 1688978831527.718,
- "type": "candidate-pair",
- "id": "CPxIhBDNnT_LlMJOnBv",
- "transportId": "T01",
- "localCandidateId": "IxIhBDNnT",
- "remoteCandidateId": "ILlMJOnBv",
- "state": "waiting",
- "nominated": true,
- "packetsSent": 1,
- "packetsReceived": 2,
- "bytesSent": 3,
- "bytesReceived": 4,
- "lastPacketSentTimestamp": 5,
- "lastPacketReceivedTimestamp": 6,
- "firstRequestTimestamp": 7,
- "lastRequestTimestamp": 8,
- "lastResponseTimestamp": 9,
- "totalRoundTripTime": 10,
- "currentRoundTripTime": 11,
- "availableOutgoingBitrate": 12,
- "availableIncomingBitrate": 13,
- "circuitBreakerTriggerCount": 14,
- "requestsReceived": 15,
- "requestsSent": 16,
- "responsesReceived": 17,
- "responsesSent": 18,
- "retransmissionsReceived": 19,
- "retransmissionsSent": 20,
- "consentRequestsSent": 21,
- "consentExpiredTimestamp": 22
- }
- `
- localIceCandidateStats := ICECandidateStats{
- Timestamp: 1688978831527.718,
- Type: StatsTypeLocalCandidate,
- ID: "ILO8S8KYr",
- TransportID: "T01",
- NetworkType: NetworkTypeUDP4,
- IP: "192.168.0.36",
- Port: 65400,
- Protocol: "udp",
- CandidateType: ICECandidateTypeHost,
- Priority: 2122260223,
- URL: "example.com",
- RelayProtocol: "tcp",
- Deleted: true,
- }
- localIceCandidateStatsJSON := `
- {
- "timestamp": 1688978831527.718,
- "type": "local-candidate",
- "id": "ILO8S8KYr",
- "transportId": "T01",
- "networkType": 1,
- "ip": "192.168.0.36",
- "port": 65400,
- "protocol": "udp",
- "candidateType": "host",
- "priority": 2122260223,
- "url": "example.com",
- "relayProtocol": "tcp",
- "deleted": true
- }
- `
- remoteIceCandidateStats := ICECandidateStats{
- Timestamp: 1689668364374.181,
- Type: StatsTypeRemoteCandidate,
- ID: "IGPGeswsH",
- TransportID: "T01",
- IP: "10.213.237.226",
- Port: 50618,
- Protocol: "udp",
- CandidateType: ICECandidateTypeHost,
- Priority: 2122194687,
- URL: "example.com",
- RelayProtocol: "tcp",
- Deleted: true,
- }
- remoteIceCandidateStatsJSON := `
- {
- "timestamp": 1689668364374.181,
- "type": "remote-candidate",
- "id": "IGPGeswsH",
- "transportId": "T01",
- "ip": "10.213.237.226",
- "port": 50618,
- "protocol": "udp",
- "candidateType": "host",
- "priority": 2122194687,
- "url": "example.com",
- "relayProtocol": "tcp",
- "deleted": true
- }
- `
- certificateStats := CertificateStats{
- Timestamp: 1689668364374.479,
- Type: StatsTypeCertificate,
- ID: "CF23:AB:FA:0B:0E:DF:12:34:D3:6C:EA:83:43:BD:79:39:87:39:11:49:41:8A:63:0E:17:B1:3F:94:FA:E3:62:20",
- Fingerprint: "23:AB:FA:0B:0E:DF:12:34:D3:6C:EA:83:43:BD:79:39:87:39:11:49:41:8A:63:0E:17:B1:3F:94:FA:E3:62:20",
- FingerprintAlgorithm: "sha-256",
- Base64Certificate: "MIIBFjCBvKADAgECAggAwlrxojpmgTAKBggqhkjOPQQDAjARMQ8wDQYDVQQDDAZXZWJSVEMwHhcNMjMwNzE3MDgxODU2WhcNMjMwODE3MDgxODU2WjARMQ8wDQYDVQQDDAZXZWJSVEMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARKETeS9qNGe3ltwp+q2KgsYWsJLFCJGap4L2aa862sPijHeuzLgO2bju/mosJN0Li7mXhuKBOsCkCMU7vZHVVVMAoGCCqGSM49BAMCA0kAMEYCIQDXyuyMMrgzd+w3c4h3vPn9AzLcf9CHVHRGYyy5ReI/hgIhALkXfaZ96TQRf5FI2mBJJUX9O/q4Poe3wNZxxWeDcYN+",
- IssuerCertificateID: "CF62:AF:88:F7:F3:0F:D6:C4:93:91:1E:AD:52:F0:A4:12:04:F9:48:E7:06:16:BA:A3:86:26:8F:1E:38:1C:48:49",
- }
- certificateStatsJSON := `
- {
- "timestamp": 1689668364374.479,
- "type": "certificate",
- "id": "CF23:AB:FA:0B:0E:DF:12:34:D3:6C:EA:83:43:BD:79:39:87:39:11:49:41:8A:63:0E:17:B1:3F:94:FA:E3:62:20",
- "fingerprint": "23:AB:FA:0B:0E:DF:12:34:D3:6C:EA:83:43:BD:79:39:87:39:11:49:41:8A:63:0E:17:B1:3F:94:FA:E3:62:20",
- "fingerprintAlgorithm": "sha-256",
- "base64Certificate": "MIIBFjCBvKADAgECAggAwlrxojpmgTAKBggqhkjOPQQDAjARMQ8wDQYDVQQDDAZXZWJSVEMwHhcNMjMwNzE3MDgxODU2WhcNMjMwODE3MDgxODU2WjARMQ8wDQYDVQQDDAZXZWJSVEMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARKETeS9qNGe3ltwp+q2KgsYWsJLFCJGap4L2aa862sPijHeuzLgO2bju/mosJN0Li7mXhuKBOsCkCMU7vZHVVVMAoGCCqGSM49BAMCA0kAMEYCIQDXyuyMMrgzd+w3c4h3vPn9AzLcf9CHVHRGYyy5ReI/hgIhALkXfaZ96TQRf5FI2mBJJUX9O/q4Poe3wNZxxWeDcYN+",
- "issuerCertificateId": "CF62:AF:88:F7:F3:0F:D6:C4:93:91:1E:AD:52:F0:A4:12:04:F9:48:E7:06:16:BA:A3:86:26:8F:1E:38:1C:48:49"
- }
- `
- return []statSample{
- {
- name: "codec_stats",
- stats: codecStats,
- json: codecStatsJSON,
- },
- {
- name: "inbound_rtp_stream_stats",
- stats: inboundRTPStreamStats,
- json: inboundRTPStreamStatsJSON,
- },
- {
- name: "outbound_rtp_stream_stats",
- stats: outboundRTPStreamStats,
- json: outboundRTPStreamStatsJSON,
- },
- {
- name: "remote_inbound_rtp_stream_stats",
- stats: remoteInboundRTPStreamStats,
- json: remoteInboundRTPStreamStatsJSON,
- },
- {
- name: "remote_outbound_rtp_stream_stats",
- stats: remoteOutboundRTPStreamStats,
- json: remoteOutboundRTPStreamStatsJSON,
- },
- {
- name: "rtp_contributing_source_stats",
- stats: csrcStats,
- json: csrcStatsJSON,
- },
- {
- name: "audio_source_stats",
- stats: audioSourceStats,
- json: audioSourceStatsJSON,
- },
- {
- name: "video_source_stats",
- stats: videoSourceStats,
- json: videoSourceStatsJSON,
- },
- {
- name: "audio_playout_stats",
- stats: audioPlayoutStats,
- json: audioPlayoutStatsJSON,
- },
- {
- name: "peer_connection_stats",
- stats: peerConnectionStats,
- json: peerConnectionStatsJSON,
- },
- {
- name: "data_channel_stats",
- stats: dataChannelStats,
- json: dataChannelStatsJSON,
- },
- {
- name: "media_stream_stats",
- stats: streamStats,
- json: streamStatsJSON,
- },
- {
- name: "sender_video_track_stats",
- stats: senderVideoTrackAttachmentStats,
- json: senderVideoTrackAttachmentStatsJSON,
- },
- {
- name: "sender_audio_track_stats",
- stats: senderAudioTrackAttachmentStats,
- json: senderAudioTrackAttachmentStatsJSON,
- },
- {
- name: "receiver_video_track_stats",
- stats: videoSenderStats,
- json: videoSenderStatsJSON,
- },
- {
- name: "receiver_audio_track_stats",
- stats: audioSenderStats,
- json: audioSenderStatsJSON,
- },
- {
- name: "receiver_video_track_stats",
- stats: videoReceiverStats,
- json: videoReceiverStatsJSON,
- },
- {
- name: "receiver_audio_track_stats",
- stats: audioReceiverStats,
- json: audioReceiverStatsJSON,
- },
- {
- name: "transport_stats",
- stats: transportStats,
- json: transportStatsJSON,
- },
- {
- name: "ice_candidate_pair_stats",
- stats: iceCandidatePairStats,
- json: iceCandidatePairStatsJSON,
- },
- {
- name: "local_ice_candidate_stats",
- stats: localIceCandidateStats,
- json: localIceCandidateStatsJSON,
- },
- {
- name: "remote_ice_candidate_stats",
- stats: remoteIceCandidateStats,
- json: remoteIceCandidateStatsJSON,
- },
- {
- name: "certificate_stats",
- stats: certificateStats,
- json: certificateStatsJSON,
- },
- }
- }
- func TestStatsMarshal(t *testing.T) {
- for _, test := range getStatsSamples() {
- t.Run(test.name+"_marshal", func(t *testing.T) {
- actualJSON, err := json.Marshal(test.stats)
- require.NoError(t, err)
- assert.JSONEq(t, test.json, string(actualJSON))
- })
- }
- }
- func TestStatsUnmarshal(t *testing.T) {
- for _, test := range getStatsSamples() {
- t.Run(test.name+"_unmarshal", func(t *testing.T) {
- actualStats, err := UnmarshalStatsJSON([]byte(test.json))
- require.NoError(t, err)
- assert.Equal(t, test.stats, actualStats)
- })
- }
- }
- func waitWithTimeout(t *testing.T, wg *sync.WaitGroup) {
- // Wait for all of the event handlers to be triggered.
- done := make(chan struct{})
- go func() {
- wg.Wait()
- done <- struct{}{}
- }()
- timeout := time.After(5 * time.Second)
- select {
- case <-done:
- break
- case <-timeout:
- t.Fatal("timed out waiting for waitgroup")
- }
- }
- func getConnectionStats(t *testing.T, report StatsReport, pc *PeerConnection) PeerConnectionStats {
- stats, ok := report.GetConnectionStats(pc)
- assert.True(t, ok)
- assert.Equal(t, stats.Type, StatsTypePeerConnection)
- return stats
- }
- func getDataChannelStats(t *testing.T, report StatsReport, dc *DataChannel) DataChannelStats {
- stats, ok := report.GetDataChannelStats(dc)
- assert.True(t, ok)
- assert.Equal(t, stats.Type, StatsTypeDataChannel)
- return stats
- }
- func getCodecStats(t *testing.T, report StatsReport, c *RTPCodecParameters) CodecStats {
- stats, ok := report.GetCodecStats(c)
- assert.True(t, ok)
- assert.Equal(t, stats.Type, StatsTypeCodec)
- return stats
- }
- func getTransportStats(t *testing.T, report StatsReport, statsID string) TransportStats {
- stats, ok := report[statsID]
- assert.True(t, ok)
- transportStats, ok := stats.(TransportStats)
- assert.True(t, ok)
- assert.Equal(t, transportStats.Type, StatsTypeTransport)
- return transportStats
- }
- func getSctpTransportStats(t *testing.T, report StatsReport) SCTPTransportStats {
- stats, ok := report["sctpTransport"]
- assert.True(t, ok)
- transportStats, ok := stats.(SCTPTransportStats)
- assert.True(t, ok)
- assert.Equal(t, transportStats.Type, StatsTypeSCTPTransport)
- return transportStats
- }
- func getCertificateStats(t *testing.T, report StatsReport, certificate *Certificate) CertificateStats {
- certificateStats, ok := report.GetCertificateStats(certificate)
- assert.True(t, ok)
- assert.Equal(t, certificateStats.Type, StatsTypeCertificate)
- return certificateStats
- }
- func findLocalCandidateStats(report StatsReport) []ICECandidateStats {
- result := []ICECandidateStats{}
- for _, s := range report {
- stats, ok := s.(ICECandidateStats)
- if ok && stats.Type == StatsTypeLocalCandidate {
- result = append(result, stats)
- }
- }
- return result
- }
- func findRemoteCandidateStats(report StatsReport) []ICECandidateStats {
- result := []ICECandidateStats{}
- for _, s := range report {
- stats, ok := s.(ICECandidateStats)
- if ok && stats.Type == StatsTypeRemoteCandidate {
- result = append(result, stats)
- }
- }
- return result
- }
- func findCandidatePairStats(t *testing.T, report StatsReport) []ICECandidatePairStats {
- result := []ICECandidatePairStats{}
- for _, s := range report {
- stats, ok := s.(ICECandidatePairStats)
- if ok {
- assert.Equal(t, StatsTypeCandidatePair, stats.Type)
- result = append(result, stats)
- }
- }
- return result
- }
- func signalPairForStats(pcOffer *PeerConnection, pcAnswer *PeerConnection) error {
- offerChan := make(chan SessionDescription)
- pcOffer.OnICECandidate(func(candidate *ICECandidate) {
- if candidate == nil {
- offerChan <- *pcOffer.PendingLocalDescription()
- }
- })
- offer, err := pcOffer.CreateOffer(nil)
- if err != nil {
- return err
- }
- if err := pcOffer.SetLocalDescription(offer); err != nil {
- return err
- }
- timeout := time.After(3 * time.Second)
- select {
- case <-timeout:
- return errReceiveOfferTimeout
- case offer := <-offerChan:
- if err := pcAnswer.SetRemoteDescription(offer); err != nil {
- return err
- }
- answer, err := pcAnswer.CreateAnswer(nil)
- if err != nil {
- return err
- }
- if err = pcAnswer.SetLocalDescription(answer); err != nil {
- return err
- }
- err = pcOffer.SetRemoteDescription(answer)
- if err != nil {
- return err
- }
- return nil
- }
- }
- func TestStatsConvertState(t *testing.T) {
- testCases := []struct {
- ice ice.CandidatePairState
- stats StatsICECandidatePairState
- }{
- {
- ice.CandidatePairStateWaiting,
- StatsICECandidatePairStateWaiting,
- },
- {
- ice.CandidatePairStateInProgress,
- StatsICECandidatePairStateInProgress,
- },
- {
- ice.CandidatePairStateFailed,
- StatsICECandidatePairStateFailed,
- },
- {
- ice.CandidatePairStateSucceeded,
- StatsICECandidatePairStateSucceeded,
- },
- }
- s, err := toStatsICECandidatePairState(ice.CandidatePairState(42))
- assert.Error(t, err)
- assert.Equal(t,
- StatsICECandidatePairState("Unknown"),
- s)
- for i, testCase := range testCases {
- s, err := toStatsICECandidatePairState(testCase.ice)
- assert.NoError(t, err)
- assert.Equal(t,
- testCase.stats,
- s,
- "testCase: %d %v", i, testCase,
- )
- }
- }
- func TestPeerConnection_GetStats(t *testing.T) {
- offerPC, answerPC, err := newPair()
- assert.NoError(t, err)
- track1, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion1")
- require.NoError(t, err)
- _, err = offerPC.AddTrack(track1)
- require.NoError(t, err)
- baseLineReportPCOffer := offerPC.GetStats()
- baseLineReportPCAnswer := answerPC.GetStats()
- connStatsOffer := getConnectionStats(t, baseLineReportPCOffer, offerPC)
- connStatsAnswer := getConnectionStats(t, baseLineReportPCAnswer, answerPC)
- for _, connStats := range []PeerConnectionStats{connStatsOffer, connStatsAnswer} {
- assert.Equal(t, uint32(0), connStats.DataChannelsOpened)
- assert.Equal(t, uint32(0), connStats.DataChannelsClosed)
- assert.Equal(t, uint32(0), connStats.DataChannelsRequested)
- assert.Equal(t, uint32(0), connStats.DataChannelsAccepted)
- }
- // Create a DC, open it and send a message
- offerDC, err := offerPC.CreateDataChannel("offerDC", nil)
- assert.NoError(t, err)
- msg := []byte("a classic test message")
- offerDC.OnOpen(func() {
- assert.NoError(t, offerDC.Send(msg))
- })
- dcWait := sync.WaitGroup{}
- dcWait.Add(1)
- answerDCChan := make(chan *DataChannel)
- answerPC.OnDataChannel(func(d *DataChannel) {
- d.OnOpen(func() {
- answerDCChan <- d
- })
- d.OnMessage(func(m DataChannelMessage) {
- dcWait.Done()
- })
- })
- assert.NoError(t, signalPairForStats(offerPC, answerPC))
- waitWithTimeout(t, &dcWait)
- answerDC := <-answerDCChan
- reportPCOffer := offerPC.GetStats()
- reportPCAnswer := answerPC.GetStats()
- connStatsOffer = getConnectionStats(t, reportPCOffer, offerPC)
- assert.Equal(t, uint32(1), connStatsOffer.DataChannelsOpened)
- assert.Equal(t, uint32(0), connStatsOffer.DataChannelsClosed)
- assert.Equal(t, uint32(1), connStatsOffer.DataChannelsRequested)
- assert.Equal(t, uint32(0), connStatsOffer.DataChannelsAccepted)
- dcStatsOffer := getDataChannelStats(t, reportPCOffer, offerDC)
- assert.Equal(t, DataChannelStateOpen, dcStatsOffer.State)
- assert.Equal(t, uint32(1), dcStatsOffer.MessagesSent)
- assert.Equal(t, uint64(len(msg)), dcStatsOffer.BytesSent)
- assert.NotEmpty(t, findLocalCandidateStats(reportPCOffer))
- assert.NotEmpty(t, findRemoteCandidateStats(reportPCOffer))
- assert.NotEmpty(t, findCandidatePairStats(t, reportPCOffer))
- connStatsAnswer = getConnectionStats(t, reportPCAnswer, answerPC)
- assert.Equal(t, uint32(1), connStatsAnswer.DataChannelsOpened)
- assert.Equal(t, uint32(0), connStatsAnswer.DataChannelsClosed)
- assert.Equal(t, uint32(0), connStatsAnswer.DataChannelsRequested)
- assert.Equal(t, uint32(1), connStatsAnswer.DataChannelsAccepted)
- dcStatsAnswer := getDataChannelStats(t, reportPCAnswer, answerDC)
- assert.Equal(t, DataChannelStateOpen, dcStatsAnswer.State)
- assert.Equal(t, uint32(1), dcStatsAnswer.MessagesReceived)
- assert.Equal(t, uint64(len(msg)), dcStatsAnswer.BytesReceived)
- assert.NotEmpty(t, findLocalCandidateStats(reportPCAnswer))
- assert.NotEmpty(t, findRemoteCandidateStats(reportPCAnswer))
- assert.NotEmpty(t, findCandidatePairStats(t, reportPCAnswer))
- assert.NoError(t, err)
- for i := range offerPC.api.mediaEngine.videoCodecs {
- codecStat := getCodecStats(t, reportPCOffer, &(offerPC.api.mediaEngine.videoCodecs[i]))
- assert.NotEmpty(t, codecStat)
- }
- for i := range offerPC.api.mediaEngine.audioCodecs {
- codecStat := getCodecStats(t, reportPCOffer, &(offerPC.api.mediaEngine.audioCodecs[i]))
- assert.NotEmpty(t, codecStat)
- }
- // Close answer DC now
- dcWait = sync.WaitGroup{}
- dcWait.Add(1)
- offerDC.OnClose(func() {
- dcWait.Done()
- })
- assert.NoError(t, answerDC.Close())
- waitWithTimeout(t, &dcWait)
- time.Sleep(10 * time.Millisecond)
- reportPCOffer = offerPC.GetStats()
- reportPCAnswer = answerPC.GetStats()
- connStatsOffer = getConnectionStats(t, reportPCOffer, offerPC)
- assert.Equal(t, uint32(1), connStatsOffer.DataChannelsOpened)
- assert.Equal(t, uint32(1), connStatsOffer.DataChannelsClosed)
- assert.Equal(t, uint32(1), connStatsOffer.DataChannelsRequested)
- assert.Equal(t, uint32(0), connStatsOffer.DataChannelsAccepted)
- dcStatsOffer = getDataChannelStats(t, reportPCOffer, offerDC)
- assert.Equal(t, DataChannelStateClosed, dcStatsOffer.State)
- connStatsAnswer = getConnectionStats(t, reportPCAnswer, answerPC)
- assert.Equal(t, uint32(1), connStatsAnswer.DataChannelsOpened)
- assert.Equal(t, uint32(1), connStatsAnswer.DataChannelsClosed)
- assert.Equal(t, uint32(0), connStatsAnswer.DataChannelsRequested)
- assert.Equal(t, uint32(1), connStatsAnswer.DataChannelsAccepted)
- dcStatsAnswer = getDataChannelStats(t, reportPCAnswer, answerDC)
- assert.Equal(t, DataChannelStateClosed, dcStatsAnswer.State)
- answerICETransportStats := getTransportStats(t, reportPCAnswer, "iceTransport")
- offerICETransportStats := getTransportStats(t, reportPCOffer, "iceTransport")
- assert.GreaterOrEqual(t, offerICETransportStats.BytesSent, answerICETransportStats.BytesReceived)
- assert.GreaterOrEqual(t, answerICETransportStats.BytesSent, offerICETransportStats.BytesReceived)
- answerSCTPTransportStats := getSctpTransportStats(t, reportPCAnswer)
- offerSCTPTransportStats := getSctpTransportStats(t, reportPCOffer)
- assert.GreaterOrEqual(t, offerSCTPTransportStats.BytesSent, answerSCTPTransportStats.BytesReceived)
- assert.GreaterOrEqual(t, answerSCTPTransportStats.BytesSent, offerSCTPTransportStats.BytesReceived)
- certificates := offerPC.configuration.Certificates
- for i := range certificates {
- assert.NotEmpty(t, getCertificateStats(t, reportPCOffer, &certificates[i]))
- }
- closePairNow(t, offerPC, answerPC)
- }
- func TestPeerConnection_GetStats_Closed(t *testing.T) {
- pc, err := NewPeerConnection(Configuration{})
- assert.NoError(t, err)
- assert.NoError(t, pc.Close())
- pc.GetStats()
- }
|