WebRTC配信技術 "WHIP" で遊ぶ

はじめに

当ポストは、低遅延配信の技術であるWHIP(WebRTC-HTTP Ingestion Protocol)を自分で動かしてみたい方へ向けた記事となります。 WebRTCを利用した配信映像の集信プロトコルであるWHIPは現在Internet-Draftではありますが、配信技術者やWebRTC技術者の注目を得て、実際に動かせる環境が整ってきました。 当ポストでは、WHIPが動く環境を作り、自前のWebRTCスタックをWHIPで使う簡単な方法を紹介します。

とはいえInternet-Draftということもあり、「WebRTCなら聞いたことあるけど、WHIPって何?配信とWebRTCが関係あるの?」という方も多いと思いますので、最初はWHIPの紹介から入りたいと思います。

WHIPとは

WHIPは、WebRTCを利用したインジェストのためのHTTPSベースのシグナリングプロトコルです。 インジェストというのは、放送機器からメディアサーバーに映像音声を送信することを言います。 人によっては"アップストリーム"、"打ち上げ"などの方が馴染み深い言葉かもしれません。 つまりWHIPは、誤解を恐れずにいうとRTMPのような配信のアップストリームにWebRTCを使おうといった試みです。

さらにWebRTCは、リアルタイム性を重視した双方向コミュニケーションの技術スタックです。 Webで使えるビデオ通話の技術ですね。 WebRTCの実体は大別して以下の特徴を持ったプロトコルセットです。

  • リアルタイムメディア伝送のためのワイヤプロトコルのセット
  • メディアストリームを設定・制御するための記述プロトコル(SDP)

これらにより、どうやって端末間の通信を確立するか?どうやってパケットをほどき、どうやって映像・音声として解釈するか?といった課題を柔軟に解決しています。 最近はこのリアルタイム性やセッションの自由度などから、大規模配信のメカニズムとしてWebRTCの利用が人気を集めており、いくつかの企業がWebRTCベースのメディア配信ネットワークを展開しています。

さて、WebRTCをアップストリームに利用しようとしたとき、ひとつの課題が浮き上がります。 WebRTCを利用するサービスでは、それぞれが独自にシグナリングプロトコルを開発する必要があるということです。 セッションに必要な情報は用途によって異なるという考え方のため、WebRTCではセッション確立までのプロトコルが規定されていないことが理由です。 ただし放送の場合はメディアを送るためにエンコーダと呼ばれる専用の機器を用いることが多いため、WebRTCを利用したい場合、サービス毎に専用機器へシグナリングプロトコルを実装する必要があります。

そういった背景で立ち上がったのがIETFのWISH(WebRTC Ingest Signaling over HTTPS) WGであり、現在は放送機器からWebRTCメディアサーバーへのセッションを確立するためのシグナリングプロトコルである WebRTC-HTTP ingestion protocol (WHIP) がInternet-Draftとして提案されています。 このWHIPというプロトコルで、どういった順番でHTTPリクエストを出して、どういった内容のHTTPレスポンスを返してね、といったことが決められている訳です。

WHIPを体験してみる

WHIPを体験してみるという場合でも、WHIPをこれから実装してみるという場合でも、まずは今実際に動作するソフトウェアのことを知っておくと役に立ちます。 簡単に、WHIPクライアントおよびWHIPサーバーの紹介と動かし方の解説をしたいと思います。

これ以降、配信映像の視聴方法としてブラウザは最新版のGoogle Chromeを推奨します。

simple-whip-server (WHIP server)

手軽に試せるWHIPサーバーは、janus-gatewayを用いたmeetecho/simple-whip-serverがあります。 これはWHIPサーバーのエンドポイントになりつつ、janus-gatewayのAPIを操作してビデオルーム上にWHIPクライアントのメディアを流してくれます。 simple-whip-serverの動作条件としてHTTP, WebSocketを有効にしたjanus-gatewayが必要なので、まずはそのセットアップから解説します。

janus-gatewayのセットアップ

WebSocketを有効にしたjanus-gatewayをビルドします。 まずjanus-gatewayの依存解決を参考に、依存環境を整えてください。 今回はREST APIとWebSocket APIを利用するので、最低限必要なのは当該ページのリストの内以下のものになります。

  • Jansson
  • libconfig
  • libnice
  • OpenSSL
  • libsrtp
  • libmicrohttpd
  • libwebsockets
  • cmake

環境が揃ったら、リポジトリをcloneしてautogen.shを実行します。

$ git clone --depth 1 https://github.com/meetecho/janus-gateway
$ cd janus-gateway
$ sh autogen.sh

するとconfigureという実行可能なスクリプトが生成されるので、これを実行します。 ここでjanusの関連ファイルのビルド先を--prefixで指定できます。 デフォルトが/opt/janus以下なので、適当に設定します。 また、configureを実行したらMakefileが生成され、makeできるようになるので実行します。

$ ./configure --prefix=/usr/local/janus --enable-websockets
$ make

ここで、macOSを利用している方のみ確認していただく内容があります。 src/transports/libjanus_websockets.laというファイルの中身を読んで、dlnameの値を確認します。

# The name that we can dlopen(3).
dlname='libjanus_websockets.1.dylib'

上記のように、libjanus_websockets.<version>.dylibのフォーマットで書き込まれていると思います。 このversionの数字を覚えておいて、次はsrc/janus.cのプリプロセッサを確認します。 以下のようにライブラリの拡張子を指定している場所があります。

#ifdef __MACH__
#define SHLIB_EXT "0.dylib"
#else

この0.dylibを先ほど確認したversionの数字となるように編集してください。 例えば、libtool 2.4.7な私のmacOS環境で生成したファイルはlibjanus_websockets.1.dylibとなっていたので、以下のようにしておきます。

#ifdef __MACH__
#define SHLIB_EXT "1.dylib"
#else

準備ができたらmake installと、janus関連の設定ファイルを有効化するためにmake configsを実行します。

$ make install && make configs

このあとクライアント側で映像コーデックにVP8とH.264を利用したいので、設定ファイルを一部修正します。 <prefix>/etc/janus/janus.plugin.videoroom.jcfgを編集し、room-1234の中のvideocodecの値をvp8,h264に変更してください。

room-1234: {
    description = "Demo Room"
    secret = "adminpwd"
    publishers = 6
    bitrate = 128000
    fir_freq = 10
    #audiocodec = "opus"
    videocodec = "vp8,h264" # もともとは"vp8"のみで、コメントアウトされている
    record = false
    #rec_dir = "/path/to/recordings-folder"
}

この状態でjanusを実行して、最終的に以下のようなログが出れば成功です。

$ <prefix>/bin/janus

(省略)

Loading transport plugin 'libjanus_http.1.dylib'...
HTTP transport timer started
HTTP webserver started (port 8088, /janus path listener)...
JANUS REST (HTTP/HTTPS) transport plugin initialized!

このままjanusを実行させておいてください。以降の試験で利用します。 ついでに、別のプロセスでjanusのビデオルームをブラウザで開けるように、janus-gatewayのhtmlディレクトリ以下にあるデモHTMLをホストしてください。

$ cd html
$ python -m http.server

下記URLが開ければ準備完了です。

simple-whip-serverのセットアップ

次にWHIPのサーバーとなるsimple-whip-serverを用意します。 Node.jsが必要になります。

$ git clone --depth 1 https://github.com/meetecho/simple-whip-server
$ cd simple-whip-server
$ npm i

これで準備ができました。 REST API, WebSocketが有効なjanus-gatewayのプロセスが立ち上がっていれば、npm run startを実行すると以下のようなログが出力され、simple-whip-serverが実行されます。

$ npm run start

> janus-whip-server@0.0.1 start
> DEBUG=whip:*,-whip:debug,janus:*,-janus:debug,-janus:vdebug node src/server.js

[1. Janus]
Connecting to Janus: { address: 'ws://127.0.0.1:8188' }
  janus:info Connecting to ws://127.0.0.1:8188 +0ms
  janus:info Janus WebSocket Client Connected +13ms
  janus:info Janus session ID is 1549944700292951 +3ms
  janus:info Janus instance version: 1.1.3 (multistream) +2ms
  whip:info Connected to Janus: ws://127.0.0.1:8188 +0ms
[2. WHIP REST API]
WHIP REST API listening on *:7080
WHIP server prototype started!
[ 'Janus OK', 'WHIP REST API OK' ]

これでWHIPのサーバーサイドは準備できました。 ここまでで、以下の3つのアプリケーションが動作していることを前提として進めます。

  • janus-gateway
  • janus-gateway/htmlの静的サーバー
  • simple-whip-server

次に、janusのビデオ会議の部屋を作りつつ、WHIPクライアントが配信するためのリソースを作っておきましょう。

$ curl -H 'Content-Type: application/json' -d '{"id": "abc123", "room": 1234}' http://localhost:7080/whip/create

simple-whip-serverが動いているときに http://localhost:7080 を開くことでWHIP配信先の管理ができるのですが、ここでEndpoint ID=abc123でありVideoRoom=1234であるエンドポイントが追加されていることを確認できます。 この状態で http://localhost:8000/videoroomtest.html を開いて、Startボタンを押し、ルーム名に1234を入力してJoin the roomボタンを押すことで、このあとWHIPクライアントから配信した映像を視聴する画面に移ることができます。

WHIPサーバーを立て、WHIPクライアントが配信した映像を視聴する準備が整ったので、以降は三種類のWHIPクライアントを紹介します。

simple-whip-client (WHIP client)

WHIPのクライアント、つまりインジェストを行うソフトウェアとして最初に紹介するのは、simple-whip-serverと対になるmeetecho/simple-whip-clientです。 かなりシンプルな実装であり、自作のWHIPサーバーの細かい検証をしたい場合では一番扱いやすいと思います。 依存環境として、以下が必要になります。

  • pkg-config
  • GLib
  • libsoup~=2.4
  • GStreamer>=1.16
  • gst-plugins-base
  • gst-plugins-bad

libsoup~=2.4について、今libsoupを入れようとすると3系が入るので、2系を明示的にインストールするよう注意してください。 また、3系がシステムデフォルトになっている場合、ビルド時にpkg-configの参照先が2系になるように注意してください。 例えば私の環境では、ビルド時の環境変数PKG_CONFIG_PATH/usr/local/libsoup/2.74.2/lib/pkgconfigを追加しました。 simple-whip-clientのセットアップは以下です。

$ git clone --depth 1 https://github.com/meetecho/simple-whip-client
$ cd simple-whip-client
$ make

makeだけでwhip-clientというバイナリが作成されます。 実行する際は、-Aおよび-Vオプションで配信する音声映像としてGStreamerのパイプラインを入力できます。

GST_DEBUG=WARNING ./whip-client -u "http://localhost:7080/whip/endpoint/abc123" \
    -A "audiotestsrc ! audioconvert ! audioresample ! queue ! opusenc ! rtpopuspay pt=100 ssrc=1 ! queue ! application/x-rtp,media=audio,encoding-name=OPUS,payload=100" \
    -V "videotestsrc ! videoconvert ! queue ! vp8enc deadline=1 ! rtpvp8pay pt=96 ssrc=2 ! queue ! application/x-rtp,media=video,encoding-name=VP8,payload=96"

起動オプションも豊富で、WHIPのInternet-Draftにあるoptionalな実装を無効にしたりできます。 起動オプションはコマンドライン引数なしの実行か、-hオプションをつけて実行することで確認できます。

GStreamer (WHIP client)

ソフトウェアの音声/映像処理によく使われるGStreamerでも、バージョン1.22からWHIPがサポートされました。 利用するには、gst-plugins-rsが必要です。 ここで追加されたwhipsinkを利用すれば、以下のようなパイプラインでgstreamerから映像配信ができます。

gst-launch-1.0 whipsink name=whip whip-endpoint="http://localhost:7080/whip/endpoint/abc123" \
    audiotestsrc ! audioconvert ! opusenc ! rtpopuspay pt=100 ! queue ! "application/x-rtp,media=audio,encoding-name=OPUS,payload=100" ! whip. \
    videotestsrc ! videoconvert ! queue ! vp8enc deadline=1 ! rtpvp8pay pt=96 ! queue ! "application/x-rtp,media=video,encoding-name=VP8,payload=96" ! whip.

OBS Studio (WHIP client)

OBS Studioでは現在PRのDraftという状況ですが、Sean-Der/obs-studioでWHIPを使うプラグインが開発されています。 PRは#7926で、バイナリが欲しい場合は自分でビルドする他、OBS StudioではGitHub Actionsでのビルドが行われているので自身の環境にあったバイナリをArtifactからダウンロードすることもできます。 下記ページの最新のビルドから、Artifactsにアップロードされているファイルをダウンロードできます。 macos-x86_64のように対応するOS・CPUアーキテクチャがファイル名に記されているので、自分の環境にあったパッケージをダウンロードしてください。

自分でビルドするか、Actionsからダウンロード・インストールしたOBS Studioを利用すると、配信先の設定の選択肢にWHIPがあります。 これを選択し、サーバーにhttp://localhost:7080/whip/endpoint/abc123を入れることでOBS StudioからWHIPでの配信ができます。

おわりに

当ポストではWHIPのサーバーとしてsimple-whip-serverを、クライアントとしてsimple-whip-client・GStreamer 1.22・OBS Studioを紹介しました。 この記事がWHIPへの興味に繋がったら幸いです。

最後に宣伝をさせてください。

NTT ComにはSmart vLiveというサービスがあり、実はWebRTCを利用した配信をしています。 インターネット配信におけるWebRTCのリアルタイム性に注目しており、インジェスト側ではなくメディアを配信する側でWebRTCを利用しています。 本ポストでは「なんで配信をWebRTCでしたいの?」という論点を取り上げませんでしたが、Smart vLiveの事例を見ていただくとどんな利用シーンがあるのかイメージしやすいかと思います。 私が個人的に好きな事例はオークション/ライブコマースです。 リアルタイム性がそのまま価値につながる利用シーンの1つだと思います。

オンサイトとリモートの時間的優位性を極力減らしたときにどんな価値が生まれるのか? 未来の当たり前に向かって、技術開発はもちろん、こういった視点での価値創出も一緒に取り組んでくれる仲間をNTT Comでは募集しています。 WebRTC配信技術の開発をしている私のチームの募集ポストはこちらになります。

© NTT Communications Corporation All Rights Reserved.