2

Goal: To synthesize speech via AWS Polly PHP SDK (not javascript), return audio blob to browser via AJAX request, and stream with HTML5 audio player.

So far I have the query to AWS working and AJAX request returning the AudioStream resource to the browser, but Firefox is complaining about the format:

Media resource could not be decoded, error: Error Code: NS_ERROR_DOM_MEDIA_METADATA_ERR (0x806e0006)

I'm not very familiar with Chrome debugging, but it does not work there either.

Below is my code, simplified for brevity.

HTML:

<audio id="audioplayer" controls preload="none">
<source id="audiosource" src="" type="audio/mpeg">
</audio>

AJAX:

var xhr = new XMLHttpRequest();
var url = 'polly_ajax.php';
var params = 'voice=' + $voice + '&pollytext=' + $pollytext;
xhr.open('POST', url, true);
xhr.responseType = 'blob';
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.onload = function(oEvent){
    var audioblob = new Blob([xhr.response], {type: 'audio/mpeg'});
    var objectURL = URL.createObjectURL(audioblob);
    $('#audiosource').attr('src',objectURL);
    $('#audioplayer').trigger('load');
    $('#audioplayer').trigger('play');
}
xhr.send();

PHP:

$pollyClient = new PollyClient();

$polly_result = $pollyClient->synthesizeSpeech([
    'OutputFormat' => 'mp3'
    , 'Text' => $_POST['pollytext']
    , 'VoiceId' => $_POST['voice']
]);

echo $polly_result['AudioStream']->getContents();

I have two ideas of what to do next, but not sure which to follow:

  1. Use a different javascript object type, instead of File() (e.g. Blob(), MediaStream(), etc.)
  2. Return the AudioStream data in a different format, instead of simply doing echo getContents

Here's the Amazon Polly PHP SDK docs, if anyone is interested: http://docs.aws.amazon.com/aws-sdk-php/v3/api/api-polly-2016-06-10.html

NOTE: I realize using async: false is not recommended. I am planning to use a proper callback once I get the audio playing.

Thank you for reading and I appreciate any help!

EDIT #1: found link showing that jQuery AJAX can only return string responses, not blobs. Updated AJAX block to show new code using XMLHttpRequest and updated error being returned from FireFox

Old jQuery AJAX code:

$.ajax({
    type: 'POST',
    async: false,
    url: 'polly_ajax.php',
    data: {
        'pollytext': $pollytext,
        'voice': $voice
    },
    success: function(response) {
        var audioblob = new File([response], {type: 'audio/mpeg'});
        var objectURL = URL.createObjectURL(audioblob);
        $('#audiosource').attr('src',objectURL);
        $('#audioplayer').trigger('load');
        $('#audioplayer').trigger('play');
    }
});

Old Firefox error:

HTTP “Content-Type” of “application/octet-stream” is not supported. Load of media resource blob:https://domain.tld/dc7619e0-ff93-4438-899b-84d641436bc8 failed.

  • I thinks that the problem is in the MIME and because of the `echo ...`. The best thing to do is to save the output of the API into an mp3 file and then get it served by a web server like Apache or NGINX. – kopiro Dec 29 '17 at 19:51
  • @kopiro I could go that route, but I was hoping to not deal with server-side cache cleanup. Do you know of anyway to save a file to disk, serve to browser, then automatically delete? – Hayden Seitz Dec 30 '17 at 01:10
  • Try by setting these headers before the echo. https://stackoverflow.com/questions/3697748/fastest-way-to-serve-a-file-using-php – kopiro Jan 02 '18 at 09:03
  • Okay so I found that jQuery ajax calls can only return responses as strings, not blobs: http://tech.chitgoks.com/2015/09/12/download-mp3-stream-via-ajax-then-load-to-html5-audio/ I've updated the original post to show my new code using XMLHttpRequest, but am still getting a similar error of `could not be decoded, error: Error Code: NS_ERROR_DOM_MEDIA_METADATA_ERR (0x806e0006)` – Hayden Seitz Jan 03 '18 at 17:30

1 Answers1

0

Found the issue. The PHP page that was being requested via AJAX was returning errors after switching from jQuery AJAX to XMLHttpRequest. Once I resolved that issue, I was able to play from the blob just fine with the above AJAX code block.

Thank you @kopiro for the help!