js/plugins/lamejs-plugin.js
/**
* @file lamejs-plugin.js
* @since 1.1.0
*/
import videojs from 'video.js';
const RecordEngine = videojs.getComponent('RecordEngine');
/**
* Audio-only engine for the lamejs library.
*
* @class
* @augments RecordEngine
*/
class LamejsEngine extends RecordEngine {
/**
* Creates an instance of this class.
*
* @param {Player} player
* The `Player` that this class should be attached to.
*
* @param {Object} [options]
* The key/value store of player options.
*/
constructor(player, options) {
super(player, options);
/**
* Enables console logging for debugging purposes.
*
* @type {boolean}
*/
this.debug = false;
/**
* Specifies the sample rate to encode at.
*
* @type {number}
*/
this.sampleRate = 44100;
/**
* Specifies the bitrate in kbps.
*
* @type {number}
*/
this.bitRate = 128;
/**
* Path to `worker-realtime.js` worker script.
*
* @type {string}
*/
this.audioWorkerURL = 'worker-realtime.js';
/**
* Mime-type for audio output.
*
* @type {string}
*/
this.audioType = 'audio/mpeg';
}
/**
* Setup recording engine.
*
* @param {LocalMediaStream} stream - Media stream to record.
* @param {Object} mediaType - Object describing the media type of this
* engine.
* @param {Boolean} debug - Indicating whether or not debug messages should
* be printed in the console.
*/
setup(stream, mediaType, debug) {
this.inputStream = stream;
this.mediaType = mediaType;
this.debug = debug;
this.config = {
debug: this.debug,
sampleRate: this.sampleRate,
bitRate: this.bitRate
};
this.engine = new Worker(this.audioWorkerURL);
this.engine.onmessage = this.onWorkerMessage.bind(this);
this.engine.postMessage({cmd: 'init', config: this.config});
}
/**
* Start recording.
*/
start() {
let AudioContext = window.AudioContext || window.webkitAudioContext;
this.audioContext = new AudioContext();
this.audioSourceNode = this.audioContext.createMediaStreamSource(
this.inputStream);
// a bufferSize of 0 instructs the browser to choose the best bufferSize
this.processor = this.audioContext.createScriptProcessor(
0, 1, 1);
this.processor.onaudioprocess = this.onAudioProcess.bind(this);
this.audioSourceNode.connect(this.processor);
this.processor.connect(this.audioContext.destination);
}
/**
* Stop recording.
*/
stop() {
if (this.processor && this.audioSourceNode) {
this.audioSourceNode.disconnect();
this.processor.disconnect();
this.processor.onaudioprocess = null;
}
if (this.audioContext) {
// ignore errors about already being closed
this.audioContext.close().then(() => {}).catch((reason) => {});
}
// free up memory
this.engine.postMessage({cmd: 'finish'});
}
/**
* Received a message from the worker.
*
* @private
* @param {Object} ev - Worker responded with event object.
*/
onWorkerMessage(ev) {
switch (ev.data.cmd) {
case 'end':
this.onStopRecording(new Blob(ev.data.buf,
{type: this.audioType}));
break;
case 'error':
this.player().trigger('error', ev.data.error);
break;
default:
// invalid message received
this.player().trigger('error', ev.data);
break;
}
}
/**
* Continuous encoding of audio data.
*
* @private
* @param {Object} ev - onaudioprocess responded with data object.
*/
onAudioProcess(ev) {
// send microphone data to LAME for MP3 encoding while recording
let data = ev.inputBuffer.getChannelData(0);
this.engine.postMessage({cmd: 'encode', buf: data});
}
}
// expose plugin
videojs.LamejsEngine = LamejsEngine;
export default LamejsEngine;