| Soares Chen | 0042ebb | 2017-06-05 13:42:06 | [diff] [blame] | 1 | <!doctype html> | 
|  | 2 | <meta charset=utf-8> | 
|  | 3 | <title>RTCPeerConnection.prototype.addTransceiver</title> | 
|  | 4 | <script src="/resources/testharness.js"></script> | 
|  | 5 | <script src="/resources/testharnessreport.js"></script> | 
| Soares Chen | 607f71c | 2017-06-27 15:23:37 | [diff] [blame] | 6 | <script src="RTCPeerConnection-helper.js"></script> | 
| Soares Chen | 0042ebb | 2017-06-05 13:42:06 | [diff] [blame] | 7 | <script> | 
|  | 8 | 'use strict'; | 
|  | 9 |  | 
|  | 10 | // Test is based on the following editor draft: | 
| Soares Chen | 7d2c2d7 | 2017-06-21 05:09:36 | [diff] [blame] | 11 | // https://rawgit.com/w3c/webrtc-pc/cc8d80f455b86c8041d63bceb8b457f45c72aa89/webrtc.html | 
| Soares Chen | 607f71c | 2017-06-27 15:23:37 | [diff] [blame] | 12 |  | 
| Soares Chen | 7d2c2d7 | 2017-06-21 05:09:36 | [diff] [blame] | 13 | // The following helper functions are called from RTCPeerConnection-helper.js: | 
|  | 14 | // generateMediaStreamTrack() | 
| Soares Chen | 0042ebb | 2017-06-05 13:42:06 | [diff] [blame] | 15 |  | 
|  | 16 | /* | 
| Soares Chen | 7d2c2d7 | 2017-06-21 05:09:36 | [diff] [blame] | 17 | 5.1. RTCPeerConnection Interface Extensions | 
|  | 18 |  | 
|  | 19 | partial interface RTCPeerConnection { | 
|  | 20 | sequence<RTCRtpSender> getSenders(); | 
|  | 21 | sequence<RTCRtpReceiver> getReceivers(); | 
|  | 22 | sequence<RTCRtpTransceiver> getTransceivers(); | 
|  | 23 | RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind, | 
|  | 24 | optional RTCRtpTransceiverInit init); | 
|  | 25 | ... | 
|  | 26 | }; | 
|  | 27 |  | 
|  | 28 | dictionary RTCRtpTransceiverInit { | 
|  | 29 | RTCRtpTransceiverDirection direction = "sendrecv"; | 
|  | 30 | sequence<MediaStream> streams; | 
|  | 31 | sequence<RTCRtpEncodingParameters> sendEncodings; | 
|  | 32 | }; | 
|  | 33 |  | 
| Soares Chen | e01045d | 2017-06-21 05:16:19 | [diff] [blame] | 34 | enum RTCRtpTransceiverDirection { | 
|  | 35 | "sendrecv", | 
|  | 36 | "sendonly", | 
|  | 37 | "recvonly", | 
|  | 38 | "inactive" | 
|  | 39 | }; | 
|  | 40 |  | 
| Soares Chen | 7d2c2d7 | 2017-06-21 05:09:36 | [diff] [blame] | 41 | 5.2. RTCRtpSender Interface | 
|  | 42 |  | 
|  | 43 | interface RTCRtpSender { | 
|  | 44 | readonly attribute MediaStreamTrack? track; | 
|  | 45 | ... | 
|  | 46 | }; | 
|  | 47 |  | 
|  | 48 | 5.3. RTCRtpReceiver Interface | 
|  | 49 |  | 
|  | 50 | interface RTCRtpReceiver { | 
|  | 51 | readonly attribute MediaStreamTrack track; | 
|  | 52 | ... | 
|  | 53 | }; | 
|  | 54 |  | 
|  | 55 | 5.4. RTCRtpTransceiver Interface | 
|  | 56 |  | 
|  | 57 | interface RTCRtpTransceiver { | 
|  | 58 | readonly attribute DOMString? mid; | 
|  | 59 | [SameObject] | 
|  | 60 | readonly attribute RTCRtpSender sender; | 
|  | 61 | [SameObject] | 
|  | 62 | readonly attribute RTCRtpReceiver receiver; | 
|  | 63 | readonly attribute boolean stopped; | 
|  | 64 | readonly attribute RTCRtpTransceiverDirection direction; | 
|  | 65 | readonly attribute RTCRtpTransceiverDirection? currentDirection; | 
|  | 66 | ... | 
|  | 67 | }; | 
| Soares Chen | 607f71c | 2017-06-27 15:23:37 | [diff] [blame] | 68 |  | 
|  | 69 | Note | 
|  | 70 | While addTrack checks if the MediaStreamTrack given as an argument is | 
|  | 71 | already being sent to avoid sending the same MediaStreamTrack twice, | 
|  | 72 | the other ways do not, allowing the same MediaStreamTrack to be sent | 
|  | 73 | several times simultaneously. | 
| Soares Chen | 0042ebb | 2017-06-05 13:42:06 | [diff] [blame] | 74 | */ | 
|  | 75 |  | 
|  | 76 | /* | 
| Soares Chen | 7d2c2d7 | 2017-06-21 05:09:36 | [diff] [blame] | 77 | 5.1. addTransceiver | 
|  | 78 | 3. If the first argument is a string, let it be kind and run the following steps: | 
|  | 79 | 1. If kind is not a legal MediaStreamTrack kind, throw a TypeError. | 
|  | 80 | */ | 
|  | 81 | test(t => { | 
|  | 82 | const pc = new RTCPeerConnection(); | 
| Soares Chen | 172fe9d | 2017-07-18 09:30:18 | [diff] [blame^] | 83 | assert_idl_attribute(pc, 'addTransceiver'); | 
| Soares Chen | 7d2c2d7 | 2017-06-21 05:09:36 | [diff] [blame] | 84 | assert_throws(new TypeError(), () => pc.addTransceiver('invalid')); | 
|  | 85 | }, 'addTransceiver() with string argument as invalid kind should throw TypeError'); | 
|  | 86 |  | 
|  | 87 | /* | 
|  | 88 | 5.1. addTransceiver | 
|  | 89 | The initial value of mid is null. | 
|  | 90 |  | 
|  | 91 | 3. If the dictionary argument is present, let direction be the value of the | 
|  | 92 | direction member. Otherwise let direction be sendrecv. | 
|  | 93 | 4. If the first argument is a string, let it be kind and run the following steps: | 
|  | 94 | 2. Let track be null. | 
|  | 95 | 8. Create an RTCRtpSender with track, streams and sendEncodings and let | 
|  | 96 | sender be the result. | 
|  | 97 | 9. Create an RTCRtpReceiver with kind and let receiver be the result. | 
|  | 98 | 10. Create an RTCRtpTransceiver with sender, receiver and direction, and let | 
|  | 99 | transceiver be the result. | 
|  | 100 | 11. Add transceiver to connection's set of transceivers. | 
|  | 101 |  | 
|  | 102 | 5.2. RTCRtpSender Interface | 
|  | 103 | Create an RTCRtpSender | 
|  | 104 | 2. Set sender.track to track. | 
|  | 105 |  | 
|  | 106 | 5.3. RTCRtpReceiver Interface | 
|  | 107 | Create an RTCRtpReceiver | 
|  | 108 | 2. Let track be a new MediaStreamTrack object [GETUSERMEDIA]. The source of | 
|  | 109 | track is a remote source provided by receiver. | 
|  | 110 | 3. Initialize track.kind to kind. | 
|  | 111 | 5. Initialize track.label to the result of concatenating the string "remote " | 
|  | 112 | with kind. | 
|  | 113 | 6. Initialize track.readyState to live. | 
|  | 114 | 7. Initialize track.muted to true. | 
|  | 115 | 8. Set receiver.track to track. | 
|  | 116 |  | 
|  | 117 | 5.4. RTCRtpTransceiver Interface | 
|  | 118 | Create an RTCRtpTransceiver | 
|  | 119 | 2. Set transceiver.sender to sender. | 
|  | 120 | 3. Set transceiver.receiver to receiver. | 
|  | 121 | 4. Let transceiver have a [[Direction]] internal slot, initialized to direction. | 
|  | 122 | 5. Let transceiver have a [[CurrentDirection]] internal slot, initialized | 
|  | 123 | to null. | 
|  | 124 | 6. Set transceiver.stopped to false. | 
| Soares Chen | 0042ebb | 2017-06-05 13:42:06 | [diff] [blame] | 125 | */ | 
|  | 126 | test(t => { | 
|  | 127 | const pc = new RTCPeerConnection(); | 
|  | 128 |  | 
| Soares Chen | 172fe9d | 2017-07-18 09:30:18 | [diff] [blame^] | 129 | assert_idl_attribute(pc, 'addTransceiver'); | 
| Soares Chen | 0042ebb | 2017-06-05 13:42:06 | [diff] [blame] | 130 |  | 
|  | 131 | const transceiver = pc.addTransceiver('audio'); | 
|  | 132 | assert_true(transceiver instanceof RTCRtpTransceiver, | 
|  | 133 | 'Expect transceiver to be instance of RTCRtpTransceiver'); | 
|  | 134 |  | 
|  | 135 | assert_equals(transceiver.mid, null); | 
|  | 136 | assert_equals(transceiver.stopped, false); | 
|  | 137 | assert_equals(transceiver.direction, 'sendrecv'); | 
| Soares Chen | 7d2c2d7 | 2017-06-21 05:09:36 | [diff] [blame] | 138 | assert_equals(transceiver.currentDirection, null); | 
| Soares Chen | 0042ebb | 2017-06-05 13:42:06 | [diff] [blame] | 139 |  | 
|  | 140 | assert_array_equals([transceiver], pc.getTransceivers(), | 
|  | 141 | `Expect added transceiver to be the only element in connection's list of transceivers`); | 
|  | 142 |  | 
|  | 143 | const sender = transceiver.sender; | 
|  | 144 |  | 
|  | 145 | assert_true(sender instanceof RTCRtpSender, | 
|  | 146 | 'Expect sender to be instance of RTCRtpSender'); | 
|  | 147 |  | 
|  | 148 | assert_equals(sender.track, null); | 
|  | 149 |  | 
|  | 150 | assert_array_equals([sender], pc.getSenders(), | 
|  | 151 | `Expect added sender to be the only element in connection's list of senders`); | 
|  | 152 |  | 
|  | 153 | const receiver = transceiver.receiver; | 
|  | 154 | assert_true(receiver instanceof RTCRtpReceiver, | 
|  | 155 | 'Expect receiver to be instance of RTCRtpReceiver'); | 
|  | 156 |  | 
| Soares Chen | 172fe9d | 2017-07-18 09:30:18 | [diff] [blame^] | 157 | const track = receiver.track; | 
| Soares Chen | 0042ebb | 2017-06-05 13:42:06 | [diff] [blame] | 158 | assert_true(track instanceof MediaStreamTrack, | 
|  | 159 | 'Expect receiver.track to be instance of MediaStreamTrack'); | 
|  | 160 |  | 
|  | 161 | assert_equals(track.kind, 'audio'); | 
|  | 162 | assert_equals(track.label, 'remote audio'); | 
|  | 163 | assert_equals(track.readyState, 'live'); | 
|  | 164 | assert_equals(track.muted, true); | 
|  | 165 |  | 
|  | 166 | assert_array_equals([receiver], pc.getReceivers(), | 
|  | 167 | `Expect added receiver to be the only element in connection's list of receivers`); | 
|  | 168 |  | 
|  | 169 | }, `addTransceiver('audio') should return an audio transceiver`); | 
|  | 170 |  | 
|  | 171 | test(t => { | 
|  | 172 | const pc = new RTCPeerConnection(); | 
|  | 173 |  | 
| Soares Chen | 172fe9d | 2017-07-18 09:30:18 | [diff] [blame^] | 174 | assert_idl_attribute(pc, 'addTransceiver'); | 
| Soares Chen | 0042ebb | 2017-06-05 13:42:06 | [diff] [blame] | 175 |  | 
|  | 176 | const transceiver = pc.addTransceiver('video'); | 
|  | 177 | assert_true(transceiver instanceof RTCRtpTransceiver, | 
|  | 178 | 'Expect transceiver to be instance of RTCRtpTransceiver'); | 
|  | 179 |  | 
|  | 180 | assert_equals(transceiver.mid, null); | 
|  | 181 | assert_equals(transceiver.stopped, false); | 
|  | 182 | assert_equals(transceiver.direction, 'sendrecv'); | 
|  | 183 |  | 
|  | 184 | assert_array_equals([transceiver], pc.getTransceivers(), | 
|  | 185 | `Expect added transceiver to be the only element in connection's list of transceivers`); | 
|  | 186 |  | 
|  | 187 | const sender = transceiver.sender; | 
|  | 188 |  | 
|  | 189 | assert_true(sender instanceof RTCRtpSender, | 
|  | 190 | 'Expect sender to be instance of RTCRtpSender'); | 
|  | 191 |  | 
|  | 192 | assert_equals(sender.track, null); | 
|  | 193 |  | 
|  | 194 | assert_array_equals([sender], pc.getSenders(), | 
|  | 195 | `Expect added sender to be the only element in connection's list of senders`); | 
|  | 196 |  | 
|  | 197 | const receiver = transceiver.receiver; | 
|  | 198 | assert_true(receiver instanceof RTCRtpReceiver, | 
|  | 199 | 'Expect receiver to be instance of RTCRtpReceiver'); | 
|  | 200 |  | 
| Soares Chen | 172fe9d | 2017-07-18 09:30:18 | [diff] [blame^] | 201 | const track = receiver.track; | 
| Soares Chen | 0042ebb | 2017-06-05 13:42:06 | [diff] [blame] | 202 | assert_true(track instanceof MediaStreamTrack, | 
|  | 203 | 'Expect receiver.track to be instance of MediaStreamTrack'); | 
|  | 204 |  | 
|  | 205 | assert_equals(track.kind, 'video'); | 
|  | 206 | assert_equals(track.label, 'remote video'); | 
|  | 207 | assert_equals(track.readyState, 'live'); | 
|  | 208 | assert_equals(track.muted, true); | 
|  | 209 |  | 
|  | 210 | assert_array_equals([receiver], pc.getReceivers(), | 
|  | 211 | `Expect added receiver to be the only element in connection's list of receivers`); | 
|  | 212 |  | 
|  | 213 | }, `addTransceiver('video') should return a video transceiver`); | 
|  | 214 |  | 
| Soares Chen | e01045d | 2017-06-21 05:16:19 | [diff] [blame] | 215 | test(t => { | 
|  | 216 | const pc = new RTCPeerConnection(); | 
|  | 217 | const transceiver = pc.addTransceiver('audio', { direction: 'sendonly' }); | 
|  | 218 | assert_equals(transceiver.direction, 'sendonly'); | 
|  | 219 | }, `addTransceiver() with direction sendonly should have result transceiver.direction be the same`); | 
|  | 220 |  | 
|  | 221 | test(t => { | 
|  | 222 | const pc = new RTCPeerConnection(); | 
|  | 223 | const transceiver = pc.addTransceiver('audio', { direction: 'inactive' }); | 
|  | 224 | assert_equals(transceiver.direction, 'inactive'); | 
|  | 225 | }, `addTransceiver() with direction inactive should have result transceiver.direction be the same`); | 
|  | 226 |  | 
|  | 227 | test(t => { | 
|  | 228 | const pc = new RTCPeerConnection(); | 
| Soares Chen | 172fe9d | 2017-07-18 09:30:18 | [diff] [blame^] | 229 | assert_idl_attribute(pc, 'addTransceiver'); | 
| Soares Chen | e01045d | 2017-06-21 05:16:19 | [diff] [blame] | 230 | assert_throws(new TypeError(), () => | 
|  | 231 | pc.addTransceiver('audio', { direction: 'invalid' })); | 
|  | 232 | }, `addTransceiver() with invalid direction should throw TypeError`); | 
|  | 233 |  | 
| Soares Chen | 0042ebb | 2017-06-05 13:42:06 | [diff] [blame] | 234 | /* | 
| Soares Chen | 607f71c | 2017-06-27 15:23:37 | [diff] [blame] | 235 | 5.1. addTransceiver | 
| Soares Chen | 7d2c2d7 | 2017-06-21 05:09:36 | [diff] [blame] | 236 | 5. If the first argument is a MediaStreamTrack , let it be track and let | 
| Soares Chen | 607f71c | 2017-06-27 15:23:37 | [diff] [blame] | 237 | kind be track.kind. | 
| Soares Chen | 607f71c | 2017-06-27 15:23:37 | [diff] [blame] | 238 | */ | 
|  | 239 | test(t => { | 
|  | 240 | const pc = new RTCPeerConnection(); | 
|  | 241 | const track = generateMediaStreamTrack('audio'); | 
|  | 242 |  | 
|  | 243 | const transceiver = pc.addTransceiver(track); | 
|  | 244 | const { sender, receiver } = transceiver; | 
|  | 245 |  | 
|  | 246 | assert_true(sender instanceof RTCRtpSender, | 
|  | 247 | 'Expect sender to be instance of RTCRtpSender'); | 
|  | 248 |  | 
|  | 249 | assert_true(receiver instanceof RTCRtpReceiver, | 
|  | 250 | 'Expect receiver to be instance of RTCRtpReceiver'); | 
|  | 251 |  | 
|  | 252 | assert_equals(sender.track, track, | 
|  | 253 | 'Expect sender.track should be the track that is added'); | 
|  | 254 |  | 
| Soares Chen | 172fe9d | 2017-07-18 09:30:18 | [diff] [blame^] | 255 | const receiverTrack = receiver.track; | 
| Soares Chen | 607f71c | 2017-06-27 15:23:37 | [diff] [blame] | 256 | assert_true(receiverTrack instanceof MediaStreamTrack, | 
|  | 257 | 'Expect receiver.track to be instance of MediaStreamTrack'); | 
|  | 258 |  | 
|  | 259 | assert_equals(receiverTrack.kind, 'audio', | 
|  | 260 | `receiver.track should have the same kind as added track's kind`); | 
|  | 261 |  | 
|  | 262 | assert_equals(receiverTrack.label, 'remote audio'); | 
|  | 263 | assert_equals(receiverTrack.readyState, 'live'); | 
|  | 264 | assert_equals(receiverTrack.muted, true); | 
|  | 265 |  | 
|  | 266 | assert_array_equals([transceiver], pc.getTransceivers(), | 
|  | 267 | `Expect added transceiver to be the only element in connection's list of transceivers`); | 
|  | 268 |  | 
|  | 269 | assert_array_equals([sender], pc.getSenders(), | 
|  | 270 | `Expect added sender to be the only element in connection's list of senders`); | 
|  | 271 |  | 
|  | 272 | assert_array_equals([receiver], pc.getReceivers(), | 
|  | 273 | `Expect added receiver to be the only element in connection's list of receivers`); | 
|  | 274 |  | 
|  | 275 | }, 'addTransceiver(track) should have result with sender.track be given track'); | 
|  | 276 |  | 
|  | 277 | test(t => { | 
|  | 278 | const pc = new RTCPeerConnection(); | 
|  | 279 | const track = generateMediaStreamTrack('audio'); | 
|  | 280 |  | 
|  | 281 | const transceiver1 = pc.addTransceiver(track); | 
|  | 282 | const transceiver2 = pc.addTransceiver(track); | 
|  | 283 |  | 
|  | 284 | assert_not_equals(transceiver1, transceiver2); | 
|  | 285 |  | 
|  | 286 | const sender1 = transceiver1.sender; | 
|  | 287 | const sender2 = transceiver2.sender; | 
|  | 288 |  | 
|  | 289 | assert_not_equals(sender1, sender2); | 
|  | 290 | assert_equals(transceiver1.sender.track, track); | 
|  | 291 | assert_equals(transceiver2.sender.track, track); | 
|  | 292 |  | 
|  | 293 | const transceivers = pc.getTransceivers(); | 
|  | 294 | assert_equals(transceivers.length, 2); | 
|  | 295 | assert_true(transceivers.includes(transceiver1)); | 
|  | 296 | assert_true(transceivers.includes(transceiver2)); | 
|  | 297 |  | 
|  | 298 | const senders = pc.getSenders(); | 
|  | 299 | assert_equals(senders.length, 2); | 
|  | 300 | assert_true(senders.includes(sender1)); | 
|  | 301 | assert_true(senders.includes(sender2)); | 
|  | 302 |  | 
|  | 303 | }, 'addTransceiver(track) multiple times should create multiple transceivers'); | 
|  | 304 |  | 
| Soares Chen | 172fe9d | 2017-07-18 09:30:18 | [diff] [blame^] | 305 |  | 
|  | 306 | /* | 
|  | 307 | 5.1. addTransceiver | 
|  | 308 | 6. Verify that each rid value in sendEncodings is composed only of | 
|  | 309 | case-sensitive alphanumeric characters (a-z, A-Z, 0-9) up to a maximum | 
|  | 310 | of 16 characters. If one of the RIDs does not meet these requirements, | 
|  | 311 | throw a TypeError. | 
|  | 312 | */ | 
|  | 313 | test(() => { | 
|  | 314 | const pc = new RTCPeerConnection(); | 
|  | 315 | assert_idl_attribute(pc, 'addTransceiver'); | 
|  | 316 |  | 
|  | 317 | assert_throws(new TypeError(), () => | 
|  | 318 | pc.addTransceiver('audio', { | 
|  | 319 | sendEncodings: [{ | 
|  | 320 | rid: '@Invalid!' | 
|  | 321 | }] | 
|  | 322 | })); | 
|  | 323 | }, 'addTransceiver() with rid containing invalid non-alphanumeric characters should throw TypeError'); | 
|  | 324 |  | 
|  | 325 | test(() => { | 
|  | 326 | const pc = new RTCPeerConnection(); | 
|  | 327 | assert_idl_attribute(pc, 'addTransceiver'); | 
|  | 328 |  | 
|  | 329 | assert_throws(new TypeError(), () => | 
|  | 330 | pc.addTransceiver('audio', { | 
|  | 331 | sendEncodings: [{ | 
|  | 332 | rid: 'a'.repeat(17) | 
|  | 333 | }] | 
|  | 334 | })); | 
|  | 335 | }, 'addTransceiver() with rid longer than 16 characters should throw TypeError'); | 
|  | 336 |  | 
|  | 337 | test(() => { | 
|  | 338 | const pc = new RTCPeerConnection(); | 
|  | 339 | pc.addTransceiver('audio', { | 
|  | 340 | sendEncodings: [{ | 
|  | 341 | rid: 'foo' | 
|  | 342 | }] | 
|  | 343 | }); | 
|  | 344 | }, `addTransceiver() with valid rid value should succeed`); | 
|  | 345 |  | 
|  | 346 | /* | 
|  | 347 | 5.1. addTransceiver | 
|  | 348 | 7. If any RTCRtpEncodingParameters dictionary in sendEncodings contains a | 
|  | 349 | read-only parameter other than rid, throw an InvalidAccessError. | 
|  | 350 |  | 
|  | 351 | - The sendEncodings argument can be used to specify the number of offered | 
|  | 352 | simulcast encodings, and optionally their RIDs and encoding parameters. | 
|  | 353 | Aside from rid , all read-only parameters in the RTCRtpEncodingParameters | 
|  | 354 | dictionaries, such as ssrc, must be left unset, or an error will be thrown. | 
|  | 355 | */ | 
|  | 356 | test(() => { | 
|  | 357 | const pc = new RTCPeerConnection(); | 
|  | 358 |  | 
|  | 359 | assert_throws('InvalidAccessError', () => | 
|  | 360 | pc.addTransceiver('audio', { | 
|  | 361 | sendEncodings: [{ | 
|  | 362 | ssrc: 2 | 
|  | 363 | }] | 
|  | 364 | })); | 
|  | 365 | }, `addTransceiver() with readonly ssrc set should throw InvalidAccessError`); | 
|  | 366 |  | 
|  | 367 | test(() => { | 
|  | 368 | const pc = new RTCPeerConnection(); | 
|  | 369 |  | 
|  | 370 | assert_throws('InvalidAccessError', () => | 
|  | 371 | pc.addTransceiver('audio', { | 
|  | 372 | sendEncodings: [{ | 
|  | 373 | rtx: { | 
|  | 374 | ssrc: 2 | 
|  | 375 | } | 
|  | 376 | }] | 
|  | 377 | })); | 
|  | 378 | }, `addTransceiver() with readonly rtx set should throw InvalidAccessError`); | 
|  | 379 |  | 
|  | 380 | test(() => { | 
|  | 381 | const pc = new RTCPeerConnection(); | 
|  | 382 |  | 
|  | 383 | assert_throws('InvalidAccessError', () => | 
|  | 384 | pc.addTransceiver('audio', { | 
|  | 385 | sendEncodings: [{ | 
|  | 386 | fec: { | 
|  | 387 | ssrc: 2 | 
|  | 388 | } | 
|  | 389 | }] | 
|  | 390 | })); | 
|  | 391 | }, `addTransceiver() with readonly fec set should throw InvalidAccessError`); | 
|  | 392 |  | 
|  | 393 | test(() => { | 
|  | 394 | const pc = new RTCPeerConnection(); | 
|  | 395 | pc.addTransceiver('audio', { | 
|  | 396 | sendEncodings: [{ | 
|  | 397 | dtx: 'enabled', | 
|  | 398 | active: false, | 
|  | 399 | priority: 'low', | 
|  | 400 | ptime: 5, | 
|  | 401 | maxBitrate: 8, | 
|  | 402 | maxFramerate: 25, | 
|  | 403 | rid: 'foo' | 
|  | 404 | }] | 
|  | 405 | }); | 
|  | 406 | }, `addTransceiver() with valid sendEncodings should succeed`); | 
|  | 407 |  | 
| Soares Chen | 607f71c | 2017-06-27 15:23:37 | [diff] [blame] | 408 | /* | 
|  | 409 | TODO | 
|  | 410 | 5.1. addTransceiver | 
| Soares Chen | 7d2c2d7 | 2017-06-21 05:09:36 | [diff] [blame] | 411 | - Adding a transceiver will cause future calls to createOffer to add a media | 
|  | 412 | description for the corresponding transceiver, as defined in [JSEP] | 
|  | 413 | (section 5.2.2.). | 
| Soares Chen | 607f71c | 2017-06-27 15:23:37 | [diff] [blame] | 414 |  | 
| Soares Chen | 7d2c2d7 | 2017-06-21 05:09:36 | [diff] [blame] | 415 | - Setting a new RTCSessionDescription may change mid to a non-null value, | 
|  | 416 | as defined in [JSEP] (section 5.5. and section 5.6.). | 
|  | 417 |  | 
| Soares Chen | 607f71c | 2017-06-27 15:23:37 | [diff] [blame] | 418 | 1. If the dictionary argument is present, and it has a streams member, let | 
|  | 419 | streams be that list of MediaStream objects. | 
| Soares Chen | 7d2c2d7 | 2017-06-21 05:09:36 | [diff] [blame] | 420 |  | 
| Soares Chen | 7d2c2d7 | 2017-06-21 05:09:36 | [diff] [blame] | 421 | 5.2. RTCRtpSender Interface | 
|  | 422 | Create an RTCRtpSender | 
|  | 423 | 3. Let sender have an [[associated MediaStreams]] internal slot, representing | 
|  | 424 | a list of MediaStream objects that the MediaStreamTrack object of this | 
|  | 425 | sender is associated with. | 
|  | 426 |  | 
|  | 427 | 4. Set sender's [[associated MediaStreams]] slot to streams. | 
|  | 428 |  | 
|  | 429 | 5. Let sender have a [[send encodings]] internal slot, representing a list | 
|  | 430 | of RTCRtpEncodingParameters dictionaries. | 
|  | 431 |  | 
|  | 432 | 6. If sendEncodings is given as input to this algorithm, and is non-empty, | 
|  | 433 | set the [[send encodings]] slot to sendEncodings. Otherwise, set it to a | 
|  | 434 | list containing a single RTCRtpEncodingParameters with active set to true. | 
|  | 435 |  | 
|  | 436 | 5.3. RTCRtpReceiver Interface | 
|  | 437 | Create an RTCRtpReceiver | 
|  | 438 | 4. If an id string, id, was given as input to this algorithm, initialize | 
|  | 439 | track.id to id. (Otherwise the value generated when track was created | 
|  | 440 | will be used.) | 
|  | 441 |  | 
|  | 442 | Tested in RTCPeerConnection-onnegotiationneeded.html | 
|  | 443 | 5.1. addTransceiver | 
|  | 444 | 12. Update the negotiation-needed flag for connection. | 
|  | 445 |  | 
|  | 446 | Out of Scope | 
|  | 447 | 5.1. addTransceiver | 
|  | 448 | 8. If sendEncodings is set, then subsequent calls to createOffer will be | 
| Soares Chen | 607f71c | 2017-06-27 15:23:37 | [diff] [blame] | 449 | configured to send multiple RTP encodings as defined in [JSEP] | 
| Soares Chen | 7d2c2d7 | 2017-06-21 05:09:36 | [diff] [blame] | 450 | (section 5.2.2. and section 5.2.1.). | 
|  | 451 |  | 
|  | 452 | When setRemoteDescription is called with a corresponding remote | 
|  | 453 | description that is able to receive multiple RTP encodings as defined | 
|  | 454 | in [JSEP] (section 3.7.), the RTCRtpSender may send multiple RTP | 
|  | 455 | encodings and the parameters retrieved via the transceiver's | 
|  | 456 | sender.getParameters() will reflect the encodings negotiated. | 
|  | 457 |  | 
|  | 458 | 9. This specification does not define how to configure createOffer to | 
| Soares Chen | 607f71c | 2017-06-27 15:23:37 | [diff] [blame] | 459 | receive multiple RTP encodings. However when setRemoteDescription is | 
|  | 460 | called with a corresponding remote description that is able to send | 
|  | 461 | multiple RTP encodings as defined in [JSEP], the RTCRtpReceiver may | 
|  | 462 | receive multiple RTP encodings and the parameters retrieved via the | 
|  | 463 | transceiver's receiver.getParameters() will reflect the encodings | 
|  | 464 | negotiated. | 
| Soares Chen | 607f71c | 2017-06-27 15:23:37 | [diff] [blame] | 465 |  | 
| Soares Chen | 7d2c2d7 | 2017-06-21 05:09:36 | [diff] [blame] | 466 | Coverage Report | 
|  | 467 | Tested Not-Tested Non-Testable Total | 
| Soares Chen | 172fe9d | 2017-07-18 09:30:18 | [diff] [blame^] | 468 | addTransceiver 14 1 3 18 | 
| Soares Chen | 7d2c2d7 | 2017-06-21 05:09:36 | [diff] [blame] | 469 | Create Sender 3 4 0 7 | 
|  | 470 | Create Receiver 8 1 0 9 | 
|  | 471 | Create Transceiver 7 0 0 7 | 
| Soares Chen | 607f71c | 2017-06-27 15:23:37 | [diff] [blame] | 472 |  | 
| Soares Chen | 172fe9d | 2017-07-18 09:30:18 | [diff] [blame^] | 473 | Total 32 6 3 41 | 
| Soares Chen | 607f71c | 2017-06-27 15:23:37 | [diff] [blame] | 474 | */ | 
| Soares Chen | 0042ebb | 2017-06-05 13:42:06 | [diff] [blame] | 475 | </script> |