Modern WebRTC Detect drop

by jib1

HTML

<video id="v1" height="120" width="160" autoplay muted></video>
<video id="v2" height="120" width="160" autoplay></video><br>
<button onclick="start()">Start!</button>
<button onclick="drop()">Drop!</button>
<div id="div"></div><div id="div2"></div>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>

JavaScript

var pc1 = new RTCPeerConnection(), pc2 = new RTCPeerConnection();

var start = () =>
  navigator.mediaDevices.getUserMedia({ video: true, audio: true })
  .then(stream => pc1.addStream(v1.srcObject = stream))
  .catch(log);

var drop = () => pc1.close();

var add = (pc, can) => can && pc.addIceCandidate(can).catch(log);
pc1.onicecandidate = e => add(pc2, e.candidate);
pc2.onicecandidate = e => add(pc1, e.candidate);
pc2.onaddstream = e => v2.srcObject = e.stream;
pc1.oniceconnectionstatechange = e => log(pc1.iceConnectionState);
pc1.onnegotiationneeded = e =>
  pc1.createOffer().then(d => pc1.setLocalDescription(d))
  .then(() => pc2.setRemoteDescription(pc1.localDescription))
  .then(() => pc2.createAnswer()).then(d => pc2.setLocalDescription(d))
  .then(() => pc1.setRemoteDescription(pc2.localDescription))
  .catch(log);

var findStat = (m, type) => [...m.values()].find(s => s.type == type && !s.isRemote);

var hasConnected = new Promise(resolve => pc2.oniceconnectionstatechange =
  e => pc2.iceConnectionState == "connected" && resolve());

var hasDropped = hasConnected.then(() => new Promise(resolve => {
  var lastPackets = countdown = 0, timeout = 3; // seconds
  var iv = setInterval(() => pc2.getStats().then(stats => {
    var packets = findStat(stats, "inbound-rtp").packetsReceived;
    update(packets +" packets");
    countdown = (packets - lastPackets)? timeout : countdown - 1;
    if (!countdown) resolve(clearInterval(iv)); 
    lastPackets = packets;
  }), 1000);
}));

hasDropped.then(() => (v2.srcObject = null, log("dropped"))).catch(log);

var update = msg => div.innerHTML = msg;
var log = msg => div2.innerHTML += "<br>" + msg;