Created
March 20, 2015 09:00
-
-
Save chikoski/00bbcb2cff65293869a0 to your computer and use it in GitHub Desktop.
A sample Firefox app which captures and records audio through microphone.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body{ | |
margin: 0; | |
padding: 0; | |
} | |
#canvas{ | |
width: 100%; | |
height: 400px; | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
} | |
#recording{ | |
color: red; | |
position: fixed; | |
top: .5em; | |
left: .5em; | |
display: none; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const FFTSIZE = 1024; | |
const HEIGHT = 400; | |
const PREFIX = "recorder"; | |
var gc; | |
var canvas; | |
var audio = new AudioContext(); | |
var analyser; | |
var stream; | |
var buf; | |
var recorder; | |
var storage = navigator.getDeviceStorage("music"); | |
var indicator; | |
var createFileName = function(event){ | |
return PREFIX + "-" + event.timeStamp + ".ogg"; | |
}; | |
var recording = function(){ | |
return recorder != null && recorder.state == "recording"; | |
}; | |
var startStopRecorder = function(){ | |
if(recording()){ | |
console.log("recorder stopped"); | |
recorder.stop(); | |
indicator.style.display = "none"; | |
}else{ | |
console.log("recorder started"); | |
recorder.start(); | |
indicator.style.display = "block"; | |
} | |
console.log(recorder.state); | |
}; | |
var initRecorder = function(stream){ | |
recorder = new MediaRecorder(stream); | |
recorder.ondataavailable = (event) => { | |
console.log(event); | |
if(storage != null){ | |
var filename = createFileName(event); | |
console.log("attempt to save as " + filename); | |
var req = storage.addNamed(event.data, filename); | |
req.onsuccess = function(){ | |
console.log("saved as " + this.result); | |
}; | |
req.onerror = function(){ | |
console.log(this.error.name); | |
}; | |
} | |
}; | |
}; | |
var initAnalyser = function(){ | |
if(analyser == null){ | |
analyser = audio.createAnalyser(); | |
analyser.fftsize = FFTSIZE; | |
buf = new Uint8Array(analyser.frequencyBinCount); | |
console.log("init analyser"); | |
} | |
}; | |
var streamAquired = function(aquired){ | |
stream = aquired; | |
initAnalyser(); | |
var source = audio.createMediaStreamSource(aquired); | |
console.log(source); | |
source.connect(analyser); | |
initRecorder(aquired); | |
update(); | |
}; | |
var aquireStream = function(){ | |
navigator.getUserMedia = | |
navigator.getUserMedia || navigator.mozGetUserMedia; | |
if(navigator.getUserMedia){ | |
console.log("getUserMedia is avialable"); | |
navigator.getUserMedia({video: false, audio: true}, | |
streamAquired, | |
error =>{ | |
console.log(error); | |
}); | |
}else{ | |
console.log("no getUserMedia"); | |
} | |
}; | |
var update = function(){ | |
if(analyser && buf && gc){ | |
analyser.getByteTimeDomainData(buf); | |
gc.fillStyle = "rgba(51, 51, 51, .4)"; | |
gc.fillRect(0, 0, FFTSIZE, HEIGHT); | |
var unitWidth = FFTSIZE * 1.0 / buf.length; | |
gc.lineWidth = 2; | |
gc.strokeStyle = "#eee"; | |
gc.beginPath(); | |
var x = 0; | |
for(var i = 0; i < buf.length; i++){ | |
var y = buf[i] / 128.0 * HEIGHT / 2; | |
x = x + unitWidth; | |
if(i === 0){ | |
gc.moveTo(x, y); | |
}else{ | |
gc.lineTo(x, y); | |
} | |
} | |
gc.stroke(); | |
} | |
window.requestAnimationFrame(update); | |
}; | |
window.addEventListener("load", function() { | |
aquireStream(); | |
canvas = document.querySelector("#canvas"); | |
canvas.setAttribute("width", FFTSIZE); | |
canvas.setAttribute("height", HEIGHT); | |
canvas.style.height = window.innerHeight + "px"; | |
gc = canvas.getContext("2d"); | |
indicator = document.querySelector("#recording"); | |
canvas.addEventListener("click", event => { | |
startStopRecorder(); | |
}); | |
}); | |
window.addEventListener("unload", event => { | |
if(recording()){ | |
recorder.stop(); | |
recorder = null; | |
} | |
if(stream != null){ | |
stream.stop(); | |
stream = null; | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1"> | |
<title>Hello World</title> | |
<!-- Inline scripts are forbidden in Firefox OS apps (CSP restrictions), | |
so we use a script file. --> | |
<script src="app.js" defer></script> | |
<link rel="stylesheet" href="app.css"> | |
</head> | |
<body> | |
<!-- This code is in the public domain. Enjoy! --> | |
<canvas id="canvas"></canvas> | |
<p id="recording">●REC</p> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "audio-caputre-sample", | |
"description": "An sample app to capture audio through microphone", | |
"launch_path": "/index.html", | |
"icons": { | |
"16": "/icons/icon16x16.png", | |
"48": "/icons/icon48x48.png", | |
"60": "/icons/icon60x60.png", | |
"128": "/icons/icon128x128.png" | |
}, | |
"type": "privileged", | |
"permissions": { | |
"audio-capture": { | |
"description": "To record audio" | |
}, | |
"device-storage:music": { | |
"description": "To store captured audio", | |
"access": "readwrite" | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment