summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webrtc/RTCRtpParameters-helper.js
blob: dd8ae0cc06d28b29865e61c5365600cbed465f35 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
'use strict';

// Test is based on the following editor draft:
// https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html

// Helper function for testing RTCRtpParameters dictionary fields

// This file depends on dictionary-helper.js which should
// be loaded from the main HTML file.

// An offer/answer exchange is necessary for getParameters() to have any
// negotiated parameters to return.
async function doOfferAnswerExchange(t, caller) {
  const callee = new RTCPeerConnection();
  t.add_cleanup(() => callee.close());
  const offer = await caller.createOffer();
  await caller.setLocalDescription(offer);
  await callee.setRemoteDescription(offer);
  const answer = await callee.createAnswer();
  await callee.setLocalDescription(answer);
  await caller.setRemoteDescription(answer);

  return callee;
}

/*
  Validates the RTCRtpParameters returned from RTCRtpSender.prototype.getParameters

  5.2.  RTCRtpSender Interface
    getParameters
      - transactionId is set to a new unique identifier, used to match this getParameters
        call to a setParameters call that may occur later.

      - encodings is set to the value of the [[SendEncodings]] internal slot.

      - The headerExtensions sequence is populated based on the header extensions that
        have been negotiated for sending.

      - 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.

      - rtcp.cname is set to the CNAME of the associated RTCPeerConnection. rtcp.reducedSize
        is set to true if reduced-size RTCP has been negotiated for sending, and false otherwise.
 */
function validateSenderRtpParameters(param) {
  validateRtpParameters(param);

  assert_array_field(param, 'encodings');
  for(const encoding of param.encodings) {
    validateEncodingParameters(encoding);
  }

  assert_not_equals(param.transactionId, undefined,
    'Expect sender param.transactionId to be set');

  assert_not_equals(param.rtcp.cname, undefined,
    'Expect sender param.rtcp.cname to be set');

  assert_not_equals(param.rtcp.reducedSize, undefined,
    'Expect sender param.rtcp.reducedSize to be set to either true or false');
}

/*
  Validates the RTCRtpParameters returned from RTCRtpReceiver.prototype.getParameters

  5.3.  RTCRtpReceiver Interface
    getParameters
      When getParameters is called, the RTCRtpParameters dictionary is constructed
      as follows:

      - The headerExtensions sequence is populated based on the header extensions that
        the receiver is currently prepared to receive.

      - The codecs sequence is populated based on the codecs that the receiver is currently
        prepared to receive.

      - rtcp.reducedSize is set to true if the receiver is currently prepared to receive
        reduced-size RTCP packets, and false otherwise. rtcp.cname is left undefined.

      - transactionId is left undefined.
 */
function validateReceiverRtpParameters(param) {
  validateRtpParameters(param);

  assert_equals(param.transactionId, undefined,
    'Expect receiver param.transactionId to be unset');

  assert_not_equals(param.rtcp.reducedSize, undefined,
    'Expect receiver param.rtcp.reducedSize to be set');

  assert_equals(param.rtcp.cname, undefined,
    'Expect receiver param.rtcp.cname to be unset');
}

/*
  dictionary RTCRtpParameters {
    DOMString                                 transactionId;
    sequence<RTCRtpEncodingParameters>        encodings;
    sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
    RTCRtcpParameters                         rtcp;
    sequence<RTCRtpCodecParameters>           codecs;
  };

 */
function validateRtpParameters(param) {
  assert_optional_string_field(param, 'transactionId');

  assert_array_field(param, 'headerExtensions');
  for(const headerExt of param.headerExtensions) {
    validateHeaderExtensionParameters(headerExt);
  }

  assert_dict_field(param, 'rtcp');
  validateRtcpParameters(param.rtcp);

  assert_array_field(param, 'codecs');
  for(const codec of param.codecs) {
    validateCodecParameters(codec);
  }
}

/*
  dictionary RTCRtpEncodingParameters {
    boolean             active;
    unsigned long       maxBitrate;

    [readonly]
    DOMString           rid;

    double              scaleResolutionDownBy;
  };

 */
function validateEncodingParameters(encoding) {
  assert_optional_boolean_field(encoding, 'active');
  assert_optional_unsigned_int_field(encoding, 'maxBitrate');

  assert_optional_string_field(encoding, 'rid');
  assert_optional_number_field(encoding, 'scaleResolutionDownBy');
}

/*
  dictionary RTCRtcpParameters {
    [readonly]
    DOMString cname;

    [readonly]
    boolean   reducedSize;
  };
 */
function validateRtcpParameters(rtcp) {
  assert_optional_string_field(rtcp, 'cname');
  assert_optional_boolean_field(rtcp, 'reducedSize');
}

/*
  dictionary RTCRtpHeaderExtensionParameters {
    [readonly]
    DOMString      uri;

    [readonly]
    unsigned short id;

    [readonly]
    boolean        encrypted;
  };
 */
function validateHeaderExtensionParameters(headerExt) {
  assert_optional_string_field(headerExt, 'uri');
  assert_optional_unsigned_int_field(headerExt, 'id');
  assert_optional_boolean_field(headerExt, 'encrypted');
}

/*
  dictionary RTCRtpCodecParameters {
    [readonly]
    unsigned short payloadType;

    [readonly]
    DOMString      mimeType;

    [readonly]
    unsigned long  clockRate;

    [readonly]
    unsigned short channels;

    [readonly]
    DOMString      sdpFmtpLine;
  };
 */
function validateCodecParameters(codec) {
  assert_optional_unsigned_int_field(codec, 'payloadType');
  assert_optional_string_field(codec, 'mimeType');
  assert_optional_unsigned_int_field(codec, 'clockRate');
  assert_optional_unsigned_int_field(codec, 'channels');
  assert_optional_string_field(codec, 'sdpFmtpLine');
}

// Helper function to test that modifying an encoding field should succeed
function test_modified_encoding(kind, field, value1, value2, desc) {
  promise_test(async t => {
    const pc = new RTCPeerConnection();
    t.add_cleanup(() => pc.close());
    const {
      sender
    } = pc.addTransceiver(kind, {
      sendEncodings: [{
        [field]: value1
      }]
    });
    await doOfferAnswerExchange(t, pc);

    const param1 = sender.getParameters();
    validateSenderRtpParameters(param1);
    const encoding1 = param1.encodings[0];

    assert_equals(encoding1[field], value1);
    encoding1[field] = value2;

    await sender.setParameters(param1);
    const param2 = sender.getParameters();
    validateSenderRtpParameters(param2);
    const encoding2 = param2.encodings[0];
    assert_equals(encoding2[field], value2);
  }, desc + ' with RTCRtpTransceiverInit');

  promise_test(async t => {
    const pc = new RTCPeerConnection();
    t.add_cleanup(() => pc.close());
    const {
      sender
    } = pc.addTransceiver(kind);
    await doOfferAnswerExchange(t, pc);

    const initParam = sender.getParameters();
    validateSenderRtpParameters(initParam);
    initParam.encodings[0][field] = value1;
    await sender.setParameters(initParam);

    const param1 = sender.getParameters();
    validateSenderRtpParameters(param1);
    const encoding1 = param1.encodings[0];

    assert_equals(encoding1[field], value1);
    encoding1[field] = value2;

    await sender.setParameters(param1);
    const param2 = sender.getParameters();
    validateSenderRtpParameters(param2);
    const encoding2 = param2.encodings[0];
    assert_equals(encoding2[field], value2);
  }, desc + ' without RTCRtpTransceiverInit');
}