HtmlAudioElement аудио задержка - PullRequest
0 голосов
/ 13 мая 2018

Интерфейс HTMLAudioElement обеспечивает доступ к свойствам элементов.При каждом запросе задерживается получение звука с сервера.

Базовый пример:

  var flush = new Audio('hello.wav');
 $(document).on('click', function() {
  flush.play();  
 });

Проблема : задержка (100 мс +), посколькупри каждом запросе (представьте более 10 различных звуков) звук необходимо загружать с сервера, даже если его объем составляет 30 КБ.

Вопрос : есть ли решение этой проблемы??либо загружайте звуки, когда DOM готов, либо используйте для этого альтернативный способ.Это проблема хоста / моего местоположения?Принимающая сторона - Heroku.

1 Ответ

0 голосов
/ 13 мая 2018

Вы можете предварительно выбрать все ваши файлы через 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 и используют API fetch для удобства чтения, но в ES5 можно сделать то же самоеи с XMLHttpRequest .

...