<!-- > Muaz Khan - www.MuazKhan.com > MIT License - www.WebRTC-Experiment.com/licence > Documentation - github.com/muaz-khan/DetectRTC > npm install detectrtc > bower install detectrtc --> <!DOCTYPE html> <html lang="en"> <head> <title>DetectRTC | Is WebRTC Supported In Your Browser?</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://plus.google.com/+MuazKhan"> <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 { vertical-align: bottom; width: 10em; } video { max-width: 100%; vertical-align: top; } input { border: 1px solid #d9d9d9; border-radius: 1px; font-size: 2em; margin: .2em; width: 30%; } p, .inner { padding: 1em; } li { border-bottom: 1px solid rgb(189, 189, 189); border-left: 1px solid rgb(189, 189, 189); padding: .5em; } label { display: inline-block; width: 8em; } .info-div { display: inline-block; vertical-align: middle; background-repeat: no-repeat; background-image: url(https://i.imgur.com/tnMN9tG.png?1); background-position: center center; width: 32px; height: 32px; } .inline-pre { margin: 0; padding: 0; border: 0; } </style> <script> document.createElement('article'); document.createElement('footer'); </script> <!-- Script used to detect WebRTC features! https://github.com/muaz-khan/DetectRTC#how-to-link --> <script src="/DetectRTC.js"> </script> <script src="https://www.webrtc-experiment.com/screenshot.js"></script> <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script> </head> <body> <article> <header style="text-align: center;"> <h1> <a href="https://github.com/muaz-khan/DetectRTC">DetectRTC</a> | Is WebRTC Supported In Your Browser? </h1> <p style="margin: 0;"> <a href="https://github.com/muaz-khan/DetectRTC">Github Source Codes</a> | <a href="https://github.com/muaz-khan/DetectRTC/commits/master">What's New?</a> </p> </header> <div style="text-align:center;"> <a href="https://www.npmjs.com/package/detectrtc" target="_blank"> <img src="https://img.shields.io/npm/v/detectrtc.svg"> </a> <a href="https://www.npmjs.com/package/detectrtc" target="_blank"> <img src="https://img.shields.io/npm/dm/detectrtc.svg"> </a> <a href="https://travis-ci.org/muaz-khan/DetectRTC"> <img src="https://travis-ci.org/muaz-khan/DetectRTC.png?branch=master"> </a> </div> <div class="github-stargazers" style="margin-top: 30px;"></div> <section class="experiment" id="detectrtc-output"> <button id="generate-image" style="float:right;">Open as Image</button> <h2 id="welcome">DetectRTC!</h2> <table id="browser-features"></table> </section> <!-- dirty trick to bypass webrtc blockers --> <iframe id="iframe" sandbox="allow-same-origin" style="display: none"></iframe> <script> var browserFeaturesTable = document.querySelector('#browser-features'); var screenWidth00 = innerWidth; if(document.querySelector('article')) { screenWidth00 = document.querySelector('article').clientWidth; } function appendTR(firstValue, secondValue, orignal) { var tr = document.createElement('tr'); tr.id = orignal; var html = '<td style="padding: 5px!important; text-aling: center!important;width:20px!important;"><a style="cursor:pointer;" href="#' + orignal + '">#</a></td>'; html += '<td style="padding:5px;width:' + (parseInt(screenWidth00 / 2) - 180) + 'px!important; overflow:hidden;padding: 5px!important; text-aling: center!important;width:50%!important;">' + firstValue + '</td>'; html += '<td style="padding:5px;">' + secondValue + '</td>'; tr.innerHTML = html; if(orignal === 'error') { tr.style.color = 'red'; } browserFeaturesTable.appendChild(tr); return tr; } window.onerror = console.error = function() { appendTR('Error', JSON.stringify(arguments), 'error'); }; function printVal(value) { return value == true ? 'Yep' : value == false ? 'Nope' : value; } function getInfoDiv(id) { return '<div class="info-div" id="' + id + '"></div>'; } var output = ''; function onDetectRTCLoaded() { browserFeaturesTable.innerHTML = ''; appendTR('Operating System', printVal(DetectRTC.osName) + ' version: ' + printVal(DetectRTC.osVersion), 'osVersion'); appendTR('Browser', printVal(DetectRTC.browser.name) + ' version: ' + printVal(DetectRTC.browser.fullVersion) + '<br>Private browsing? ' + printVal(DetectRTC.browser.isPrivateBrowsing), 'fullVersion'); appendTR('Display resolutions', printVal(DetectRTC.displayResolution), 'displayResolution'); appendTR('Display aspect ratio', printVal(DetectRTC.displayAspectRatio), 'displayAspectRatio'); output = printVal(DetectRTC.hasSpeakers); if(DetectRTC.audioOutputDevices.length) { output += '<br>Found speaker devices: ' + DetectRTC.audioOutputDevices.length; var labels = []; DetectRTC.audioOutputDevices.forEach(function(device) { if(DetectRTC.browser.name === 'Edge' && device.isCustomLabel) { device.label = 'Microsoft Edge is unable to detect label for this speaker device.'; } labels.push(device.label); }); output += '<br><div style="margin-left:15px;">' + labels.join('<br>') + '</div>'; } appendTR('System has Speakers?', output, 'audioOutputDevices'); output = printVal(DetectRTC.hasMicrophone); if(DetectRTC.audioInputDevices.length) { output += '<br>Found microphone devices: ' + DetectRTC.audioInputDevices.length; var labels = []; DetectRTC.audioInputDevices.forEach(function(device) { labels.push(device.label); }); output += '<br><div style="margin-left:15px;">' + labels.join('<br>') + '</div>'; } appendTR('System has Microphone?', output, 'audioInputDevices'); output = printVal(DetectRTC.hasWebcam); if(DetectRTC.videoInputDevices.length) { output += '<br>Found webcam devices: ' + DetectRTC.videoInputDevices.length; var labels = []; DetectRTC.videoInputDevices.forEach(function(device) { labels.push(device.label); }); output += '<br><div style="margin-left:15px;">' + labels.join('<br>') + '</div>'; } appendTR('System has Webcam?', output, 'videoInputDevices'); appendTR('Website has webcam permissions?', printVal(DetectRTC.isWebsiteHasWebcamPermissions), 'isWebsiteHasWebcamPermissions'); appendTR('Website has microphone permissions?', printVal(DetectRTC.isWebsiteHasMicrophonePermissions), 'isWebsiteHasMicrophonePermissions'); appendTR('Browser allows getUserMedia on this page?', printVal(DetectRTC.isGetUserMediaSupported), 'isGetUserMediaSupported'); appendTR('Can you change output audio devices?' + getInfoDiv('infoIcon-set-sink-id'), printVal(DetectRTC.isSetSinkIdSupported), 'isSetSinkIdSupported'); appendTR('Can you change camera resolutions without making new getUserMedia request?' + getInfoDiv('infoIcon-apply-constraints'), printVal(DetectRTC.isApplyConstraintsSupported), 'isApplyConstraintsSupported'); appendTR('Browser Supports WebRTC (Either 1.0 or 1.1)?', printVal(DetectRTC.isWebRTCSupported), 'isWebRTCSupported'); appendTR('Browser Supports ORTC (WebRTC 1.1)?', printVal(DetectRTC.isORTCSupported), 'isORTCSupported'); appendTR('Can you replace tracks without renegotiating peers?' + getInfoDiv('infoIcon-replace-tracks'), printVal(DetectRTC.isRTPSenderReplaceTracksSupported), 'isRTPSenderReplaceTracksSupported'); appendTR('Can your browser record remote audio or process remote audio stream in WebAudio API?', printVal(DetectRTC.isRemoteStreamProcessingSupported), 'isRemoteStreamProcessingSupported'); appendTR('Browser Supports WebSockets API?', printVal(DetectRTC.isWebSocketsSupported), 'isWebSocketsSupported'); var tr = appendTR('Your system blocked WebSockets protocol or WebSockets server is not accessible?', printVal(DetectRTC.isWebSocketsBlocked), 'isWebSocketsBlocked'); DetectRTC.checkWebSocketsSupport(function() { tr.querySelectorAll('td')[2].innerHTML = printVal(DetectRTC.isWebSocketsBlocked); }); appendTR('Browser Supports WebAudio API?', printVal(DetectRTC.isAudioContextSupported), 'isAudioContextSupported'); appendTR('Browser Supports SCTP Data Channels?', printVal(DetectRTC.isSctpDataChannelsSupported), 'isSctpDataChannelsSupported'); appendTR('Browser Supports RTP Data Channels?', printVal(DetectRTC.isRtpDataChannelsSupported), 'isRtpDataChannelsSupported'); appendTR('This page Supports Screen Capturing API?' + getInfoDiv('infoIcon-isScreenCapturingSupported'), printVal(DetectRTC.isScreenCapturingSupported), 'isScreenCapturingSupported'); appendTR('Does Browser Support multi-monitor selection & capturing screen of any monitor?', printVal(DetectRTC.isMultiMonitorScreenCapturingSupported), 'isMultiMonitorScreenCapturingSupported'); appendTR('Is it a mobile device?', printVal(DetectRTC.isMobileDevice), 'isMobileDevice'); appendTR('Does Browser Support Stream Capturing from Canvas?', printVal(DetectRTC.isVideoSupportsStreamCapturing), 'isVideoSupportsStreamCapturing'); appendTR('Does Browser Support Stream Capturing from Video?', printVal(DetectRTC.isVideoSupportsStreamCapturing), 'isVideoSupportsStreamCapturing'); appendTR('Does Browser Support Promises?', printVal(DetectRTC.isPromisesSupported), 'isPromisesSupported'); appendTR('<a id="btn-show-ip-addresses" href"#" style="cursor:pointer;">Click to show IP addresses</a>', '', ''); document.getElementById('btn-show-ip-addresses').onclick = function(e) { e.preventDefault(); var parentNode = this.parentNode.parentNode; parentNode.parentNode.removeChild(parentNode); if(DetectRTC.browser.name === 'Edge') { navigator.mediaDevices.getUserMedia({video: true}).then(function(stream) { detectIpAddresses(stream); }); return; } detectIpAddresses(); }; function detectIpAddresses(stream) { DetectRTC.DetectLocalIPAddress(function(ipAddress, isPublic, isIpv4) { if(!ipAddress) return; // console.log(ipAddress, isPublic, isIpv4); if (ipAddress.indexOf('Local') !== -1) { appendTR('Your <strong>Local</strong> IP Address', ipAddress); } else { appendTR('Your <strong>Public</strong> IP Address', ipAddress); } if(!stream) return; stream.getTracks().forEach(function(track) { track.stop(); }); stream = null; }, stream); } // appendTR(DetectRTC.MediaStream === false ? 'Your system does NOT supports MediaStream.' : 'Your system supports MediaStream.', '<strong>MediaStream.prototype:</strong><br>' + DetectRTC.MediaStream.toString().split(',').join(', '), 'MediaStream'); // appendTR(DetectRTC.MediaStreamTrack === false ? 'Your system does NOT supports MediaStreamTrack.' : 'Your system supports MediaStreamTrack.', '<strong>MediaStreamTrack.prototype:</strong><br>' + DetectRTC.MediaStreamTrack.toString().split(',').join(', '), 'MediaStreamTrack'); // appendTR(DetectRTC.RTCPeerConnection === false ? 'Your system does NOT supports RTCPeerConnection API.' : 'Your system supports RTCPeerConnection API.', '<strong>RTCPeerConnection.prototype:</strong><br>' + DetectRTC.RTCPeerConnection.toString().split(',').join(', '), 'RTCPeerConnection'); document.getElementById('infoIcon-isScreenCapturingSupported').onclick = function() { var pre = this.parentNode.querySelector('pre'); if(pre) { pre.parentNode.removeChild(pre); return; } pre = document.createElement('pre'); pre.className = 'sh_javascript inline-pre'; pre.innerHTML += '\ # Edge >= 17 or Firefox >= 60 or Safari >=13<br>\ navigator.getDisplayMedia({<br>\ video: true<br>\ }).then(screenStream => {<br>\ video.srcObject = screenStream;<br>\ }, error => {<br>\ alert(error);<br>\ });<br>\ <br>\ # Firefox<br>\ navigator.mediaDevices.getUserMedia({<br>\ video: {<br>\ mediaSource: \'window\' || \'screen\'<br>\ }<br>\ }).then(function(screenStream) {<br>\ video.srcObject = screenStream;<br>\ });<br><br>\ # Chrome+Opera desktopCapture API i.e. extension'; this.parentNode.appendChild(pre); pre.focus(); }; document.getElementById('infoIcon-set-sink-id').onclick = function() { var pre = this.parentNode.querySelector('pre'); if(pre) { pre.parentNode.removeChild(pre); return; } pre = document.createElement('pre'); pre.className = 'sh_javascript inline-pre'; pre.innerHTML += '\ var secondarySpeakers = DetectRTC.audioOutputDevices[1];<br>\ if(secondarySpeakers) {<br>\ videoElement.setSinkId(secondarySpeakers.deviceId);<br>\ }'; this.parentNode.appendChild(pre); pre.focus(); }; document.getElementById('infoIcon-apply-constraints').onclick = function() { var pre = this.parentNode.querySelector('pre'); if(pre) { pre.parentNode.removeChild(pre); return; } pre = document.createElement('pre'); pre.className = 'sh_javascript inline-pre'; pre.innerHTML += '\ oldMediaStream.getVideoTracks().forEach(function(track) {<br>\ var videoConstraints = {<br>\ width: {min: 640, ideal: 1280},<br>\ height: {min: 480, ideal: 720},<br>\ };<br>\ track.applyConstraints(videoConstraints); <br>\ });'; this.parentNode.appendChild(pre); pre.focus(); }; document.getElementById('infoIcon-replace-tracks').onclick = function() { var pre = this.parentNode.querySelector('pre'); if(pre) { pre.parentNode.removeChild(pre); return; } pre = document.createElement('pre'); pre.className = 'sh_javascript inline-pre'; pre.innerHTML += '\ var newTrack = newMediaStream.getVideoTracks()[0];<br>\ var rtpSenders = rtcPeerConnection.getSenders()[0];<br>\ rtpSenders.replaceTrack(newTrack);'; this.parentNode.appendChild(pre); pre.focus(); }; } function reloadDetectRTC(callback) { DetectRTC.load(function() { onDetectRTCLoaded(); if(callback && typeof callback == 'function') { callback(); } }); } DetectRTC.load(function() { reloadDetectRTC(); try { if(DetectRTC.MediaDevices[0] && DetectRTC.MediaDevices[0].isCustomLabel) { navigator.mediaDevices.getUserMedia({audio: true, video: true}).then(function(stream) { var video; try { video = document.createElement('video'); video.muted = true; video.volume = 0; video.src = URL.createObjectURL(stream); video.style.display = 'none'; video.style.opacity = 0; (document.body || document.documentElement).appendChild(vide); } catch(e) {} reloadDetectRTC(function() { // release camera stream.getTracks().forEach(function(track) { track.stop(); }); if(video && video.parentNode) { video.parentNode.removeChild(video); } }); }).catch(reloadDetectRTC); return; } } catch(e) {} onDetectRTCLoaded(); }); document.getElementById('generate-image').onclick = function() { document.getElementById('generate-image').style.display = 'none'; html2canvas(browserFeaturesTable.parentNode, { background :'#FFFFFF', grabMouse: false, onrendered: function(canvas) { var image = canvas.toDataURL('image/jpeg'); window.open(image); document.getElementById('generate-image').style.display = 'inline-block'; } }); }; function dataURLToBlob(dataURL) { var BASE64_MARKER = ';base64,'; if (dataURL.indexOf(BASE64_MARKER) == -1) { var parts = dataURL.split(','); var contentType = parts[0].split(':')[1]; var raw = decodeURIComponent(parts[1]); return new Blob([raw], { type: contentType }); } var parts = dataURL.split(BASE64_MARKER); var contentType = parts[0].split(':')[1]; var raw = window.atob(parts[1]); var rawLength = raw.length; var uInt8Array = new Uint8Array(rawLength); for (var i = 0; i < rawLength; ++i) { uInt8Array[i] = raw.charCodeAt(i); } return new Blob([uInt8Array], { type: contentType }); } if(DetectRTC.version) { document.getElementById('welcome').innerHTML = 'DetectRTC v' + DetectRTC.version; } </script> <section class="experiment"> <h2 class="header" id="updates" style="color: red; padding-bottom: .1em;"><a href="https://github.com/muaz-khan/DetectRTC/issues" target="_blank">DetectRTC Issues</a> </h2> <div id="github-issues"></div> </section> <section class="experiment"> <h2 class="header" id="updates" style="color: red; padding-bottom: .1em;"><a href="https://github.com/muaz-khan/DetectRTC/commits/master" target="_blank">Latest Updates</a></h2> <div id="github-commits"></div> </section> <section class="experiment"><small id="send-message"></small></section> <section class="experiment"> <h2 class="header"> How to use <a href="https://github.com/muaz-khan/DetectRTC" target="_blank">DetectRTC</a>?</h2> <pre class="sh_html"> <script src="https://www.webrtc-experiment.com/DetectRTC.js"></script> <script> // OR otherwise use <a href="https://www.npmjs.com/package/detectrtc">NPM</a> var DetectRTC = require('detectrtc'); </script> </pre> </section> <section class="experiment"> <pre class="sh_javascript"> DetectRTC.load(function() { DetectRTC.hasWebcam (has webcam device!) DetectRTC.hasMicrophone (has microphone device!) DetectRTC.hasSpeakers (has speakers!) DetectRTC.isScreenCapturingSupported DetectRTC.isSctpDataChannelsSupported DetectRTC.isRtpDataChannelsSupported DetectRTC.isAudioContextSupported DetectRTC.isWebRTCSupported DetectRTC.isDesktopCapturingSupported DetectRTC.isMobileDevice DetectRTC.isWebSocketsSupported DetectRTC.isWebSocketsBlocked DetectRTC.checkWebSocketsSupport(callback) DetectRTC.isWebsiteHasWebcamPermissions // getUserMedia allowed for HTTPs domain in Chrome? DetectRTC.isWebsiteHasMicrophonePermissions // getUserMedia allowed for HTTPs domain in Chrome? DetectRTC.audioInputDevices // microphones DetectRTC.audioOutputDevices // speakers DetectRTC.videoInputDevices // cameras DetectRTC.osName DetectRTC.osVersion DetectRTC.browser.name === 'Edge' || 'Chrome' || 'Firefox' DetectRTC.browser.version DetectRTC.browser.isChrome DetectRTC.browser.isFirefox DetectRTC.browser.isOpera DetectRTC.browser.isIE DetectRTC.browser.isSafari DetectRTC.browser.isEdge DetectRTC.browser.isPrivateBrowsing // incognito or private modes DetectRTC.isCanvasSupportsStreamCapturing DetectRTC.isVideoSupportsStreamCapturing DetectRTC.DetectLocalIPAddress(callback) }); </pre> </section> </article> <footer> <p> <a href="https://www.webrtc-experiment.com/">WebRTC Experiments</a> | <a href="http://www.muazkhan.com/">Muaz Khan</a> | <a href="https://twitter.com/WebRTCWeb">@WebRTCWeb</a> | <a href="https://twitter.com/muazkh">@muazkh</a> </p> </footer> <!-- commits.js is useless for you! --> <script> window.useThisGithubPath = 'muaz-khan/DetectRTC'; </script> <script src="https://www.webrtc-experiment.com/commits.js" async> </script> </body> </html>