
83 |

88 |

93 |

98 |

103 |

108 |

113 |

118 |
├── 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 |
Recording: 00:00
9 | 10 | 11 | -------------------------------------------------------------------------------- /desktopCapture-p2p/extension-pages/video.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |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 | 
4 |
5 | * https://chrome.google.com/webstore/detail/recordrtc/ndcljioonkecdnaaihodjgiliohngojp
6 |
7 |
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 |
4 |
5 |
6 |
7 | ## How to install?
8 |
9 |
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 |
118 | Select a camera device:
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 | Select a microphone device:
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 | Select video codecs:
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 | Camera resolutions:
155 |
156 |
157 |
158 |
166 |
167 |
168 |
169 |
170 |
171 | Select video frame rates:
172 |
173 |
174 |
175 |
181 |
182 |
183 |
184 |
185 |
186 | Select video bitrates:
187 |
188 |
189 |
190 |
199 |
200 |
201 |
202 |
203 |
204 | Fix video seeking issues?
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 | YouTube visibility:
215 |
216 |
217 |
218 |
224 |
225 |
226 |
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 |
--------------------------------------------------------------------------------