Skip to content

Instantly share code, notes, and snippets.

@chikoski
Created March 20, 2015 09:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chikoski/00bbcb2cff65293869a0 to your computer and use it in GitHub Desktop.
Save chikoski/00bbcb2cff65293869a0 to your computer and use it in GitHub Desktop.
A sample Firefox app which captures and records audio through microphone.
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;
}
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;
}
});
<!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>
{
"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