RTCPeerConnection-setDescription-transceiver.html (11249B)
1 <!doctype html> 2 <meta charset=utf-8> 3 <title>RTCPeerConnection Set Session Description - Transceiver Tests</title> 4 <script src="/resources/testharness.js"></script> 5 <script src="/resources/testharnessreport.js"></script> 6 <script src="RTCPeerConnection-helper.js"></script> 7 <script> 8 'use strict'; 9 10 // Test is based on the following editor draft: 11 // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html 12 13 // The following helper functions are called from RTCPeerConnection-helper.js: 14 // generateAnswer 15 16 /* 17 4.3.2. Interface Definition 18 19 [Constructor(optional RTCConfiguration configuration)] 20 interface RTCPeerConnection : EventTarget { 21 Promise<void> setLocalDescription( 22 RTCSessionDescriptionInit description); 23 24 Promise<void> setRemoteDescription( 25 RTCSessionDescriptionInit description); 26 ... 27 }; 28 29 4.6.2. RTCSessionDescription Class 30 dictionary RTCSessionDescriptionInit { 31 required RTCSdpType type; 32 DOMString sdp = ""; 33 }; 34 35 4.6.1. RTCSdpType 36 enum RTCSdpType { 37 "offer", 38 "pranswer", 39 "answer", 40 "rollback" 41 }; 42 43 5.4. RTCRtpTransceiver Interface 44 45 interface RTCRtpTransceiver { 46 readonly attribute DOMString? mid; 47 [SameObject] 48 readonly attribute RTCRtpSender sender; 49 [SameObject] 50 readonly attribute RTCRtpReceiver receiver; 51 readonly attribute RTCRtpTransceiverDirection direction; 52 readonly attribute RTCRtpTransceiverDirection? currentDirection; 53 ... 54 }; 55 */ 56 57 /* 58 4.3.1.6. Set the RTCSessionSessionDescription 59 7. If description is set as a local description, then run the following steps for 60 each media description in description that is not yet associated with an 61 RTCRtpTransceiver object: 62 1. Let transceiver be the RTCRtpTransceiver used to create the media 63 description. 64 2. Set transceiver's mid value to the mid of the corresponding media 65 description. 66 */ 67 promise_test(t => { 68 const pc = new RTCPeerConnection(); 69 t.add_cleanup(() => pc.close()); 70 const transceiver = pc.addTransceiver('audio'); 71 assert_equals(transceiver.mid, null); 72 73 return pc.createOffer() 74 .then(offer => { 75 assert_equals(transceiver.mid, null, 76 'Expect transceiver.mid to still be null after createOffer'); 77 78 return pc.setLocalDescription(offer) 79 .then(() => { 80 assert_equals(typeof transceiver.mid, 'string', 81 'Expect transceiver.mid to set to valid string value'); 82 83 assert_equals(offer.sdp.includes(`\r\na=mid:${transceiver.mid}`), true, 84 'Expect transceiver mid to be found in offer SDP'); 85 }); 86 }); 87 }, 'setLocalDescription(offer) with m= section should assign mid to corresponding transceiver'); 88 89 /* 90 4.3.1.6. Set the RTCSessionSessionDescription 91 8. If description is set as a remote description, then run the following steps 92 for each media description in description: 93 2. If no suitable transceiver is found (transceiver is unset), run the following 94 steps: 95 1. Create an RTCRtpSender, sender, from the media description. 96 2. Create an RTCRtpReceiver, receiver, from the media description. 97 3. Create an RTCRtpTransceiver with sender, receiver and direction, and let 98 transceiver be the result. 99 3. Set transceiver's mid value to the mid of the corresponding media description. 100 */ 101 promise_test(t => { 102 const pc1 = new RTCPeerConnection(); 103 t.add_cleanup(() => pc1.close()); 104 const pc2 = new RTCPeerConnection(); 105 106 t.add_cleanup(() => pc2.close()); 107 108 const transceiver1 = pc1.addTransceiver('audio'); 109 assert_array_equals(pc1.getTransceivers(), [transceiver1]); 110 assert_array_equals(pc2.getTransceivers(), []); 111 112 return pc1.createOffer() 113 .then(offer => { 114 return Promise.all([ 115 pc1.setLocalDescription(offer), 116 pc2.setRemoteDescription(offer) 117 ]) 118 .then(() => { 119 const transceivers = pc2.getTransceivers(); 120 assert_equals(transceivers.length, 1, 121 'Expect new transceiver added to pc2 after setRemoteDescription'); 122 123 const [ transceiver2 ] = transceivers; 124 125 assert_equals(typeof transceiver2.mid, 'string', 126 'Expect transceiver2.mid to be set'); 127 128 assert_equals(transceiver1.mid, transceiver2.mid, 129 'Expect transceivers of both side to have the same mid'); 130 131 assert_equals(offer.sdp.includes(`\r\na=mid:${transceiver2.mid}`), true, 132 'Expect transceiver mid to be found in offer SDP'); 133 }); 134 }); 135 }, 'setRemoteDescription(offer) with m= section and no existing transceiver should create corresponding transceiver'); 136 137 /* 138 4.3.1.6. Set the RTCSessionSessionDescription 139 9. If description is of type "rollback", then run the following steps: 140 1. If the mid value of an RTCRtpTransceiver was set to a non-null value by 141 the RTCSessionDescription that is being rolled back, set the mid value 142 of that transceiver to null, as described by [JSEP] (section 4.1.8.2.). 143 */ 144 promise_test(t => { 145 const pc = new RTCPeerConnection(); 146 t.add_cleanup(() => pc.close()); 147 const transceiver = pc.addTransceiver('audio'); 148 assert_equals(transceiver.mid, null); 149 150 return pc.createOffer() 151 .then(offer => { 152 assert_equals(transceiver.mid, null); 153 return pc.setLocalDescription(offer); 154 }) 155 .then(() => { 156 assert_not_equals(transceiver.mid, null); 157 return pc.setLocalDescription({ type: 'rollback' }); 158 }) 159 .then(() => { 160 assert_equals(transceiver.mid, null, 161 'Expect transceiver.mid to become null again after rollback'); 162 }); 163 }, 'setLocalDescription(rollback) should unset transceiver.mid'); 164 165 promise_test(t => { 166 const pc = new RTCPeerConnection(); 167 t.add_cleanup(() => pc.close()); 168 const transceiver1 = pc.addTransceiver('audio'); 169 assert_equals(transceiver1.mid, null); 170 171 return pc.createOffer() 172 .then(offer => 173 pc.setLocalDescription(offer) 174 .then(() => generateAnswer(offer))) 175 .then(answer => pc.setRemoteDescription(answer)) 176 .then(() => { 177 // pc is back to stable state 178 // create another transceiver 179 const transceiver2 = pc.addTransceiver('video'); 180 181 assert_not_equals(transceiver1.mid, null); 182 assert_equals(transceiver2.mid, null); 183 184 return pc.createOffer() 185 .then(offer => pc.setLocalDescription(offer)) 186 .then(() => { 187 assert_not_equals(transceiver1.mid, null); 188 assert_not_equals(transceiver2.mid, null, 189 'Expect transceiver2.mid to become set'); 190 191 return pc.setLocalDescription({ type: 'rollback' }); 192 }) 193 .then(() => { 194 assert_not_equals(transceiver1.mid, null, 195 'Expect transceiver1.mid to stay set'); 196 197 assert_equals(transceiver2.mid, null, 198 'Expect transceiver2.mid to be rolled back to null'); 199 }); 200 }) 201 }, 'setLocalDescription(rollback) should only unset transceiver mids associated with current round'); 202 203 /* 204 4.3.1.6. Set the RTCSessionSessionDescription 205 9. If description is of type "rollback", then run the following steps: 206 2. If an RTCRtpTransceiver was created by applying the RTCSessionDescription 207 that is being rolled back, and a track has not been attached to it via 208 addTrack, remove that transceiver from connection's set of transceivers, 209 as described by [JSEP] (section 4.1.8.2.). 210 */ 211 promise_test(t => { 212 const pc1 = new RTCPeerConnection(); 213 t.add_cleanup(() => pc1.close()); 214 const pc2 = new RTCPeerConnection(); 215 216 t.add_cleanup(() => pc2.close()); 217 218 pc1.addTransceiver('audio'); 219 220 return pc1.createOffer() 221 .then(offer => pc2.setRemoteDescription(offer)) 222 .then(() => { 223 const transceivers = pc2.getTransceivers(); 224 assert_equals(transceivers.length, 1); 225 const [ transceiver ] = transceivers; 226 227 assert_equals(typeof transceiver.mid, 'string', 228 'Expect transceiver.mid to be set'); 229 230 return pc2.setRemoteDescription({ type: 'rollback' }) 231 .then(() => { 232 assert_equals(transceiver.mid, null, 233 'Expect transceiver.mid to be unset'); 234 235 assert_array_equals(pc2.getTransceivers(), [], 236 `Expect transceiver to be removed from pc2's transceiver list`); 237 }); 238 }); 239 }, 'setRemoteDescription(rollback) should remove newly created transceiver from transceiver list'); 240 241 promise_test(async t => { 242 const pc1 = new RTCPeerConnection(); 243 t.add_cleanup(() => pc1.close()); 244 const pc2 = new RTCPeerConnection(); 245 t.add_cleanup(() => pc2.close()); 246 247 pc1.addTransceiver('audio'); 248 const offer = await pc1.createOffer(); 249 await pc1.setLocalDescription(offer); 250 251 await pc2.setRemoteDescription(offer); 252 pc2.getTransceivers()[0].stop(); 253 const answer = await pc2.createAnswer(); 254 255 await pc1.setRemoteDescription(answer); 256 257 assert_equals(pc1.getTransceivers()[0].currentDirection, 'inactive', 'A stopped m-line should give an inactive transceiver'); 258 }, 'setRemoteDescription should set transceiver inactive if its corresponding m section is rejected'); 259 260 /* 261 TODO 262 - Steps for transceiver direction is added to tip of tree draft, but not yet 263 published as editor's draft 264 265 4.3.1.6. Set the RTCSessionSessionDescription 266 8. If description is set as a remote description, then run the following steps 267 for each media description in description: 268 1. As described by [JSEP] (section 5.9.), attempt to find an existing 269 RTCRtpTransceiver object, transceiver, to represent the media description. 270 3. If the media description has no MID, and transceiver's mid is unset, generate 271 a random value as described in [JSEP] (section 5.9.). 272 4. If the direction of the media description is sendrecv or sendonly, and 273 transceiver.receiver.track has not yet been fired in a track event, process 274 the remote track for the media description, given transceiver. 275 5. If the media description is rejected, and transceiver is not already stopped, 276 stop the RTCRtpTransceiver transceiver. 277 278 [JSEP] 279 5.9. Applying a Remote Description 280 - If the m= section is not associated with any RtpTransceiver 281 (possibly because it was dissociated in the previous step), 282 either find an RtpTransceiver or create one according to the 283 following steps: 284 285 - If the m= section is sendrecv or recvonly, and there are 286 RtpTransceivers of the same type that were added to the 287 PeerConnection by addTrack and are not associated with any 288 m= section and are not stopped, find the first (according to 289 the canonical order described in Section 5.2.1) such 290 RtpTransceiver. 291 292 - If no RtpTransceiver was found in the previous step, create 293 one with a recvonly direction. 294 */ 295 </script>