クラウド電話APIサービス Twillio を使ってみる (C#)

# クラウド電話APIサービス Twillio を使ってみる (C#)

今回は、クラウド電話APIサービス Twillio を使ってみます。
言語は C# で実装します。

### Twillioとは
Twilio は開発者向けのプラットフォームサービスで、数行のコードでインターネットと電話・SMS をつなぐ事が出来ます。
ネット上の仕組みを電話から操作したり、ネット上の情報を電話や SMS に通知することができるようになります。
※一部制限がありますが、試用版もあります。

### 各種リンク
・公式サイト
https://twilio.kddi-web.com/
・料金体系
https://twilio.kddi-web.com/price/
・ポータルサイト
https://jp.twilio.com/login/kddi-web
・開発ドキュメント
https://jp.twilio.com/docs/
・C#/.NET ヘルパーライブラリー
https://jp.twilio.com/docs/libraries/csharp

### 必要なもの
・Twillio アカウント
・Windows Server

### システム構成

![sss.png](https://qiita-image-store.s3.amazonaws.com/0/134550/4798b93e-fdfa-1e97-c518-a5b56c368830.png)

ユーザーが Twillio に対して電話をかけると、Twillio が指定されたURLをコールし、
レスポンスの XML の内容を実行します。
この XML は、TWILIOマークアップ言語形式で記述することで様々な動作を指定する事が可能です。
※URLは、ポータルサイトにて設定します。

## TWILIO マークアップ言語
TWILIO マークアップ言語の詳細は以下のページに記載されています。
https://jp.twilio.com/docs/api/twiml

各機能を試してみます。

#### Say
指定したテキストを読み上げてくれます。

|オプション|内容|
|:-----------------|:------------------|
|language|言語指定|
|loop|繰り返し回数|
|voice|音声選択(man, woman, alice)|

日本語の応答例になります。
電話をかけると「こんにちは！」と音声が返ってきます。
※日本語の場合、音声は alice しか使う事が出来ません。

```csharp
using System.Web.Http;
using System.Text;
using System.Threading.Tasks;

using Twilio.AspNet.Common;
using Twilio.AspNet.Mvc;
using Twilio.TwiML;

namespace Dummy
{
    public class TestController : TwilioController
    {
        [HttpPost]
        public async Task<TwiMLResult> Begin(VoiceRequest request)
        {
            var response = new VoiceResponse();
            response.Say("こんにちは！", language: "ja-jp", loop: 1, voice: "alice"); // man, woman, 
            return TwiML(response, Encoding.GetEncoding("UTF-8"));
        }
    }
}
```

language を指定しない場合、デフォルトで英語となります。
英語の場合、音声を man, woman, alice の中から選択出来るようになります。

```csharp
var response = new VoiceResponse();
response.Say("Hello! I am man", loop: 1, voice: "man");
response.Say("Hello! I am woman", loop: 1, voice: "woman");
response.Say("Hello! I am alice", loop: 1, voice: "alice");
return TwiML(response, Encoding.GetEncoding("UTF-8"));
```


#### Play
発信者に向けて音声ファイルを再生します。 

```csharp
var response = new VoiceResponse();
response.Play(url: "https://api.twilio.com/cowbell.mp3", loop: 1);
return TwiML(response, Encoding.GetEncoding("UTF-8"));
```

#### Dial
通話の発信者を別の電話へ接続します。

```csharp
var response = new VoiceResponse();
var dial = new Dial(callerId: "発信者のコールID");
dial.Number(phoneNumber: "接続先電話番号");
response.Dial(dial);
return TwiML(response, Encoding.GetEncoding("UTF-8"));
```

接続先への着信時に、いきなり通話を始めるのではなく、
まず指定した音声を接続先の電話に出力した後に、通話を始めたい場合は、以下のように記述します。
すると、接続時に指定URLがコールされ「電話が転送されてきましたよ！」と
音声が流れた後に通話が開始します。

```csharp

    [HttpPost]
    public async Task<TwiMLResult> Begin(VoiceRequest request)
    {
        var response = new VoiceResponse();       
        var dial = new Dial(callerId: "発信者のコールID");
        dial.Number(phoneNumber: "接続先電話番号",
                    url: "CallerInfo",
                    method: "POST");
        response.Dial(dial);
        return TwiML(response, Encoding.GetEncoding("UTF-8"));
    }

    [HttpPost]
    public TwiMLResult CallerInfo(VoiceRequest request)
    {
        var response = new VoiceResponse();
        response.Say("電話が転送されてきましたよ！", language: "ja-jp", loop: 1, voice: "alice");
        return TwiML(response, Encoding.GetEncoding("UTF-8"));
    }

```

#### Record 
発信者の声を録音します。 

|オプション|内容|
|:-----------------|:------------------|
|action|録音終了時にコールされるURL|
|method|GET、POST|
|timeout|一定秒数の間無音が続き Twilio が録音を終了するまでの、無音時間を秒で指定|
|maxLength|録音最大秒数|
|playBeep|録音を開始する前に通知音を鳴らすかどうかを指定|
|trim|"trim-silence": 録音の始めと終わりの無音部分を削除、"do-not-trim":削除しない
|recordingStatusCallback|録音データ保存完了時にコールされるURL|
|recordingStatusCallbackMethod|GET、POST|

```csharp
[HttpPost]
public async Task<TwiMLResult> Begin(VoiceRequest request)
{
    var response = new VoiceResponse();
    response.Record(action: "RecordFinish",
                    method: "POST",
                    timeout: 4,
                    maxLength: 10,
                    playBeep: true,
                    trim: "trim-silence",
                    recordingStatusCallback: "RecordSaveComplete",
                    recordingStatusCallbackMethod: "POST");
    return TwiML(response, Encoding.GetEncoding("UTF-8"));
}

[HttpPost]
public TwiMLResult RecordFinish(VoiceRequest request)
{
    // 録音終了
    var url = request.RecordingUrl; // 録音データURL

    var response = new VoiceResponse();
    response.Say("録音終了しました！", language: "ja-jp", loop: 1, voice: "alice");
    return TwiML(response);
}

[HttpPost]
public void RecordSaveComplete(VoiceRequest request)
{
    // 録音データ保存完了    
}
```

#### Pause 
指定した秒数、無音で待機します。

```csharp
[HttpPost]
public async Task<TwiMLResult> Begin(VoiceRequest request)
{
    var response = new VoiceResponse();
    response.Say("３秒待機します", language: "ja-jp");
    response.Pause(3);
    response.Say("３秒待機しました。", language: "ja-jp");
    return TwiML(response, Encoding.GetEncoding("UTF-8"));
}
```

#### Hangup 
通話を終了します。

```csharp
[HttpPost]
public async Task<TwiMLResult> Begin(VoiceRequest request)
{
    var response = new VoiceResponse();
    response.Hangup();
    return TwiML(response, Encoding.GetEncoding("UTF-8"));
}
```

#### Redirect 
コールフローを別のURLへリダイレクトします。

```csharp
[HttpPost]
public async Task<TwiMLResult> Begin(VoiceRequest request)
{
    var response = new VoiceResponse();
    response.Say("リダイレクトします。", language: "ja-jp");
    response.Redirect("Redirect", method: "POST");
    return TwiML(response, Encoding.GetEncoding("UTF-8"));
}

[HttpPost]
public TwiMLResult Redirect(VoiceRequest request)
{
    var response = new VoiceResponse();
    response.Say("リダイレクトされました。", language: "ja-jp");
    return TwiML(response, Encoding.GetEncoding("UTF-8"));
}
```

以上、今回は、クラウド電話APIサービス Twillio を使ってみました。