|  | <!doctype html> | 
|  | <meta charset=utf-8> | 
|  | <title>RTCRtpParameters transactionId</title> | 
|  | <script src="/resources/testharness.js"></script> | 
|  | <script src="/resources/testharnessreport.js"></script> | 
|  | <script src="dictionary-helper.js"></script> | 
|  | <script src="RTCRtpParameters-helper.js"></script> | 
|  | <script> | 
|  | 'use strict'; | 
|  |  | 
|  | // Test is based on the following editor draft: | 
|  | // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html | 
|  |  | 
|  | // The following helper functions are called from RTCRtpParameters-helper.js: | 
|  | // doOfferAnswerExchange | 
|  | // validateSenderRtpParameters | 
|  |  | 
|  | /* | 
|  | 5.1. RTCPeerConnection Interface Extensions | 
|  | partial interface RTCPeerConnection { | 
|  | RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind, | 
|  | optional RTCRtpTransceiverInit init); | 
|  | ... | 
|  | }; | 
|  |  | 
|  | dictionary RTCRtpTransceiverInit { | 
|  | RTCRtpTransceiverDirection direction = "sendrecv"; | 
|  | sequence<MediaStream> streams; | 
|  | sequence<RTCRtpEncodingParameters> sendEncodings; | 
|  | }; | 
|  |  | 
|  | addTransceiver | 
|  | 2. If the dictionary argument is present, and it has a sendEncodings member, | 
|  | let sendEncodings be that list of RTCRtpEncodingParameters objects, or an | 
|  | empty list otherwise. | 
|  | 7. Create an RTCRtpSender with track, streams and sendEncodings and let | 
|  | sender be the result. | 
|  |  | 
|  | 5.2. RTCRtpSender Interface | 
|  | interface RTCRtpSender { | 
|  | Promise<void> setParameters(optional RTCRtpParameters parameters); | 
|  | RTCRtpParameters getParameters(); | 
|  | }; | 
|  |  | 
|  | dictionary RTCRtpParameters { | 
|  | DOMString transactionId; | 
|  | sequence<RTCRtpEncodingParameters> encodings; | 
|  | sequence<RTCRtpHeaderExtensionParameters> headerExtensions; | 
|  | RTCRtcpParameters rtcp; | 
|  | sequence<RTCRtpCodecParameters> codecs; | 
|  | RTCDegradationPreference degradationPreference; | 
|  | }; | 
|  |  | 
|  | getParameters | 
|  | - transactionId is set to a new unique identifier, used to match this | 
|  | getParameters call to a setParameters call that may occur later. | 
|  | */ | 
|  |  | 
|  | /* | 
|  | 5.2. getParameters | 
|  | - transactionId is set to a new unique identifier, used to match this | 
|  | getParameters call to a setParameters call that may occur later. | 
|  | */ | 
|  | promise_test(async t => { | 
|  | const pc = new RTCPeerConnection(); | 
|  | t.add_cleanup(() => pc.close()); | 
|  | const { sender } = pc.addTransceiver('audio'); | 
|  | await doOfferAnswerExchange(t, pc); | 
|  |  | 
|  | const param1 = sender.getParameters(); | 
|  | const param2 = sender.getParameters(); | 
|  |  | 
|  | validateSenderRtpParameters(param1); | 
|  | validateSenderRtpParameters(param2); | 
|  |  | 
|  | assert_not_equals(param1.transactionId, param2.transactionId); | 
|  | }, `sender.getParameters() should return different transaction IDs for each call`); | 
|  |  | 
|  | /* | 
|  | 5.2. setParameters | 
|  | 7. If parameters.encodings.length is different from N, or if any parameter | 
|  | in the parameters argument, marked as a Read-only parameter, has a value | 
|  | that is different from the corresponding parameter value returned from | 
|  | sender.getParameters(), abort these steps and return a promise rejected | 
|  | with a newly created InvalidModificationError. Note that this also applies | 
|  | to transactionId. | 
|  | */ | 
|  | promise_test(async t => { | 
|  | const pc = new RTCPeerConnection(); | 
|  | t.add_cleanup(() => pc.close()); | 
|  | const { sender } = pc.addTransceiver('audio'); | 
|  | await doOfferAnswerExchange(t, pc); | 
|  |  | 
|  | const param = sender.getParameters(); | 
|  | validateSenderRtpParameters(param); | 
|  |  | 
|  | const { transactionId } = param; | 
|  | param.transactionId = `${transactionId}-modified`; | 
|  |  | 
|  | return promise_rejects(t, 'InvalidModificationError', | 
|  | sender.setParameters(param)); | 
|  | }, `sender.setParameters() with transaction ID different from last getParameters() should reject with InvalidModificationError`); | 
|  |  | 
|  | promise_test(async t => { | 
|  | const pc = new RTCPeerConnection(); | 
|  | t.add_cleanup(() => pc.close()); | 
|  | const { sender } = pc.addTransceiver('audio'); | 
|  | await doOfferAnswerExchange(t, pc); | 
|  |  | 
|  | const param = sender.getParameters(); | 
|  | validateSenderRtpParameters(param); | 
|  |  | 
|  | param.transactionId = undefined; | 
|  |  | 
|  | return promise_rejects_js(t, TypeError, | 
|  | sender.setParameters(param)); | 
|  | }, `sender.setParameters() with transaction ID unset should reject with TypeError`); | 
|  |  | 
|  | promise_test(async t => { | 
|  | const pc = new RTCPeerConnection(); | 
|  | t.add_cleanup(() => pc.close()); | 
|  | const { sender } = pc.addTransceiver('audio'); | 
|  | await doOfferAnswerExchange(t, pc); | 
|  |  | 
|  | const param = sender.getParameters(); | 
|  | validateSenderRtpParameters(param); | 
|  |  | 
|  | return sender.setParameters(param) | 
|  | .then(() => | 
|  | promise_rejects(t, 'InvalidStateError', | 
|  | sender.setParameters(param))); | 
|  | }, `setParameters() twice with the same parameters should reject with InvalidStateError`); | 
|  |  | 
|  | promise_test(async t => { | 
|  | const pc = new RTCPeerConnection(); | 
|  | t.add_cleanup(() => pc.close()); | 
|  | const { sender } = pc.addTransceiver('audio'); | 
|  | await doOfferAnswerExchange(t, pc); | 
|  |  | 
|  | const param1 = sender.getParameters(); | 
|  | const param2 = sender.getParameters(); | 
|  |  | 
|  | validateSenderRtpParameters(param1); | 
|  | validateSenderRtpParameters(param2); | 
|  |  | 
|  | assert_not_equals(param1.transactionId, param2.transactionId); | 
|  |  | 
|  | return promise_rejects(t, 'InvalidModificationError', | 
|  | sender.setParameters(param1)); | 
|  | }, `setParameters() with parameters older than last getParameters() should reject with InvalidModificationError`); | 
|  |  | 
|  | </script> |