ライブ配信時の「受講者発言リクエスト」WebRTCサンプル（Agora.io Video、Real-time Messaging SDK利用）

<meta name="description" content="Agora.io Video、Agora.io Real-time Messaging SDK利用を利用したライブ配信時の「受講者発言リクエスト」WebRTC用サンプルになります。受講者発言リクエスト機能とは、ライブ配信中に質問や意見を発したい受講者(視聴のみ)に対応するための機能です。マルチプラットフォームでのライブ配信システムの開発を想定し、WebRTC用サンプルをご紹介します。" />

#概要
今回は[Agora.io Video SDK](https://docs.agora.io/en/Video/product_video?platform=All%20Platforms)、[Agora.io Real-time MessagingSDK](https://docs.agora.io/en/Real-time-Messaging/product_rtm?platform=All%20Platforms)を利用したライブ配信サービスでの「受講者発言リクエスト」機能のWebRTCサンプルをご紹介します。

「受講者発言リクエスト」機能とは、ライブ配信中に質問や意見を発したい受講者(視聴のみ)に対応するための機能で、受講者が発言リクエストを配信者に送信し許可されると、受講者の映像・音声が有効になり、配信者と受講者にてリアルタイムに会話ができる機能になります。


##利用するSDK
・agora.io VideoSDK（Web）
・agora.io Real-time Messaging SDK（Web）

##サンプルコード
[サンプルコード](https://github.com/fu-jimoto/AgoraIO-AudienceRemarks)
（バージョン3は[AudienceRemarks-v3](https://github.com/fu-jimoto/AgoraIO-AudienceRemarks/tree/master/AudienceRemarks-v3)、バージョン4は[AudienceRemarks-v4](https://github.com/fu-jimoto/AgoraIO-AudienceRemarks/tree/master/AudienceRemarks-v4)）

以降は、バージョン4用サンプルで説明しています。

##機能一覧
[受講者側]
・受講者発言リクエスト
[配信者側]
・受講者発言リクエスト応答（許可/拒否）
・受講者発言オン
・受講者発言オフ
※基本機能(入室/退室など)は省略しています。

##シーケンス
受講者発言リクエストの流れは以下になります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505696/aa8a6170-2413-58f8-2bd4-3672733e4f67.png" width="65%" alt="sequenceflow">
※ざっくりと流れをつかむ目的のため、細かい部分は省略しています。


##実装のポイント
【配信者、受講者の役割を分けるには】
・入室時、配信者の場合はストリームをパブリッシュし、受講者の場合はパブリッシュしません。
　（これにより配信者のみが映像・音声を送信し、受講者は視聴のみとなります。）
・受講者発言リクエスト許可時、受講者のストリームをパブリッシュします。
　（これにより受講者の映像・音声が送信され発話できるようになります。）

【受講者発言リクエストを送信/応答するには】
・Agora.io Real-time Messaging SDKを利用して接続し、テキストメッセージを受講者から配信者に送信します。
　（これにより配信者側でテキストメッセージごとに応答処理を切り分けます。）

##実装
※追加・変更分のみ記載します。

・Join時のパブリッシュ制御
Join時は配信者のみストリームをパブリッシュするように変更します。

```javascript:index.js

async function join() {
  /*省略*/
  //hostの場合のみpublishする
  if(options.role == "host"){
    [localTracks.audioTrack, localTracks.videoTrack ] = await Promise.all([
      // create local tracks, using microphone and camera
      AgoraRTC.createMicrophoneAudioTrack(),
      AgoraRTC.createCameraVideoTrack()
    ]);
    // play local video track
    localTracks.videoTrack.play("local-player");
    $("#local-player-name").text(`localVideo(${options.uid})`);
    // publish local stream
    // publish local tracks to channel
    await client.publish(Object.values(localTracks));
    console.log("publish success");
  }
}
```

・Real-time Messaging SDKの追加

```html:index.html
  <script src="agora-rtm-sdk-1.4.1.js"></script> 
```

・受講者発言用UIの追加

```html:index.html
<form id="join-form">
.....(省略)
 <div class="form-group w-25">
  <div class="form-check">
    <input class="form-check-input" type="radio" name="role" id="role" value="host" checked>
    <label class="form-check-label" for="host">host</label>
  </div>
 <div class="form-check">
    <input class="form-check-input" type="radio" name="role" id="role" value="audience">
    <label class="form-check-label" for="audience">audience</label>
  </div>
 </div>
</form>

<div class="input-group mb-2 w-50">
  <div class="input-group-prepend">
    <span class="input-group-text">Message</span>
  </div>
  <textarea type="text" class="form-control" id="messageDisp" ></textarea>
</div>
<div class="button-group mb-2">
  <button id="request" class="btn btn-info btn-sm">REQUEST</button>
</div>

<div class="input-group mb-2 w-25">
  <div class="input-group-prepend">
    <span class="input-group-text">Audience ID</span>
  </div>
  <select type="text" class="form-control" id="audienceId" ></select>
</div>

<div class="button-group mb-2">
  <button id="muteOfRemote" class="btn btn-info btn-sm">MUTE</button>
  <button id="unmuteOfRemote" class="btn btn-info btn-sm">UNMUTE</button>
</div>
```

・各種ボタンクリック時処理の追加

```javascript:index.js
$("#unmuteOfRemote").click(function (e) {
  console.log("unmuteOfRemote")
  unmuteOfRemote();
})

$("#muteOfRemote").click(function (e) {
  console.log("muteOfRemote")
  muteOfRemote();
})

$("#request").click(function (e) {
  console.log("request")
  request();
})

```

・メッセージ処理の追加（送信部分）

```javascript:index.js
function sendChannelMessage(localMessage){
  setDispMessage(localMessage);
  rtc.channelRtm.sendMessage({text:localMessage}).then(function(){
console.log("AgoraRTM client succeed in sending channel message: " + localMessage);
  }).catch(function(err){
console.log("AgoraRTM client failed to sending role" + err);
  });
}
```

・メッセージ処理の追加（受信部分）

```javascript
function receiveChannelMessage(){
    //省略//
  rtc.channelRtm.on("ChannelMessage", function (sentMessage, senderId) {
    console.log("AgoraRTM client got message: " + JSON.stringify(sentMessage) + " from " + senderId);

    setDispMessage(sentMessage.text);
    console.log((sentMessage.text == senderId + ":requested") && (options.uid == host));
    if ((sentMessage.text == senderId + ":requested") && (options.uid == host)){
      var res = confirm("Are you sure " + senderId + " to be speaker?");
      (res == true) ? permit(senderId) : deny(senderId);
  
    }
    //省略//
  });
}
```

##動作確認

実装が完了したので動作を確認します。

###１. 初期表示
１-１．index.htmlファイルをクリックし起動します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505696/7c5f874c-6e7b-03f0-fccd-d0a5d7dd3348.png" width="50%" alt="index_html">

###２. 入室（配信開始）
２-１.(配信者/受講者)"APPID"を入力します。
２-２.(配信者)Roleで"host"を選択し"Join"ボタンをクリックします。
２-３.(受講者)Roleで"audience"を選択し"Join"ボタンをクリックします。
この時点で配信者の映像・音声が受講者側に送信されます。
[配信者側]
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505696/16db46c9-61d2-788d-9324-7044019b5b86.png" width="50%" alt="join_host">
[受講者側]
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505696/df9c81a0-a848-1079-f4bb-9a1b7e4353f8.png" width="50%" alt="join_audience">
###３. (受講者)発言リクエスト送付
受講者が"Request"ボタンをクリックします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505696/ab88cfda-2ac4-8cfe-2d37-1183f229e28e.png" width="50%" alt="request_audience">
###４. (配信者)リクエスト許可
４-１．配信者側に受講者発言リクエストの確認ダイアログが表示されます。
４-２．配信者はOKをクリックし許可します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505696/889cd5b6-6775-13cb-9d75-fc586958e477.png" width="30%" alt="ok_host">
###５. (受講者)映像・音声の有効化
５-１.受講者側にカメラ・マイク許可ダイアログが表示されます。
５-２.受講者は許可をクリックします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505696/df2a190e-4247-8958-0356-6ac3ef7b116d.png" width="30%" alt="camera_ok_audience">
５-３.配信者側、受講者側両方に受講者の映像・音声が送信されます。
[配信者側]
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505696/b6bfd071-b2a5-3145-4443-7d9b325a8765.png" width="50%" alt="after_ok_host">
[受講者側]
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505696/ee847905-2231-5325-2907-e060d47b4845.png" width="50%" alt="after_ok_audience">

５-４.配信者、受講者で会話します。
###６. (配信者側)受講者発言オフ
６－１．(配信者)受講者の"AudienceID"を選択します。
６－２．(配信者)"MUTE"ボタンをクリックします。
受講者が発言前(視聴のみ)に戻ります。
###７. (配信者側)受講者発言オン
７－１．(配信者)受講者の"AudienceID"を選択します。
７－２．(配信者)"UNMUTE"ボタンをクリックします。
受講者が再び発言の状態になります。

受講者発言リクエストができました。

##関連サイト
・[Agora.io SDKでビデオ通話アプリの開発(WebRTC版)](
https://qiita.com/v-cube/items/db5e4eedce44e73d5114)
・[Agora.io ライブ配信・ビデオ通話SDKチュートリアル](https://qiita.com/v-cube/items/50d4cea6eee8626e4dc3)
・[Agora.io SDKを利用したライブコマースサンプル(WebRTC版)](https://qiita.com/v-cube/items/e236027b40017bb98a92)
・[ライブコマースシステム構築の「はまりどころ」と「対策」](https://qiita.com/v-cube/items/09d91523da3c53c4ae78)



#最後に
[**agora.ioに関するお問い合わせはこちらから**](https://jp.vcube.com/lp/agora?utm_campaign=Agora&utm_source=Qiita&arc_id=216b0291d1aac471b915)
[<img width="912" alt="スクリーンショット 0001-08-15 13.41.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/5d815376-9b89-08fa-9434-6fa7e8e67bcf.png">](https://jp.vcube.com/lp/agora?utm_campaign=Agora&utm_source=Qiita&arc_id=216b0291d1aac471b915)