RTCPeerConnection methods can take dictionaries as input
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 31 Jan 2017 17:52:33 +0000 (17:52 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 31 Jan 2017 17:52:33 +0000 (17:52 +0000)
https://bugs.webkit.org/show_bug.cgi?id=167590

Patch by Youenn Fablet <youenn@apple.com> on 2017-01-31
Reviewed by Alex Christensen.

Source/WebCore:

Test: webrtc/rtcpeerconnection-error-messages.html

Made addIceCandidate/setRemoteDescription/setLocalDescription take either dictionaries or objects as parameter.
Spec only mandates this for addIceCandidate, but sites may be using the old version for setRemoteDescription and setLocalDescription.

Updated RTCPeerConnection methods error messages.

* Modules/mediastream/RTCPeerConnection.js:
(getLocalStreams):
(getStreamById):
(addStream):
(createOffer):
(createAnswer):
(setLocalDescription):
(setRemoteDescription):
(addIceCandidate):
(getStats):
* Modules/mediastream/RTCPeerConnectionInternals.js:

LayoutTests:

Replacing fast/mediastream/RTCPeerConnection-js-built-ins-check-this.html by webrtc/rtcpeerconnection-error-messages.html.
It is a bit more thorough and does not hard code the error message.

* fast/mediastream/RTCPeerConnection-addIceCandidate-expected.txt:
* fast/mediastream/RTCPeerConnection-addIceCandidate.html:
* fast/mediastream/RTCPeerConnection-js-built-ins-check-this-expected.txt: Removed.
* fast/mediastream/RTCPeerConnection-js-built-ins-check-this.html: Removed.
* fast/mediastream/RTCPeerConnection-setLocalDescription-offer-expected.txt:
* fast/mediastream/RTCPeerConnection-setLocalDescription-offer.html:
* fast/mediastream/RTCPeerConnection-setRemoteDescription-offer-expected.txt:
* fast/mediastream/RTCPeerConnection-setRemoteDescription-offer.html:
* webrtc/rtcpeerconnection-error-messages-expected.txt: Added.
* webrtc/rtcpeerconnection-error-messages.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@211436 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/mediastream/RTCPeerConnection-addIceCandidate-expected.txt
LayoutTests/fast/mediastream/RTCPeerConnection-addIceCandidate.html
LayoutTests/fast/mediastream/RTCPeerConnection-js-built-ins-check-this-expected.txt [deleted file]
LayoutTests/fast/mediastream/RTCPeerConnection-js-built-ins-check-this.html [deleted file]
LayoutTests/fast/mediastream/RTCPeerConnection-setLocalDescription-offer-expected.txt
LayoutTests/fast/mediastream/RTCPeerConnection-setLocalDescription-offer.html
LayoutTests/fast/mediastream/RTCPeerConnection-setRemoteDescription-offer-expected.txt
LayoutTests/fast/mediastream/RTCPeerConnection-setRemoteDescription-offer.html
LayoutTests/webrtc/rtcpeerconnection-error-messages-expected.txt [new file with mode: 0644]
LayoutTests/webrtc/rtcpeerconnection-error-messages.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/Modules/mediastream/RTCPeerConnection.js
Source/WebCore/Modules/mediastream/RTCPeerConnectionInternals.js

index 7ebbb9d..7515550 100644 (file)
@@ -1,3 +1,24 @@
+2017-01-31  Youenn Fablet  <youenn@apple.com>
+
+        RTCPeerConnection methods can take dictionaries as input
+        https://bugs.webkit.org/show_bug.cgi?id=167590
+
+        Reviewed by Alex Christensen.
+
+        Replacing fast/mediastream/RTCPeerConnection-js-built-ins-check-this.html by webrtc/rtcpeerconnection-error-messages.html.
+        It is a bit more thorough and does not hard code the error message.
+
+        * fast/mediastream/RTCPeerConnection-addIceCandidate-expected.txt:
+        * fast/mediastream/RTCPeerConnection-addIceCandidate.html:
+        * fast/mediastream/RTCPeerConnection-js-built-ins-check-this-expected.txt: Removed.
+        * fast/mediastream/RTCPeerConnection-js-built-ins-check-this.html: Removed.
+        * fast/mediastream/RTCPeerConnection-setLocalDescription-offer-expected.txt:
+        * fast/mediastream/RTCPeerConnection-setLocalDescription-offer.html:
+        * fast/mediastream/RTCPeerConnection-setRemoteDescription-offer-expected.txt:
+        * fast/mediastream/RTCPeerConnection-setRemoteDescription-offer.html:
+        * webrtc/rtcpeerconnection-error-messages-expected.txt: Added.
+        * webrtc/rtcpeerconnection-error-messages.html: Added.
+
 2017-01-31  Chris Dumez  <cdumez@apple.com>
 
         Add better test coverage for scripting windows opened via window.open()
index 70f9cfa..d41c940 100644 (file)
@@ -23,7 +23,7 @@ PASS promise pc.addIceCandidate(new RTCIceCandidate({candidate: 'bad content', s
 PASS promise pc.addIceCandidate(new RTCIceCandidate({candidate: 'bad content', sdpMLineIndex: sdpMLineIndex})) rejected with OperationError (DOM Exception 34): Invalid candidate content
 
 *** Test some OK input
-PASS promise pc.addIceCandidate(new RTCIceCandidate({candidate: validCandidate, sdpMid: sdpMid})) fulfilled with undefined
+PASS promise pc.addIceCandidate({candidate: validCandidate, sdpMid: sdpMid}) fulfilled with undefined
 PASS promise pc.addIceCandidate(new RTCIceCandidate({candidate: validCandidate, sdpMLineIndex: sdpMLineIndex})) fulfilled with undefined
 *** A valid sdpMid takes precedesce over a bad sdpMLineIndex
 PASS promise pc.addIceCandidate(new RTCIceCandidate({candidate: validCandidate, sdpMid: sdpMid, sdpMLineIndex: badSdpMLineIndex})) fulfilled with undefined
index a45dd92..9f383ff 100644 (file)
             })
             .then(function () {
                 debug("<br>*** Test some OK input");
-                return promiseShouldResolve("pc.addIceCandidate(new RTCIceCandidate({candidate: validCandidate, sdpMid: sdpMid}))");
+                // Testing passing a RTCIceCandidateInit
+                return promiseShouldResolve("pc.addIceCandidate({candidate: validCandidate, sdpMid: sdpMid})");
             })
             .then(function () {
+                // Testing passing a RTCIceCandidate
                 return promiseShouldResolve("pc.addIceCandidate(new RTCIceCandidate({candidate: validCandidate, sdpMLineIndex: sdpMLineIndex}))");
             })
             .then(function () {
diff --git a/LayoutTests/fast/mediastream/RTCPeerConnection-js-built-ins-check-this-expected.txt b/LayoutTests/fast/mediastream/RTCPeerConnection-js-built-ins-check-this-expected.txt
deleted file mode 100644 (file)
index 589fefd..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-Verify that the RTCPeerConnection JS built-in methods check calling 'this'
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS promise RTCPeerConnection.prototype.createOffer.call({}) rejected with TypeError: Function should be called on an RTCPeerConnection
-PASS promise RTCPeerConnection.prototype.createAnswer.call({}) rejected with TypeError: Function should be called on an RTCPeerConnection
-PASS promise RTCPeerConnection.prototype.setLocalDescription.call({}) rejected with TypeError: Function should be called on an RTCPeerConnection
-PASS promise RTCPeerConnection.prototype.setRemoteDescription.call({}) rejected with TypeError: Function should be called on an RTCPeerConnection
-PASS promise RTCPeerConnection.prototype.addIceCandidate.call({}) rejected with TypeError: Function should be called on an RTCPeerConnection
-FAIL promise RTCPeerConnection.prototype.getStats.call({}, null) rejected with TypeError: Can only call RTCPeerConnection.getStats on instances of RTCPeerConnection; expected reason TypeError: Function should be called on an RTCPeerConnection
-PASS promise objectWithPcPrototype.createOffer() rejected with TypeError: Function should be called on an RTCPeerConnection
-PASS promise objectWithPcPrototype.createAnswer() rejected with TypeError: Function should be called on an RTCPeerConnection
-PASS promise objectWithPcPrototype.setLocalDescription() rejected with TypeError: Function should be called on an RTCPeerConnection
-PASS promise objectWithPcPrototype.setRemoteDescription() rejected with TypeError: Function should be called on an RTCPeerConnection
-PASS promise objectWithPcPrototype.addIceCandidate() rejected with TypeError: Function should be called on an RTCPeerConnection
-FAIL promise objectWithPcPrototype.getStats() rejected with TypeError: Can only call RTCPeerConnection.getStats on instances of RTCPeerConnection; expected reason TypeError: Function should be called on an RTCPeerConnection
-PASS End of test promise chain
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/LayoutTests/fast/mediastream/RTCPeerConnection-js-built-ins-check-this.html b/LayoutTests/fast/mediastream/RTCPeerConnection-js-built-ins-check-this.html
deleted file mode 100644 (file)
index 0def683..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <script src="../../resources/js-test-pre.js"></script>
-        <script src="resources/promise-utils.js"></script>
-    </head>
-    <body>
-        <script>
-            description("Verify that the RTCPeerConnection JS built-in methods check calling 'this'");
-
-            const reason = "TypeError: Function should be called on an RTCPeerConnection";
-
-            function Foo() {}
-            Foo.prototype = RTCPeerConnection.prototype;
-            let objectWithPcPrototype = new Foo();
-
-            promiseShouldReject("RTCPeerConnection.prototype.createOffer.call({})", "reason")
-            .then(() => promiseShouldReject("RTCPeerConnection.prototype.createAnswer.call({})", "reason"))
-            .then(() => promiseShouldReject("RTCPeerConnection.prototype.setLocalDescription.call({})", "reason"))
-            .then(() => promiseShouldReject("RTCPeerConnection.prototype.setRemoteDescription.call({})", "reason"))
-            .then(() => promiseShouldReject("RTCPeerConnection.prototype.addIceCandidate.call({})", "reason"))
-            .then(() => promiseShouldReject("RTCPeerConnection.prototype.getStats.call({}, null)", "reason"))
-
-            .then(() => promiseShouldReject("objectWithPcPrototype.createOffer()", "reason"))
-            .then(() => promiseShouldReject("objectWithPcPrototype.createAnswer()", "reason"))
-            .then(() => promiseShouldReject("objectWithPcPrototype.setLocalDescription()", "reason"))
-            .then(() => promiseShouldReject("objectWithPcPrototype.setRemoteDescription()", "reason"))
-            .then(() => promiseShouldReject("objectWithPcPrototype.addIceCandidate()", "reason"))
-            .then(() => promiseShouldReject("objectWithPcPrototype.getStats()", "reason"))
-
-            .then(() => {
-                testPassed("End of test promise chain");
-                finishJSTest();
-            })
-            .catch(error => {
-                testFailed("Error in promise chain: " + error);
-                finishJSTest();
-            });
-
-            window.jsTestIsAsync = true;
-            window.successfullyParsed = true;
-
-        </script>
-        <script src="../../resources/js-test-post.js"></script>
-    </body>
-</html>
index e09011f..c479b2d 100644 (file)
@@ -31,8 +31,8 @@ PASS firstOffer set as local description (again)
 PASS pc.signalingState is 'have-local-offer'
 
 *** Try setting local descriptions with bad types for the current state
-PASS promise pc.setLocalDescription(new RTCSessionDescription({type:'answer', sdp:firstOffer.sdp})); rejected with InvalidStateError (DOM Exception 11): Description type incompatible with current signaling state
-PASS promise pc.setLocalDescription(new RTCSessionDescription({type:'pranswer', sdp:firstOffer.sdp})); rejected with InvalidStateError (DOM Exception 11): Description type incompatible with current signaling state
+PASS promise pc.setLocalDescription({type:'answer', sdp:firstOffer.sdp}); rejected with InvalidStateError (DOM Exception 11): Description type incompatible with current signaling state
+PASS promise pc.setLocalDescription({type:'pranswer', sdp:firstOffer.sdp}); rejected with InvalidStateError (DOM Exception 11): Description type incompatible with current signaling state
 
 *** Add videoTrack
 PASS pc.getTransceivers().length is 2
index 1274d8f..001a56d 100644 (file)
                 debug("");
 
                 debug("*** Try setting local descriptions with bad types for the current state");
-                return promiseShouldReject("pc.setLocalDescription(new RTCSessionDescription({type:'answer', sdp:firstOffer.sdp}));");
+                return promiseShouldReject("pc.setLocalDescription({type:'answer', sdp:firstOffer.sdp});");
             })
             .then(function () {
-                return promiseShouldReject("pc.setLocalDescription(new RTCSessionDescription({type:'pranswer', sdp:firstOffer.sdp}));");
+                return promiseShouldReject("pc.setLocalDescription({type:'pranswer', sdp:firstOffer.sdp});");
             })
             .then(function () {
                 debug("");
index 40a7688..1b75679 100644 (file)
@@ -33,8 +33,8 @@ PASS remoteOffer1 set as remote description (again)
 PASS pc.signalingState is 'have-remote-offer'
 
 *** Try setting local descriptions with bad types for the current state
-PASS promise pc.setRemoteDescription(new RTCSessionDescription({type:'answer', sdp:remoteOffer1.sdp})); rejected with InvalidStateError (DOM Exception 11): Description type incompatible with current signaling state
-PASS promise pc.setRemoteDescription(new RTCSessionDescription({type:'pranswer', sdp:remoteOffer1.sdp})); rejected with InvalidStateError (DOM Exception 11): Description type incompatible with current signaling state
+PASS promise pc.setRemoteDescription({type:'answer', sdp:remoteOffer1.sdp}); rejected with InvalidStateError (DOM Exception 11): Description type incompatible with current signaling state
+PASS promise pc.setRemoteDescription({type:'pranswer', sdp:remoteOffer1.sdp}); rejected with InvalidStateError (DOM Exception 11): Description type incompatible with current signaling state
 
 *** Create (remote) offer with video (remoteOffer2)
 *** Done, start testing with remoteOffer2
index df91a62..17549a5 100644 (file)
                 debug("");
 
                 debug("*** Try setting local descriptions with bad types for the current state");
-                return promiseShouldReject("pc.setRemoteDescription(new RTCSessionDescription({type:'answer', sdp:remoteOffer1.sdp}));");
+                return promiseShouldReject("pc.setRemoteDescription({type:'answer', sdp:remoteOffer1.sdp});");
             })
             .then(function () {
-                return promiseShouldReject("pc.setRemoteDescription(new RTCSessionDescription({type:'pranswer', sdp:remoteOffer1.sdp}));");
+                return promiseShouldReject("pc.setRemoteDescription({type:'pranswer', sdp:remoteOffer1.sdp});");
             })
             .then(function () {
                 debug("");
diff --git a/LayoutTests/webrtc/rtcpeerconnection-error-messages-expected.txt b/LayoutTests/webrtc/rtcpeerconnection-error-messages-expected.txt
new file mode 100644 (file)
index 0000000..0b07728
--- /dev/null
@@ -0,0 +1,30 @@
+TypeError: The RTCPeerConnection.localDescription getter can only be used on instances of RTCPeerConnection
+TypeError: The RTCPeerConnection.currentLocalDescription getter can only be used on instances of RTCPeerConnection
+TypeError: The RTCPeerConnection.pendingLocalDescription getter can only be used on instances of RTCPeerConnection
+TypeError: The RTCPeerConnection.remoteDescription getter can only be used on instances of RTCPeerConnection
+TypeError: The RTCPeerConnection.currentRemoteDescription getter can only be used on instances of RTCPeerConnection
+TypeError: The RTCPeerConnection.pendingRemoteDescription getter can only be used on instances of RTCPeerConnection
+TypeError: The RTCPeerConnection.signalingState getter can only be used on instances of RTCPeerConnection
+TypeError: The RTCPeerConnection.iceGatheringState getter can only be used on instances of RTCPeerConnection
+TypeError: The RTCPeerConnection.iceConnectionState getter can only be used on instances of RTCPeerConnection
+[object RTCPeerConnection] has no property named connectionState
+[object RTCPeerConnection] has no property named canTrickleIceCandidates
+[object RTCPeerConnection] has no property named defaultIceServers
+TypeError: Can only call RTCPeerConnection.getConfiguration on instances of RTCPeerConnection
+TypeError: Can only call RTCPeerConnection.setConfiguration on instances of RTCPeerConnection
+TypeError: Can only call RTCPeerConnection.close on instances of RTCPeerConnection
+TypeError: The RTCPeerConnection.onnegotiationneeded getter can only be used on instances of RTCPeerConnection
+TypeError: The RTCPeerConnection.onicecandidate getter can only be used on instances of RTCPeerConnection
+[object RTCPeerConnection] has no property named onicecandidateerror
+TypeError: The RTCPeerConnection.onsignalingstatechange getter can only be used on instances of RTCPeerConnection
+TypeError: The RTCPeerConnection.oniceconnectionstatechange getter can only be used on instances of RTCPeerConnection
+TypeError: The RTCPeerConnection.onicegatheringstatechange getter can only be used on instances of RTCPeerConnection
+[object RTCPeerConnection] has no property named onconnectionstatechange
+Promise rejected with: TypeError: Can only call RTCPeerConnection.createOffer on instances of RTCPeerConnection
+Promise rejected with: TypeError: Can only call RTCPeerConnection.createAnswer on instances of RTCPeerConnection
+Promise rejected with: TypeError: Can only call RTCPeerConnection.setLocalDescription on instances of RTCPeerConnection
+Promise rejected with: TypeError: Can only call RTCPeerConnection.setRemoteDescription on instances of RTCPeerConnection
+Promise rejected with: TypeError: Can only call RTCPeerConnection.addIceCandidate on instances of RTCPeerConnection
+
+PASS Exercising TypeError messages in RTCPeerConnection 
+
diff --git a/LayoutTests/webrtc/rtcpeerconnection-error-messages.html b/LayoutTests/webrtc/rtcpeerconnection-error-messages.html
new file mode 100644 (file)
index 0000000..83c64e6
--- /dev/null
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<div id="log"></div>
+<script src='../resources/testharness.js'></script>
+<script src='../resources/testharnessreport.js'></script>
+<script>
+function log(msg)
+{
+    document.getElementById("log").innerHTML += msg + "<br>";
+}
+
+function printMethodError(method, target)
+{
+    try {
+        method.call(target);
+        assert_unreached();
+    } catch(e) {
+         log(e);
+    }
+}
+
+function printPromiseMethodError(method, target)
+{
+    return method.call(target).then(assert_unreached, (e) => {
+         log("Promise rejected with: " + e);
+    });
+}
+
+function printGetterError(object, getterName, target)
+{
+    const property = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(object), getterName);
+    if (property  === undefined) {
+        log(object + " has no property named " + getterName);
+        return;
+    }
+    printMethodError(property.get, target);
+}
+
+promise_test(function(test) {
+    // This test prints exceptions to check the format of their messages.
+
+    var pc = new RTCPeerConnection();
+    var candidate = new RTCIceCandidate({ candidate: "foo", sdpMid: "bar" });
+
+    var results = [
+        printPromiseMethodError(pc.createOffer, candidate),
+        printPromiseMethodError(pc.createAnswer, candidate),
+        printPromiseMethodError(pc.setLocalDescription, candidate),
+        printPromiseMethodError(pc.setRemoteDescription, candidate),
+        printPromiseMethodError(pc.addIceCandidate, candidate),
+
+        printGetterError(pc, "localDescription", candidate),
+        printGetterError(pc, "currentLocalDescription", candidate),
+        printGetterError(pc, "pendingLocalDescription", candidate),
+        printGetterError(pc, "remoteDescription", candidate),
+        printGetterError(pc, "currentRemoteDescription", candidate),
+        printGetterError(pc, "pendingRemoteDescription", candidate),
+        printGetterError(pc, "signalingState", candidate),
+        printGetterError(pc, "iceGatheringState", candidate),
+        printGetterError(pc, "iceConnectionState", candidate),
+        printGetterError(pc, "connectionState", candidate),
+        printGetterError(pc, "canTrickleIceCandidates", candidate),
+        printGetterError(pc, "defaultIceServers", candidate),
+
+        printMethodError(pc.getConfiguration, candidate),
+        printMethodError(pc.setConfiguration, candidate),
+        printMethodError(pc.close, candidate),
+
+        printGetterError(pc, "onnegotiationneeded", candidate),
+        printGetterError(pc, "onicecandidate", candidate),
+        printGetterError(pc, "onicecandidateerror", candidate),
+        printGetterError(pc, "onsignalingstatechange", candidate),
+        printGetterError(pc, "oniceconnectionstatechange", candidate),
+        printGetterError(pc, "onicegatheringstatechange", candidate),
+        printGetterError(pc, "onconnectionstatechange", candidate),
+    ];
+    return Promise.all(results);
+}, "Exercising TypeError messages in RTCPeerConnection");
+</script>
index ce103c3..893e207 100644 (file)
@@ -1,3 +1,29 @@
+2017-01-31  Youenn Fablet  <youenn@apple.com>
+
+        RTCPeerConnection methods can take dictionaries as input
+        https://bugs.webkit.org/show_bug.cgi?id=167590
+
+        Reviewed by Alex Christensen.
+
+        Test: webrtc/rtcpeerconnection-error-messages.html
+
+        Made addIceCandidate/setRemoteDescription/setLocalDescription take either dictionaries or objects as parameter.
+        Spec only mandates this for addIceCandidate, but sites may be using the old version for setRemoteDescription and setLocalDescription.
+
+        Updated RTCPeerConnection methods error messages.
+
+        * Modules/mediastream/RTCPeerConnection.js:
+        (getLocalStreams):
+        (getStreamById):
+        (addStream):
+        (createOffer):
+        (createAnswer):
+        (setLocalDescription):
+        (setRemoteDescription):
+        (addIceCandidate):
+        (getStats):
+        * Modules/mediastream/RTCPeerConnectionInternals.js:
+
 2017-01-31  Simon Fraser  <simon.fraser@apple.com>
 
         REGRESSION (r209411): Scrolling to a fragment identifier in overflow:scroll inside position:fixed no longer works
index 51023f1..cbe7c56 100644 (file)
@@ -58,7 +58,7 @@ function getLocalStreams()
     "use strict";
 
     if (!@isRTCPeerConnection(this))
-        @throwTypeError("Function should be called on an RTCPeerConnection");
+        throw @makeThisTypeError("RTCPeerConnection", "getLocalStreams");
 
     return this.@localStreams.slice();
 }
@@ -68,7 +68,7 @@ function getStreamById(streamIdArg)
     "use strict";
 
     if (!@isRTCPeerConnection(this))
-        @throwTypeError("Function should be called on an RTCPeerConnection");
+        throw @makeThisTypeError("RTCPeerConnection", "getStreamById");
 
     if (arguments.length < 1)
         @throwTypeError("Not enough arguments");
@@ -85,7 +85,7 @@ function addStream(stream)
     "use strict";
 
     if (!@isRTCPeerConnection(this))
-        @throwTypeError("Function should be called on an RTCPeerConnection");
+        throw @makeThisTypeError("RTCPeerConnection", "addStream");
 
     if (arguments.length < 1)
         @throwTypeError("Not enough arguments");
@@ -105,7 +105,7 @@ function removeStream(stream)
     "use strict";
 
     if (!@isRTCPeerConnection(this))
-        @throwTypeError("Function should be called on an RTCPeerConnection");
+        throw @makeThisTypeError("RTCPeerConnection", "removeStream");
 
     if (arguments.length < 1)
         @throwTypeError("Not enough arguments");
@@ -132,7 +132,7 @@ function createOffer()
     "use strict";
 
     if (!@isRTCPeerConnection(this))
-        return @Promise.@reject(new @TypeError("Function should be called on an RTCPeerConnection"));
+        return @Promise.@reject(@makeThisTypeError("RTCPeerConnection", "createOffer"));
 
     const peerConnection = this;
 
@@ -156,7 +156,7 @@ function createAnswer()
     "use strict";
 
     if (!@isRTCPeerConnection(this))
-        return @Promise.@reject(new @TypeError("Function should be called on an RTCPeerConnection"));
+        return @Promise.@reject(@makeThisTypeError("RTCPeerConnection", "createAnswer"));
 
     const peerConnection = this;
 
@@ -180,14 +180,16 @@ function setLocalDescription()
     "use strict";
 
     if (!@isRTCPeerConnection(this))
-        return @Promise.@reject(new @TypeError("Function should be called on an RTCPeerConnection"));
+        return @Promise.@reject(@makeThisTypeError("RTCPeerConnection", "setLocalDescription"));
 
     const peerConnection = this;
 
+    // FIXME: According the spec, we should throw when receiving a RTCSessionDescription.
     const objectInfo = {
         "constructor": @RTCSessionDescription,
         "argName": "description",
-        "argType": "RTCSessionDescription"
+        "argType": "RTCSessionDescription",
+        "maybeDictionary": "true"
     };
     return @objectAndCallbacksOverload(arguments, "setLocalDescription", objectInfo, function (description) {
         // Promise mode
@@ -209,14 +211,16 @@ function setRemoteDescription()
     "use strict";
 
     if (!@isRTCPeerConnection(this))
-        return @Promise.@reject(new @TypeError("Function should be called on an RTCPeerConnection"));
+        return @Promise.@reject(@makeThisTypeError("RTCPeerConnection", "setRemoteDescription"));
 
     const peerConnection = this;
 
+    // FIXME: According the spec, we should throw when receiving a RTCSessionDescription.
     const objectInfo = {
         "constructor": @RTCSessionDescription,
         "argName": "description",
-        "argType": "RTCSessionDescription"
+        "argType": "RTCSessionDescription",
+        "maybeDictionary": "true"
     };
     return @objectAndCallbacksOverload(arguments, "setRemoteDescription", objectInfo, function (description) {
         // Promise mode
@@ -238,14 +242,15 @@ function addIceCandidate()
     "use strict";
 
     if (!@isRTCPeerConnection(this))
-        return @Promise.@reject(new @TypeError("Function should be called on an RTCPeerConnection"));
+        return @Promise.@reject(@makeThisTypeError("RTCPeerConnection", "addIceCandidate"));
 
     const peerConnection = this;
 
     const objectInfo = {
         "constructor": @RTCIceCandidate,
         "argName": "candidate",
-        "argType": "RTCIceCandidate"
+        "argType": "RTCIceCandidate",
+        "maybeDictionary": "true"
     };
     return @objectAndCallbacksOverload(arguments, "addIceCandidate", objectInfo, function (candidate) {
         // Promise mode
index 3cd6dd2..498d4f8 100644 (file)
@@ -71,7 +71,18 @@ function objectAndCallbacksOverload(args, functionName, objectInfo, promiseMode,
         argsCount = 1;
     } else {
         const hasMatchingType = objectArg instanceof objectInfo.constructor;
-        objectArgOk = objectInfo.defaultsToNull ? (objectArg === null || typeof objectArg === "undefined" || hasMatchingType) : hasMatchingType;
+        if (hasMatchingType)
+            objectArgOk = true;
+        else if (objectInfo.defaultsToNull)
+            objectArgOk = objectArg === null || typeof objectArg === "undefined";
+        else if (objectInfo.maybeDictionary) {
+            try {
+                objectArg = new objectInfo.constructor(objectArg);
+                objectArgOk = true;
+            } catch (e) {
+                objectArgOk = false;
+            }
+        }
     }
 
     if (!objectArgOk)