Skyway WebRTC Gateway の簡単な使い方についてまとめる

# WebRTC Gateways について
遠隔会議などで主に使用されている遠隔通信技術WebRTCであるが, ブラウザなどを使用せずに直接通信が可能になるWebRTC Gatewaysという規格が存在していることは意外にも知られていない. この技術は, WebRTC技術と同じようにP2P通信を最終的には可能にするのだが, WebRTCと違うのはブラウザやアプリといったものを繋げるのではなく, Gatewayと呼ばれるものを繋げる点にある. これによって, 規格に定められた方式を行うことなく直接通信することが出来るのがWebRTC Gatewaysの最大のメリットと言えるだろう.

https://datatracker.ietf.org/doc/html/draft-ietf-rtcweb-gateways-02

## Skyway WebRTC Gateway について
しかし, 上記のGatewayは通常のWebRTCと違って明確な定義はされていない. また, ブラウザのように標準的なものに実装されているものでもないため, 実装は通常のWebRTC実装に比べると格段に上がる. WebRTCは仕組み自体が複雑なので, 全てを実装しようと思うと相当な難易度であることは言うまでもない.
NTTコミュニケーションズはこれを比較的容易に実装出来るものを提供している. 今回は, その実装方法を説明した記事があまりにも少なかったので簡単ではあるが記載している. なお, 下記に公式ドキュメントのリンクを載せておく.

https://webrtc.ecl.ntt.com/documents/webrtc-gateway.html

### 今回, 実装するもの

環境1のPCと環境2の別々のPCでSkyway Gatewayを介して通信を繋げる. 今回は, ビデオ映像や音声データを転送するMediaStreamとバイトや文字を繋げるDataChannelの両方を実装したものを載せている.

![webrtc_gateway.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1083592/66e1c3b8-0c07-7d62-ef64-5136174217af.png)


### 手順

主な手順は以下の通りになる.

1. [Skyway](https://webrtc.ecl.ntt.com/)にアクセス後, ログイン(会員未登録の場合は会員登録)
1. API Keyの発行
1. [Skyway WebRTC Gateway Git](https://github.com/skyway/skyway-webrtc-gateway)をGit Cloneする
1. /skyway-webrtc-gateway/samplesへ移動
1. API Keyを入力
1. Gateway Server 起動
1. プログラム実行

なお, API Keyについての説明は下記のサイトが分かりやすいので参考にどうぞ.

https://qiita.com/A-Kira/items/b26b82ee488384b302ad

### 環境構築

実装環境：Ubuntu20.04LTS

それでは, 上記の手順から実際に必要コマンドを入力することで環境を構築していく. なお, Skyway WebRTC Gatewayで使用するGateway ServerはOSによっては動作しないことがあるので, 注意が必要である.

#### Skyway API Keyの発行

最初に上記の[サイト](https://qiita.com/A-Kira/items/b26b82ee488384b302ad)を参考にAPI Keyを発行する. なお, 基本的にアドレスとして記入するものは「localhost」のみで良い. また, 取得出来たAPI Keyを記録しておく.

#### Skyway Gateway インストール

サンプルコードを入手するために下記コマンドを実行する.

    git clone https://github.com/skyway/skyway-webrtc-gateway

同様に, Gateway Serverも[リンク](https://github.com/skyway/skyway-webrtc-gateway/releases)から, GUIで入手するか下記のコマンドを入力する. なお, 使用するデバイスがarm版なのかx64版なのかで動作するものが変更するので注意.

    wget https://github.com/skyway/skyway-webrtc-gateway/releases/download/4.0.1/gateway_linux_arm

その後, インストールしたものに権限を付与する.

    chmod +x gateway_linux_arm

#### 環境1

今回, 環境1で使用したコードは以下の通りである. なお, ポートは上記のRCTPとSCTPともに全て空いている. 使用する場合は出力部分を増やし, 確認してほしい. 今回は, ビデオ送信部分とDatacahnel部分のみを出力している.

~~~ruby:callee.rb

  SKYWAY_API_KEY = ENV["API_KEY"]
  PEER_ID = "callee"
  TARGET_ID = "caller"
  RECV_ADDR = "127.0.0.1"
  VIDEO_RECV_PORT = 20000
  AUDIO_RECV_PORT = 20001
  VIDEO_RTCP_RECV_PORT = 20010
  AUDIO_RTCP_RECV_PORT = 20011
  
  DATA_RECV_ADDR = "127.0.0.1"
  DATA_RECV_PORT = 10002
  
  #connect to skyway server
  peer_token = create_peer(SKYWAY_API_KEY, PEER_ID)
  #port open request for sending data
  (video_id, video_ip, video_port) = create_media(true)
  (audio_id, audio_ip, audio_port) = create_media(false)
  (video_rtcp_id, video_rtcp_ip, video_rtcp_port) = create_rtcp()
  (audio_rtcp_id, audio_rtcp_ip, audio_rtcp_port) = create_rtcp()
  (data_id, dest_ip, dest_port) = create_data
  
  
  media_connection_id = wait_call(PEER_ID, peer_token)
  data_connection_id = wait_connection(PEER_ID, peer_token)
  wait_open(data_connection_id)
  
  video_redirect = [RECV_ADDR, VIDEO_RECV_PORT]
  audio_redirect = [RECV_ADDR, AUDIO_RECV_PORT]
  video_rtcp_redirect = [RECV_ADDR, VIDEO_RTCP_RECV_PORT]
  audio_rtcp_redirect = [RECV_ADDR, AUDIO_RTCP_RECV_PORT]
  answer(media_connection_id, video_id, video_redirect, audio_id, audio_redirect, video_rtcp_id, video_rtcp_redirect, audio_rtcp_id, audio_rtcp_redirect)
  wait_ready(media_connection_id)
  manage_data_transmission_settings(data_connection_id, data_id, DATA_RECV_ADDR, DATA_RECV_PORT)
  
  puts "Video Recv from #{RECV_ADDR}:#{VIDEO_RECV_PORT}"
  puts "Data Send to #{dest_ip}:#{dest_port}"
  puts "Data Recv from #{DATA_RECV_ADDR}:#{DATA_RECV_PORT}"
  
  sleep(1000)
  #closing
  request(:delete, "/media/connections/#{media_connection_id}")
  request(:delete, "/peers/#{PEER_ID}?token=#{peer_token}")
~~~

最初に, Gateway Serverを立ち上げる.

    ./gateway_linux_arm

ディレクトリを移動

    cd skyway-webrtc-gateway/samples

[サイト](https://qiita.com/A-Kira/items/b26b82ee488384b302ad)で取得したAPI Keyを下記コマンドで入力

    export API_KEY="YOUR KEY"

最後に, 上記のプログラムを実行する. なお, peer部分はpeerなので何でも良い.

    ruby callee.rb peer

一度, 待機させて環境2へ

#### 環境2

環境1と同様に使用するコードを載せておく.

~~~ruby:caller.rb
  require './util.rb'

  SKYWAY_API_KEY = ENV["API_KEY"]
  PEER_ID = "caller"
  TARGET_ID = "callee"
  RECV_ADDR = "127.0.0.1"
  VIDEO_RECV_PORT = 20000
  AUDIO_RECV_PORT = 20001
  VIDEO_RTCP_RECV_PORT = 20010
  AUDIO_RTCP_RECV_PORT = 20011
  
  DATA_RECV_ADDR = "127.0.0.1"
  DATA_RECV_PORT = 10001
  
  #connect to skyway server
  peer_token = create_peer(SKYWAY_API_KEY, PEER_ID)
  #port open request for sending data
  (video_id, video_ip, video_port) = create_media(true)
  (audio_id, audio_ip, audio_port) = create_media(false)
  (video_rtcp_id, video_rtcp_ip, video_rtcp_port) = create_rtcp()
  (audio_rtcp_id, audio_rtcp_ip, audio_rtcp_port) = create_rtcp()
  (data_id, dest_ip, dest_port) = create_data
  
  video_redirect = [RECV_ADDR, VIDEO_RECV_PORT]
  audio_redirect = [RECV_ADDR, AUDIO_RECV_PORT]
  video_rtcp_redirect = [RECV_ADDR, VIDEO_RTCP_RECV_PORT]
  audio_rtcp_redirect = [RECV_ADDR, AUDIO_RTCP_RECV_PORT]
  media_connection_id = call(PEER_ID, peer_token, TARGET_ID, video_id, video_redirect, audio_id, audio_redirect, video_rtcp_id, video_rtcp_redirect, audio_rtcp_id, audio_rtcp_redirect)
  data_connection_id = connect(peer_token, PEER_ID, TARGET_ID, data_id, DATA_RECV_ADDR, DATA_RECV_PORT)
  wait_ready(media_connection_id)
  wait_open(data_connection_id)
  
  puts "Video Send to #{video_ip}:#{video_port}"
  puts "Data Send to #{dest_ip}:#{dest_port}"
  puts "Data Recv from #{DATA_RECV_ADDR}:#{DATA_RECV_PORT}"
  
  sleep(100000)
  #closing
  request(:delete, "/media/connections/#{media_connection_id}")
  request(:delete, "/peers/#{PEER_ID}?token=#{peer_token}")
~~~

環境1と同じ手順である.

Gateway Serverを立ち上げる.

    ./gateway_linux_arm

ディレクトリを移動

    cd skyway-webrtc-gateway/samples

[サイト](https://qiita.com/A-Kira/items/b26b82ee488384b302ad)で取得したAPI Keyを下記コマンドで入力

    export API_KEY="YOUR KEY"

最後に, 上記のプログラムを実行する. なお, peer部分は環境1と必ず同じにすること.

    ruby callee.rb peer

すると, 下記のようにデバッグされれば正常に動作している. なお, ポート番号は変動するため下記と違っていても問題ない.

~~~:環境1
Video Recv from 127.0.0.1:20000
Data Send to 127.0.0.1:10002
Data Recv from 127.0.0.1:50001
~~~
~~~:環境2
Video Send to 127.0.0.1:50005
Data Send to 127.0.0.1:10001
Data Recv from 127.0.0.1:50001
~~~

あとは, 指定されているポートにUDPでパケットを送ってやれば良い. 試しに下記コマンドを記しておく.

~~~:環境1
nc -u -l 10002
~~~

~~~:環境2
nc localhost -u 50001
~~~

環境1側でhello worldと入力し, 環境2側で出力されていれば問題ない.

同様にビデオ側も

~~~:環境1 受信
    gst-launch-1.0 udpsrc port=20000 caps="application/x-rtp,payload=(int)100" ! rtpjitterbuffer latency=500 ! rtph264depay ! avdec_h264 output-corrupt=false ! videoconvert ! fpsdisplaysink sync=false

~~~
~~~:環境2 送信
    gst-launch-1.0 autovideosrc name=src0 ! video/x-raw,width=640,height=480 ! videoconvert ! x264enc bitrate=90000 pass=quant quantizer=25 rc-lookahead=0 sliced-threads=true speed-preset=superfast sync-lookahead=0 tune=zerolatency ! rtph264pay pt=100 mtu=1400 config-interval=3 ! udpsink port=50005 host=127.0.0.1 sync=false
~~~

そして, 環境1側でビデオ映像が流れるはずである.

#### まとめ

今回は, こんなにも便利に使用出来るWebRTC GatewaysであるSkyway Gatewayの記事が少なかったので記載した. 今後も, WebRTCに関連した記事や技術記事を上げていこうと思う.