UNPKG

uploadable-react-audio-recorder

Version:
131 lines (118 loc) 4.19 kB
import encodeWAV from './waveEncoder'; /* interface Navigator { webkitGetUserMedia?: typeof navigator.getUserMedia, mozGetUserMedia?: typeof navigator.getUserMedia, msGetUserMedia?: typeof navigator.getUserMedia, }; navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; */ function getAudioContext(){ var ctxt = { sampleRate: null, createGain: null, createMediaStreamSource: null, createScriptProcessor: null, destination:null, decodeAudioData:null, createBufferSource:null }; try{ ctxt = new AudioContext(); }catch(e){ console.log(e); } return ctxt; } export default class WAVEInterface { static audioContext = getAudioContext(); static bufferSize = 2048; playbackNode: AudioBufferSourceNode; recordingNodes: AudioNode[] = []; recordingStream: MediaStream; buffers: Float32Array[][]; // one buffer for each channel L,R encodingCache?: Blob; get bufferLength() { return this.buffers[0].length * WAVEInterface.bufferSize; } get audioDuration() { return this.bufferLength / WAVEInterface.audioContext.sampleRate; } get audioData() { return this.encodingCache || encodeWAV(this.buffers, this.bufferLength, WAVEInterface.audioContext.sampleRate); } startRecording() { return new Promise((resolve, reject) => { try{ navigator.getUserMedia({ audio: true }, (stream) => { const { audioContext } = WAVEInterface; const recGainNode = audioContext.createGain(); const recSourceNode = audioContext.createMediaStreamSource(stream); const recProcessingNode = audioContext.createScriptProcessor(WAVEInterface.bufferSize, 2, 2); if(recGainNode && recSourceNode && recProcessingNode) { if (this.encodingCache) this.encodingCache = null; recProcessingNode.onaudioprocess = (event) => { // console.log('audio process', this); if (this.encodingCache) this.encodingCache = null; // save left and right buffers for (let i = 0; i < 2; i++) { const channel = event.inputBuffer.getChannelData(i); this.buffers[i].push(new Float32Array(channel)); } }; recSourceNode.connect(recGainNode); recGainNode.connect(recProcessingNode); recProcessingNode.connect(audioContext.destination); this.recordingStream = stream; this.recordingNodes.push(recSourceNode, recGainNode, recProcessingNode); resolve(stream); } }, (err) => { reject(err); }); } catch(e){ reject(e); } }); } stopRecording() { if (this.recordingStream) { this.recordingStream.getTracks()[0].stop(); delete this.recordingStream; } for (let i in this.recordingNodes) { this.recordingNodes[i].disconnect(); delete this.recordingNodes[i]; } } startPlayback(loop: boolean = false, onended: () => void) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsArrayBuffer(this.audioData); reader.onloadend = () => { WAVEInterface.audioContext.decodeAudioData(reader.result, (buffer) => { const source = WAVEInterface.audioContext.createBufferSource(); source.buffer = buffer; source.connect(WAVEInterface.audioContext.destination); source.loop = loop; source.start(0); source.onended = onended; this.playbackNode = source; resolve(source); }); }; }); } stopPlayback() { this.playbackNode.stop(); } reset() { if (this.playbackNode) { this.playbackNode.stop(); this.playbackNode.disconnect(0); delete this.playbackNode; } this.stopRecording(); this.buffers = [[], []]; } }