UNPKG

@jonz94/getstats

Version:

Fork from https://github.com/manuquentin/getStats

723 lines (606 loc) 31.2 kB
<script>window.demoVersion = '2019.02.20';</script> <!-- > Muaz Khan - www.MuazKhan.com > MIT License - www.WebRTC-Experiment.com/licence > Documentation - github.com/muaz-khan/getStats --> <!DOCTYPE html> <html lang="en"> <head> <title>getStats.js Demo | WebRTC getStats API</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> <link rel="author" type="text/html" href="https://muazkhan.com"> <meta name="author" content="Muaz Khan"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <link rel="stylesheet" href="https://www.webrtc-experiment.com/style.css"> <style> audio, video { -moz-transition: all 1s ease; -ms-transition: all 1s ease; -o-transition: all 1s ease; -webkit-transition: all 1s ease; transition: all 1s ease; vertical-align: top; } input { border: 1px solid #d9d9d9; border-radius: 1px; font-size: 2em; margin: .2em; width: 30%; } .setup { border-bottom-left-radius: 0; border-top-left-radius: 0; font-size: 102%; height: 47px; margin-left: -9px; margin-top: 8px; position: absolute; } p { padding: 1em; } li { border-bottom: 1px solid rgb(189, 189, 189); border-left: 1px solid rgb(189, 189, 189); padding: .5em; } .videos-container { border: 2px solid black; padding: .1em; border-radius: 0.2em; background: white; overflow: hidden; } .videos-container h2 { border: 0; border-top: 1px solid black; margin: 0; text-align: center; display:block; } video { width:100%; background: black; } .videos-container p { margin: 0; padding: 0; text-align: left; } table { width: 100%; } td, th, tr { padding: 1px 3px; } td { width: 40%!important; } td:first-child, th { font-weight: bold; color: #EC008C; } td:first-child, th:first-child { width: 150px!important; } table { border-bottom: 1px dotted #BBA9A9; border-left: 1px dotted #BBA9A9; } label { width: 100px!important; display: inline-block; text-align: right; padding-right: 15px; } tr { display: none; } </style> <script src="https://www.webrtc-experiment.com/getStats.js"></script> <script src="https://www.webrtc-experiment.com/IceServersHandler.js"></script> <!-- for Edge/FF/Chrome/Opera/etc. getUserMedia support --> <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script> </head> <body> <article> <header style="text-align: center;"> <h1> getStats.js Demo | WebRTC getStats API </h1> <p> <a href="https://www.webrtc-experiment.com/">HOME</a> <span> &copy; </span> <a href="http://www.MuazKhan.com/" target="_blank">Muaz Khan</a> . <a href="http://twitter.com/WebRTCWeb" target="_blank" title="Twitter profile for WebRTC Experiments">@WebRTCWeb</a> . <a href="https://github.com/muaz-khan?tab=repositories" target="_blank" title="Github Profile">Github</a> . <a href="https://github.com/muaz-khan/getStats/issues?state=open" target="_blank">Latest issues</a> . <a href="https://github.com/muaz-khan/getStats/commits/master" target="_blank">What's New?</a> </p> </header> <div class="github-stargazers"></div> <section style="margin: 20px; text-align: center; color: red;"> <small id="demoVersion"></small> <script>var date=new Date(window.demoVersion),month=date.toLocaleString("en-us",{month:"long"}),day=date.getUTCDate();day.toString().length<=9&&(day=day.toString().length == 1 ? "0"+day : day);var year=date.getUTCFullYear(); document.getElementById("demoVersion").innerHTML="Last Updated On: <time>"+month+" "+day+" "+year+"</time>";</script> </section> <div style="text-align: center; margin-bottom: 20px;"> <button id="btn-stop" disabled>Stop Camera & getStats</button> <select id="select-iceTransportPolicy"> <option value="all">STUN+TURN</option> <option value="relay">TURN Only</option> </select> <select id="select-iceTransportLimitation"> <option value="all">UDP+TCP</option> <option value="udp">UDP Only</option> <option value="tcp">TCP Only</option> </select> <select id="select-codec"> <option value="vp8">VP8</option> <option value="vp9">VP9</option> <option value="h264">H264</option> </select> </div> <table> <thead> <th></th> <th>First Peer</th> <th>Second Peer</th> </thead> <tbody> <tr class="firefox-allowed chrome-allowed"> <td> Videos </td> <td> <video id="peer2-to-peer1" autoplay playsinilne controls muted volume=0></video> </td> <td> <video id="peer1-to-peer2" autoplay playsinilne controls muted volume=0></video> </td> </tr> <tr class="firefox-allowed chrome-allowed"> <td>Bandwidth Speed</td> <td><span id="peer1-bandwidthSpeed"></span> per second</td> <td><span id="peer2-bandwidthSpeed"></span> per second</td> </tr> <tr class="firefox-allowed chrome-allowed"> <td>STUN/TURN?</td> <td> <label>Local:</label> <span id="peer1-localIceType"></span> (<span id="peer1-localTransport"></span>)<br> <label>Remote:</label> <span id="peer1-remoteIceType"></span> (<span id="peer1-remoteTransport"></span>)<br> </td> <td> <label>Local:</label> <span id="peer2-localIceType"></span> (<span id="peer2-localTransport"></span>)<br> <label>Remote:</label> <span id="peer2-remoteIceType"></span> (<span id="peer2-remoteTransport"></span>)<br> </td> </tr> <tr class="firefox-not-allowed chrome-allowed"> <td>Codecs</td> <td> <label>Send:</label> <span id="peer1-codecsSend"></span><br> <label>Recv:</label> <span id="peer1-codecsRecv"></span><br> </td> <td> <label>Send:</label> <span id="peer2-codecsSend"></span><br> <label>Recv:</label> <span id="peer2-codecsRecv"></span><br> </td> </tr> <tr class="firefox-not-allowed chrome-allowed"> <td>Encryption</td> <td><span id="peer1-encryptedAs"></span></td> <td><span id="peer2-encryptedAs"></span></td> </tr> <tr class="firefox-allowed chrome-allowed"> <td>IP Address</td> <td> <label>Send:</label> <span id="peer1-externalIPAddressLocal"></span><br> <label>Recv:</label> <span id="peer1-externalIPAddressRemote"></span> </td> <td> <label>Send:</label> <span id="peer2-externalIPAddressLocal"></span><br> <label>Recv:</label> <span id="peer2-externalIPAddressRemote"></span> </td> </tr> <tr class="firefox-not-allowed chrome-allowed"> <td>Resolutions</td> <td> <label>Send:</label> <span id="peer1-videoResolutionsForSenders"></span><br> <label>Recv:</label> <span id="peer1-videoResolutionsForReceivers"></span> </td> <td> <label>Send:</label> <span id="peer2-videoResolutionsForSenders"></span><br> <label>Recv:</label> <span id="peer2-videoResolutionsForReceivers"></span> </td> </tr> <tr class="firefox-allowed chrome-allowed"> <td>Data</td> <td> <label>Send:</label> <span id="peer1-totalDataForSenders"></span><br> <label>Recv:</label> <span id="peer1-totalDataForReceivers"></span> </td> <td> <label>Send:</label> <span id="peer2-totalDataForSenders"></span><br> <label>Recv:</label> <span id="peer2-totalDataForReceivers"></span> </td> </tr> <tr class="firefox-allowed chrome-not-allowed"> <td>framerateMean</td> <td> <label>Send:</label> <span id="peer1-framerateMean"></span> </td> <td> <label>Send:</label> <span id="peer2-framerateMean"></span> </td> </tr> <tr class="firefox-allowed chrome-not-allowed"> <td>bitrateMean</td> <td> <label>Send:</label> <span id="peer1-bitrateMean"></span> </td> <td> <label>Send:</label> <span id="peer2-bitrateMean"></span> </td> </tr> <tr class="firefox-not-allowed chrome-allowed"> <td>latency</td> <td> <label>Audio:</label> <span id="peer1-audio-latency"></span><br> <label>Video:</label> <span id="peer1-video-latency"></span> </td> <td> <label>Audio:</label> <span id="peer2-audio-latency"></span><br> <label>Video:</label> <span id="peer2-video-latency"></span> </td> </tr> <tr class="firefox-not-allowed chrome-allowed"> <td>packetsLost</td> <td> <label>Audio:</label> <span id="peer1-audio-packetsLost"></span><br> <label>Video:</label> <span id="peer1-video-packetsLost"></span> </td> <td> <label>Audio:</label> <span id="peer2-audio-packetsLost"></span><br> <label>Video:</label> <span id="peer2-video-packetsLost"></span> </td> </tr> </tbody> </table> <blockquote style="margin: 20px;"> Multi-user peer-to-peer demo: <a href="https://rtcmulticonnection.herokuapp.com/demos/getStats.html">getStats using RTCMultiConnection</a> </blockquote> <script> var iceTransportPolicy = document.getElementById('select-iceTransportPolicy'); if(localStorage.getItem('iceTransportPolicy')) { iceTransportPolicy.value = localStorage.getItem('iceTransportPolicy'); } iceTransportPolicy.onchange = function() { localStorage.setItem('iceTransportPolicy', this.value); location.reload(); }; var iceTransportLimitation = document.getElementById('select-iceTransportLimitation'); if(localStorage.getItem('iceTransportLimitation')) { iceTransportLimitation.value = localStorage.getItem('iceTransportLimitation'); } iceTransportLimitation.onchange = function() { localStorage.setItem('iceTransportLimitation', this.value); location.reload(); }; var codec = document.getElementById('select-codec'); if(localStorage.getItem('codec')) { codec.value = localStorage.getItem('codec'); } codec.onchange = function() { localStorage.setItem('codec', this.value); location.reload(); }; function addIceCandidate(peer, candidate) { if(iceTransportLimitation.value === 'tcp') { if(candidate.candidate.toLowerCase().indexOf('tcp') === -1) { return; // ignore UDP } } if(iceTransportLimitation.value === 'udp') { if(candidate.candidate.toLowerCase().indexOf('udp') === -1) { return; // ignore UDP } } peer.addIceCandidate(candidate); } </script> <script> var offerer, answerer; var offererToAnswerer = document.getElementById('peer1-to-peer2'); var answererToOfferer = document.getElementById('peer2-to-peer1'); var iceServers = { iceServers: IceServersHandler.getIceServers(), iceTransportPolicy: iceTransportPolicy.value, rtcpMuxPolicy: 'require', bundlePolicy: 'max-bundle' }; var mediaConstraints = { OfferToReceiveAudio: true, OfferToReceiveVideo: true }; </script> <script> /* offerer */ function offererPeer(video_stream) { offerer = new RTCPeerConnection(iceServers); offerer.idx = 1; video_stream.getTracks().forEach(function(track) { offerer.addTrack(track, video_stream); }); var firedOnce = false; offerer.ontrack = function (event) { if(firedOnce) return; firedOnce = true; offererToAnswerer.srcObject = event.streams[0]; if(/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) { getStats(offerer, event.streams[0].getTracks()[0], function(result) { previewGetStatsResult(offerer, result); }, 1000); return; } getStats(offerer, function(result) { previewGetStatsResult(offerer, result); }, 1000); }; offerer.onicecandidate = function (event) { if (!event || !event.candidate) return; addIceCandidate(answerer, event.candidate); }; offerer.createOffer(mediaConstraints).then(function (offer) { offer.sdp = preferSelectedCodec(offer.sdp); offerer.setLocalDescription(offer).then(function() { answererPeer(offer, video_stream); }); }); } </script> <script> /* answerer */ function answererPeer(offer, video_stream) { answerer = new RTCPeerConnection(iceServers); answerer.idx = 2; video_stream.getTracks().forEach(function(track) { answerer.addTrack(track, video_stream); }); var firedOnce = false; answerer.ontrack = function (event) { if(firedOnce) return; firedOnce = true; answererToOfferer.srcObject = event.streams[0]; if(/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) { getStats(offerer, event.streams[0].getTracks()[0], function(result) { previewGetStatsResult(offerer, result); }, 1000); return; } getStats(answerer, function(result) { previewGetStatsResult(answerer, result); }, 1000); }; answerer.onicecandidate = function (event) { if (!event || !event.candidate) return; addIceCandidate(offerer, event.candidate); }; answerer.setRemoteDescription(offer).then(function() { answerer.createAnswer(mediaConstraints).then(function (answer) { answer.sdp = preferSelectedCodec(answer.sdp); answerer.setLocalDescription(answer).then(function() { offerer.setRemoteDescription(answer); }); }); }); } </script> <script> var video_constraints = { mandatory: {}, optional: [] }; function getUserMedia(successCallback) { function errorCallback(e) { alert(JSON.stringify(e, null, '\t')); } var mediaConstraints = { video: true, audio: true }; navigator.mediaDevices.getUserMedia(mediaConstraints).then(successCallback).catch(errorCallback); } </script> <script> var CAMERA_STREAM; getUserMedia(function (video_stream) { CAMERA_STREAM = video_stream; offererPeer(video_stream); document.getElementById('btn-stop').disabled = false; }); </script> <script> var STOP_GETSTATS = false; document.getElementById('btn-stop').onclick = function() { this.disabled = true; STOP_GETSTATS = true; if(CAMERA_STREAM && CAMERA_STREAM.active === true) { CAMERA_STREAM.getTracks().forEach(function(track) { track.stop(); }); } }; function previewGetStatsResult(peer, result) { if(STOP_GETSTATS) { result.nomore(); return; } if(result.connectionType.remote.candidateType.indexOf('relayed') !== -1) { result.connectionType.remote.candidateType = 'TURN'; } else { result.connectionType.remote.candidateType = 'STUN'; } document.getElementById('peer' + peer.idx + '-remoteIceType').innerHTML = result.connectionType.remote.candidateType; document.getElementById('peer' + peer.idx + '-externalIPAddressRemote').innerHTML = result.connectionType.remote.ipAddress.join(', '); document.getElementById('peer' + peer.idx + '-remoteTransport').innerHTML = result.connectionType.remote.transport.join(', '); if(result.connectionType.local.candidateType.indexOf('relayed') !== -1) { result.connectionType.local.candidateType = 'TURN'; } else { result.connectionType.local.candidateType = 'STUN'; } document.getElementById('peer' + peer.idx + '-localIceType').innerHTML = result.connectionType.local.candidateType; document.getElementById('peer' + peer.idx + '-externalIPAddressLocal').innerHTML = result.connectionType.local.ipAddress.join(', '); document.getElementById('peer' + peer.idx + '-localTransport').innerHTML = result.connectionType.local.transport.join(', '); document.getElementById('peer' + peer.idx + '-encryptedAs').innerHTML = result.encryption; document.getElementById('peer' + peer.idx + '-videoResolutionsForSenders').innerHTML = result.resolutions.send.width + 'x' + result.resolutions.send.height; document.getElementById('peer' + peer.idx + '-videoResolutionsForReceivers').innerHTML = result.resolutions.recv.width + 'x' + result.resolutions.recv.height; document.getElementById('peer' + peer.idx + '-totalDataForSenders').innerHTML = bytesToSize(result.audio.bytesSent + result.video.bytesSent); document.getElementById('peer' + peer.idx + '-totalDataForReceivers').innerHTML = bytesToSize(result.audio.bytesReceived + result.video.bytesReceived); document.getElementById('peer' + peer.idx + '-codecsSend').innerHTML = result.audio.send.codecs.concat(result.video.send.codecs).join(', '); document.getElementById('peer' + peer.idx + '-codecsRecv').innerHTML = result.audio.recv.codecs.concat(result.video.recv.codecs).join(', '); document.getElementById('peer' + peer.idx + '-bandwidthSpeed').innerHTML = bytesToSize(result.bandwidth.speed); document.getElementById('peer' + peer.idx + '-framerateMean').innerHTML = bytesToSize(result.video.send.framerateMean); document.getElementById('peer' + peer.idx + '-bitrateMean').innerHTML = bytesToSize(result.video.send.bitrateMean); document.getElementById('peer' + peer.idx + '-audio-latency').innerHTML = result.audio.latency + 'ms'; document.getElementById('peer' + peer.idx + '-video-latency').innerHTML = result.video.latency + 'ms'; document.getElementById('peer' + peer.idx + '-audio-packetsLost').innerHTML = result.audio.packetsLost; document.getElementById('peer' + peer.idx + '-video-packetsLost').innerHTML = result.video.packetsLost; if (result.ended === true) { result.nomore(); } window.getStatsResult = result; } if (typeof window.InstallTrigger !== 'undefined') { var all = document.querySelectorAll('.firefox-allowed'); for(var i = 0; i < all.length; i++) { all[i].style.display = 'table-row'; } var all = document.querySelectorAll('.firefox-not-allowed'); for(var i = 0; i < all.length; i++) { all[i].style.display = 'none'; } } else { var all = document.querySelectorAll('.chrome-allowed'); for(var i = 0; i < all.length; i++) { all[i].style.display = 'table-row'; } var all = document.querySelectorAll('.chrome-not-allowed'); for(var i = 0; i < all.length; i++) { all[i].style.display = 'none'; } } function bytesToSize(bytes) { var k = 1000; var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; if (bytes <= 0) { return '0 Bytes'; } var i = parseInt(Math.floor(Math.log(bytes) / Math.log(k)), 10); if(!sizes[i]) { return '0 Bytes'; } return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i]; } function preferSelectedCodec(sdp) { var info = splitLines(sdp); if(codec.value === 'vp8' && info.vp8LineNumber === info.videoCodecNumbers[0]) { return sdp; } if(codec.value === 'vp9' && info.vp9LineNumber === info.videoCodecNumbers[0]) { return sdp; } if(codec.value === 'h264' && info.h264LineNumber === info.videoCodecNumbers[0]) { return sdp; } sdp = preferCodec(sdp, codec.value, info); return sdp; } function preferCodec(sdp, codec, info) { var preferCodecNumber = ''; if(codec === 'vp8') { if(!info.vp8LineNumber) { return sdp; } preferCodecNumber = info.vp8LineNumber; } if(codec === 'vp9') { if(!info.vp9LineNumber) { return sdp; } preferCodecNumber = info.vp9LineNumber; } if(codec === 'h264') { if(!info.h264LineNumber) { return sdp; } preferCodecNumber = info.h264LineNumber; } var newLine = info.videoCodecNumbersOriginal.split('SAVPF')[0] + 'SAVPF '; var newOrder = [preferCodecNumber]; info.videoCodecNumbers.forEach(function(codecNumber) { if(codecNumber === preferCodecNumber) return; newOrder.push(codecNumber); }); newLine += newOrder.join(' '); sdp = sdp.replace(info.videoCodecNumbersOriginal, newLine); return sdp; } function splitLines(sdp) { var info = {}; sdp.split('\n').forEach(function(line) { if (line.indexOf('m=video') === 0) { info.videoCodecNumbers = []; line.split('SAVPF')[1].split(' ').forEach(function(codecNumber) { codecNumber = codecNumber.trim(); if(!codecNumber || !codecNumber.length) return; info.videoCodecNumbers.push(codecNumber); info.videoCodecNumbersOriginal = line; }); } if (line.indexOf('VP8/90000') !== -1 && !info.vp8LineNumber) { info.vp8LineNumber = line.replace('a=rtpmap:', '').split(' ')[0]; } if (line.indexOf('VP9/90000') !== -1 && !info.vp9LineNumber) { info.vp9LineNumber = line.replace('a=rtpmap:', '').split(' ')[0]; } if (line.indexOf('H264/90000') !== -1 && !info.h264LineNumber) { info.h264LineNumber = line.replace('a=rtpmap:', '').split(' ')[0]; } }); return info; } </script> <section> <h2 class="header" id="updates" style="color: red; padding-bottom: .1em;"><a href="https://github.com/muaz-khan/getStats/issues" target="_blank">getStats Issues</a> </h2> <div id="github-issues"></div> </section> <section> <h2 class="header" id="feedback">Feedback</h2> <div> <textarea id="message" style="border: 1px solid rgb(189, 189, 189); height: 8em; margin: .2em; outline: none; resize: vertical; width: 98%;" placeholder="Have any message? Suggestions or something went wrong?"></textarea> </div> <button id="send-message" style="font-size: 1em;">Send Message</button> <small style="margin-left: 1em;">Enter your email too; if you want "direct" reply!</small> </section> <section> <h2 class="header" id="updates" style="color: red; padding-bottom: .1em;"><a href="https://github.com/muaz-khan/getStats/commits/master" target="_blank">Latest Updates</a> </h2> <div id="github-commits"></div> </section> </article> <a href="https://github.com/muaz-khan/getStats" class="fork-left"></a> <footer> <p> <a href="https://www.webrtc-experiment.com/">WebRTC Experiments</a> © <a href="https://plus.google.com/+MuazKhan" rel="author" target="_blank">Muaz Khan</a> <a href="mailto:muazkh@gmail.com" target="_blank">muazkh@gmail.com</a> </p> </footer> <!-- commits.js is useless for you! --> <script> window.useThisGithubPath = 'muaz-khan/getStats'; </script> <script src="https://www.webrtc-experiment.com/commits.js" async></script> </body> </html>