vueとskywayによるビデオ通話で参加者離脱の処理をする
2020/07/05の日報
Hanasot開発の日報、第9日目です。
やったことは
- vueプロジェクトのskywayによるグループ通話で参加者が離脱した際の処理を追加する
です。
時間は、
- Hanasot開発 31min
- 日報ブログ 37min
- 日報ブログ引っ越し準備 59min
です。
運動は
- アンイーブン・プルアップ 左右7repsずつ * 2(右手の1セット目は初めてスタローン流でできました!)
- フル・プルアップ 順手 8reps
- フル・プルアップ 逆手 8reps
です。
skywayによるグループ通話で参加者が離脱した際の処理を追加する
前回の記事でskywayによるグループ通話は開通しました。これで任意のルームを作成して、複数人によるビデオ通話自体はできることになります。加えてHanasot(哲学対話web)で必要な機能は
- ミュート・カメラオフ機能
- 発言権を1人に限定する機能(横から口を挟ませない)
- 発言権のリクエストをする機能(挙手マークを画面上に出すなど)
- 発言権を他の参加者に渡す機能(基本的に挙手している人に渡す)
という感じですね。で、今日実装したのは「もし参加者が離脱した場合に、離脱した参加者の映像を消す」機能です。哲学対話では対話中の離脱は基本的に想定されないのですが、通信状態の悪化やPCの電源オフ、ブラウザを閉じるなどの動作によって離脱してしまった場合に、残った参加者で対話を続けるための機能です。それではソースコードを見ていきましょう。
async addVideo(mediaConnection) { const participants = []; let remoteStreams = []; mediaConnection.on('stream', () => { // video要素にカメラ映像をセットして再生 Object.keys(mediaConnection.remoteStreams).forEach( key => { const remoteStream = mediaConnection.remoteStreams[key]; const remoteId = remoteStream.peerId; participants.push(remoteId); remoteStreams.push(remoteStream); }); }); this.participants = participants; await new Promise(resolve => setTimeout(resolve, 1000)); remoteStreams.forEach(async remoteStream => { const videoElm = document.getElementById(remoteStream.peerId); videoElm.srcObject = remoteStream; videoElm.play(); }); }, async removeVideo(mediaConnection) { const participants = []; let remoteStreams = []; // video要素にカメラ映像をセットして再生 Object.keys(mediaConnection.remoteStreams).forEach( key => { const remoteStream = mediaConnection.remoteStreams[key]; const remoteId = remoteStream.peerId; participants.push(remoteId); remoteStreams.push(remoteStream); }); this.participants = participants; await new Promise(resolve => setTimeout(resolve, 1000)); remoteStreams.forEach(async remoteStream => { const videoElm = document.getElementById(remoteStream.peerId); videoElm.srcObject = remoteStream; videoElm.play(); }); }, setEventListener(mediaConnection) { this.addVideo(mediaConnection); const self = this; mediaConnection.on('peerJoin', function () { self.addVideo(mediaConnection); }); mediaConnection.on('peerLeave', function () { self.removeVideo(mediaConnection); }); } },
今日追加したのはこの部分です。順番に解説していきます。
まず'peerLeave'
イベントを捕まえるように、setEventListenerで登録しておきます。これは参加者が離脱した際に発火するイベントです。
発火したらself.removeVideo(mediaConnection);
メソッドを呼びます。中身はaddVideoとほとんど同じものです。なぜかというと
<video v-for="participant in participants" :key="participant" :id="participant" width="400px" autoplay muted playsinline></video>
このように参加者の映像を出力するvideoタグをv-forで生成しているためです。参加者が減ろうが増えようがdataプロパティに登録されているparticipants
の値さえ正しければ、参加者の人数分のvideoタグを生成してくれます。addVideoとちょっと違うのは下記の部分ですね。
// removeVideoにはこのイベントを設定していません mediaConnection.on('stream', () => {
このstream
は相手方の映像が届いたときに発火するイベントです。今回は参加者が離脱する際に発火するpeerLeave
イベントから始まるため、相手方の映像は既に表示されています。したがってstream
イベントが発火しないんです。addVideoと同じ処理でいけたら記述量が少なくなったんですが、仕方ありませんね。
今回のハマりどころと解決方法
いうほどハマってないんですが、実装するまではaddVideoでremoveVideoの処理もまかなえるだろうと思っていました。理由は前述したとおりv-for
を使っているのでparticipants
の中身を適切なものに変えるだけで、videoタグの増減は行われるからです。でも単純にpeerLeave
イベントでaddVideoを呼び出しても想定通りの動作はしませんでした。そこでこんなふうにして原因を調べました。
実行されるであろう箇所にひたすらconsole.log
を入れるんです。単純で最強のデバッグ。jsの好きなところを挙げてといわれたら「ログの出しやすさ」は間違いなく挙げると思います。めっちゃ簡単なんですもん。
ということで、こんなふうにしてstream
イベントは参加者が離脱した時には発火しないことを見つけたら後はサクサクとできました。
所感
ログ大事だなーってのは仕事でも常々思います。期待通りの動作をしなかったら面倒でもすぐにログをいっぱい仕込んで確認した方が絶対早いです。ソースコードとにらめっこする前にデータはどこでどうなっているのかをちゃんと把握していないと意味がないですからね。
明日はミュートとカメラオフ機能の実装をやっていきます。がんばります。