WebRTCについて調べた

WebRTCについて調べた

こんにちは、@24guchiaです。

Webの記事何本かと本2冊買って読んでみたので、一度、現状の理解を書いてみます。

ちなみに買った本は下の本と、

 

わか(った気にな)るWebRTCの電子版です。

https://booth.pm/ja/items/504677

読む順番としては、わか(った気にな)るWebRTCを読んで、

ざっくり概要を頭に入れてわかった気になってから、リックテレコムのWebRTCの本を読むと良いと思います。

いきなりリックテレコムから入ると心が折れること間違い無し。

最近、リックテレコムから販売されている本を買うことが増えてきた。

この記事で分かること

WebRTCってそもそも何か、どういうところで使われてて、

どんなプロトコルが用意されているかが分か(った気にな)るようになります。

なんで調べたの?

Twilioを使うにあたって、Twilioがそのあたり難しい部分を吸収したライブラリやSDKを用意してくれてるけど、

デバッグするにあたってあまりにも分からないことが多すぎたため。

Twilio使わないから知らなくても良いや〜って思わず、ネットワークについての勉強になるし、

最近ではiOS11からWebRTC対応されスマホ全般で使える技術となったので、

Web系の開発をしている人は押さえておくべき技術になっていくでしょう。

WebRTCってそもそも何?

Web Real Time Communicationの略。名前の通り、

ブラウザでのリアルタイム性を持つコミュニケーション全般を取り扱います。

コミュニケーションは具体的に、音声通話や動画(ビデオチャット)などを指します。

特長はインターネット回線につながっているブラウザさえあれば、

上記コミュニケーションを行える点です。

もう電話機や専用のソフトウェアは必要なくなります。

WebRTCを使っているサービスは何がある?

Twilio

appear.in

Slack音声通話

などがあります。使ったことがあるサービスがあると思います。

リアルタイムコミュニケーションってどうやってるの?

  1. 音声などの情報入出力の許可をユーザによって行わせる
    • 不正にユーザの情報を収集しづらくするために、ユーザに許可・拒否を選択させる
  2. ピア同士の接続の確立
    • 次に詳細な説明を書きます
  3. ピア同士のデータ交換
    • データ交換によって、音声通話やビデオチャットが可能になります
  4. 接続の終了

ピア同士の接続の確立って難しそうだね?

はい、難しいですね

接続の確立について、オファーアンサーネゴシエーションという

ローカルとリモートの設定を交換する手法があります。

  1. 接続を試みる側がどのメディアどのデコードで送るかをオファーとして送る
  2. 受け手側は、送られたオファーに対して、対応可能かと他に使いたいものリストをアンサーとしてオファー側に送る
  3. アンサーを受取、各ピア同士で受け取った情報を設定することでデータ交換が行えるようになる

ネットワークの制限

セキュリティを高めるためのファイアウォールや

NATの存在が接続の確立にあたっては障害となる。

その回避を行うため、特別なプロトコルが用意されています。

NAT is 何?

Network Address Translatorの略。

IPアドレスは有限の資源であり、資源の有効活用のために使われる。

グローバルIPをNAT機能持ちルータで、ルータ内のプライベートIPとの変換を行う技術。

NAPTであることがほとんどで、ポートの変換も行うことが多い。

正確にはNAPTだけど、一旦NATで統一します。

ピア同士が接続されるWebRTCだが、

NATの存在のため、接続先ピアがどのプライベートIPを持っているかが

外側からは分からないため、下記NAT越えが行われる。

NAT越え is 何?

上記問題への対応のため、ピアに直接パケットを送るために行われる手法・技術。

具体的には、ホールパンチという手法でNATを透過したテストパケットを送れるかどうかを試す。

ホールパンチ is 何?

NATの外から、プライベートIPアドレスとポート番号のペアを知るために行われる手法。

具体的には下記手法を試していく。

ICE is 何?

Interactive Connectivity Establishmentの略。プロトコルのひとつ。

NAT越えを行うための手法の一つ。ICEでは下記を行う。

  • IPアドレスとポート番号のペアを集める
  • ピア同士がペアを交換する
  • ホールパンチを試す
  • 繋がるペアでデータ交換を行う

上記が純粋な手法で、よくあるICEではSTUNプロトコルとTURNプロトコルを使い、

ピア同士の接続の確立を試みます。

また、VanillaとTrickleという拡張がある。

Vanilla ICE is 何?

標準のICEを指す。拡張であるTrickleが出来たため、標準がVanillaと呼ばれる。

VanillaはすべてのIPアドレスとポート番号のペアを収集してから

すべて接続を試し、接続確立されたものから使用するペアを選択する。

バニラという単語自体には標準という意味がある。

ICEという名前のためのシャレみたいなもんでしょうね。

Trickle ICE is 何?

標準のICEに対し、拡張されたICEを指す。

Vanillaに対し、Trickleではペアを順次交換し、接続成功した時点で処理が終了されるので、

接続確立までがVanillaよりも速くできる可能性がある。

現時点ではChrome/Firefoxと一部ブラウザでしか対応していないため、

使用する際には最新の情報を調べてください。

Trickleは滴り落ちるという意味なので、ペアを少しずつ試すという点が

アイスが滴り落ちるのと様子に似ているからこの名前なんだと思います。

STUN is 何?

Session Traversal Utilities for NAT の略。プロトコルのひとつ。

これもNAT越えのための手法のひとつ。

STUNで対象のピアのネットワーク上にNATが存在するかどうかを確認するプロトコル。

テストパケットをSTUNサーバに送り、自分のIPが外部のネットワーク上からどういうIPで見えるかを確認します。

自分のIPと一致していれば、NATは存在しません。

NATが存在しなければ、NAT越えの必要なくパケットを送ることが出来ます。

存在する場合は、NATが一つ以上存在し、一番外側のNATの情報が取得できます。

STUNでアドレスとポートのマッピングを取得します。

このマッピング情報をもとにピア同士で接続するのがSTUNです。

TURN is 何?

Traversal Using Relays around NAT の略。プロトコルのひとつ。

TURNはSTUNの拡張プロトコル。ICEがホールパンチに失敗した場合、メディアリレーを行う。

ブラウザに実装されているTURNクライアントと、NATの外にあるTURNサーバと

接続先のピアがTURNサーバを経由し、メディア情報を交換している。

STUNとの違いはSTUNはピア同士で接続するのに対し、

TURNはピアとピアの間にTURNサーバが存在し、

TURNサーバ経由で接続する点が異なります。

ICEとSTUNとTURNの関係

同じNAT超えをしているし最初どういう関係かわかりませんでしたが、

iwashiさんからTwitterでリプライいただけたので書いておきます。

各プロトコルは独立している。TURNはSTUNの拡張プロトコル。

ICEはICE自身でのアドレスとポートのマッピングを行い、

さらにTURNとSTUNも利用するプロトコルです。

まとまれ

これらのプロトコルを用いて、ピア同士で接続できれば晴れてリアルタイムコミュニケーションが楽しめます。

Twilioではこの辺り難しいところを何も考えずに使える点が良いですね。

音声通話はもちろん、最近ではビデオチャット機能も充実してきているとのことなので、

手っ取り早くWebRTCに触れてみたい方はTwilioをさわってみてはどうでしょう。

https://twilio.kddi-web.com/

どういう構成だとSTUNでつなぐことが出来て、

TURNが必要になるのはどういう構成なのかなど今度調べてみます。

Please follow and like us:

Twilio.Taskrouterを調べて使ってみた【長文】

こんにちは、@24guchia です。

掲題通り、便利そうだけどなんか難しそうだな・・・

と思って避けていたTwilio.Taskrouter導入しました。

 

最初にお伝えします。

理解が難しいですが、とても便利な機能です。

顧客を待たせることになる受電、手を抜かずにやりきりましょう。

 

2017/11/04 追記

なんと、Twilio.TaskrouterのプロマネからTwitterでコメントありました。

後ほど、まとめますが、気になる方は僕のTwitterアカウント参照してください。

@24guchia

2017/11/06 追記

一部、不明点やアドバイス頂いた点を追記しました。

Twilio.Syncで受電割り振りすると言ったな

http://harinoma.info/?p=32

あれは嘘だ。

すいません、Syncの使い方間違えてました。

Sync自体は在席管理で使い続けます。Syncも便利です。

Sync → Taskrouter変更の経緯

そもそもSyncでデータの中身に対して、クエリを発行する方法がない。

そのため、全件取得して中身を取り出して、該当する人だったら

その人に通話を割り振るとしていたが、500件mapに入れたら検索だけで10秒位かかった。

遅すぎて流石に厳しいので、ACDに特化したTaskrouterについて調べることにしました。

Taskrouter概要

理解が必要な概念は下記の通り。

  • Workspace
    • 以下概念を入れるための入れ物
  • Workflow
    • ACDとして、どの呼をどのTaskqueue(後述)に入れるかのルール設定ができる
    • 挙動としては、一般的なSwitch文に似ている。JSON形式で記述方法はSQLライクな文法で設定することが出来る
  • Taskqueue
    • 呼を入れて、待たせる。保留と同等なので、架電側には保留音が流れる(電話の場合)
    • FIFOとLIFOが選べる
    • このTaskqueueに入っているTask(後述)をどの属性を持ったWorker(後述)が対応可能かフィルタできる
    • 一般的な使い方はTaskqueueにセールス部門、サポート部門、全社員というような使い分けを行う
  • Task
    • 受電した呼に属性をJSONで持たせたもの
    • Taskが持っている属性でWorkflowの評価が行われ、Taskqueueへキューされる
    • 受電以外に問い合わせメールとかにも使えるらしいので、Taskという名前らしい
  • Worker
    • Taskを対応する人。オペレーターや営業など
    • Task同様、JSONで属性を持つ。Taskqueueのフィルタの際に評価される
    • 例えば、Aさんにセールス部門という属性をもたせ、Bさんにサポート部門という属性をもたせて、得意なTaskをこなせるように設定する
    • Task対応できるかどうかの属性(Available)やどういう状況(Activity)を持たせる
  • その他
    • Workflowによって、タスクキューという通話一覧にキューされる。
    • 優先度と時間によってエスカレートする仕組みがある。
    • タイムアウトの時間設定ができるので何秒か対応できなかったら、自動でエスカレートし、次の評価されたQueueに入る。

概念はこのようになっています。

振り分け処理について

先述の通り、Workflowsに設定しているJSONで振り分けを行っている。

task_routingに設定されているfiltersはSwitch文のように動作する。

filtersのexpressionに合致するタスクは、そのfilter内のtargetsに沿って通話振り分けが行われる。

いずれにも一致しない場合、default_filterのキューに入れられる。

switch caseとdefaultと同じです。

expressionの文法

SQLライク。JSONのキーバリューを走査してくれる。

ANDとORで接続する。一般的な比較ができる、==,!=,>,<,HAS,CONTAINS,IN,NOT INが使える。

型はString,Numbers(int and float),Booleanがある。配列も使える。

タスクにJSONで属性つけるとexpressionでの評価対象になる。

ここらへんはドキュメント読んでください。

Taskrouterってどうやって作るの

いつも通り、管理コンソールかREST APIで作る。

https://jp.twilio.com/console/taskrouter/workspaces/create

で、Twimlでどうやって使うの

Enqueueでworkflowに入れる。

そのときにTask名詞でexpressionの評価対象になる属性をJSON形式で設定できる。

で、クライアントではどう使うの

Taskrouter.jsというJavaScriptSDKが用意されているのでそれを使う。

トークン生成が必要なので、サーバ必須。

ここのところ激プッシュしてるFunctionsでもOKらしい。動画参照

https://www.youtube.com/watch?v=XMg5ytgyn1E

FunctionsだとCRM連携ってどうやるんだろう?

Taskrouterを使う場合の受電の流れ

  1. 受電するとTwilioの受電時Webhookが呼ばれる
    1. この画面で管理してるやつ → https://jp.twilio.com/console/phone-numbers/incoming
  2. 1で呼び出されたWebhook内でTaskをあるWorkflowにenqueueするtwimlを生成する
  3. Workflowの処理が呼び出だされTaskの属性とWorkerの属性によってタスク割り振りが決定し、予約が作成する
  4. 割り振りされたら、コールバックが呼ばれる
    1. この画面で管理してるやつ → https://jp.twilio.com/console/taskrouter/workspaces/WSxxx/workflows/WWxxx
  5. 4で呼び出されたコールバック内で、タスクをどうするかを決める処理を行う
    1. 今のところ使っているのはVoiceのみのため、基本的に全部callでWorkerのcontact_uriに電話かける
    2. Voice以外のタスクを取り扱うようになったら、適切なチャネルに流れるように設計する必要がある
  6. クライアントに電話がかかる
    1. 具体的にはTwilio.Device.incomingとworkerのイベントでresevation.createdが並行して呼ばれる。
    2. 並行に呼ばれるのはかなり厄介なので、他はどうしてるか知りたい

受電のフローはこうです。

Taskrouterの勘所

Taskとあるが、Queue(保留)の仕組みを組み合わせているだけ

これが理解できておらず、苦労しました。

Taskrouterで割り振られた通話の親通話がなぜか取れない

callAPIの受電では親通話に紐付いて、

クライアント側は子通話が生成されるが、Queueと同じ仕組みのため、

割り振られた受電でも、Queueに入っている通話に対して架電しているので、

親子関係が生成されない。

追記:親子関係が生成されない件について

下記ドキュメントにあるようにinstruction:conferenceを使用することで親子関係が生成されるようです。

https://www.twilio.com/docs/api/taskrouter/reservations#conference

現在はdequeueでクライアントにかけているため、

conferenceに変更し、どう挙動するか後ほどまとめます。

 

ACDって要するにロードバランサーだよね

Automatic Call Distributor/着信呼自動分配装置って、名前いかついし

そんなのWebで似た概念ないよな・・・って思ってたけど、

ロードバランサーと同じってのに気づくと、よく分からないものから

なんとなくイメージが付けやすくなると思います。

良いところ

  • 振り分け、タイムアウト、エスカレートできる
    • 振り分けはともかく、タイムアウトとエスカレートの処理を書くのはなかなかしんどいと思う
  • ソースを修正せずに、管理コンソールだけで受電振り分け設定を変更できる
    • 注意として、管理コンソールだけでは使用できない設定があり、更にAPIで設定しても管理コンソールに表示されないようなので、この事情を知らない人が勝手に変えると壊れる可能性があります
  • 受電したとき、clientだとcurrentの親callを取らないどこからの受電分からないが、taskrouterだとreservation.task.attributesに入ってる
    • 2017/11/06追記: conferenceでTaskを割り振りすることで親受電を取れるようです。現在、確認中
  • taskの生成を行う際、JSONになんでも情報を持たせることができ、クライアントでtask.attributesで参照できる
    • task.attibutesはめちゃくちゃ便利です!DBで取得した値を設定することで、クライアント側に受電と同時に取得した値の参照が出来るようになります。
    • API呼び出しとAPI保守費用が下がるので、めちゃくちゃ単純な割り振りしかないからいいやって思わずに、使うと良いです

困りどころ

  • dequeue/callを使うと、クライアントの受電とアサインされたtaskの受電で2つとも同じ処理(Twilio.Device.incoming)を通るので、処理の切り分けが必要
    • dequeueだと、connection.parameters.ApiVersionがなぜかないが判断基準にするには微妙(そもそもない事自体がバグなのでは?)
  • dequeue/callを使うと、Twilio.Device.incomingがreservation.createdより先に発火する事が多い
    • 電話は鳴るが、アサインされたtaskが参照できないので若干無駄な瞬間がある
    • たまにreservationの方が速かったりするので、reservation.createdを必ず待つことができない
  • ワーカーのavailabilityを見て、割り振りするかの設定であるskip_ifが管理コンソールで変更できない
    • API呼び出しで解決しました
    • APIでskip_if付けても、管理コンソールに表示されないっぽい?
    • 挙動確認したところ、ドキュメント通りなので反映はされているらしい
    • StackOverflowで聞いてるけど、回答が来なくて悲しかったのはちょっと前の話
    • https://stackoverflow.com/questions/46884250/how-do-i-configure-skip-if-on-twilio-taskrouter-workflow
    • 2017/11/06追記:↑先日、回答がありました。現在はAPIで更新/参照の必要があります
    • なんとドキュメントに見れない件がNoteとして記載されていました。嬉しい:)
    • https://www.twilio.com/docs/api/taskrouter/worker-presence
  • TaskQueueに対応可能Workerがいなくても、一旦キューに入ってタイムアウトまで待つ
    • 対応可能Workerがいない場合、次のキュー判定に入るかどうかの設定がほしい
  • TaskAttributesがマルチバイト文字が未サポート
    • 下記、気合のエンコードとデコードで解決
    • サーバ側(Php)でurlencode()でエンコードして、クライアント側(Taskrouter.js)でdecodeURIComponent(reservation.task.attributes.name)でデコードする
    • Syncではマルチバイト文字対応してるのになんでだろう
    • 2017/11/06追記:Taskの割り振りに関係ないため、対応していないらしい。現在、対応を希望していますが、同上の理由により優先度を上げて対応は難しいとのこと。

REST APIではまったとこ(Php)

https://www.twilio.com/docs/api/taskrouter/workers

  • Workerを作るAPIのオプショナルパラメータでドキュメントのFIELDがプログラムで使う連想配列のキーと一致しない
    • ActivitySidはactivitySid、Attributesはattributesをキーにする必要がある。ドキュメント仕事してくれ
    • パラメータ変換するだけのクラス作りました
  • Attributesに設定するのは単純な配列じゃなくて、JSON化する必要がある
    • JSON化はTwilioのライブラリ側でやるでも良いような気がする
    • json_encode,json_decodeしないで文字列でゴリゴリJSONを扱うってあんまりしないし
  • Worker削除しようとする時に、そのWorkerのavailableがtrueだと削除できない。
    • 対応として、削除する関数にforce引数を付けて、force=trueだったら削除前にavailableがfalseのactivityに変えている。
  • QuickStartのドキュメントは更新されてないので、APIは別でドキュメントを読む必要あり

Taskrouter.jsではまったとこ(クライアント側)

  • Workerのトークン生成でreservation更新を許可しておらず、403が出た
    • エラーメッセージがちょっと分かりづらかった
    • 403 Policies defined such that we cannot access the given resource
    • dequeueでかかってきた通話をconnectするとreservationが更新されたのでより混乱してしまった
  • Worker生成のオプションでdisconnectActivitySid設定しても、アクティビティが変わらない?

まとめ

困りどころ多いですね!

ただそれを差し引いても便利機能なので、がんばって実装しましょう。

後で使いそうなドキュメント

Please follow and like us: