<!doctype html>
<meta charset=utf-8>
<title>RTCPeerConnection RTP extensions</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../third_party/sdp/sdp.js"></script>
<script>
'use strict';

async function setup() {
  const pc1 = new RTCPeerConnection();
  pc1.addTransceiver('audio');
  // Make sure there is more than one rid, since there's no reason to use
  // rtp-stream-id/repaired-rtp-stream-id otherwise. Some implementations
  // may use them for unicast anyway, which isn't a spec violation, just
  // a little silly.
  pc1.addTransceiver('video', {sendEncodings: [{rid: '0'}, {rid: '1'}]});
  const offer = await pc1.createOffer();
  pc1.close();
  return offer.sdp;
}

// Extensions that MUST be supported
const mandatoryExtensions = [
  // Directly referenced in WebRTC RTP usage
  'urn:ietf:params:rtp-hdrext:ssrc-audio-level', // RFC 8834 5.2.2
  'urn:ietf:params:rtp-hdrext:sdes:mid',  // RFC 8834 5.2.4
  'urn:3gpp:video-orientation',  // RFC 8834 5.2.5
  // Required for support of simulcast with RID
  'urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id',  // RFC 8852 4.3
  'urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id',  // RFC 8852 4.4
];

// For further testing:
// - Add test for rapid synchronization - RFC 8834 5.2.1
// - Add test for encrypted header extensions (RFC 6904)
// - Separate tests for extensions in audio and video sections

for (const extension of mandatoryExtensions) {
  promise_test(async t => {
    const sdp = await setup();
    const extensions = SDPUtils.matchPrefix(sdp, 'a=extmap:')
          .map(SDPUtils.parseExtmap);
    assert_true(!!extensions.find(ext => ext.uri === extension));
  }, `RTP header extension ${extension} is present in offer`);
}

// Test for illegal remote behavior: Reassignment of hdrext ID
// in a subsequent offer/answer cycle.
promise_test(async t => {
  const pc1 = new RTCPeerConnection();
  t.add_cleanup(() => pc1.close());
  const pc2 = new RTCPeerConnection();
  t.add_cleanup(() => pc2.close());

  pc1.addTransceiver('audio');
  await pc1.setLocalDescription();
  await pc2.setRemoteDescription(pc1.localDescription);
  await pc2.setLocalDescription();
  await pc1.setRemoteDescription(pc2.localDescription);
  // Do a second offer/answer cycle.
  await pc1.setLocalDescription();
  await pc2.setRemoteDescription(pc1.localDescription);
  const answer = await pc2.createAnswer();

  // Swap the extension number of the two required extensions
  answer.sdp = answer.sdp.replace('urn:ietf:params:rtp-hdrext:ssrc-audio-level',
                     'xyzzy')
  .replace('urn:ietf:params:rtp-hdrext:sdes:mid',
           'urn:ietf:params:rtp-hdrext:ssrc-audio-level')
  .replace('xyzzy',
           'urn:ietf:params:rtp-hdrext:sdes:mid');

  return promise_rejects_dom(t, 'InvalidAccessError',
                            pc1.setRemoteDescription(answer));
}, 'RTP header extension reassignment causes failure');

</script>
