├── .DS_Store ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .project ├── README.md ├── ajde.ts ├── assets ├── alert.png ├── arrow.png ├── arrow_black.png ├── busy.gif ├── css │ └── content.css ├── cursor.png ├── icon.png ├── icon_red.png └── ok.png ├── build ├── assets │ ├── arrow.png │ ├── arrow_black.png │ ├── icon.png │ └── icon_red.png ├── manifest.json └── src │ ├── background.js │ ├── install.js │ ├── options.js │ ├── ourrecorder.js │ └── receiver.js ├── manifest.json ├── package.json ├── release.sh ├── release.zip └── src ├── background.js ├── content.js ├── install.html ├── install.js ├── options.html ├── options.js ├── ourrecorder.js ├── receiver.html └── receiver.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnWeidner/ScreenRecorderExtension/88fe4b2d02c27e0f3b9878d71dd3d47789250800/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | save/* 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Paths 2 | 3 | build 4 | node_modules 5 | # public -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "es5", 4 | "printWidth": 80, 5 | "tabWidth": 2, 6 | "useTabs": false, 7 | "semi": true 8 | } 9 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | ScreenRecorderExtension 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ScreenRecorderExtension 2 | A Chrome extension for recording your computer screen and audio from your computer mic. 3 | 4 | ### To Do 5 | - [ ] Record audio from system 6 | - [ ] Stop sharing feedback 7 | 8 | 9 | 10 | ### Contributors 11 | - Creator: John Weidner [https://github.com/JohnWeidner/ScreenRecorderExtension] 12 | - Dejan Zdravkovic 13 | - Gabriel Henrique [https://github.com/gabrieldesousah/ScreenRecorderExtension] 14 | - Stanica (freelancer) 15 | - Imad J [https://www.freelancer.com/u/jeghalef] -------------------------------------------------------------------------------- /ajde.ts: -------------------------------------------------------------------------------- 1 | import * as EBML from './'; 2 | import {Decoder, Encoder, tools} from './'; 3 | import EBMLReader from './EBMLReader'; 4 | 5 | window.OurRecorder = async function (stream: string) { 6 | const decoder = new Decoder(); 7 | const reader = new EBMLReader(); 8 | reader.logging = true; 9 | 10 | let tasks = Promise.resolve(void 0); 11 | let jumpStop = Promise.resolve(void 0); 12 | let webM = new Blob([], {type: "video/webm"}); 13 | 14 | //const stream = await navigator.mediaDevices.getUserMedia({video: true, audio: true}); 15 | window.rec = new MediaRecorder(stream, { mimeType: 'video/webm; codecs="vp8, opus"'}); 16 | 17 | const ondataavailable = (ev: BlobEvent)=>{ 18 | const chunk = ev.data; 19 | webM = new Blob([webM, chunk], {type: chunk.type}); 20 | console.log(chunk.size, webM.size); 21 | const task = async ()=>{ 22 | const buf = await readAsArrayBuffer(chunk); 23 | const elms = decoder.decode(buf); 24 | elms.forEach((elm)=>{ reader.read(elm); }); 25 | }; 26 | tasks = tasks.then(()=> task() ); 27 | }; 28 | 29 | rec.addEventListener("dataavailable", ondataavailable); 30 | 31 | // if set timeslice, bug occur on firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1272371 32 | // rec.start(100); 33 | rec.start(); 34 | 35 | //await sleep(10 * 1000); 36 | 37 | let count = 0; 38 | while(webM.size === 0){ 39 | /* if(count > 10){ 40 | alert("MediaRecorder did not record anything"); 41 | throw new Error("MediaRecorder did not record anything"); 42 | }*/ 43 | await sleep(1*1000); // wait dataavailable event 44 | count++; 45 | } 46 | 47 | rec.removeEventListener("dataavailable", ondataavailable); 48 | rec.stream.getTracks().map((track) => { track.stop(); }); 49 | 50 | await tasks; // wait data processing 51 | reader.stop(); 52 | 53 | 54 | /*const raw_video = document.createElement("video"); 55 | raw_video.src = URL.createObjectURL(webM); 56 | raw_video.controls = true; 57 | 58 | put(raw_video, "media-recorder original(not seekable)");*/ 59 | 60 | // const infos = [ 61 | /* {duration: reader.duration, title: "add duration only (seekable but slow)"}, 62 | {cues: reader.cues, title: "add cues only (seekable file)"},*/ 63 | // {duration: reader.duration, cues: reader.cues, title: "add duration and cues (valid seekable file)"}, 64 | // ]; 65 | // for(const info of infos){ 66 | const info = {duration: reader.duration, cues: reader.cues, title: "add duration and cues (valid seekable file)"}; 67 | const refinedMetadataBuf = tools.putRefinedMetaData(reader.metadatas, info); 68 | const webMBuf = await readAsArrayBuffer(webM); 69 | const body = webMBuf.slice(reader.metadataSize); 70 | const refinedWebM = new Blob([refinedMetadataBuf, body], {type: webM.type}); 71 | 72 | // logging 73 | 74 | //console.group(info.title); 75 | const refinedBuf = await readAsArrayBuffer(refinedWebM); 76 | const _reader = new EBMLReader(); 77 | _reader.logging = true; 78 | new Decoder().decode(refinedBuf).forEach((elm)=> _reader.read(elm) ); 79 | _reader.stop(); 80 | //console.groupEnd(); 81 | 82 | var b = URL.createObjectURL(refinedWebM); 83 | var a = document.createElement("a"); 84 | document.body.appendChild(a); 85 | a.style = "display: none"; 86 | a.href = b; 87 | a.download = "screenVideo.webm"; 88 | a.click(); 89 | } 90 | 91 | function put(elm: HTMLElement, title: string): void { 92 | const h1 = document.createElement("h1"); 93 | h1.appendChild(document.createTextNode(title)); 94 | document.body.appendChild(h1); 95 | document.body.appendChild(elm); 96 | } 97 | 98 | function readAsArrayBuffer(blob: Blob): Promise { 99 | return new Promise((resolve, reject)=>{ 100 | const reader = new FileReader(); 101 | reader.readAsArrayBuffer(blob); 102 | reader.onloadend = ()=>{ resolve(reader.result); }; 103 | reader.onerror = (ev)=>{ reject(ev.error); }; 104 | }); 105 | } 106 | 107 | function sleep(ms: number): Promise{ 108 | return new Promise((resolve)=> setTimeout(resolve, ms) ); 109 | } 110 | 111 | // MediaRecorder API 112 | interface BlobEvent extends Event { 113 | data: Blob; 114 | } 115 | 116 | declare class MediaRecorder extends EventTarget { 117 | constructor(stream: MediaStream, opt: any); 118 | start(timeslice?: number): void; 119 | stop(): void; 120 | mimeType: string; 121 | state: "inactive"|"recording"|"paused"; 122 | stream: MediaStream; 123 | videoBitsPerSecond: number; 124 | audioBitsPerSecond: number; 125 | ondataavailable?: (ev: BlobEvent)=> void; 126 | onerror?: (ev: ErrorEvent)=> void; 127 | addEventListener(event: "dataavailable", callback: (ev: BlobEvent)=> any); 128 | requestData(): Blob; 129 | } 130 | 131 | 132 | 133 | //main(); 134 | -------------------------------------------------------------------------------- /assets/alert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnWeidner/ScreenRecorderExtension/88fe4b2d02c27e0f3b9878d71dd3d47789250800/assets/alert.png -------------------------------------------------------------------------------- /assets/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnWeidner/ScreenRecorderExtension/88fe4b2d02c27e0f3b9878d71dd3d47789250800/assets/arrow.png -------------------------------------------------------------------------------- /assets/arrow_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnWeidner/ScreenRecorderExtension/88fe4b2d02c27e0f3b9878d71dd3d47789250800/assets/arrow_black.png -------------------------------------------------------------------------------- /assets/busy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnWeidner/ScreenRecorderExtension/88fe4b2d02c27e0f3b9878d71dd3d47789250800/assets/busy.gif -------------------------------------------------------------------------------- /assets/css/content.css: -------------------------------------------------------------------------------- 1 | /* This is used? */ 2 | 3 | #cursor { 4 | position: absolute; 5 | z-index: 10000; 6 | width: 32px; 7 | height: 32px; 8 | background: transparent url(cursor.png) 0 0 no-repeat; 9 | } 10 | -------------------------------------------------------------------------------- /assets/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnWeidner/ScreenRecorderExtension/88fe4b2d02c27e0f3b9878d71dd3d47789250800/assets/cursor.png -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnWeidner/ScreenRecorderExtension/88fe4b2d02c27e0f3b9878d71dd3d47789250800/assets/icon.png -------------------------------------------------------------------------------- /assets/icon_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnWeidner/ScreenRecorderExtension/88fe4b2d02c27e0f3b9878d71dd3d47789250800/assets/icon_red.png -------------------------------------------------------------------------------- /assets/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnWeidner/ScreenRecorderExtension/88fe4b2d02c27e0f3b9878d71dd3d47789250800/assets/ok.png -------------------------------------------------------------------------------- /build/assets/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnWeidner/ScreenRecorderExtension/88fe4b2d02c27e0f3b9878d71dd3d47789250800/build/assets/arrow.png -------------------------------------------------------------------------------- /build/assets/arrow_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnWeidner/ScreenRecorderExtension/88fe4b2d02c27e0f3b9878d71dd3d47789250800/build/assets/arrow_black.png -------------------------------------------------------------------------------- /build/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnWeidner/ScreenRecorderExtension/88fe4b2d02c27e0f3b9878d71dd3d47789250800/build/assets/icon.png -------------------------------------------------------------------------------- /build/assets/icon_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnWeidner/ScreenRecorderExtension/88fe4b2d02c27e0f3b9878d71dd3d47789250800/build/assets/icon_red.png -------------------------------------------------------------------------------- /build/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Screen Recorder", 3 | "description": "Records a narrated video of your computer screen", 4 | "version": "0.20.3", 5 | "manifest_version": 2, 6 | "icons": { 7 | "16": "assets/icon.png", 8 | "128": "assets/icon.png" 9 | }, 10 | "background": { 11 | "scripts": ["src/background.js", "src/ourrecorder.js"] 12 | }, 13 | "browser_action": { 14 | "default_icon": "assets/icon.png", 15 | "default_popup": "src/receiver.html" 16 | }, 17 | "options_ui": { 18 | "page": "src/options.html", 19 | "chrome_style": true 20 | }, 21 | "permissions": [ 22 | "desktopCapture", 23 | "notifications", 24 | "activeTab", 25 | "storage", 26 | "unlimitedStorage", 27 | "downloads" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /build/src/background.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const DESKTOP_MEDIA = ['window', 'tab']; 4 | var recordingTab; 5 | var recType; 6 | var x = 1; 7 | var rec = []; 8 | var runner; 9 | var OkToResume; 10 | var volume; 11 | var audioContext; 12 | var gainNode; 13 | var microphone; 14 | var now_rec=""; 15 | 16 | // console.log('in src/background.js'); 17 | 18 | chrome.runtime.onInstalled.addListener(function (details) { 19 | if (details.reason == 'install') { 20 | chrome.tabs.create({ 21 | url: chrome.extension.getURL('src/install.html'), 22 | active: true, 23 | }); 24 | } 25 | }); 26 | 27 | chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { 28 | //console.log( 'in listener recType=' + recType + ' pauseRecording=' + request.pauseRecording ); 29 | if (request.prepareRecording == 'on') PrepareRecording(request.recVolume); 30 | if (request.prepareTabRecording == 'on') 31 | PrepareTabRecording(request.recVolume); 32 | if (request.stopRecording == 'on'){ 33 | // console.log(new Date().toLocaleTimeString()); 34 | 35 | StopRecording(); 36 | } 37 | if(request.cancelRecording == "on"){ 38 | CancelRecording(); 39 | } 40 | if(request.initialmsg == "on"){ 41 | InitialMag(); 42 | } 43 | if (request.pauseRecording == 'on') { 44 | if (recType == 'screen') PauseRecording(); 45 | if (recType == 'tab') PauseTabRecording(); 46 | } 47 | if (request.resumeRecording == 'on') { 48 | if (recType == 'screen') ResumeRecording(); 49 | if (recType == 'tab') ResumeTabRecording(); 50 | } 51 | if (request.checkRecState == 'what') { 52 | var curState = rec.state; 53 | sendResponse({ state: now_rec, timer: x }); 54 | } 55 | }); 56 | 57 | function PrepareTabRecording(recVolume) { 58 | recType = 'tab'; 59 | volume = recVolume; 60 | chrome.tabCapture.capture( 61 | { audio: false, video: true }, 62 | function (streamTab) { 63 | chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { 64 | recordingTab = tabs[0].id; 65 | StartRecording(streamTab); 66 | }); 67 | } 68 | ); 69 | } 70 | 71 | chrome.tabs.onActivated.addListener(function (e) { 72 | console.log( 'in tabs.onActivated recType=' + recType + ' rec.state=' + rec.state ); 73 | if (recType == 'tab' && rec.state == 'recording' && e.tabId != recordingTab) { 74 | PauseRecording(); 75 | OkToResume = false; 76 | chrome.notifications.create('extfy1', { 77 | type: 'basic', 78 | iconUrl: 'assets/alert.png', 79 | title: 'ExtensionForYou', 80 | message: 'You left the tab being recorded. Recording is paused.', 81 | requireInteraction: true, 82 | }); 83 | } 84 | if (recType == 'tab' && rec.state == 'paused' && e.tabId != recordingTab) { 85 | OkToResume = false; 86 | chrome.notifications.create('extfy1', { 87 | type: 'basic', 88 | iconUrl: 'assets/alert.png', 89 | title: 'ExtensionForYou', 90 | message: 'You left the tab being recorded. Recording is paused.', 91 | requireInteraction: true, 92 | }); 93 | } 94 | if (recType == 'tab' && rec.state == 'paused' && e.tabId == recordingTab) { 95 | OkToResume = true; 96 | chrome.notifications.create('extfy1', { 97 | type: 'basic', 98 | iconUrl: 'assets/ok.png', 99 | title: 'ExtensionForYou', 100 | message: 'You are now ready to resume recording.', 101 | requireInteraction: true, 102 | }); 103 | } 104 | }); 105 | 106 | function ResumeTabRecording() { 107 | if (OkToResume) ResumeRecording(); 108 | } 109 | function PauseTabRecording() { 110 | PauseRecording(); 111 | } 112 | function PrepareRecording(recVolume) { 113 | now_rec = "recording"; 114 | recType = 'screen'; 115 | volume = recVolume; 116 | chrome.desktopCapture.chooseDesktopMedia(DESKTOP_MEDIA, onAccessApproved); 117 | } 118 | function onAccessApproved(id, options) { 119 | //console.log( 'onAccessApproved id=' + id + ' options=' + options ); 120 | if (!id) { 121 | //console.log('Access rejected.'); 122 | return; 123 | } 124 | var constraints = { 125 | audio: false, 126 | video: { 127 | minFrameRate: 15, 128 | mandatory: { 129 | chromeMediaSource: 'desktop', 130 | chromeMediaSourceId: id, 131 | maxWidth: screen.width, 132 | maxHeight: screen.height, 133 | //maxWidth:1280, 134 | //maxHeight:720 135 | }, 136 | }, 137 | }; 138 | 139 | navigator.mediaDevices 140 | .getUserMedia(constraints) 141 | .then(StartRecording) 142 | .catch(getUserMediaError); 143 | } 144 | function StartRecording(stream) { 145 | audioContext = new AudioContext(); 146 | gainNode = audioContext.createGain(); 147 | runner = setInterval(mainTimer, 1000); 148 | 149 | navigator.mediaDevices 150 | .getUserMedia({ audio: true }) 151 | .then(function (audioStream) { 152 | microphone = audioContext.createMediaStreamSource(audioStream); 153 | microphone.connect(gainNode); 154 | var dest = audioContext.createMediaStreamDestination(); 155 | gainNode.connect(dest); 156 | gainNode.gain.value = volume; 157 | var firstAudioTrack = dest.stream.getAudioTracks()[0]; 158 | stream.addTrack(firstAudioTrack); 159 | OurRecorder(stream); 160 | }) 161 | .catch(getUserMediaError); 162 | 163 | chrome.browserAction.setIcon({ path: 'assets/icon_red.png' }); 164 | } 165 | function getUserMediaError(error) { 166 | alert('src/background.js: getUserMedia() error: ', error); 167 | } 168 | function PauseRecording() { 169 | rec.pause(); 170 | now_rec = "paused"; 171 | clearInterval(runner); 172 | chrome.browserAction.setIcon({ path: 'assets/icon.png' }); 173 | } 174 | function ResumeRecording() { 175 | now_rec = "recording"; 176 | rec.resume(); 177 | runner = setInterval(mainTimer, 1000); 178 | chrome.browserAction.setIcon({ path: 'assets/icon_red.png' }); 179 | chrome.notifications.clear('extfy1'); 180 | } 181 | function StopRecording() { 182 | // now_rec = "inactive"; 183 | // setTimeout(() => { 184 | now_rec = "inactive"; 185 | // }, 1000*10); 186 | chrome.browserAction.setBadgeText({ text: '' }); 187 | clearInterval(runner); 188 | x = 1; 189 | rec.stop(); 190 | chrome.browserAction.setIcon({ path: 'assets/icon.png' }); 191 | chrome.notifications.clear('extfy1'); 192 | } 193 | function InitialMag() { 194 | now_rec = ""; 195 | console.log("bacg"+new Date().toLocaleTimeString()); 196 | } 197 | function CancelRecording() { 198 | now_rec = ""; 199 | } 200 | function mainTimer() { 201 | x += 1; 202 | var date = new Date(null); 203 | date.setSeconds(x); 204 | var result = date.toISOString().substr(11, 8); 205 | } 206 | -------------------------------------------------------------------------------- /build/src/install.js: -------------------------------------------------------------------------------- 1 | navigator.mediaDevices 2 | .getUserMedia({ audio: true, video: false }) 3 | .then(function (stream) { 4 | /* use the stream */ 5 | console.log('getUserMedia() success: ', stream); 6 | stream.getAudioTracks()[0].stop(); 7 | setTimeout(flashArrow, 3000); 8 | document.getElementById('overlayMsg').style.display = 'none'; 9 | document 10 | .getElementById('extensionArrow') 11 | .addEventListener('mouseover', function (event) { 12 | fadeOut = true; 13 | }); 14 | }) 15 | .catch(function (error) { 16 | console.log('src/install.js: getUserMedia() error: ', error); 17 | }); 18 | 19 | var fadeOut = false; 20 | var fadeIn = true; 21 | 22 | function flashArrow() { 23 | document.getElementById('extensionArrow').style.opacity = fadeOut 24 | ? 0 25 | : fadeIn 26 | ? 0.8 27 | : 0.1; 28 | if (!fadeOut) { 29 | fadeIn = !fadeIn; 30 | setTimeout(flashArrow, 700); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /build/src/options.js: -------------------------------------------------------------------------------- 1 | function save_options() { 2 | var downloadas = document.querySelector('input[name="downloadas"]:checked') 3 | .id; 4 | var custom_filename = document.getElementById('custom_filename').value; 5 | chrome.storage.sync.set( 6 | { 7 | opt_dwnld_type: downloadas, 8 | opt_custom_fname: custom_filename, 9 | }, 10 | function () { 11 | var status = document.getElementById('status'); 12 | status.textContent = 'Options saved.'; 13 | setTimeout(function () { 14 | status.textContent = ''; 15 | }, 1000); 16 | } 17 | ); 18 | } 19 | 20 | function restore_options() { 21 | chrome.storage.sync.get(function (items) { 22 | document.getElementById(items.opt_dwnld_type).checked = true; 23 | document.getElementById('custom_filename').value = items.opt_custom_fname; 24 | }); 25 | } 26 | document.addEventListener('DOMContentLoaded', restore_options); 27 | document.getElementById('save').addEventListener('click', save_options); 28 | -------------------------------------------------------------------------------- /build/src/receiver.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const DESKTOP_MEDIA = ['screen', 'window', 'tab']; 3 | var recVolume = 1; 4 | 5 | var audioContext1 = new AudioContext(); 6 | var gainNode1 = audioContext1.createGain(); 7 | 8 | window.winRec = document.getElementById('recWindow'); 9 | window.winPause = document.getElementById('pauseWindow'); 10 | window.btnStart = document.getElementById('start'); 11 | window.talkToTestMic = document.getElementById('testMic'); 12 | window.btnStartTab = document.getElementById('starttab'); 13 | window.btnResume = document.getElementById('resume'); 14 | window.btnStop = document.getElementById('stop'); 15 | window.btnCancel = document.getElementById('cancel'); 16 | window.ourTimer = document.getElementById('timer'); 17 | window.volume = document.getElementById('volume'); 18 | window.tooLoud = document.getElementById('tooLoud'); 19 | window.monitorState = document.getElementById('monitorState'); 20 | window.waiting1 = document.getElementById('waiting1'); 21 | window.waiting2 = document.getElementById('waiting2'); 22 | window.waiting3 = document.getElementById('waiting3'); 23 | 24 | var savedVol = window.localStorage.getItem('recVolume'); 25 | if (savedVol == null) { 26 | savedVol = 0.5; 27 | } 28 | window.volume.value = savedVol; 29 | recVolume = savedVol; 30 | gainNode1.gain.value = savedVol; 31 | 32 | chrome.runtime.sendMessage({ checkRecState: 'what' }, function (response) { 33 | // alert(response.state.value); 34 | // alert(response.state); 35 | 36 | if (response.state == 'recording' || response.state == 'paused') { 37 | winRec.style.display = 'none'; 38 | winPause.style.display = 'block'; 39 | PauseRecording(); 40 | UpdateTimer(response.timer); 41 | } 42 | else if(response.state == 'inactive'){ 43 | winRec.style.display = 'none'; 44 | winPause.style.display = 'block'; 45 | waitingDisplay(); 46 | } 47 | else{ 48 | winRec.style.display = 'block'; 49 | winPause.style.display = 'none'; 50 | talkToTestMic.style.display = 'block'; 51 | btnStart.style.display = 'none'; 52 | } 53 | }); 54 | 55 | navigator.mediaDevices 56 | .getUserMedia({ audio: true, video: false }) 57 | .then(vumeter) 58 | .catch(getUserMediaError); 59 | 60 | 61 | 62 | btnStartTab.addEventListener('click', function (event) { 63 | StartTabRecording(); 64 | }); 65 | 66 | btnStart.addEventListener('click', function (event) { 67 | StartRecording(); 68 | }); 69 | 70 | btnResume.addEventListener('click', function (event) { 71 | ResumeRecording(); 72 | }); 73 | 74 | btnStop.addEventListener('click', function (event) { 75 | StopRecording(); 76 | console.log(new Date().toLocaleTimeString()); 77 | waitingDisplay(); 78 | }); 79 | 80 | function waitingDisplay(){ 81 | ourTimer.innerHTML = ''; 82 | monitorState.innerHTML = ''; 83 | btnResume.hidden = 'true'; 84 | btnStop.hidden = 'true'; 85 | 86 | waiting1.innerHTML = 'Preparing video. Please wait...
'; 87 | 88 | var myImage = new Image(120, 20); 89 | myImage.src = '../assets/busy.gif'; 90 | waiting2.append(myImage); 91 | btnCancel.hidden = false; 92 | 93 | setInterval(function(){ 94 | waiting3.innerHTML = new Date().toLocaleTimeString(); 95 | }, 1000); 96 | 97 | } 98 | 99 | btnCancel.addEventListener('click', function (event) { 100 | 101 | chrome.runtime.sendMessage({ cancelRecording: 'on' }, function (response) {}); 102 | window.close(); 103 | }); 104 | 105 | volume.addEventListener('change', changeRecordingLevel); 106 | volume.addEventListener('input', changeRecordingLevel); 107 | 108 | function changeRecordingLevel(event) { 109 | recVolume = volume.value; 110 | gainNode1.gain.value = recVolume; 111 | window.localStorage.setItem('recVolume', recVolume); 112 | } 113 | 114 | function getUserMediaError(error) { 115 | alert('src/receiver.js: GetUserMedia() error: ', error); 116 | } 117 | 118 | function StartTabRecording() { 119 | chrome.runtime.sendMessage( 120 | { prepareTabRecording: 'on', recVolume: recVolume }, 121 | function (response) {} 122 | ); 123 | window.close(); 124 | } 125 | function StartRecording() { 126 | chrome.runtime.sendMessage( 127 | { prepareRecording: 'on', recVolume: recVolume }, 128 | function (response) {} 129 | ); 130 | window.close(); 131 | } 132 | 133 | function PauseRecording() { 134 | chrome.runtime.sendMessage({ pauseRecording: 'on' }, function (response) {}); 135 | } 136 | function ResumeRecording() { 137 | chrome.runtime.sendMessage({ resumeRecording: 'on' }, function (response) {}); 138 | window.close(); 139 | } 140 | 141 | function StopRecording() { 142 | console.log(new Date().toLocaleTimeString()); 143 | chrome.runtime.sendMessage({ stopRecording: 'on' }, function (response) {}); 144 | } 145 | 146 | var meterWidth = 0; 147 | 148 | var cnvs = document.getElementById('vumeter'); 149 | var cnvs_cntxt = cnvs.getContext('2d'); 150 | 151 | drawLoop(); 152 | 153 | function vumeter(stream) { 154 | var max_level_L = 0; 155 | var old_level_L = 0; 156 | 157 | var microphone1 = audioContext1.createMediaStreamSource(stream); 158 | var javascriptNode = audioContext1.createScriptProcessor(1024, 1, 1); 159 | 160 | microphone1.connect(gainNode1); 161 | gainNode1.connect(javascriptNode); 162 | javascriptNode.connect(audioContext1.destination); 163 | 164 | var greenCount = 0; 165 | var volume = 0; 166 | var averaging = 0.7; 167 | javascriptNode.onaudioprocess = function (event) { 168 | var buf = event.inputBuffer.getChannelData(0); 169 | var bufLength = buf.length; 170 | var sum = 0; 171 | var x; 172 | 173 | // Do a root-mean-square on the samples: sum up the squares... 174 | for (var i = 0; i < bufLength; i++) { 175 | x = buf[i]; 176 | sum += x * x; 177 | } 178 | 179 | // ... then take the square root of the sum. 180 | var rms = Math.sqrt(sum / bufLength); 181 | 182 | // Now smooth this out with the averaging factor applied 183 | // to the previous sample - take the max here because we 184 | // want "fast attack, slow release." 185 | volume = Math.max(rms, volume * averaging); 186 | 187 | meterWidth = (cnvs.width - 20) * volume * 4; 188 | }; 189 | } 190 | 191 | var prevMeterWidth = 0; 192 | var greenCount = 0; 193 | function drawLoop(time) { 194 | if (meterWidth != prevMeterWidth) { 195 | prevMeterWidth = meterWidth; 196 | var width = prevMeterWidth; 197 | cnvs_cntxt.clearRect(0, 0, cnvs.width, cnvs.height); 198 | cnvs_cntxt.fillStyle = '#00ff00'; 199 | var max_green = cnvs.width * 0.75; 200 | if (width > 20) { 201 | talkToTestMic.style.display = 'none'; 202 | btnStart.style.display = 'block'; 203 | } 204 | if (width > max_green) { 205 | cnvs_cntxt.fillRect(10, 10, max_green, cnvs.height - 20); // x,y,w,h 206 | cnvs_cntxt.fillStyle = '#ff0000'; 207 | cnvs_cntxt.fillRect(max_green, 10, width - max_green, cnvs.height - 20); // x,y,w,h 208 | tooLoud.style.opacity = 1; 209 | greenCount = 0; 210 | } else { 211 | cnvs_cntxt.fillRect(10, 10, width, cnvs.height - 20); // x,y,w,h 212 | greenCount++; 213 | if (greenCount > 30) { 214 | tooLoud.style.opacity = 0; 215 | } 216 | } 217 | } 218 | // set up the next visual callback 219 | window.requestAnimationFrame(drawLoop); 220 | } 221 | 222 | function UpdateTimer(v) { 223 | var date = new Date(null); 224 | date.setSeconds(v); 225 | var result = date.toISOString().substr(11, 8); 226 | ourTimer.innerHTML = result; 227 | } 228 | 229 | chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { 230 | chrome.storage.sync.set( 231 | { 232 | opt_curTab: extractHostname(tabs[0].url), 233 | }, 234 | function () {} 235 | ); 236 | }); 237 | 238 | function extractHostname(url) { 239 | var hostname; 240 | if (url.indexOf('://') > -1) { 241 | hostname = url.split('/')[2]; 242 | } else { 243 | hostname = url.split('/')[0]; 244 | } 245 | hostname = hostname.split(':')[0]; 246 | hostname = hostname.split('?')[0]; 247 | return hostname; 248 | } 249 | 250 | 251 | chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { 252 | if(request.showDialog == 'success'){ 253 | chrome.runtime.sendMessage({ initialmsg: 'on' }, function (response) {}); 254 | window.close(); 255 | } 256 | }); -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Screen Recorder", 3 | "description": "Records a narrated video of your computer screen", 4 | "version": "0.20.4", 5 | "manifest_version": 2, 6 | "icons": { 7 | "16": "assets/icon.png", 8 | "128": "assets/icon.png" 9 | }, 10 | "background": { 11 | "scripts": ["src/background.js", "src/ourrecorder.js"] 12 | }, 13 | "browser_action": { 14 | "default_icon": "assets/icon.png", 15 | "default_popup": "src/receiver.html" 16 | }, 17 | "options_ui": { 18 | "page": "src/options.html", 19 | "chrome_style": true 20 | }, 21 | "permissions": [ 22 | "desktopCapture", 23 | "notifications", 24 | "activeTab", 25 | "storage", 26 | "unlimitedStorage", 27 | "downloads" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "screen-recorder-extension", 3 | "version": "0.16.3", 4 | "description": "Google Chrome Extension for screen recorder", 5 | "main": "src/background.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/JohnWeidner/ScreenRecorderExtension.git" 12 | }, 13 | "keywords": [ 14 | "screen-recorder-chrome-extension" 15 | ], 16 | "author": "JohnWeidner and Contributors", 17 | "license": "ISC", 18 | "bugs": { 19 | "url": "https://github.com/JohnWeidner/ScreenRecorderExtension/issues" 20 | }, 21 | "homepage": "https://github.com/JohnWeidner/ScreenRecorderExtension#readme" 22 | } 23 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | rm release.zip 2 | vi manifest.json 3 | rm -rf build 4 | mkdir build 5 | mkdir build/src 6 | mkdir build/assets 7 | cp src/background.js build/src/. 8 | cp src/install.js build/src/. 9 | cp manifest.json build/. 10 | cp src/ourrecorder.js build/src/. 11 | cp src/receiver.js build/src/. 12 | cp src/options.js build/src/. 13 | cp assets/arrow.png build/assets/. 14 | cp assets/arrow_black.png build/assets/. 15 | cp assets/icon.png build/assets/. 16 | cp assets/icon_red.png build/assets/. 17 | cp assets/busy.gif build/assets/. 18 | cp src/install.html build/src/. 19 | cp src/receiver.html build/src/. 20 | cp src/options.html build/src/. 21 | cd build 22 | zip ../release.zip -r * 23 | -------------------------------------------------------------------------------- /release.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnWeidner/ScreenRecorderExtension/88fe4b2d02c27e0f3b9878d71dd3d47789250800/release.zip -------------------------------------------------------------------------------- /src/background.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const DESKTOP_MEDIA = ['window', 'tab']; 4 | var recordingTab; 5 | var recType; 6 | var x = 1; 7 | var rec = []; 8 | var runner; 9 | var OkToResume; 10 | var volume; 11 | var audioContext; 12 | var gainNode; 13 | var microphone; 14 | var now_rec=""; 15 | 16 | // console.log('in src/background.js'); 17 | 18 | chrome.runtime.onInstalled.addListener(function (details) { 19 | if (details.reason == 'install') { 20 | chrome.tabs.create({ 21 | url: chrome.extension.getURL('src/install.html'), 22 | active: true, 23 | }); 24 | } 25 | }); 26 | 27 | chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { 28 | //console.log( 'in listener recType=' + recType + ' pauseRecording=' + request.pauseRecording ); 29 | if (request.prepareRecording == 'on') PrepareRecording(request.recVolume); 30 | if (request.prepareTabRecording == 'on') 31 | PrepareTabRecording(request.recVolume); 32 | if (request.stopRecording == 'on'){ 33 | // console.log(new Date().toLocaleTimeString()); 34 | 35 | StopRecording(); 36 | } 37 | if(request.cancelRecording == "on"){ 38 | CancelRecording(); 39 | } 40 | if(request.initialmsg == "on"){ 41 | InitialMag(); 42 | } 43 | if (request.pauseRecording == 'on') { 44 | if (recType == 'screen') PauseRecording(); 45 | if (recType == 'tab') PauseTabRecording(); 46 | } 47 | if (request.resumeRecording == 'on') { 48 | if (recType == 'screen') ResumeRecording(); 49 | if (recType == 'tab') ResumeTabRecording(); 50 | } 51 | if (request.checkRecState == 'what') { 52 | var curState = rec.state; 53 | sendResponse({ state: now_rec, timer: x }); 54 | } 55 | }); 56 | 57 | function PrepareTabRecording(recVolume) { 58 | recType = 'tab'; 59 | volume = recVolume; 60 | chrome.tabCapture.capture( 61 | { audio: false, video: true }, 62 | function (streamTab) { 63 | chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { 64 | recordingTab = tabs[0].id; 65 | StartRecording(streamTab); 66 | }); 67 | } 68 | ); 69 | } 70 | 71 | chrome.tabs.onActivated.addListener(function (e) { 72 | console.log( 'in tabs.onActivated recType=' + recType + ' rec.state=' + rec.state ); 73 | if (recType == 'tab' && rec.state == 'recording' && e.tabId != recordingTab) { 74 | PauseRecording(); 75 | OkToResume = false; 76 | chrome.notifications.create('extfy1', { 77 | type: 'basic', 78 | iconUrl: 'assets/alert.png', 79 | title: 'ExtensionForYou', 80 | message: 'You left the tab being recorded. Recording is paused.', 81 | requireInteraction: true, 82 | }); 83 | } 84 | if (recType == 'tab' && rec.state == 'paused' && e.tabId != recordingTab) { 85 | OkToResume = false; 86 | chrome.notifications.create('extfy1', { 87 | type: 'basic', 88 | iconUrl: 'assets/alert.png', 89 | title: 'ExtensionForYou', 90 | message: 'You left the tab being recorded. Recording is paused.', 91 | requireInteraction: true, 92 | }); 93 | } 94 | if (recType == 'tab' && rec.state == 'paused' && e.tabId == recordingTab) { 95 | OkToResume = true; 96 | chrome.notifications.create('extfy1', { 97 | type: 'basic', 98 | iconUrl: 'assets/ok.png', 99 | title: 'ExtensionForYou', 100 | message: 'You are now ready to resume recording.', 101 | requireInteraction: true, 102 | }); 103 | } 104 | }); 105 | 106 | function ResumeTabRecording() { 107 | if (OkToResume) ResumeRecording(); 108 | } 109 | function PauseTabRecording() { 110 | PauseRecording(); 111 | } 112 | function PrepareRecording(recVolume) { 113 | now_rec = "recording"; 114 | recType = 'screen'; 115 | volume = recVolume; 116 | chrome.desktopCapture.chooseDesktopMedia(DESKTOP_MEDIA, onAccessApproved); 117 | } 118 | function onAccessApproved(id, options) { 119 | //console.log( 'onAccessApproved id=' + id + ' options=' + options ); 120 | if (!id) { 121 | //console.log('Access rejected.'); 122 | return; 123 | } 124 | var constraints = { 125 | audio: false, 126 | video: { 127 | minFrameRate: 15, 128 | mandatory: { 129 | chromeMediaSource: 'desktop', 130 | chromeMediaSourceId: id, 131 | maxWidth: screen.width, 132 | maxHeight: screen.height, 133 | //maxWidth:1280, 134 | //maxHeight:720 135 | }, 136 | }, 137 | }; 138 | 139 | navigator.mediaDevices 140 | .getUserMedia(constraints) 141 | .then(StartRecording) 142 | .catch(getUserMediaError); 143 | } 144 | function StartRecording(stream) { 145 | audioContext = new AudioContext(); 146 | gainNode = audioContext.createGain(); 147 | runner = setInterval(mainTimer, 1000); 148 | 149 | navigator.mediaDevices 150 | .getUserMedia({ audio: true }) 151 | .then(function (audioStream) { 152 | microphone = audioContext.createMediaStreamSource(audioStream); 153 | microphone.connect(gainNode); 154 | var dest = audioContext.createMediaStreamDestination(); 155 | gainNode.connect(dest); 156 | gainNode.gain.value = volume; 157 | var firstAudioTrack = dest.stream.getAudioTracks()[0]; 158 | stream.addTrack(firstAudioTrack); 159 | OurRecorder(stream); 160 | }) 161 | .catch(getUserMediaError); 162 | 163 | chrome.browserAction.setIcon({ path: 'assets/icon_red.png' }); 164 | } 165 | function getUserMediaError(error) { 166 | alert('src/background.js: getUserMedia() error: ', error); 167 | } 168 | function PauseRecording() { 169 | rec.pause(); 170 | now_rec = "paused"; 171 | clearInterval(runner); 172 | chrome.browserAction.setIcon({ path: 'assets/icon.png' }); 173 | } 174 | function ResumeRecording() { 175 | now_rec = "recording"; 176 | rec.resume(); 177 | runner = setInterval(mainTimer, 1000); 178 | chrome.browserAction.setIcon({ path: 'assets/icon_red.png' }); 179 | chrome.notifications.clear('extfy1'); 180 | } 181 | function StopRecording() { 182 | // now_rec = "inactive"; 183 | // setTimeout(() => { 184 | now_rec = "inactive"; 185 | // }, 1000*10); 186 | chrome.browserAction.setBadgeText({ text: '' }); 187 | clearInterval(runner); 188 | x = 1; 189 | rec.stop(); 190 | chrome.browserAction.setIcon({ path: 'assets/icon.png' }); 191 | chrome.notifications.clear('extfy1'); 192 | } 193 | function InitialMag() { 194 | now_rec = ""; 195 | console.log("bacg"+new Date().toLocaleTimeString()); 196 | } 197 | function CancelRecording() { 198 | now_rec = ""; 199 | } 200 | function mainTimer() { 201 | x += 1; 202 | var date = new Date(null); 203 | date.setSeconds(x); 204 | var result = date.toISOString().substr(11, 8); 205 | } 206 | -------------------------------------------------------------------------------- /src/content.js: -------------------------------------------------------------------------------- 1 | // This is used? 2 | console.log('Content.js'); 3 | 4 | document.body.innerHTML += '
'; 5 | var cursorOffset = { 6 | left: 16, 7 | top: 16, 8 | }; 9 | var $cursor = document.getElementById('cursor'); 10 | document.body.addEventListener( 11 | 'mouseup', 12 | function (e) { 13 | chrome.runtime.sendMessage({ checkRecState: 'what' }, function (response) { 14 | if (response.state == 'recording') { 15 | setTimeout(function () { 16 | $cursor.style.opacity = 1; 17 | $cursor.style.left = e.pageX - cursorOffset.left + 'px'; 18 | $cursor.style.top = e.pageY - cursorOffset.top + 'px'; 19 | setTimeout(function () { 20 | fadeOutEffect($cursor); 21 | }, 200); 22 | }, 80); 23 | } 24 | }); 25 | }, 26 | false 27 | ); 28 | function fadeOutEffect(fadeTarget) { 29 | var fadeEffect = setInterval(function () { 30 | if (!fadeTarget.style.opacity) { 31 | fadeTarget.style.opacity = 1; 32 | } 33 | if (fadeTarget.style.opacity < 0.1) { 34 | clearInterval(fadeEffect); 35 | } else { 36 | fadeTarget.style.opacity -= 0.1; 37 | } 38 | }, 50); 39 | } 40 | -------------------------------------------------------------------------------- /src/install.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Screen Recorder 4 | 62 | 63 | 64 |
65 | 66 |
Allow Screen Recorder to use your microphone.
67 |
68 | 69 |

Welcome to Screen Recorder

70 |
71 | Tap the ’Screen icon at the top right of your browser to start and stop recording. 73 |
74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/install.js: -------------------------------------------------------------------------------- 1 | navigator.mediaDevices 2 | .getUserMedia({ audio: true, video: false }) 3 | .then(function (stream) { 4 | /* use the stream */ 5 | console.log('getUserMedia() success: ', stream); 6 | stream.getAudioTracks()[0].stop(); 7 | setTimeout(flashArrow, 3000); 8 | document.getElementById('overlayMsg').style.display = 'none'; 9 | document 10 | .getElementById('extensionArrow') 11 | .addEventListener('mouseover', function (event) { 12 | fadeOut = true; 13 | }); 14 | }) 15 | .catch(function (error) { 16 | console.log('src/install.js: getUserMedia() error: ', error); 17 | }); 18 | 19 | var fadeOut = false; 20 | var fadeIn = true; 21 | 22 | function flashArrow() { 23 | document.getElementById('extensionArrow').style.opacity = fadeOut 24 | ? 0 25 | : fadeIn 26 | ? 0.8 27 | : 0.1; 28 | if (!fadeOut) { 29 | fadeIn = !fadeIn; 30 | setTimeout(flashArrow, 700); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Options 5 | 10 | 11 | 12 | 13 |
14 | Download as: 15 | 22 | custom filename: 23 |
24 | use 25 | domain name of site being recorded
26 |
27 | 28 |
29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/options.js: -------------------------------------------------------------------------------- 1 | function save_options() { 2 | var downloadas = document.querySelector('input[name="downloadas"]:checked') 3 | .id; 4 | var custom_filename = document.getElementById('custom_filename').value; 5 | chrome.storage.sync.set( 6 | { 7 | opt_dwnld_type: downloadas, 8 | opt_custom_fname: custom_filename, 9 | }, 10 | function () { 11 | var status = document.getElementById('status'); 12 | status.textContent = 'Options saved.'; 13 | setTimeout(function () { 14 | status.textContent = ''; 15 | }, 1000); 16 | } 17 | ); 18 | } 19 | 20 | function restore_options() { 21 | chrome.storage.sync.get(function (items) { 22 | document.getElementById(items.opt_dwnld_type).checked = true; 23 | document.getElementById('custom_filename').value = items.opt_custom_fname; 24 | }); 25 | } 26 | document.addEventListener('DOMContentLoaded', restore_options); 27 | document.getElementById('save').addEventListener('click', save_options); 28 | -------------------------------------------------------------------------------- /src/receiver.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Screen Recorder 4 | 62 | 63 | 64 |
65 |
66 | Test your mic recording level by talking at a normal volume. If the 67 | meter displays red, decrease the level below. 68 |
69 | 70 | Mic Level:   - 71 | + 72 |
73 |
Too Loud
74 | 75 |
Talk to test mic
76 | 77 |
78 |
79 |

80 |

Recording is paused.

81 | 82 | 83 | 84 |
85 |
86 |
87 | 88 | 89 |
90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/receiver.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const DESKTOP_MEDIA = ['screen', 'window', 'tab']; 3 | var recVolume = 1; 4 | 5 | var audioContext1 = new AudioContext(); 6 | var gainNode1 = audioContext1.createGain(); 7 | 8 | window.winRec = document.getElementById('recWindow'); 9 | window.winPause = document.getElementById('pauseWindow'); 10 | window.btnStart = document.getElementById('start'); 11 | window.talkToTestMic = document.getElementById('testMic'); 12 | window.btnStartTab = document.getElementById('starttab'); 13 | window.btnResume = document.getElementById('resume'); 14 | window.btnStop = document.getElementById('stop'); 15 | window.btnCancel = document.getElementById('cancel'); 16 | window.ourTimer = document.getElementById('timer'); 17 | window.volume = document.getElementById('volume'); 18 | window.tooLoud = document.getElementById('tooLoud'); 19 | window.monitorState = document.getElementById('monitorState'); 20 | window.waiting1 = document.getElementById('waiting1'); 21 | window.waiting2 = document.getElementById('waiting2'); 22 | window.waiting3 = document.getElementById('waiting3'); 23 | 24 | var savedVol = window.localStorage.getItem('recVolume'); 25 | if (savedVol == null) { 26 | savedVol = 0.5; 27 | } 28 | window.volume.value = savedVol; 29 | recVolume = savedVol; 30 | gainNode1.gain.value = savedVol; 31 | 32 | chrome.runtime.sendMessage({ checkRecState: 'what' }, function (response) { 33 | // alert(response.state.value); 34 | // alert(response.state); 35 | 36 | if (response.state == 'recording' || response.state == 'paused') { 37 | winRec.style.display = 'none'; 38 | winPause.style.display = 'block'; 39 | PauseRecording(); 40 | UpdateTimer(response.timer); 41 | } 42 | else if(response.state == 'inactive'){ 43 | winRec.style.display = 'none'; 44 | winPause.style.display = 'block'; 45 | waitingDisplay(); 46 | } 47 | else{ 48 | winRec.style.display = 'block'; 49 | winPause.style.display = 'none'; 50 | talkToTestMic.style.display = 'block'; 51 | btnStart.style.display = 'none'; 52 | } 53 | }); 54 | 55 | navigator.mediaDevices 56 | .getUserMedia({ audio: true, video: false }) 57 | .then(vumeter) 58 | .catch(getUserMediaError); 59 | 60 | 61 | 62 | btnStartTab.addEventListener('click', function (event) { 63 | StartTabRecording(); 64 | }); 65 | 66 | btnStart.addEventListener('click', function (event) { 67 | StartRecording(); 68 | }); 69 | 70 | btnResume.addEventListener('click', function (event) { 71 | ResumeRecording(); 72 | }); 73 | 74 | btnStop.addEventListener('click', function (event) { 75 | StopRecording(); 76 | console.log(new Date().toLocaleTimeString()); 77 | waitingDisplay(); 78 | }); 79 | 80 | function waitingDisplay(){ 81 | ourTimer.innerHTML = ''; 82 | monitorState.innerHTML = ''; 83 | btnResume.hidden = 'true'; 84 | btnStop.hidden = 'true'; 85 | 86 | waiting1.innerHTML = 'Preparing video. Please wait...
'; 87 | 88 | var myImage = new Image(120, 20); 89 | myImage.src = '../assets/busy.gif'; 90 | waiting2.append(myImage); 91 | btnCancel.hidden = false; 92 | 93 | setInterval(function(){ 94 | waiting3.innerHTML = new Date().toLocaleTimeString(); 95 | }, 1000); 96 | 97 | } 98 | 99 | btnCancel.addEventListener('click', function (event) { 100 | 101 | chrome.runtime.sendMessage({ cancelRecording: 'on' }, function (response) {}); 102 | window.close(); 103 | }); 104 | 105 | volume.addEventListener('change', changeRecordingLevel); 106 | volume.addEventListener('input', changeRecordingLevel); 107 | 108 | function changeRecordingLevel(event) { 109 | recVolume = volume.value; 110 | gainNode1.gain.value = recVolume; 111 | window.localStorage.setItem('recVolume', recVolume); 112 | } 113 | 114 | function getUserMediaError(error) { 115 | alert('src/receiver.js: GetUserMedia() error: ', error); 116 | } 117 | 118 | function StartTabRecording() { 119 | chrome.runtime.sendMessage( 120 | { prepareTabRecording: 'on', recVolume: recVolume }, 121 | function (response) {} 122 | ); 123 | window.close(); 124 | } 125 | function StartRecording() { 126 | chrome.runtime.sendMessage( 127 | { prepareRecording: 'on', recVolume: recVolume }, 128 | function (response) {} 129 | ); 130 | window.close(); 131 | } 132 | 133 | function PauseRecording() { 134 | chrome.runtime.sendMessage({ pauseRecording: 'on' }, function (response) {}); 135 | } 136 | function ResumeRecording() { 137 | chrome.runtime.sendMessage({ resumeRecording: 'on' }, function (response) {}); 138 | window.close(); 139 | } 140 | 141 | function StopRecording() { 142 | console.log(new Date().toLocaleTimeString()); 143 | chrome.runtime.sendMessage({ stopRecording: 'on' }, function (response) {}); 144 | } 145 | 146 | var meterWidth = 0; 147 | 148 | var cnvs = document.getElementById('vumeter'); 149 | var cnvs_cntxt = cnvs.getContext('2d'); 150 | 151 | drawLoop(); 152 | 153 | function vumeter(stream) { 154 | var max_level_L = 0; 155 | var old_level_L = 0; 156 | 157 | var microphone1 = audioContext1.createMediaStreamSource(stream); 158 | var javascriptNode = audioContext1.createScriptProcessor(1024, 1, 1); 159 | 160 | microphone1.connect(gainNode1); 161 | gainNode1.connect(javascriptNode); 162 | javascriptNode.connect(audioContext1.destination); 163 | 164 | var greenCount = 0; 165 | var volume = 0; 166 | var averaging = 0.7; 167 | javascriptNode.onaudioprocess = function (event) { 168 | var buf = event.inputBuffer.getChannelData(0); 169 | var bufLength = buf.length; 170 | var sum = 0; 171 | var x; 172 | 173 | // Do a root-mean-square on the samples: sum up the squares... 174 | for (var i = 0; i < bufLength; i++) { 175 | x = buf[i]; 176 | sum += x * x; 177 | } 178 | 179 | // ... then take the square root of the sum. 180 | var rms = Math.sqrt(sum / bufLength); 181 | 182 | // Now smooth this out with the averaging factor applied 183 | // to the previous sample - take the max here because we 184 | // want "fast attack, slow release." 185 | volume = Math.max(rms, volume * averaging); 186 | 187 | meterWidth = (cnvs.width - 20) * volume * 4; 188 | }; 189 | } 190 | 191 | var prevMeterWidth = 0; 192 | var greenCount = 0; 193 | function drawLoop(time) { 194 | if (meterWidth != prevMeterWidth) { 195 | prevMeterWidth = meterWidth; 196 | var width = prevMeterWidth; 197 | cnvs_cntxt.clearRect(0, 0, cnvs.width, cnvs.height); 198 | cnvs_cntxt.fillStyle = '#00ff00'; 199 | var max_green = cnvs.width * 0.75; 200 | if (width > 20) { 201 | talkToTestMic.style.display = 'none'; 202 | btnStart.style.display = 'block'; 203 | } 204 | if (width > max_green) { 205 | cnvs_cntxt.fillRect(10, 10, max_green, cnvs.height - 20); // x,y,w,h 206 | cnvs_cntxt.fillStyle = '#ff0000'; 207 | cnvs_cntxt.fillRect(max_green, 10, width - max_green, cnvs.height - 20); // x,y,w,h 208 | tooLoud.style.opacity = 1; 209 | greenCount = 0; 210 | } else { 211 | cnvs_cntxt.fillRect(10, 10, width, cnvs.height - 20); // x,y,w,h 212 | greenCount++; 213 | if (greenCount > 30) { 214 | tooLoud.style.opacity = 0; 215 | } 216 | } 217 | } 218 | // set up the next visual callback 219 | window.requestAnimationFrame(drawLoop); 220 | } 221 | 222 | function UpdateTimer(v) { 223 | var date = new Date(null); 224 | date.setSeconds(v); 225 | var result = date.toISOString().substr(11, 8); 226 | ourTimer.innerHTML = result; 227 | } 228 | 229 | chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { 230 | chrome.storage.sync.set( 231 | { 232 | opt_curTab: extractHostname(tabs[0].url), 233 | }, 234 | function () {} 235 | ); 236 | }); 237 | 238 | function extractHostname(url) { 239 | var hostname; 240 | if (url.indexOf('://') > -1) { 241 | hostname = url.split('/')[2]; 242 | } else { 243 | hostname = url.split('/')[0]; 244 | } 245 | hostname = hostname.split(':')[0]; 246 | hostname = hostname.split('?')[0]; 247 | return hostname; 248 | } 249 | 250 | 251 | chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { 252 | if(request.showDialog == 'success'){ 253 | chrome.runtime.sendMessage({ initialmsg: 'on' }, function (response) {}); 254 | window.close(); 255 | } 256 | }); --------------------------------------------------------------------------------