I have two peers both sending video over WebRTC. The peers use perfect negotiation in parallel, which means in some cases one peer may make an offer, and then throw it away and use the other peer's offer instead. For some reason when this happens, once the connection opens for real and this peer receives a media track, the track is already immediately 'ended' and cannot be used.
I've simplified this to a minimal repro:
const rtc1 = new RTCPeerConnection();
const rtc2 = new RTCPeerConnection();
rtc1.ontrack = ({ track }) => { console.log('rtc1 got track:', track.readyState); };
rtc2.ontrack = ({ track }) => { console.log('rtc2 got track:', track.readyState); };
stream = await navigator.mediaDevices.getUserMedia({ video: true });
rtc2.addTrack(stream.getTracks()[0], stream);
rtc1.addTrack(stream.getTracks()[0], stream);
// These two lines break everything:
o = await rtc2.createOffer();
await rtc2.setLocalDescription(o);
// ---
o = await rtc1.createOffer();
await rtc1.setLocalDescription(o);
await rtc2.setRemoteDescription(o)
a = await rtc2.createAnswer();
await rtc2.setLocalDescription(a);
await rtc1.setRemoteDescription(a);
I think this should set up a WebRTC connection with a SendRecv video stream going in both directions, so that it prints got track: live
twice.
Unfortunately, in reality this prints:
rtc2 got track: ended
rtc1 got track: live
I.e. rtc2's track is already 'ended' when the ontrack
callback fires. RTC2 never receives a working media track. Why?
I'm testing this in the latest Chrome: 100.0.4896.75.
Commenting out the two lines marked above that create an unused offer does solve this. In that case, both tracks are live
as expected. It seems like that offer should not be a problem though, and with the officially encouraged 'perfect negotiation' setup pattern (or anything similar) these kinds of unused offers seem inevitable.
This in fact shouldn't happen, and it doesn't happen in Firefox.
It turns out this is a bug in Chrome: https://bugs.chromium.org/p/chromium/issues/detail?id=1315611