tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

RTCPeerConnection-transceivers.https.html (24770B)


      1 <!doctype html>
      2 <meta name="timeout" content="long"/>
      3 <meta charset=utf-8>
      4 <title>RTCPeerConnection-transceivers.https.html</title>
      5 <script src="/resources/testharness.js"></script>
      6 <script src="/resources/testharnessreport.js"></script>
      7 <script src="RTCPeerConnection-helper.js"></script>
      8 <script>
      9 'use strict';
     10 
     11 // The following helper functions are called from RTCPeerConnection-helper.js:
     12 //   exchangeOffer
     13 //   exchangeOfferAndListenToOntrack
     14 //   exchangeAnswer
     15 //   exchangeAnswerAndListenToOntrack
     16 //   addEventListenerPromise
     17 //   createPeerConnectionWithCleanup
     18 //   createTrackAndStreamWithCleanup
     19 //   findTransceiverForSender
     20 
     21 promise_test(async t => {
     22  const pc = createPeerConnectionWithCleanup(t);
     23  const [track, stream] = await createTrackAndStreamWithCleanup(t);
     24  const sender = pc.addTrack(track, stream);
     25  const transceiver = findTransceiverForSender(pc, sender);
     26  assert_true(transceiver instanceof RTCRtpTransceiver);
     27  assert_true(transceiver.sender instanceof RTCRtpSender);
     28  assert_equals(transceiver.sender, sender);
     29 }, 'addTrack: creates a transceiver for the sender');
     30 
     31 promise_test(async t => {
     32  const pc = createPeerConnectionWithCleanup(t);
     33  const [track, stream] = await createTrackAndStreamWithCleanup(t);
     34  const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
     35  assert_array_equals(pc.getTransceivers(), [transceiver],
     36                      'pc.getTransceivers() equals [transceiver]');
     37  assert_array_equals(pc.getSenders(), [transceiver.sender],
     38                      'pc.getSenders() equals [transceiver.sender]');
     39  assert_array_equals(pc.getReceivers(), [transceiver.receiver],
     40                      'pc.getReceivers() equals [transceiver.receiver]');
     41 }, 'addTrack: "transceiver == {sender,receiver}"');
     42 
     43 promise_test(async t => {
     44  const pc = createPeerConnectionWithCleanup(t);
     45  const [track, stream] = await createTrackAndStreamWithCleanup(t);
     46  const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
     47  assert_true(transceiver.sender.track instanceof MediaStreamTrack,
     48              'transceiver.sender.track instanceof MediaStreamTrack');
     49  assert_equals(transceiver.sender.track, track,
     50                'transceiver.sender.track == track');
     51 }, 'addTrack: transceiver.sender is associated with the track');
     52 
     53 promise_test(async t => {
     54  const pc = createPeerConnectionWithCleanup(t);
     55  const [track, stream] = await createTrackAndStreamWithCleanup(t);
     56  const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
     57  assert_true(transceiver.receiver instanceof RTCRtpReceiver,
     58              'transceiver.receiver instanceof RTCRtpReceiver');
     59  assert_true(transceiver.receiver.track instanceof MediaStreamTrack,
     60              'transceiver.receiver.track instanceof MediaStreamTrack');
     61  assert_not_equals(transceiver.receiver.track, track,
     62                    'transceiver.receiver.track != track');
     63 }, 'addTrack: transceiver.receiver has its own track');
     64 
     65 promise_test(async t => {
     66  const pc = createPeerConnectionWithCleanup(t);
     67  const [track, stream] = await createTrackAndStreamWithCleanup(t);
     68  const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
     69  assert_true(transceiver.receiver.track.muted);
     70 }, 'addTrack: transceiver.receiver\'s track is muted');
     71 
     72 promise_test(async t => {
     73  const pc = createPeerConnectionWithCleanup(t);
     74  const [track, stream] = await createTrackAndStreamWithCleanup(t);
     75  const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
     76  assert_equals(transceiver.mid, null);
     77 }, 'addTrack: transceiver is not associated with an m-section');
     78 
     79 promise_test(async t => {
     80  const pc = createPeerConnectionWithCleanup(t);
     81  const [track, stream] = await createTrackAndStreamWithCleanup(t);
     82  const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
     83  // `stopped` is non-standard. Move to external/wpt/webrtc/legacy/?
     84  assert_false(transceiver.stopped);
     85 }, 'addTrack: transceiver is not stopped');
     86 
     87 promise_test(async t => {
     88  const pc = createPeerConnectionWithCleanup(t);
     89  const [track, stream] = await createTrackAndStreamWithCleanup(t);
     90  const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
     91  assert_equals(transceiver.direction, 'sendrecv');
     92 }, 'addTrack: transceiver\'s direction is sendrecv');
     93 
     94 promise_test(async t => {
     95  const pc = createPeerConnectionWithCleanup(t);
     96  const [track, stream] = await createTrackAndStreamWithCleanup(t);
     97  const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
     98  assert_equals(transceiver.currentDirection, null);
     99 }, 'addTrack: transceiver\'s currentDirection is null');
    100 
    101 promise_test(async t => {
    102  const pc = createPeerConnectionWithCleanup(t);
    103  const [track, stream] = await createTrackAndStreamWithCleanup(t);
    104  const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
    105  await pc.setLocalDescription(await pc.createOffer());
    106  assert_not_equals(transceiver.mid, null, 'transceiver.mid != null');
    107 }, 'setLocalDescription(offer): transceiver gets associated with an m-section');
    108 
    109 promise_test(async t => {
    110  const pc = createPeerConnectionWithCleanup(t);
    111  const [track, stream] = await createTrackAndStreamWithCleanup(t);
    112  const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
    113  const offer = await pc.createOffer();
    114  await pc.setLocalDescription(offer);
    115  let sdp = offer.sdp;
    116  let sdpMidLineStart = sdp.indexOf('a=mid:');
    117  let sdpMidLineEnd = sdp.indexOf('\r\n', sdpMidLineStart);
    118  assert_true(sdpMidLineStart != -1 && sdpMidLineEnd != -1,
    119              'Failed to parse offer SDP for a=mid');
    120  let parsedMid = sdp.substring(sdpMidLineStart + 6, sdpMidLineEnd);
    121  assert_equals(transceiver.mid, parsedMid, 'transceiver.mid == parsedMid');
    122 }, 'setLocalDescription(offer): transceiver.mid matches the offer SDP');
    123 
    124 promise_test(async t => {
    125  const pc1 = createPeerConnectionWithCleanup(t);
    126  pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
    127  const pc2 = createPeerConnectionWithCleanup(t);
    128  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
    129  assert_true(trackEvent instanceof RTCTrackEvent,
    130              'trackEvent instanceof RTCTrackEvent');
    131  assert_true(trackEvent.track instanceof MediaStreamTrack,
    132              'trackEvent.track instanceof MediaStreamTrack');
    133 }, 'setRemoteDescription(offer): ontrack fires with a track');
    134 
    135 promise_test(async t => {
    136  const pc1 = createPeerConnectionWithCleanup(t);
    137  const [track, stream] = await createTrackAndStreamWithCleanup(t);
    138  pc1.addTrack(track, stream);
    139  const pc2 = createPeerConnectionWithCleanup(t);
    140  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
    141  assert_true(trackEvent.track instanceof MediaStreamTrack,
    142              'trackEvent.track instanceof MediaStreamTrack');
    143  assert_equals(trackEvent.streams.length, 1,
    144                'trackEvent contains a single stream');
    145  assert_true(trackEvent.streams[0] instanceof MediaStream,
    146              'trackEvent has a MediaStream');
    147  assert_equals(trackEvent.streams[0].id, stream.id,
    148                'trackEvent.streams[0].id == stream.id');
    149 }, 'setRemoteDescription(offer): ontrack\'s stream.id is the same as stream.id');
    150 
    151 promise_test(async t => {
    152  const pc1 = createPeerConnectionWithCleanup(t);
    153  pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
    154  const pc2 = createPeerConnectionWithCleanup(t);
    155  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
    156  assert_true(trackEvent.transceiver instanceof RTCRtpTransceiver,
    157              'trackEvent.transceiver instanceof RTCRtpTransceiver');
    158 }, 'setRemoteDescription(offer): ontrack fires with a transceiver.');
    159 
    160 promise_test(async t => {
    161  const pc1 = createPeerConnectionWithCleanup(t);
    162  const [track, stream] = await createTrackAndStreamWithCleanup(t);
    163  const transceiver = findTransceiverForSender(pc1, pc1.addTrack(track, stream));
    164  const pc2 = createPeerConnectionWithCleanup(t);
    165  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
    166  assert_equals(transceiver.mid, trackEvent.transceiver.mid);
    167 }, 'setRemoteDescription(offer): transceiver.mid is the same on both ends');
    168 
    169 promise_test(async t => {
    170  const pc1 = createPeerConnectionWithCleanup(t);
    171  pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
    172  const pc2 = createPeerConnectionWithCleanup(t);
    173  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
    174  const transceiver = trackEvent.transceiver;
    175  assert_array_equals(pc2.getTransceivers(), [transceiver],
    176                      'pc2.getTransceivers() equals [transceiver]');
    177  assert_array_equals(pc2.getSenders(), [transceiver.sender],
    178                      'pc2.getSenders() equals [transceiver.sender]');
    179  assert_array_equals(pc2.getReceivers(), [transceiver.receiver],
    180                      'pc2.getReceivers() equals [transceiver.receiver]');
    181 }, 'setRemoteDescription(offer): "transceiver == {sender,receiver}"');
    182 
    183 promise_test(async t => {
    184  const pc1 = createPeerConnectionWithCleanup(t);
    185  pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
    186  const pc2 = createPeerConnectionWithCleanup(t);
    187  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
    188  assert_equals(trackEvent.transceiver.direction, 'recvonly');
    189 }, 'setRemoteDescription(offer): transceiver.direction is recvonly');
    190 
    191 promise_test(async t => {
    192  const pc1 = createPeerConnectionWithCleanup(t);
    193  pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
    194  const pc2 = createPeerConnectionWithCleanup(t);
    195  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
    196  assert_equals(trackEvent.transceiver.currentDirection, null);
    197 }, 'setRemoteDescription(offer): transceiver.currentDirection is null');
    198 
    199 promise_test(async t => {
    200  const pc1 = createPeerConnectionWithCleanup(t);
    201  pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
    202  const pc2 = createPeerConnectionWithCleanup(t);
    203  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
    204  // `stopped` is non-standard. Move to external/wpt/webrtc/legacy/?
    205  assert_false(trackEvent.transceiver.stopped);
    206 }, 'setRemoteDescription(offer): transceiver.stopped is false');
    207 
    208 promise_test(async t => {
    209  const pc1 = createPeerConnectionWithCleanup(t);
    210  pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
    211  const pc2 = createPeerConnectionWithCleanup(t);
    212  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
    213  const transceiver = trackEvent.transceiver;
    214  assert_equals(transceiver.currentDirection, null,
    215                'SRD(offer): transceiver.currentDirection is null');
    216  await pc2.setLocalDescription(await pc2.createAnswer());
    217  assert_equals(transceiver.currentDirection, 'recvonly',
    218                'SLD(answer): transceiver.currentDirection is recvonly');
    219 }, 'setLocalDescription(answer): transceiver.currentDirection is recvonly');
    220 
    221 promise_test(async t => {
    222  const pc1 = createPeerConnectionWithCleanup(t);
    223  const [track, stream] = await createTrackAndStreamWithCleanup(t);
    224  const transceiver = findTransceiverForSender(pc1, pc1.addTrack(track, stream));
    225  const pc2 = createPeerConnectionWithCleanup(t);
    226  await exchangeOffer(pc1, pc2);
    227  assert_equals(transceiver.currentDirection, null,
    228                'SLD(offer): transceiver.currentDirection is null');
    229  await exchangeAnswer(pc1, pc2);
    230  assert_equals(transceiver.currentDirection, 'sendonly',
    231                'SRD(answer): transceiver.currentDirection is sendonly');
    232 }, 'setLocalDescription(answer): transceiver.currentDirection is sendonly');
    233 
    234 promise_test(async t => {
    235  const pc = createPeerConnectionWithCleanup(t);
    236  const [track, stream] = await createTrackAndStreamWithCleanup(t);
    237  const transceiver = pc.addTransceiver(track);
    238  assert_true(transceiver instanceof RTCRtpTransceiver);
    239  assert_true(transceiver.sender instanceof RTCRtpSender);
    240  assert_true(transceiver.receiver instanceof RTCRtpReceiver);
    241  assert_equals(transceiver.sender.track, track);
    242 }, 'addTransceiver(track): creates a transceiver for the track');
    243 
    244 promise_test(async t => {
    245  const pc = createPeerConnectionWithCleanup(t);
    246  const [track, stream] = await createTrackAndStreamWithCleanup(t);
    247  const transceiver = pc.addTransceiver(track);
    248  assert_array_equals(pc.getTransceivers(), [transceiver],
    249                      'pc.getTransceivers() equals [transceiver]');
    250  assert_array_equals(pc.getSenders(), [transceiver.sender],
    251                      'pc.getSenders() equals [transceiver.sender]');
    252  assert_array_equals(pc.getReceivers(), [transceiver.receiver],
    253                      'pc.getReceivers() equals [transceiver.receiver]');
    254 }, 'addTransceiver(track): "transceiver == {sender,receiver}"');
    255 
    256 promise_test(async t => {
    257  const pc = createPeerConnectionWithCleanup(t);
    258  const [track, stream] = await createTrackAndStreamWithCleanup(t);
    259  const transceiver = pc.addTransceiver(track, {direction:'inactive'});
    260  assert_equals(transceiver.direction, 'inactive');
    261 }, 'addTransceiver(track, init): initialize direction to inactive');
    262 
    263 promise_test(async t => {
    264  const pc = createPeerConnectionWithCleanup(t);
    265  const otherPc = createPeerConnectionWithCleanup(t);
    266  const [track, stream] = await createTrackAndStreamWithCleanup(t);
    267  const transceiver = pc.addTransceiver(track, {
    268    sendEncodings: [{active:false}]
    269  });
    270 
    271  // Negotiate parameters.
    272  const offer = await pc.createOffer();
    273  await pc.setLocalDescription(offer);
    274  await otherPc.setRemoteDescription(offer);
    275  const answer = await otherPc.createAnswer();
    276  await otherPc.setLocalDescription(answer);
    277  await pc.setRemoteDescription(answer);
    278 
    279  const params = transceiver.sender.getParameters();
    280  assert_false(params.encodings[0].active);
    281 }, 'addTransceiver(track, init): initialize sendEncodings[0].active to false');
    282 
    283 promise_test(async t => {
    284  const pc1 = createPeerConnectionWithCleanup(t);
    285  const pc2 = createPeerConnectionWithCleanup(t);
    286  const [track] = await createTrackAndStreamWithCleanup(t);
    287  pc1.addTransceiver(track, {streams:[]});
    288  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
    289  assert_equals(trackEvent.streams.length, 0, 'trackEvent.streams.length == 0');
    290 }, 'addTransceiver(0 streams): ontrack fires with no stream');
    291 
    292 promise_test(async t => {
    293  const pc1 = createPeerConnectionWithCleanup(t);
    294  const pc2 = createPeerConnectionWithCleanup(t);
    295  const [track] = await createTrackAndStreamWithCleanup(t);
    296  const stream = new MediaStream();
    297  pc1.addTransceiver(track, {streams:[stream]});
    298  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
    299  assert_equals(trackEvent.streams.length, 1, 'trackEvent.streams.length == 1');
    300  assert_equals(trackEvent.streams[0].id, stream.id,
    301                'trackEvent.streams[0].id == stream.id');
    302 }, 'addTransceiver(1 stream): ontrack fires with corresponding stream');
    303 
    304 promise_test(async t => {
    305  const pc1 = createPeerConnectionWithCleanup(t);
    306  const pc2 = createPeerConnectionWithCleanup(t);
    307  const [track] = await createTrackAndStreamWithCleanup(t);
    308  const stream0 = new MediaStream();
    309  const stream1 = new MediaStream();
    310  pc1.addTransceiver(track, {streams:[stream0, stream1]});
    311  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
    312  assert_equals(trackEvent.streams.length, 2, 'trackEvent.streams.length == 2');
    313  assert_equals(trackEvent.streams[0].id, stream0.id,
    314                'trackEvent.streams[0].id == stream0.id');
    315  assert_equals(trackEvent.streams[1].id, stream1.id,
    316                'trackEvent.streams[1].id == stream1.id');
    317 }, 'addTransceiver(2 streams): ontrack fires with corresponding two streams');
    318 
    319 promise_test(async t => {
    320  const pc1 = createPeerConnectionWithCleanup(t);
    321  const pc2 = createPeerConnectionWithCleanup(t);
    322  const [track] = await createTrackAndStreamWithCleanup(t);
    323  pc1.addTrack(track);
    324  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
    325  assert_equals(trackEvent.streams.length, 0, 'trackEvent.streams.length == 0');
    326 }, 'addTrack(0 streams): ontrack fires with no stream');
    327 
    328 promise_test(async t => {
    329  const pc1 = createPeerConnectionWithCleanup(t);
    330  const pc2 = createPeerConnectionWithCleanup(t);
    331  const [track] = await createTrackAndStreamWithCleanup(t);
    332  const stream = new MediaStream();
    333  pc1.addTrack(track, stream);
    334  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
    335  assert_equals(trackEvent.streams.length, 1, 'trackEvent.streams.length == 1');
    336  assert_equals(trackEvent.streams[0].id, stream.id,
    337                'trackEvent.streams[0].id == stream.id');
    338 }, 'addTrack(1 stream): ontrack fires with corresponding stream');
    339 
    340 promise_test(async t => {
    341  const pc1 = createPeerConnectionWithCleanup(t);
    342  const pc2 = createPeerConnectionWithCleanup(t);
    343  const [track] = await createTrackAndStreamWithCleanup(t);
    344  const stream0 = new MediaStream();
    345  const stream1 = new MediaStream();
    346  pc1.addTrack(track, stream0, stream1);
    347  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
    348  assert_equals(trackEvent.streams.length, 2, 'trackEvent.streams.length == 2');
    349  assert_equals(trackEvent.streams[0].id, stream0.id,
    350                'trackEvent.streams[0].id == stream0.id');
    351  assert_equals(trackEvent.streams[1].id, stream1.id,
    352                'trackEvent.streams[1].id == stream1.id');
    353 }, 'addTrack(2 streams): ontrack fires with corresponding two streams');
    354 
    355 promise_test(async t => {
    356  const pc = createPeerConnectionWithCleanup(t);
    357  const [track, stream] = await createTrackAndStreamWithCleanup(t);
    358  const transceiver = pc.addTransceiver('audio');
    359  assert_equals(transceiver.direction, 'sendrecv');
    360 }, 'addTransceiver(\'audio\'): creates a transceiver with direction sendrecv');
    361 
    362 promise_test(async t => {
    363  const pc = createPeerConnectionWithCleanup(t);
    364  const [track, stream] = await createTrackAndStreamWithCleanup(t);
    365  const transceiver = pc.addTransceiver('audio');
    366  assert_equals(transceiver.receiver.track.kind, 'audio');
    367 }, 'addTransceiver(\'audio\'): transceiver.receiver.track.kind == \'audio\'');
    368 
    369 promise_test(async t => {
    370  const pc = createPeerConnectionWithCleanup(t);
    371  const [track, stream] = await createTrackAndStreamWithCleanup(t);
    372  const transceiver = pc.addTransceiver('video');
    373  assert_equals(transceiver.receiver.track.kind, 'video');
    374 }, 'addTransceiver(\'video\'): transceiver.receiver.track.kind == \'video\'');
    375 
    376 promise_test(async t => {
    377  const pc = createPeerConnectionWithCleanup(t);
    378  const [track, stream] = await createTrackAndStreamWithCleanup(t);
    379  const transceiver = pc.addTransceiver('audio');
    380  assert_equals(transceiver.sender.track, null);
    381 }, 'addTransceiver(\'audio\'): transceiver.sender.track == null');
    382 
    383 promise_test(async t => {
    384  const pc = createPeerConnectionWithCleanup(t);
    385  const [track, stream] = await createTrackAndStreamWithCleanup(t);
    386  const transceiver = pc.addTransceiver('audio');
    387  assert_equals(transceiver.currentDirection, null);
    388 }, 'addTransceiver(\'audio\'): transceiver.currentDirection is null');
    389 
    390 promise_test(async t => {
    391  const pc = createPeerConnectionWithCleanup(t);
    392  const [track, stream] = await createTrackAndStreamWithCleanup(t);
    393  const transceiver = pc.addTransceiver('audio');
    394  // `stopped` is non-standard. Move to external/wpt/webrtc/legacy/?
    395  assert_false(transceiver.stopped);
    396 }, 'addTransceiver(\'audio\'): transceiver.stopped is false');
    397 
    398 promise_test(async t => {
    399  const pc = createPeerConnectionWithCleanup(t);
    400  const [track, stream] = await createTrackAndStreamWithCleanup(t, 'audio');
    401  const transceiver = pc.addTransceiver('audio');
    402  const sender = pc.addTrack(track, stream);
    403  assert_equals(sender, transceiver.sender, 'sender == transceiver.sender');
    404  assert_equals(sender.track, track, 'sender.track == track');
    405 }, 'addTrack reuses reusable transceivers');
    406 
    407 promise_test(async t => {
    408  const pc = createPeerConnectionWithCleanup(t);
    409  const [track, stream] = await createTrackAndStreamWithCleanup(t, 'audio');
    410  const t1 = pc.addTransceiver('audio');
    411  const t2 = pc.addTransceiver(track);
    412  assert_not_equals(t2, t1, 't2 != t1');
    413  assert_equals(t2.sender.track, track, 't2.sender.track == track');
    414 }, 'addTransceiver does not reuse reusable transceivers');
    415 
    416 promise_test(async t => {
    417  const pc1 = createPeerConnectionWithCleanup(t);
    418  const pc2 = createPeerConnectionWithCleanup(t);
    419  const [track, stream] = await createTrackAndStreamWithCleanup(t);
    420  const pc1Transceiver = findTransceiverForSender(pc1, pc1.addTrack(track, stream));
    421  const pc2TrackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
    422  const pc2Transceiver = pc2TrackEvent.transceiver;
    423  assert_equals(pc2Transceiver.direction, 'recvonly',
    424                'pc2Transceiver.direction is recvonly after SRD(offer)');
    425  const pc2Sender = pc2.addTrack(track, stream);
    426  assert_equals(pc2Transceiver.sender, pc2Sender,
    427                'pc2Transceiver.sender == sender');
    428  assert_equals(pc2Transceiver.direction, 'sendrecv',
    429                'pc2Transceiver.direction is sendrecv after addTrack()');
    430  assert_equals(pc2Transceiver.currentDirection, null,
    431                'pc2Transceiver.currentDirection is null before answer');
    432  const pc1TrackEvent = await exchangeAnswerAndListenToOntrack(t, pc1, pc2);
    433  assert_equals(pc2Transceiver.currentDirection, 'sendrecv',
    434                'pc2Transceiver.currentDirection is sendrecv after SLD(answer)');
    435  assert_equals(pc1TrackEvent.transceiver, pc1Transceiver,
    436                'Answer: pc1.ontrack fires with the existing transceiver.');
    437  assert_equals(pc1Transceiver.currentDirection, 'sendrecv',
    438                'pc1Transceiver.currentDirection is sendrecv');
    439  assert_equals(pc2.getTransceivers().length, 1,
    440                'pc2.getTransceivers().length == 1');
    441  assert_equals(pc1.getTransceivers().length, 1,
    442                'pc1.getTransceivers().length == 1');
    443 }, 'Can setup two-way call using a single transceiver');
    444 
    445 promise_test(async t => {
    446  const pc1 = createPeerConnectionWithCleanup(t);
    447  const pc2 = createPeerConnectionWithCleanup(t);
    448  const [track, stream] = await createTrackAndStreamWithCleanup(t, 'audio');
    449  const transceiver = pc1.addTransceiver(track);
    450  await exchangeOffer(pc1, pc2);
    451  await exchangeAnswer(pc1, pc2);
    452  assert_equals(transceiver.currentDirection, 'sendonly');
    453  // `stopped` is non-standard. Move to external/wpt/webrtc/legacy/?
    454  assert_false(transceiver.stopped);
    455  pc1.close();
    456  assert_equals(transceiver.currentDirection, 'stopped');
    457  assert_true(transceiver.stopped);
    458 }, 'Closing the PC stops the transceivers');
    459 
    460 promise_test(async t => {
    461  const pc1 = createPeerConnectionWithCleanup(t);
    462  const pc1Sender = pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
    463  const localTransceiver = findTransceiverForSender(pc1, pc1Sender);
    464  const pc2 = createPeerConnectionWithCleanup(t);
    465  exchangeIceCandidates(pc1, pc2);
    466 
    467  const e = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
    468  await exchangeAnswer(pc1, pc2);
    469  localTransceiver.direction = 'inactive';
    470  await exchangeOfferAnswer(pc1, pc2);
    471 
    472  localTransceiver.direction = 'sendrecv';
    473  await exchangeOfferAndListenToOntrack(t, pc1, pc2);
    474 }, 'Changing transceiver direction to \'sendrecv\' makes ontrack fire');
    475 
    476 // Regression test coverage for https://crbug.com/950280.
    477 promise_test(async t => {
    478  const pc1 = new RTCPeerConnection();
    479  t.add_cleanup(() => pc1.close());
    480  const pc2 = new RTCPeerConnection();
    481  t.add_cleanup(() => pc2.close());
    482  const pc2Promise = pc2.createOffer()
    483    .then((offer) => { return pc1.setRemoteDescription(offer); })
    484    .then(() => { return pc1.createAnswer(); })
    485    .then((answer) => { return pc1.setLocalDescription(answer); });
    486  pc1.addTransceiver('audio', { direction: 'recvonly' });
    487  const pc1Promise = pc1.createOffer()
    488    .then(() => { pc1.addTrack(pc1.getReceivers()[0].track); });
    489  await Promise.all([pc1Promise, pc2Promise]);
    490  assert_equals(pc1.getSenders()[0].track, pc1.getReceivers()[0].track);
    491 }, 'transceiver.sender.track does not revert to an old state');
    492 
    493 // Regression test coverage for https://crbug.com/950280.
    494 promise_test(async t => {
    495  const pc1 = new RTCPeerConnection();
    496  t.add_cleanup(() => pc1.close());
    497  const pc2 = new RTCPeerConnection();
    498  t.add_cleanup(() => pc2.close());
    499  const pc2Promise = pc2.createOffer()
    500    .then((offer) => { return pc1.setRemoteDescription(offer); })
    501    .then(() => { return pc1.createAnswer(); });
    502  pc1.addTransceiver('audio', { direction: 'recvonly' });
    503  const pc1Promise = pc1.createOffer()
    504    .then(() => { pc1.getTransceivers()[0].direction = 'inactive'; });
    505  await Promise.all([pc1Promise, pc2Promise]);
    506  assert_equals(pc1.getTransceivers()[0].direction, 'inactive');
    507 }, 'transceiver.direction does not revert to an old state');
    508 
    509 </script>