Twilioで録音された録音データを、S3に自動でアップロードして削除する

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

# はじめに

みなさん、こんにちは。
KDDIウェブコミュニケーションズの Twilio事業部エバンジェリストの高橋です。

今回は、Twilio 上で録音された録音データを自動的に S3 にアップロードし、アップロードが完了すると該当する録音データを自動的に Twilio 上から削除する方法をご紹介します。

## 準備

事前に以下の準備をしておいてください。

- Twilio CLI のインストール（[こちらの記事](https://qiita.com/mobilebiz/items/456ce8b455f6aa84cc1e)を参考にしてください）
- Twilio CLI サーバーレスプラグインのインストール（[こちらの記事](https://qiita.com/mobilebiz/items/fb4439bf162098e345ae)を参考にしてください）
- S3 にバケットを作成（バケット名を控えておいてください）
- S3 にアップロードする権限をもった、AWS のアクセスキーとシークレットアクセスキー

## ソースコードの準備

今回のプログラムは、すでに GitHub 上に公開されていますので、そちらを使って作業をしていきましょう。

- 適当な作業ディレクトリに移動します。
- 以下のコマンドでプログラムを取得します。

```sh
git clone https://github.com/twilioforkwc/twilio-voice-recording-to-s3.git
```

- 設定情報を設定しますので、以下のコマンドをつかって設定情報のサンプルをコピーします。

```sh
cd twilio-voice-recording-to-s3
cp .env.sample .env
```

- コピーした`.env`をエディタで開き、以下の内容で更新します。

| 項目名                | 内容                                                   |
| :-------------------- | :----------------------------------------------------- |
| ACCOUNT_SID           | Twilio のアカウント SID（AC から始まる文字列）         |
| AUTH_TOKEN            | 同じく Auth Token                                      |
| AWS_ACCESS_KEY        | AWS のアクセスキー                                     |
| AWS_SECRET_ACCESS_KEY | 同じくシークレットアクセスキー                         |
| AWS_REGION            | AWS のリージョン（デフォルトは東京リージョン）         |
| AWS_S3_BUCKET         | 録音データを保管するバケット名                         |
| AWS_S3_PREFIX         | 録音データのプレフィックス（デフォルトは`Recordings`） |

### 解説

今回作成したコード（`export-s3.js`）をご紹介します。

```javascript
const axios = require("axios");
const AWS = require("aws-sdk");
const S3UploadStream = require("s3-upload-stream");

const transfer_recording = async (context, download_url, upload_stream) => {
  const res = await axios({
    method: "GET",
    url: download_url,
    responseType: "stream",
    auth: {
      username: context.ACCOUNT_SID,
      password: context.AUTH_TOKEN,
    },
  });
  res.data.pipe(upload_stream);
  return new Promise((resolve, reject) => {
    upload_stream.on("uploaded", resolve);
    upload_stream.on("error", (error) => reject(error));
  });
};

exports.handler = async function (context, event, callback) {
  try {
    if (event.RecordingStatus !== "completed") {
      throw new Error("Not completed.");
    }

    const download_url = `${event.RecordingUrl}.mp3`;
    const upload_path = `${context.AWS_S3_PREFIX}/${event.CallSid}_${event.RecordingSid}.mp3`;

    // Initialize AWS configure
    AWS.config.update({
      region: context.AWS_REGION,
      credentials: new AWS.Credentials(
        context.AWS_ACCESS_KEY,
        context.AWS_SECRET_ACCESS_KEY
      ),
    });

    let s3Stream = S3UploadStream(new AWS.S3());

    let upload_stream = s3Stream.upload({
      Bucket: context.AWS_S3_BUCKET,
      Key: upload_path,
      ContentType: "audio/mpeg",
    });

    console.log(`Transferring ${event.CallSid} to ${upload_path}`);
    await transfer_recording(context, download_url, upload_stream);

    const client = context.getTwilioClient();
    await client.recordings(event.RecordingSid).remove();

    callback(null, "Transfer completed.");
  } catch (err) {
    callback(err);
  }
};

```

axios を使って録音データをストリームとして取得し、それを [S3UploadStream](https://www.npmjs.com/package/s3-upload-stream) に Pipe することでアップロードします。Pipe でつなぐことで、ローカルに一時ファイルを作成することなく転送が可能です（素敵！）。

axios でデータを取得するときに、Basic 認証をかけていますが、これは Twilio の Programmable Voice の設定にある**Enforce HTTP Auth on Media URLs** を有効にしていることを想定しています（無効にしていても動作しますが、ぜひ有効にしましょう）。
![スクリーンショット 2021-04-12 13.15.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/ea9f03da-6839-b808-33da-134b72c136f0.png)

## デプロイ

<font color='red'>デプロイするときは、Twilio CLI プロファイルが対象の Twilio プロジェクトのものであることを確認してください。</font>
違うプロファイルでデプロイをすると、間違ったプロジェクト内に Functions ができてしまいます。プロファイルを切り替えるときは、`twilio profiles:use プロファイル名`で行います。

- 以下のコマンドを使って、プログラムをデプロイします。

```sh
twilio serverless:deploy --force
```

- 以下のような感じでデプロイがされれば成功です。

```sh
Deploying functions & assets to the Twilio Runtime

Account         ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Token           5c19****************************
Service Name    twilioVoiceRecordingToS3
Environment     dev
Root Directory  /Users/katsumi/Documents/workspace/Node.js/twilioVoiceRecordingToS3
Dependencies    aws-sdk, axios, s3-upload-stream, twilio
Env Variables   AWS_ACCESS_KEY, AWS_SECRET_ACCESS_KEY, AWS_REGION, AWS_S3_BUCKET, AWS_S3_PREFIX
Runtime         undefined

✔ Serverless project successfully deployed

Deployment Details
Domain: twiliovoicerecordingtos3-XXXX-dev.twil.io
Service:
   twilioVoiceRecordingToS3 (ZSe8d5680a4c68e08a6bc5a41e964588c9)
Environment:
   dev (ZEdb28386fa0b2467c75db08f29b263b5b)
Build SID:
   ZB44ca257c919636d6c8f23f33d5f8d1d1
Runtime:
   node12
View Live Logs:
   https://www.twilio.com/console/assets/api/ZSe8d5680a4c68e08a6bc5a41e964588c9/environment/ZEdb28386fa0b2467c75db08f29b263b5b
Functions:
   https://twiliovoicerecordingtos3-XXXX-dev.twil.io/export-s3
Assets:

```

最後の方に表示される`Functions:`の URL（ https://twiliovoicerecordingtos3-XXXX-dev.twil.io/export-s3 ）を控えておいてください（XXXX のところに数字が入ります）。

## Twilio 側の設定

Twilio 録音では、通話が終了してから録音データが作成されるまでに少しだけタイムラグが発生します。そのため、録音データが完成したときに通知される [RecordingStatusCallback](https://jp.twilio.com/docs/voice/twiml/record#attributes-recording-status-callback) を利用するのがよいです。

具体的には、\<Record>動詞の `RecordingStatusCallback` に、今控えておいた Functions の URL を指定します。もし Studio で録音をしているのであれば、**Record Voicemail** ウィジェットに以下のような設定項目がありますので、そこに先程の URL を設定します。
![RecordingStatusCallback.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/885cc207-878f-6d28-ac08-60a0a57bedf1.png)

## テスト

以上でセットアップは終了です。  
あとは実際にテストをして、Twilio 上に録音データが残っていないことと、S3 に録音データがアップロードされたことを確認してください。
![スクリーンショット 2021-04-12 13.31.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/71733155-35ba-a41f-cefd-60731a1ea314.png)

# まとめ

録音データの保存場所を日本に限定させておきたい場合などは、今回の方法を使って対処することが可能です。また、録音データが溜まっていくと Twilio 上にストレージの料金がかかりますので、そのような心配からも S3 への転送は有効ですね。
あとは、必要に応じて S3 の暗号化を設定しておくと良いでしょう。

---
### Twilio（トゥイリオ）とは

https://cloudapi.kddi-web.com
Twilio は音声通話、メッセージング（SMS /チャット）、ビデオなどの 様々なコミュニケーション手段をアプリケーションやビジネスへ容易に組み込むことのできるクラウド API サービスです。初期費用不要な従量課金制で、各種開発言語に対応しているため、多くのハッカソンイベントやスタートアップなどにも、ご利用いただいております。

自己紹介|　
:--|:--
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/b51a8b88-abd5-ce5e-195a-de3564ba2ae6.png" height='200' width='150'/>|高橋克己（Katsumi Takahashi） 自称「<font color='red'>赤い芸人</font>」<br />グローバル・インターネット・ジャパン株式会社　代表取締役<br />株式会社KDDIウェブコミュニケーションズ　Twilio事業部エバンジェリスト<br /><br />2001年より大手通信事業者の法人サービスの教育に携わり、企業における電話のしくみや重要性を研究。2016年よりTwilio事業部にジョインし、Twilioを使ったスマートコミュニケーションの普及活動を精力的に行っている。<br />2015 Hall of Doers<br />2019 Twilio Champions