@@ -10,7 +10,9 @@ import (
1010 "encoding/json"
1111 "errors"
1212 "fmt"
13+ "io"
1314 "sync"
15+ "sync/atomic"
1416 "testing"
1517 "time"
1618
@@ -1428,6 +1430,31 @@ func TestPeerConnection_GetStats(t *testing.T) { //nolint:cyclop // involves mul
14281430 })
14291431 })
14301432
1433+ // register OnTrack before we start signaling so we can safely wait for the first RTP packet.
1434+ var gotFirstPacket atomic.Bool
1435+ var once sync.Once
1436+ answerPC .OnTrack (func (tr * TrackRemote , _ * RTPReceiver ) {
1437+ once .Do (func () {
1438+ go func () {
1439+ // read one RTP packet to ensure TrackRemote has been initialized.
1440+ for {
1441+ _ , _ , firstPacketErr := tr .ReadRTP ()
1442+
1443+ if firstPacketErr == nil {
1444+ gotFirstPacket .Store (true )
1445+
1446+ return
1447+ }
1448+
1449+ if errors .Is (firstPacketErr , io .EOF ) || errors .Is (firstPacketErr , io .ErrClosedPipe ) {
1450+ return
1451+ }
1452+ // retry on transient errors
1453+ }
1454+ }()
1455+ })
1456+ })
1457+
14311458 assert .NoError (t , signalPairForStats (offerPC , answerPC ))
14321459 waitWithTimeout (t , & dcWait )
14331460
@@ -1473,26 +1500,14 @@ func TestPeerConnection_GetStats(t *testing.T) { //nolint:cyclop // involves mul
14731500 }
14741501 assert .NoError (t , track1 .WriteSample (sample ))
14751502
1476- // Poll for packets to arrive rather than using a fixed wait time.
1477- // This ensures the test is deterministic and fails fast with clear context
1478- // if packets don't arrive within the timeout period.
1479- assert .Eventually (t , func () bool {
1480- reportPCAnswer = answerPC .GetStats ()
1481- receivers := answerPC .GetReceivers ()
1482- for _ , r := range receivers {
1483- for _ , tr := range r .Tracks () {
1484- if tr .SSRC () == 0 {
1485- continue
1486- }
1487- matches := findInboundRTPStatsBySSRC (reportPCAnswer , tr .SSRC ())
1488- if len (matches ) > 0 && matches [0 ].PacketsReceived > 0 {
1489- return true
1490- }
1491- }
1492- }
1493-
1494- return false
1495- }, time .Second , 10 * time .Millisecond , "Expected packets to be received" )
1503+ // Wait until the remote track has read one RTP packet (avoids racing GetStats with TrackRemote initialization).
1504+ assert .Eventually (
1505+ t ,
1506+ gotFirstPacket .Load ,
1507+ 2 * time .Second ,
1508+ 10 * time .Millisecond ,
1509+ "Expected to read an RTP packet" ,
1510+ )
14961511
14971512 // Get fresh stats after sending the sample
14981513 reportPCAnswer = answerPC .GetStats ()
0 commit comments