<!doctype html>
<meta charset=utf-8>
<title>Test legacy offerToReceiveAudio/Video options</title>
<link rel="help" href="https://w3c.github.io/webrtc-pc/#legacy-configuration-extensions">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../RTCPeerConnection-helper.js"></script>
<script>
  'use strict';

  /*
   *  4.3.3.2 Configuration data extensions
   *  partial dictionary RTCOfferOptions
   */

  /*
   *  offerToReceiveAudio of type boolean
   *    When this is given a non-false value, no outgoing track of type
   *    "audio" is attached to the PeerConnection, and the existing
   *    localDescription (if any) doesn't contain any sendrecv or recv
   *    audio media sections, createOffer() will behave as if
   *    addTransceiver("audio") had been called once prior to the createOffer() call.
   */
  promise_test(t => {
    const pc = new RTCPeerConnection();

    t.add_cleanup(() => pc.close());

    return pc.createOffer({ offerToReceiveAudio: true })
    .then(offer1 => {
      assert_equals(countAudioLine(offer1.sdp), 1,
        'Expect created offer to have audio line');

      // The first createOffer implicitly calls addTransceiver('audio'),
      // so all following offers will also have audio media section
      // in their SDP.
      return pc.createOffer({ offerToReceiveAudio: false })
      .then(offer2 => {
        assert_equals(countAudioLine(offer2.sdp), 1,
          'Expect audio line to remain in created offer');
      })
    });
  }, 'createOffer() with offerToReceiveAudio should add audio line to all subsequent created offers');

  /*
   *  offerToReceiveVideo of type boolean
   *    When this is given a non-false value, and no outgoing track
   *    of type "video" is attached to the PeerConnection, and the
   *    existing localDescription (if any) doesn't contain any sendecv
   *    or recv video media sections, createOffer() will behave as if
   *    addTransceiver("video") had been called prior to the createOffer() call.
   */
  promise_test(t => {
    const pc = new RTCPeerConnection();

    t.add_cleanup(() => pc.close());

    return pc.createOffer({ offerToReceiveVideo: true })
    .then(offer1 => {
      assert_equals(countVideoLine(offer1.sdp), 1,
      'Expect created offer to have video line');

      return pc.createOffer({ offerToReceiveVideo: false })
      .then(offer2 => {
        assert_equals(countVideoLine(offer2.sdp), 1,
          'Expect video line to remain in created offer');
      })
    });
  }, 'createOffer() with offerToReceiveVideo should add video line to all subsequent created offers');

  promise_test(t => {
    const pc = new RTCPeerConnection();

    t.add_cleanup(() => pc.close());

    return pc.createOffer({
      offerToReceiveAudio: true,
      offerToReceiveVideo: false
    }).then(offer1 => {
      assert_equals(countAudioLine(offer1.sdp), 1,
        'Expect audio line to be found in created offer');

      assert_equals(countVideoLine(offer1.sdp), 0,
        'Expect video line to not be found in create offer');

      return pc.createOffer({
        offerToReceiveAudio: false,
        offerToReceiveVideo: true
      }).then(offer2 => {
        assert_equals(countAudioLine(offer2.sdp), 1,
          'Expect audio line to remain in created offer');

        assert_equals(countVideoLine(offer2.sdp), 1,
          'Expect video line to be found in create offer');
      })
    });
  }, 'createOffer() with offerToReceiveAudio:true, then with offerToReceiveVideo:true, should have result offer with both audio and video line');


  // Run some tests for both audio and video kinds
  ['audio', 'video'].forEach((kind) => {
    const capsKind = kind[0].toUpperCase() + kind.slice(1);

    const offerToReceiveTrue = {};
    offerToReceiveTrue[`offerToReceive${capsKind}`] = true;

    const offerToReceiveFalse = {};
    offerToReceiveFalse[`offerToReceive${capsKind}`] = false;

    // Start testing
    promise_test(t => {
      const pc = new RTCPeerConnection();
      t.add_cleanup(() => pc.close());
      const dummy = pc.createDataChannel('foo'); // Just to have something to offer

      return pc.createOffer(offerToReceiveFalse)
      .then(() => {
        assert_equals(pc.getTransceivers().length, 0,
          'Expect pc to have no transceivers');
      });
    }, `createOffer() with offerToReceive${capsKind} set to false should not create a transceiver`);

    promise_test(t => {
      const pc = new RTCPeerConnection();

      t.add_cleanup(() => pc.close());

      return pc.createOffer(offerToReceiveTrue)
      .then(() => {
        assert_equals(pc.getTransceivers().length, 1,
          'Expect pc to have one transceiver');

        const transceiver = pc.getTransceivers()[0];
        assert_equals(transceiver.direction, 'recvonly',
          'Expect transceiver to have "recvonly" direction');
      });
    }, `createOffer() with offerToReceive${capsKind} should create a "recvonly" transceiver`);

    promise_test(t => {
      const pc = new RTCPeerConnection();

      t.add_cleanup(() => pc.close());

      return pc.createOffer(offerToReceiveTrue)
      .then(() => {
        assert_equals(pc.getTransceivers().length, 1,
          'Expect pc to have one transceiver');

        const transceiver = pc.getTransceivers()[0];
        assert_equals(transceiver.direction, 'recvonly',
          'Expect transceiver to have "recvonly" direction');
      })
      .then(() => pc.createOffer(offerToReceiveTrue))
      .then(() => {
        assert_equals(pc.getTransceivers().length, 1,
          'Expect pc to still have only one transceiver');
      })
      ;
    }, `offerToReceive${capsKind} option should be ignored if a non-stopped "recvonly" transceiver exists`);

    promise_test(t => {
      const pc = new RTCPeerConnection();

      t.add_cleanup(() => pc.close());

      return getTrackFromUserMedia(kind)
      .then(([track, stream]) => {
        pc.addTrack(track, stream);
        return pc.createOffer();
      })
      .then(() => {
        assert_equals(pc.getTransceivers().length, 1,
          'Expect pc to have one transceiver');

        const transceiver = pc.getTransceivers()[0];
        assert_equals(transceiver.direction, 'sendrecv',
          'Expect transceiver to have "sendrecv" direction');
      })
      .then(() => pc.createOffer(offerToReceiveTrue))
      .then(() => {
        assert_equals(pc.getTransceivers().length, 1,
          'Expect pc to still have only one transceiver');
      })
      ;
    }, `offerToReceive${capsKind} option should be ignored if a non-stopped "sendrecv" transceiver exists`);

    promise_test(t => {
      const pc = new RTCPeerConnection();

      t.add_cleanup(() => pc.close());

      return getTrackFromUserMedia(kind)
      .then(([track, stream]) => {
        pc.addTrack(track, stream);
        return pc.createOffer(offerToReceiveFalse);
      })
      .then(() => {
        assert_equals(pc.getTransceivers().length, 1,
          'Expect pc to have one transceiver');

        const transceiver = pc.getTransceivers()[0];
        assert_equals(transceiver.direction, 'sendonly',
          'Expect transceiver to have "sendonly" direction');
      })
      ;
    }, `offerToReceive${capsKind} set to false with a track should create a "sendonly" transceiver`);

    promise_test(t => {
      const pc = new RTCPeerConnection();

      t.add_cleanup(() => pc.close());

      pc.addTransceiver(kind, {direction: 'recvonly'});

      return pc.createOffer(offerToReceiveFalse)
      .then(() => {
        assert_equals(pc.getTransceivers().length, 1,
          'Expect pc to have one transceiver');

        const transceiver = pc.getTransceivers()[0];
        assert_equals(transceiver.direction, 'inactive',
          'Expect transceiver to have "inactive" direction');
      })
      ;
    }, `offerToReceive${capsKind} set to false with a "recvonly" transceiver should change the direction to "inactive"`);

    promise_test(t => {
      const pc = new RTCPeerConnection();
      t.add_cleanup(() => pc.close());
      const pc2 = new RTCPeerConnection();

      t.add_cleanup(() => pc2.close());

      return getTrackFromUserMedia(kind)
      .then(([track, stream]) => {
        pc.addTrack(track, stream);
        return pc.createOffer();
      })
      .then((offer) => pc.setLocalDescription(offer))
      .then(() => pc2.setRemoteDescription(pc.localDescription))
      .then(() => pc2.createAnswer())
      .then((answer) => pc2.setLocalDescription(answer))
      .then(() => pc.setRemoteDescription(pc2.localDescription))
      .then(() => pc.createOffer(offerToReceiveFalse))
      .then((offer) => {
        assert_equals(pc.getTransceivers().length, 1,
          'Expect pc to have one transceiver');

        const transceiver = pc.getTransceivers()[0];
        assert_equals(transceiver.direction, 'sendonly',
          'Expect transceiver to have "sendonly" direction');
      })
      ;
    }, `subsequent offerToReceive${capsKind} set to false with a track should change the direction to "sendonly"`);
  });

  promise_test(t => {
    const pc = new RTCPeerConnection();

    t.add_cleanup(() => pc.close());

    return pc.createOffer({ offerToReceiveAudio: true, offerToReceiveVideo: true })
    .then(() => {
      assert_equals(pc.getTransceivers().length, 2,
        'Expect pc to have two transceivers');

      assert_equals(pc.getTransceivers()[0].direction, 'recvonly',
        'Expect first transceiver to have "recvonly" direction');
      assert_equals(pc.getTransceivers()[1].direction, 'recvonly',
        'Expect second transceiver to have "recvonly" direction');
    });
  }, 'offerToReceiveAudio and Video should create two "recvonly" transceivers');

</script>
