Интеграция с другими технологиями

Web Audio API делает обработку и анализ звука фундаментальной частью веб‑платформы. Будучи ключевым строительным блоком для веб‑разработчиков, он спроектирован так, чтобы легко интегрироваться и работать совместно с другими технологиями.

Настраиваем фоновую музыку с помощью HTML-элемента <audio>

Как я упоминал в самом начале книги, у тега <audio> есть множество ограничений, из‑за которых он плохо подходит для игр и интерактивных приложений. Однако у него есть одно важное преимущество — встроенная поддержка буферизации и стриминга, что делает его идеальной технологией для воспроизведения длительных аудиотреков. Загрузка большого буфера медленна с точки зрения сети и затратна с точки зрения управления памятью. Поэтому использование <audio> идеально подходит для воспроизведения музыки или саундтрека в игре.

Вместо того, чтобы идти обычным путём — загружать звук напрямую через XMLHttpRequest и затем декодировать буфер — вы можете использовать узел источника медиапотока MediaElementAudioSourceNode. Он создаёт узлы, которые ведут себя почти так же, как узлы источников звука AudioSourceNode, но работают поверх существующего тега <audio>. Как только мы подключим этот узел к нашему аудиографу, можно применить все полученные ранее знания о Web Audio API для создания интересных эффектов. В этом небольшом примере к тегу <audio> применяется низкочастотный фильтр:

window.addEventListener('load', onLoad, false);

function onLoad() {
  var audio = new Audio();
  source = context.createMediaElementSource(audio);

  var filter = context.createBiquadFilter();
  filter.type = filter.LOWPASS;
  filter.frequency.value = 440;

  source.connect(this.filter);
  filter.connect(context.destination);

  audio.src = 'http://example.com/the.mp3';
  audio.play();
}

Захват звука в реальном времени

Одной из наиболее востребованных функций Web Audio API является интеграция с getUserMedia, которая даёт браузерам доступ к аудио‑ и видеопотокам подключённых микрофонов и камер. На момент написания этой книги эта функция была доступна в Chrome только при включении специального флага. Чтобы её активировать, нужно было открыть about:flags и включить эксперимент Web Audio Input, как на Рисунке 7-1.

Рисунок 7-1. Включение эксперимента Web Audio Input в Chrome
Рисунок 7-1. Включение эксперимента Web Audio Input в Chrome

После включения этой функции можно использовать узел Web Audio — MediaStreamSourceNode. Этот узел оборачивает объект аудиопотока, доступный после его инициализации. Это полностью аналогично тому, как узлы MediaElementSourceNode оборачивают элементы <audio>. В следующем примере мы визуализируем живой аудиопоток, обработанный режекторным фильтром (notch filter):

function getLiveInput() {
  // Запрашиваем только аудиопоток
  navigator.webkitGetUserMedia(
    { audio: true },
    onStream,
    onStreamError
  );
};

function onStream(stream) {
  // Оборачиваем MediaStreamSourceNode вокруг аудиопотока
  var input = context.createMediaStreamSource(stream);

  // Подключаем вход к фильтру
  var filter = context.createBiquadFilter();
  filter.frequency.value = 60.0;
  filter.type = filter.NOTCH;
  filter.Q = 10.0;

  var analyser = context.createAnalyser();

  // Подключаем граф
  input.connect(filter);
  filter.connect(analyser);

  // Настраиваем анимацию
  requestAnimationFrame(render);
};

function onStreamError(e) {
  console.error(e);
};

function render() {
  // Визуализируем аудиопоток
  requestAnimationFrame(render);
};  

Другой способ создания потоков основан на WebRTC PeerConnection. Подключив поток связи к Web Audio API, вы, например, сможете пространственно расположить несколько участников видеоконференции.

Управление аудио при переключении вкладок

Разрабатывая веб‑приложение, в котором есть воспроизведение звука, важно учитывать состояние страницы. Классический пример проблемы: когда один из множества открытых табов воспроизводит звук, но непонятно, какой именно. Для музыкального приложения это может быть допустимо, ведь музыка должна продолжать играть независимо от того, видна ли страница. Однако для игры чаще всего нужно приостанавливать игровой процесс (и воспроизведение звука), если страница перестаёт быть активной.

К счастью, API видимости страницы Page Visibility API предоставляет возможность определять, скрыта страница или видна. Состояние можно узнать через булево свойство document.hidden. Событие, которое срабатывает при изменении видимости, называется visibilitychange. Так как API до сих пор считается экспериментальным, все названия свойств и событий пишутся с префиксом webkit. С учётом этого, приведённый ниже код останавливает узел‑источник, когда страница скрывается, и возобновляет его работу, когда страница снова становится видимой:

// Слушаем событие изменения видимости страницы
document.addEventListener('webkitvisibilitychange', onVisibilityChange);

function onVisibilityChange() {
  if (document.webkitHidden) {
    source.stop(0);
  } else {
    source.start(0);
  }
}