diff --git a/README.md b/README.md index 23f9e37a..4040f79d 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ The Opus encoder will not work if the value is not 8000, 12000, 16000, 24000 or rec.addEventListener( type, listener[, useCapture] ) -**addEventListener** will add an event listener to the event target. Custom events are "recordingProgress", "recordingError", "dataAvailable", "start", "pause", "resume" and "stop". +**addEventListener** will add an event listener to the event target. Available events are "recordingProgress", "streamError", "streamReady", dataAvailable", "start", "pause", "resume" and "stop". rec.setMonitorGain( gain ) diff --git a/example.html b/example.html index 8514a4af..826f6477 100644 --- a/example.html +++ b/example.html @@ -77,9 +77,6 @@

Log

init.addEventListener( "click", function(){ - init.disabled = pause.disabled = resume.disabled = stopButton.disabled = true; - start.disabled = false; - recorder = new Recorder({ monitorGain: monitorGain.value, numberOfChannels: numberOfChannels.value, @@ -117,10 +114,16 @@

Log

screenLogger('Recorded ' + e.detail + ' seconds'); }); - recorder.addEventListener( "recordingError", function(e){ + recorder.addEventListener( "streamError", function(e){ screenLogger('Error encountered: ' + e.error.name ); }); + recorder.addEventListener( "streamReady", function(e){ + screenLogger('Audio stream is ready. Recording can begin.'); + init.disabled = pause.disabled = resume.disabled = stopButton.disabled = true; + start.disabled = false; + }); + recorder.addEventListener( "dataAvailable", function(e){ var fileName = new Date().toISOString() + "." + e.detail.type.split("/")[1]; var url = URL.createObjectURL( e.detail ); diff --git a/oggopus.js b/oggopus.js index 6c0504e2..88574349 100644 --- a/oggopus.js +++ b/oggopus.js @@ -29,11 +29,10 @@ var OggOpus = function( config ){ OggOpus.prototype.encode = function( samples ) { var sampleIndex = 0; - var lengthToCopy; while ( sampleIndex < samples.length ) { - lengthToCopy = Math.min( this.encoderBufferLength - this.encoderBufferIndex, samples.length - sampleIndex ); + var lengthToCopy = Math.min( this.encoderBufferLength - this.encoderBufferIndex, samples.length - sampleIndex ); this.encoderBuffer.set( samples.subarray( sampleIndex, sampleIndex+lengthToCopy ), this.encoderBufferIndex ); sampleIndex += lengthToCopy; this.encoderBufferIndex += lengthToCopy; @@ -199,18 +198,23 @@ OggOpus.prototype.segmentPacket = function( packetLength ) { var packetIndex = 0; while ( packetLength >= 0 ) { + + if ( this.segmentTableIndex === 255 ) { + this.generatePage(); + this.headerType = 1; + } + var segmentLength = Math.min( packetLength, 255 ); this.segmentTable[ this.segmentTableIndex++ ] = segmentLength; this.segmentData.set( this.encoderOutputBuffer.subarray( packetIndex, packetIndex + segmentLength ), this.segmentDataIndex ); this.segmentDataIndex += segmentLength; packetIndex += segmentLength; packetLength -= 255; - - if ( this.segmentTableIndex === 255 ) { - this.generatePage(); - this.headerType = ( packetLength >= 0 ) ? 1 : 0; - } } this.granulePosition += ( 48 * this.encoderFrameSize ); + if ( this.segmentTableIndex === 255 ) { + this.generatePage(); + this.headerType = 0; + } }; diff --git a/recorder.js b/recorder.js index 05f11820..5f0fc8aa 100755 --- a/recorder.js +++ b/recorder.js @@ -49,25 +49,28 @@ Recorder.prototype.createAudioNodes = function(){ this.monitorNode = this.audioContext.createGain(); this.setMonitorGain( this.config.monitorGain ); - // 6th order butterworth if ( this.config.sampleRate < this.audioContext.sampleRate ) { - this.filterNode = this.audioContext.createBiquadFilter(); - this.filterNode2 = this.audioContext.createBiquadFilter(); - this.filterNode3 = this.audioContext.createBiquadFilter(); - this.filterNode.type = this.filterNode2.type = this.filterNode3.type = "lowpass"; - - var nyquistFreq = this.config.sampleRate / 2; - this.filterNode.frequency.value = this.filterNode2.frequency.value = this.filterNode3.frequency.value = nyquistFreq - ( nyquistFreq / 3.5355 ); - this.filterNode.Q.value = 0.51764; - this.filterNode2.Q.value = 0.70711; - this.filterNode3.Q.value = 1.93184; - - this.filterNode.connect( this.filterNode2 ); - this.filterNode2.connect( this.filterNode3 ); - this.filterNode3.connect( this.scriptProcessorNode ); + this.createButterworthFilter(); } }; +Recorder.prototype.createButterworthFilter = function(){ + this.filterNode = this.audioContext.createBiquadFilter(); + this.filterNode2 = this.audioContext.createBiquadFilter(); + this.filterNode3 = this.audioContext.createBiquadFilter(); + this.filterNode.type = this.filterNode2.type = this.filterNode3.type = "lowpass"; + + var nyquistFreq = this.config.sampleRate / 2; + this.filterNode.frequency.value = this.filterNode2.frequency.value = this.filterNode3.frequency.value = nyquistFreq - ( nyquistFreq / 3.5355 ); + this.filterNode.Q.value = 0.51764; + this.filterNode2.Q.value = 0.70711; + this.filterNode3.Q.value = 1.93184; + + this.filterNode.connect( this.filterNode2 ); + this.filterNode2.connect( this.filterNode3 ); + this.filterNode3.connect( this.scriptProcessorNode ); +}; + Recorder.prototype.initStream = function(){ var that = this; navigator.getUserMedia( @@ -77,9 +80,10 @@ Recorder.prototype.initStream = function(){ that.sourceNode = that.audioContext.createMediaStreamSource( stream ); that.sourceNode.connect( that.filterNode || that.scriptProcessorNode ); that.sourceNode.connect( that.monitorNode ); + that.eventTarget.dispatchEvent( new Event( "streamReady" ) ); }, function ( e ) { - that.eventTarget.dispatchEvent( new ErrorEvent( "recordingError", { error: e } ) ); + that.eventTarget.dispatchEvent( new ErrorEvent( "streamError", { error: e } ) ); } ); }; @@ -129,9 +133,6 @@ Recorder.prototype.setMonitorGain = function( gain ){ Recorder.prototype.start = function(){ if ( this.state === "inactive" && this.sourceNode ) { - this.monitorNode.connect( this.audioContext.destination ); - this.scriptProcessorNode.connect( this.audioContext.destination ); - var that = this; this.worker = new Worker( this.config.workerPath ); this.worker.addEventListener( "message", function( e ) { @@ -153,7 +154,9 @@ Recorder.prototype.start = function(){ this.state = "recording"; this.recordingTime = 0; - this.recordBuffers = function(){ delete this.recordBuffers }; + this.monitorNode.connect( this.audioContext.destination ); + this.scriptProcessorNode.connect( this.audioContext.destination ); + this.recordBuffers = function(){ delete this.recordBuffers }; // First buffer can contain old data this.eventTarget.dispatchEvent( new Event( 'start' ) ); this.eventTarget.dispatchEvent( new CustomEvent( 'recordingProgress', { "detail": this.recordingTime } ) ); }