+Class(UnlimitedPizza, "Pepperoni").inherits(Widget)({
+ INNER_HTML : ' \
+<a class="record-button">⬤</a> \
+<div class="record-info"> \
+ <div class="record-progress"> \
+ <div class="record-progress-bar-container"> \
+ <div class="record-progress-bar"></div> \
+ </div> \
+ <a class="record-clear">X</a> \
+ </div> \
+ <audio class="record-preview" controls></audio> \
+</div> \
+ ',
+ PAUSE : '▐▐',
+ RECORD : '⬤',
+ prototype : {
+ maxSize : 1048576,
+ recording : false,
+ source : null,
+ recorder : null,
+ context : null,
+ workerPath : '/js/vendor/recorderjs/recorderWorker.js',
+ init : function init(config) {
+ Widget.prototype.init.call(this, config);
+
+ if (!this.context) {
+ this.context = new (window.AudioContext || window.webkitAudioContext)();
+ }
+
+ if (!this.source) {
+ this._getUserMedia({
+ audio : true
+ }, this._onUserMedia.bind(this), this._onUserMediaError.bind(this))
+ }
+
+ this.element.html(this.constructor.INNER_HTML);
+
+ this.controlButton = this.element.find('.record-button');
+ this.clearButton = this.element.find('.record-clear');
+ this.audioElement = this.element.find('audio');
+ this.progressBarContainer = this.element.find('.record-progress-bar-container');
+ this.progressBar = this.element.find('.record-progress-bar');
+
+ this._bindEvents();
+ },
+
+ record : function record() {
+ if (this.recorder && !this.recording) {
+ this._canRecord(function handleCanRecord(canRecord) {
+ if (canRecord) {
+ this.recording = true;
+ this.controlButton.addClass('recording')
+ this.controlButton.html(this.constructor.PAUSE);
+ this._interval = setInterval(this._onRecordCheck.bind(this), 100);
+ this.recorder.record();
+ }
+ }.bind(this));
+ }
+ },
+
+ stop : function stop() {
+ if (this.recorder && this.recording) {
+ this.recording = false;
+ this.controlButton.removeClass('recording')
+ this.controlButton.html(this.constructor.RECORD);
+ clearInterval(this._interval);
+ this.recorder.stop();
+ this.recorder.exportWAV();
+ }
+ },
+
+ clear : function clear() {
+ if (this.recorder) {
+ this.progressBar.width(0);
+ this.audioElement.attr('src', '');
+ this.audioElement[0].load();
+ this.recorder.clear()
+ }
+ },
+
+ finalize : function finalize(callback) {
+ if (this.recorder) {
+ this.recorder.exportWAV(callback);
+ }
+ },
+
+ getBuffer : function getBuffer(callback) {
+ if (this.recorder) {
+ this.recorder.getBuffer(callback);
+ }
+ },
+
+ _bindEvents : function bindEvents() {
+ this.controlButton.on('click', function () {
+ if (this.recording) {
+ this.stop();
+ } else {
+ this.record();
+ }
+ }.bind(this))
+
+ this.clearButton.on('click', function () {
+ if (!this.recording) {
+ this.clear();
+ }
+ }.bind(this))
+ },
+
+ _onRecording : function _onRecording(buffer) {
+ this._buffer = buffer;
+
+ this.audioElement.attr('src', URL.createObjectURL(buffer));
+ this.audioElement[0].load();
+ },
+
+ _onUserMedia : function _onUserMedia(localMediaStream) {
+ this.source = this.context.createMediaStreamSource(localMediaStream);
+ this.recorder = new Recorder(this.source, {
+ workerPath : this.workerPath,
+ callback : this._onRecording.bind(this)
+ });
+ },
+
+ _onUserMediaError : function _onUserMediaError(error) {
+ console.log("Something went wrong", error);
+ this.disable();
+ },
+
+ _onRecordCheck : function _onRecordCheck() {
+ this._canRecord(function (canRecord, bufferSize) {
+ var width = bufferSize * this.progressBarContainer.width() / this.maxSize;
+ this.progressBar.width(width);
+ if (!canRecord) {
+ this.stop();
+ }
+ }.bind(this));
+ },
+
+ _canRecord : function _canRecord(callback) {
+ this.recorder.getBuffer(function getBuffer(buffer) {
+ var bufferSize = buffer[0].length + buffer[1].length;
+ callback && callback(bufferSize <= this.maxSize, bufferSize);
+ }.bind(this));
+ },
+
+ // Normalize get user media
+ _getUserMedia : (navigator.getUserMedia ||
+ navigator.webkitGetUserMedia ||
+ navigator.mozGetUserMedia ||
+ navigator.msGetUserMedia).bind(navigator)
+ }
+});