| <!doctype html> | |
| <meta charset=utf-8> | |
| <title>RTCRtpParameters codecs</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.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; | |
| }; | |
| dictionary RTCRtpCodecParameters { | |
| [readonly] | |
| unsigned short payloadType; | |
| [readonly] | |
| DOMString mimeType; | |
| [readonly] | |
| unsigned long clockRate; | |
| [readonly] | |
| unsigned short channels; | |
| [readonly] | |
| DOMString sdpFmtpLine; | |
| }; | |
| getParameters | |
| - The codecs sequence is populated based on the codecs that have been negotiated | |
| for sending, and which the user agent is currently capable of sending. | |
| If setParameters has removed or reordered codecs, getParameters MUST return | |
| the shortened/reordered list. However, every time codecs are renegotiated by | |
| a new offer/answer exchange, the list of codecs MUST be restored to the full | |
| negotiated set, in the priority order indicated by the remote description, | |
| in effect discarding the effects of setParameters. | |
| codecs | |
| - When using the setParameters method, the codecs sequence from the corresponding | |
| call to getParameters can be reordered and entries can be removed, but entries | |
| cannot be added, and the RTCRtpCodecParameters dictionary members cannot be modified. | |
| */ | |
| // Get the first codec from param.codecs. | |
| // Assert that param.codecs has at least one element | |
| function getFirstCodec(param) { | |
| const { codecs } = param; | |
| assert_greater_than(codecs.length, 0); | |
| return codecs[0]; | |
| } | |
| /* | |
| 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 codec = getFirstCodec(param); | |
| if(codec.payloadType === undefined) { | |
| codec.payloadType = 8; | |
| } else { | |
| codec.payloadType += 1; | |
| } | |
| return promise_rejects_dom(t, 'InvalidModificationError', | |
| sender.setParameters(param)); | |
| }, 'setParameters() with codec.payloadType modified 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); | |
| const codec = getFirstCodec(param); | |
| if(codec.mimeType === undefined) { | |
| codec.mimeType = 'audio/piedpiper'; | |
| } else { | |
| codec.mimeType = `${codec.mimeType}-modified`; | |
| } | |
| return promise_rejects_dom(t, 'InvalidModificationError', | |
| sender.setParameters(param)); | |
| }, 'setParameters() with codec.mimeType modified 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); | |
| const codec = getFirstCodec(param); | |
| if(codec.clockRate === undefined) { | |
| codec.clockRate = 8000; | |
| } else { | |
| codec.clockRate += 1; | |
| } | |
| return promise_rejects_dom(t, 'InvalidModificationError', | |
| sender.setParameters(param)); | |
| }, 'setParameters() with codec.clockRate modified 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); | |
| const codec = getFirstCodec(param); | |
| if(codec.channels === undefined) { | |
| codec.channels = 6; | |
| } else { | |
| codec.channels += 1; | |
| } | |
| return promise_rejects_dom(t, 'InvalidModificationError', | |
| sender.setParameters(param)); | |
| }, 'setParameters() with codec.channels modified 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); | |
| const codec = getFirstCodec(param); | |
| if(codec.sdpFmtpLine === undefined) { | |
| codec.sdpFmtpLine = 'a=fmtp:98 0-15'; | |
| } else { | |
| codec.sdpFmtpLine = `${codec.sdpFmtpLine};foo=1`; | |
| } | |
| return promise_rejects_dom(t, 'InvalidModificationError', | |
| sender.setParameters(param)); | |
| }, 'setParameters() with codec.sdpFmtpLine modified 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); | |
| const { codecs } = param; | |
| codecs.push({ | |
| payloadType: 2, | |
| mimeType: 'audio/piedpiper', | |
| clockRate: 1000, | |
| channels: 2 | |
| }); | |
| return promise_rejects_dom(t, 'InvalidModificationError', | |
| sender.setParameters(param)); | |
| }, 'setParameters() with new codecs inserted should reject with InvalidModificationError'); | |
| </script> |