Skip to content

Commit 12cb8ab

Browse files
committed
Fire OnTrack before reading first RTP
Prior to this, we would wait for a single RTP packet to figure out the codec which is not to spec.
1 parent d9e2ce5 commit 12cb8ab

6 files changed

+62
-101
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ cover.out
2626
examples/sfu-ws/cert.pem
2727
examples/sfu-ws/key.pem
2828
wasm_exec.js
29+
*.DS_Store

peerconnection.go

+1-15
Original file line numberDiff line numberDiff line change
@@ -1228,21 +1228,7 @@ func (pc *PeerConnection) startReceiver(incoming trackDetails, receiver *RTPRece
12281228
return
12291229
}
12301230

1231-
go func(track *TrackRemote) {
1232-
b := make([]byte, pc.api.settingEngine.getReceiveMTU())
1233-
n, _, err := track.peek(b)
1234-
if err != nil {
1235-
pc.log.Warnf("Could not determine PayloadType for SSRC %d (%s)", track.SSRC(), err)
1236-
return
1237-
}
1238-
1239-
if err = track.checkAndUpdateTrack(b[:n]); err != nil {
1240-
pc.log.Warnf("Failed to set codec settings for track SSRC %d (%s)", track.SSRC(), err)
1241-
return
1242-
}
1243-
1244-
pc.onTrack(track, receiver)
1245-
}(t)
1231+
pc.onTrack(t, receiver)
12461232
}
12471233
}
12481234

peerconnection_go_test.go

+16-31
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"time"
2424

2525
"github.com/pion/ice/v2"
26-
"github.com/pion/rtp"
2726
"github.com/pion/transport/v2/test"
2827
"github.com/pion/transport/v2/vnet"
2928
"github.com/viamrobotics/webrtc/v3/internal/util"
@@ -1017,9 +1016,11 @@ func TestICERestart_Error_Handling(t *testing.T) {
10171016
}
10181017

10191018
type trackRecords struct {
1020-
mu sync.Mutex
1021-
trackIDs map[string]struct{}
1022-
receivedTrackIDs map[string]struct{}
1019+
mu sync.Mutex
1020+
trackIDs map[string]struct{}
1021+
receivedTrackIDs map[string]struct{}
1022+
onAllTracksReceived chan struct{}
1023+
onAllTracksReceivedOnce sync.Once
10231024
}
10241025

10251026
func (r *trackRecords) newTrack() (*TrackLocalStaticRTP, error) {
@@ -1036,6 +1037,11 @@ func (r *trackRecords) handleTrack(t *TrackRemote, _ *RTPReceiver) {
10361037
if _, exist := r.trackIDs[tID]; exist {
10371038
r.receivedTrackIDs[tID] = struct{}{}
10381039
}
1040+
if len(r.receivedTrackIDs) == len(r.trackIDs) {
1041+
r.onAllTracksReceivedOnce.Do(func() {
1042+
close(r.onAllTracksReceived)
1043+
})
1044+
}
10391045
}
10401046

10411047
func (r *trackRecords) remains() int {
@@ -1049,32 +1055,16 @@ func TestPeerConnection_MassiveTracks(t *testing.T) {
10491055
var (
10501056
api = NewAPI()
10511057
tRecs = &trackRecords{
1052-
trackIDs: make(map[string]struct{}),
1053-
receivedTrackIDs: make(map[string]struct{}),
1058+
trackIDs: make(map[string]struct{}),
1059+
receivedTrackIDs: make(map[string]struct{}),
1060+
onAllTracksReceived: make(chan struct{}),
10541061
}
1055-
tracks = []*TrackLocalStaticRTP{}
10561062
trackCount = 256
10571063
pingInterval = 1 * time.Second
10581064
noiseInterval = 100 * time.Microsecond
10591065
timeoutDuration = 20 * time.Second
1060-
rawPkt = []byte{
1061-
0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64,
1062-
0x27, 0x82, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x98, 0x36, 0xbe, 0x88, 0x9e,
1063-
}
1064-
samplePkt = &rtp.Packet{
1065-
Header: rtp.Header{
1066-
Marker: true,
1067-
Extension: false,
1068-
ExtensionProfile: 1,
1069-
Version: 2,
1070-
SequenceNumber: 27023,
1071-
Timestamp: 3653407706,
1072-
CSRC: []uint32{},
1073-
},
1074-
Payload: rawPkt[20:],
1075-
}
1076-
connected = make(chan struct{})
1077-
stopped = make(chan struct{})
1066+
connected = make(chan struct{})
1067+
stopped = make(chan struct{})
10781068
)
10791069
assert.NoError(t, api.mediaEngine.RegisterDefaultCodecs())
10801070
offerPC, answerPC, err := api.newPair(Configuration{})
@@ -1085,7 +1075,6 @@ func TestPeerConnection_MassiveTracks(t *testing.T) {
10851075
assert.NoError(t, err)
10861076
_, err = offerPC.AddTrack(track)
10871077
assert.NoError(t, err)
1088-
tracks = append(tracks, track)
10891078
}
10901079
answerPC.OnTrack(tRecs.handleTrack)
10911080
offerPC.OnICEConnectionStateChange(func(s ICEConnectionState) {
@@ -1107,12 +1096,8 @@ func TestPeerConnection_MassiveTracks(t *testing.T) {
11071096
}
11081097
}()
11091098
assert.NoError(t, signalPair(offerPC, answerPC))
1110-
// Send a RTP packets to each track to trigger track event after connected.
11111099
<-connected
1112-
time.Sleep(1 * time.Second)
1113-
for _, track := range tracks {
1114-
assert.NoError(t, track.WriteRTP(samplePkt))
1115-
}
1100+
11161101
// Ping trackRecords to see if any track event not received yet.
11171102
tooLong := time.After(timeoutDuration)
11181103
for {

peerconnection_media_test.go

+38-14
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"time"
2222

2323
"github.com/pion/interceptor"
24+
mock_interceptor "github.com/pion/interceptor/pkg/mock"
2425
"github.com/pion/logging"
2526
"github.com/pion/randutil"
2627
"github.com/pion/rtcp"
@@ -1055,10 +1056,34 @@ func TestPeerConnection_Simulcast_Probe(t *testing.T) {
10551056
panic(err)
10561057
}
10571058
registerSimulcastHeaderExtensions(m, RTPCodecTypeVideo)
1059+
assert.NoError(t, m.RegisterDefaultCodecs())
1060+
ir := &interceptor.Registry{}
1061+
1062+
trackReadDone := make(chan struct{})
1063+
ir.Add(&mock_interceptor.Factory{
1064+
NewInterceptorFn: func(_ string) (interceptor.Interceptor, error) {
1065+
return &mock_interceptor.Interceptor{
1066+
BindRemoteStreamFn: func(_ *interceptor.StreamInfo, reader interceptor.RTPReader) interceptor.RTPReader {
1067+
count := int64(0)
1068+
return interceptor.RTPReaderFunc(func(b []byte, a interceptor.Attributes) (int, interceptor.Attributes, error) {
1069+
if a == nil {
1070+
a = interceptor.Attributes{}
1071+
}
1072+
if atomic.AddInt64(&count, 1) > 5 {
1073+
// confirm read before sending any more packets for probing
1074+
<-trackReadDone
1075+
}
1076+
return reader.Read(b, a)
1077+
})
1078+
},
1079+
}, nil
1080+
},
1081+
})
1082+
assert.NoError(t, ConfigureSimulcastExtensionHeaders(m))
10581083

10591084
pcOffer, pcAnswer, err := NewAPI(WithSettingEngine(SettingEngine{
10601085
LoggerFactory: &undeclaredSsrcLoggerFactory{unhandledSimulcastError},
1061-
}), WithMediaEngine(m)).newPair(Configuration{})
1086+
}), WithMediaEngine(m), WithInterceptorRegistry(ir)).newPair(Configuration{})
10621087
assert.NoError(t, err)
10631088

10641089
firstTrack, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "firstTrack", "firstTrack")
@@ -1103,26 +1128,24 @@ func TestPeerConnection_Simulcast_Probe(t *testing.T) {
11031128
time.Sleep(20 * time.Millisecond)
11041129
}
11051130

1131+
// establish undeclared SSRC (half number of probes)
11061132
for ; sequenceNumber <= 5; sequenceNumber++ {
11071133
sendRTPPacket()
11081134
}
11091135

1110-
assert.NoError(t, signalPair(pcOffer, pcAnswer))
1111-
11121136
trackRemoteChan := make(chan *TrackRemote, 1)
11131137
pcAnswer.OnTrack(func(trackRemote *TrackRemote, _ *RTPReceiver) {
11141138
trackRemoteChan <- trackRemote
11151139
})
11161140

1117-
trackRemote := func() *TrackRemote {
1118-
for {
1119-
select {
1120-
case t := <-trackRemoteChan:
1121-
return t
1122-
default:
1123-
sendRTPPacket()
1124-
}
1125-
}
1141+
assert.NoError(t, signalPair(pcOffer, pcAnswer))
1142+
1143+
trackRemote := <-trackRemoteChan
1144+
1145+
go func() {
1146+
_, _, err = trackRemote.Read(make([]byte, 1500))
1147+
assert.NoError(t, err)
1148+
close(trackReadDone)
11261149
}()
11271150

11281151
func() {
@@ -1136,8 +1159,7 @@ func TestPeerConnection_Simulcast_Probe(t *testing.T) {
11361159
}
11371160
}()
11381161

1139-
_, _, err = trackRemote.Read(make([]byte, 1500))
1140-
assert.NoError(t, err)
1162+
<-trackReadDone
11411163

11421164
closePairNow(t, pcOffer, pcAnswer)
11431165
})
@@ -1754,6 +1776,8 @@ func TestPeerConnection_Zero_PayloadType(t *testing.T) {
17541776
trackFired := make(chan struct{})
17551777

17561778
pcAnswer.OnTrack(func(track *TrackRemote, _ *RTPReceiver) {
1779+
_, _, err = track.Read(make([]byte, 1500))
1780+
assert.NoError(t, err)
17571781
require.Equal(t, track.Codec().MimeType, MimeTypePCMU)
17581782
close(trackFired)
17591783
})

track_local_static_test.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,9 @@ func Test_TrackLocalStatic_PayloadType(t *testing.T) {
149149
assert.NoError(t, err)
150150

151151
onTrackFired, onTrackFiredFunc := context.WithCancel(context.Background())
152-
offerer.OnTrack(func(track *TrackRemote, r *RTPReceiver) {
152+
offerer.OnTrack(func(track *TrackRemote, _ *RTPReceiver) {
153+
_, _, err = track.Read(make([]byte, 1500))
154+
assert.NoError(t, err)
153155
assert.Equal(t, track.PayloadType(), PayloadType(100))
154156
assert.Equal(t, track.Codec().RTPCodecCapability.MimeType, "video/VP8")
155157

@@ -284,6 +286,8 @@ func Test_TrackLocalStatic_Padding(t *testing.T) {
284286
onTrackFired, onTrackFiredFunc := context.WithCancel(context.Background())
285287

286288
offerer.OnTrack(func(track *TrackRemote, _ *RTPReceiver) {
289+
_, _, err = track.Read(make([]byte, 1500))
290+
assert.NoError(t, err)
287291
assert.Equal(t, track.PayloadType(), PayloadType(100))
288292
assert.Equal(t, track.Codec().RTPCodecCapability.MimeType, "video/VP8")
289293

track_remote.go

+1-40
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ type TrackRemote struct {
2929
params RTPParameters
3030
rid string
3131

32-
receiver *RTPReceiver
33-
peeked []byte
34-
peekedAttributes interceptor.Attributes
32+
receiver *RTPReceiver
3533
}
3634

3735
func newTrackRemote(kind RTPCodecType, ssrc, rtxSsrc SSRC, rid string, receiver *RTPReceiver) *TrackRemote {
@@ -107,26 +105,8 @@ func (t *TrackRemote) Codec() RTPCodecParameters {
107105
func (t *TrackRemote) Read(b []byte) (n int, attributes interceptor.Attributes, err error) {
108106
t.mu.RLock()
109107
r := t.receiver
110-
peeked := t.peeked != nil
111108
t.mu.RUnlock()
112109

113-
if peeked {
114-
t.mu.Lock()
115-
data := t.peeked
116-
attributes = t.peekedAttributes
117-
118-
t.peeked = nil
119-
t.peekedAttributes = nil
120-
t.mu.Unlock()
121-
// someone else may have stolen our packet when we
122-
// released the lock. Deal with it.
123-
if data != nil {
124-
n = copy(b, data)
125-
err = t.checkAndUpdateTrack(b)
126-
return
127-
}
128-
}
129-
130110
// If there's a separate RTX track and an RTX packet is available, return that
131111
if rtxPacketReceived := r.readRTX(t); rtxPacketReceived != nil {
132112
n = copy(b, rtxPacketReceived.pkt)
@@ -187,25 +167,6 @@ func (t *TrackRemote) ReadRTP() (*rtp.Packet, interceptor.Attributes, error) {
187167
return r, attributes, nil
188168
}
189169

190-
// peek is like Read, but it doesn't discard the packet read
191-
func (t *TrackRemote) peek(b []byte) (n int, a interceptor.Attributes, err error) {
192-
n, a, err = t.Read(b)
193-
if err != nil {
194-
return
195-
}
196-
197-
t.mu.Lock()
198-
// this might overwrite data if somebody peeked between the Read
199-
// and us getting the lock. Oh well, we'll just drop a packet in
200-
// that case.
201-
data := make([]byte, n)
202-
n = copy(data, b[:n])
203-
t.peeked = data
204-
t.peekedAttributes = a
205-
t.mu.Unlock()
206-
return
207-
}
208-
209170
// SetReadDeadline sets the max amount of time the RTP stream will block before returning. 0 is forever.
210171
func (t *TrackRemote) SetReadDeadline(deadline time.Time) error {
211172
return t.receiver.setRTPReadDeadline(deadline, t)

0 commit comments

Comments
 (0)