4

我無法在向我的服務器端API發出「AJAX」請求時播放音頻。如何播放使用HTML5 Audio API從XMLHTTPRequest返回的音頻

我已經後端目前正使用IBM的沃森文本到語音的服務,服務從文本音頻的Node.js代碼:

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中的字符串「test」在後端變成了一個文本參數,並且在synthesizeAndRender中的選項變量中結束。

+0

你確定支持音頻格式嗎? – Musa

+0

我相信它一定是。我最初通過一個url直接用相同的Chrome瀏覽器測試了相同的後端代碼,並且它可以很好地運行。 – exiquio

+0

實際上,測試是在Chromium和Gnu/Linux上完成的。我相信它應該與OSX中的Chrome相同,我現在正在編寫此代碼,但我不確定。 – exiquio

回答

9

不幸的是,與Chrome的HTML5音頻實現不同,Chrome的Web Audio doesn't support audio/ogg;codecs=opus,這是您的請求在此處使用的內容。您需要將格式設置爲audio/wav才能生效。爲了確保它傳遞給服務器請求,我建議將它放在查詢字符串(accept=audio/wav,urlencoded)中。

您只是想播放音頻,還是需要訪問Web Audio API進行音頻轉換?如果您只需要播放音頻,我可以向您演示如何使用HTML5 Audio API(不是Web Audio音頻API)輕鬆播放。使用HTML5音頻,您可以使用下面的技術流式傳輸,,您可以使用最佳的audio/ogg;codecs=opus格式。

就這麼簡單,動態地設置您的音頻元素的來源,通過一些從DOM查詢像這樣:

(在HTML)

<audio id="myAudioElement" /> 

(在你的JS)

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

您還可以通過XMLHttpRequest設置音頻元素的來源,但不會獲得流式傳輸。但是由於您可以使用POST方法,因此您不限於GET請求的文本長度(對於此API,大約6KB)。要設置在XHR,你從一個blob響應創建數據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,你必須等待,直到數據被滿載玩。有可能是一種使用非常新的媒體源擴展API從XMLHttpRequest進行流式處理,目前僅在Chrome和IE(不包括Firefox或Safari)中可用。這是我目前正在嘗試的一種方法。如果我成功了,我會在這裏更新。

+0

Eric用關於兼容性的聲明和Chromium問題的鏈接回答了我的問題,並詳細闡述了可能的解決方法,非常感謝。 – exiquio

+0

我從過去的2天掙扎。你可以請看這個http://stackoverflow.com/questions/32163749/ –

+0

AAC格式將在所有瀏覽器,BTW。你不限於使用WAV(這是巨大的)。 – ffxsam