AWS Lambdaで音声合成(OpenJTalk)＆エンコード(ffmpeg)

探求室の@junya108です。
[HameeAdventCalendar2016](http://qiita.com/advent-calendar/2016/hamee)の21日目です。
AmazonDashButtonを買ったのでボタンを押したら電気、エアコン、テレビetc.が全部つくボタンの記事にしようと思ってたけど、変更。
先日、リリースされた[Amazon Polly](https://aws.amazon.com/jp/polly/?nc2=h_a1)を試して感じた問題点を解決してみたいと思います。
#Amazon Pollyの問題点
喋りも滑らかで日本語にも対応している点は非常に良いのですが、声色がイマイチ。
#解決策
lambda上で音声合成やエンコードをやって声色の自由度を増やしてみようと思います。
#やることのまとめ
今回は音声合成にはopenjtalk、エンコードにはffmpegを利用します。
これをamazon linuxでコンパイルしてlambdaにアップロードしてテスト実行。という感じです。
#音声合成
macを新調したばかりでdockerが入ってなかったので、まずは、[docker for mac](https://docs.docker.com/docker-for-mac/)をインストール。

amazonlinuxのイメージをpullしてrun。
[lambdaの実行環境](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/current-supported-versions.html)よりもdockerイメージが新しいけど大丈夫かな。

```bash
$ docker pull amazonlinux:2016.09
$ docker run -i -t amazonlinux:2016.09 /bin/bash
```


パッケージをupdateして、必要なライブラリをinstall。

```bash
bash-4.2# yum update -y
bash-4.2# yum install gcc44 gcc-c++ libgcc44 cmake wget git aws-cli autoconf automake libtool npm epel-release yasm -y
```

hts_engine_APIをコンパイル＆インストール

```bash
bash-4.2# cd /tmp
bash-4.2# wget http://downloads.sourceforge.net/hts-engine/hts_engine_API-1.08.tar.gz
bash-4.2# tar zxvf hts_engine_API-1.08.tar.gz
bash-4.2# cd hts_engine_API-1.08
bash-4.2# ./configure
bash-4.2# make
bash-4.2# make install
```

OpenJTalkをコンパイル＆インストール

```bash
bash-4.2# wget http://downloads.sourceforge.net/open-jtalk/open_jtalk-1.07.tar.gz
bash-4.2# tar zxvf open_jtalk-1.07.tar.gz
bash-4.2# cd open_jtalk-1.07
bash-4.2# ./configure --with-charset=UTF-8
bash-4.2# make
bash-4.2# make install
```

#エンコード
必要なコーデックをinstall 

```bash
bash-4.2# mkdir /usr/local/src/ffmpeg_sources
bash-4.2# cd /usr/local/src/ffmpeg_sources
bash-4.2# git clone --depth 1 git://git.code.sf.net/p/opencore-amr/fdk-aac
bash-4.2# cd fdk-aac
bash-4.2# autoreconf -fiv
bash-4.2# ./configure --prefix="/usr/local/src/ffmpeg_build" --disable-shared
bash-4.2# make
bash-4.2# make install
```

ffmpegをコンパイル＆インストール

```bash
bash-4.2# cd /usr/local/src/ffmpeg_sources
bash-4.2# git clone --depth 1 git://source.ffmpeg.org/ffmpeg
bash-4.2# cd ffmpeg
bash-4.2# PKG_CONFIG_PATH="/usr/local/src/ffmpeg_build/lib/pkgconfig" ./configure --enable-static --disable-shared --prefix="/usr/local/src/ffmpeg_build" --extra-cflags="-I/usr/local/src/ffmpeg_build/include" --extra-ldflags="-L/usr/local/src/ffmpeg_build/lib" --bindir="/usr/local/src/bin" --enable-gpl --enable-nonfree --enable-libfdk_aac
bash-4.2# make
bash-4.2# make install
```

#lambdaで動かしてみる
テストでテキストを音声変換して、aacにエンコードしてS３に保存して見る。

```js:exports.js
var AWS = require('aws-sdk');
var s3 = new AWS.S3({apiVersion: '2006-03-01'});
var https = require('https');
var fs = require('fs');
var OpenJTalk = require('openjtalk');

exports.myHandler = function(event, context, callback) {

  var voice = new OpenJTalk({htsvoice: './node_modules/openjtalk/voice/mei/mei_happy.htsvoice'});

  voice._makeWav('未来はいつも面白い。',0,function(err,result){

    var cmd = './ffmpeg -i "' + '/tmp/'+result.wav + '" -vn -ac 2 -ar 44100 -ab 128k -acodec libfdk_aac -f mp4 "'+ '/tmp/'+result.wav +'.m4a"';
    var exec = require('child_process').exec;
    var child = exec(cmd, function(error, stdout, stderr) {

      var audioFileName=result.wav + '.m4a';
      var s3Params = {
        ACL: 'public-read',
        Bucket: {BUCKET_NAME},
        Key: audioFileName,
        Body: new Buffer(fs.readFileSync('/tmp/'+audioFileName))
      };

      s3.putObject(s3Params, function(err, data) {
        callback(null, 'Success!');
      };

    });

  });
    
};
```

これと、node_modulesとコンパイルしたopenjtalk,ffmpegをzipでまとめる。
ここで問題発生。。ファイルサイズが60M超。。
lambdaの[制限](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/limits.html)によると、lambdaで動かせるのはzipのサイズは50Mまで。
削減できそうなファイルを整理してもまだ50M超えてる。。
とりあえず、制限超えてるけど、S３にアップロードしてlambdaに登録して見る。
なんと！
怒られない、登録できちゃう。
テストしてみてちゃんとS３にファイルが作成されることを確認。

<img width="1948" alt="スクリーンショット 2016-12-21 7.54.33.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/71312/c5c69e42-ef2e-d4dd-42c0-1b0f711bf8fc.jpeg">

#まとめ
- ちゃんと動いた。
- メモリが128Mのlambda環境で50文字（150byte）を変換して音声合成で5000msec,エンコードで1200msecぐらい。
- 計算上はAmazon Pollyよりも安い。
- zipサイズが50M超えてもアップロード出来ちゃう。