Amazon Pollyで合成したmp3をHTML5 audioコンポーネントで再生するまで


text -> Polly -> mp3 -> DynamoDB -> api response -> blob -> html5 audio
をやっていきたいと思います。
リアルタイムのAPIに音声合成を組み込む場合の実装例になります。

環境

  • AWS Lambda + Boto3
  • Vue.js

前提

S3にファイルを保存するのではなく、バイナリとしてDynamoDBに格納します。
合成音声が短い文章である場合、この方法は十分に有効です。

Pollyで音声を合成

lambdaからboto3で使っていきます。
リアルタイム変換を行いますが、200文字でもAPIに組み込めるレベルの応答時間(1,000ms程度)です。
ポイントはresponse['AudioStream']がStreamingBodyクラスになります。
https://botocore.amazonaws.com/v1/documentation/api/latest/reference/response.html

def text_to_speach(text):
    polly = boto3.client("polly")

    response = polly.synthesize_speech(
        Text=text,
        OutputFormat="mp3",
        VoiceId="Mizuki")

    return response["AudioStream"].read()

DynamoDBへの格納

Pollyで変換したmp3のバイナリデータをDynamoDBに格納すると、バイナリ型として格納されます。
これはBase64でエンコードされたバイナリデータになります。

BlobURLの作成

DynamoDBに格納されたデータを何らかのAPIを通じてクライアントで取得します。
この際まだ音声データはBase64でエンコードされたバイナリデータです。
これをBlob形式に変換するには、以下のようにします。
ポイントは
- base64をデコードしてUnit8Arrayを作る
- Unit8Arrayからaudio/mpegを指定してBlobを作る
- BlobからBlobURLを作る
となります。

private base64ToBlob(base64Data) {
    const byteCharacters = atob(base64Data)
    const byteNumbers = new Array(byteCharacters.length)
    for (let i = 0; i < byteCharacters.length; i++) {
      byteNumbers[i] = byteCharacters.charCodeAt(i)
    }
    const byteArray = new Uint8Array(byteNumbers)
    const blobUrl = URL.createObjectURL(
      new Blob([byteArray], {
        type: 'audio/mpeg',
      })
    )

    return blobUrl
  }

再生

あとはこのBlobURLをaudioコンポーネントのsrcに指定してください。(以下はVueの場合)
<audio v-bind:src="srcBlobUrl" autoplay />

まとめ

  • Pollyのリアルタイム音声合成はAPIに組み込めるくらい速い
  • DynamoDBにバイナリをBase64エンコードで格納することができる
  • Base64をオンメモリでBlobに変換してaudioコンポーネントに利用できる