首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >HtmlAudioElement音频时延

HtmlAudioElement音频时延
EN

Stack Overflow用户
提问于 2018-05-13 08:41:43
回答 1查看 376关注 0票数 0

HTMLAudioElement接口提供了对元素属性的访问。在每次请求时都会延迟从服务器获取声音。

一个基本的例子:

代码语言:javascript
复制
  var flush = new Audio('hello.wav');
 $(document).on('click', function() {
  flush.play();  
 });

Problem:有一个延迟(100ms+),因为每个请求(想象10+不同的声音)都需要从服务器下载声音,即使声音容量是30 KB。

问题:这个问题有解决办法吗?要么在DOM准备好时下载声音,要么使用另一种方法。这是主机/我的位置问题吗?主人是Heroku。

EN

回答 1

Stack Overflow用户

发布于 2018-05-13 10:32:15

您可以通过AJAX作为小泡预取所有文件,然后使用blobURI直接从内存中播放这些文件,这样可以消除提取时间,但是您仍然有解码时间。

代码语言:javascript
复制
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>

代码语言:javascript
复制
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音频API

代码语言:javascript
复制
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);
}
代码语言:javascript
复制
<!-- 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中也可以这样做。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50314313

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档