TeaWeb/vendor/opus-recorder/recorder.js
2018-02-27 17:20:49 +01:00

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;
/***/ })
/******/ ]);
});