Как воспроизвести звук, возвращенный из XMLHTTPRequest, с помощью HTML5 Audio API

Я не могу воспроизводить звук при отправке запроса «AJAX» к моему API на стороне сервера.

У меня есть серверный код Node.js, который использует службу IBM Watson Text-to-Speech для передачи звука из текста:

var render = function(request, response) {
    var options = {
        text: request.params.text,
        voice: 'VoiceEnUsMichael',
        accept: 'audio/ogg; codecs=opus'
    };

    synthesizeAndRender(options, request, response);
};

var synthesizeAndRender = function(options, request, response) {
    var synthesizedSpeech = textToSpeech.synthesize(options);

    synthesizedSpeech.on('response', function(eventResponse) {
        if(request.params.text.download) {
            var contentDisposition = 'attachment; filename=transcript.ogg';

            eventResponse.headers['content-disposition'] = contentDisposition;
        }
    });

    synthesizedSpeech.pipe(response);
};

У меня есть код на стороне клиента, чтобы справиться с этим:

var xhr = new XMLHttpRequest(),
    audioContext = new AudioContext(),
    source = audioContext.createBufferSource();

module.controllers.TextToSpeechController = {
    fetch: function() {
        xhr.onload = function() {
            var playAudio = function(buffer) {
                source.buffer = buffer;
                source.connect(audioContext.destination);

                source.start(0);
            };

            // TODO: Handle properly (exiquio)
            // NOTE: error is being received
            var handleError = function(error) {
                console.log('An audio decoding error occurred');
            }

            audioContext
                .decodeAudioData(xhr.response, playAudio, handleError);
        };
        xhr.onerror = function() { console.log('An error occurred'); };

        var urlBase = 'http://localhost:3001/api/v1/text_to_speech/';
        var url = [
            urlBase,
            'test',
        ].join('');

        xhr.open('GET', encodeURI(url), true);
        xhr.setRequestHeader('x-access-token', Application.token);
        xhr.responseType = 'arraybuffer';
        xhr.send();
    }
}

Серверная часть возвращает ожидаемый звук, но мой метод успеха playAudio никогда не вызывается. Вместо этого всегда вызывается handleError, а объект ошибки всегда равен нулю.

Может ли кто-нибудь объяснить, что я делаю неправильно и как это исправить? Мы будем очень признательны.

Спасибо.

ПРИМЕЧАНИЕ. Строка «тест» в URL-адресе становится текстовым параметром на бэкэнде и заканчивается в переменной параметров в SyntheAndRender.


person exiquio    schedule 19.05.2015    source источник
comment
Вы уверены, что формат аудио поддерживается?   -  person Musa    schedule 19.05.2015
comment
Я считаю, что это должно быть. Первоначально я тестировал один и тот же внутренний код напрямую с тем же браузером Chrome через URL-адрес, и он работал нормально.   -  person exiquio    schedule 19.05.2015
comment
На самом деле тест проводился на Chromium и Gnu/Linux. Я считаю, что это должно быть то же самое с Chrome в OSX, где я сейчас пишу этот код, но я не уверен.   -  person exiquio    schedule 19.05.2015
comment
ОБНОВЛЕНИЕ: я выполнил следующий запрос в том же браузере, который использую для разработки этого кода: localhost:3001/api/v1/text_to_speech/this%20is%20a%20test ‹ -- Это было сделано с закомментированным кодом аутентификации, и он отобразил встроенный аудиоплеер и воспроизвел ожидаемое аудио. Теперь могу с уверенностью сказать, что аудиотип принят. Мое единственное предположение о моей проблеме - это то, как я делаю заголовки на стороне сервера выше. Часть приложения кажется мне потенциально проблемой.   -  person exiquio    schedule 20.05.2015


Ответы (1)


К сожалению, в отличие от реализации Chrome HTML5 Audio, Chrome Web Audio не поддерживает аудио/ ogg;codecs=opus, который используется здесь в вашем запросе. Вам нужно установить формат audio/wav, чтобы это работало. Чтобы убедиться, что он передан серверному запросу, я предлагаю поместить его в строку запроса (accept=audio/wav, urlencoded).

Вы просто хотите воспроизвести звук или вам нужен доступ к API веб-аудио для преобразования звука? Если вам просто нужно воспроизвести аудио, я могу показать вам, как легко воспроизвести его с помощью HTML5 Audio API (а не веб-аудио). А с помощью HTML5 Audio вы можете транслировать его, используя описанную ниже технику, и вы можете использовать оптимальный формат audio/ogg;codecs=opus.

Это так же просто, как динамическая установка источника вашего аудиоэлемента, запрашиваемого из DOM с помощью чего-то вроде этого:

(в HTML)

<audio id="myAudioElement" />

(в вашем JS)

var audio = document.getElementById('myAudioElement') || new Audio();
audio.src = yourUrl;

Вы также можете установить источник аудиоэлемента через XMLHttpRequest, но вы не получите потоковую передачу. Но поскольку вы можете использовать метод POST, вы не ограничены длиной текста запроса GET (для этого API ~ 6 КБ). Чтобы установить его в xhr, вы создаете uri данных из ответа большого двоичного объекта:

    xhr.open('POST', encodeURI(url), true);
    xhr.setRequestHeader('Content-Type', 'application/json');
    xhr.responseType = 'blob';
    xhr.onload = function(evt) {
      var blob = new Blob([xhr.response], {type: 'audio/ogg'});
      var objectUrl = URL.createObjectURL(blob);
      audio.src = objectUrl;
      // Release resource when it's loaded
      audio.onload = function(evt) {
        URL.revokeObjectURL(objectUrl);
      };
      audio.play();
    };
    var data = JSON.stringify({text: yourTextToSynthesize});
    xhr.send(data);

Как видите, с XMLHttpRequest для воспроизведения необходимо дождаться полной загрузки данных. Возможно существует способ потоковой передачи из XMLHttpRequest с использованием совершенно нового API расширений источника мультимедиа, который в настоящее время доступен только в Chrome и IE (не в Firefox или Safari). Это подход, с которым я сейчас экспериментирую. Я обновлю здесь, если у меня все получится.

person Eric S. Bullington    schedule 25.05.2015
comment
Эрик ответил на мой вопрос заявлением о совместимости и ссылкой на проблему с Chromium, а также подробно рассказал о возможном обходном пути, который я очень ценю. - person exiquio; 27.05.2015
comment
Я борюсь за последние 2 дня. Не могли бы вы посмотреть на этот stackoverflow.com/questions/32163749 - person Dan; 23.08.2015
comment
Кстати, формат AAC будет работать во всех браузерах. Вы не ограничены использованием WAV (который огромен). - person ffxsam; 01.07.2016