第 5 章 STUN/TURN サーバーの構築 52 STUN サーバーを構築する $ sudO apt install coturn Ubuntu の場合はもっと簡単で、 apt コマンドでインストールできます。 Ubuntu でのインストール方法 56 ウトを外します。現段階ではそもそも TURN サーバーの設定を行っていないのでそのま TURN 機能を利用せず、 STUN 機能のみを動作させる場合は stun-only のコメントア STUN サーバーのみ利用する #1istening-port=3478 if allowed by configuration. # "plain" TCP & UDP port(s) , t00 # Note: actually, TLS & DTLS sessions can connect to the # TURN listener port for UDP and TCP (Defau1t : 3478 ) . マリスト 5.1 turnserver. conf 14 行目付近 合は、 listening-port のコメントアウトを外して数値を書き換えます。 待ち受けポート番号はデフォルト設定では 3478 が使用されます。これを変更したい場 待ち受けポート番号の変更 せん。いくっか重要な設定項目を紹介しますので、必要に応じて変更してください。 ・・といっても実は STUN サーバーとして動作させるだけなら、設定はほぼ必要ありま 集は root 権限で行ってください。 場所にあるかもしれません。設定はこのファイルを編集することで行います。もちろん編 Ubuntu では /etc/turnserver. conf にあります。インストール方法によっては別の coturn の設定ファイルは、 CentOS では /etc/turnserver/turnserver . conf 、 STUN サーバーで必要な設定 可能です。まずは STUN サーバーのみ使用する設定で構築していきましよう。 coturn は STUN/TURN の両方の機能を備えており、両方同時でも片方だけでも使用
8.1 プラウザーの挙動を変える Firefox で模擬キャプチャデバイスを使用する方法 で、左上にはドットがランダムに点滅しながら表示されています。 このとき取得される映像は全体が 1 色で塗られ、色が少しずっ変化していくもの video : true, audio: true, fake : true Iet mediaStream = await navigator. mediaDevices . getUserMedia( マリスト 8.1 Firefox で模擬キャプチャデバイスを起動するためのコード ます。 true を含め バイスを使用するには、 getUserMedia の引数の制約条件に fake: その方法は他のプラウザーとは大きく異なります。 Firefox で模擬キャプチャデ Firefox にも模擬キャプチャデバイスを使用する方法は用意されているのですが、 △図 8.5 Firefox のテストパターン映像 87 りません。 報が少なかったりする点で、他のプラウザーに比べると使い勝手はあまり良くあ ソースコードを書き換えないといけなかったり、取得される映像から得られる情
第 3 章通信相手を見つけて、つなげる・・・シグナリング ますが、このときだけは candidate プロバティの値は空になっています。 マリスト 3.6 通信経路候補の交換 V 通信経路候補を見つけた / / 通信経路候補が見つかったとき (event) = > { pc ・ onicecandidate if (event . candidate) { / / 通信経路候補を通話相手に教えるため送信 ws . send({ tO : remoteUser, ) icecandidate' event : data : event . candidate }else{ / / 通信経路候補を見つけ終えたら event . candidate は空 マ相手から通信経路候補が送られてきた / / WebSocket メッセージを受信 ws ・ onmessage = async (e) = > { ) icecandidate' ) { if (e . data. event / / 相手から送られてきた通信経路候補を登録 await pc. addIceCandidate(new RTClceCandidate(). data. data) ) ; 接続に必要な手順は以上で終わりです。 通信経路候補の交換が終わると、その情報をもとに両者のプラウザーがお互いに接続を 式行します。見事接続に成功すれば、お互いのメディアストリームが送信されてビデオ チャット通話がはじまります。 一三ロ 46
2.2 メディアストリームの条件を指定する マリスト 2.5 デバイスが対応していない値を ide で指定 1et mediaStream = await navigator. mediaDevices. getUserMedia( video : { width: {min: 1280 , ideal : 1500 } , height : {min: 720 , ideal : 1000 } たとえばスペックの低い環境のためにフレームレートを最大川 . ()fps までに制限するに 映像のフレームレートをフレーム毎秒 (fps) で指定します。 frameRate aspectRatio: {exact : 1 .7777777778 } / / アスペクト比 16 : 9 video : { 1et mediaStream = await navigator. mediaDevices . getUserMedia( v リスト 2.6 アスペクト比の指定 在、 Firefox はこの項目に対応していません。 4 : 3 なら 1 .3333333333 、 16 : 9 なら 1 .7777777778 となります * 7 ( リスト 2.6 ) 。執筆時現 ある " 4 : 3 " や " 16 : 9 " といった表記ではなく、縦を 1 としたときの横の長さです。つまり 映像の縦横比 ( アスペクト比 ) を指定します。ただしその指定方法は一般的に馴染みの aspectRatio るようにクロップしているようです。 けは挙動が異なり、指定サイズよりも大きな映像を取得した上で指定サイズびったりにな が勝手に選択するか、あるいは選択できなければ工ラーとなります。ただし、 Chrome だ ideal で指定した場合、その値に近いもの ( この場合は 1 , 280 x 720 など ) をプラウザー いため、ほとんどの Web カメラでは対応していません。デバイスが対応していない値を しかし、 1 , 500 x 1 , 000 というサイズは画面や映像のサイズとして一般的なものではな め、この表記となります。 は、リスト 2.7 のように指定します。 27 * 7 実際には永遠に 3 や 7 が続く循環小数ですが、小数は小数点第 10 位で四捨五人すると規定されているた
5.3 TURN サーバーを構築する turnadmin コマンドでユーザーを登録するには次のように指定します。オプションの一 るので、直接 SQL 文を利用する必要はありません。 min コマンドを使います。スキーマの管理も含めてすべてこのコマンドが面倒を見てくれ DB でユーザー情報を管理するときは、先ほどパスワードの変換にも利用した turnad 能です。 Redis にも対応しています。ューザー情報の管理に利用する DB は設定ファイルで変更可 デフォルトでは SQLite を利用しますが、それ以外に MySQL 、 PostgreSQL 、 MongoDB 、 DB に登録されているユーザーを確認するには一 1 オプションを使います。 $ sud0 turnadmin —a —u username —r example ・ jp —p pa5Sw0rd k が一 a に変わっただけですね。 ューザを削除するときは -d オプションを使い、削除したいユーザのユーザ名と realm username [example ・ jp] $ turnadmin ー 1 を指定します。 $ sudo turnadmin —d —u username —r example ・ jp アプリで TURN サーバーを使うように指定する 63 'turn: 198.51.100.135:3478?transport=tcp' 'turn: 198.51.100.135:3478?transport=udp' urls : [ ' stun : 198.51.100.135 : 3478 ' } , {urls : iceservers: [ let pc = new RTCPeerConnection({ マリスト 5.12 TURN サーバーをリストに追加 ワードも指定する必要があります ( リスト 5.12 ) 。 していましたが、 TURN サーバーではそれに加えて user Ⅱ e と credential つまりパス サーバーのリストに TURN サーバーを追加します。 STUN サーバーでは urls だけ指定 STUN サーバーのときと同様、 RTCPeerConnection のコンストラクターに渡す ICE
第 6 章映像・音声以外をやり取りする・・・アータチャネル if(e . data. event = = 'offer'){ オプジェクトの onopen イベントが発火します。データの送信は、このイベントが発火し データチャネルの接続確立後、データの送受信ができるようになると RTCDataChannel 6.2 データの送受信 sdp : answerSdp event : ' answer ) to: 'A1ice' ws . send({ await pc . setLoca1Description(answerSdp) ; 1et answerSdp = await pc. createAnswer() ; await pc. setRemoteDescription(new RTCSessionDescription(). data. sdp) ) ; / / 以降の手順はメディアストリームの場合と同じ dc = event . channel ; / / RTCDataChanne1 オブジェクトは引数の channel プロバティに格納されている pc ・ ondatachannel = (event) = > { / / 接続を要求された側は ondatachannel イベントの引数で RTCDataChanne1 を取得する iceTransportPOIicy: ) a11 ' iceservers : [{urls : 'stun: stun ・ 1 ・ google.com : 19302 ' } ] , pc = new RTCPeerConnection ( { / / RTCPeerConnection の生成は接続を要求する側と同じ マリスト 6.3 データの送信 ドを呼び出すだけです。 データの送信 てから行うようにしてください。 データの送信自体はいたって簡単で、 RTCDataChannel オプジェクトの send メソッ dc. onopen = ( ) = > { / / データチャネルが利用可能になると。Ⅱ。 pe 取イベントが発火する 68 "text/plain"})) ; dc . send(new B10b( ['blob'] , {type : dc. send(new ArrayBuffer(128) ) ; dc . send(new Uint8Array( [ 0 , 1 , 2 , 253 , 254 , 255 ] ) ) ; / / バイナリデータも送信できる dc . send(' 文字列 ,); / / 文字列も送信できる
6.1 データチャネルの開始方法 第 2 引数にはデータチャネルのオプションを指定できます。特に必要がなければ、未指 着呼側 sdp: 0fferSdp event : 'offer' t 0 : ' Bob ' ws . send({ await pc . setLoca1Description(offerSdp) ; let offerSdp = await pc. createOffer() ; / / 以降の手順はメディアストリームの場合と同じ / / maxRetransmits : 0 / / maxPacketLifeTime: 100 , / / ordered: false, / / データチャネルのオプション ( 後述 ) 'label' / / ラベル ( 65 , 535 バイト以内の任意の文字列 ) Iet dc = pc . createDataChanneI ( / / 接続を要求する側は、 createDataChanneI メソッドを使って RTCDataChanne1 を生成する iceTransportP01icy: ' a11 ' 'stun: stun ・ 1 ・ google.com/ 19302 ' } ] , iceServers : [{urlS : Iet pc = new RTCPeerConnection({ / / RTCPeerConnection の生成はメディアストリームの場合と同じ マリスト 6.1 データチャネルの開始 ( 発呼側 ) 定でかまいません。これについては本章の後半で改めて説明します。 リスト 6.2 データチャネルの開始 ( 着呼側 ) オプジェクトを取得できるようにしておきます。 イベントが発火するのでこれにイベントハンドラーを設定し、引数から RTCDataChannel チャネルの接続が確立したときに RTCPeerConnection オプジェクトの ondatachannel また、着呼側では createDataChanne1 メソッドは呼び出しません。その代わり、データ を利用したいという情報は含まれているので、これを保存するだけでよいのです。 に何かする必要はありません。発呼側から送られてきたオファー SDP にデータチャネル 着呼側では、データチャネルの利用を RTCPeerConnection オプジェクトに伝えるため WS. onmessage = async (e) let dc; let pc; / / 接続を要求された側 67
5.3 TURN サーバーを構築する 同一の LAN に接続されていないようにしましよう。各端末が同一の LAN につながって いると LAN 内で付与されているプライベート IP で接続できるため、 STUN サーバーを TURN サーバーで必要な設定 編集していきます。 今度は TURN サーバーを構築をしてみましよう。先ほどと同じように設定ファイルを 5.3 TURN サーバーを構築する 使う必要がないからです。 TURN サーバーを有効化するためにもう一度コメントアウトしておいてください。 なお、 STUN サーバー構築時に stun-only のコメントアウトを外していた場合は、 なっています。 TURN サーバーの構築では、 STUN サーバーのときに比べて設定が必要な項目が多く ポート番号の範囲を変更する リスト 5.5 turnserver. conf 146 行目付近 # Lower and upper bounds Of the UDP relay endpoints : # (default values are 49152 and 65535 ) # mi Ⅱー port = 49152 #max—port=65535 接続に使用するポート番号の範囲を指定します。 min-port が下限、 なり、デフォルト値は 49152 ~ 65535 となっています。 フィンガープリントとユーザー認証の有効化 マリスト 5.6 turnserver. conf 162 行目付近 # Uncomment tO use fingerprints in the TURN messages ・ # By default the fingerprints are off . #fingerprint # Uncomment tO use long—term credential mechanism. 59 #lt—cred—mech # By default れ 0 credentials mechanism is used (any user allowed) . max-port が上限と
3.3 シグナリングのシーケンス RTCPeerConnection オプジェクトの生成 時に接続する場合はその接続数だけオプジェクトを生成することになります。 このオプジェクトは 1 接続につき 1 つずつ必要です。ビデオ会議のように複数人と同 シグナリングは主にこのオプジェクトのメソッドを呼び出しあうことで行われます。 生成しています。 RTCPeerConnection は WebRTC 接続の基礎となるオプジェクトで、 図 3.1 ではアリスとポプのどちらも、最初に RTCPeerConnection オプジェクトを メディアストリームの登録 横に置いといてください。 コンストラクター引数の内容と意味については第 4 章で説明しますので、今はいったん iceTransportP01icy: ' a11 ' 'stun: stun ・ 1 ・ google ・ com: 19302 ' } ] , iceservers : let pc = new RTCPeerConnection ( { マリスト 3.1 RTCPeerConnection 次に、人力デバイスから取得したメディアストリームを相手に送信するために アストリームのトラックを RTCPeerConnection オプジェクトに登録します。 Y リスト 3.2 addTrack(addStream) / / メディアストリームは事前に取得しておく 1et 10ca1Stream = await navigator. mediaDevices . getUserMedia( {audio: true, video : true} / / 送信したい自分のメディアストリームを登録する / / ※ pc は RTCPeerConnection オブジェクト if ( 'addTrack' in pc){ / / 新仕様 10ca1Stream. getTracks() . forEach( (track) = > { pc. addTrack(track, 10ca1Stream) ; }else{ / / 旧仕様 pc. addStream(10ca1Stream) ; メディ 現在の仕様では、 addTrack メソッドを呼び出してメディアストリームに含まれるト ラック単位で登録を行います。以前の仕様では、 addStream メソッドを呼び出してメディ 39
第 3 章通信相手を見つけて、つなげる・・・シグナリング アストリーム単位で登録していました。 40 うな操作をするためには、トラック単位で扱えるほうが都合がよいのです。 替えたり、複数の映像トラックを同時に送信したりすることができます。そのよ 本書では説明していませんが、 WebRTC では送信する映像トラックを動的に切り からです。 なぜこのような仕様変更があったかというと、そのほうが都合がよい場合がある 比べると少し冗長なように思えます。 新旧 2 つの仕様を見比べると、旧仕様のほうがシンプルで、現在の仕様はそれに トラックとメディアストリーム event . stream ; remoteVideoEIem. srcObj ect pc. onaddstream = (event) = > { / / 旧仕様 }else{ remoteVideoEIem. srcObject = event. streams [ 0 ] ; if (event . track . kind 'video' ) { / / ontrack イベントは video と audio で 2 回発火するが、 video のときのみ処理を行う pc. ontrack = (event) = > { / / 新仕様 if (typeof pc . ontrack ! = 'undefined' ) { / / ※ remoteVideoE1em は映像の再生を行う video 要素 / / 相手のメディアストリームを表示する マリスト 3.3 ontrack(onaddstream) どうかで処理を分けるとよいでしよう。 Edge は旧仕様のみの対応となっているため、。 ntrack イベントハンドラーが存在するか きます。こちらもやはり Firefox と Safari は新仕様に対応しているのに対し、 Chrome と で、これを video 要素の srcObject として設定すれば相手のメディアストリームを再生で イベントが発火します。これらのイベントの引数にメディアストリームが含まれているの 一方、相手のメディアストリームが利用可能になると、 ontrack または onaddstream ソッドが存在するかどうかを判定して、処理を分ける必要があります。 に対応していますが、 Chrome と Edge は旧仕様にしか対応していません。 addTrack メ プラウザーによって対応状況が分かれており、執筆時現在、 Firefox と Safari は新仕様