You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			200 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			JavaScript
		
	
			
		
		
	
	
			200 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			JavaScript
		
	
(function(window) {
 | 
						|
  // internal: same as jQuery.extend(true, args...)
 | 
						|
  var extend = function() {
 | 
						|
    var target = arguments[0],
 | 
						|
        sources = [].slice.call(arguments, 1);
 | 
						|
    for (var i = 0; i < sources.length; ++i) {
 | 
						|
      var src = sources[i];
 | 
						|
      for (key in src) {
 | 
						|
        var val = src[key];
 | 
						|
        target[key] = typeof val === "object"
 | 
						|
          ? extend(typeof target[key] === "object" ? target[key] : {}, val)
 | 
						|
          : val;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return target;
 | 
						|
  };
 | 
						|
 | 
						|
  var WORKER_FILE = {
 | 
						|
    wav: "WebAudioRecorderWav.js",
 | 
						|
    ogg: "WebAudioRecorderOgg.js",
 | 
						|
    mp3: "WebAudioRecorderMp3.js"
 | 
						|
  };
 | 
						|
 | 
						|
  // default configs
 | 
						|
  var CONFIGS = {
 | 
						|
    workerDir: "/",     // worker scripts dir (end with /)
 | 
						|
    numChannels: 2,     // number of channels
 | 
						|
    encoding: "wav",    // encoding (can be changed at runtime)
 | 
						|
 | 
						|
    // runtime options
 | 
						|
    options: {
 | 
						|
      timeLimit: 300,           // recording time limit (sec)
 | 
						|
      encodeAfterRecord: false, // process encoding after recording
 | 
						|
      progressInterval: 1000,   // encoding progress report interval (millisec)
 | 
						|
      bufferSize: undefined,    // buffer size (use browser default)
 | 
						|
 | 
						|
      // encoding-specific options
 | 
						|
      wav: {
 | 
						|
        mimeType: "audio/wav"
 | 
						|
      },
 | 
						|
      ogg: {
 | 
						|
        mimeType: "audio/ogg",
 | 
						|
        quality: 0.5            // (VBR only): quality = [-0.1 .. 1]
 | 
						|
      },
 | 
						|
      mp3: {
 | 
						|
        mimeType: "audio/mpeg",
 | 
						|
        bitRate: 160            // (CBR only): bit rate = [64 .. 320]
 | 
						|
      }
 | 
						|
    }
 | 
						|
  };
 | 
						|
 | 
						|
  // constructor
 | 
						|
  var WebAudioRecorder = function(sourceNode, configs) {
 | 
						|
    extend(this, CONFIGS, configs || {});
 | 
						|
    this.context = sourceNode.context;
 | 
						|
    if (this.context.createScriptProcessor == null)
 | 
						|
      this.context.createScriptProcessor = this.context.createJavaScriptNode;
 | 
						|
    this.input = this.context.createGain();
 | 
						|
    sourceNode.connect(this.input);
 | 
						|
    this.buffer = [];
 | 
						|
    this.initWorker();
 | 
						|
  };
 | 
						|
 | 
						|
  // instance methods
 | 
						|
  extend(WebAudioRecorder.prototype, {
 | 
						|
    isRecording: function() { return this.processor != null; },
 | 
						|
 | 
						|
    setEncoding: function(encoding) {
 | 
						|
      if (this.isRecording())
 | 
						|
        this.error("setEncoding: cannot set encoding during recording");
 | 
						|
      else if (this.encoding !== encoding) {
 | 
						|
        this.encoding = encoding;
 | 
						|
        this.initWorker();
 | 
						|
      }
 | 
						|
    },
 | 
						|
 | 
						|
    setOptions: function(options) {
 | 
						|
      if (this.isRecording())
 | 
						|
        this.error("setOptions: cannot set options during recording");
 | 
						|
      else {
 | 
						|
        extend(this.options, options);
 | 
						|
        this.worker.postMessage({ command: "options", options: this.options });
 | 
						|
      }
 | 
						|
    },
 | 
						|
 | 
						|
    startRecording: function() {
 | 
						|
      if (this.isRecording())
 | 
						|
        this.error("startRecording: previous recording is running");
 | 
						|
      else {
 | 
						|
        var numChannels = this.numChannels,
 | 
						|
            buffer = this.buffer,
 | 
						|
            worker = this.worker;
 | 
						|
        this.processor = this.context.createScriptProcessor(
 | 
						|
                                this.options.bufferSize,
 | 
						|
                                this.numChannels, this.numChannels);
 | 
						|
        this.input.connect(this.processor);
 | 
						|
        this.processor.connect(this.context.destination);
 | 
						|
        this.processor.onaudioprocess = function(event) {
 | 
						|
          for (var ch = 0; ch < numChannels; ++ch)
 | 
						|
            buffer[ch] = event.inputBuffer.getChannelData(ch);
 | 
						|
          worker.postMessage({ command: "record", buffer: buffer });
 | 
						|
        };
 | 
						|
        this.worker.postMessage({
 | 
						|
          command: "start",
 | 
						|
          bufferSize: this.processor.bufferSize
 | 
						|
        });
 | 
						|
        this.startTime = Date.now();
 | 
						|
      }
 | 
						|
    },
 | 
						|
 | 
						|
    recordingTime: function() {
 | 
						|
      return this.isRecording() ? (Date.now() - this.startTime) * 0.001 : null;
 | 
						|
    },
 | 
						|
 | 
						|
    cancelRecording: function() {
 | 
						|
      if (this.isRecording()) {
 | 
						|
        this.input.disconnect();
 | 
						|
        this.processor.disconnect();
 | 
						|
        delete this.processor;
 | 
						|
        this.worker.postMessage({ command: "cancel" });
 | 
						|
      } else
 | 
						|
        this.error("cancelRecording: no recording is running");
 | 
						|
    },
 | 
						|
 | 
						|
    finishRecording: function() {
 | 
						|
      if (this.isRecording()) {
 | 
						|
        this.input.disconnect();
 | 
						|
        this.processor.disconnect();
 | 
						|
        delete this.processor;
 | 
						|
        this.worker.postMessage({ command: "finish" });
 | 
						|
      } else
 | 
						|
        this.error("finishRecording: no recording is running");
 | 
						|
    },
 | 
						|
 | 
						|
    cancelEncoding: function() {
 | 
						|
      if (this.options.encodeAfterRecord)
 | 
						|
        if (this.isRecording())
 | 
						|
          this.error("cancelEncoding: recording is not finished");
 | 
						|
        else {
 | 
						|
          this.onEncodingCanceled(this);
 | 
						|
          this.initWorker();
 | 
						|
        }
 | 
						|
      else
 | 
						|
        this.error("cancelEncoding: invalid method call");
 | 
						|
    },
 | 
						|
 | 
						|
    initWorker: function() {
 | 
						|
      if (this.worker != null)
 | 
						|
        this.worker.terminate();
 | 
						|
      this.onEncoderLoading(this, this.encoding);
 | 
						|
      this.worker = new Worker(this.workerDir + WORKER_FILE[this.encoding]);
 | 
						|
      var _this = this;
 | 
						|
      this.worker.onmessage = function(event) {
 | 
						|
        var data = event.data;
 | 
						|
        switch (data.command) {
 | 
						|
          case "loaded":
 | 
						|
            _this.onEncoderLoaded(_this, _this.encoding);
 | 
						|
            break;
 | 
						|
          case "timeout":
 | 
						|
            _this.onTimeout(_this);
 | 
						|
            break;
 | 
						|
          case "progress":
 | 
						|
            _this.onEncodingProgress(_this, data.progress);
 | 
						|
            break;
 | 
						|
          case "complete":
 | 
						|
            _this.onComplete(_this, data.blob);
 | 
						|
            break;
 | 
						|
          case "error":
 | 
						|
            _this.error(data.message);
 | 
						|
        }
 | 
						|
      };
 | 
						|
      this.worker.postMessage({
 | 
						|
        command: "init",
 | 
						|
        config: {
 | 
						|
          sampleRate: this.context.sampleRate,
 | 
						|
          numChannels: this.numChannels
 | 
						|
        },
 | 
						|
        options: this.options
 | 
						|
      });
 | 
						|
    },
 | 
						|
 | 
						|
    error: function(message) {
 | 
						|
      this.onError(this, "WebAudioRecorder.js:" + message);
 | 
						|
    },
 | 
						|
 | 
						|
    // event handlers
 | 
						|
    onEncoderLoading: function(recorder, encoding) {},
 | 
						|
    onEncoderLoaded: function(recorder, encoding) {},
 | 
						|
    onTimeout: function(recorder) { recorder.finishRecording(); },
 | 
						|
    onEncodingProgress: function (recorder, progress) {},
 | 
						|
    onEncodingCanceled: function(recorder) {},
 | 
						|
    onComplete: function(recorder, blob) {
 | 
						|
      recorder.onError(recorder, "WebAudioRecorder.js: You must override .onComplete event");
 | 
						|
    },
 | 
						|
    onError: function(recorder, message) { console.log(message); }
 | 
						|
  });
 | 
						|
 | 
						|
  window.WebAudioRecorder = WebAudioRecorder;
 | 
						|
})(window);
 |