2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

先日はVonageのCommunication APIを使ってみようということで、下記の記事を投稿させていただきました。 

なんとなく、どんなことができるのかご理解いただけたかと思います。今日は実際に動くもので、体験していただけるようなサービスをサクッと作ってみたいと思います。

とはいえ、使えるサービスだと運用したくなってしまうので、あまり使えないサービスを作ってみます。もうタイトルにありますが、誰に聞かれるかわからないメッセージサービスを作ってみます。そして作り始めたら以外に長くなってしまったので、前編と後編で分けてお届けします。

サービスの内容は簡単で、特定の番号に電話すると

  1. 誰かが残したボイスメッセージを聞くことができる。
  2. 誰に聞かれるかわからないけどボイスメッセージを残すことができる。

です。ニーズもなければ用途もありませんが、早速作っていきましょう。

プロジェクトの作成

今回は(といか、”も") C#, Visual Studioでロジックを書きます。

今回使うサーバーは予めAzure Web Appを用意しましたが、この手順は省きます。

まずはプロジェクトの作成を行います、今回は特にユーザー用のUIいらないのでAPIサービスを作成します。Visual Studioから下記のステップを踏んでください。

image.png

新規プロジェクトが作成されましたら、Controllersフォルダーを右クリック、コントローラーを作成します。 今回はAPIコントローラーを指定します。

image.png

HandleCallsControllers.csというコントローラーを作成しました。

一旦コントローラーを作成したところで、準備完了ということで次にいきます。

image.png

今回はVonage SDKを利用しますので、こちらも事前にインストールしておきます。

image.png

これで準備は一旦完了です。

コールを受けられるようにする

では場所を移動して、次はVonageの管理画面へ。まずはコールを受けられるように管理画面にて設定します。管理画面にログインして下記のステップを踏んでください。

image.png

新規プロジェクトが作成されたら次は新しいControllerを作成します。既存のコントローラーは消して大丈夫です。

image.png

次に回答URL、イベントURL、フォールバックURLが求められるので、Visual Studioに戻り、それぞれ一旦作成します。

何をどうするかはまた後で考えるとして、一旦受け口を下記のように準備します。

[Route("api/[controller]")]
[ApiController]
public class HandleCallsController : ControllerBase
{

    [HttpPost]
    [AllowAnonymous]
    [Route("/answer")]
    [Produces("application/json")]
    [ProducesResponseType(StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public IActionResult CallAnswer()
    {
        return Ok();
    }

    [HttpPost]
    [AllowAnonymous]
    [Route("/event")]
    [Produces("application/json")]
    [ProducesResponseType(StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public IActionResult CallEvent()
    {
        return Ok();
    }

    [HttpPost]
    [AllowAnonymous]
    [Route("/fallback")]
    [Produces("application/json")]
    [ProducesResponseType(StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public IActionResult CallFallback()
    {
        return Ok();
    }

}

一旦リリースして、アクセスできるようにします。リリースできていることを確認。

image.png

Swaggerに関してはだいぶ古くなってしまいましたが、こちらの記事参照ください。

それでは、下記のように入力して、アプリケーション作成とします。

image.png

生成ボタンは画面右下

image.png

生成されると、電話番号とリンクできるページに遷移されますので、もっている電話番号と紐づけましょう。電話番号の取得などはVonageさんにサポートお願いできるかと思います(未確認)。

今回アメリカの番号がリンクされてない状態でありましたので、それを使います。

image.png

リンクされたました。

image.png

ボイスメッセージを残せるようにする

それでは、早速コールを受けてボイスメッセージを残せるようにしましょう。

まず、コールが来ると先ほどの /answer にリクエストが来るので、それに対して回答をします。回答はTalkActionというオブジェクトに格納します。

 var talkAction = new TalkAction
 {
     Text = "Welcome to Leave Message application service from " +
     $"{string.Join(" ", Request.Query["from"].ToString().ToCharArray())}" +
     ", Press 1 to leave a message, or 2 to listen to messages."
 };

その次に、1か2を選択してほしいので、アクションを求めます。ここでMultiInputActionというオブジェクトに格納します。ここで指定したアクションはEventUrlに送信されます。

var inputAction = new MultiInputAction
{
  EventUrl = new[] { $"{Request.Scheme}://{Request.Host}/dtmf" },
  Dtmf = new DtmfSettings
  {
    TimeOut = 10,
    MaxDigits = 1
  }
};

これらをNccoというオブジェクトにいれ、その文字列にして下記のように返します(Jsonで返す)。


var ncco = new Ncco(talkAction, inputAction);

return ncco.ToString();

ユーザーが1を押した場合の、指定したURLにリクエストが飛びますので、そのアクションを下記のように用意します。 リクエストできたMultiInputオブジェクトをC#のオブジェクトに載せ、input.Dtmf.Digitsで番号を理解し、アクションを組み立てます。メッセージを録音するロジックはまた別に組んであるので、ここでは「メッセージを録音してください」とアナウンスしてから3秒後にメッセージを録音するアクションにリクエストを送ります。

[HttpPost]
[Route("/dtmf")]
public ActionResult<string> HandleInput()
{
    var input = WebhookParser.ParseWebhook<MultiInput>(Request.Body, Request.ContentType);

    if (input.Dtmf.Digits == "1")
    {
        // Return recordNcco
       
        var talkAction = new TalkAction
        {
            Text = "Please record your random message. Press # when finished."
        };
        var recordAction = new RecordAction
        {
            EndOnSilence = "3",
            BeepStart = true,
            EventUrl = new[] { $"{Request.Scheme}://{Request.Host}/recording" },
            EventMethod = "POST",
            EndOnKey = "#"
        };

        var ncco = new Ncco(talkAction, recordAction);
        return ncco.ToString();

    }
    else
    {
       // Handle invalid input
       var talkAction = new TalkAction
       {
           Text = "You did not listen to me too well, you can only choose 1 or 2, Press 1 to leave a message, or 2 to listen to messages."
       };

       var inputAction = new MultiInputAction
       {
           EventUrl = new[] { $"{Request.Scheme}://{Request.Host}/dtmf" },
           Dtmf = new DtmfSettings
           {
               TimeOut = 10,
               MaxDigits = 1
           }
       };

       var ncco = new Ncco(talkAction, inputAction);

       return ncco.ToString();
   }
}

録音を処理するロジックは下記です。ここでは特に変わった処理はなくSDKにある録音機能を使って指定したファイル名で保存するようにしています。

[HttpPost("/recording")]
public async Task<IActionResult> Recording()
{
    var appId = _applicationId;
    var privateKeyPath = _privateKeyPath;
    var credentials = Credentials.FromAppIdAndPrivateKeyPath(appId, privateKeyPath);
    var voiceClient = new VoiceClient(credentials);
    var record = await Vonage.Utility.WebhookParser.ParseWebhookAsync<Record>(Request.Body, Request.ContentType);
    var recording = await voiceClient.GetRecordingAsync(record.RecordingUrl);

    var fileName = Guid.NewGuid().ToString() + "_" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".mp3";

    await System.IO.File.WriteAllBytesAsync(fileName, recording.ResultStream);
    return StatusCode(204);
}

一旦ここまでで、実装して今日の記事は終わりとします。

次回

次回は、レコーディングしたメッセージを聞いてみる、をやってみます。そうすると、とりあえず、だれに聞かれるかわからないメッセージを残せて、誰にあてて残されたかわからないメッセージを聞くことができるサービスの完成です。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?