Skip to content

Commit e628ffd

Browse files
committed
[WebRTC] Add support for legacy Offer options
https://bugs.webkit.org/show_bug.cgi?id=256707 <rdar://problem/109569164> Reviewed by Youenn Fablet. Some websites still rely on the legacy offer options, despite the spec recommendation of using transceivers, so bring back those options, behind a runtime WebPreference, disabled by default. Covered by new tests backported from WPT. Upstream commit: web-platform-tests/wpt@9c29d4e * LayoutTests/TestExpectations: * LayoutTests/platform/glib/TestExpectations: * Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml: * Source/WebCore/Modules/mediastream/PeerConnectionBackend.cpp: (WebCore::PeerConnectionBackend::addTransceiver): * Source/WebCore/Modules/mediastream/PeerConnectionBackend.h: * Source/WebCore/Modules/mediastream/RTCOfferOptions.h: * Source/WebCore/Modules/mediastream/RTCOfferOptions.idl: * Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp: (WebCore::RTCPeerConnection::addReceiveOnlyTransceiver): (WebCore::RTCPeerConnection::createOffer): * Source/WebCore/Modules/mediastream/RTCPeerConnection.h: * Source/WebCore/Modules/mediastream/gstreamer/GStreamerMediaEndpoint.cpp: (WebCore::GStreamerMediaEndpoint::createTransceiverBackends): (WebCore::GStreamerMediaEndpoint::addTransceiver): (WebCore::GStreamerMediaEndpoint::onNegotiationNeeded): * Source/WebCore/Modules/mediastream/gstreamer/GStreamerMediaEndpoint.h: * Source/WebCore/Modules/mediastream/gstreamer/GStreamerPeerConnectionBackend.cpp: (WebCore::GStreamerPeerConnectionBackend::addTransceiverFromTrackOrKind): (WebCore::GStreamerPeerConnectionBackend::addTransceiver): * Source/WebCore/Modules/mediastream/gstreamer/GStreamerPeerConnectionBackend.h: * Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp: (WebCore::LibWebRTCMediaEndpoint::createTransceiverBackends): (WebCore::LibWebRTCMediaEndpoint::addTransceiver): (WebCore::LibWebRTCMediaEndpoint::OnNegotiationNeededEvent): * Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.h: * Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.cpp: (WebCore::LibWebRTCPeerConnectionBackend::addTransceiverFromTrackOrKind): (WebCore::LibWebRTCPeerConnectionBackend::addTransceiver): * Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.h: Canonical link: https://commits.webkit.org/283089@main
1 parent b7683c4 commit e628ffd

27 files changed

Lines changed: 358 additions & 66 deletions

LayoutTests/TestExpectations

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,16 @@ imported/w3c/web-platform-tests/video-rvfc [ Skip ]
245245
fast/mediastream/getUserMedia-rvfc.html [ Skip ]
246246
webrtc/peerConnection-rvfc.html [ Skip ]
247247

248+
# Our implementation of pc.setLocalDescription() is not fully spec compliant, steps 4.2 and 4.3 are
249+
# not implemented.
250+
imported/w3c/web-platform-tests/webrtc/legacy/munge-dont.html [ Failure ]
251+
252+
# The addstream event is not supported anymore.
253+
imported/w3c/web-platform-tests/webrtc/legacy/onaddstream.https.html [ Skip ]
254+
255+
# The non-promise based createOffer/createAnswer functions are not supported anymore.
256+
imported/w3c/web-platform-tests/webrtc/legacy/simplecall_callbacks.https.html [ Skip ]
257+
248258
# This test only makes sense on Mac
249259
fast/attachment/attachment-subtitle-resize.html [ Skip ]
250260

LayoutTests/imported/w3c/resources/import-expectations.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,6 @@
466466
"web-platform-tests/webrtc": "import",
467467
"web-platform-tests/webrtc-extensions": "import",
468468
"web-platform-tests/webrtc-priority": "import",
469-
"web-platform-tests/webrtc/legacy": "skip",
470469
"web-platform-tests/websockets": "import",
471470
"web-platform-tests/webstorage": "import",
472471
"web-platform-tests/webstorage/": "import",
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11

2-
FAIL createOffer() with offerToReceiveAudio should add audio line to all subsequent created offers assert_equals: Expect created offer to have audio line expected 1 but got 0
3-
FAIL createOffer() with offerToReceiveVideo should add video line to all subsequent created offers assert_equals: Expect created offer to have video line expected 1 but got 0
4-
FAIL createOffer() with offerToReceiveAudio:true, then with offerToReceiveVideo:true, should have result offer with both audio and video line assert_equals: Expect audio line to be found in created offer expected 1 but got 0
2+
PASS createOffer() with offerToReceiveAudio should add audio line to all subsequent created offers
3+
PASS createOffer() with offerToReceiveVideo should add video line to all subsequent created offers
4+
PASS createOffer() with offerToReceiveAudio:true, then with offerToReceiveVideo:true, should have result offer with both audio and video line
55
PASS createOffer() with offerToReceiveAudio set to false should not create a transceiver
6-
FAIL createOffer() with offerToReceiveAudio should create a "recvonly" transceiver assert_equals: Expect pc to have one transceiver expected 1 but got 0
7-
FAIL offerToReceiveAudio option should be ignored if a non-stopped "recvonly" transceiver exists assert_equals: Expect pc to have one transceiver expected 1 but got 0
6+
PASS createOffer() with offerToReceiveAudio should create a "recvonly" transceiver
7+
PASS offerToReceiveAudio option should be ignored if a non-stopped "recvonly" transceiver exists
88
PASS offerToReceiveAudio option should be ignored if a non-stopped "sendrecv" transceiver exists
9-
FAIL offerToReceiveAudio set to false with a track should create a "sendonly" transceiver assert_equals: Expect transceiver to have "sendonly" direction expected "sendonly" but got "sendrecv"
10-
FAIL offerToReceiveAudio set to false with a "recvonly" transceiver should change the direction to "inactive" assert_equals: Expect transceiver to have "inactive" direction expected "inactive" but got "recvonly"
11-
FAIL subsequent offerToReceiveAudio set to false with a track should change the direction to "sendonly" assert_equals: Expect transceiver to have "sendonly" direction expected "sendonly" but got "sendrecv"
9+
PASS offerToReceiveAudio set to false with a track should create a "sendonly" transceiver
10+
PASS offerToReceiveAudio set to false with a "recvonly" transceiver should change the direction to "inactive"
11+
PASS subsequent offerToReceiveAudio set to false with a track should change the direction to "sendonly"
1212
PASS createOffer() with offerToReceiveVideo set to false should not create a transceiver
13-
FAIL createOffer() with offerToReceiveVideo should create a "recvonly" transceiver assert_equals: Expect pc to have one transceiver expected 1 but got 0
14-
FAIL offerToReceiveVideo option should be ignored if a non-stopped "recvonly" transceiver exists assert_equals: Expect pc to have one transceiver expected 1 but got 0
13+
PASS createOffer() with offerToReceiveVideo should create a "recvonly" transceiver
14+
PASS offerToReceiveVideo option should be ignored if a non-stopped "recvonly" transceiver exists
1515
PASS offerToReceiveVideo option should be ignored if a non-stopped "sendrecv" transceiver exists
16-
FAIL offerToReceiveVideo set to false with a track should create a "sendonly" transceiver assert_equals: Expect transceiver to have "sendonly" direction expected "sendonly" but got "sendrecv"
17-
FAIL offerToReceiveVideo set to false with a "recvonly" transceiver should change the direction to "inactive" assert_equals: Expect transceiver to have "inactive" direction expected "inactive" but got "recvonly"
18-
FAIL subsequent offerToReceiveVideo set to false with a track should change the direction to "sendonly" assert_equals: Expect transceiver to have "sendonly" direction expected "sendonly" but got "sendrecv"
19-
FAIL offerToReceiveAudio and Video should create two "recvonly" transceivers assert_equals: Expect pc to have two transceivers expected 2 but got 0
16+
PASS offerToReceiveVideo set to false with a track should create a "sendonly" transceiver
17+
PASS offerToReceiveVideo set to false with a "recvonly" transceiver should change the direction to "inactive"
18+
PASS subsequent offerToReceiveVideo set to false with a track should change the direction to "sendonly"
19+
PASS offerToReceiveAudio and Video should create two "recvonly" transceivers
2020

LayoutTests/imported/w3c/web-platform-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!doctype html>
1+
<!doctype html><!-- webkit-test-runner [ LegacyWebRTCOfferOptionsEnabled=true ] -->
22
<meta charset=utf-8>
33
<title>Test legacy offerToReceiveAudio/Video options</title>
44
<link rel="help" href="https://w3c.github.io/webrtc-pc/#legacy-configuration-extensions">
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
PASS checkAddTransceiverWithStream
3-
FAIL checkAddTransceiverWithOfferToReceiveAudio assert_equals: expected "[{currentDirection:null,direction:\"recvonly\",mid:null,receiver:{track:{kind:\"audio\"}},sender:{track:null},stopped:false}]" but got "[]"
4-
FAIL checkAddTransceiverWithOfferToReceiveVideo assert_equals: expected "[{currentDirection:null,direction:\"recvonly\",mid:null,receiver:{track:{kind:\"video\"}},sender:{track:null},stopped:false}]" but got "[]"
5-
FAIL checkAddTransceiverWithOfferToReceiveBoth assert_equals: expected "[{currentDirection:null,direction:\"recvonly\",mid:null,receiver:{track:{kind:\"audio\"}},sender:{track:null},stopped:false},{currentDirection:null,direction:\"recvonly\",mid:null,receiver:{track:{kind:\"video\"}},sender:{track:null},stopped:false}]" but got "[]"
3+
PASS checkAddTransceiverWithOfferToReceiveAudio
4+
PASS checkAddTransceiverWithOfferToReceiveVideo
5+
PASS checkAddTransceiverWithOfferToReceiveBoth
66

LayoutTests/imported/w3c/web-platform-tests/webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
<!doctype html>
1+
<!doctype html><!-- webkit-test-runner [ LegacyWebRTCOfferOptionsEnabled=true ] -->
22
<meta charset=utf-8>
33
<title>RTCRtpTransceiver with OfferToReceive legacy options</title>
44
<script src="/resources/testharness.js"></script>
55
<script src="/resources/testharnessreport.js"></script>
6+
<script src=/resources/testdriver.js></script>
7+
<script src=/resources/testdriver-vendor.js></script>
8+
<script src='/mediacapture-streams/permission-helper.js'></script>
69
<script src="../RTCPeerConnection-helper.js"></script>
710
<script>
811
'use strict';
@@ -37,7 +40,7 @@
3740
const checkAddTransceiverWithStream = async t => {
3841
const pc = new RTCPeerConnection();
3942
t.add_cleanup(() => pc.close());
40-
43+
await setMediaPermission();
4144
const audioStream = await navigator.mediaDevices.getUserMedia({audio: true});
4245
const videoStream = await navigator.mediaDevices.getUserMedia({video: true});
4346
t.add_cleanup(() => stopTracks(audioStream, videoStream));
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
PASS RTCSessionDescription.type is read-only
3+
PASS RTCSessionDescription.sdp is read-only
4+
PASS RTCIceCandidate.candidate is read-only
5+
PASS Rejects SDP munging between createOffer and setLocalDescription
6+
PASS Rejects SDP munging between createAnswer and setLocalDescription
7+
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<!doctype html>
2+
<meta charset=utf-8>
3+
<meta name="timeout" content="long">
4+
<title>SDP munging is a bad idea</title>
5+
<script src="/resources/testharness.js"></script>
6+
<script src="/resources/testharnessreport.js"></script>
7+
<script>
8+
'use strict';
9+
10+
const sdp = `v=0
11+
o=- 0 3 IN IP4 127.0.0.1
12+
s=-
13+
t=0 0
14+
m=video 9 UDP/TLS/RTP/SAVPF 100
15+
c=IN IP4 0.0.0.0
16+
a=rtcp-mux
17+
a=sendonly
18+
a=mid:video
19+
a=rtpmap:100 VP8/90000
20+
a=fmtp:100 max-fr=30;max-fs=3600
21+
a=fingerprint:sha-256 A7:24:72:CA:6E:02:55:39:BA:66:DF:6E:CC:4C:D8:B0:1A:BF:1A:56:65:7D:F4:03:AD:7E:77:43:2A:29:EC:93
22+
a=ice-ufrag:ETEn
23+
a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l
24+
`;
25+
const candidateString = 'candidate:1905690388 1 udp 2113937151 192.168.0.1 58041 typ host generation 0 ufrag thC8';
26+
27+
// See https://bugs.chromium.org/p/chromium/issues/detail?id=662898
28+
// and https://bugs.chromium.org/p/chromium/issues/detail?id=823036
29+
// for why neither of these is feasible to enforce.
30+
31+
// Note that this does not restrict creating a
32+
// new RTCSessionDescription with a modified copy.
33+
test(() => {
34+
const desc = new RTCSessionDescription({
35+
type: 'offer',
36+
sdp,
37+
});
38+
assert_throws_js(TypeError, () => {
39+
desc.type = 'answer';
40+
});
41+
}, 'RTCSessionDescription.type is read-only');
42+
43+
test(() => {
44+
const desc = new RTCSessionDescription({
45+
type: 'offer',
46+
sdp,
47+
});
48+
assert_throws_js(TypeError, () => {
49+
desc.sdp += 'a=dont-modify-me\r\n';
50+
});
51+
}, 'RTCSessionDescription.sdp is read-only');
52+
53+
test(() => {
54+
const candidate = new RTCIceCandidate({
55+
sdpMid: '0',
56+
candidate: candidateString,
57+
});
58+
assert_throws_js(TypeError, () => {
59+
candidate.candidate += ' myattribute value';
60+
});
61+
}, 'RTCIceCandidate.candidate is read-only');
62+
63+
// https://w3c.github.io/webrtc-pc/#dom-peerconnection-setlocaldescription
64+
// If type is "offer", and sdp is not the empty string and not equal to
65+
// connection.[[LastCreatedOffer]], then return a promise rejected with a
66+
// newly created InvalidModificationError and abort these steps.
67+
promise_test(async t => {
68+
const pc = new RTCPeerConnection();
69+
t.add_cleanup(() => pc.close());
70+
pc.addTransceiver('audio');
71+
const offer = await pc.createOffer();
72+
return promise_rejects_dom(t, 'InvalidModificationError',
73+
pc.setLocalDescription({type: 'offer', sdp: offer.sdp + 'a=munging-is-not-good\r\n'}));
74+
}, 'Rejects SDP munging between createOffer and setLocalDescription');
75+
76+
// If type is "answer" or "pranswer", and sdp is not the empty string and not equal to
77+
// connection.[[LastCreatedAnswer]], then return a promise rejected with a
78+
// newly created InvalidModificationError and abort these steps.
79+
promise_test(async t => {
80+
const pc = new RTCPeerConnection();
81+
t.add_cleanup(() => pc.close());
82+
await pc.setRemoteDescription({type: 'offer', sdp});
83+
84+
const answer = await pc.createAnswer();
85+
return promise_rejects_dom(t, 'InvalidModificationError',
86+
pc.setLocalDescription({type: 'answer', sdp: answer.sdp + 'a=munging-is-not-good\r\n'}));
87+
}, 'Rejects SDP munging between createAnswer and setLocalDescription');
88+
</script>

LayoutTests/imported/w3c/web-platform-tests/webrtc/legacy/onaddstream.https.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
<title>onaddstream tests</title>
44
<script src="/resources/testharness.js"></script>
55
<script src="/resources/testharnessreport.js"></script>
6+
<script src=/resources/testdriver.js></script>
7+
<script src=/resources/testdriver-vendor.js></script>
8+
<script src='/mediacapture-streams/permission-helper.js'></script>
69
<script>
710
'use strict';
811

@@ -90,6 +93,7 @@
9093
promise_test(async t => {
9194
const pc1 = new RTCPeerConnection();
9295
t.add_cleanup(() => pc1.close());
96+
await setMediaPermission();
9397
const stream1 = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
9498
t.add_cleanup(() => stopTracks(stream1));
9599
const audio1 = stream1.getAudioTracks()[0];
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5+
<title>RTCPeerConnection Connection Test</title>
6+
<script src="../RTCPeerConnection-helper.js"></script>
7+
</head>
8+
<body>
9+
<div id="log"></div>
10+
<div>
11+
<video id="local-view" muted autoplay="autoplay"></video>
12+
<video id="remote-view" muted autoplay="autoplay"></video>
13+
</div>
14+
15+
<!-- These files are in place when executing on W3C. -->
16+
<script src="/resources/testharness.js"></script>
17+
<script src="/resources/testharnessreport.js"></script>
18+
<script type="text/javascript">
19+
var test = async_test('Can set up a basic WebRTC call.');
20+
21+
var gFirstConnection = null;
22+
var gSecondConnection = null;
23+
24+
// if the remote video gets video data that implies the negotiation
25+
// as well as the ICE and DTLS connection are up.
26+
document.getElementById('remote-view')
27+
.addEventListener('loadedmetadata', function() {
28+
// Call negotiated: done.
29+
test.done();
30+
});
31+
32+
function getNoiseStreamOkCallback(localStream) {
33+
gFirstConnection = new RTCPeerConnection(null);
34+
test.add_cleanup(() => gFirstConnection.close());
35+
gFirstConnection.onicecandidate = onIceCandidateToFirst;
36+
localStream.getTracks().forEach(function(track) {
37+
gFirstConnection.addTrack(track, localStream);
38+
});
39+
gFirstConnection.createOffer(onOfferCreated, failed('createOffer'));
40+
41+
var videoTag = document.getElementById('local-view');
42+
videoTag.srcObject = localStream;
43+
};
44+
45+
var onOfferCreated = test.step_func(function(offer) {
46+
gFirstConnection.setLocalDescription(offer);
47+
48+
// This would normally go across the application's signaling solution.
49+
// In our case, the "signaling" is to call this function.
50+
receiveCall(offer.sdp);
51+
});
52+
53+
function receiveCall(offerSdp) {
54+
gSecondConnection = new RTCPeerConnection(null);
55+
test.add_cleanup(() => gSecondConnection.close());
56+
gSecondConnection.onicecandidate = onIceCandidateToSecond;
57+
gSecondConnection.ontrack = onRemoteTrack;
58+
59+
var parsedOffer = new RTCSessionDescription({ type: 'offer',
60+
sdp: offerSdp });
61+
gSecondConnection.setRemoteDescription(parsedOffer);
62+
63+
gSecondConnection.createAnswer(onAnswerCreated,
64+
failed('createAnswer'));
65+
};
66+
67+
var onAnswerCreated = test.step_func(function(answer) {
68+
gSecondConnection.setLocalDescription(answer);
69+
70+
// Similarly, this would go over the application's signaling solution.
71+
handleAnswer(answer.sdp);
72+
});
73+
74+
function handleAnswer(answerSdp) {
75+
var parsedAnswer = new RTCSessionDescription({ type: 'answer',
76+
sdp: answerSdp });
77+
gFirstConnection.setRemoteDescription(parsedAnswer);
78+
};
79+
80+
var onIceCandidateToFirst = test.step_func(function(event) {
81+
gSecondConnection.addIceCandidate(event.candidate);
82+
});
83+
84+
var onIceCandidateToSecond = test.step_func(function(event) {
85+
gFirstConnection.addIceCandidate(event.candidate);
86+
});
87+
88+
var onRemoteTrack = test.step_func(function(event) {
89+
var videoTag = document.getElementById('remote-view');
90+
if (!videoTag.srcObject) {
91+
videoTag.srcObject = event.streams[0];
92+
}
93+
});
94+
95+
// Returns a suitable error callback.
96+
function failed(function_name) {
97+
return test.unreached_func('WebRTC called error callback for ' + function_name);
98+
}
99+
100+
// This function starts the test.
101+
test.step(function() {
102+
getNoiseStream({ video: true, audio: true })
103+
.then(test.step_func(getNoiseStreamOkCallback), failed('getNoiseStream'));
104+
});
105+
</script>
106+
107+
</body>
108+
</html>

0 commit comments

Comments
 (0)