或者,更严格地说:我们如何估计时间偏移量(相对于
performance.timing.navigationStart
)开始的时候
AudioContext/ScriptProcessor
我的webapp收集鼠标事件,同时从麦克风记录音频数据(使用
AudioContext
ScriptProcessor
).
event.timeStamp
财产(指
性能.计时.导航开始
see event.timeStamp in Chrome > 49
)两只老鼠的
onmousedown
事件和音频数据处理事件
onaudioprocess
. 开始录音的时间估计为
听觉过程
根据事件的时间戳触发事件。因为Chrome支持
baseLatency
see AudioContext.baseLatency
),我把它减去时间戳(或者应该加上它?我不确定)。下面的代码显示了
_startRecTime
我目前正在Chrome 69上进行测试(在Windows PC hexacore和ASUS quadcore的Android平板电脑上)。
感谢@kaido建议使用
事件而不是
onclick
有更好的估计方法吗
_星体
?
var myAudioPeakThreshold = 0.001;
var myInChannels = 2;
var myOutChannels = 2;
var myBitsPerSample = 16;
var mySampleRate = 48000;
var myBufferSize = 16384;
var myLatency = 0.01;
var _samplesCount = 0;
var _startRecTime = 0;
function debug(txt) {
document.getElementById("debug").innerHTML += txt + "\r\n";
}
function onMouse(e) {
var tClick = e.timeStamp/1000;
debug("onMouse: " + tClick.toFixed(6));
}
function myInit() {
// thanks to Kaiido for pointing out that in this
// context "onmousedown" is more effective than "onclick"
document.getElementById("clickMe").onmousedown = onMouse;
debug("INFO: initialising navigator.mediaDevices.getUserMedia");
navigator.mediaDevices.getUserMedia({
audio: {
channelCount: myInChannels,
latency: myLatency,
sampleRate: mySampleRate,
sampleSize: myBitsPerSample
},
video: false
})
.then(
function(stream) {
debug("INFO: navigator.mediaDevices.getUserMedia initialised");
var audioContext = new AudioContext;
var audioSource = audioContext.createMediaStreamSource(stream);
debug("INFO: baseLatency is: " + (audioSource.context.baseLatency ? audioSource.context.baseLatency.toFixed(3) : "unknown") + "s");
debug("INFO: sampleRate is: " + audioSource.context.sampleRate.toFixed(0) + "Hz");
this.node = audioSource.context.createScriptProcessor.call(
audioSource.context,
myBufferSize,
myInChannels,
myOutChannels);
// audio data processing callback
this.node.onaudioprocess = function(e) {
var samplesCount = e.inputBuffer.getChannelData(0).length;
// init timing
if(_samplesCount == 0) {
_startRecTime = e.timeStamp/1000 - samplesCount / audioSource.context.sampleRate;
if(typeof audioSource.context.baseLatency !== "undefined") {
_startRecTime -= audioSource.context.baseLatency;
}
}
// simple peak detection
var tPeak = 0, i = 0;
while(i < samplesCount) {
if(e.inputBuffer.getChannelData(0)[i] > myAudioPeakThreshold) {
tPeak = _startRecTime + (_samplesCount + i)/audioSource.context.sampleRate;
debug("onPeak : " + tPeak.toFixed(6));
break;
}
i++;
}
_samplesCount += samplesCount;
}
// connect the node between source and destination
audioSource.connect(this.node);
this.node.connect(audioSource.context.destination);
return;
})
.catch(
function(e) {
debug("ERROR: navigator.mediaDevices.getUserMedia failed");
return;
});
}
<body onload="myInit()">
<button id="clickMe" style="width: 500px; height: 500px">click me</button>
<pre id="debug"></pre>
</body>