Звук воспроизводится в Chrome, но не в Safari - PullRequest
0 голосов
/ 01 октября 2018

У меня есть угловое приложение, в котором я установил обработчик click кнопки, чтобы загрузить аудиофайл и воспроизвести его.Я использую этот код для этого:

onPreviewPressed(media: Media): void {
    const url = ".....";

    this.httpClient.get(url, {responseType: 'blob'}).subscribe(x => {
        const fileReader = new FileReader();

        fileReader.onloadend = () => {
            const context = new ((<any>window).AudioContext || (<any>window).webkitAudioContext)();
            const source = context.createBufferSource();

            context.decodeAudioData(fileReader.result, buffer => {
                source.buffer = buffer;
                source.connect(context.destination);
                source.start(0);
            }, y => {
                console.info("Error: " + y);
            });
        };

        fileReader.readAsArrayBuffer(x);
    });
}

Если я перехожу на страницу в Chrome и нажимаю кнопку, звук начинается прямо вверх.Если я делаю это в Safari, то ничего не происходит.Я знаю, что Safari заблокировал все, но это происходит в ответ на нажатие кнопки, это не автоматическое воспроизведение.

Звук отправляется обратно с сервера через скрипт PHP, и он отправляет заголовки, как это, весли это имеет значение:

header("Content-Type: audio/mpeg");
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($_GET['file']));
header('Cache-Control: no-cache');

1 Ответ

0 голосов
/ 01 октября 2018

Нет, это не « в ответ на нажатие кнопки ».
В ответ на это событие щелчка вы запускаете асинхронную задачу.К тому времени, когда вы звоните source.start(0), ваше событие уже давно умерло (или, по крайней мере, больше не является "жестом доверенного пользователя". Поэтому они действительно заблокируют этот вызов.

Чтобы обойти это, вы можете просто пометитьконтекст разрешен с тишиной. Затем, когда данные будут доступны, вы сможете запустить их без ограничений:

function markContextAsAllowed(context) {
  const gain = context.createGain();
  gain.gain.value = 0; // silence
  const osc = context.createOscillator();
  osc.connect(gain);
  gain.connect(context.destination);
  osc.onended = e => gain.disconnect();
  osc.start(0);
  osc.stop(0.01);
}


onPreviewPressed(media: Media): void {
  const url = ".....";
  // declare in the event handler
  const context = new(window.AudioContext || window.webkitAudioContext)();
  const source = context.createBufferSource();
  // allow context synchronously
  markContextAsAllowed(context);


  this.httpClient.get(url, {
    responseType: 'blob'
  }).subscribe(x => {
    const fileReader = new FileReader();

    fileReader.onloadend = () => {
      context.decodeAudioData(fileReader.result, buffer => {
        source.buffer = buffer;
        source.connect(context.destination);
        source.start(0);
      }, y => {
        console.info("Error: " + y);
      });
    };

    fileReader.readAsArrayBuffer(x);
  });
}

Как скрипка, так как Safari не любит чрезмернуюЗащищенный StackSnippets®

Кроме того, мои угловые знания очень ограничены, но если httpClient.get поддерживает опцию {responseType: 'arraybuffer'}, вы можете избавиться от этого FileReader и избежать двойного заполнения памяти одними и теми же данными..

Наконец, если вы собираетесь воспроизводить этот звук более одного раза, рассмотрите возможность его предварительной выборки и предварительного декодирования, тогда вы сможете избежать всего асинхронного беспорядка.

...