Twilio Flex Conferenceの参加者情報


前回の記事でガッツリ書きすぎて燃え尽きたので
TwilioFlexネタ軽い感じで一つ

# Conferenceの参加者情報

Twilio Flexで通話を行うと、常にConference（複数人で出来る会議通話）になります。
誰にも転送しない二人での会話だったとしてもConferenceです。

電話をかけた人と、電話を取った担当者の二人の場合に以下のようになります。

- Conference
    - Call (Worker)
    - Call (Customer)

1Conferenceに対してそれぞれのCallがある感じですね。
もちろん転送等をして話者が増えるとそれに伴いCallも増えます。

そして、その情報はParticipants(参加者)として持っています。


## WEBコンソールで確認してみる

ではその情報をWEBコンソールで確認してみます。
![conference.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149339/70994cc9-5cea-6076-0f48-bad58c9f2099.png)

さきほどの通り、電話をかけた人と電話を取った担当者の二人分がParticipantsの情報からわかります。

ふむふむ


## APIでConferenceを取得してみる

公式ドキュメントにURLが載っていますので、それを参考にとりあえずURLを叩いてみます。

```sh
https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/Conferences/{ConferenceSid}
```


こんなXMLが返ってきました。

```xml
<TwilioResponse>
    <Conference>
        <Status>completed</Status>
        <ReasonConferenceEnded>participant-with-end-conference-on-exit-left</ReasonConferenceEnded>
        <DateUpdated>Tue, XX Xxx 2021 XX:XX:XX +0000</DateUpdated>
        <Region>jp1</Region>
        <FriendlyName>WTxxxxxxxx</FriendlyName>
        <Uri>/2010-04-01/Accounts/ACxxxxxxxx/Conferences/CFxxxxxxxx</Uri>
        <AccountSid>ACxxxxxxxx</AccountSid>
        <CallSidEndingConference>CAxxxxxxxx</CallSidEndingConference>
        <Sid>CFxxxxxxxx</Sid>
        <DateCreated>Tue, XX Xxx 2021 XX:XX:XX +0000</DateCreated>
        <ApiVersion>2010-04-01</ApiVersion>
        <SubresourceUris>
        <Participants>/2010-04-01/Accounts/ACxxxxxxxx/Conferences/CFxxxxxxxx/Participants</Participants>
        <Recordings>/2010-04-01/Accounts/AC6xxxxxxxx/Conferences/CFxxxxxxxx/Recordings</Recordings>
    </SubresourceUris>
    </Conference>
</TwilioResponse>
```

パッと見た感じここに直接参加者情報はなさそうです。
ParticipantsというタグにあるのがParticipantsのURLのようです。(公式ドキュメントにももちろん載ってます)

これでもっかい叩いてみましょう。

## APIでParticipantsを取得してみる


```sh
https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/Conferences/{ConferenceSid}/Participants.json
```

※「Participants」だけだと先ほどと同じXML形式ですが、「Participants.json」とすればJSON形式で返ってきます

こんなJSONが返ってきました。

```json
{
    "first_page_uri": "/2010-04-01/Accounts/ACxxxxxxxx/Conferences/CFxxxxxxxx/Participants.json?PageSize=50&Page=0",
    "end": 0,
    "previous_page_uri": null,
    "uri": "/2010-04-01/Accounts/ACxxxxxxxx/Conferences/CFxxxxxxxx/Participants.json?PageSize=50&Page=0",
    "page_size": 50,
    "start": 0,
    "participants": [],
    "next_page_uri": null,
    "page": 0
}
```

### 空やないかい:rage:

## 何も入ってなかったけど…会議中に見てみると…？

APIで取得するとParticipantsは空で返ってきました。
どゆこと…？？？

**なんとここのParticipantsの情報はリアルタイムで更新されていく**ので、
最終的に**会議が終了すると参加者はいなくなるためデータとしてもなくなります**

**通話中にAPIを叩くとデータが入っている**ことが確認できます。


じゃあWEBコンソールに出てる情報はどこから出とるんや！
という話なんですが、それはわからなかったのでどなたか教えてください:cry:

----
### 2022/02/28 追記:writing_hand:

会議終了後も参加者が取得できる新しくAPIが追加されていました。:point_down:

https://qiita.com/sst_2b/items/5de74c075bb29b66f8ea

※リアルタイムで取得したい場合だと、まだ↓の取得方法もありかなと:frowning:

----

## 会議中に取得してみよう

Conference参加者のCallSIDを取得したいことがあると思います。（あるよね？？）

先ほどの通り、会議が終わってからでは取得できない為、会議中に取得するしかありません。

Conferenceのステータスコールバックを使う方法もありますが、
どうしてもFlex UIの画面側で自分の今の通話中の情報が取得したい場合
Flex UIでリスナーを使用して取得することができます。

出来ます言うてますが、結構怪しい取得方法な気がしますので
もしかしたら、正式にちゃんとこういう取得方法があるよ！

というのがあるかもしれません。
その場合は、これもまた是非教えてください:disappointed_relieved:


## リスナー設定とFlex UIのSyncを利用

まずFlex UI側でリスナーの設定を行います。
今回は担当者側から電話をかけた時に会議情報を取得するという設定です。
今回はタスクにAcceptされた後というイベントを使います。

**「afterAcceptTask」**

そして、電話をかけてタスクに割り当てられて会議通話が始まった場合に
イベントが発火します。

payloadにタスクの情報が色々入っていますので、Conferenceを取得します。

### ソース

```js
  flex.Actions.addListener("afterAcceptTask", (payload) => {
    // 外線の時のみ処理
    if (payload.task.attributes.direction === "outbound") {
      const fetchConference = () => {
        const fetchDelay = 3000;
        setTimeout(() => {
          let conferenceSid = "";
          let workerCallSid = "";
          let customerCallSid= "";

          // 会議情報を取得
          const conference = payload.task.conference;

          // sync mapのイベントリスナー(Conferenceにitemが追加されたら実行)
          conference.source.map.on("itemAdded", async (data) => {
            // ConferenceからParticipantsの情報を取得
            const { conferenceSid, participants } = payload.task.conference;
            conferenceSid = conferenceSid;

            // ワーカーとカスタマーコールのSIDを取得
            participants.forEach((participant) => {
              if (participant.workerSid !== null) {
                workerCallSid = participant.callSid;
              } else {
                customerCallSid = participant.callSid;
              }
            });

            if (participantsData.customerCallSid) {
              await createConferenceCallApi(
                conferenceSid ,
                customerCallSid,
                workerCallSid
              );
            }
          });
        }, fetchDelay);
      };

      fetchConference();
    }
  });
```

### ※注 なんでsetTimeout？
タスクが作成されてからConferenceが作成されるまで微妙なタイムラグがあるためちょっと待ってます。
（ここのやり方が怪しい…）

### Flex UIのSyncを利用

ここで取得したconferenceにはなんとSyncのmapを持っています。
この点についてのドキュメントが探せなかったのであったら教えてください（教えてくださいばっかり:sweat:）


で、Syncのリアルタイム検知機能を利用して、参加者の追加を検知します。

**「itemAdded」**

Conference作成時に自分自身はすでにParticipantsに追加されている？ので
この「itemAdded」ではかけた相手が電話に出たときに発火します。

そして、イベント発火後にpayload.task.conference.participantsにアクセスするとデータが2件あることが確認できます！

2件ある中に、担当者と顧客側のCallSidが入っているので取得し
これをconferenceSidと一緒にどこかに保持しておけば、
通話終了後も、どのConferenceにどのCallが紐付いてるかがわかります。

##　まとめ

色々と試行錯誤してやった方法ですので多分理想形ではないと思いますが
こんな取得方法もあるんだということで:expressionless: