360 lines
No EOL
9.8 KiB
JavaScript
360 lines
No EOL
9.8 KiB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
|
|
if(typeof exports === 'object' && typeof module === 'object')
|
|
module.exports = factory();
|
|
else if(typeof define === 'function' && define.amd)
|
|
define([], factory);
|
|
else if(typeof exports === 'object')
|
|
exports["Recorder"] = factory();
|
|
else
|
|
root["Recorder"] = factory();
|
|
})(typeof self !== 'undefined' ? self : this, function() {
|
|
return /******/ (function(modules) { // webpackBootstrap
|
|
/******/ // The module cache
|
|
/******/ var installedModules = {};
|
|
/******/
|
|
/******/ // The require function
|
|
/******/ function __webpack_require__(moduleId) {
|
|
/******/
|
|
/******/ // Check if module is in cache
|
|
/******/ if(installedModules[moduleId]) {
|
|
/******/ return installedModules[moduleId].exports;
|
|
/******/ }
|
|
/******/ // Create a new module (and put it into the cache)
|
|
/******/ var module = installedModules[moduleId] = {
|
|
/******/ i: moduleId,
|
|
/******/ l: false,
|
|
/******/ exports: {}
|
|
/******/ };
|
|
/******/
|
|
/******/ // Execute the module function
|
|
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
|
/******/
|
|
/******/ // Flag the module as loaded
|
|
/******/ module.l = true;
|
|
/******/
|
|
/******/ // Return the exports of the module
|
|
/******/ return module.exports;
|
|
/******/ }
|
|
/******/
|
|
/******/
|
|
/******/ // expose the modules object (__webpack_modules__)
|
|
/******/ __webpack_require__.m = modules;
|
|
/******/
|
|
/******/ // expose the module cache
|
|
/******/ __webpack_require__.c = installedModules;
|
|
/******/
|
|
/******/ // define getter function for harmony exports
|
|
/******/ __webpack_require__.d = function(exports, name, getter) {
|
|
/******/ if(!__webpack_require__.o(exports, name)) {
|
|
/******/ Object.defineProperty(exports, name, {
|
|
/******/ configurable: false,
|
|
/******/ enumerable: true,
|
|
/******/ get: getter
|
|
/******/ });
|
|
/******/ }
|
|
/******/ };
|
|
/******/
|
|
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
|
/******/ __webpack_require__.n = function(module) {
|
|
/******/ var getter = module && module.__esModule ?
|
|
/******/ function getDefault() { return module['default']; } :
|
|
/******/ function getModuleExports() { return module; };
|
|
/******/ __webpack_require__.d(getter, 'a', getter);
|
|
/******/ return getter;
|
|
/******/ };
|
|
/******/
|
|
/******/ // Object.prototype.hasOwnProperty.call
|
|
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
|
/******/
|
|
/******/ // __webpack_public_path__
|
|
/******/ __webpack_require__.p = "";
|
|
/******/
|
|
/******/ // Load entry module and return exports
|
|
/******/ return __webpack_require__(__webpack_require__.s = 0);
|
|
/******/ })
|
|
/************************************************************************/
|
|
/******/ ([
|
|
/* 0 */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
/* WEBPACK VAR INJECTION */(function(global) {
|
|
|
|
var AudioContext = global.AudioContext || global.webkitAudioContext;
|
|
|
|
|
|
// Constructor
|
|
var Recorder = function( config ){
|
|
|
|
if ( !Recorder.isRecordingSupported() ) {
|
|
throw new Error("Recording is not supported in this browser");
|
|
}
|
|
|
|
this.state = "inactive";
|
|
this.config = Object.assign({
|
|
bufferLength: 4096,
|
|
encoderApplication: 2049,
|
|
encoderFrameSize: 20,
|
|
encoderPath: 'encoderWorker.min.js',
|
|
encoderSampleRate: 48000,
|
|
leaveStreamOpen: false,
|
|
maxBuffersPerPage: 40,
|
|
mediaTrackConstraints: true,
|
|
monitorGain: 0,
|
|
numberOfChannels: 1,
|
|
recordingGain: 1,
|
|
resampleQuality: 3,
|
|
streamPages: false,
|
|
wavBitDepth: 16,
|
|
}, config );
|
|
|
|
this.initWorker();
|
|
};
|
|
|
|
|
|
// Static Methods
|
|
Recorder.isRecordingSupported = function(){
|
|
return AudioContext && global.navigator && global.navigator.mediaDevices && global.navigator.mediaDevices.getUserMedia && global.WebAssembly;
|
|
};
|
|
|
|
|
|
// Instance Methods
|
|
Recorder.prototype.clearStream = function(){
|
|
if ( this.stream ) {
|
|
|
|
if ( this.stream.getTracks ) {
|
|
this.stream.getTracks().forEach( function( track ){
|
|
track.stop();
|
|
});
|
|
}
|
|
|
|
else {
|
|
this.stream.stop();
|
|
}
|
|
|
|
delete this.stream;
|
|
}
|
|
|
|
if ( this.audioContext ){
|
|
this.audioContext.close();
|
|
delete this.audioContext;
|
|
}
|
|
};
|
|
|
|
Recorder.prototype.encodeBuffers = function( inputBuffer ){
|
|
if ( this.state === "recording" ) {
|
|
var buffers = [];
|
|
for ( var i = 0; i < inputBuffer.numberOfChannels; i++ ) {
|
|
buffers[i] = inputBuffer.getChannelData(i);
|
|
}
|
|
|
|
this.encoder.postMessage({
|
|
command: "encode",
|
|
buffers: buffers
|
|
});
|
|
}
|
|
};
|
|
|
|
Recorder.prototype.initAudioContext = function( sourceNode ){
|
|
if (sourceNode && sourceNode.context) {
|
|
this.audioContext = sourceNode.context;
|
|
}
|
|
|
|
if ( !this.audioContext ) {
|
|
this.audioContext = new AudioContext();
|
|
}
|
|
|
|
return this.audioContext;
|
|
};
|
|
|
|
Recorder.prototype.initAudioGraph = function(){
|
|
var self = this;
|
|
|
|
// First buffer can contain old data. Don't encode it.
|
|
this.encodeBuffers = function(){
|
|
delete this.encodeBuffers;
|
|
};
|
|
|
|
this.scriptProcessorNode = this.audioContext.createScriptProcessor( this.config.bufferLength, this.config.numberOfChannels, this.config.numberOfChannels );
|
|
this.scriptProcessorNode.connect( this.audioContext.destination );
|
|
this.scriptProcessorNode.onaudioprocess = function( e ) {
|
|
self.encodeBuffers( e.inputBuffer );
|
|
};
|
|
|
|
this.monitorGainNode = this.audioContext.createGain();
|
|
this.setMonitorGain( this.config.monitorGain );
|
|
this.monitorGainNode.connect( this.audioContext.destination );
|
|
|
|
this.recordingGainNode = this.audioContext.createGain();
|
|
this.setRecordingGain( this.config.recordingGain );
|
|
this.recordingGainNode.connect( this.scriptProcessorNode );
|
|
};
|
|
|
|
Recorder.prototype.initSourceNode = function( sourceNode ){
|
|
var self = this;
|
|
|
|
if ( sourceNode && sourceNode.context ) {
|
|
return global.Promise.resolve( sourceNode );
|
|
}
|
|
|
|
if ( this.stream && this.sourceNode ) {
|
|
return global.Promise.resolve( this.sourceNode );
|
|
}
|
|
|
|
return global.navigator.mediaDevices.getUserMedia({ audio : this.config.mediaTrackConstraints }).then( function( stream ){
|
|
self.stream = stream;
|
|
return self.audioContext.createMediaStreamSource( stream );
|
|
});
|
|
};
|
|
|
|
Recorder.prototype.initWorker = function(){
|
|
var self = this;
|
|
var streamPage = function( e ) { self.streamPage( e.data ); };
|
|
var storePage = function( e ) { self.storePage( e.data ); };
|
|
|
|
this.recordedPages = [];
|
|
this.totalLength = 0;
|
|
this.encoder = new global.Worker( this.config.encoderPath );
|
|
this.encoder.addEventListener( "message", this.config.streamPages ? streamPage : storePage );
|
|
};
|
|
|
|
Recorder.prototype.pause = function(){
|
|
if ( this.state === "recording" ){
|
|
this.state = "paused";
|
|
this.onpause();
|
|
}
|
|
};
|
|
|
|
Recorder.prototype.resume = function() {
|
|
if ( this.state === "paused" ) {
|
|
this.state = "recording";
|
|
this.onresume();
|
|
}
|
|
};
|
|
|
|
Recorder.prototype.setRecordingGain = function( gain ){
|
|
this.config.recordingGain = gain;
|
|
|
|
if ( this.recordingGainNode && this.audioContext ) {
|
|
this.recordingGainNode.gain.setTargetAtTime(gain, this.audioContext.currentTime, 0.01);
|
|
}
|
|
};
|
|
|
|
Recorder.prototype.setMonitorGain = function( gain ){
|
|
this.config.monitorGain = gain;
|
|
|
|
if ( this.monitorGainNode && this.audioContext ) {
|
|
this.monitorGainNode.gain.setTargetAtTime(gain, this.audioContext.currentTime, 0.01);
|
|
}
|
|
};
|
|
|
|
Recorder.prototype.start = function( sourceNode ){
|
|
if ( this.state === "inactive" ) {
|
|
var self = this;
|
|
this.initAudioContext( sourceNode );
|
|
this.initAudioGraph();
|
|
|
|
return this.initSourceNode( sourceNode ).then( function( sourceNode ){
|
|
self.state = "recording";
|
|
self.encoder.postMessage( Object.assign({
|
|
command: 'init',
|
|
originalSampleRate: self.audioContext.sampleRate,
|
|
wavSampleRate: self.audioContext.sampleRate
|
|
}, self.config));
|
|
self.sourceNode = sourceNode;
|
|
self.sourceNode.connect( self.monitorGainNode );
|
|
self.sourceNode.connect( self.recordingGainNode );
|
|
self.onstart();
|
|
});
|
|
}
|
|
};
|
|
|
|
Recorder.prototype.stop = function(){
|
|
if ( this.state !== "inactive" ) {
|
|
this.state = "inactive";
|
|
this.monitorGainNode.disconnect();
|
|
this.scriptProcessorNode.disconnect();
|
|
this.recordingGainNode.disconnect();
|
|
this.sourceNode.disconnect();
|
|
|
|
if ( !this.config.leaveStreamOpen ) {
|
|
this.clearStream();
|
|
}
|
|
|
|
this.encoder.postMessage({ command: "done" });
|
|
}
|
|
};
|
|
|
|
Recorder.prototype.storePage = function( page ) {
|
|
if ( page === null ) {
|
|
var outputData = new Uint8Array( this.totalLength );
|
|
this.recordedPages.reduce( function( offset, page ){
|
|
outputData.set( page, offset );
|
|
return offset + page.length;
|
|
}, 0);
|
|
|
|
this.ondataavailable( outputData );
|
|
this.initWorker();
|
|
this.onstop();
|
|
}
|
|
|
|
else {
|
|
this.recordedPages.push( page );
|
|
this.totalLength += page.length;
|
|
}
|
|
};
|
|
|
|
Recorder.prototype.streamPage = function( page ) {
|
|
if ( page === null ) {
|
|
this.initWorker();
|
|
this.onstop();
|
|
}
|
|
|
|
else {
|
|
this.ondataavailable( page );
|
|
}
|
|
};
|
|
|
|
|
|
// Callback Handlers
|
|
Recorder.prototype.ondataavailable = function(){};
|
|
Recorder.prototype.onpause = function(){};
|
|
Recorder.prototype.onresume = function(){};
|
|
Recorder.prototype.onstart = function(){};
|
|
Recorder.prototype.onstop = function(){};
|
|
|
|
|
|
module.exports = Recorder;
|
|
|
|
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1)))
|
|
|
|
/***/ }),
|
|
/* 1 */
|
|
/***/ (function(module, exports) {
|
|
|
|
var g;
|
|
|
|
// This works in non-strict mode
|
|
g = (function() {
|
|
return this;
|
|
})();
|
|
|
|
try {
|
|
// This works if eval is allowed (see CSP)
|
|
g = g || Function("return this")() || (1,eval)("this");
|
|
} catch(e) {
|
|
// This works if the window reference is available
|
|
if(typeof window === "object")
|
|
g = window;
|
|
}
|
|
|
|
// g can still be undefined, but nothing to do about it...
|
|
// We return undefined, instead of nothing here, so it's
|
|
// easier to handle this case. if(!global) { ...}
|
|
|
|
module.exports = g;
|
|
|
|
|
|
/***/ })
|
|
/******/ ]);
|
|
}); |