TwilioとGoogle Homeで構内放送システムを構築する

:::note alert
2023年5月1日を持ちまして、株式会社KDDIウェブコミュニケーションズのTwilioリセール事業が終了したため、本記事に記載されている内容は正確ではないことを予めご了承ください。
:::

# はじめに

構内放送システムってご存知でしょうか。病院や工場、オフィスなどでよく見かける、アナウンスを一斉配信できる、あのシステムです。
あまり知られていませんが、実は電話システムと連携して作られていることが多いのです。専門用語では、ページングシステムといいます。
PBX（電話交換機）にページング拡張装置をつけて、アンプを通してスピーカーに繋いでおき、電話機の特番を押して話をすると、スピーカーから音声が流れるしくみです。装置やスピーカーの設置、配線など、実は結構初期費用がかかるのですが、今回はこれをGoogle HomeとTwilioでサクッと作ってしまいたいと思います。

# 準備

## 必要なもの

- Google Home mini（Homeでもminiでも構いません）
- Node.js（7.x以上）とPython（2.x）が動作するPC
- Twilioのアカウント（トライアルアカウントでも動くと思います）

## 動作のしくみ

1. Twilioで購入した050番号に電話をかけます。
2. メッセージを吹き込んだら電話を切ります。
3. Google Homeと同じネットワークに設置したPC経由でメッセージが通知されます。
4. Google Homeでメッセージが再生されます。

# 構築

## 手順

1. PC上にgoogle-home-notifierをセットアップします。
2. google-home-notifierを起動します。
3. Twilio上で録音するしくみを作ります。
4. 録音したデータをWebhookするしくみを作ります。
5. 電話番号を購入して、録音できるようにします。
6. テストします。

## google-home-notifierのセットアップ

google-home-nogifierは、Google Homeに対して音声を再生したり、音楽（mp3）を再生したりすることができるアプリケーションです。Nodeのモジュールとしての提供の他、プロキシーサーバーとして動作するプログラムも提供しています。
プログラムはgithubで公開されており、MITライセンスに基づき利用できます（商用利用も可能です）。
今回はプロキシーを使って、PCを介してTwilioとGoogle Homeをつなごうと思います。
以下の作業はPC上で行います。Node.js（バージョン7以上）とPython（バージョン2.x系）がインストールされていることを確認しておいてください。

1. 適当なディレクトリに移動します。
2. 以下の手順でインストールをします。

```lang:sh
$ git clone https://github.com/noelportugal/google-home-notifier
$ cd google-home-notifier
$ npm install
```

## google-home-notifierの起動

インストールができたら、一部コードを変更します。そのためには、Google HomeのIPアドレスを事前に調べておく必要があります。
スマホのGoogle Homeアプリを起動して、でバイスの設定画面の一番下に書かれているIPアドレスを控えておきます。
![GoogleHomeIPアドレス.png](https://qiita-image-store.s3.amazonaws.com/0/86046/a305a0d0-8263-d73d-8007-e8093558e20f.png)

次に、移動したディレクトリの中のexample.jsというファイルを編集します。

```lang:example.js
var express = require('express');
var googlehome = require('./google-home-notifier');
var ngrok = require('ngrok');
var bodyParser = require('body-parser');
var app = express();
const serverPort = 8091; // default port

var deviceName = 'Google Home';
var ip = '192.168.1.20'; // default IP

var urlencodedParser = bodyParser.urlencoded({ extended: false });
```

9行目のipアドレス（192.168.1.20）を、先程調べたGoogle HomeのIPアドレスに変更して保存します。
では実行してみましょう。

```lang:sh
$ node example.js
Endpoints:
    http://192.168.1.20:8091/google-home-notifier
    https://xxxxx.ngrok.io/google-home-notifier
GET example:
curl -X GET https://xxxxx.ngrok.io/google-home-notifier?text=Hello+Google+Home  - to play given text
curl -X GET https://xxxxx.ngrok.io/google-home-notifier?text=http%3A%2F%2Fdomain%2Ffile.mp3 - to play from given url
POST example:
curl -X POST -d "text=Hello Google Home" https://xxxxx.ngrok.io/google-home-notifier - to play given text
curl -X POST -d "http://domain/file.mp3" https://xxxxx.ngrok.io/google-home-notifier - to play from given url
```
こんな感じで表示がされれば実行中です。Endopointsのところで表示されている、https://xxxxx.ngrok.io/google-home-notifier というURL（xxxxxのところには皆さん独自の文字列が表示されています）をメモ帳にコピーしておきます。このURLは起動する度に変わります。
ちなみに終了するにはCtrl-Cを押します。

## 録音部分のコーディング

再生する側の準備が整ったので、今度は入力側を作っていきます。
1. Twilioの管理コンソールにログインして、Runtime→Functionsを選択します。
2. 新しいFunctionを作成します。テンプレートはBlankを選択します。
3. FUNCTION NAMEに、「Record」、PATHには、「/record」と入力します。
4. ACCESS CONTROLにチェックを入れます。
5. EVENTは「Incoming Voice Calls」を選びます。
6. CODE欄は、以下のコードで上書きします。

```lang:Record
exports.handler = function(context, event, callback) {
  let twiml = new Twilio.twiml.VoiceResponse();
  let voiceParams = {}
  voiceParams.language = 'ja-JP'
  voiceParams.voice = 'alice'
  twiml.say(voiceParams, "Google Homeで再生したいメッセージを吹き込んでください。")
  twiml.record({
    recordingStatusCallback: 'https://'+context.DOMAIN_NAME+'/recorded'
  })
  callback(null, twiml);
};
```
最後に「SAVE」ボタンを押して、変更を保存します。

## 録音データをWebhookする部分のコーディング

次に、録音が終わったときの処理を作っていきます。
1. もう一つ、新しいFunctionを作成します。テンプレートはBlankを選択します。
2. FUNCTION NAMEに、「Recorded」、PATHには、「/recorded」と入力します。
3. ACCESS CONTROLにチェックを入れます。
4. EVENTは「Select...」のままにしておきます。
5. CODE欄は、以下のコードで上書きします。

```lang:Recorded
exports.handler = function(context, event, callback) {
  const got = require('got')
  const url = 'https://XXXXXXX.ngrok.io/google-home-notifier'
  const options = {
    json: true,
    body: {text: event.RecordingUrl}
  }
  got.post(url, options)
  .then(res => {
    console.log(res.body)
    callback(null, 'OK')
  })
  .catch(error => {
    console.log(error)
    callback(error)
  })
};
```
3行目のhttps://xxxxxx.ngrok.io/google-hone-notifier の部分を、先程控えておいたexamples.jsを実行した時に表示されたURLに書き換えてください。
最後に「SAVE」ボタンを押して、変更を保存します。

## 電話番号の購入と設定

次に、Twilioで着信させるための電話番号の購入と、設定を行います。
1. Twilioの管理コンソールの「Phone numbers」（電話番号）を選択します。
2. 「番号を購入」を選択します。
3. 国のリストから、「Japan（+81）」を選択し、「検索」ボタンを押します。
4. 購入可能な番号が一覧表示されたら、TYPEが「ローカル」のいずれかの番号の「購入」ボタンを押します。
5. 購入しますか？のダイアログが表示されたら、「この番号を購入する」ボタンを押します。
6. Congratulationsダイアログが表示されたら、「番号を設定する」ボタンを押します。
7. Voice & Faxセクションの中のA CALL COMES INのプルダウンから「Function」を選択し、さらに先程作成した「Record」を選択します。
<img width="986" alt="スクリーンショット 2018-01-11 11.48.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/86046/55cd4b91-529b-8ea0-3eb2-9b7dce179a4d.png">

「保存」ボタンを押して設定を完了します。

## テスト

以上でセットアップはすべて完了です。
PC側でプログラムが起動中であることを確認して、050番号に電話をかけてみます。
電話がかかるとメッセージが流れるので、発信音の後にメッセージを吹き込みます。
メッセージが終了したら電話を切ります（切らないと続けてメッセージを入れられます）。
Google Home側からメッセージが再生されれば成功です。

# まとめ

今回はPCを介してGoogle Homeにデータを送りましたが、PCの代わりにRaspberry Piを使う方法もあります。
詳しくはgoogle-home-notifierのGitHubに記載がありますので参考にしてみてください。

また、音声ファイルだけでなく、文字を日本語で再生させることもできるようなので、色々と試してみると面白いかと思います。