SoundRecognizer = { rec: null, wave: null, SampleRate: 16000, testBitRate: 16, isCloseRecorder: false, SendInterval: 300, realTimeSendTryType: 'pcm', realTimeSendTryEncBusy: 0, realTimeSendTryTime: 0, realTimeSendTryNumber: 0, transferUploadNumberMax: 0, realTimeSendTryChunk: null, soundType: "pcm", init: function (config) { this.soundType = config.soundType || 'pcm'; this.SampleRate = config.sampleRate || 16000; this.recwaveElm = config.recwaveElm || ''; this.TransferUpload = config.translerCallBack || this.TransferProcess; this.initRecorder(); }, RealTimeSendTryReset: function (type) { this.realTimeSendTryType = type; this.realTimeSendTryTime = 0; }, RealTimeSendTry: function (rec, isClose) { var that = this; var t1 = Date.now(), endT = 0, recImpl = Recorder.prototype; if (this.realTimeSendTryTime == 0) { this.realTimeSendTryTime = t1; this.realTimeSendTryEncBusy = 0; this.realTimeSendTryNumber = 0; this.transferUploadNumberMax = 0; this.realTimeSendTryChunk = null; } if (!isClose && t1 - this.realTimeSendTryTime < this.SendInterval) { return;//控制缓冲达到指定间隔才进行传输 } this.realTimeSendTryTime = t1; var number = ++this.realTimeSendTryNumber; //借用SampleData函数进行数据的连续处理,采样率转换是顺带的 var chunk = Recorder.SampleData(rec.buffers, rec.srcSampleRate, this.SampleRate, this.realTimeSendTryChunk, { frameType: isClose ? "" : this.realTimeSendTryType }); //清理已处理完的缓冲数据,释放内存以支持长时间录音,最后完成录音时不能调用stop,因为数据已经被清掉了 for (var i = this.realTimeSendTryChunk ? this.realTimeSendTryChunk.index : 0; i < chunk.index; i++) { rec.buffers[i] = null; } this.realTimeSendTryChunk = chunk; //没有新数据,或结束时的数据量太小,不能进行mock转码 if (chunk.data.length == 0 || isClose && chunk.data.length < 2000) { this.TransferUpload(number, null, 0, null, isClose); return; } //实时编码队列阻塞处理 if (!isClose) { if (this.realTimeSendTryEncBusy >= 2) { console.log("编码队列阻塞,已丢弃一帧", 1); return; } } this.realTimeSendTryEncBusy++; //通过mock方法实时转码成mp3、wav var encStartTime = Date.now(); var recMock = Recorder({ type: this.realTimeSendTryType , sampleRate: this.SampleRate //采样率 , bitRate: this.testBitRate //比特率 }); recMock.mock(chunk.data, chunk.sampleRate); recMock.stop(function (blob, duration) { that.realTimeSendTryEncBusy && (that.realTimeSendTryEncBusy--); blob.encTime = Date.now() - encStartTime; //转码好就推入传输 that.TransferUpload(number, blob, duration, recMock, isClose); }, function (msg) { that.realTimeSendTryEncBusy && (that.realTimeSendTryEncBusy--); //转码错误?没想到什么时候会产生错误! console.log("不应该出现的错误:" + msg, 1); }); }, recordClose: function () { try { this.rec.close(function () { this.isCloseRecorder = true; }); this.RealTimeSendTry(this.rec, true);//最后一次发送 } catch (ex) { // recordClose(); } }, recordEnd: function () { try { this.rec.stop(function (blob, time) { this.recordClose(); }, function (s) { this.recordClose(); }); } catch (ex) { } }, initRecorder: function () { var that = this; var rec = Recorder({ type: that.soundType , bitRate: that.testBitRate , sampleRate: that.SampleRate , onProcess: function (buffers, level, time, sampleRate) { that.wave.input(buffers[buffers.length - 1], level, sampleRate); that.RealTimeSendTry(rec, false);//推入实时处理,因为是unknown格式,这里简化函数调用,没有用到buffers和bufferSampleRate,因为这些数据和rec.buffers是完全相同的。 } }); rec.open(function () { that.wave = Recorder.FrequencyHistogramView({ elem: that.recwaveElm, lineCount: 90 , position: 0 , minHeight: 1 , stripeEnable: false }); rec.start(); that.isCloseRecorder = false; that.RealTimeSendTryReset(that.soundType);//重置 }); this.rec = rec; }, TransferProcess: function (number, blobOrNull, duration, blobRec, isClose) { } }