├── screen-recording ├── camera-mic.html ├── images │ ├── edit-icon.png │ ├── list-icon.png │ ├── main-icon.png │ ├── no-video.png │ ├── cross-icon.png │ ├── upload-icon.png │ ├── recordRTC-progress-1.png │ ├── recordRTC-progress-2.png │ ├── recordRTC-progress-3.png │ ├── recordRTC-progress-4.png │ └── recordRTC-progress-5.png ├── background │ ├── background.players.js │ ├── background.tabCapture.js │ ├── background.badgeText.js │ ├── background.messaging.js │ ├── background.getUserMedia.js │ ├── background.desktopCapture.js │ ├── background.contentScript.js │ └── background.common.js ├── video.html ├── camera-mic.js ├── video.js ├── manifest.json ├── README.md ├── RecordRTC │ ├── getAllAudioVideoDevices.js │ └── MultiStreamRecorder.js ├── dropdown.html ├── preview.html ├── preview │ └── preview.php.upload.js └── options.html ├── getUserMedia-on-http ├── camera-mic.html ├── icon.png ├── example │ ├── index.html │ └── index.js ├── manifest.json ├── camera-mic.js ├── webrtc-handler.js ├── README.md └── content-script.js ├── desktopCapture ├── icon.png ├── different-api │ ├── icon.png │ ├── manifest.json │ └── background-script.js ├── manifest.json ├── background-script.js ├── content-script.js └── README.md ├── tabCapture ├── images │ ├── pause22.png │ ├── tabCapture128.png │ ├── tabCapture16.png │ ├── tabCapture22.png │ ├── tabCapture32.png │ └── tabCapture48.png ├── manifest.json ├── IceServersHandler.js ├── README.md ├── options.html ├── options.js └── shareStreamUsingRTCMultiConnection.js ├── file-sharing ├── images │ ├── progress.gif │ ├── fileCapture16.png │ ├── fileCapture22.png │ ├── fileCapture32.png │ ├── fileCapture48.png │ └── fileCapture128.png ├── fonts │ ├── MyriadPro-Light.otf │ ├── DXI1ORHCpsQm3Vp6mXoaTQ7aC6SjiAOpAWOKfJDfVRY.woff2 │ ├── DXI1ORHCpsQm3Vp6mXoaTRampu5_7CjHW5spxoeN3Vs.woff2 │ ├── DXI1ORHCpsQm3Vp6mXoaTRdwxCXfZpKo5kWAx_74bHs.woff2 │ ├── DXI1ORHCpsQm3Vp6mXoaTYjoYw3YTyktCCer_ilOlhE.woff2 │ ├── DXI1ORHCpsQm3Vp6mXoaTZ6vnaPZw6nYDxM4SVEMFKg.woff2 │ ├── DXI1ORHCpsQm3Vp6mXoaTfgrLsWo7Jk1KvZser0olKY.woff2 │ ├── DXI1ORHCpsQm3Vp6mXoaTfy1_HTwRwgtl1cPga3Fy3Y.woff2 │ ├── MTP_ySUJH_bn48VBG8sNSg7aC6SjiAOpAWOKfJDfVRY.woff2 │ ├── MTP_ySUJH_bn48VBG8sNShampu5_7CjHW5spxoeN3Vs.woff2 │ ├── MTP_ySUJH_bn48VBG8sNShdwxCXfZpKo5kWAx_74bHs.woff2 │ ├── MTP_ySUJH_bn48VBG8sNSojoYw3YTyktCCer_ilOlhE.woff2 │ ├── MTP_ySUJH_bn48VBG8sNSp6vnaPZw6nYDxM4SVEMFKg.woff2 │ ├── MTP_ySUJH_bn48VBG8sNSvgrLsWo7Jk1KvZser0olKY.woff2 │ └── MTP_ySUJH_bn48VBG8sNSvy1_HTwRwgtl1cPga3Fy3Y.woff2 ├── README.md ├── options.js ├── manifest.json ├── background.js └── options.html ├── desktopCapture-p2p ├── images │ ├── chat.png │ ├── stop.png │ ├── pause22.png │ ├── checkmark.png │ ├── help-icon.png │ ├── progress.gif │ ├── desktopCapture128.png │ ├── desktopCapture16.png │ ├── desktopCapture22.png │ ├── desktopCapture32.png │ └── desktopCapture48.png ├── extension-pages │ ├── camera-mic.html │ ├── video.js │ ├── video.html │ ├── camera-mic.js │ ├── chat.js │ ├── chat.html │ ├── dropdown.html │ ├── options.html │ ├── options.js │ └── dropdown.js ├── Privacy.md ├── background │ ├── online-offline.js │ ├── setupWebRTCConnection.js │ ├── globals.js │ ├── gotTabCaptureStream.js │ ├── runtimePort.js │ ├── helpers │ │ └── IceServersHandler.js │ ├── setDefaults.js │ ├── gotStream.js │ ├── captureTabUsingTabCapture.js │ ├── captureCamera.js │ ├── shareStreamUsingAntMediaServer.js │ ├── common.js │ ├── onAccessApproved.js │ └── captureDesktop.js ├── server.js ├── manifest.json ├── screen-receivers │ └── ant │ │ └── index.html └── README.md ├── get-any-webrtc-peer-stream ├── icon.png ├── manifest.json ├── content-script.js └── RTCPeerConnection-override.js ├── .gitignore ├── README.md ├── LICENSE └── Screen-Capturing.js └── server.js /screen-recording/camera-mic.html: -------------------------------------------------------------------------------- 1 | RecordRTC 2 | -------------------------------------------------------------------------------- /getUserMedia-on-http/camera-mic.html: -------------------------------------------------------------------------------- 1 | getUserMedia 2 | -------------------------------------------------------------------------------- /desktopCapture/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/desktopCapture/icon.png -------------------------------------------------------------------------------- /getUserMedia-on-http/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/getUserMedia-on-http/icon.png -------------------------------------------------------------------------------- /tabCapture/images/pause22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/tabCapture/images/pause22.png -------------------------------------------------------------------------------- /file-sharing/images/progress.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/images/progress.gif -------------------------------------------------------------------------------- /desktopCapture-p2p/images/chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/desktopCapture-p2p/images/chat.png -------------------------------------------------------------------------------- /desktopCapture-p2p/images/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/desktopCapture-p2p/images/stop.png -------------------------------------------------------------------------------- /get-any-webrtc-peer-stream/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/get-any-webrtc-peer-stream/icon.png -------------------------------------------------------------------------------- /tabCapture/images/tabCapture128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/tabCapture/images/tabCapture128.png -------------------------------------------------------------------------------- /tabCapture/images/tabCapture16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/tabCapture/images/tabCapture16.png -------------------------------------------------------------------------------- /tabCapture/images/tabCapture22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/tabCapture/images/tabCapture22.png -------------------------------------------------------------------------------- /tabCapture/images/tabCapture32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/tabCapture/images/tabCapture32.png -------------------------------------------------------------------------------- /tabCapture/images/tabCapture48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/tabCapture/images/tabCapture48.png -------------------------------------------------------------------------------- /desktopCapture-p2p/images/pause22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/desktopCapture-p2p/images/pause22.png -------------------------------------------------------------------------------- /desktopCapture/different-api/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/desktopCapture/different-api/icon.png -------------------------------------------------------------------------------- /file-sharing/images/fileCapture16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/images/fileCapture16.png -------------------------------------------------------------------------------- /file-sharing/images/fileCapture22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/images/fileCapture22.png -------------------------------------------------------------------------------- /file-sharing/images/fileCapture32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/images/fileCapture32.png -------------------------------------------------------------------------------- /file-sharing/images/fileCapture48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/images/fileCapture48.png -------------------------------------------------------------------------------- /screen-recording/images/edit-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/screen-recording/images/edit-icon.png -------------------------------------------------------------------------------- /screen-recording/images/list-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/screen-recording/images/list-icon.png -------------------------------------------------------------------------------- /screen-recording/images/main-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/screen-recording/images/main-icon.png -------------------------------------------------------------------------------- /screen-recording/images/no-video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/screen-recording/images/no-video.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node 2 | node_modules 3 | 4 | # bower 5 | bower_components 6 | 7 | .DS_Store 8 | 9 | .zip 10 | .tar 11 | */*.zip 12 | -------------------------------------------------------------------------------- /desktopCapture-p2p/images/checkmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/desktopCapture-p2p/images/checkmark.png -------------------------------------------------------------------------------- /desktopCapture-p2p/images/help-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/desktopCapture-p2p/images/help-icon.png -------------------------------------------------------------------------------- /desktopCapture-p2p/images/progress.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/desktopCapture-p2p/images/progress.gif -------------------------------------------------------------------------------- /file-sharing/fonts/MyriadPro-Light.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/fonts/MyriadPro-Light.otf -------------------------------------------------------------------------------- /file-sharing/images/fileCapture128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/images/fileCapture128.png -------------------------------------------------------------------------------- /screen-recording/images/cross-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/screen-recording/images/cross-icon.png -------------------------------------------------------------------------------- /screen-recording/images/upload-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/screen-recording/images/upload-icon.png -------------------------------------------------------------------------------- /desktopCapture-p2p/images/desktopCapture128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/desktopCapture-p2p/images/desktopCapture128.png -------------------------------------------------------------------------------- /desktopCapture-p2p/images/desktopCapture16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/desktopCapture-p2p/images/desktopCapture16.png -------------------------------------------------------------------------------- /desktopCapture-p2p/images/desktopCapture22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/desktopCapture-p2p/images/desktopCapture22.png -------------------------------------------------------------------------------- /desktopCapture-p2p/images/desktopCapture32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/desktopCapture-p2p/images/desktopCapture32.png -------------------------------------------------------------------------------- /desktopCapture-p2p/images/desktopCapture48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/desktopCapture-p2p/images/desktopCapture48.png -------------------------------------------------------------------------------- /screen-recording/images/recordRTC-progress-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/screen-recording/images/recordRTC-progress-1.png -------------------------------------------------------------------------------- /screen-recording/images/recordRTC-progress-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/screen-recording/images/recordRTC-progress-2.png -------------------------------------------------------------------------------- /screen-recording/images/recordRTC-progress-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/screen-recording/images/recordRTC-progress-3.png -------------------------------------------------------------------------------- /screen-recording/images/recordRTC-progress-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/screen-recording/images/recordRTC-progress-4.png -------------------------------------------------------------------------------- /screen-recording/images/recordRTC-progress-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/screen-recording/images/recordRTC-progress-5.png -------------------------------------------------------------------------------- /desktopCapture-p2p/extension-pages/camera-mic.html: -------------------------------------------------------------------------------- 1 | 2 | WebRTC Desktop Sharing 3 | -------------------------------------------------------------------------------- /file-sharing/fonts/DXI1ORHCpsQm3Vp6mXoaTQ7aC6SjiAOpAWOKfJDfVRY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/fonts/DXI1ORHCpsQm3Vp6mXoaTQ7aC6SjiAOpAWOKfJDfVRY.woff2 -------------------------------------------------------------------------------- /file-sharing/fonts/DXI1ORHCpsQm3Vp6mXoaTRampu5_7CjHW5spxoeN3Vs.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/fonts/DXI1ORHCpsQm3Vp6mXoaTRampu5_7CjHW5spxoeN3Vs.woff2 -------------------------------------------------------------------------------- /file-sharing/fonts/DXI1ORHCpsQm3Vp6mXoaTRdwxCXfZpKo5kWAx_74bHs.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/fonts/DXI1ORHCpsQm3Vp6mXoaTRdwxCXfZpKo5kWAx_74bHs.woff2 -------------------------------------------------------------------------------- /file-sharing/fonts/DXI1ORHCpsQm3Vp6mXoaTYjoYw3YTyktCCer_ilOlhE.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/fonts/DXI1ORHCpsQm3Vp6mXoaTYjoYw3YTyktCCer_ilOlhE.woff2 -------------------------------------------------------------------------------- /file-sharing/fonts/DXI1ORHCpsQm3Vp6mXoaTZ6vnaPZw6nYDxM4SVEMFKg.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/fonts/DXI1ORHCpsQm3Vp6mXoaTZ6vnaPZw6nYDxM4SVEMFKg.woff2 -------------------------------------------------------------------------------- /file-sharing/fonts/DXI1ORHCpsQm3Vp6mXoaTfgrLsWo7Jk1KvZser0olKY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/fonts/DXI1ORHCpsQm3Vp6mXoaTfgrLsWo7Jk1KvZser0olKY.woff2 -------------------------------------------------------------------------------- /file-sharing/fonts/DXI1ORHCpsQm3Vp6mXoaTfy1_HTwRwgtl1cPga3Fy3Y.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/fonts/DXI1ORHCpsQm3Vp6mXoaTfy1_HTwRwgtl1cPga3Fy3Y.woff2 -------------------------------------------------------------------------------- /file-sharing/fonts/MTP_ySUJH_bn48VBG8sNSg7aC6SjiAOpAWOKfJDfVRY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/fonts/MTP_ySUJH_bn48VBG8sNSg7aC6SjiAOpAWOKfJDfVRY.woff2 -------------------------------------------------------------------------------- /file-sharing/fonts/MTP_ySUJH_bn48VBG8sNShampu5_7CjHW5spxoeN3Vs.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/fonts/MTP_ySUJH_bn48VBG8sNShampu5_7CjHW5spxoeN3Vs.woff2 -------------------------------------------------------------------------------- /file-sharing/fonts/MTP_ySUJH_bn48VBG8sNShdwxCXfZpKo5kWAx_74bHs.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/fonts/MTP_ySUJH_bn48VBG8sNShdwxCXfZpKo5kWAx_74bHs.woff2 -------------------------------------------------------------------------------- /file-sharing/fonts/MTP_ySUJH_bn48VBG8sNSojoYw3YTyktCCer_ilOlhE.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/fonts/MTP_ySUJH_bn48VBG8sNSojoYw3YTyktCCer_ilOlhE.woff2 -------------------------------------------------------------------------------- /file-sharing/fonts/MTP_ySUJH_bn48VBG8sNSp6vnaPZw6nYDxM4SVEMFKg.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/fonts/MTP_ySUJH_bn48VBG8sNSp6vnaPZw6nYDxM4SVEMFKg.woff2 -------------------------------------------------------------------------------- /file-sharing/fonts/MTP_ySUJH_bn48VBG8sNSvgrLsWo7Jk1KvZser0olKY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/fonts/MTP_ySUJH_bn48VBG8sNSvgrLsWo7Jk1KvZser0olKY.woff2 -------------------------------------------------------------------------------- /file-sharing/fonts/MTP_ySUJH_bn48VBG8sNSvy1_HTwRwgtl1cPga3Fy3Y.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muaz-khan/Chrome-Extensions/HEAD/file-sharing/fonts/MTP_ySUJH_bn48VBG8sNSvy1_HTwRwgtl1cPga3Fy3Y.woff2 -------------------------------------------------------------------------------- /desktopCapture-p2p/Privacy.md: -------------------------------------------------------------------------------- 1 | # Privacy Policy 2 | 3 | ## We Do NOT do this 4 | 5 | 1. We don't track any user data 6 | 2. We don't use Google analytics or similar services 7 | 8 | ## We Only do this 9 | 10 | 1. Use socket.io for webrtc handshake 11 | 12 | ## and that's it. -------------------------------------------------------------------------------- /desktopCapture-p2p/extension-pages/video.js: -------------------------------------------------------------------------------- 1 | // var src = location.href.split('?src=')[1]; 2 | // document.querySelector('video').src = src; 3 | 4 | navigator.mediaDevices.getUserMedia({video: true}).then(function(stream) { 5 | document.querySelector('video').srcObject = stream; 6 | }).catch(function() { 7 | alert('Unable to capture your camera.'); 8 | }); 9 | -------------------------------------------------------------------------------- /screen-recording/background/background.players.js: -------------------------------------------------------------------------------- 1 | var videoPlayers = []; 2 | 3 | function initVideoPlayer(stream) { 4 | var videoPlayer = document.createElement('video'); 5 | videoPlayer.muted = !enableTabCaptureAPI; 6 | videoPlayer.volume = !!enableTabCaptureAPI; 7 | videoPlayer.srcObject = stream; 8 | 9 | videoPlayers.push(videoPlayer); 10 | } 11 | -------------------------------------------------------------------------------- /desktopCapture-p2p/background/online-offline.js: -------------------------------------------------------------------------------- 1 | window.addEventListener('offline', function() { 2 | if (!connection || !connection.attachStreams.length) return; 3 | 4 | // setDefaults(); 5 | // chrome.runtime.reload(); 6 | }, false); 7 | 8 | window.addEventListener('online', function() { 9 | if (!connection) return; 10 | 11 | // setDefaults(); 12 | // chrome.runtime.reload(); 13 | }, false); -------------------------------------------------------------------------------- /file-sharing/README.md: -------------------------------------------------------------------------------- 1 | # Chrome Extension to share files 2 | 3 | ## Disclaimer 4 | 5 | No more maintaining this extension; as of 2019. So please use at your own risk. 6 | 7 | * https://www.webrtc-experiment.com/disclaimer/ 8 | 9 | ## License 10 | 11 | [Chrome-Extensions](https://github.com/muaz-khan/Chrome-Extensions) are released under [MIT license](https://github.com/muaz-khan/Chrome-Extensions/blob/master/LICENSE) . Copyright (c) [Muaz Khan](https://MuazKhan.com). 12 | -------------------------------------------------------------------------------- /desktopCapture-p2p/background/setupWebRTCConnection.js: -------------------------------------------------------------------------------- 1 | function setupWebRTCConnection(stream) { 2 | // forcing RTCMultiConnection ONLY 3 | // reason: webserver doesn't has enough memory and CPU to serve any media server 4 | shareStreamUsingRTCMultiConnection(stream); 5 | 6 | if (streaming_method === 'RTCMultiConnection') { 7 | // shareStreamUsingRTCMultiConnection(stream); 8 | } 9 | 10 | if (streaming_method === 'AntMediaServer') { 11 | // shareStreamUsingAntMediaServer(stream); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /desktopCapture-p2p/background/globals.js: -------------------------------------------------------------------------------- 1 | var runtimePort; 2 | 3 | var desktop_id; 4 | var constraints; 5 | var room_password = ''; 6 | var room_id = ''; 7 | var codecs = 'default'; 8 | var bandwidth; 9 | 10 | var enableTabCaptureAPI; 11 | var enableMicrophone; 12 | var enableSpeakers; 13 | var enableCamera; 14 | var enableScreen; 15 | var isSharingOn; 16 | 17 | var streaming_method = 'RTCMultiConnection'; 18 | 19 | var room_url_box = true; 20 | 21 | var connection; // RTCMultiConnection 22 | var popup_id; 23 | 24 | var videoPlayers = []; 25 | 26 | var microphoneDevice = false; 27 | var cameraDevice = false; 28 | -------------------------------------------------------------------------------- /desktopCapture-p2p/background/gotTabCaptureStream.js: -------------------------------------------------------------------------------- 1 | function gotTabCaptureStream(stream, constraints) { 2 | if (!stream) { 3 | if (constraints.audio === true) { 4 | enableSpeakers = false; 5 | captureTabUsingTabCapture(resolutions); 6 | return; 7 | } 8 | return alert('still no tabCapture stream'); 9 | // chrome.runtime.reload(); 10 | } 11 | 12 | var newStream = new MediaStream(); 13 | 14 | stream.getTracks().forEach(function(track) { 15 | newStream.addTrack(track); 16 | }); 17 | 18 | initVideoPlayer(newStream); 19 | 20 | gotStream(newStream); 21 | } 22 | -------------------------------------------------------------------------------- /screen-recording/video.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | RecordRTC Extension 5 | 6 | 7 | 8 |

Recording: 00:00

9 | 10 | 11 | -------------------------------------------------------------------------------- /desktopCapture-p2p/extension-pages/video.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WebRTC Desktop Sharing 5 | 6 | 19 | 20 | 21 |

Close this window to stop the broadcast!

22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /get-any-webrtc-peer-stream/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "Get Any WebRTC Peer Stream", 3 | "author": "Muaz Khan", 4 | "version" : "1.0", 5 | "manifest_version" : 2, 6 | "minimum_chrome_version": "48", 7 | "description" : "Get Stream From Any WebRTC Peer from any website.", 8 | "homepage_url": "https://www.webrtc-experiment.com/", 9 | "content_scripts": [ { 10 | "js": [ "content-script.js" ], 11 | "all_frames": true, 12 | "run_at": "document_start", 13 | "matches": [""] 14 | }], 15 | "icons" : { 16 | "48" : "icon.png" 17 | }, 18 | "permissions": [ 19 | "", 20 | "tabs" 21 | ], 22 | "web_accessible_resources": [ 23 | "icon.png", 24 | "RTCPeerConnection-override.js" 25 | ] 26 | } -------------------------------------------------------------------------------- /desktopCapture/different-api/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "Screen Capturing XYZ", 3 | "author": "Muaz Khan", 4 | "version" : "3.4", 5 | "manifest_version" : 2, 6 | "minimum_chrome_version": "40", 7 | "description" : "Capture full-screen or specific application's screen on any HTTPs domain! Even audio+tab!", 8 | "homepage_url": "https://github.com/muaz-khan/Chrome-Extensions", 9 | "background": { 10 | "scripts": ["background-script.js"], 11 | "persistent": false 12 | }, 13 | "externally_connectable": { 14 | "matches": ["https://www.webrtc-experiment.com/*", "https://localhost:9001/*"] 15 | }, 16 | "icons" : { 17 | "48" : "icon.png" 18 | }, 19 | "permissions": [ 20 | "desktopCapture" 21 | ], 22 | "web_accessible_resources": [ 23 | "icon.png" 24 | ] 25 | } -------------------------------------------------------------------------------- /file-sharing/options.js: -------------------------------------------------------------------------------- 1 | chrome.storage.sync.get(null, function(items) { 2 | if (items['room_id']) { 3 | document.getElementById('room_id').value = items['room_id']; 4 | } 5 | 6 | if (items['chunk_size']) { 7 | document.getElementById('chunk_size').value = items['chunk_size']; 8 | } 9 | }); 10 | 11 | document.getElementById('room_id').onblur = function() { 12 | this.disabled = true; 13 | 14 | chrome.storage.sync.set({ 15 | room_id: this.value 16 | }, function() { 17 | document.getElementById('room_id').disabled = false; 18 | }); 19 | }; 20 | 21 | document.getElementById('chunk_size').onblur = function() { 22 | this.disabled = true; 23 | 24 | chrome.storage.sync.set({ 25 | chunk_size: this.value 26 | }, function() { 27 | document.getElementById('chunk_size').disabled = false; 28 | }); 29 | }; 30 | -------------------------------------------------------------------------------- /desktopCapture/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "Screen Capturing", 3 | "author": "Muaz Khan", 4 | "version" : "3.7", 5 | "manifest_version" : 2, 6 | "minimum_chrome_version": "34", 7 | "description" : "Capture full-screen or specific application's screen on any HTTPs domain!", 8 | "homepage_url": "https://github.com/muaz-khan/Chrome-Extensions/tree/master/desktopCapture", 9 | "background": { 10 | "scripts": ["background-script.js"], 11 | "persistent": false 12 | }, 13 | "content_scripts": [ { 14 | "js": [ "content-script.js" ], 15 | "all_frames": true, 16 | "run_at": "document_end", 17 | "matches": ["https://www.webrtc-experiment.com/*"] 18 | }], 19 | "icons" : { 20 | "48" : "icon.png" 21 | }, 22 | "permissions": [ 23 | "desktopCapture" 24 | ], 25 | "web_accessible_resources": [ 26 | "icon.png" 27 | ] 28 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebRTC [Chrome Extensions](https://github.com/muaz-khan/Chrome-Extensions) 2 | 3 | | Description | Download | Install | 4 | | ------------- |-------------|-------------| 5 | | Record full screen, apps' screen, youtube audio, and more. | [Source Code](https://github.com/muaz-khan/Chrome-Extensions/tree/master/screen-recording) | [Install from Google Web Store](https://chrome.google.com/webstore/detail/recordrtc/ndcljioonkecdnaaihodjgiliohngojp) | 6 | | Share full screen, apps' screen, youtube audio, and more. | [Source Code](https://github.com/muaz-khan/Chrome-Extensions/tree/master/desktopCapture-p2p) | [Install from Google Web Store](https://chrome.google.com/webstore/detail/webrtc-desktop-sharing/nkemblooioekjnpfekmjhpgkackcajhg) | 7 | 8 | ## License 9 | 10 | [Chrome-Extensions](https://github.com/muaz-khan/Chrome-Extensions) are released under [MIT license](https://github.com/muaz-khan/Chrome-Extensions/blob/master/LICENSE) . Copyright (c) [Muaz Khan](https://MuazKhan.com). 11 | -------------------------------------------------------------------------------- /getUserMedia-on-http/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | getUserMedia on HTTP 5 | 19 | 20 | 21 |

getUserMedia on HTTP / Install This Extension

22 | 23 |
24 | 25 | 26 | 27 |
28 | 29 |
30 | 31 |
32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /desktopCapture-p2p/background/runtimePort.js: -------------------------------------------------------------------------------- 1 | chrome.runtime.onConnect.addListener(function(port) { 2 | runtimePort = port; 3 | 4 | runtimePort.onMessage.addListener(function(message) { 5 | if (!message || !message.messageFromContentScript1234) { 6 | return; 7 | } 8 | 9 | if (message.startSharing || message.stopSharing) { 10 | captureDesktop(); 11 | } 12 | 13 | if(message.openChat) { 14 | if(connection) { 15 | connection.send({ 16 | openChat: true 17 | }); 18 | } 19 | } 20 | 21 | if(message.closeChat) { 22 | if(connection) { 23 | connection.send({ 24 | closeChat: true 25 | }); 26 | } 27 | } 28 | 29 | if(message.newChatMessage) { 30 | if(connection) { 31 | connection.send({ 32 | newChatMessage: message.newChatMessage 33 | }); 34 | } 35 | } 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /file-sharing/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "WebRTC File Sharing", 3 | "short_name" : "FileSharing", 4 | "author": "Muaz Khan", 5 | "version" : "2.6", 6 | "manifest_version" : 2, 7 | "minimum_chrome_version": "34", 8 | "description" : "Instant/Private/Reliable file sharing across all devices(mobile/desktop), among single or multiple users.", 9 | "homepage_url": "https://webrtcweb.com/fs", 10 | "background": { 11 | "scripts": ["background.js"], 12 | "persistent": false 13 | }, 14 | "browser_action" : { 15 | "default_icon" : "images/fileCapture22.png", 16 | "default_title" : "File Sharing", 17 | "default_popup": "popup.html" 18 | }, 19 | "icons" : { 20 | "16" : "images/fileCapture16.png", 21 | "22" : "images/fileCapture22.png", 22 | "32" : "images/fileCapture32.png", 23 | "48" : "images/fileCapture48.png", 24 | "128": "images/fileCapture128.png" 25 | }, 26 | "permissions": ["tabs", "storage", ""], 27 | "web_accessible_resources": [ 28 | "images/fileCapture48.png" 29 | ], 30 | "options_ui": { 31 | "page": "options.html", 32 | "chrome_style": true 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /getUserMedia-on-http/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "getUserMedia", 3 | "author": "Muaz Khan", 4 | "version" : "1.2", 5 | "manifest_version" : 2, 6 | "minimum_chrome_version": "34", 7 | "description" : "Access camera, mic or screen on any HTTP domain! i.e. Call getUserMedia on any HTTP website!", 8 | "homepage_url": "https://github.com/muaz-khan/Chrome-Extensions/tree/master/getUserMedia-on-http", 9 | "background": { 10 | "scripts": ["webrtc-handler.js", "background-script.js"], 11 | "persistent": false 12 | }, 13 | "content_scripts":[ 14 | { 15 | "matches":[ 16 | "" 17 | ], 18 | "js":[ 19 | "webrtc-handler.js", "content-script.js" 20 | ], 21 | "all_frames": true, 22 | "run_at": "document_start" 23 | } 24 | ], 25 | "icons" : { 26 | "48" : "icon.png" 27 | }, 28 | "permissions": [ 29 | "desktopCapture", 30 | "tabs", 31 | "", 32 | "tabCapture", 33 | "activeTab" 34 | ], 35 | "web_accessible_resources": [ 36 | "icon.png" 37 | ] 38 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 [Muaz Khan](https://github.com/muaz-khan) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /tabCapture/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "Tab Capturing & Sharing", 3 | "author": "Muaz Khan", 4 | "version" : "2.3", 5 | "manifest_version" : 2, 6 | "description" : "Capture & Share any tab privately with multiple users!", 7 | "homepage_url": "https://github.com/muaz-khan/Chrome-Extensions/tree/master/tabCapture", 8 | "background": { 9 | "scripts": ["socket.io.js", "RTCMultiConnection.min.js", "IceServersHandler.js", "CodecsHandler.js", "shareStreamUsingRTCMultiConnection.js", "tab-capturing.js"], 10 | "persistent": false 11 | }, 12 | "permissions": [ 13 | "tabCapture", "activeTab", "storage" 14 | ], 15 | "browser_action" : { 16 | "default_icon" : "images/tabCapture22.png", 17 | "default_title" : "Share this tab!" 18 | }, 19 | "icons" : { 20 | "16" : "images/tabCapture16.png", 21 | "22" : "images/tabCapture22.png", 22 | "32" : "images/tabCapture32.png", 23 | "48" : "images/tabCapture48.png", 24 | "128": "images/tabCapture128.png" 25 | }, 26 | "web_accessible_resources": [ 27 | "images/tabCapture48.png" 28 | ], 29 | "options_ui": { 30 | "page": "options.html", 31 | "chrome_style": true 32 | } 33 | } -------------------------------------------------------------------------------- /tabCapture/IceServersHandler.js: -------------------------------------------------------------------------------- 1 | // IceServersHandler.js 2 | 3 | var IceServersHandler = (function() { 4 | function getIceServers(connection) { 5 | // resiprocate: 3344+4433 6 | // pions: 7575 7 | var iceServers = [{ 8 | 'urls': [ 9 | 'stun:webrtcweb.com:7788' 10 | ], 11 | 'username': 'muazkh', 12 | 'credential': 'muazkh' 13 | }, 14 | { 15 | 'urls': [ 16 | 'turn:webrtcweb.com:7788', // coTURN 7788+8877 17 | 'turn:webrtcweb.com:8877', 18 | 'turn:webrtcweb.com:4455', // restund udp 19 | ], 20 | 'username': 'muazkh', 21 | 'credential': 'muazkh' 22 | }, 23 | { 24 | 'urls': [ 25 | 'stun:stun.l.google.com:19302', 26 | 'stun:stun1.l.google.com:19302', 27 | 'stun:stun2.l.google.com:19302', 28 | 'stun:stun.l.google.com:19302?transport=udp', 29 | ] 30 | } 31 | ]; 32 | 33 | return iceServers; 34 | } 35 | 36 | return { 37 | getIceServers: getIceServers 38 | }; 39 | })(); 40 | -------------------------------------------------------------------------------- /desktopCapture-p2p/background/helpers/IceServersHandler.js: -------------------------------------------------------------------------------- 1 | // IceServersHandler.js 2 | 3 | var IceServersHandler = (function() { 4 | function getIceServers(connection) { 5 | // resiprocate: 3344+4433 6 | // pions: 7575 7 | var iceServers = [{ 8 | 'urls': [ 9 | 'stun:webrtcweb.com:7788' 10 | ], 11 | 'username': 'muazkh', 12 | 'credential': 'muazkh' 13 | }, 14 | { 15 | 'urls': [ 16 | 'turn:webrtcweb.com:7788', // coTURN 7788+8877 17 | 'turn:webrtcweb.com:8877', 18 | 'turn:webrtcweb.com:4455', // restund udp 19 | ], 20 | 'username': 'muazkh', 21 | 'credential': 'muazkh' 22 | }, 23 | { 24 | 'urls': [ 25 | 'stun:stun.l.google.com:19302', 26 | 'stun:stun1.l.google.com:19302', 27 | 'stun:stun2.l.google.com:19302', 28 | 'stun:stun.l.google.com:19302?transport=udp', 29 | ] 30 | } 31 | ]; 32 | 33 | return iceServers; 34 | } 35 | 36 | return { 37 | getIceServers: getIceServers 38 | }; 39 | })(); 40 | -------------------------------------------------------------------------------- /desktopCapture-p2p/extension-pages/camera-mic.js: -------------------------------------------------------------------------------- 1 | document.write('

The purpose of this page is to access your camera and microphone.

'); 2 | document.write('

You can REMOVE i.e. DELETE camera permissions anytime on these two pages:

'); 3 | document.write('
chrome://settings/content/camera?search=camera');
 4 | document.write('
chrome://settings/content/microphone?search=microphone');
 5 | 
 6 | var constraints = {
 7 |     audio: true,
 8 |     video: true
 9 | };
10 | 
11 | navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
12 |     document.write('

'); 13 | document.querySelector('h1').innerHTML = 'Now you can close this page and click extension icon again.' 14 | 15 | document.querySelector('video').srcObject = stream; 16 | }).catch(function(error) { 17 | document.querySelector('h1').innerHTML = 'Unable to capture your camera and microphone.
' + error; 18 | }); 19 | -------------------------------------------------------------------------------- /file-sharing/background.js: -------------------------------------------------------------------------------- 1 | // background.js 2 | 3 | chrome.runtime.onConnect.addListener(function(port) { 4 | port.onMessage.addListener(portOnMessageHanlder); 5 | 6 | var progressStarted = false; 7 | 8 | function portOnMessageHanlder(message) { 9 | if (!message || !message.changeIcon) { 10 | return; 11 | } 12 | 13 | if (message.defaultIcon) { 14 | chrome.browserAction.setIcon({ 15 | path: 'images/fileCapture128.png' 16 | }); 17 | progressStarted = false; 18 | } 19 | 20 | if (message.path && !progressStarted) { 21 | progressStarted = true; 22 | chrome.browserAction.setIcon({ 23 | path: 'images/progress.gif' 24 | }); 25 | } 26 | 27 | if(message.path){ 28 | setBadgeText(message.percentage); 29 | } 30 | 31 | if(message.connected) { 32 | // setBadgeText('conn', message.color); 33 | } 34 | } 35 | }); 36 | 37 | function setBadgeText(percentage, color) { 38 | chrome.browserAction.setBadgeBackgroundColor({ 39 | color: color || [0, 0, 0, 255] 40 | }); 41 | 42 | chrome.browserAction.setBadgeText({ 43 | text: percentage 44 | }); 45 | 46 | chrome.browserAction.setTitle({ 47 | title: percentage + ' file progress' 48 | }); 49 | } 50 | -------------------------------------------------------------------------------- /get-any-webrtc-peer-stream/content-script.js: -------------------------------------------------------------------------------- 1 | var s = document.createElement('script'); 2 | s.src = chrome.extension.getURL('RTCPeerConnection-override.js'); 3 | s.onload = function() { 4 | this.remove(); 5 | }; 6 | (document.head || document.documentElement).appendChild(s); 7 | 8 | window.addEventListener('message', function (event) { 9 | if(event.data && event.data.RTCPeerConnection_SDP) { 10 | createAnswer(event.data.RTCPeerConnection_SDP); 11 | } 12 | }); 13 | 14 | function createAnswer(sdp) { 15 | peer = new webkitRTCPeerConnection(null); 16 | 17 | peer.onicecandidate = function(event) { 18 | if (!event || !!event.candidate) return; 19 | 20 | window.postMessage({ 21 | RTCPeerConnection_SDP: { 22 | sdp: peer.localDescription.sdp, 23 | type: peer.localDescription.type 24 | } 25 | }, '*'); 26 | }; 27 | 28 | peer.onaddstream = function(event) { 29 | alert('Received stream from webpage: ' + event.stream.id); 30 | }; 31 | 32 | peer.setRemoteDescription(new RTCSessionDescription(sdp)); 33 | 34 | peer.createAnswer(function(sdp) { 35 | peer.setLocalDescription(sdp); 36 | }, function() {}, { 37 | optional: [], 38 | mandatory: { 39 | OfferToReceiveAudio: true, 40 | OfferToReceiveVideo: true 41 | } 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /desktopCapture-p2p/background/setDefaults.js: -------------------------------------------------------------------------------- 1 | function setDefaults() { 2 | chrome.storage.sync.set({ 3 | enableTabCaptureAPI: 'false', 4 | enableMicrophone: 'false', 5 | enableCamera: 'false', 6 | enableScreen: 'false', 7 | isSharingOn: 'false', 8 | enableSpeakers: 'false' 9 | }); 10 | 11 | if (connection) { 12 | connection.attachStreams.forEach(function(stream) { 13 | try { 14 | stream.getTracks().forEach(function(track) { 15 | try { 16 | track.stop(); 17 | } catch (e) {} 18 | }); 19 | } catch (e) {} 20 | }); 21 | 22 | try { 23 | connection.close(); 24 | } catch (e) {} 25 | 26 | try { 27 | connection.closeSocket(); 28 | } catch (e) {} 29 | 30 | connection = null; 31 | } 32 | 33 | chrome.browserAction.setIcon({ 34 | path: 'images/desktopCapture22.png' 35 | }); 36 | 37 | if (popup_id) { 38 | try { 39 | chrome.windows.remove(popup_id); 40 | } catch (e) {} 41 | 42 | popup_id = null; 43 | } 44 | 45 | chrome.browserAction.setTitle({ 46 | title: 'Share Desktop' 47 | }); 48 | 49 | chrome.browserAction.setBadgeText({ 50 | text: '' 51 | }); 52 | 53 | chrome.runtime.reload(); 54 | } 55 | -------------------------------------------------------------------------------- /file-sharing/options.html: -------------------------------------------------------------------------------- 1 | 38 | 39 |

Set Your Own Room ID:

40 | 41 | 42 |
43 | 44 | It will use your room-id instead of generating random string. 45 |
46 | E.g. You can always share this with screen viewers: 47 |
48 | https://webrtcweb.com/fs#your_room_id 49 |
50 |
51 | 52 |

Set File Chunk Size:

53 | 54 | 55 |
56 | 57 | If your file receivers are using Firefox, then set "15000" which is maximum reciving limit in Firefox. 58 | 59 |
60 | 61 | Wanna learn "how to use"? 62 | 63 | -------------------------------------------------------------------------------- /desktopCapture-p2p/background/gotStream.js: -------------------------------------------------------------------------------- 1 | function gotStream(stream) { 2 | if (!stream) { 3 | setDefaults(); 4 | 5 | chrome.windows.create({ 6 | url: "data:text/html,

Internal error occurred while capturing the screen.

", 7 | type: 'popup', 8 | width: screen.width / 2, 9 | height: 170 10 | }); 11 | return; 12 | } 13 | 14 | chrome.browserAction.setTitle({ 15 | title: 'Connecting to WebSockets server.' 16 | }); 17 | 18 | chrome.browserAction.disable(); 19 | 20 | addStreamStopListener(stream, function() { 21 | setDefaults(); 22 | // chrome.runtime.reload(); 23 | }); 24 | 25 | // as it is reported that if you drag chrome screen's status-bar 26 | // and scroll up/down the screen-viewer page. 27 | // chrome auto-stops the screen without firing any 'onended' event. 28 | // chrome also hides screen status bar. 29 | chrome.windows.create({ 30 | url: chrome.extension.getURL('_generated_background_page.html'), 31 | type: 'popup', 32 | focused: false, 33 | width: 1, 34 | height: 1, 35 | top: parseInt(screen.height), 36 | left: parseInt(screen.width) 37 | }, function(win) { 38 | var background_page_id = win.id; 39 | 40 | setTimeout(function() { 41 | // chrome.windows.remove(background_page_id); 42 | }, 3000); 43 | }); 44 | 45 | setupWebRTCConnection(stream); 46 | 47 | chrome.browserAction.setIcon({ 48 | path: 'images/pause22.png' 49 | }); 50 | } 51 | -------------------------------------------------------------------------------- /desktopCapture/different-api/background-script.js: -------------------------------------------------------------------------------- 1 | // this background script is used to invoke desktopCapture API 2 | // to capture screen-MediaStream. 3 | 4 | var screenOptions = ['screen', 'window']; 5 | 6 | chrome.runtime.onMessageExternal.addListener(function(message, sender, callback) { 7 | console.log(message); 8 | 9 | if (message == 'get-sourceId') { 10 | chrome.desktopCapture.chooseDesktopMedia(screenOptions, sender.tab, onAccessApproved); 11 | return; 12 | } 13 | 14 | if(!!message.screenOptions) { 15 | screenOptions = message.screenOptions; 16 | } 17 | 18 | if (message.getSourceId && message.requestURL) { 19 | // via code.google.com/p/chromium/issues/detail?id=425344 20 | sender.tab.url = message.requestURL; 21 | chrome.desktopCapture.chooseDesktopMedia(screenOptions, sender.tab, onAccessApproved); 22 | } 23 | 24 | if(message === 'are-you-there') { 25 | callback('rtcmulticonnection-extension-loaded'); 26 | } 27 | 28 | // on getting sourceId 29 | // "sourceId" will be empty if permission is denied. 30 | function onAccessApproved(sourceId) { 31 | console.log('sourceId', sourceId); 32 | 33 | // if "cancel" button is clicked 34 | if (!sourceId || !sourceId.length || chrome.runtime.lastError) { 35 | return callback('PermissionDeniedError'); 36 | } 37 | 38 | // "ok" button is clicked; share "sourceId" with the 39 | // content-script which will forward it to the webpage 40 | callback({ 41 | sourceId: sourceId 42 | }); 43 | } 44 | }); 45 | -------------------------------------------------------------------------------- /getUserMedia-on-http/camera-mic.js: -------------------------------------------------------------------------------- 1 | document.write('

The purpose of this page is to access your camera and microphone.

'); 2 | 3 | var port = chrome.runtime.connect(); 4 | 5 | var hints = location.href.split('?hints=')[1]; 6 | if (hints) { 7 | hints = JSON.parse(hints); 8 | } else { 9 | hints = { 10 | audio: true, 11 | video: true 12 | }; 13 | } 14 | navigator.mediaDevices.getUserMedia(hints).then(function(stream) { 15 | stream.getTracks().forEach(function(track) { 16 | track.stop(); 17 | }); 18 | port.postMessage(hints); 19 | window.close(); 20 | }).catch(function(e) { 21 | port.postMessage({ 22 | error: e 23 | }); 24 | 25 | var html = '

Unable to access your camera and microphone.

'; 26 | html += '

Please go to following pages and remove "getUserMedia" from blocked-list:

'; 27 | html += '
chrome://settings/content/microphone?search=camera
'; 28 | html += '
chrome://settings/content/microphone?search=microphone
'; 29 | 30 | if(e.message && e.message.toString().length) { 31 | html += '
Error Message: ' + e.message + '
'; 32 | } 33 | 34 | document.body.innerHTML = html; 35 | }); 36 | -------------------------------------------------------------------------------- /desktopCapture-p2p/background/captureTabUsingTabCapture.js: -------------------------------------------------------------------------------- 1 | function captureTabUsingTabCapture(resolutions) { 2 | chrome.tabs.query({ 3 | active: true, 4 | currentWindow: true 5 | }, function(arrayOfTabs) { 6 | var activeTab = arrayOfTabs[0]; 7 | var activeTabId = activeTab.id; // or do whatever you need 8 | 9 | var constraints = { 10 | video: true, 11 | videoConstraints: { 12 | mandatory: { 13 | chromeMediaSource: 'tab', 14 | maxWidth: resolutions.maxWidth, 15 | maxHeight: resolutions.maxHeight, 16 | minWidth: resolutions.minWidth, 17 | minHeight: resolutions.minHeight, 18 | minAspectRatio: getAspectRatio(resolutions.maxWidth, resolutions.maxHeight), 19 | maxAspectRatio: getAspectRatio(resolutions.maxWidth, resolutions.maxHeight), 20 | minFrameRate: 64, 21 | maxFrameRate: 128 22 | } 23 | } 24 | }; 25 | 26 | if (!!enableSpeakers) { 27 | constraints.audio = true; 28 | constraints.audioConstraints = { 29 | mandatory: { 30 | echoCancellation: true 31 | }, 32 | optional: [{ 33 | googDisableLocalEcho: false // https://www.chromestatus.com/feature/5056629556903936 34 | }] 35 | }; 36 | } 37 | 38 | // chrome.tabCapture.onStatusChanged.addListener(function(event) { /* event.status */ }); 39 | 40 | chrome.tabCapture.capture(constraints, function(stream) { 41 | gotTabCaptureStream(stream, constraints); 42 | }); 43 | }); 44 | } 45 | -------------------------------------------------------------------------------- /desktopCapture/background-script.js: -------------------------------------------------------------------------------- 1 | // this background script is used to invoke desktopCapture API 2 | // to capture screen-MediaStream. 3 | 4 | var screenOptions = ['screen', 'window']; 5 | 6 | chrome.runtime.onConnect.addListener(function (port) { 7 | port.onMessage.addListener(portOnMessageHanlder); 8 | 9 | // this one is called for each message from "content-script.js" 10 | function portOnMessageHanlder(message) { 11 | if(!!message['get-custom-sourceId']) { 12 | screenOptions = message['get-custom-sourceId']; 13 | chrome.desktopCapture.chooseDesktopMedia(screenOptions, port.sender.tab, onAccessApproved); 14 | return; 15 | } 16 | 17 | if(message == 'get-sourceId') { 18 | chrome.desktopCapture.chooseDesktopMedia(screenOptions, port.sender.tab, onAccessApproved); 19 | return; 20 | } 21 | 22 | if(message == 'audio-plus-tab') { 23 | screenOptions = ['screen', 'window', 'audio', 'tab']; 24 | chrome.desktopCapture.chooseDesktopMedia(screenOptions, port.sender.tab, onAccessApproved); 25 | return; 26 | } 27 | } 28 | 29 | // on getting sourceId 30 | // "sourceId" will be empty if permission is denied. 31 | function onAccessApproved(sourceId, opts) { 32 | // if "cancel" button is clicked 33 | if(!sourceId || !sourceId.length) { 34 | return port.postMessage('PermissionDeniedError'); 35 | } 36 | 37 | // "ok" button is clicked; share "sourceId" with the 38 | // content-script which will forward it to the webpage 39 | port.postMessage({ 40 | sourceId: sourceId, 41 | canRequestAudioTrack: !!opts.canRequestAudioTrack 42 | }); 43 | } 44 | }); 45 | -------------------------------------------------------------------------------- /tabCapture/README.md: -------------------------------------------------------------------------------- 1 | # Disclaimer 2 | 3 | No more maintaining this extension; as of 2019. So please use at your own risk. 4 | 5 | * https://www.webrtc-experiment.com/disclaimer/ 6 | 7 | ---- 8 | 9 | ## Chrome tabCapture extension 10 | 11 | This chrome extension not only captures content of the selected tab, but also provides multi-user peer-to-peer tab-streaming. 12 | 13 | ## Codes to view the shared tab 14 | 15 | ``` 16 | index.html 17 | ``` 18 | 19 | ## How to capture stream using tabCapture APIs? 20 | 21 | ```javascript 22 | chrome.tabs.getSelected(null, function (tab) { 23 | var video_constraints = { 24 | mandatory: { 25 | chromeMediaSource: 'tab' 26 | } 27 | }; 28 | var constraints = { 29 | audio: false, 30 | video: true, 31 | videoConstraints: video_constraints 32 | }; 33 | chrome.tabCapture.capture(constraints, function (stream) { 34 | // it is a LocalMediaStream object!! 35 | }); 36 | }); 37 | ``` 38 | 39 | ## How to publish yourself? 40 | 41 | Make ZIP of the directory. Then navigate to [Chrome WebStore Developer Dashboard](https://chrome.google.com/webstore/developer/dashboard) and click **Add New Item** blue button. 42 | 43 | To learn more about how to publish a chrome extension in Google App Store: 44 | 45 | * https://developer.chrome.com/webstore/publish 46 | 47 | ## For more information 48 | 49 | For additional information, click [this link](https://github.com/muaz-khan/WebRTC-Experiment/blob/7cd04a81b30cdca2db159eb746e2714307640767/Chrome-Extensions/desktopCapture/README.md). 50 | 51 | ## License 52 | 53 | [Chrome-Extensions](https://github.com/muaz-khan/Chrome-Extensions) are released under [MIT license](https://github.com/muaz-khan/Chrome-Extensions/blob/master/LICENSE) . Copyright (c) [Muaz Khan](https://MuazKhan.com). 54 | -------------------------------------------------------------------------------- /tabCapture/options.html: -------------------------------------------------------------------------------- 1 | 38 | 39 |

Select Screen Resolutions:

40 | 46 |
47 |

Set Bandwidth:

48 | 49 | kbps 50 |

51 | 52 | kbps 53 |
54 |

Password Protected Room?

55 | 56 | 57 |
58 | Keep empty for NO password. 59 |
60 |

Set Your Own Room ID:

61 | 62 | 63 |
64 | 65 | It will use your room-id instead of generating random string. 66 | 67 |
68 | 69 | -------------------------------------------------------------------------------- /desktopCapture/content-script.js: -------------------------------------------------------------------------------- 1 | // this content-script plays role of medium to publish/subscribe messages from webpage to the background script 2 | 3 | // this object is used to make sure our extension isn't conflicted with irrelevant messages! 4 | var rtcmulticonnectionMessages = { 5 | 'are-you-there': true, 6 | 'get-sourceId': true, 7 | 'audio-plus-tab': true 8 | }; 9 | 10 | // this port connects with background script 11 | var port = chrome.runtime.connect(); 12 | 13 | // if background script sent a message 14 | port.onMessage.addListener(function (message) { 15 | // get message from background script and forward to the webpage 16 | window.postMessage(message, '*'); 17 | }); 18 | 19 | // this event handler watches for messages sent from the webpage 20 | // it receives those messages and forwards to background script 21 | window.addEventListener('message', function (event) { 22 | // if invalid source 23 | if (event.source != window) 24 | return; 25 | 26 | if(!!event.data['get-custom-sourceId']) { 27 | // forward message to background script 28 | port.postMessage(event.data); 29 | return; 30 | } 31 | 32 | // it is 3rd party message 33 | if(!rtcmulticonnectionMessages[event.data]) return; 34 | 35 | // if browser is asking whether extension is available 36 | if(event.data == 'are-you-there') { 37 | window.postMessage('rtcmulticonnection-extension-loaded', '*'); 38 | } 39 | 40 | // if it is something that need to be shared with background script 41 | if(event.data == 'get-sourceId' || event.data === 'audio-plus-tab') { 42 | // forward message to background script 43 | port.postMessage(event.data); 44 | } 45 | }); 46 | 47 | // inform browser that you're available! 48 | window.postMessage('rtcmulticonnection-extension-loaded', '*'); 49 | -------------------------------------------------------------------------------- /desktopCapture-p2p/extension-pages/chat.js: -------------------------------------------------------------------------------- 1 | var txtChatMessage = document.getElementById('txt-chat-message'); 2 | var chatMessages = document.getElementById('chat-messages'); 3 | 4 | var port = chrome.runtime.connect(); 5 | 6 | txtChatMessage.onkeyup = function(e) { 7 | if(e.keyCode === 13) { 8 | var checkmark_id = (Math.random()*100).toString().replace('.', ''); 9 | appendChatMessage('You', this.value, checkmark_id); 10 | port.postMessage({ 11 | messageFromContentScript1234: true, 12 | newChatMessage: this.value, 13 | checkmark_id: checkmark_id 14 | }); 15 | this.value = ''; 16 | } 17 | }; 18 | 19 | function appendChatMessage(name, message, checkmark_id) { 20 | var div = document.createElement('div'); 21 | if(checkmark_id) { 22 | div.innerHTML = '

' + name + ':

' + message + '

'; 23 | } 24 | else { 25 | div.innerHTML = '

' + name + ':

' + message + '

'; 26 | } 27 | chatMessages.appendChild(div); 28 | 29 | chatMessages.scrollTop = chatMessages.clientHeight; 30 | chatMessages.scrollTop = chatMessages.scrollHeight - chatMessages.scrollTop; 31 | } 32 | 33 | port.onMessage.addListener(function(message) { 34 | if (!message || !message.messageFromContentScript1234) { 35 | return; 36 | } 37 | 38 | if(message.newChatMessage) { 39 | appendChatMessage('Viewer', message.newChatMessage); 40 | } 41 | 42 | if(message.receivedChatMessage) { 43 | if(document.getElementById(message.checkmark_id)) { 44 | document.getElementById(message.checkmark_id).style.display = ''; 45 | } 46 | } 47 | }); 48 | 49 | window.onbeforeunload = function() { 50 | port.postMessage({ 51 | messageFromContentScript1234: true, 52 | closeChat: true 53 | }); 54 | }; 55 | -------------------------------------------------------------------------------- /desktopCapture-p2p/background/captureCamera.js: -------------------------------------------------------------------------------- 1 | function captureCamera(callback) { 2 | var supported = navigator.mediaDevices.getSupportedConstraints(); 3 | var constraints = {}; 4 | 5 | if (enableCamera) { 6 | constraints.video = { 7 | width: { 8 | min: 640, 9 | ideal: 1920, 10 | max: 1920 11 | }, 12 | height: { 13 | min: 400, 14 | ideal: 1080 15 | } 16 | }; 17 | 18 | if (supported.aspectRatio) { 19 | constraints.video.aspectRatio = 1.777777778; 20 | } 21 | 22 | if (supported.frameRate) { 23 | constraints.video.frameRate = { 24 | ideal: 30 25 | }; 26 | } 27 | 28 | if (cameraDevice && cameraDevice.length) { 29 | constraints.video.deviceId = cameraDevice; 30 | } 31 | } 32 | 33 | if (enableMicrophone) { 34 | constraints.audio = {}; 35 | 36 | if (microphoneDevice && microphoneDevice.length) { 37 | constraints.audio.deviceId = microphoneDevice; 38 | } 39 | 40 | if (supported.echoCancellation) { 41 | constraints.audio.echoCancellation = true; 42 | } 43 | } 44 | 45 | navigator.mediaDevices.getUserMedia(constraints).then(function(stream) { 46 | initVideoPlayer(stream); 47 | callback(stream); 48 | 49 | if (enableCamera && !enableScreen) { 50 | openVideoPreview(stream); 51 | } 52 | }).catch(function(error) { 53 | // error.message === 'Failed due to shutdown' 54 | chrome.tabs.create({ 55 | url: 'extension-pages/camera-mic.html' 56 | }); 57 | 58 | // setDefaults(); 59 | chrome.storage.sync.set({ 60 | enableTabCaptureAPI: 'false', 61 | enableMicrophone: 'false', 62 | enableCamera: 'false', 63 | enableScreen: 'false', 64 | isSharingOn: 'false', 65 | enableSpeakers: 'false' 66 | }); 67 | }); 68 | } 69 | -------------------------------------------------------------------------------- /desktopCapture-p2p/background/shareStreamUsingAntMediaServer.js: -------------------------------------------------------------------------------- 1 | function shareStreamUsingAntMediaServer(stream) { 2 | var wrapper = new AntMediaWrapper(); 3 | wrapper.callbacks('onopen', function() { 4 | var uid = room_id || (Math.random() * 100).toString().replace('.', ''); 5 | wrapper.publish(stream, uid, function(isPublished, error) { 6 | if (isPublished === true) { 7 | var resultingURL = 'http://webrtcweb.com/screen/ant/?s=' + uid; 8 | var hlsURL = 'http://webrtcweb.com/screen/ant/?s=' + uid + '&hls=true'; 9 | 10 | var html = "Unique Room URL

Copy following private URL:

"; 11 | html += "


"; 12 | html += "


"; 13 | 14 | var popup_width = 600; 15 | var popup_height = 230; 16 | 17 | chrome.windows.create({ 18 | url: "data:text/html," + html, 19 | type: 'popup', 20 | width: popup_width, 21 | height: popup_height, 22 | top: parseInt((screen.height / 2) - (popup_height / 2)), 23 | left: parseInt((screen.width / 2) - (popup_width / 2)), 24 | focused: true 25 | }, function(win) { 26 | popup_id = win.id; 27 | }); 28 | 29 | chrome.browserAction.enable(); 30 | setBadgeText(0); 31 | } else { 32 | alert(error); 33 | } 34 | }); 35 | }); 36 | 37 | wrapper.callbacks('onerror', function() { 38 | alert('Ant-Media Server is down or not reachable in the moment. Please go to options page and try other streaming method.'); 39 | stream.getTracks().forEach(function(track) { 40 | track.stop(); 41 | }); 42 | setDefaults(); 43 | }); 44 | } 45 | -------------------------------------------------------------------------------- /desktopCapture-p2p/server.js: -------------------------------------------------------------------------------- 1 | // http://127.0.0.1:9001 2 | // http://localhost:9001 3 | 4 | var server = require('http'), 5 | url = require('url'), 6 | path = require('path'), 7 | fs = require('fs'); 8 | 9 | function serverHandler(request, response) { 10 | var uri = url.parse(request.url).pathname, 11 | filename = path.join(process.cwd(), uri); 12 | 13 | fs.exists(filename, function(exists) { 14 | if (!exists) { 15 | response.writeHead(404, { 16 | 'Content-Type': 'text/plain' 17 | }); 18 | response.write('404 Not Found: ' + filename + '\n'); 19 | response.end(); 20 | return; 21 | } 22 | 23 | if (filename.indexOf('favicon.ico') !== -1) { 24 | return; 25 | } 26 | 27 | var isWin = !!process.platform.match(/^win/); 28 | 29 | if (fs.statSync(filename).isDirectory() && !isWin) { 30 | filename += '/index.html'; 31 | } else if (fs.statSync(filename).isDirectory() && !!isWin) { 32 | filename += '\\index.html'; 33 | } 34 | 35 | fs.readFile(filename, 'binary', function(err, file) { 36 | if (err) { 37 | response.writeHead(500, { 38 | 'Content-Type': 'text/plain' 39 | }); 40 | response.write(err + '\n'); 41 | response.end(); 42 | return; 43 | } 44 | 45 | var contentType; 46 | 47 | if (filename.indexOf('.html') !== -1) { 48 | contentType = 'text/html'; 49 | } 50 | 51 | if (filename.indexOf('.js') !== -1) { 52 | contentType = 'application/javascript'; 53 | } 54 | 55 | if (contentType) { 56 | response.writeHead(200, { 57 | 'Content-Type': contentType 58 | }); 59 | } else response.writeHead(200); 60 | 61 | response.write(file, 'binary'); 62 | response.end(); 63 | }); 64 | }); 65 | } 66 | 67 | var app; 68 | 69 | app = server.createServer(serverHandler); 70 | 71 | app = app.listen(process.env.PORT || 9001, process.env.IP || "0.0.0.0", function() { 72 | var addr = app.address(); 73 | console.log("Server listening at", addr.address + ":" + addr.port); 74 | }); 75 | -------------------------------------------------------------------------------- /desktopCapture-p2p/extension-pages/chat.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Chat 5 | 6 | 84 | 85 | 86 |
87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /desktopCapture-p2p/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"WebRTC Desktop Sharing", 3 | "author":"Muaz Khan", 4 | "version":"6.2", 5 | "manifest_version":2, 6 | "minimum_chrome_version":"34", 7 | "description":"WebRTC P2P HQ/HD screen-sharing. Share camera, microphone, speakers, full-screen, or software's screens.", 8 | "homepage_url":"https://github.com/muaz-khan/Chrome-Extensions/tree/master/desktopCapture-p2p", 9 | "background":{ 10 | "scripts":[ 11 | "background/helpers/socket.io.js", 12 | "background/helpers/adapter.js", 13 | "background/helpers/RTCMultiConnection.min.js", 14 | "background/helpers/CodecsHandler.js", 15 | "background/helpers/IceServersHandler.js", 16 | "background/helpers/MultiStreamsMixer.js", 17 | "background/helpers/AntMediaWrapper.js", 18 | "background/globals.js", 19 | "background/common.js", 20 | "background/runtimePort.js", 21 | "background/online-offline.js", 22 | "background/gotTabCaptureStream.js", 23 | "background/gotStream.js", 24 | "background/onAccessApproved.js", 25 | "background/setupWebRTCConnection.js", 26 | "background/shareStreamUsingRTCMultiConnection.js", 27 | "background/shareStreamUsingAntMediaServer.js", 28 | "background/setDefaults.js", 29 | "background/captureDesktop.js", 30 | "background/captureCamera.js", 31 | "background/captureTabUsingTabCapture.js" 32 | ], 33 | "persistent":false 34 | }, 35 | "browser_action":{ 36 | "default_icon":"images/desktopCapture22.png", 37 | "default_title":"Share Your Screen", 38 | "default_popup": "extension-pages/dropdown.html" 39 | }, 40 | "icons":{ 41 | "16":"images/desktopCapture16.png", 42 | "22":"images/desktopCapture22.png", 43 | "32":"images/desktopCapture32.png", 44 | "48":"images/desktopCapture48.png", 45 | "128":"images/desktopCapture128.png" 46 | }, 47 | "permissions":[ 48 | "desktopCapture", 49 | "storage", 50 | "tabs", 51 | "", 52 | "activeTab", 53 | "tabCapture" 54 | ], 55 | "web_accessible_resources":[ 56 | "images/desktopCapture48.png" 57 | ], 58 | "options_ui":{ 59 | "page":"extension-pages/options.html", 60 | "chrome_style":true 61 | } 62 | } -------------------------------------------------------------------------------- /screen-recording/camera-mic.js: -------------------------------------------------------------------------------- 1 | document.write('

The purpose of this page is to access your camera and microphone.

'); 2 | 3 | var port = chrome.runtime.connect(); 4 | 5 | navigator.mediaDevices.getUserMedia({ 6 | audio: true, 7 | video: true 8 | }).then(function(stream) { 9 | var tracksLength = stream.getTracks().length; 10 | 11 | stream.getTracks().forEach(function(track) { 12 | track.stop(); 13 | }); 14 | 15 | if(tracksLength <= 1) { 16 | throw new Error('Expected two tracks but received: ' + tracksLength); 17 | } 18 | 19 | port.postMessage({ 20 | messageFromContentScript1234: true, 21 | startRecording: true 22 | }); 23 | window.close(); 24 | }).catch(function(e) { 25 | navigator.mediaDevices.getUserMedia({ 26 | audio: true 27 | }).then(function(stream) { 28 | var tracksLength = stream.getTracks().length; 29 | 30 | stream.getTracks().forEach(function(track) { 31 | track.stop(); 32 | }); 33 | 34 | if(tracksLength < 1) { 35 | throw new Error('Expected at least one track but received: ' + tracksLength); 36 | } 37 | 38 | port.postMessage({ 39 | messageFromContentScript1234: true, 40 | startRecording: true, 41 | onlyMicrophone: true 42 | }); 43 | window.close(); 44 | }).catch(function() { 45 | var html = '

Unable to access your camera and/or microphone.

'; 46 | html += '

Please go to following pages and remove "RecordRTC" from blocked-list:

'; 47 | html += '
chrome://settings/content/camera?search=camera
'; 48 | html += '
chrome://settings/content/microphone?search=microphone
'; 49 | 50 | if(e.message && e.message.toString().length) { 51 | html += '
Error Message: ' + e.message + '
'; 52 | } 53 | 54 | document.body.innerHTML = html; 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /screen-recording/video.js: -------------------------------------------------------------------------------- 1 | // var src = location.href.split('?src=')[1]; 2 | // document.querySelector('video').src = src; 3 | 4 | var video = document.querySelector('video'); 5 | video.style.height = parseInt(innerHeight - 100) + 'px'; 6 | 7 | var deviceId = {}; 8 | chrome.storage.sync.get(null, function(items) { 9 | var hints = { 10 | video: true 11 | }; 12 | 13 | if(items['camera'] && typeof items['camera'] === 'string') { 14 | hints.video = { 15 | deviceId: items['camera'] 16 | }; 17 | } 18 | 19 | if(items['videoResolutions'] && items['videoResolutions'] !== 'default') { 20 | var videoResolutions = items['videoResolutions']; 21 | 22 | if(hints.video === true) { 23 | hints.video = {}; 24 | } 25 | 26 | var width = videoResolutions.split('x')[0]; 27 | var height = videoResolutions.split('x')[1]; 28 | 29 | if(width && height) { 30 | hints.video.width = { 31 | ideal: width 32 | }; 33 | 34 | hints.video.height = { 35 | ideal: height 36 | }; 37 | } 38 | } 39 | 40 | navigator.mediaDevices.getUserMedia(hints).then(function(stream) { 41 | video.srcObject = stream; 42 | }).catch(function() { 43 | // retry with default devices 44 | hints = { 45 | video: true 46 | }; 47 | 48 | navigator.mediaDevices.getUserMedia(hints).then(function(stream) { 49 | video.srcObject = stream; 50 | }).catch(function() { 51 | alert('Unable to capture your camera.'); 52 | }); 53 | }); 54 | }); 55 | 56 | 57 | document.querySelector('button').onclick = function() { 58 | window.close(); 59 | }; 60 | 61 | function msToTime(s) { 62 | function addZ(n) { 63 | return (n < 10 ? '0' : '') + n; 64 | } 65 | 66 | var ms = s % 1000; 67 | s = (s - ms) / 1000; 68 | var secs = s % 60; 69 | s = (s - secs) / 60; 70 | var mins = s % 60; 71 | var hrs = (s - mins) / 60; 72 | 73 | return addZ(mins) + ':' + addZ(secs); 74 | } 75 | 76 | var span = document.querySelector('span'); 77 | var startedAt = (new Date).getTime(); 78 | var counter = 1; 79 | (function looper() { 80 | counter ++; 81 | 82 | if(counter % 2 == 0) { 83 | span.style.color = 'red'; 84 | } 85 | else { 86 | span.style.color = 'black'; 87 | } 88 | 89 | var current = (new Date).getTime() - startedAt; 90 | span.innerHTML = msToTime(current); 91 | setTimeout(looper, 1000); 92 | })(); 93 | -------------------------------------------------------------------------------- /screen-recording/background/background.tabCapture.js: -------------------------------------------------------------------------------- 1 | function captureTabUsingTabCapture(isNoAudio) { 2 | chrome.tabs.query({ 3 | active: true, 4 | currentWindow: true 5 | }, function(arrayOfTabs) { 6 | var activeTab = arrayOfTabs[0]; 7 | var activeTabId = activeTab.id; // or do whatever you need 8 | 9 | var constraints = { 10 | audio: isNoAudio === true ? false : true, 11 | video: true, 12 | videoConstraints: { 13 | mandatory: { 14 | chromeMediaSource: 'tab', 15 | maxWidth: 3840, 16 | maxHeight: 2160 17 | } 18 | }, 19 | audioConstraints: isNoAudio === true ? false : { 20 | mandatory: { 21 | echoCancellation: true 22 | } 23 | } 24 | }; 25 | 26 | // chrome.tabCapture.onStatusChanged.addListener(function(event) { /* event.status */ }); 27 | 28 | chrome.tabCapture.capture(constraints, function(stream) { 29 | gotTabCaptureStream(stream, constraints); 30 | 31 | // chrome.tabs.update(activeTabId, {active: true}); 32 | 33 | try { 34 | // to fix bug: https://github.com/muaz-khan/RecordRTC/issues/281 35 | chrome.tabs.executeScript(activeTabId, { 36 | code: executeScriptForTabCapture.toString() + ';executeScriptForTabCapture();' 37 | }); 38 | } 39 | catch(e) {} 40 | }); 41 | }); 42 | } 43 | 44 | function gotTabCaptureStream(stream, constraints) { 45 | if (!stream) { 46 | if (constraints.audio === true) { 47 | captureTabUsingTabCapture(true); 48 | return; 49 | } 50 | chrome.runtime.reload(); 51 | return; 52 | } 53 | 54 | var newStream = new MediaStream(); 55 | 56 | if(enableTabCaptureAPIAudioOnly) { 57 | getTracks(stream, 'audio').forEach(function(track) { 58 | newStream.addTrack(track); 59 | }); 60 | } 61 | else { 62 | stream.getTracks().forEach(function(track) { 63 | newStream.addTrack(track); 64 | }); 65 | } 66 | 67 | initVideoPlayer(newStream); 68 | 69 | gotStream(newStream); 70 | } 71 | 72 | function executeScriptForTabCapture() { 73 | var div = document.createElement('img'); 74 | div.style = 'position: fixed;top: 0px;right: 0px;width: 20px;z-index: 2147483647;'; 75 | div.src = 'https://webrtcweb.com/progress.gif'; 76 | (document.body || document.documentElement).appendChild(div); 77 | } 78 | -------------------------------------------------------------------------------- /Screen-Capturing.js/server.js: -------------------------------------------------------------------------------- 1 | // Muaz Khan - www.MuazKhan.com 2 | // MIT License - www.WebRTC-Experiment.com/licence 3 | // Documentation - github.com/muaz-khan/getScreenId 4 | 5 | var port = process.env.PORT || 9001; 6 | 7 | var server = require('http'), 8 | url = require('url'), 9 | path = require('path'), 10 | fs = require('fs'); 11 | 12 | function serverHandler(request, response) { 13 | try { 14 | var uri = url.parse(request.url).pathname, 15 | filename = path.join(process.cwd(), uri); 16 | 17 | if (filename && filename.search(/server.js/g) !== -1) { 18 | response.writeHead(404, { 19 | 'Content-Type': 'text/plain' 20 | }); 21 | response.write('404 Not Found: ' + path.join('/', uri) + '\n'); 22 | response.end(); 23 | return; 24 | } 25 | 26 | var stats; 27 | 28 | try { 29 | stats = fs.lstatSync(filename); 30 | } catch (e) { 31 | response.writeHead(404, { 32 | 'Content-Type': 'text/plain' 33 | }); 34 | response.write('404 Not Found: ' + path.join('/', uri) + '\n'); 35 | response.end(); 36 | return; 37 | } 38 | 39 | if (fs.statSync(filename).isDirectory()) { 40 | response.writeHead(404, { 41 | 'Content-Type': 'text/html' 42 | }); 43 | 44 | filename += '/index.html'; 45 | } 46 | 47 | 48 | fs.readFile(filename, 'utf8', function(err, file) { 49 | if (err) { 50 | response.writeHead(500, { 51 | 'Content-Type': 'text/plain' 52 | }); 53 | response.write('404 Not Found: ' + path.join('/', uri) + '\n'); 54 | response.end(); 55 | return; 56 | } 57 | 58 | response.writeHead(200); 59 | response.write(file, 'utf8'); 60 | response.end(); 61 | }); 62 | } catch (e) { 63 | response.writeHead(404, { 64 | 'Content-Type': 'text/plain' 65 | }); 66 | response.write('

Unexpected error:



' + e.stack || e.message || JSON.stringify(e)); 67 | response.end(); 68 | } 69 | } 70 | 71 | var app = server.createServer(serverHandler); 72 | 73 | function runServer() { 74 | app = app.listen(port, process.env.IP || '0.0.0.0', function() { 75 | var addr = app.address(); 76 | 77 | if (addr.address === '0.0.0.0') { 78 | addr.address = 'localhost'; 79 | } 80 | 81 | console.log('Server listening at http://' + addr.address + ':' + addr.port); 82 | }); 83 | } 84 | 85 | runServer(); 86 | -------------------------------------------------------------------------------- /screen-recording/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"RecordRTC", 3 | "short_name":"RecordRTC", 4 | "author":"Muaz Khan", 5 | "version":"9.1", 6 | "manifest_version":2, 7 | "minimum_chrome_version":"49", 8 | "description":"Record screen activity, camera, mic, tab, speakers in 4K HD video format (using RecordRTC)", 9 | "homepage_url":"https://github.com/muaz-khan/Chrome-Extensions/tree/master/screen-recording", 10 | "background":{ 11 | "scripts":[ 12 | "background/background.common.js", 13 | "background/background.js", 14 | "background/background.desktopCapture.js", 15 | "background/background.tabCapture.js", 16 | "background/background.badgeText.js", 17 | "background/background.getUserMedia.js", 18 | "background/background.messaging.js", 19 | "background/background.players.js", 20 | "RecordRTC/MediaStreamRecorder.js", 21 | "RecordRTC/MultiStreamRecorder.js", 22 | "RecordRTC/MultiStreamsMixer.js", 23 | "RecordRTC/StereoAudioRecorder.js", 24 | "RecordRTC/DiskStorage.js", 25 | "RecordRTC/EBML.js" 26 | ], 27 | "persistent":false 28 | }, 29 | "content_scripts":[ 30 | { 31 | "matches":[ 32 | "" 33 | ], 34 | "js":[ 35 | "background/background.contentScript.js" 36 | ], 37 | "all_frames": true, 38 | "run_at": "document_start" 39 | } 40 | ], 41 | "browser_action":{ 42 | "default_icon":"images/main-icon.png", 43 | "default_title":"Record Your Screen, Tab or Camera", 44 | "default_popup": "dropdown.html" 45 | }, 46 | "icons":{ 47 | "16":"images/main-icon.png", 48 | "22":"images/main-icon.png", 49 | "32":"images/main-icon.png", 50 | "48":"images/main-icon.png", 51 | "128":"images/main-icon.png" 52 | }, 53 | "permissions":[ 54 | "desktopCapture", 55 | "storage", 56 | "tabs", 57 | "tabCapture", 58 | "activeTab", 59 | "", 60 | "identity", 61 | "https://www.googleapis.com/*" 62 | ], 63 | "oauth2": { 64 | "client_id": "41556190767-99gorp1l5qij3hlsos4jms4vosbilrsa.apps.googleusercontent.com", 65 | "scopes": [ 66 | "https://www.googleapis.com/auth/youtube.upload", 67 | "https://www.googleapis.com/auth/youtube" 68 | ] 69 | }, 70 | "content_security_policy": "script-src 'self' https://apis.google.com; object-src 'self'", 71 | "web_accessible_resources":[ 72 | "images/main-icon.png" 73 | ], 74 | "options_ui":{ 75 | "page":"options.html", 76 | "chrome_style":false, 77 | "open_in_tab": true 78 | } 79 | } -------------------------------------------------------------------------------- /desktopCapture-p2p/background/common.js: -------------------------------------------------------------------------------- 1 | function getAspectRatio(w, h) { 2 | function gcd(a, b) { 3 | return (b == 0) ? a : gcd(b, a % b); 4 | } 5 | var r = gcd(w, h); 6 | return (w / r) / (h / r); 7 | } 8 | 9 | function openVideoPreview(stream) { 10 | // var win = window.open("extension-pages/video.html?src=" + URL.createObjectURL(stream), "_blank", "top=0,left=0"); 11 | var win = window.open("extension-pages/video.html", "_blank", "top=0,left=0"); 12 | var timer = setInterval(function() { 13 | if (win.closed) { 14 | // captureDesktop(); 15 | setDefaults(); 16 | 17 | clearInterval(timer); 18 | } 19 | }, 1000); 20 | return win; 21 | } 22 | 23 | function initVideoPlayer(stream) { 24 | var videoPlayer = document.createElement('video'); 25 | videoPlayer.muted = !enableTabCaptureAPI; 26 | videoPlayer.volume = !!enableTabCaptureAPI; 27 | videoPlayer.autoplay = true; 28 | videoPlayer.srcObject = stream; 29 | videoPlayers.push(videoPlayer); 30 | } 31 | 32 | function addStreamStopListener(stream, callback) { 33 | var streamEndedEvent = 'ended'; 34 | if ('oninactive' in stream) { 35 | streamEndedEvent = 'inactive'; 36 | } 37 | stream.addEventListener(streamEndedEvent, function() { 38 | callback(); 39 | callback = function() {}; 40 | }, false); 41 | stream.getAudioTracks().forEach(function(track) { 42 | track.addEventListener(streamEndedEvent, function() { 43 | callback(); 44 | callback = function() {}; 45 | }, false); 46 | }); 47 | stream.getVideoTracks().forEach(function(track) { 48 | track.addEventListener(streamEndedEvent, function() { 49 | callback(); 50 | callback = function() {}; 51 | }, false); 52 | }); 53 | } 54 | 55 | function getUserMediaError(e) { 56 | setDefaults(); 57 | 58 | chrome.windows.create({ 59 | url: "data:text/html,

getUserMediaError: " + JSON.stringify(e, null, '
') + "


Constraints used:
" + JSON.stringify(constraints, null, '
') + '
', 60 | type: 'popup', 61 | width: screen.width / 2, 62 | height: 170 63 | }); 64 | } 65 | 66 | function setBadgeText(text) { 67 | chrome.browserAction.setBadgeBackgroundColor({ 68 | color: [255, 0, 0, 255] 69 | }); 70 | 71 | chrome.browserAction.setBadgeText({ 72 | text: text + '' 73 | }); 74 | 75 | chrome.browserAction.setTitle({ 76 | title: text + ' users are viewing your screen!' 77 | }); 78 | } 79 | 80 | // sometimes extension unexpectedly crashes or reloads 81 | // in this case, making sure to remove "ON" status 82 | // chrome.storage.sync.set({ isSharingOn: 'false' }); 83 | -------------------------------------------------------------------------------- /get-any-webrtc-peer-stream/RTCPeerConnection-override.js: -------------------------------------------------------------------------------- 1 | var nativePeer; 2 | 3 | (function looper() { 4 | var RTC = window.RTCPeerConnection || window.webkitRTCPeerConnection; 5 | 6 | if (typeof RTC.prototype.addTrack !== 'undefined' && isFuncNative(RTC.prototype.addTrack)) { 7 | RTC.prototype._addTrack = RTC.prototype.addTrack; 8 | RTC.prototype.addTrack = function(track, stream) { 9 | nativePeer = this; 10 | nativePeer.streamEvent = 'track'; 11 | this._addTrack(track, stream); 12 | }; 13 | } else if (typeof RTC.prototype.addStream !== 'undefined' && isFuncNative(RTC.prototype.addStream)) { 14 | RTC.prototype._addStream = RTC.prototype.addStream; 15 | RTC.prototype.addStream = function(stream) { 16 | nativePeer = this; 17 | nativePeer.streamEvent = 'addstream'; 18 | this._addStream(stream); 19 | }; 20 | } 21 | 22 | if (typeof nativePeer === 'undefined' || typeof nativePeer.streamEvent === 'undefined') { 23 | // console.error('looper'); 24 | setTimeout(looper, 1); // recheck 25 | return; 26 | } 27 | 28 | var dontDuplicate = {}; 29 | nativePeer.addEventListener(nativePeer.streamEvent, function(event) { 30 | if (nativePeer.streamEvent === 'track') { 31 | event.stream = event.streams[0]; 32 | } 33 | 34 | if(dontDuplicate[event.stream.id]) return; 35 | dontDuplicate[event.stream.id] = true; 36 | 37 | alert('Goto remote stream, creating offer'); 38 | 39 | createOffer(event.stream); 40 | }, false); 41 | })(); 42 | 43 | function isFuncNative(f) { 44 | return !!f && (typeof f).toLowerCase() == 'function' && 45 | (f === Function.prototype || 46 | /^\s*function\s*(\b[a-z$_][a-z0-9$_]*\b)*\s*\((|([a-z$_][a-z0-9$_]*)(\s*,[a-z$_][a-z0-9$_]*)*)\)\s*{\s*\[native code\]\s*}\s*$/i.test(String(f))); 47 | } 48 | 49 | window.addEventListener('message', function (event) { 50 | if(event.data && event.data.RTCPeerConnection_SDP) { 51 | peer.setRemoteDescription(new RTCSessionDescription(event.data.RTCPeerConnection_SDP)); 52 | } 53 | }); 54 | 55 | function createOffer(stream) { 56 | peer = new webkitRTCPeerConnection(null); 57 | peer.addStream(stream); 58 | 59 | peer.onicecandidate = function(event) { 60 | if (!event || !!event.candidate) return; 61 | 62 | window.postMessage({ 63 | RTCPeerConnection_SDP: { 64 | sdp: peer.localDescription.sdp, 65 | type: peer.localDescription.type 66 | } 67 | }, '*'); 68 | }; 69 | 70 | peer.createOffer(function(sdp) { 71 | peer.setLocalDescription(sdp); 72 | }, function() {}, { 73 | optional: [], 74 | mandatory: { 75 | OfferToReceiveAudio: false, 76 | OfferToReceiveVideo: false 77 | } 78 | }); 79 | } 80 | -------------------------------------------------------------------------------- /screen-recording/background/background.badgeText.js: -------------------------------------------------------------------------------- 1 | function setVODRecordingBadgeText(text, title) { 2 | chrome.browserAction.setBadgeBackgroundColor({ 3 | color: [203, 0, 15, 255] 4 | }); 5 | 6 | chrome.browserAction.setBadgeText({ 7 | text: text 8 | }); 9 | 10 | chrome.browserAction.setTitle({ 11 | title: title && title.length ? title + ' duration' : 'Record Screen' 12 | }); 13 | } 14 | 15 | function msToTime(s) { 16 | function addZ(n) { 17 | return (n < 10 ? '0' : '') + n; 18 | } 19 | 20 | var ms = s % 1000; 21 | s = (s - ms) / 1000; 22 | var secs = s % 60; 23 | s = (s - secs) / 60; 24 | var mins = s % 60; 25 | var hrs = (s - mins) / 60; 26 | 27 | return addZ(hrs) + ':' + addZ(mins) + ':' + addZ(secs) + '.' + ms; 28 | } 29 | 30 | function convertTime(miliseconds) { 31 | var totalSeconds = Math.floor(miliseconds / 1000); 32 | var minutes = Math.floor(totalSeconds / 60); 33 | var seconds = totalSeconds - minutes * 60; 34 | 35 | minutes += ''; 36 | seconds += ''; 37 | 38 | if (minutes.length === 1) { 39 | // minutes = '0' + minutes; 40 | } 41 | 42 | if (seconds.length === 1) { 43 | seconds = '0' + seconds; 44 | } 45 | 46 | return minutes + ':' + seconds; 47 | } 48 | 49 | 50 | var initialTime, timer; 51 | 52 | function checkTime() { 53 | if (!initialTime || !isRecording) return; 54 | var timeDifference = Date.now() - initialTime; 55 | var formatted = convertTime(timeDifference); 56 | setBadgeText(formatted); 57 | 58 | chrome.browserAction.setTitle({ 59 | title: 'Recording duration: ' + formatted 60 | }); 61 | } 62 | 63 | function setBadgeText(text) { 64 | chrome.browserAction.setBadgeBackgroundColor({ 65 | color: [255, 0, 0, 255] 66 | }); 67 | 68 | chrome.browserAction.setBadgeText({ 69 | text: text + '' 70 | }); 71 | } 72 | 73 | 74 | var images = ['recordRTC-progress-1.png', 'recordRTC-progress-2.png', 'recordRTC-progress-3.png', 'recordRTC-progress-4.png', 'recordRTC-progress-5.png']; 75 | var imgIndex = 0; 76 | var reverse = false; 77 | 78 | function onRecording() { 79 | if(!isRecording) return; 80 | 81 | chrome.browserAction.setIcon({ 82 | path: 'images/' + images[imgIndex] 83 | }); 84 | 85 | if (!reverse) { 86 | imgIndex++; 87 | 88 | if (imgIndex > images.length - 1) { 89 | imgIndex = images.length - 1; 90 | reverse = true; 91 | } 92 | } else { 93 | imgIndex--; 94 | 95 | if (imgIndex < 0) { 96 | imgIndex = 1; 97 | reverse = false; 98 | } 99 | } 100 | 101 | if (isRecording) { 102 | setTimeout(onRecording, 800); 103 | return; 104 | } 105 | 106 | chrome.browserAction.setIcon({ 107 | path: 'images/main-icon.png' 108 | }); 109 | } 110 | -------------------------------------------------------------------------------- /getUserMedia-on-http/example/index.js: -------------------------------------------------------------------------------- 1 | var logs = document.querySelector('#logs'); 2 | function showLog(log) { 3 | var div = document.createElement('div'); 4 | div.innerHTML = log; 5 | logs.appendChild(div); 6 | } 7 | 8 | var getUserMediaStreamObject; 9 | 10 | function getUserMedia() { 11 | if(typeof getUserMediaHttp !== 'function') { 12 | showLog('getUserMedia extension is not installed or disabled.'); 13 | showLog('Please install this extension: https://chrome.google.com/webstore/detail/getusermedia/nbnpcmljmiinldficickhdoaiblgkggc'); 14 | return; 15 | } 16 | 17 | showLog('Calling getUserMediaHttp...'); 18 | 19 | var hints = { 20 | audio: true, 21 | video: true 22 | }; 23 | 24 | var checkedRadioId = document.querySelector('input[type=radio]:checked').id; 25 | 26 | if(checkedRadioId === 'camera') { 27 | hints = { 28 | audio: true, 29 | video: true 30 | }; 31 | } 32 | 33 | if(checkedRadioId === 'microphone') { 34 | hints = { 35 | audio: true 36 | }; 37 | } 38 | 39 | if(checkedRadioId === 'screen') { 40 | hints = { 41 | video: { 42 | mediaSource: 'screen' 43 | } 44 | }; 45 | } 46 | 47 | showLog('getUserMediaHttp hints: ' + JSON.stringify(hints)); 48 | 49 | navigator.mediaDevices.getUserMedia(hints).then(function(stream) { 50 | getUserMediaStreamObject = stream; 51 | 52 | showLog('Got stream from getUserMediaHttp...'); 53 | 54 | stream.getTracks().forEach(function(track) { 55 | showLog(track.kind + ': ' + track.readyState); 56 | }); 57 | 58 | document.querySelector('video').srcObject = stream; 59 | }).catch(function(e) { 60 | showLog('Message: ' + e.message); 61 | showLog('Stack: ' + e.stack); 62 | }); 63 | } 64 | 65 | document.querySelector('#getUserMedia').onclick = function() { 66 | this.disabled = true; 67 | 68 | if(!getUserMediaStreamObject) { 69 | this.innerHTML = 'Stop getUserMedia Stream'; 70 | getUserMedia(); 71 | } 72 | else { 73 | this.innerHTML = 'getUserMedia'; 74 | 75 | getUserMediaStreamObject.getTracks().forEach(function(track) { 76 | track.stop(); 77 | }); 78 | 79 | document.querySelector('video').srcObject = null; 80 | } 81 | 82 | setTimeout(function() { 83 | document.querySelector('#getUserMedia').disabled = false; 84 | }, 1000); 85 | }; 86 | 87 | document.querySelectorAll('#radio-container input[type=radio]').forEach(function(radio) { 88 | radio.onclick = function() { 89 | document.querySelectorAll('#radio-container input[type=radio]:checked').forEach(function(radio) { 90 | radio.checked = false; 91 | }); 92 | this.checked = true; 93 | }; 94 | }); 95 | -------------------------------------------------------------------------------- /desktopCapture-p2p/screen-receivers/ant/index.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | WebRTC AntMedia Broadcast Viewer 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 63 | 64 | 65 | 66 |
67 |
68 |
69 | 70 | 71 | 72 | 73 | 118 | -------------------------------------------------------------------------------- /screen-recording/background/background.messaging.js: -------------------------------------------------------------------------------- 1 | var runtimePort; 2 | 3 | chrome.runtime.onConnect.addListener(function(port) { 4 | runtimePort = port; 5 | 6 | runtimePort.onMessage.addListener(function(message) { 7 | if (!message || !message.messageFromContentScript1234) { 8 | return; 9 | } 10 | 11 | if (message.startRecording) { 12 | if(message.onlyMicrophone && enableCamera) { 13 | message.startRecording = false; 14 | message.stopRecording = true; 15 | alert('Unable to access camera device.'); 16 | setDefaults(); 17 | return; 18 | } 19 | } 20 | 21 | if (message.startRecording) { 22 | if(message.dropdown) { 23 | openPreviewOnStopRecording = true; 24 | openCameraPreviewDuringRecording = true; 25 | } 26 | 27 | if (isRecording && message.dropdown) { 28 | stopScreenRecording(); 29 | return; 30 | } 31 | 32 | if(message.RecordRTC_Extension) { 33 | openPreviewOnStopRecording = false; 34 | openCameraPreviewDuringRecording = false; 35 | 36 | enableTabCaptureAPI = message['enableTabCaptureAPI'] === true; 37 | enableTabCaptureAPIAudioOnly = message['enableTabCaptureAPIAudioOnly'] === true; 38 | enableScreen = message['enableScreen'] === true; 39 | enableMicrophone = message['enableMicrophone'] === true; 40 | enableCamera = message['enableCamera'] === true; 41 | enableSpeakers = message['enableSpeakers'] === true; 42 | 43 | startRecordingCallback = function(file) { 44 | port.postMessage({ 45 | messageFromContentScript1234: true, 46 | startedRecording: true 47 | }); 48 | }; 49 | 50 | chrome.storage.sync.set({ 51 | enableTabCaptureAPI: enableTabCaptureAPI ? 'true' : 'false', 52 | enableTabCaptureAPIAudioOnly: enableTabCaptureAPIAudioOnly ? 'true' : 'false', 53 | enableMicrophone: enableMicrophone ? 'true' : 'false', 54 | enableCamera: enableCamera ? 'true' : 'false', 55 | enableScreen: enableScreen ? 'true' : 'false', 56 | enableSpeakers: enableSpeakers ? 'true' : 'false', 57 | isRecording: 'true' 58 | }, function() { 59 | getUserConfigs(); 60 | }); 61 | return; 62 | } 63 | 64 | getUserConfigs(); 65 | return; 66 | } 67 | 68 | if (message.stopRecording) { 69 | if(message.RecordRTC_Extension) { 70 | stopRecordingCallback = function(file) { 71 | var reader = new FileReader(); 72 | reader.onload = function(e) { 73 | port.postMessage({ 74 | messageFromContentScript1234: true, 75 | stoppedRecording: true, 76 | file: e.target.result 77 | }); 78 | }; 79 | reader.readAsDataURL(file); 80 | }; 81 | } 82 | 83 | stopScreenRecording(); 84 | return; 85 | } 86 | }); 87 | }); 88 | -------------------------------------------------------------------------------- /screen-recording/background/background.getUserMedia.js: -------------------------------------------------------------------------------- 1 | var microphoneDevice = false; 2 | var cameraDevice = false; 3 | 4 | function captureCamera(callback, defaultDevices) { 5 | var supported = navigator.mediaDevices.getSupportedConstraints(); 6 | var constraints = { 7 | audio: !!enableMicrophone, 8 | video: !!enableCamera 9 | }; 10 | 11 | if (enableCamera && !defaultDevices) { 12 | if(videoResolutions !== 'default' && videoResolutions.length) { 13 | var width = videoResolutions.split('x')[0]; 14 | var height = videoResolutions.split('x')[1]; 15 | 16 | if(width && height) { 17 | constraints.video = { 18 | width: { 19 | ideal: width 20 | }, 21 | height: { 22 | ideal: height 23 | } 24 | }; 25 | }; 26 | } 27 | 28 | if (supported.aspectRatio) { 29 | constraints.video.aspectRatio = 1.777777778; 30 | } 31 | 32 | if (supported.frameRate && videoMaxFrameRates) { 33 | constraints.video.frameRate = { 34 | ideal: parseInt(videoMaxFrameRates) 35 | }; 36 | } 37 | 38 | if (cameraDevice && typeof cameraDevice === 'string') { 39 | constraints.video.deviceId = cameraDevice; 40 | } 41 | } 42 | 43 | if (enableMicrophone && !defaultDevices) { 44 | constraints.audio = {}; 45 | 46 | if (microphoneDevice && typeof microphoneDevice === 'string') { 47 | constraints.audio.deviceId = microphoneDevice; 48 | } 49 | 50 | if (supported.echoCancellation) { 51 | constraints.audio.echoCancellation = true; 52 | } 53 | } 54 | 55 | if(!constraints.audio && !constraints.video) { 56 | // todo: should we display alert? 57 | constraints = { 58 | audio: true, 59 | video: true 60 | }; 61 | } 62 | 63 | navigator.mediaDevices.getUserMedia(constraints).then(function(stream) { 64 | initVideoPlayer(stream); 65 | callback(stream); 66 | 67 | if (enableCamera && !enableScreen && openCameraPreviewDuringRecording) { 68 | var win = window.open("video.html", "_blank", "top=0,left=0,width=" + screen.width + ",height=" + screen.height); 69 | 70 | var timer = setInterval(function() { 71 | if (win.closed) { 72 | clearInterval(timer); 73 | stopScreenRecording(); 74 | } 75 | }, 1000); 76 | } 77 | }).catch(function(error) { 78 | if(!defaultDevices) { 79 | // retry with default devices 80 | captureCamera(callback, true); 81 | return; 82 | } 83 | 84 | false && chrome.tabs.create({ 85 | url: 'camera-mic.html' 86 | }); 87 | 88 | var popup_width = screen.width - parseInt(screen.width / 3); 89 | var popup_height = screen.height - parseInt(screen.height / 3); 90 | chrome.windows.create({ 91 | url: 'camera-mic.html', 92 | type: 'popup', 93 | width: popup_width, 94 | height: popup_height, 95 | top: parseInt((screen.height / 2) - (popup_height / 2)), 96 | left: parseInt((screen.width / 2) - (popup_width / 2)), 97 | focused: true 98 | }); 99 | 100 | // setDefaults(); 101 | }); 102 | } 103 | -------------------------------------------------------------------------------- /tabCapture/options.js: -------------------------------------------------------------------------------- 1 | chrome.storage.sync.get(null, function(items) { 2 | if (items['resolutions']) { 3 | document.getElementById('resolutions').value = items['resolutions']; 4 | } else { 5 | chrome.storage.sync.set({ 6 | resolutions: 'fit-screen' 7 | }, function() { 8 | document.getElementById('resolutions').value = 'fit-screen' 9 | }); 10 | } 11 | 12 | if (items['min_bandwidth']) { 13 | document.getElementById('min_bandwidth').value = items['min_bandwidth']; 14 | } else { 15 | chrome.storage.sync.set({ 16 | min_bandwidth: 512 17 | }, function() {}); 18 | } 19 | 20 | if (items['max_bandwidth']) { 21 | document.getElementById('max_bandwidth').value = items['max_bandwidth']; 22 | } else { 23 | chrome.storage.sync.set({ 24 | max_bandwidth: 1048 25 | }, function() {}); 26 | } 27 | 28 | if (items['room_password']) { 29 | document.getElementById('room_password').value = items['room_password']; 30 | } 31 | 32 | if (items['room_id']) { 33 | document.getElementById('room_id').value = items['room_id']; 34 | } 35 | }); 36 | 37 | document.getElementById('resolutions').onchange = function() { 38 | this.disabled = true; 39 | 40 | chrome.storage.sync.set({ 41 | resolutions: this.value 42 | }, function() { 43 | document.getElementById('resolutions').disabled = false; 44 | }); 45 | }; 46 | 47 | document.getElementById('min_bandwidth').onblur = function() { 48 | var maxValue = parseInt(document.getElementById('max_bandwidth').value); 49 | var minValue = parseInt(document.getElementById('min_bandwidth').value); 50 | if(maxValue < minValue) { 51 | console.log('Min-Bandwidth must be lower than Max-Bandwidth.'); 52 | document.getElementById('max_bandwidth').value = 53 | document.getElementById('min_bandwidth').value = this.value; 54 | return; 55 | } 56 | 57 | this.disabled = true; 58 | 59 | chrome.storage.sync.set({ 60 | min_bandwidth: this.value 61 | }, function() { 62 | document.getElementById('min_bandwidth').disabled = false; 63 | }); 64 | }; 65 | 66 | document.getElementById('max_bandwidth').onblur = function() { 67 | var maxValue = parseInt(document.getElementById('max_bandwidth').value); 68 | var minValue = parseInt(document.getElementById('min_bandwidth').value); 69 | if(maxValue < minValue) { 70 | console.log('Min-Bandwidth must be lower than Max-Bandwidth.'); 71 | document.getElementById('max_bandwidth').value = 72 | document.getElementById('min_bandwidth').value = this.value; 73 | return; 74 | } 75 | 76 | this.disabled = true; 77 | 78 | chrome.storage.sync.set({ 79 | max_bandwidth: this.value 80 | }, function() { 81 | document.getElementById('max_bandwidth').disabled = false; 82 | }); 83 | }; 84 | 85 | document.getElementById('room_password').onblur = function() { 86 | this.disabled = true; 87 | 88 | chrome.storage.sync.set({ 89 | room_password: this.value 90 | }, function() { 91 | document.getElementById('room_password').disabled = false; 92 | }); 93 | }; 94 | 95 | document.getElementById('room_id').onblur = function() { 96 | this.disabled = true; 97 | 98 | chrome.storage.sync.set({ 99 | room_id: this.value 100 | }, function() { 101 | document.getElementById('room_id').disabled = false; 102 | }); 103 | }; 104 | -------------------------------------------------------------------------------- /getUserMedia-on-http/webrtc-handler.js: -------------------------------------------------------------------------------- 1 | function webrtcHandler() { 2 | return { 3 | createOffer: function(stream, callback) { 4 | var peer = this.getPeer(); 5 | 6 | if(stream) { 7 | if ('addStream' in peer) { 8 | peer.addStream(stream); 9 | } else { 10 | peer.addTrack(stream.getVideoTracks()[0], stream); 11 | } 12 | } 13 | 14 | peer.onicecandidate = function(event) { 15 | if (!event || event.candidate) { 16 | return; 17 | } 18 | 19 | callback({ 20 | sdp: peer.localDescription.sdp, 21 | type: peer.localDescription.type 22 | }); 23 | }; 24 | peer.createOffer({ 25 | OfferToReceiveAudio: false, 26 | OfferToReceiveVideo: false 27 | }).then(function(sdp) { 28 | peer.setLocalDescription(sdp); 29 | }).catch(function(error) { 30 | console.error('createOffer', error); 31 | }); 32 | }, 33 | setRemoteDescription: function(sdp) { 34 | this.peer.setRemoteDescription(new RTCSessionDescription(sdp)).catch(function(error) { 35 | console.error('setRemoteDescription', error); 36 | }); 37 | }, 38 | createAnswer: function(sdp, callback) { 39 | var peer = this.getPeer(); 40 | 41 | peer.onicecandidate = function(event) { 42 | if (!event || event.candidate) { 43 | return; 44 | } 45 | 46 | callback({ 47 | sdp: peer.localDescription.sdp, 48 | type: peer.localDescription.type 49 | }); 50 | }; 51 | this.peer.setRemoteDescription(new RTCSessionDescription(sdp)).then(function() { 52 | peer.createAnswer({ 53 | OfferToReceiveAudio: true, 54 | OfferToReceiveVideo: true 55 | }).then(function(sdp) { 56 | peer.setLocalDescription(sdp); 57 | }).catch(function(error) { 58 | console.error('createAnswer', error); 59 | }); 60 | }).catch(function(error) { 61 | console.error('setRemoteDescription', error); 62 | }); 63 | 64 | if ('onaddstream' in peer) { 65 | peer.onaddstream = function(event) { 66 | callback({ 67 | stream: event.stream 68 | }); 69 | }; 70 | } else { 71 | peer.onaddtrack = function(event) { 72 | callback({ 73 | stream: event.streams[0] 74 | }); 75 | }; 76 | } 77 | }, 78 | getParams: function() { 79 | return params = { 80 | iceServers: [], // IceServersHandler.getIceServers() 81 | iceTransportPolicy: 'all', 82 | bundlePolicy: 'max-bundle', 83 | iceTransportPolicy: 0, 84 | rtcpMuxPolicy: 'require' // or negotiate 85 | }; 86 | }, 87 | getPeer: function() { 88 | var WebRTC_Native_Peer = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection; 89 | var peer = new WebRTC_Native_Peer(null); 90 | this.peer = peer; 91 | return peer; 92 | } 93 | }; 94 | } 95 | -------------------------------------------------------------------------------- /screen-recording/README.md: -------------------------------------------------------------------------------- 1 | # Record Screen Activity, Camera, Tab, Speakers and Microphone in 4K HD video (H264, VP8, VP9, MKV) 2 | 3 | ![Try it now in CWS](https://raw.github.com/GoogleChrome/chrome-app-samples/master/tryitnowbutton.png "Click here to install this extension from the Chrome Web Store") 4 | 5 | * https://chrome.google.com/webstore/detail/recordrtc/ndcljioonkecdnaaihodjgiliohngojp 6 | 7 | Install RecordRTC Extension 8 | 9 | ## Call From Your Own WebSite 10 | 11 | **Live Demo:** [simple-demos/RecordRTC_Extension.html](https://www.webrtc-experiment.com/RecordRTC/simple-demos/RecordRTC_Extension.html) 12 | 13 | You can call this chrome extension directly from your own website as well! 14 | 15 | ```javascript 16 | if(typeof RecordRTC_Extension === 'undefined') { 17 | alert('RecordRTC chrome extension is either disabled or not installed.'); 18 | } 19 | 20 | var recorder = new RecordRTC_Extension(); 21 | recorder.startRecording(recorder.getSupoortedFormats()[7], function() { 22 | setTimeout(function() { 23 | recorder.stopRecording(function(blob) { 24 | console.log(blob.size, blob); 25 | var url = URL.createObjectURL(blob); 26 | video.src = url; 27 | }); 28 | }, 3000); 29 | }); 30 | ``` 31 | 32 | For simple code: 33 | 34 | ```javascript 35 | var recorder = new RecordRTC_Extension(); 36 | 37 | recorder.startRecording({ 38 | enableScreen: true, 39 | enableMicrophone: true, 40 | enableSpeakers: true 41 | }); 42 | 43 | btnStopRecording.onclick = function() { 44 | recorder.stopRecording(function(blob) { 45 | console.log(blob.size, blob); 46 | var url = URL.createObjectURL(blob); 47 | video.src = url; 48 | }); 49 | }; 50 | ``` 51 | 52 | ### `getSupoortedFormats` 53 | 54 | You can pass any of the following on `startRecording` method: 55 | 56 | ```javascript 57 | const getSupoortedFormats = [{ 58 | enableScreen: true 59 | }, { 60 | enableScreen: true, 61 | enableMicrophone: true 62 | }, { 63 | enableScreen: true, 64 | enableSpeakers: true 65 | }, { 66 | enableScreen: true, 67 | enableMicrophone: true, 68 | enableSpeakers: true 69 | }, { 70 | enableTabCaptureAPI: true 71 | }, { 72 | enableTabCaptureAPI: true, 73 | enableTabCaptureAPIAudioOnly: true 74 | }, { 75 | enableScreen: true, 76 | enableCamera: true 77 | }, { 78 | enableMicrophone: true, 79 | enableCamera: true 80 | }, { 81 | enableMicrophone: true, 82 | enableSpeakers: true 83 | }, { 84 | enableMicrophone: true 85 | }, { 86 | enableSpeakers: true 87 | }]; 88 | ``` 89 | 90 | ### API Explanation 91 | 92 | 1. First step is to initialize the constructor `new RecordRTC_Extension()`. 93 | 2. Second step is, pass two parameters on `startRecording`. First paramter is named as `recording-formats` and last parameter is named as `recording-start-callback`. 94 | 3. Manually stop the recording using `stopRecording` method. Callback contains two arguments. First argument is `Blob` object and second argument is `error` string. 95 | 96 | ## Disclaimer 97 | 98 | * https://www.webrtc-experiment.com/disclaimer/ 99 | 100 | ## License 101 | 102 | [Chrome-Extensions](https://github.com/muaz-khan/Chrome-Extensions) are released under [MIT license](https://github.com/muaz-khan/Chrome-Extensions/blob/master/LICENSE) . Copyright (c) [Muaz Khan](https://MuazKhan.com). 103 | -------------------------------------------------------------------------------- /screen-recording/RecordRTC/getAllAudioVideoDevices.js: -------------------------------------------------------------------------------- 1 | if (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) { 2 | // Firefox 38+, Microsoft Edge, and Chrome 44+ seems having support of enumerateDevices 3 | navigator.enumerateDevices = function(callback) { 4 | navigator.mediaDevices.enumerateDevices().then(callback); 5 | }; 6 | } 7 | 8 | function getAllAudioVideoDevices(successCallback, failureCallback) { 9 | if (!navigator.enumerateDevices && window.MediaStreamTrack && window.MediaStreamTrack.getSources) { 10 | navigator.enumerateDevices = window.MediaStreamTrack.getSources.bind(window.MediaStreamTrack); 11 | } 12 | 13 | if (!navigator.enumerateDevices && navigator.mediaDevices.enumerateDevices) { 14 | navigator.enumerateDevices = navigator.mediaDevices.enumerateDevices.bind(navigator); 15 | } 16 | 17 | if (!navigator.enumerateDevices) { 18 | failureCallback(null, 'Neither navigator.mediaDevices.enumerateDevices NOR MediaStreamTrack.getSources are available.'); 19 | return; 20 | } 21 | 22 | var allMdiaDevices = []; 23 | var allAudioDevices = []; 24 | var allVideoDevices = []; 25 | 26 | var audioInputDevices = []; 27 | var audioOutputDevices = []; 28 | var videoInputDevices = []; 29 | var videoOutputDevices = []; 30 | 31 | navigator.enumerateDevices(function(devices) { 32 | devices.forEach(function(_device) { 33 | var device = {}; 34 | for (var d in _device) { 35 | device[d] = _device[d]; 36 | } 37 | 38 | // make sure that we are not fetching duplicate devics 39 | var skip; 40 | allMdiaDevices.forEach(function(d) { 41 | if (d.id === device.id) { 42 | skip = true; 43 | } 44 | }); 45 | 46 | if (skip) { 47 | return; 48 | } 49 | 50 | // if it is MediaStreamTrack.getSources 51 | if (device.kind === 'audio') { 52 | device.kind = 'audioinput'; 53 | } 54 | 55 | if (device.kind === 'video') { 56 | device.kind = 'videoinput'; 57 | } 58 | 59 | if (!device.deviceId) { 60 | device.deviceId = device.id; 61 | } 62 | 63 | if (!device.id) { 64 | device.id = device.deviceId; 65 | } 66 | 67 | if (device.kind === 'audioinput' || device.kind === 'audio') { 68 | audioInputDevices.push(device); 69 | } 70 | 71 | if (device.kind === 'audiooutput') { 72 | audioOutputDevices.push(device); 73 | } 74 | 75 | if (device.kind === 'videoinput' || device.kind === 'video') { 76 | videoInputDevices.push(device); 77 | } 78 | 79 | if (device.kind.indexOf('audio') !== -1) { 80 | allAudioDevices.push(device); 81 | } 82 | 83 | if (device.kind.indexOf('video') !== -1) { 84 | allVideoDevices.push(device); 85 | } 86 | 87 | // there is no 'videoouput' in the spec. 88 | // so videoOutputDevices will always be [empty] 89 | 90 | allMdiaDevices.push(device); 91 | }); 92 | 93 | if (successCallback) { 94 | successCallback({ 95 | allMdiaDevices: allMdiaDevices, 96 | allVideoDevices: allVideoDevices, 97 | allAudioDevices: allAudioDevices, 98 | videoInputDevices: videoInputDevices, 99 | audioInputDevices: audioInputDevices, 100 | audioOutputDevices: audioOutputDevices 101 | }); 102 | } 103 | }); 104 | } 105 | -------------------------------------------------------------------------------- /screen-recording/background/background.desktopCapture.js: -------------------------------------------------------------------------------- 1 | function captureDesktop() { 2 | if (isRecording) { 3 | stopScreenRecording(); 4 | return; 5 | } 6 | 7 | if (recorder && recorder.streams) { 8 | recorder.streams.forEach(function(stream, idx) { 9 | stream.getTracks().forEach(function(track) { 10 | track.stop(); 11 | }); 12 | 13 | if (idx == 0 && typeof stream.onended === 'function') { 14 | stream.onended(); 15 | } 16 | }); 17 | recorder.streams = null; 18 | return; 19 | } 20 | 21 | chrome.browserAction.setIcon({ 22 | path: 'images/main-icon.png' 23 | }); 24 | 25 | if (enableTabCaptureAPI) { 26 | captureTabUsingTabCapture(); 27 | return; 28 | } 29 | 30 | var screenSources = ['screen', 'window', 'audio']; 31 | 32 | if (enableSpeakers === false) { 33 | screenSources = ['screen', 'window']; 34 | } 35 | 36 | chrome.desktopCapture.chooseDesktopMedia(screenSources, onAccessApproved); 37 | } 38 | 39 | function onAccessApproved(chromeMediaSourceId, opts) { 40 | if (!chromeMediaSourceId || !chromeMediaSourceId.toString().length) { 41 | setDefaults(); 42 | chrome.runtime.reload(); 43 | return; 44 | } 45 | 46 | var constraints = { 47 | audio: false, 48 | video: { 49 | mandatory: { 50 | chromeMediaSource: 'desktop', 51 | chromeMediaSourceId: chromeMediaSourceId 52 | }, 53 | optional: [] 54 | } 55 | }; 56 | 57 | if (videoMaxFrameRates && videoMaxFrameRates.toString().length) { 58 | videoMaxFrameRates = parseInt(videoMaxFrameRates); 59 | 60 | // 30 fps seems max-limit in Chrome? 61 | if (videoMaxFrameRates /* && videoMaxFrameRates <= 30 */ ) { 62 | constraints.video.maxFrameRate = videoMaxFrameRates; 63 | } 64 | } 65 | 66 | constraints.video.mandatory.maxWidth = 3840; 67 | constraints.video.mandatory.maxHeight = 2160; 68 | 69 | constraints.video.mandatory.minWidth = 3840; 70 | constraints.video.mandatory.minHeight = 2160; 71 | 72 | if (opts.canRequestAudioTrack === true) { 73 | constraints.audio = { 74 | mandatory: { 75 | chromeMediaSource: 'desktop', 76 | chromeMediaSourceId: chromeMediaSourceId, 77 | echoCancellation: true 78 | }, 79 | optional: [] 80 | }; 81 | } 82 | 83 | navigator.mediaDevices.getUserMedia(constraints).then(function(stream) { 84 | if(enableSpeakers && !enableScreen) { 85 | var screenOnly = new MediaStream(); 86 | getTracks(stream, 'video').forEach(function(track) { 87 | screenOnly.addTrack(track); 88 | 89 | // remove video track, because we are gonna record only speakers 90 | stream.removeTrack(track); 91 | }); 92 | 93 | initVideoPlayer(screenOnly); 94 | addStreamStopListener(screenOnly, function() { 95 | stopScreenRecording(); 96 | }); 97 | 98 | // alert('You can stop recording only using extension icon. Whenever you are done, click extension icon to stop the recording.'); 99 | } 100 | else { 101 | addStreamStopListener(stream, function() { 102 | stopScreenRecording(); 103 | }); 104 | } 105 | 106 | initVideoPlayer(stream); 107 | gotStream(stream); 108 | }).catch(function(error) { 109 | alert('Unable to capture screen using:\n' + JSON.stringify(constraints, null, '\t') + '\n\n' + error); 110 | setDefaults(); 111 | chrome.runtime.reload(); 112 | }); 113 | } 114 | -------------------------------------------------------------------------------- /getUserMedia-on-http/README.md: -------------------------------------------------------------------------------- 1 | # DO NOT USE THIS 2 | 3 | # PLEASE USE HTTPS 4 | 5 | # NOT RECOMMENDED 6 | 7 | # YOUR CHOICE; at YOUR own RISK 8 | 9 | ---- 10 | 11 | # Call getUserMedia on any HTTP website 12 | 13 | This chrome extension allows you invoke getUserMedia on any HTTP domain. You can invoke getUserMedia for camera+microphone or screen or tabs. 14 | 15 | Source code is available in the `./example/` directory. 16 | 17 | ### First Step, Check If Extension Installed 18 | 19 | ```javascript 20 | if (typeof getUserMediaHttp === 'function') { 21 | alert('Yes. getUserMedia extension is installed & enabled.'); 22 | } 23 | ``` 24 | 25 | ### Capture Camera+Microphone 26 | 27 | ```javascript 28 | if (typeof getUserMediaHttp === 'function') { 29 | navigator.mediaDevices.getUserMedia({ 30 | audio: true, 31 | video: true 32 | }).then(function(stream) { 33 | console.log('got stream', stream); 34 | }).catch(function(e) { 35 | console.error(e); 36 | }); 37 | } 38 | ``` 39 | 40 | ### Capture Screen 41 | 42 | ```javascript 43 | if (typeof getUserMediaHttp === 'function') { 44 | navigator.mediaDevices.getUserMedia({ 45 | audio: false, 46 | video: { 47 | mediaSource: 'screen', 48 | mdiaSourceTypes: ['screen'] 49 | } 50 | }).then(function(stream) { 51 | console.log('got stream', stream); 52 | }).catch(function(e) { 53 | console.error(e); 54 | }); 55 | } 56 | ``` 57 | 58 | ### Supported Constraints 59 | 60 | All getUserMedia constraints are supported. E.g. 61 | 62 | ```javascript 63 | if (typeof getUserMediaHttp === 'function') { 64 | navigator.mediaDevices.getUserMedia({ 65 | audio: { 66 | echoCancellation: true 67 | }, 68 | video: { 69 | width: { 70 | exact: 1920 71 | }, 72 | height: { 73 | exact: 1080 74 | }, 75 | frameRate: 32 76 | } 77 | }).then(function(stream) { 78 | console.log('got stream', stream); 79 | }).catch(function(e) { 80 | console.error(e); 81 | }); 82 | } 83 | ``` 84 | 85 | For screen capturing: 86 | 87 | ```javascript 88 | if (typeof getUserMediaHttp === 'function') { 89 | navigator.mediaDevices.getUserMedia({ 90 | audio: false, 91 | video: { 92 | mediaSource: 'screen', 93 | mdiaSourceTypes: ['screen'], 94 | width: screen.width, 95 | height: screen.height, 96 | aspectRatio: 1.77, 97 | frameRate: 64 98 | } 99 | }).then(function(stream) { 100 | console.log('got stream', stream); 101 | }).catch(function(e) { 102 | console.error(e); 103 | }); 104 | } 105 | ``` 106 | 107 | ### Special Constraints 108 | 109 | These are custom constraints that are available only in this extension. 110 | 111 | ```javascript 112 | mdiaSourceTypes: ['screen', 'window', 'tab', 'audio'] 113 | ``` 114 | 115 | `mdiaSourceTypes` allows you choose between what type of screen you want to capture. E.g. 116 | 117 | ```javascript 118 | var constraints = { 119 | mdiaSourceTypes: ['screen', 'audio'], 120 | mdiaSourceTypes: ['tab', 'audio'], 121 | mdiaSourceTypes: ['window', 'audio'], 122 | mdiaSourceTypes: ['screen'], 123 | mdiaSourceTypes: ['window'], 124 | mdiaSourceTypes: ['tab'], 125 | } 126 | ``` 127 | 128 | ## Disclaimer 129 | 130 | No more maintaining this extension; as of 2019. So please use at your own risk. 131 | 132 | * https://www.webrtc-experiment.com/disclaimer/ 133 | 134 | ## License 135 | 136 | [Chrome-Extensions](https://github.com/muaz-khan/Chrome-Extensions) are released under [MIT license](https://github.com/muaz-khan/Chrome-Extensions/blob/master/LICENSE) . Copyright (c) [Muaz Khan](https://MuazKhan.com). 137 | -------------------------------------------------------------------------------- /desktopCapture-p2p/extension-pages/dropdown.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 75 | 76 | 77 |
78 |
79 |
80 | Screen Without Audio 81 |
82 |
83 |
84 |
85 | Screen + Microphone 86 |
87 |
88 |
89 |
90 | Screen + Speakers 91 |
92 |
93 |
94 |
95 | Screen + Microphone + Speakers 96 |
97 |
98 |
99 |
100 | Screen + Microphone + Speakers + Camera 101 |
102 |
103 |
104 |
105 | Chrome Tab + Speakers 106 |
107 |
108 |
109 |
110 | Screen + Camera 111 |
112 |
113 |
114 |
115 | Camera Only 116 |
117 |
118 |
119 | Options 120 |
121 |
122 | 123 |
124 |
125 |
126 | Open Chat Box 127 |
128 |
129 |
130 |
131 | Stop Sharing 132 |
133 |
134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /desktopCapture-p2p/README.md: -------------------------------------------------------------------------------- 1 | # Chrome extension for WebRTC Screen Sharing 2 | 3 | WebRTC Screen Sharing 4 | 5 | WebRTC Screen Sharing 6 | 7 | ## How to install? 8 | 9 | Install Dessktop Sharing Extension 10 | 11 | * https://chrome.google.com/webstore/detail/webrtc-desktop-sharing/nkemblooioekjnpfekmjhpgkackcajhg 12 | 13 | ## How to view screen? 14 | 15 | Try any of the below URL. Replace `your_room_id` with real room-id: 16 | 17 | ``` 18 | https://www.webrtc-experiment.com/screen/?s=your_room_id 19 | ``` 20 | 21 | ## Developer Notes 22 | 23 | 1. Chrome extension can share your screen, tab, any application's window, camera, microphone and speakers. 24 | 2. Clicking extension icon will generate a unique random room URL. You can share that URL with multiple users and all of them can view your screen. 25 | 3. [RTCMultiConnection](https://github.com/muaz-khan/RTCMultiConnection) is a WebRTC library that is used for peer-to-peer WebRTC streaming. 26 | 4. PubNub is used as a signaling method for handshake. However you can use [any WebRTC signaing option](https://github.com/muaz-khan/WebRTC-Experiment/blob/master/Signaling.md). 27 | 5. You can replace or include your own STUN+TURN servers in the [IceServersHandler.js](https://github.com/muaz-khan/Chrome-Extensions/blob/master/desktopCapture-p2p/IceServersHandler.js) file. 28 | 6. VP8 is currently default video codecs. However VP9 is recommended. You can always change codecs using options page. 29 | 7. [getStats](https://github.com/muaz-khan/getStats) is a WebRTC library that is used for bandwidth & codecs detection. This library is optional. You can always remove it. 30 | 31 | ## Before publishing it for your own business 32 | 33 | > This step is optional. You can keep using `webrtc-experiment.com` URL as a screen viewer. 34 | 35 | Open [desktop-capturing.js](https://github.com/muaz-khan/Chrome-Extensions/blob/master/desktopCapture-p2p/desktop-capturing.js) and find following line: 36 | 37 | ```javascript 38 | var resultingURL = 'https://www.webrtc-experiment.com/screen/?s=' + connection.sessionid; 39 | ``` 40 | 41 | Replace above line with your own server/website: 42 | 43 | ```javascript 44 | var resultingURL = 'https://yourWebSite.com/index.html?s=' + connection.sessionid; 45 | ``` 46 | 47 | You can find `index.html` here: 48 | 49 | * [desktopCapture-p2p/index.html](https://github.com/muaz-khan/Chrome-Extensions/blob/master/desktopCapture-p2p/index.html) 50 | 51 | ## How to publish it for your own business? 52 | 53 | Make ZIP of the directory. Then navigate to [Chrome WebStore Developer Dashboard](https://chrome.google.com/webstore/developer/dashboard) and click **Add New Item** blue button. 54 | 55 | To learn more about how to publish a chrome extension in Google App Store: 56 | 57 | * https://developer.chrome.com/webstore/publish 58 | 59 | ## For more information 60 | 61 | For additional information, click [this link](https://github.com/muaz-khan/WebRTC-Experiment/blob/7cd04a81b30cdca2db159eb746e2714307640767/Chrome-Extensions/desktopCapture/README.md). 62 | 63 | ## It is Open-Sourced! 64 | 65 | * https://github.com/muaz-khan/Chrome-Extensions/tree/master/desktopCapture-p2p 66 | 67 | ## License 68 | 69 | [Chrome-Extensions](https://github.com/muaz-khan/Chrome-Extensions) are released under [MIT license](https://github.com/muaz-khan/Chrome-Extensions/blob/master/LICENSE) . Copyright (c) [Muaz Khan](https://MuazKhan.com). 70 | -------------------------------------------------------------------------------- /screen-recording/dropdown.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 74 | RecordRTC Extension 75 | 76 | 77 |
78 |
79 |
80 | Screen Only (without audio) 81 |
82 |
83 |
84 |
85 | Screen + Microphone 86 |
87 |
88 |
89 |
90 | Screen + Speakers 91 |
92 |
93 |
94 |
95 | Screen + Microphone + Speakers 96 |
97 |
98 |
99 |
100 | Chrome Tab 101 |
102 |
103 |
104 |
105 | Chrome Tab (Audio Only) 106 |
107 |
108 |
109 |
110 | Full Screen + Camera 111 |
112 |
113 |
114 |
115 | Microphone + Camera 116 |
117 |
118 |
119 |
120 | Microphone + Speakers 121 |
122 |
123 |
124 |
125 | Microphone Only 126 |
127 |
128 |
129 |
130 | Speakers Only 131 |
132 |
133 |
134 | See All Recordings 135 |
136 |
137 | Options 138 |
139 |
140 | 141 |
142 |
143 |
144 | Stop Recording 145 |
146 |
147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /screen-recording/preview.html: -------------------------------------------------------------------------------- 1 | 116 | 117 | RecordRTC Extension 118 | 119 |
120 | 121 | 122 | 123 |

124 | 125 | 126 | 127 |

128 | 129 |

130 | 131 |

132 | 133 | 134 |
135 | 136 |
137 | 138 |
Upload to YouTube
139 |
140 | 141 |
142 | 143 |
144 | 145 |
146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /desktopCapture-p2p/background/onAccessApproved.js: -------------------------------------------------------------------------------- 1 | function onAccessApproved(chromeMediaSourceId, opts) { 2 | if (!chromeMediaSourceId) { 3 | setDefaults(); 4 | return; 5 | } 6 | 7 | var resolutions = opts.resolutions; 8 | 9 | chrome.storage.sync.get(null, function(items) { 10 | constraints = { 11 | audio: false, 12 | video: { 13 | mandatory: { 14 | chromeMediaSource: 'desktop', 15 | chromeMediaSourceId: chromeMediaSourceId, 16 | maxWidth: resolutions.maxWidth, 17 | maxHeight: resolutions.maxHeight, 18 | minWidth: resolutions.minWidth, 19 | minHeight: resolutions.minHeight, 20 | minAspectRatio: getAspectRatio(resolutions.maxWidth, resolutions.maxHeight), 21 | maxAspectRatio: getAspectRatio(resolutions.maxWidth, resolutions.maxHeight), 22 | minFrameRate: 64, 23 | maxFrameRate: 128 24 | }, 25 | optional: [] 26 | } 27 | }; 28 | 29 | if (opts.canRequestAudioTrack === true) { 30 | constraints.audio = { 31 | mandatory: { 32 | chromeMediaSource: 'desktop', 33 | chromeMediaSourceId: chromeMediaSourceId, 34 | echoCancellation: true 35 | }, 36 | optional: [{ 37 | googDisableLocalEcho: false // https://www.chromestatus.com/feature/5056629556903936 38 | }] 39 | }; 40 | } 41 | 42 | navigator.webkitGetUserMedia(constraints, function(screenStream) { 43 | var win; 44 | addStreamStopListener(screenStream, function() { 45 | if (win && !win.closed) { 46 | win.close(); 47 | } else { 48 | captureDesktop(); 49 | } 50 | }); 51 | 52 | if (opts.stream) { 53 | if (enableCamera && opts.stream.getVideoTracks().length) { 54 | var cameraStream = opts.stream; 55 | 56 | screenStream.fullcanvas = true; 57 | screenStream.width = screen.width; // or 3840 58 | screenStream.height = screen.height; // or 2160 59 | 60 | cameraStream.width = parseInt((15 / 100) * screenStream.width); 61 | cameraStream.height = parseInt((15 / 100) * screenStream.height); 62 | cameraStream.top = screenStream.height - cameraStream.height - 20; 63 | cameraStream.left = screenStream.width - cameraStream.width - 20; 64 | 65 | var mixer = new MultiStreamsMixer([screenStream, cameraStream]); 66 | 67 | mixer.frameInterval = 1; 68 | mixer.startDrawingFrames(); 69 | 70 | screenStream = mixer.getMixedStream(); 71 | // win = openVideoPreview(screenStream); 72 | } else if (enableMicrophone && opts.stream.getAudioTracks().length) { 73 | var speakers = new MediaStream(); 74 | screenStream.getAudioTracks().forEach(function(track) { 75 | speakers.addTrack(track); 76 | screenStream.removeTrack(track); 77 | }); 78 | 79 | var mixer = new MultiStreamsMixer([speakers, opts.stream]); 80 | mixer.getMixedStream().getAudioTracks().forEach(function(track) { 81 | screenStream.addTrack(track); 82 | }); 83 | 84 | screenStream.getVideoTracks().forEach(function(track) { 85 | track.onended = function() { 86 | if (win && !win.closed) { 87 | win.close(); 88 | } else { 89 | captureDesktop(); 90 | } 91 | }; 92 | }) 93 | } 94 | } 95 | 96 | gotStream(screenStream); 97 | }, getUserMediaError); 98 | }); 99 | } 100 | -------------------------------------------------------------------------------- /getUserMedia-on-http/content-script.js: -------------------------------------------------------------------------------- 1 | var port = chrome.runtime.connect(); 2 | port.onMessage.addListener(function(message) { 3 | window.postMessage({ 4 | 'get-user-media-http': message, 5 | 'from-background': true 6 | }, '*'); 7 | }); 8 | 9 | window.addEventListener('message', function(event) { 10 | if (event.source != window || !event.data['from-webpage'] || !event.data['get-user-media-http']) return; 11 | port.postMessage(event.data['get-user-media-http']); 12 | }); 13 | 14 | function getUserMediaHttp() { 15 | if(location.protocol === 'https:' || location.protocol === 'chrome:' || document.domain === 'localhost' || document.domain === '127.0.0.1') { 16 | // ignore HTTPs and localhost and chrome 17 | return; 18 | } 19 | 20 | if(!navigator.mediaDevices) { 21 | navigator.mediaDevices = {}; 22 | } 23 | 24 | var hints = { 25 | audio: true, 26 | video: true 27 | }; 28 | 29 | var errorCallback = function(error) { 30 | console.error('getUserMediaHttp error', error); 31 | }; 32 | 33 | var successCallback = function(stream) { 34 | stream.getTracks().forEach(function(track) { 35 | console.log('getUserMediaHttp stream', track.kind, track.readyState); 36 | }); 37 | }; 38 | 39 | navigator.mediaDevices.getUserMedia = function(_hints) { 40 | if (!_hints || (!_hints.audio && !_hints.video && !_hints.screen && !_hints.tab)) { 41 | _hints = { 42 | audio: true, 43 | video: true 44 | }; 45 | } 46 | 47 | hints = _hints; 48 | 49 | getUserMedia(); 50 | 51 | return { 52 | then: function(callback) { 53 | if(typeof callback !== 'function') { 54 | throw new Error('"callback" must be a function.'); 55 | } 56 | 57 | successCallback = callback; 58 | 59 | return { 60 | catch: function(callback) { 61 | if(typeof callback !== 'function') { 62 | throw new Error('"callback" must be a function.'); 63 | } 64 | 65 | errorCallback = callback; 66 | } 67 | } 68 | } 69 | } 70 | }; 71 | 72 | function getUserMedia() { 73 | window.postMessage({ 74 | 'get-user-media-http': hints, 75 | 'from-webpage': true 76 | }, '*'); 77 | } 78 | 79 | window.addEventListener('message', function(event) { 80 | if (event.source != window || !event.data['from-background']) return; 81 | 82 | var hints = event.data['get-user-media-http']; 83 | if (!hints) return; 84 | 85 | if(hints.error) { 86 | errorCallback(hints.error); 87 | return; 88 | } 89 | 90 | if (hints.sdp && hints.sdp.type === 'offer') { 91 | var rtc = new webrtcHandler(); 92 | rtc.createAnswer(hints.sdp, function(answer) { 93 | if (answer.sdp) { 94 | window.postMessage({ 95 | 'get-user-media-http': { 96 | sdp: answer 97 | }, 98 | 'from-webpage': true 99 | }, '*'); 100 | } 101 | 102 | if (answer.stream) { 103 | answer.stream.oninactive = function() { 104 | window.postMessage({ 105 | 'get-user-media-http': { 106 | 'stream-stop': answer.stream.id 107 | }, 108 | 'from-webpage': true 109 | }, '*'); 110 | rtc.peer.close(); 111 | rtc.peer = null; 112 | }; 113 | successCallback(answer.stream); 114 | 115 | window.addEventListener('beforeunload', function() { 116 | answer.stream.getTracks().forEach(function(track) { 117 | track.stop(); 118 | }); 119 | }, false); 120 | } 121 | }); 122 | } 123 | }); 124 | } 125 | 126 | var script = document.createElement('script'); 127 | (document.head || document.body || document.documentElement).appendChild(script).text = getUserMediaHttp.toString() + ';' + webrtcHandler.toString() + ';getUserMediaHttp();'; 128 | script.remove(); 129 | -------------------------------------------------------------------------------- /screen-recording/preview/preview.php.upload.js: -------------------------------------------------------------------------------- 1 | var server_url = 'https://your-domain.com/f/'; 2 | 3 | document.querySelector('#btn-php-upload').onclick = function() { 4 | if (!file) { 5 | fname.innerHTML = 'You did NOT record anything yet.'; 6 | return; 7 | } 8 | 9 | this.disabled = true; 10 | 11 | fresolutions.innerHTML = fsize.innerHTML = fduration.innerHTML = browserCache.innerHTML = ''; 12 | fname.innerHTML = 'Upload started...'; 13 | 14 | uploadToPHPServer(file, function(progress, videoURL) { 15 | browserCache.innerHTML = ''; 16 | 17 | if (progress === 'ended' || videoURL) { 18 | showPHPURL(videoURL); 19 | document.title = 'Upload successful'; 20 | return; 21 | } 22 | 23 | if (progress != 'Upload started...') { 24 | fname.innerHTML = 'Upload Progress: ' + progress + '%'; 25 | browserCache.innerHTML = ''; 26 | } else { 27 | fname.innerHTML = progress; 28 | } 29 | 30 | document.title = progress + '% uploaded'; 31 | 32 | if (progress >= 99 || videoURL || progress === 'progress-ended') { 33 | browserCache.innerHTML = ''; 34 | fname.innerHTML = 'Uploaded to Server. Retrieving the private video URL...'; 35 | } 36 | }); 37 | }; 38 | 39 | function showPHPURL(videoURL) { 40 | DiskStorage.UpdateFileInfo(file.name, { 41 | php: videoURL 42 | }, function() { 43 | file.url = videoURL; 44 | if(!file.item) file.item = {}; 45 | file.item.php = videoURL; 46 | onGettingFile(file, file.item); 47 | }); 48 | } 49 | 50 | function uploadToPHPServer(blob, callback) { 51 | // create FormData 52 | var formData = new FormData(); 53 | 54 | var fName = blob.name; 55 | 56 | formData.append('video-filename', fName); 57 | formData.append('video-blob', blob); 58 | 59 | callback('Uploading recorded-file to server.'); 60 | 61 | makeXMLHttpRequest(server_url, formData, function(progress) { 62 | if (progress === 'upload-faild') { 63 | return; 64 | } 65 | 66 | if (progress !== 'http-response-200') { 67 | callback(progress); 68 | return; 69 | } 70 | 71 | callback('ended', server_url + fName); 72 | }); 73 | } 74 | 75 | function deleteFromPHPServer(fName, callback) { 76 | // create FormData 77 | var formData = new FormData(); 78 | 79 | formData.append('delete-file', fName); 80 | 81 | makeXMLHttpRequest(server_url + 'delete.php', formData, function(progress) { 82 | if (progress === 'deleted' || progress === 'Problem deleting file.') { 83 | callback(progress, fName) 84 | } 85 | }); 86 | } 87 | 88 | function makeXMLHttpRequest(url, data, callback) { 89 | var request = new XMLHttpRequest(); 90 | request.onreadystatechange = function() { 91 | if (request.readyState == 4 && request.status == 200) { 92 | if (request.responseText && request.responseText.toString().indexOf('

Upload failed.

') === 0) { 93 | fname.innerHTML = request.responseText; 94 | header.style.height = 'auto'; 95 | header.style.color = 'red'; 96 | callback('upload-faild'); 97 | return; 98 | } 99 | 100 | if (request.responseText && request.responseText.toString().indexOf('deleted successfully') !== -1) { 101 | callback('deleted') 102 | return; 103 | } 104 | 105 | if (request.responseText && request.responseText.toString() === 'Problem deleting file.') { 106 | callback(request.responseText) 107 | return; 108 | } 109 | 110 | callback('http-response-200'); 111 | } 112 | }; 113 | 114 | request.upload.onloadstart = function() { 115 | callback('Upload started...'); 116 | }; 117 | 118 | request.upload.onprogress = function(event) { 119 | callback(Math.round(event.loaded / event.total * 100)); 120 | }; 121 | 122 | request.upload.onload = function() { 123 | callback('progress-about-to-end'); 124 | }; 125 | 126 | request.upload.onload = function() { 127 | callback('progress-ended'); 128 | }; 129 | 130 | request.upload.onerror = function(error) { 131 | callback('Failed to upload to server'); 132 | }; 133 | 134 | request.upload.onabort = function(error) { 135 | callback('Upload aborted.'); 136 | }; 137 | 138 | request.open('POST', url); 139 | request.send(data); 140 | } 141 | -------------------------------------------------------------------------------- /desktopCapture-p2p/extension-pages/options.html: -------------------------------------------------------------------------------- 1 | 117 | WebRTC Desktop Sharing 118 | 119 | 120 |
Loading configuration
121 | 122 |
123 |

Resolutions:

124 |
125 | 133 |
134 |
135 | 136 |
137 |

Codecs:

138 |
139 | 145 |
146 |
147 | 148 | 157 | 158 |
159 |

Bandwidth:

160 | 161 | 162 | E.g. 8192 or 1048 or 512 or any digit. 163 |
164 | 165 |
166 |

Room Password:

167 | 168 | 169 | Keep empty for normal rooms. Currently works only for Peer-to-Peer streaming method. 170 |
171 | 172 |
173 |

Room Unique ID:

174 | 175 | 176 | Set Your Own Room-ID (to make it secure & protected & reusable). Keep empty for random room-id. 177 |
178 | 179 |
180 |

Room URL box:

181 | 182 | 183 | You can ignore/hide the link box. For reusable room-ids: we do not need to show popup again and again. 184 |
185 | 186 | -------------------------------------------------------------------------------- /desktopCapture-p2p/background/captureDesktop.js: -------------------------------------------------------------------------------- 1 | function captureDesktop() { 2 | false && chrome.storage.sync.set({ 3 | isSharingOn: 'false' 4 | }); 5 | 6 | if (connection && connection.attachStreams[0]) { 7 | setDefaults(); 8 | 9 | connection && connection.attachStreams.forEach(function(stream) { 10 | stream.getTracks().forEach(function(track) { 11 | track.stop(); 12 | }); 13 | }); 14 | 15 | chrome.storage.sync.set({ 16 | enableTabCaptureAPI: 'false', 17 | enableMicrophone: 'false', 18 | enableCamera: 'false', 19 | enableScreen: 'false', 20 | isSharingOn: 'false', 21 | enableSpeakers: 'false' 22 | }); 23 | return; 24 | } 25 | 26 | chrome.browserAction.setTitle({ 27 | title: 'Capturing Desktop' 28 | }); 29 | 30 | desktop_id = null; 31 | constraints = null; 32 | room_password = ''; 33 | room_id = ''; 34 | codecs = 'default'; 35 | bandwidth = null; 36 | 37 | enableTabCaptureAPI = null; 38 | enableMicrophone = null; 39 | enableSpeakers = null; 40 | enableCamera = null; 41 | enableScreen = null; 42 | isSharingOn = null; 43 | 44 | streaming_method = 'RTCMultiConnection'; 45 | 46 | room_url_box = true; 47 | 48 | chrome.storage.sync.get(null, function(items) { 49 | var resolutions = {}; 50 | 51 | if (items['room_password']) { 52 | room_password = items['room_password']; 53 | } 54 | 55 | if (items['room_id']) { 56 | room_id = items['room_id']; 57 | } 58 | 59 | if (items['streaming_method']) { 60 | streaming_method = items['streaming_method']; 61 | } 62 | 63 | if (items['room_url_box'] === 'false') { 64 | room_url_box = false; 65 | } 66 | 67 | if (items['codecs']) { 68 | codecs = items['codecs']; 69 | } 70 | 71 | if (items['bandwidth']) { 72 | bandwidth = items['bandwidth']; 73 | } 74 | 75 | if (items['enableTabCaptureAPI'] == 'true') { 76 | enableTabCaptureAPI = items['enableTabCaptureAPI']; 77 | } 78 | 79 | if (items['enableMicrophone'] == 'true') { 80 | enableMicrophone = items['enableMicrophone']; 81 | } 82 | 83 | if (items['enableSpeakers'] == 'true') { 84 | enableSpeakers = items['enableSpeakers']; 85 | } 86 | 87 | if (items['enableCamera'] == 'true') { 88 | enableCamera = items['enableCamera']; 89 | } 90 | 91 | if (items['enableScreen'] == 'true') { 92 | enableScreen = items['enableScreen']; 93 | } 94 | 95 | if (items['enableTabCaptureAPI'] == 'true') { 96 | enableTabCaptureAPI = items['enableTabCaptureAPI']; 97 | } 98 | 99 | if (items['isSharingOn'] == 'true') { 100 | isSharingOn = items['isSharingOn']; 101 | } 102 | 103 | var _resolutions = items['resolutions']; 104 | if (!_resolutions) { 105 | _resolutions = 'fit-screen'; 106 | chrome.storage.sync.set({ 107 | resolutions: 'fit-screen' 108 | }, function() {}); 109 | } 110 | 111 | if (_resolutions === 'fit-screen') { 112 | // resolutions.maxWidth = screen.availWidth; 113 | // resolutions.maxHeight = screen.availHeight; 114 | 115 | resolutions.maxWidth = screen.width; 116 | resolutions.maxHeight = screen.height; 117 | } 118 | 119 | if (_resolutions === '4K') { 120 | resolutions.maxWidth = 3840; 121 | resolutions.maxHeight = 2160; 122 | } 123 | 124 | if (_resolutions === '1080p') { 125 | resolutions.maxWidth = 1920; 126 | resolutions.maxHeight = 1080; 127 | } 128 | 129 | if (_resolutions === '720p') { 130 | resolutions.maxWidth = 1280; 131 | resolutions.maxHeight = 720; 132 | } 133 | 134 | if (_resolutions === '480p') { 135 | resolutions.maxWidth = 853; 136 | resolutions.maxHeight = 480; 137 | } 138 | 139 | if (_resolutions === '360p') { 140 | resolutions.maxWidth = 640; 141 | resolutions.maxHeight = 360; 142 | } 143 | 144 | if (_resolutions === '4K') { 145 | alert('"4K" resolutions is not stable in Chrome. Please try "fit-screen" instead.'); 146 | } 147 | 148 | var sources = ['screen', 'window', 'tab']; 149 | 150 | if (enableSpeakers) { 151 | sources.push('audio'); 152 | } 153 | 154 | if (enableTabCaptureAPI) { 155 | captureTabUsingTabCapture(resolutions); 156 | return; 157 | } 158 | 159 | if (enableCamera || enableMicrophone) { 160 | captureCamera(function(stream) { 161 | if (!enableScreen) { 162 | gotStream(stream); 163 | return; 164 | } 165 | 166 | desktop_id = chrome.desktopCapture.chooseDesktopMedia(sources, function(chromeMediaSourceId, opts) { 167 | opts = opts || {}; 168 | opts.resolutions = resolutions; 169 | opts.stream = stream; 170 | onAccessApproved(chromeMediaSourceId, opts); 171 | }); 172 | }); 173 | return; 174 | } 175 | 176 | desktop_id = chrome.desktopCapture.chooseDesktopMedia(sources, function(chromeMediaSourceId, opts) { 177 | opts = opts || {}; 178 | opts.resolutions = resolutions; 179 | onAccessApproved(chromeMediaSourceId, opts); 180 | }); 181 | }); 182 | } 183 | -------------------------------------------------------------------------------- /desktopCapture/README.md: -------------------------------------------------------------------------------- 1 | # Please use `getDisplayMedia` instead 2 | 3 | ```javascript 4 | getScreenStream(function(screenStream) { 5 | video.srcObject = screenStream; 6 | }); 7 | 8 | function getScreenStream(callback) { 9 | if (navigator.getDisplayMedia) { 10 | navigator.getDisplayMedia({ 11 | video: true 12 | }).then(screenStream => { 13 | callback(screenStream); 14 | }); 15 | } else if (navigator.mediaDevices.getDisplayMedia) { 16 | navigator.mediaDevices.getDisplayMedia({ 17 | video: true 18 | }).then(screenStream => { 19 | callback(screenStream); 20 | }); 21 | } else { 22 | getScreenId(function(error, sourceId, screen_constraints) { 23 | navigator.mediaDevices.getUserMedia(screen_constraints).then(function(screenStream) { 24 | callback(screenStream); 25 | }); 26 | }); 27 | } 28 | } 29 | ``` 30 | 31 | ## Disclaimer 32 | 33 | No more maintaining this extension; as of 2019. So please use at your own risk. 34 | 35 | * https://www.webrtc-experiment.com/disclaimer/ 36 | 37 | ---- 38 | 39 | 40 | # Google Chrome [desktopCapture extension](https://github.com/muaz-khan/Chrome-Extensions/tree/master/desktopCapture) 41 | 42 | > This chrome extension simply captures content of your screen. It returns `source-id` to callee; and that `source-id` can be used as `chromeMediaSourceId` in WebRTC applications to capture screen's MediaStream. 43 | 44 | | Description | Download | Install | 45 | | ------------- |-------------|-------------| 46 | | Access/capture screen from any HTTPs domain. | [Source Code](https://github.com/muaz-khan/Chrome-Extensions/tree/master/desktopCapture) | [Install from Google Web Store](https://chrome.google.com/webstore/detail/screen-capturing/ajhifddimkapgcifgcodmmfdlknahffk) | 47 | 48 | # Demos 49 | 50 | Note: Following demos works only if you install chrome extension from [Google WebStore](https://chrome.google.com/webstore/detail/screen-capturing/ajhifddimkapgcifgcodmmfdlknahffk). 51 | 52 | * https://www.webrtc-experiment.com/getScreenId/ 53 | * https://www.webrtc-experiment.com/Screen-Capturing/ 54 | * https://www.webrtc-experiment.com/Pluginfree-Screen-Sharing/ (peer to peer) 55 | 56 | 57 | # How to modify this chrome extension? 58 | 59 | 1. Download ZIP 60 | 2. Windows users can use WinZip/WinRAR/7Zip however MacOSX/Linux users can use `tar -zxvf desktopCapture.tar.gz` to extract the archive 61 | 3. Add your own domain [here at line #17](https://github.com/muaz-khan/Chrome-Extensions/blob/master/desktopCapture/manifest.json#L17) 62 | 4. LocalHost users can test directly by adding `unpacked extension..` via `chrome://extensions/` 63 | 5. Otherwise you can make ZIP of the entire directory and upload at [Google dashboard](https://chrome.google.com/webstore/developer/dashboard) 64 | 65 | Here is how to modify `allowed-domains` in `manifest.json` file: 66 | 67 | ``` 68 | { 69 | "content_scripts": [ { 70 | "js": [ "content-script.js" ], 71 | "all_frames": true, 72 | "run_at": "document_end", 73 | "matches": ["https://www.domain.com/*"] 74 | }] 75 | } 76 | ``` 77 | 78 | # How to publish? 79 | 80 | Learn more about how to publish a chrome extension in Google App Store: 81 | 82 | * https://developer.chrome.com/webstore/publish 83 | 84 | For additional information, click [this link](https://github.com/muaz-khan/WebRTC-Experiment/blob/7cd04a81b30cdca2db159eb746e2714307640767/Chrome-Extensions/desktopCapture/README.md). 85 | 86 | # How to use? 87 | 88 | Download and link `Screen-Capturing.js`: 89 | 90 | * https://github.com/muaz-khan/Chrome-Extensions/tree/master/Screen-Capturing.js 91 | 92 | Now you can use `getScreenConstraints` method to capture your screen: 93 | 94 | ```javascript 95 | getScreenConstraints(function(error, screen_constraints) { 96 | if (error) { 97 | return alert(error); 98 | } 99 | 100 | navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia; 101 | navigator.getUserMedia({ 102 | video: screen_constraints 103 | }, function(stream) { 104 | var video = document.querySelector('video'); 105 | video.src = URL.createObjectURL(stream); 106 | video.play(); 107 | }, function(error) { 108 | alert(JSON.stringify(error, null, '\t')); 109 | }); 110 | }); 111 | ``` 112 | 113 | For more `Screen-Capturing.js` snippets/help: 114 | 115 | * https://github.com/muaz-khan/Chrome-Extensions/tree/master/Screen-Capturing.js#how-to-use-screen-capturingjs 116 | 117 | ---- 118 | 119 | # Do NOT Deploy Chrome Extension YourSelf!!!! 120 | 121 | * https://github.com/muaz-khan/getScreenId 122 | 123 | > getScreenId | Capture Screen on Any Domain! This script is a hack used to support single chrome extension usage on any HTTPs domain. 124 | 125 | First step, install this chrome extension: 126 | 127 | * https://chrome.google.com/webstore/detail/screen-capturing/ajhifddimkapgcifgcodmmfdlknahffk 128 | 129 | Now use `getScreenId.js` (on any HTTPs page): 130 | 131 | ```html 132 | 133 | 134 | 144 | ``` 145 | 146 | ## License 147 | 148 | [Chrome-Extensions](https://github.com/muaz-khan/Chrome-Extensions) are released under [MIT license](https://github.com/muaz-khan/Chrome-Extensions/blob/master/LICENSE) . Copyright (c) [Muaz Khan](https://MuazKhan.com). 149 | -------------------------------------------------------------------------------- /screen-recording/background/background.contentScript.js: -------------------------------------------------------------------------------- 1 | var port = chrome.runtime.connect(); 2 | port.onMessage.addListener(function(message) { 3 | message.messageFromContentScript1234 = true 4 | window.postMessage(message, '*'); 5 | }); 6 | 7 | window.addEventListener('message', function(event) { 8 | if (event.source != window || !event.data.messageFromContentScript1234) return; 9 | port.postMessage(event.data); 10 | }); 11 | 12 | // ctrl+tab to stop the recording 13 | var isControlKeyPressed; 14 | window.addEventListener('keydown', function(e) { 15 | keyCode = e.which || e.keyCode || 0; 16 | 17 | if(keyCode === 17) { 18 | isControlKeyPressed = true; 19 | } 20 | }, false); 21 | 22 | window.addEventListener('keyup', function(e) { 23 | keyCode = e.which || e.keyCode || 0; 24 | 25 | if(isControlKeyPressed && keyCode === 32) { 26 | port.postMessage({ 27 | messageFromContentScript1234: true, 28 | stopRecording: true, 29 | dropdown: true 30 | }); 31 | 32 | e.preventDefault(); 33 | e.stopPropagation(); 34 | return false; 35 | } 36 | 37 | if(keyCode === 17) { 38 | isControlKeyPressed = false; 39 | } 40 | }, false); 41 | 42 | function RecordRTC_Extension(config) { 43 | config = config || { 44 | enableTabCaptureAPI: false, 45 | enableTabCaptureAPIAudioOnly: false, 46 | enableScreen: true, 47 | enableSpeakers: true, 48 | enableCamera: false, 49 | enableMicrophone: false 50 | }; 51 | 52 | var startCallback = function() { 53 | // 54 | }; 55 | 56 | var stopCallback = function() { 57 | // 58 | }; 59 | 60 | var supportedValues = ['enableTabCaptureAPI', 'enableTabCaptureAPIAudioOnly', 'enableScreen', 'enableSpeakers', 'enableCamera', 'enableMicrophone']; 61 | 62 | window.addEventListener('message', function(event) { 63 | if (event.source != window || !event.data.messageFromContentScript1234) return; 64 | 65 | if(event.data.startedRecording === true) { 66 | startCallback(); 67 | } 68 | 69 | if(event.data.stoppedRecording === true) { 70 | stopCallback(dataURItoBlob(event.data.file)); 71 | } 72 | }); 73 | 74 | // via: https://stackoverflow.com/a/12300351/552182 75 | function dataURItoBlob(dataURI) { 76 | var byteString = atob(dataURI.split(',')[1]); 77 | var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0] 78 | var ab = new ArrayBuffer(byteString.length); 79 | var ia = new Uint8Array(ab); 80 | for (var i = 0; i < byteString.length; i++) { 81 | ia[i] = byteString.charCodeAt(i); 82 | } 83 | var blob = new Blob([ab], {type: mimeString}); 84 | return blob; 85 | } 86 | 87 | function getSupoortedFormats() { 88 | return [{ 89 | enableScreen: true 90 | }, { 91 | enableScreen: true, 92 | enableMicrophone: true 93 | }, { 94 | enableScreen: true, 95 | enableSpeakers: true 96 | }, { 97 | enableScreen: true, 98 | enableMicrophone: true, 99 | enableSpeakers: true 100 | }, { 101 | enableTabCaptureAPI: true 102 | }, { 103 | enableTabCaptureAPI: true, 104 | enableTabCaptureAPIAudioOnly: true 105 | }, { 106 | enableScreen: true, 107 | enableCamera: true 108 | }, { 109 | enableMicrophone: true, 110 | enableCamera: true 111 | }, { 112 | enableMicrophone: true, 113 | enableSpeakers: true 114 | }, { 115 | enableMicrophone: true 116 | }, { 117 | enableSpeakers: true 118 | }]; 119 | } 120 | 121 | return { 122 | startRecording: function(options, callback) { 123 | startCallback = callback || function() {}; 124 | 125 | if(options) { 126 | if(typeof options != 'object') { 127 | callback(false, 'First parameter must be an object.') 128 | return; 129 | } 130 | 131 | if(!Object.keys(options).length) { 132 | callback(false, 'First parameter must specify at least one recoding type.') 133 | return; 134 | } 135 | 136 | var mismatchedValues = []; 137 | Object.keys(options).forEach(function(key) { 138 | if(supportedValues.indexOf(key) == -1) { 139 | mismatchedValues.push(key); 140 | } 141 | }); 142 | 143 | if(mismatchedValues.length) { 144 | callback(false, 'Unsupported parameters detected: ' + mismatchedValues.join(', ')) 145 | return; 146 | } 147 | 148 | config = options; // override 149 | } 150 | 151 | config.messageFromContentScript1234 = true; 152 | config.startRecording = true; 153 | config.RecordRTC_Extension = true; // hint for background page 154 | 155 | window.postMessage(config, '*'); 156 | }, 157 | stopRecording: function(callback) { 158 | stopCallback = callback || function() {}; 159 | 160 | if(!config.startRecording) { 161 | callback(false, 'There is no recorder to stop.'); 162 | return; 163 | } 164 | 165 | config.startRecording = false; 166 | config.stopRecording = true; 167 | 168 | window.postMessage(config, '*'); 169 | }, 170 | getSupoortedFormats: getSupoortedFormats 171 | } 172 | } 173 | 174 | var script = document.createElement('script'); 175 | (document.head || document.body || document.documentElement).appendChild(script).text = RecordRTC_Extension.toString() + ';;'; 176 | script.remove(); 177 | -------------------------------------------------------------------------------- /tabCapture/shareStreamUsingRTCMultiConnection.js: -------------------------------------------------------------------------------- 1 | function shareStreamUsingRTCMultiConnection(stream) { 2 | // www.RTCMultiConnection.org/docs/ 3 | connection = new RTCMultiConnection(); 4 | connection.socketURL = 'https://muazkhan.com:9001/'; 5 | connection.autoCloseEntireSession = true; 6 | 7 | // this must match the viewer page 8 | connection.socketMessageEvent = 'desktopCapture'; 9 | 10 | connection.password = null; 11 | if (room_password && room_password.length) { 12 | connection.password = room_password; 13 | } 14 | 15 | connection.enableLogs = false; 16 | connection.session = { 17 | audio: true, 18 | video: true, 19 | oneway: true 20 | }; 21 | 22 | connection.candidates = { 23 | stun: true, 24 | turn: true 25 | }; 26 | 27 | connection.iceProtocols = { 28 | tcp: true, 29 | udp: true 30 | }; 31 | 32 | connection.optionalArgument = { 33 | optional: [], 34 | mandatory: {} 35 | }; 36 | 37 | connection.channel = connection.sessionid = connection.userid; 38 | 39 | if (room_id && room_id.length) { 40 | connection.channel = connection.sessionid = connection.userid = room_id; 41 | } 42 | 43 | connection.autoReDialOnFailure = true; 44 | connection.getExternalIceServers = false; 45 | 46 | connection.iceServers = IceServersHandler.getIceServers(); 47 | 48 | function setBandwidth(sdp, value) { 49 | sdp = sdp.replace(/b=AS([^\r\n]+\r\n)/g, ''); 50 | sdp = sdp.replace(/a=mid:video\r\n/g, 'a=mid:video\r\nb=AS:' + value + '\r\n'); 51 | return sdp; 52 | } 53 | 54 | connection.processSdp = function(sdp) { 55 | if (bandwidth) { 56 | try { 57 | bandwidth = parseInt(bandwidth); 58 | } catch (e) { 59 | bandwidth = null; 60 | } 61 | 62 | if (bandwidth && bandwidth != NaN && bandwidth != 'NaN' && typeof bandwidth == 'number') { 63 | sdp = setBandwidth(sdp, bandwidth); 64 | sdp = BandwidthHandler.setVideoBitrates(sdp, { 65 | min: bandwidth, 66 | max: bandwidth 67 | }); 68 | } 69 | } 70 | 71 | if (!!codecs && codecs !== 'default') { 72 | sdp = CodecsHandler.preferCodec(sdp, codecs); 73 | } 74 | return sdp; 75 | }; 76 | 77 | // www.rtcmulticonnection.org/docs/sdpConstraints/ 78 | connection.sdpConstraints.mandatory = { 79 | OfferToReceiveAudio: false, 80 | OfferToReceiveVideo: false 81 | }; 82 | 83 | connection.onstream = connection.onstreamended = function(event) { 84 | try { 85 | event.mediaElement.pause(); 86 | delete event.mediaElement; 87 | } catch (e) {} 88 | }; 89 | 90 | // www.RTCMultiConnection.org/docs/dontCaptureUserMedia/ 91 | connection.dontCaptureUserMedia = true; 92 | 93 | // www.RTCMultiConnection.org/docs/attachStreams/ 94 | connection.attachStreams.push(stream); 95 | 96 | var text = '-'; 97 | (function looper() { 98 | if (!connection) { 99 | setBadgeText(''); 100 | return; 101 | } 102 | 103 | if (connection.isInitiator) { 104 | setBadgeText('0'); 105 | return; 106 | } 107 | 108 | text += ' -'; 109 | if (text.length > 6) { 110 | text = '-'; 111 | } 112 | 113 | setBadgeText(text); 114 | setTimeout(looper, 500); 115 | })(); 116 | 117 | // www.RTCMultiConnection.org/docs/open/ 118 | connection.socketCustomEvent = connection.sessionid; 119 | 120 | function roomOpenCallback(isRoomOpened, roomid, error) { 121 | if(error) { 122 | alert(error); 123 | } 124 | 125 | chrome.browserAction.enable(); 126 | setBadgeText(0); 127 | 128 | if (room_url_box === true) { 129 | var resultingURL = 'https://www.webrtc-experiment.com/screen/?s=' + connection.sessionid; 130 | 131 | // resultingURL = 'http://localhost:9001/?s=' + connection.sessionid; 132 | 133 | if (room_password && room_password.length) { 134 | resultingURL += '&p=' + room_password; 135 | } 136 | 137 | if (bandwidth) { 138 | resultingURL += '&bandwidth=' + bandwidth; 139 | } 140 | if (!!codecs && codecs !== 'default') { 141 | resultingURL += '&codecs=' + codecs; 142 | } 143 | 144 | var popup_width = 600; 145 | var popup_height = 170; 146 | 147 | chrome.windows.create({ 148 | url: "data:text/html,Unique Room URL

Copy following private URL:

You can share this private-session URI with fellows using email or social networks.

", 149 | type: 'popup', 150 | width: popup_width, 151 | height: popup_height, 152 | top: parseInt((screen.height / 2) - (popup_height / 2)), 153 | left: parseInt((screen.width / 2) - (popup_width / 2)), 154 | focused: true 155 | }, function(win) { 156 | // popup_id = win.id; 157 | }); 158 | } 159 | 160 | connection.socket.on(connection.socketCustomEvent, function(message) { 161 | if (message.receivedYourScreen) { 162 | setBadgeText(connection.isInitiator ? connection.getAllParticipants().length : ''); 163 | } 164 | }); 165 | } 166 | 167 | connection.open(connection.sessionid, roomOpenCallback); 168 | 169 | connection.onleave = connection.onPeerStateChanged = function() { 170 | setBadgeText(connection.isInitiator ? connection.getAllParticipants().length : ''); 171 | }; 172 | } 173 | -------------------------------------------------------------------------------- /screen-recording/options.html: -------------------------------------------------------------------------------- 1 | 107 | 108 | RecordRTC Extension 109 | 110 |

Applying Changes...

111 | 112 |
113 |

Customize RecordRTC Extension

114 | 115 | 116 | 117 | 120 | 121 | 124 | 125 | 126 | 127 | 130 | 131 | 134 | 135 | 136 | 137 | 140 | 141 | 150 | 151 | 152 | 153 | 156 | 157 | 167 | 168 | 169 | 170 | 173 | 174 | 182 | 183 | 184 | 185 | 188 | 189 | 200 | 201 | 202 | 203 | 206 | 207 | 210 | 211 | 212 | 213 | 216 | 217 | 225 | 226 |
118 | Select a camera device: 119 | 122 | 123 |
128 | Select a microphone device: 129 | 132 | 133 |
138 | Select video codecs: 139 | 142 |
143 | 144 | 145 | 146 | 147 | 148 |
149 |
154 | Camera resolutions: 155 | 158 | 166 |
171 | Select video frame rates: 172 | 175 | 181 |
186 | Select video bitrates: 187 | 190 | 199 |
204 | Fix video seeking issues? 205 | 208 | 209 |
214 | YouTube visibility: 215 | 218 | 224 |
227 | 228 |
229 | 230 | 231 | 232 | -------------------------------------------------------------------------------- /screen-recording/background/background.common.js: -------------------------------------------------------------------------------- 1 | var recorder; 2 | var isRecording = false; 3 | var bitsPerSecond = 0; 4 | var isChrome = true; // used by RecordRTC 5 | 6 | var enableTabCaptureAPI = false; 7 | var enableTabCaptureAPIAudioOnly = false; 8 | 9 | var enableScreen = true; 10 | var enableMicrophone = false; 11 | var enableCamera = false; 12 | var cameraStream = false; 13 | 14 | var enableSpeakers = true; 15 | 16 | var videoCodec = 'Default'; 17 | var videoMaxFrameRates = ''; 18 | var videoResolutions = '1920x1080'; 19 | 20 | var startedVODRecordedAt = (new Date).getTime(); 21 | 22 | var startRecordingCallback = function() {}; 23 | var stopRecordingCallback = function(file) {}; 24 | var openPreviewOnStopRecording = true; 25 | var openCameraPreviewDuringRecording = true; 26 | 27 | var fixVideoSeekingIssues = false; 28 | 29 | function isMediaRecorderCompatible() { 30 | return true; 31 | } 32 | 33 | function isMimeTypeSupported(mimeType) { 34 | if (typeof MediaRecorder.isTypeSupported !== 'function') { 35 | return true; 36 | } 37 | 38 | return MediaRecorder.isTypeSupported(mimeType); 39 | } 40 | 41 | function bytesToSize(bytes) { 42 | var k = 1000; 43 | var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; 44 | if (bytes === 0) { 45 | return '0 Bytes'; 46 | } 47 | var i = parseInt(Math.floor(Math.log(bytes) / Math.log(k)), 10); 48 | return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i]; 49 | } 50 | 51 | var Storage = {}; 52 | 53 | if (typeof AudioContext !== 'undefined') { 54 | Storage.AudioContext = AudioContext; 55 | } else if (typeof webkitAudioContext !== 'undefined') { 56 | Storage.AudioContext = webkitAudioContext; 57 | } 58 | 59 | MediaStream.prototype.stop = function() { 60 | this.getTracks().forEach(function(track) { 61 | track.stop(); 62 | }); 63 | }; 64 | 65 | function getRandomString() { 66 | if (window.crypto && window.crypto.getRandomValues && navigator.userAgent.indexOf('Safari') === -1) { 67 | var a = window.crypto.getRandomValues(new Uint32Array(3)), 68 | token = ''; 69 | for (var i = 0, l = a.length; i < l; i++) { 70 | token += a[i].toString(36); 71 | } 72 | return token; 73 | } else { 74 | return (Math.random() * new Date().getTime()).toString(36).replace(/\./g, ''); 75 | } 76 | } 77 | 78 | function getFileName(fileExtension) { 79 | var str = getRandomString(); 80 | str = str.substr(0, 5); 81 | return (new Date).toLocaleDateString().replace(/\//g,'-') + '-' + str + '.' + fileExtension; 82 | } 83 | 84 | function addStreamStopListener(stream, callback) { 85 | var streamEndedEvent = 'ended'; 86 | if ('oninactive' in stream && !('onended' in stream)) { 87 | streamEndedEvent = 'inactive'; 88 | } 89 | stream.addEventListener(streamEndedEvent, function() { 90 | callback(); 91 | callback = function() {}; 92 | }); 93 | getTracks(stream, 'audio').forEach(function(track) { 94 | track.addEventListener(streamEndedEvent, function() { 95 | callback(); 96 | callback = function() {}; 97 | }); 98 | }); 99 | getTracks(stream, 'video').forEach(function(track) { 100 | track.addEventListener(streamEndedEvent, function() { 101 | callback(); 102 | callback = function() {}; 103 | }); 104 | }); 105 | } 106 | 107 | function getMixedAudioStream(arrayOfMediaStreams) { 108 | // via: @pehrsons 109 | if(typeof Storage === 'undefined') { 110 | window.Storage = { 111 | AudioContextConstructor: null, 112 | AudioContext: window.AudioContext || window.webkitAudioContext 113 | }; 114 | } 115 | 116 | if (!Storage.AudioContextConstructor) { 117 | Storage.AudioContextConstructor = new Storage.AudioContext(); 118 | } 119 | 120 | var context = Storage.AudioContextConstructor; 121 | 122 | var audioSources = []; 123 | 124 | var gainNode = context.createGain(); 125 | gainNode.connect(context.destination); 126 | gainNode.gain.value = 0; // don't hear self 127 | 128 | var audioTracksLength = 0; 129 | arrayOfMediaStreams.forEach(function(stream) { 130 | if (!getTracks(stream, 'audio').length) { 131 | return; 132 | } 133 | 134 | audioTracksLength++; 135 | 136 | var audioSource = context.createMediaStreamSource(stream); 137 | audioSource.connect(gainNode); 138 | audioSources.push(audioSource); 139 | }); 140 | 141 | if (!audioTracksLength) { 142 | return; 143 | } 144 | 145 | mediaStremDestination = context.createMediaStreamDestination(); 146 | audioSources.forEach(function(audioSource) { 147 | audioSource.connect(mediaStremDestination); 148 | }); 149 | 150 | return mediaStremDestination.stream; 151 | } 152 | 153 | function getTracks(stream, kind) { 154 | if (!stream || !stream.getTracks) { 155 | return []; 156 | } 157 | 158 | return stream.getTracks().filter(function(t) { 159 | return t.kind === (kind || 'audio'); 160 | }); 161 | } 162 | 163 | function getSeekableBlob(inputBlob, callback) { 164 | // EBML.js copyrights goes to: https://github.com/legokichi/ts-ebml 165 | if (typeof EBML === 'undefined') { 166 | throw new Error('Please link: https://cdn.webrtc-experiment.com/EBML.js'); 167 | } 168 | 169 | var reader = new EBML.Reader(); 170 | var decoder = new EBML.Decoder(); 171 | var tools = EBML.tools; 172 | 173 | var fileReader = new FileReader(); 174 | fileReader.onload = function(e) { 175 | var ebmlElms = decoder.decode(this.result); 176 | ebmlElms.forEach(function(element) { 177 | reader.read(element); 178 | }); 179 | reader.stop(); 180 | var refinedMetadataBuf = tools.makeMetadataSeekable(reader.metadatas, reader.duration, reader.cues); 181 | var body = this.result.slice(reader.metadataSize); 182 | var newBlob = new Blob([refinedMetadataBuf, body], { 183 | type: 'video/webm' 184 | }); 185 | 186 | callback(newBlob); 187 | }; 188 | fileReader.readAsArrayBuffer(inputBlob); 189 | } 190 | -------------------------------------------------------------------------------- /desktopCapture-p2p/extension-pages/options.js: -------------------------------------------------------------------------------- 1 | function querySelectorAll(selector, element) { 2 | element = element || document; 3 | return Array.prototype.slice.call(element.querySelectorAll(selector)); 4 | } 5 | 6 | var elements_ids = querySelectorAll('input, select').map(function(item) { 7 | return item.id; 8 | }); 9 | 10 | var changes = document.getElementById('changes'); 11 | 12 | chrome.storage.sync.get(null, function(items) { 13 | elements_ids.forEach(function(id) { 14 | if (!items[id]) return; 15 | 16 | var element = document.getElementById(id); 17 | if (items[id]) { 18 | if (element.type === 'checkbox') { 19 | element.checked = items[id] === 'true'; 20 | } else { 21 | element.value = items[id]; 22 | } 23 | } else { 24 | var item = {}; 25 | item[element.id] = element.type === 'checkbox' ? 26 | (element.checked === true ? 'true' : 'false') : 27 | element.value; 28 | 29 | try { 30 | chrome.storage.sync.set(item); 31 | } 32 | catch(e) { 33 | location.reload(); 34 | } 35 | } 36 | }); 37 | setCustomSelectElements(); 38 | setTimeout(function() { 39 | changes.style.display = 'none'; 40 | }, 600); 41 | }); 42 | 43 | elements_ids.forEach(function(id) { 44 | var element = document.getElementById(id); 45 | element.onchange = function(e) { 46 | e && e.stopPropagation(); 47 | element.disabled = true; 48 | 49 | changes.querySelector('span').innerHTML = 'Saving Changes'; 50 | changes.style.display = 'block'; 51 | 52 | var item = {}; 53 | item[element.id] = element.type === 'checkbox' ? 54 | (element.checked === true ? 'true' : 'false') : 55 | element.value; 56 | 57 | try { 58 | chrome.storage.sync.set(item, function() { 59 | element.disabled = false; 60 | setTimeout(function() { 61 | changes.style.display = 'none'; 62 | }, 600); 63 | }); 64 | } 65 | catch(e) { 66 | location.reload(); 67 | } 68 | }; 69 | 70 | if (element.type) { 71 | element.parentNode.onclick = function() { 72 | if (element.type !== 'checkbox') { 73 | element.focus(); 74 | } else { 75 | element.checked = !element.checked; 76 | } 77 | }; 78 | 79 | element.onclick = element.onfocus = function(e) { 80 | e && e.stopPropagation(); 81 | }; 82 | } 83 | }); 84 | 85 | querySelectorAll('.help-icon').forEach(function(helpIcon) { 86 | var shown = false; 87 | helpIcon.onclick = function(e) { 88 | e.stopPropagation(); 89 | 90 | var small = helpIcon.parentNode.querySelector('small'); 91 | if(shown) { 92 | small.style.marginTop = '0px'; 93 | setTimeout(function() { 94 | small.style.height = '0px'; 95 | }, 500); 96 | shown = false; 97 | } 98 | else { 99 | small.style.height = 'auto'; 100 | small.style.marginTop = '10px'; 101 | shown = true; 102 | } 103 | }; 104 | }); 105 | 106 | /* custom select */ 107 | function setCustomSelectElements() { 108 | var x, i, j, selElmnt, a, b, c; 109 | x = document.getElementsByClassName('custom-select'); 110 | for (i = 0; i < x.length; i++) { 111 | selElmnt = x[i].getElementsByTagName('select')[0]; 112 | a = document.createElement('DIV'); 113 | a.setAttribute('class', 'select-selected'); 114 | a.innerHTML = selElmnt.options[selElmnt.selectedIndex].innerHTML; 115 | x[i].appendChild(a); 116 | b = document.createElement('DIV'); 117 | b.setAttribute('class', 'select-items select-hide'); 118 | 119 | for (j = 0; j < selElmnt.length; j++) { 120 | c = document.createElement('DIV'); 121 | c.innerHTML = selElmnt.options[j].innerHTML; 122 | 123 | c.setAttribute('data-value', selElmnt.options[j].value); 124 | c.setAttribute('data-target', selElmnt.id); 125 | 126 | c.onclick = function(e) { 127 | var y, i, k, s, h; 128 | s = this.parentNode.parentNode.getElementsByTagName('select')[0]; 129 | h = this.parentNode.previousSibling; 130 | for (i = 0; i < s.length; i++) { 131 | if (s.options[i].innerHTML == this.innerHTML) { 132 | s.selectedIndex = i; 133 | h.innerHTML = this.innerHTML; 134 | y = this.parentNode.getElementsByClassName('same-as-selected'); 135 | for (k = 0; k < y.length; k++) { 136 | y[k].removeAttribute('class'); 137 | } 138 | this.setAttribute('class', 'same-as-selected'); 139 | break; 140 | } 141 | } 142 | h.click(); 143 | 144 | var value = this.getAttribute('data-value'); 145 | var target = this.getAttribute('data-target'); 146 | document.getElementById(target).value = value; 147 | document.getElementById(target).onchange(); 148 | }; 149 | b.appendChild(c); 150 | } 151 | x[i].appendChild(b); 152 | a.onclick = function(e) { 153 | e.stopPropagation(); 154 | closeAllSelect(this); 155 | this.nextSibling.classList.toggle('select-hide'); 156 | this.classList.toggle('select-arrow-active'); 157 | }; 158 | } 159 | 160 | function closeAllSelect(elmnt) { 161 | var x, y, i, arrNo = []; 162 | x = document.getElementsByClassName('select-items'); 163 | y = document.getElementsByClassName('select-selected'); 164 | for (i = 0; i < y.length; i++) { 165 | if (elmnt == y[i]) { 166 | arrNo.push(i) 167 | } else { 168 | y[i].classList.remove('select-arrow-active'); 169 | } 170 | } 171 | for (i = 0; i < x.length; i++) { 172 | if (arrNo.indexOf(i)) { 173 | x[i].classList.add('select-hide'); 174 | } 175 | } 176 | } 177 | document.onclick = closeAllSelect; 178 | } 179 | -------------------------------------------------------------------------------- /desktopCapture-p2p/extension-pages/dropdown.js: -------------------------------------------------------------------------------- 1 | var runtimePort = chrome.runtime.connect({ 2 | name: location.href.replace(/\/|:|#|\?|\$|\^|%|\.|`|~|!|\+|@|\[|\||]|\|*. /g, '').split('\n').join('').split('\r').join('') 3 | }); 4 | 5 | runtimePort.onMessage.addListener(function(message) { 6 | if (!message || !message.messageFromContentScript1234) { 7 | return; 8 | } 9 | }); 10 | 11 | document.getElementById('full-screen').onclick = function() { 12 | chrome.storage.sync.set({ 13 | enableTabCaptureAPI: 'false', 14 | enableMicrophone: 'false', 15 | enableCamera: 'false', 16 | enableScreen: 'true', // TRUE 17 | isSharingOn: 'true', // TRUE 18 | enableSpeakers: 'false' // FALSE 19 | }, function() { 20 | runtimePort.postMessage({ 21 | messageFromContentScript1234: true, 22 | startSharing: true 23 | }); 24 | window.close(); 25 | }); 26 | }; 27 | 28 | document.getElementById('full-screen-audio').onclick = function() { 29 | chrome.storage.sync.set({ 30 | enableTabCaptureAPI: 'false', 31 | enableMicrophone: 'false', 32 | enableCamera: 'false', 33 | enableScreen: 'true', // TRUE 34 | isSharingOn: 'true', // TRUE 35 | enableSpeakers: 'true' // TRUE 36 | }, function() { 37 | runtimePort.postMessage({ 38 | messageFromContentScript1234: true, 39 | startSharing: true 40 | }); 41 | window.close(); 42 | }); 43 | }; 44 | 45 | document.getElementById('full-screen-audio-microphone').onclick = function() { 46 | chrome.storage.sync.set({ 47 | enableTabCaptureAPI: 'false', 48 | enableMicrophone: 'true', // TRUE 49 | enableCamera: 'false', 50 | enableScreen: 'true', // TRUE 51 | isSharingOn: 'true', // TRUE 52 | enableSpeakers: 'true' // TRUE 53 | }, function() { 54 | runtimePort.postMessage({ 55 | messageFromContentScript1234: true, 56 | startSharing: true 57 | }); 58 | window.close(); 59 | }); 60 | }; 61 | 62 | document.getElementById('full-screen-audio-microphone-camera').onclick = function() { 63 | chrome.storage.sync.set({ 64 | enableTabCaptureAPI: 'false', 65 | enableMicrophone: 'true', // TRUE 66 | enableCamera: 'true', 67 | enableScreen: 'true', // TRUE 68 | isSharingOn: 'true', // TRUE 69 | enableSpeakers: 'true' // TRUE 70 | }, function() { 71 | runtimePort.postMessage({ 72 | messageFromContentScript1234: true, 73 | startSharing: true 74 | }); 75 | window.close(); 76 | }); 77 | }; 78 | 79 | document.getElementById('selected-tab').onclick = function() { 80 | chrome.storage.sync.set({ 81 | enableTabCaptureAPI: 'true', // TRUE 82 | enableMicrophone: 'false', 83 | enableCamera: 'false', 84 | enableScreen: 'false', 85 | isSharingOn: 'true', // TRUE 86 | enableSpeakers: 'true' 87 | }, function() { 88 | runtimePort.postMessage({ 89 | messageFromContentScript1234: true, 90 | startSharing: true 91 | }); 92 | window.close(); 93 | }); 94 | }; 95 | 96 | document.getElementById('microphone-screen').onclick = function() { 97 | chrome.storage.sync.set({ 98 | enableTabCaptureAPI: 'false', 99 | enableMicrophone: 'true', // TRUE 100 | enableCamera: 'false', 101 | enableScreen: 'true', // TRUE 102 | isSharingOn: 'true', // TRUE 103 | enableSpeakers: 'false' 104 | }, function() { 105 | runtimePort.postMessage({ 106 | messageFromContentScript1234: true, 107 | startSharing: true 108 | }); 109 | window.close(); 110 | }); 111 | }; 112 | 113 | document.getElementById('microphone-screen-camera').onclick = function() { 114 | chrome.storage.sync.set({ 115 | enableTabCaptureAPI: 'false', 116 | enableMicrophone: 'true', // TRUE 117 | enableCamera: 'true', // TRUE 118 | enableScreen: 'true', // TRUE 119 | isSharingOn: 'true', // TRUE 120 | enableSpeakers: 'false' 121 | }, function() { 122 | runtimePort.postMessage({ 123 | messageFromContentScript1234: true, 124 | startSharing: true 125 | }); 126 | window.close(); 127 | }); 128 | }; 129 | 130 | document.getElementById('microphone-webcam').onclick = function() { 131 | chrome.storage.sync.set({ 132 | enableTabCaptureAPI: 'false', 133 | enableMicrophone: 'true', // TRUE 134 | enableCamera: 'true', // TRUE 135 | enableScreen: 'false', // FALSE 136 | isSharingOn: 'true', // TRUE 137 | enableSpeakers: 'false' 138 | }, function() { 139 | runtimePort.postMessage({ 140 | messageFromContentScript1234: true, 141 | startSharing: true 142 | }); 143 | window.close(); 144 | }); 145 | }; 146 | 147 | document.getElementById('btn-options').onclick = function(e) { 148 | e.preventDefault(); 149 | location.href = this.href; 150 | }; 151 | 152 | function querySelectorAll(selector, element) { 153 | element = element || document; 154 | return Array.prototype.slice.call(element.querySelectorAll(selector)); 155 | } 156 | 157 | chrome.storage.sync.get('isSharingOn', function(obj) { 158 | var isSharingOn = obj.isSharingOn === 'true'; 159 | 160 | document.getElementById('default-section').style.display = isSharingOn ? 'none' : 'block'; 161 | document.getElementById('stop-section').style.display = isSharingOn ? 'block' : 'none'; 162 | 163 | // auto-stop-sharing 164 | if (isSharingOn) { 165 | // document.getElementById('stop-sharing').click(); 166 | } 167 | }); 168 | 169 | document.getElementById('stop-sharing').onclick = function() { 170 | chrome.storage.sync.set({ 171 | isSharingOn: 'false' 172 | }, function() { 173 | runtimePort.postMessage({ 174 | messageFromContentScript1234: true, 175 | stopSharing: true 176 | }); 177 | window.close(); 178 | }); 179 | }; 180 | 181 | document.getElementById('enable-chat').onclick = function() { 182 | var popup_width = 312; 183 | var popup_height = 400; 184 | 185 | runtimePort.postMessage({ 186 | messageFromContentScript1234: true, 187 | openChat: true 188 | }); 189 | 190 | window.open('chat.html','Chat','width='+popup_width+',height='+popup_height+',toolbar=0,menubar=0,location=0,status=1,scrollbars=1,resizable=0,top='+(screen.height - popup_height)+',left=' + (screen.width - popup_width - 30)); 191 | window.close(); 192 | }; 193 | -------------------------------------------------------------------------------- /screen-recording/RecordRTC/MultiStreamRecorder.js: -------------------------------------------------------------------------------- 1 | // ______________________ 2 | // MultiStreamRecorder.js 3 | 4 | /* 5 | * Video conference recording, using captureStream API along with WebAudio and Canvas2D API. 6 | */ 7 | 8 | /** 9 | * MultiStreamRecorder can record multiple videos in single container. 10 | * @summary Multi-videos recorder. 11 | * @license {@link https://github.com/muaz-khan/RecordRTC#license|MIT} 12 | * @author {@link http://www.MuazKhan.com|Muaz Khan} 13 | * @typedef MultiStreamRecorder 14 | * @class 15 | * @example 16 | * var options = { 17 | * mimeType: 'video/webm' 18 | * } 19 | * var recorder = new MultiStreamRecorder(ArrayOfMediaStreams, options); 20 | * recorder.record(); 21 | * recorder.stop(function(blob) { 22 | * video.src = URL.createObjectURL(blob); 23 | * 24 | * // or 25 | * var blob = recorder.blob; 26 | * }); 27 | * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} 28 | * @param {MediaStreams} mediaStreams - Array of MediaStreams. 29 | * @param {object} config - {disableLogs:true, frameInterval: 1, mimeType: "video/webm"} 30 | */ 31 | 32 | function MultiStreamRecorder(arrayOfMediaStreams, options) { 33 | arrayOfMediaStreams = arrayOfMediaStreams || []; 34 | var self = this; 35 | 36 | var mixer; 37 | var mediaRecorder; 38 | 39 | options = options || { 40 | mimeType: 'video/webm', 41 | video: { 42 | width: 360, 43 | height: 240 44 | } 45 | }; 46 | 47 | if (!options.frameInterval) { 48 | options.frameInterval = 10; 49 | } 50 | 51 | if (!options.video) { 52 | options.video = {}; 53 | } 54 | 55 | if (!options.video.width) { 56 | options.video.width = 360; 57 | } 58 | 59 | if (!options.video.height) { 60 | options.video.height = 240; 61 | } 62 | 63 | /** 64 | * This method records all MediaStreams. 65 | * @method 66 | * @memberof MultiStreamRecorder 67 | * @example 68 | * recorder.record(); 69 | */ 70 | this.record = function() { 71 | // github/muaz-khan/MultiStreamsMixer 72 | mixer = new MultiStreamsMixer(arrayOfMediaStreams); 73 | 74 | if (getAllVideoTracks().length) { 75 | mixer.frameInterval = options.frameInterval || 10; 76 | mixer.width = options.video.width || 360; 77 | mixer.height = options.video.height || 240; 78 | mixer.startDrawingFrames(); 79 | } 80 | 81 | if (options.previewStream && typeof options.previewStream === 'function') { 82 | options.previewStream(mixer.getMixedStream()); 83 | } 84 | 85 | // record using MediaRecorder API 86 | mediaRecorder = new MediaStreamRecorder(mixer.getMixedStream(), options); 87 | mediaRecorder.record(); 88 | }; 89 | 90 | function getAllVideoTracks() { 91 | var tracks = []; 92 | arrayOfMediaStreams.forEach(function(stream) { 93 | getTracks(stream, 'video').forEach(function(track) { 94 | tracks.push(track); 95 | }); 96 | }); 97 | return tracks; 98 | } 99 | 100 | /** 101 | * This method stops recording MediaStream. 102 | * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee. 103 | * @method 104 | * @memberof MultiStreamRecorder 105 | * @example 106 | * recorder.stop(function(blob) { 107 | * video.src = URL.createObjectURL(blob); 108 | * }); 109 | */ 110 | this.stop = function(callback) { 111 | if (!mediaRecorder) { 112 | return; 113 | } 114 | 115 | mediaRecorder.stop(function(blob) { 116 | self.blob = blob; 117 | 118 | callback(blob); 119 | 120 | self.clearRecordedData(); 121 | }); 122 | }; 123 | 124 | /** 125 | * This method pauses the recording process. 126 | * @method 127 | * @memberof MultiStreamRecorder 128 | * @example 129 | * recorder.pause(); 130 | */ 131 | this.pause = function() { 132 | if (mediaRecorder) { 133 | mediaRecorder.pause(); 134 | } 135 | }; 136 | 137 | /** 138 | * This method resumes the recording process. 139 | * @method 140 | * @memberof MultiStreamRecorder 141 | * @example 142 | * recorder.resume(); 143 | */ 144 | this.resume = function() { 145 | if (mediaRecorder) { 146 | mediaRecorder.resume(); 147 | } 148 | }; 149 | 150 | /** 151 | * This method resets currently recorded data. 152 | * @method 153 | * @memberof MultiStreamRecorder 154 | * @example 155 | * recorder.clearRecordedData(); 156 | */ 157 | this.clearRecordedData = function() { 158 | if (mediaRecorder) { 159 | mediaRecorder.clearRecordedData(); 160 | mediaRecorder = null; 161 | } 162 | 163 | if (mixer) { 164 | mixer.releaseStreams(); 165 | mixer = null; 166 | } 167 | }; 168 | 169 | /** 170 | * Add extra media-streams to existing recordings. 171 | * @method 172 | * @memberof MultiStreamRecorder 173 | * @param {MediaStreams} mediaStreams - Array of MediaStreams 174 | * @example 175 | * recorder.addStreams([newAudioStream, newVideoStream]); 176 | */ 177 | this.addStreams = function(streams) { 178 | if (!streams) { 179 | throw 'First parameter is required.'; 180 | } 181 | 182 | if (!(streams instanceof Array)) { 183 | streams = [streams]; 184 | } 185 | 186 | arrayOfMediaStreams.concat(streams); 187 | 188 | if (!mediaRecorder || !mixer) { 189 | return; 190 | } 191 | 192 | mixer.appendStreams(streams); 193 | }; 194 | 195 | /** 196 | * Reset videos during live recording. Replace old videos e.g. replace cameras with full-screen. 197 | * @method 198 | * @memberof MultiStreamRecorder 199 | * @param {MediaStreams} mediaStreams - Array of MediaStreams 200 | * @example 201 | * recorder.resetVideoStreams([newVideo1, newVideo2]); 202 | */ 203 | this.resetVideoStreams = function(streams) { 204 | if (!mixer) { 205 | return; 206 | } 207 | 208 | if (streams && !(streams instanceof Array)) { 209 | streams = [streams]; 210 | } 211 | 212 | mixer.resetVideoStreams(streams); 213 | }; 214 | 215 | // for debugging 216 | this.name = 'MultiStreamRecorder'; 217 | this.toString = function() { 218 | return this.name; 219 | }; 220 | } 221 | 222 | if (typeof RecordRTC !== 'undefined') { 223 | RecordRTC.MultiStreamRecorder = MultiStreamRecorder; 224 | } 225 | --------------------------------------------------------------------------------