代码之家  ›  专栏  ›  技术社区  ›  Muttley

如何在javascript中精确地对鼠标事件和音频录制事件进行时间对齐?[关闭]

  •  3
  • Muttley  · 技术社区  · 7 年前

    或者,更严格地说:我们如何估计时间偏移量(相对于 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>
    0 回复  |  直到 7 年前
    推荐文章