Watson API Text-To-Speechの音声がSafariで再生できない件

  • 4
    いいね
  • 4
    コメント
この記事は最終更新日から1年以上が経過しています。

WebAudio で再生しようとするとAudioContext.decodeAudioDataに失敗する

どうやら、こちらにあるヘッダーの破損が原因の様子。
https://developer.ibm.com/answers/questions/180732/seems-watson-text-to-speech-service-returns-a-wav.html

node.jsでTextToSpeechのwavファイルを取得して, クライアントにレスポンスする処理の例

実際にwavデータを見てみると...

バイナリファイルの先頭から ArrayBuffer として出力してみる

{
"0": 82,   // R
"1": 73,   // I
"2": 70,   // F
"3": 70,   // F
"4": 255,  // (totalDataLen & 0xff);
"5": 255,  // ((totalDataLen >> 8) & 0xff);
"6": 255,  // ((totalDataLen >> 16) & 0xff);
"7": 255,  // ((totalDataLen >> 24) & 0xff);
"8": 87,   // W
"9": 65,   // A
"10": 86,  // V
"11": 69,  // E
"12": 102, // f
"13": 109, // m
"14": 116, // t
"15": 32,  // ' '
"16": 16,  // 4 bytes: size of 'fmt ' chunk
"17": 0,
"18": 0,
"19": 0,
"20": 1,   // format = 1
"21": 0,
"22": 1,   // channels
"23": 0,
"24": 34,  // sampleRate & 0xff
"25": 86,  // sampleRate >> 8) & 0xff
"26": 0,   // sampleRate >> 16) & 0xff
"27": 0,   // sampleRate >> 24) & 0xff
"28": 68,  // byteRate & 0xff
"29": 172, // byteRate >> 8 ) & 0xff
"30": 0,   // byteRate >> 16) & 0xff
"31": 0,   // byteRate >> 24) & 0xff
"32": 2,   // block align
"33": 0,   // 0
"34": 16,  // bits per sample
"35": 0,
"36": 76,  // L
"37": 73,  // I
"38": 83,  // S
"39": 84,  // T
"40": 26,  // totalAudioLen & 0xff = 16x2+6=38byte??
"41": 0,   // totalAudioLen >> 8 & 0xff
"42": 0,   // totalAudioLen >> 16 & 0xff
"43": 0    // totalAudioLen >> 24 & 0xff
}

長さ部分の表示が、、明らかに違う.. 全部255で埋まっている... (実際にデータは数KB)
36-39 は "data" が入る想定だが,実際には "LIST" と入っている.

結果的に以下のように, ヘッダーを入れ替える関数を用意して、処理する.

var buffer = getBufferWithFixedWavHeader(response);

/**
 * get ArrayBuffer by fixed header data
 * @param data binaryData
 * @return ArrayBuffer
 */
function getBufferWithFixedWavHeader(data){
    var headerSize = 44;
    var metaDataSize = 48;

    var noHeaderLen   = data.length - (headerSize + metaDataSize);
    var totalAudioLen = noHeaderLen;
    var totalDataLen  = noHeaderLen + headerSize - 8;

    var header = new ArrayBuffer(headerSize);
    for(var i = 0; i < headerSize; i++){
        header[i] = data[i];
    }

    // Total Data Length
    header[4] = (totalDataLen & 0xff);
    header[5] = ((totalDataLen >> 8) & 0xff);
    header[6] = ((totalDataLen >> 16) & 0xff);
    header[7] = ((totalDataLen >> 24) & 0xff);
    // data
    header[36] = 100; //'d'
    header[37] = 97;  //'a'
    header[38] = 116; //'t'
    header[39] = 97;  //'a'
    // Total Audio Length
    header[40] = (totalAudioLen & 0xff);
    header[41] = ((totalAudioLen >> 8) & 0xff);
    header[42] = ((totalAudioLen >> 16) & 0xff);
    header[43] = ((totalAudioLen >> 24) & 0xff);

    // join
    var buffer = new ArrayBuffer(headerSize + noHeaderLen);
    // header
    for(var i = 0; i < headerSize; i++){
        buffer[i] = header[i];
    }
    // data
    for(var i = headerSize,j = (headerSize+metaDataSize) ; j < data.length ; i++,j++){
        buffer[i] = data[j];
    }

    return buffer;
}