FirefoxでのWebRTC通信の実装手順をコード例とともに紹介します。
FireFox同士でWebRTCを使った映像送受信を実現します。
このコードをgitで配布します。目次のgithubを参照ください。 ※nodjs必要です。
WebRTC(Web Real-Time Communication)は、ブラウザやモバイルアプリでリアルタイムに音声やビデオ、データ通信を行うための技術です。プラグインや外部ソフトウェアを必要とせず、P2P(ピア・ツー・ピア)接続を利用することで、高速かつ低遅延な通信を実現します。 要するにp2pでデータの通信を行い高速で低遅延なデータをやり取りします。WebRTCは映像、音声だけでなくその他データの通信が可能なため、テキストデータも送る事ができます。
WebRTCを活用するために、以下の要素は必須です
最低限これらを知る必要があります。
P2P接続を行うには、自分(オファー側)と相手(アンサー側)の情報を理解する必要があります。
これらの情報をもとに、どの経路で通信するかを決定し、P2P接続を実現します。
SDPには自分と相手の情報が含まれています。以下の手順でSDPを交換します
これだけなので、とても単純なのですがたくさんの課題が残っています。
自分、相手のsdp情報を互いに受け渡しする必要がある。
SDP情報の交換にはシグナリングサーバーを使用します。一般的にはWebSocketが利用されますが、メールでもSDPを交換することは可能です。
近年では、WHIPやWHEPという規格現れ色々なサービスで対応させている。今後メジャーになってくるのかまだ、わからない。
SDPには自分の情報が含まれていますが、これだけでは自分のIPアドレスを確認できません。STUNサーバーを使ってIPアドレスとUDPポートを取得します。 今回同じPCなので不要。
sturnサーバーにip addressとudpポートを教えてもらいます。
実際に動作を確認したい場合はここから確認できます。
udpポート制限、ip制限等でどうしても接続できない場合turnサーバーを経由して接続します。
skywayさんが詳しく解説されています。
今回同じPCなので不要。
sdpのやり取りを大雑把にコードに直すと
//offer = Aさん
let Apeer = RTCPeerConnection();//RTCPeerConnectionを初期化する。
let offer = Apeer.createOffer();//sdp生成
Apeer.setLocalDescription(offer);//Aの情報を登録
//sdpをBさんに渡す
//answer = Bさん
let Bpeer = RTCPeerConnection();//RTCPeerConnectionを初期化する。
Bpeer.setRemoteDescription(A-sdp);//Aさんのsdpを登録する
let answer = Bpeer.createAnswer()//Aさんのsdpに対して回答する。
Apeer.setLocalDescription(answer);//回答したものを登録
//回答したsdpをAさんに送る
Apeer.setRemoteDescription(B-sdp)//Bさんのsdpを追加する。
//接続完了。
という流れになります。
より細かくしていくと今回は「映像通信のみを想定」
WebRTC接続のためにRTCPeerConnectionを作成します。必要に応じてiceServersを登録します。
// TURN/STUNサーバーを指定し、RTCPeerConnectionを作成
//今回は不要。
let pc_config = { "iceServers": [] };
let peer = new RTCPeerConnection(pc_config);
peer.onicecandidate = function (evt) {
if (!evt.candidate) {
// SDP情報を送信する処理
// ...
}
};
今回は映像を送信するため、addTrackでビデオストリームを追加します。 addstream、addTrack、addTransceiverを使い映像音声を送る事ができますが、addstreamは非推奨となっているため、 aaddTrackを利用してください。
//peerに通信するものを入れる。
//映像の通信をしたいのでaddTrackで追加する。
var localstream = await navigator.mediaDevices.getUserMedia({audio: false, video: true})
peer.addTrack(localStream);
//データのやり取りもする場合
//peer.createDataChannel("channel");
//addTransceiverは送るもの受け取るものを自由に指定できます。
自分のSDP情報を作成し、RTCPeerConnectionに設定します。
//Offerで自分の情報作成し、peerに入れる。
peer.createOffer().then(offersdp =>{
peer.setLocalDescription(offersdp)
})
setLocalDescriptionをするとpeer.onicecandidateイベントが発生しまするのでこれを利用し、通信経路がそろってから相手にSDP情報を渡します。「Vanilla ICE」
送信方法は自由です。手動での入力でも機能します。
//1.Peerを作成する。のコードです。
peer.onicecandidate = function (evt) {
//このonicecandidateイベントは複数回発火する。
if (evt.candidate) {
} else {
//これを送る(peer.localDescription)
//SDPを送る処理
//....
}
};
相手側でもRTCPeerConnectionを作成し、必要なメディアを追加します。 「1.Peerを作成」と「2.通信する」ものと同じです。
let peer2 = new RTCPeerConnection(pc_config);
//省略....
ここからoffer時の処理と異なります。
受信したSDPをRemoteDescriptionに設定します。
peer2.setRemoteDescription(offersdp);
SDP情報を作成し、LocalDescriptionに設定します。
//createanswerで自分の情報作成し、LocalDescriptionに入れる。
peer.createAnswer().then(answersdp =>{
peer.setLocalDescription(answersdp)
})
作成したSDPをオファー側に送り返します。
//1.Peerを作成する。のコードです。
peer.onicecandidate = function (evt) {
//このonicecandidateイベントは複数回発火する。
if (evt.candidate) {
} else {
//これを送る(peer2.localDescription)
//SDPを送る処理
//....
}
};
オファー側は、相手からのSDPを受信し、RemoteDescriptionに設定します。
peer.setRemoteDescription(answersdp);
これでwebrtc通信ができるようになります。
webrtcを実装してつまづいたところは
sdpの生成はcreateOffer()
,createAnswer()
の後にsetLocalDescriptionでsdpを生成できますが、この時、非同期で通信経路を複数収集します。そのため、処理をちゃんとしてあげないと基本つながりません。「Trickle ICE」
その代わりに全て収集した後に送る方法「Vanilla ICE」でsdpを送ります。
一番簡単な方法はonicecandidateで通信経路収集が止まった時にsdpを送る方法です。
peer.onicecandidate = (evt) => {
if (!evt.candidate) {
//sdpを送る処理
}
}
createOffer()
,createAnswer()
は非同期処理のため、待機しないといけません。
awaitかthenを使って待機してください。
peerConnection.createOffer()
.then(function (sessionDescription) {
return peerConnection.setLocalDescription(sessionDescription);
})
githubにコードを載せておきます。ほとんどhttps://html5experts.jp/mganeko/20013/
から改変していませんが...問題なく動くと思います。
readmeに記入するべきですが...
npm i
npm run start
index.htmlを2つブラウザーで表示してください。
2つstart Videoをクリックします。
その後Connectをクリックしてください。
webrtcでの映像通信のサンプルコードが豊富なのでwebrtcを使うだけなら簡単に実装できます。
webrtcの問題点はつながらない時の原因の切り分けが難しい。いろんなos,ブラウザー,バージョン etcがあって検証や、対処が難しい...
質問や、間違いがありましたら、お気軽にどうぞ
※お名前とコメントの内容を入力してください。
※全てこのブログ上に公表されます。
※許可なく管理者によって修正・削除する場合がございます。 詳しくはプライバシーポリシーを参照ください