javascript - HtmlAudioElement 音频时间延迟

标签 javascript html html5-audio

HTMLAudioElement接口(interface)提供对元素属性的访问。每次请求从服务器获取声音都有延迟。
一个基本的例子:

  var flush = new Audio('hello.wav');
 $(document).on('click', function() {
  flush.play();  
 });
        
问题 :有一个延迟(100ms+),因为每次请求(想象 10+ 种不同的声音)都需要从服务器下载声音,即使声音的容量为 30 KB。
问题 : 这个问题有解决办法吗?要么在 DOM 准备好时下载声音,要么为此使用其他方式。这是主机/我的位置问题吗?主机是 Heroku。

最佳答案

您可以通过 AJAX 将所有文件预取为 Blobs然后使用 blobURI 直接从内存中播放它们,摆脱了获取时间,但你仍然有解码时间。

const db_url = 'https://dl.dropboxusercontent.com/s/';
const urls = ['1cdwpm3gca9mlo0/kick.mp3', 'h2j6vm17r07jf03/snare.mp3', 'kbgd2jm7ezk3u3x/hihat.mp3', 'h8pvqqol3ovyle8/tom.mp3'];

preload(urls)
  .then(blobURis => {
    blobURis.forEach((uri, i) => {
      const btn = document.createElement('button');
      btn.onclick = e => new Audio(uri).play();
      btn.textContent = urls[i].split('/')[1].split('.')[0];
      document.body.appendChild(btn);
    });
  });

function preload(urls) {
  const requests = urls.map(url => fetch(db_url + url)
      .then(r => r.blob()) // request as Blob
      .then(b => URL.createObjectURL(b)) // get a blobURI to access from memory
  );
  return Promise.all(requests);
}


因此,您还可以预解码您的文件并始终使用相同的 <audio>每次对每个文件。

const db_url = 'https://dl.dropboxusercontent.com/s/';
const urls = ['1cdwpm3gca9mlo0/kick.mp3', 'h2j6vm17r07jf03/snare.mp3', 'kbgd2jm7ezk3u3x/hihat.mp3', 'h8pvqqol3ovyle8/tom.mp3'];

preload(urls)
  .then(blobURis => {
    blobURis.forEach((uri, i) => {
      const audio = new Audio(uri);
      audio.autoplay = false;
      const btn = document.createElement('button');
      btn.onclick = e => {
        audio.currentTime = 0;
        audio.play(); 
      }
      btn.textContent = urls[i].split('/')[1].split('.')[0];
      document.body.appendChild(btn);
    });
  });

function preload(urls) {
  const requests = urls.map(url => fetch(db_url + url)
      .then(r => r.blob())
      .then(b => URL.createObjectURL(b))
  );
  return Promise.all(requests);
}


但是您仍然不能完全确定它会在您要求时启动。

因此,绝对没有延迟的最好方法是使用 Web Audio API .

const db_url = 'https://dl.dropboxusercontent.com/s/';
const urls = ['1cdwpm3gca9mlo0/kick.mp3', 'h2j6vm17r07jf03/snare.mp3', 'kbgd2jm7ezk3u3x/hihat.mp3', 'h8pvqqol3ovyle8/tom.mp3'];
const a_ctx = new (window.AudioContext || window.webkitAudioContext)();

preload(urls)
  .then(audioBuffers => {
    audioBuffers.forEach((buf, i) => {
      const btn = document.createElement('button');
      btn.onclick = e => {
        const source = a_ctx.createBufferSource();
        source.buffer = buf;
        source.connect(a_ctx.destination);
        source.start(0);
      };
      btn.textContent = urls[i].split('/')[1].split('.')[0];
      document.body.appendChild(btn);
    });
  });

function preload(urls) {
  const requests = urls.map(url => fetch(db_url + url)
    .then(r => r.arrayBuffer()) // this time we request as ArrayBuffer
    .then(b => a_ctx.decodeAudioData(b))
  );
  return Promise.all(requests);
}
<!-- Promising decodeAudioData for Safari https://github.com/mohayonao/promise-decode-audio-data/ [MIT] -->
<script src="https://cdn.rawgit.com/mohayonao/promise-decode-audio-data/eb4b1322/build/promise-decode-audio-data.min.js"></script>


Ps:所有示例都在 ES6 中,并使用 fetch API 以便于阅读,但在 ES5 和 XMLHttpRequest 中可以完成完全相同的操作.

关于javascript - HtmlAudioElement 音频时间延迟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50314313/

相关文章:

javascript - javascript 中的内部 html 不工作

javascript - 在按键时验证小数点前后的数字

javascript - 如何在 Three.js 中从 OBJ 模型正确渲染四线框?

javascript - 使外部脚本可供 qooxdoo 对象的所有成员使用

php - 在 PHP 中删除换行符并添加 BR 标记

javascript - Bootstrap 模式内的音频标签工作正常,但下载按钮位置超出模式

javascript - 无法为我的排序方法创建下拉按钮

css - 将 div 样式化为具有 2 个具有动态宽度的列

html - CSS - 自动 div 高度?

node.js - Electron 无法在 Raspberry Pi 3b+ 中使用 <audio> Html5 标签播放 mp3 音频文件