DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (b6d82b1a6b02)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
<!DOCTYPE HTML>
<html>
<head>
  <script type="application/javascript" src="pc.js"></script>
</head>
<body>
<pre id="test">
<script type="application/javascript">
  createHTML({
    bug: "1032839",
    title: "Replace video and audio (with WebAudio) tracks",
    visible: true
  });

  function allLocalStreamsHaveSender(pc) {
    return pc.getLocalStreams()
      .every(s => s.getTracks()        // Every local stream,
        .some(t => pc.getSenders()     // should have some track,
          .some(sn => sn.track == t))) // that's being sent over |pc|.
  }

  function allRemoteStreamsHaveReceiver(pc) {
    return pc.getRemoteStreams()
      .every(s => s.getTracks()        // Every remote stream,
        .some(t => pc.getReceivers()   // should have some track,
          .some(sn => sn.track == t))) // that's being received over |pc|.
  }

  function replacetest(wrapper) {
    var pc = wrapper._pc;
    var oldSenderCount = pc.getSenders().length;
    var sender = pc.getSenders().find(sn => sn.track.kind == "video");
    var oldTrack = sender.track;
    ok(sender, "We have a sender for video");
    ok(allLocalStreamsHaveSender(pc),
       "Shouldn't have any local streams without a corresponding sender");
    ok(allRemoteStreamsHaveReceiver(pc),
       "Shouldn't have any remote streams without a corresponding receiver");

    var newTrack;
    var audiotrack;
    return getUserMedia({video:true, audio:true})
      .then(newStream => {
        window.grip = newStream;
        newTrack = newStream.getVideoTracks()[0];
        audiotrack = newStream.getAudioTracks()[0];
        isnot(newTrack, sender.track, "replacing with a different track");
        ok(!pc.getLocalStreams().some(s => s == newStream),
           "from a different stream");
        // Use wrapper function, since it updates expected tracks
        return wrapper.senderReplaceTrack(sender, newTrack, newStream);
      })
      .then(() => {
        is(pc.getSenders().length, oldSenderCount, "same sender count");
        is(sender.track, newTrack, "sender.track has been replaced");
        ok(!pc.getSenders().map(sn => sn.track).some(t => t == oldTrack),
           "old track not among senders");
        // Spec does not say we add this new track to any stream
        ok(!pc.getLocalStreams().some(s => s.getTracks()
                                           .some(t => t == sender.track)),
           "track does not exist among pc's local streams");
        return sender.replaceTrack(audiotrack)
          .then(() => ok(false, "replacing with different kind should fail"),
                e => is(e.name, "TypeError",
                        "replacing with different kind should fail"));
      });
  }

  runNetworkTest(function () {
    test = new PeerConnectionTest();
    test.audioCtx = new AudioContext();
    test.setMediaConstraints([{video: true, audio: true}], [{video: true}]);
    test.chain.removeAfter("PC_REMOTE_WAIT_FOR_MEDIA_FLOW");

    // Test replaceTrack on pcRemote separately since it's video only.
    test.chain.append([
      function PC_REMOTE_VIDEOONLY_REPLACE_VIDEOTRACK(test) {
        return replacetest(test.pcRemote);
      },
      function PC_LOCAL_NEW_VIDEOTRACK_WAIT_FOR_MEDIA_FLOW(test) {
        return test.pcLocal.waitForMediaFlow();
      }
    ]);

    // Replace video twice on pcLocal to make sure it still works
    // (does audio twice too, but hey)
    test.chain.append([
      function PC_LOCAL_AUDIOVIDEO_REPLACE_VIDEOTRACK_1(test) {
        return replacetest(test.pcLocal);
      },
      function PC_REMOTE_NEW_VIDEOTRACK_WAIT_FOR_MEDIA_FLOW_1(test) {
        return test.pcRemote.waitForMediaFlow();
      },
      function PC_LOCAL_AUDIOVIDEO_REPLACE_VIDEOTRACK_2(test) {
        return replacetest(test.pcLocal);
      },
      function PC_REMOTE_NEW_VIDEOTRACK_WAIT_FOR_MEDIA_FLOW_2(test) {
        return test.pcRemote.waitForMediaFlow();
      }
    ]);

    test.chain.append([
      function PC_LOCAL_AUDIOVIDEO_REPLACE_VIDEOTRACK_WITHSAME(test) {
        var pc = test.pcLocal._pc;
        var sender = pc.getSenders().find(sn => sn.track.kind == "video");
        ok(sender, "should still have a sender of video");
        return sender.replaceTrack(sender.track)
          .then(() => ok(true, "replacing with itself should succeed"));
      },
      function PC_REMOTE_NEW_SAME_VIDEOTRACK_WAIT_FOR_MEDIA_FLOW(test) {
        return test.pcRemote.waitForMediaFlow();
      }
    ]);

    // Replace the gUM audio track on pcLocal with a WebAudio track.
    test.chain.append([
      function PC_LOCAL_AUDIOVIDEO_REPLACE_AUDIOTRACK_WEBAUDIO(test) {
        var pc = test.pcLocal._pc;
        var sender = pc.getSenders().find(sn => sn.track.kind == "audio");
        ok(sender, "track has a sender");
        var oldSenderCount = pc.getSenders().length;
        var oldTrack = sender.track;

        var sourceNode = test.audioCtx.createOscillator();
        sourceNode.type = 'sine';
        // We need a frequency not too close to the fake audio track
        // (440Hz for loopback devices, 1kHz for fake tracks).
        sourceNode.frequency.value = 2000;
        sourceNode.start();

        var destNode = test.audioCtx.createMediaStreamDestination();
        sourceNode.connect(destNode);
        var newTrack = destNode.stream.getAudioTracks()[0];

        return test.pcLocal.senderReplaceTrack(
            sender, newTrack, destNode.stream)
          .then(() => {
            is(pc.getSenders().length, oldSenderCount, "same sender count");
            ok(!pc.getSenders().some(sn => sn.track == oldTrack),
               "Replaced track should be removed from senders");
            // TODO: Should PC remove local streams when there are no senders
            // associated with it? getLocalStreams() isn't in the spec anymore,
            // so I guess it is pretty arbitrary?
            is(sender.track, newTrack, "sender.track has been replaced");
            // Spec does not say we add this new track to any stream
            ok(!pc.getLocalStreams().some(s => s.getTracks()
                                               .some(t => t == sender.track)),
               "track exists among pc's local streams");
          });
      }
    ]);
    test.chain.append([
      function PC_LOCAL_CHECK_WEBAUDIO_FLOW_PRESENT(test) {
        return test.pcRemote.checkReceivingToneFrom(test.audioCtx, test.pcLocal);
      }
    ]);
    test.chain.append([
      function PC_LOCAL_INVALID_ADD_VIDEOTRACKS(test) {
        let videoTransceivers = test.pcLocal._pc.getTransceivers()
          .filter(transceiver => {
            return !transceiver.stopped &&
                   transceiver.receiver.track.kind == "video" &&
                   transceiver.sender.track;
          });

        ok(videoTransceivers.length,
           "There is at least one non-stopped video transceiver with a track.");

        videoTransceivers.forEach(transceiver => {
            var stream = test.pcLocal._pc.getLocalStreams()[0];;
            var track = transceiver.sender.track;
            try {
              test.pcLocal._pc.addTrack(track, stream);
              ok(false, "addTrack existing track should fail");
            } catch (e) {
              is(e.name, "InvalidAccessError",
                 "addTrack existing track should fail");
            }
          });
      }
    ]);
    test.run();
  });
</script>
</pre>
</body>
</html>