Skip to content

Commit

Permalink
解决设备卡顿时接收到PCM缺失导致的音频变短 xiangyuecn#51
Browse files Browse the repository at this point in the history
  • Loading branch information
xiangyuecn committed Oct 26, 2019
1 parent edb2a13 commit cbd272b
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 23 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ IOS其他浏览器||

*2019-07-22*[#34](https://github.com/xiangyuecn/Recorder/issues/34)反馈研究后发现,问题一:macOS、IOS的Safari对连续调用录音(中途未调用close)是有问题的,但只要调用close后再重复录音就没有问题。问题二:IOS上如果录音之前先播放了任何Audio,录音过程可能会变得很诡异,但如果先录音,就不存在此问题(19-09-18 Evan:QQ1346751357反馈发现本问题并非必现,[功能页面](https://hft.bigdatahefei.com/LocateSearchService/sfc/index),但本库的Demo内却必现,原因不明)。chrome、firefox正常的很。目测这两个问题是非我等屌丝能够解决的,于是报告给苹果家程序员看看,因此发了个[帖子](https://forums.developer.apple.com/message/373108),顺手在`Feedback Assistant`提交了`bug report`,但好几天过去了没有任何回应(顺带给微软一个好评)。

*2019-10-26* 针对[#51](https://github.com/xiangyuecn/Recorder/issues/51)的问题研究后发现,如果录音时设备偶尔出现很卡的情况下(CPU被其他程序大量占用),浏览器采集到的音频是断断续续的,导致10秒的录音可能就只返回了5秒的数据量,这个时候最终编码得到的音频时长明显变短,播放时的效果就像快放一样。此问题能够稳定复现(使用别的程序大量占用CPU来模拟),目前已在`envIn`内部函数中进行了补偿处理,在浏览器两次传入PCM数据之间填充一段静默数据已弥补丢失的时长;最终编码得到的音频时长将和实际录音时长基本一致,消除了快放效果,但由于丢失的音频已被静默数据代替,听起来就是数据本身的断断续续的效果。在设备不卡时录音没有此问题。




Expand All @@ -246,7 +248,7 @@ set={
//注意,取值不能过低,2048开始不同浏览器可能回调速率跟不上造成音质问题(低端浏览器→说的就是腾讯X5)

,onProcess:NOOP //接收到录音数据时的回调函数:fn(buffers,powerLevel,bufferDuration,bufferSampleRate)
//buffers=[[Int16,...],...]:缓冲的PCM数据,为从开始录音到现在的所有pcm片段;powerLevel:当前缓冲的音量级别0-100,bufferDuration:已缓冲时长,bufferSampleRate:缓冲使用的采样率(当type支持边录边转码(Worker)时,此采样率和设置的采样率相同,否则不一定相同)
//buffers=[[Int16,...],...]:缓冲的PCM数据,为从开始录音到现在的所有pcm片段,每次回调可能增加0-n个不定量的pcm片段;powerLevel:当前缓冲的音量级别0-100,bufferDuration:已缓冲时长,bufferSampleRate:缓冲使用的采样率(当type支持边录边转码(Worker)时,此采样率和设置的采样率相同,否则不一定相同)
//如果需要绘制波形之类功能,需要实现此方法即可,使用以计算好的powerLevel可以实现音量大小的直观展示,使用buffers可以达到更高级效果
//注意,buffers数据的采样率和set.sampleRate不一定相同,可能为浏览器提供的原始采样率rec.srcSampleRate,也可能为已转换好的采样率set.sampleRate;如需浏览器原始采样率的数据,请使用rec.buffers数据,而不是本回调的参数;如需明确和set.sampleRate完全相同采样率的数据,请在onProcess中自行连续调用采样率转换函数Recorder.SampleData(),配合mock方法可实现实时转码和压缩语音传输
}
Expand Down Expand Up @@ -302,7 +304,7 @@ set={

buffers中的PCM数据为浏览器采集的原始音频数据,采样率为浏览器提供的原始采样率`rec.srcSampleRate`;在`rec.set.onProcess`回调中`buffers`参数就是此数据或者此数据重新采样后的新数据。

如果你需要长时间实时录音(如长时间语音通话),并且不需要得到最终完整编码的音频文件,Recorder初始化时应当使用一个未知的类型进行初始化(如: type:"unknown",仅仅用于初始化而已,实时转码可以手动转成有效格式,因为有效格式可能内部还有其他类型的缓冲),并且实时在`onProcess`中修改`rec.buffers`数组,只保留最后两个元素,其他元素设为null(代码:`rec.buffers[rec.buffers.length-3]=null`),以释放占用的内存,并且录音结束时不要调用`stop`(因为已录音的时间非常长时,stop操作会导致占用大量的内存,甚至不足),直接调用`close`丢弃所有数据即可。
如果你需要长时间实时录音(如长时间语音通话),并且不需要得到最终完整编码的音频文件,Recorder初始化时应当使用一个未知的类型进行初始化(如: type:"unknown",仅仅用于初始化而已,实时转码可以手动转成有效格式,因为有效格式可能内部还有其他类型的缓冲),并且实时在`onProcess`中修改`rec.buffers`数组,只保留最后两个元素,其他元素设为null(代码:`rec.buffers[rec.buffers.length-3]=null`),以释放占用的内存,并且录音结束时可以不用调用`stop`直接调用`close`丢弃所有数据即可。只要buffers[0]==null时调用`stop`永远会直接走fail回调

### 【属性】rec.srcSampleRate
浏览器提供的原始采样率,只有start或mock调用后才会有值,此采样率就是rec.buffers数据的采样率。
Expand Down
5 changes: 5 additions & 0 deletions app-support-sample/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,11 @@ IOS-Weixin底层会把从微信素材下载过来的原始音频信息存储在s
## 【静态方法】RecordApp.Current.CanProcess()
识别的底层平台是否支持实时返回PCM数据,如果返回值为true,`set.onProcess`将可以被实时回调。

## 【静态方法】RecordApp.GetStartUsedRecOrNull()
获取底层平台录音过程中会使用用来处理实时数据的Recorder对象实例rec,如果底层录音过程中不实用Recorder进行数据的实时处理,将返回null。除了微信平台外,其他平台均会返回rec,但Start调用前和Stop调用后均会返回null,只有Start后和Stop彻底完成前之间才会返回rec。

rec中的方法不一定都能使用,主要用来获取内部缓冲用的,比如:实时清理缓冲,当缓冲被清理,Stop时永远会走fail回调。

## 【静态属性】RecordApp.Platforms
支持的平台列表,目前有三个:
1. `Native`: 原生App平台支持,底层由实际的`JsBridge`提供,此平台默认未开启
Expand Down
2 changes: 1 addition & 1 deletion dist/app-support/app.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/recorder-core.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 13 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@

<script>
//兼容环境
var PageLM="2019-8-29 11:20:33";
var PageLM="2019-10-26 13:47:12";

function BuildHtml(html,o,notEncode,loop){return o||(o={}),html=(null==html?"":html+"").replace(/\{(fn:)?(:)?(.+?)\}/gi,function(a,b,c,code){try{var v=eval(b?code:"o."+code);return v=void 0===v?"":v+"",c||notEncode?v:v}catch(e){return console.log("BuildHtml Fail",a+"\n"+e.stack),""}}),loop&&/\{(fn:)?(.+?)\}/.test(html)&&(html=BuildHtml(html,o,notEncode,loop)),html};
function RandomKey(){
Expand Down Expand Up @@ -175,6 +175,12 @@
<audio class="recPlay" style="width:100%"></audio>
<div class="reclog"></div>

<hr>
<div class="pd">
<label><input type="checkbox" class="disableEnvInFixSet">禁用设备卡顿时音频输入丢失补偿功能(通过别的程序大量占用CPU来模拟设备卡顿)</label>
<div><a href="https://github.com/xiangyuecn/Recorder/issues/51">issues#51</a>如果没有进行补偿,录音时设备偶尔出现很卡的情况下(CPU被其他程序大量占用),浏览器采集到的音频是断断续续的,导致10秒的录音可能就只返回了5秒的数据量,这个时候最终编码得到的音频时长明显变短,播放时的效果就像快放一样。未禁用时会在卡顿时自动补偿静默音频,消除了快放效果,但由于丢失的音频已被静默数据代替,听起来就是数据本身的断断续续的效果。在设备不卡时录音没有此问题。</div>
</div>

<hr>
<div class="pd">
【测试App】
Expand Down Expand Up @@ -258,13 +264,19 @@

var wave,waveSet=$(".recwaveSet")[0].checked;

var disableEnvInFixSet=$(".disableEnvInFixSet")[0].checked;
if(disableEnvInFixSet){
reclog("已禁用设备卡顿时音频输入丢失补偿,可以通过别的程序大量占用CPU来模拟设备卡顿,然后录音听听未补偿时的播放效果,然后再试试不禁用的效果");
};

var realTimeSendSet=$(".realTimeSendSet")[0].checked;
var realTimeSendTime=+$(".realTimeSend").val();

rec=Recorder({
type:type
,bitRate:bit
,sampleRate:sample
,disableEnvInFix:disableEnvInFixSet
,onProcess:function(buffers,level,time,sampleRate){
$(".recpowerx").css("width",level+"%");
$(".recpowert").html(time+"/"+level);
Expand Down
2 changes: 1 addition & 1 deletion recorder.mp3.min.js

Large diffs are not rendered by default.

Loading

0 comments on commit cbd272b

Please sign in to comment.