0. 前置き
WebRTC サーバである Janus (読み: ヤヌス) をインストールします。
WebRTC は簡単に言うと、音声や動画を中継するシステムです。
Janus のクライアントアプリはサンプルが提供されています。
本稿では Janus を LAN (192.168.xx.xx) で稼働させ、サーバとして Linux を、
クライアントとしてスマートフォンでサンプルを動作させることを前提とします。
(対応確認のために PC の Web ブラウザも使用しています)
LAN で WebRTC を使用する場合はスマートフォンの対応に偏りがあり、
すべてのスマートフォンで使用できるわけではなく、Firefox や Safari ではマイクやカメラが許可されません。
マイク / カメラ入力の対応状況 (LAN)
動作可否 OS / 基本ソフト Web ブラウザ 備考 ○ Android 15 Chrome 147.0.7727.137 OK 問題なし × Firefox 150.0.1 マイク / カメラ ともにエラー ○ iOS 18.7.8 Chrome 147.0.7727.99 OK 問題なし × Firefox 150.1 マイク / カメラ ともにエラー × Safari/604.1 △ Windows11 Pro 24H2 Chrome 147.0.7727.138 Echo Test はエラー
Audio Room はエラーにならない△ Firefox 150.0.1 △ Microsoft Edge 147.0.3912.98 × macOS Sequoia 15.7.2 Chrome 147.0.7727.138 https: で LAN に接続できない × Firefox 150.0.1 マイク / カメラ ともにエラー × Safari 26.3
Janus のインストール環境
• AlmaLinux release 10.0 (Purple Lion)
(IP アドレス: 192.168.11.20/24)
• Janus version: 1203 (1.2.3)
今回はこれに従う。
1-1. Janus をコンパイルするために開発ツールをインストールする。
$ su1-2. Janus をコンパイルする。
# dnf install -y epel-release
# dnf config-manager --set-enabled crb
# dnf groupinstall -y "Development Tools"
# dnf install -y git wget make cmake gcc gcc-c++ kernel-devel libtool autoconf automake pkgconfig which
# dnf install -y libmicrohttpd-devel jansson-devel libsrtp-devel libnice-devel glib2-devel opus-devel libogg-devel \
libcurl-devel libconfig-devel libwebsockets libwebsockets-devel gengetopt lua-devel
# exit
$ wget https://github.com/meetecho/janus-gateway/archive/refs/tags/v1.2.3.tar.gz1-3. Janus をインストールする。
$ tar xzf v1.2.3.tar.gz
$ cd janus-gateway-1.2.3/
janus-gateway-1.2.3/$ ./autogen.sh
janus-gateway-1.2.3/$ ./configure --prefix=/opt/janus \
--disable-rabbitmq --disable-mqtt --disable-data-channels \
--enable-rest --enable-websockets --enable-recordings
janus-gateway-1.2.3/$ make
janus-gateway-1.2.3/$ su1-4. 動作確認用に RTP (UDP) の使用範囲を狭くする。
janus-gateway-1.2.3/# make install
janus-gateway-1.2.3/# make configs
janus-gateway-1.2.3/# exit
janus-gateway-1.2.3/$ /opt/janus/bin/janus --version
janus-gateway-1.2.3/$ ls -ogh /opt/janus/share/janus/html/demos/ | head
Janus version: 1203 (1.2.3) Janus commit: not-a-git-repo Compiled on: Fri Oct 24 03:28:55 AM JST 2025
janus-gateway-1.2.3/$ cd
total 884K -rw-r--r--. 1 9.9K Oct 25 00:54 admin.html -rw-r--r--. 1 53K Oct 25 00:54 admin.js -rw-r--r--. 1 5.6K Oct 25 00:54 audiobridge.html -rw-r--r--. 1 21K Oct 25 00:54 audiobridge.js drwxr-xr-x. 2 84 Oct 25 00:54 background -rw-r--r--. 1 8.4K Oct 25 00:54 canvas.html -rw-r--r--. 1 25K Oct 25 00:54 canvas.js -rw-r--r--. 1 7.5K Oct 25 00:54 devices.html -rw-r--r--. 1 30K Oct 25 00:54 devices.js
$
動作確認やリバースプロキシをしないなら、この設定は不要。1-5. ファイアウォールを設定する。
$ su
# vim /opt/janus/etc/janus/janus.jcfg
(標準は rtp_port_range = "20000-40000")
…
media: { #ipv6 = true #ipv6_linklocal = true #min_nack_queue = 500 rtp_port_range = "10000-10009" #dtls_mtu = 1200 #no_media_timer = 1 #slowlink_threshold = 4 #twcc_period = 100 #dtls_timeout = 500 # Janus は、キーフレームに関係する NACK キューに対して最適化を行うことができます。 # 具体的には、キーフレームがユーザーに送信される都度に NACK バッファを空にするよう Janus を設定できます。 # これにより、Janus はキーフレームが送信される直前に送信されたパケットに対する NACK 要求を無視できます。 # これは、キーフレームによってユーザーに完全に機能する画像が復元されると想定できるためです。 # (これが、ビデオの再送信が一般的に必要な主な理由です) # この最適化はほとんどの場合正常に動作することが知られていますが、 # 一部の極端な場合は逆効果になる可能性があるため、デフォルトでは無効になっています。 #nack_optimizations = true # もし DSCP パケットのマーキングと優先順位付けが必要なら dscp プロパティを特定の値に設定できます。 # そして Janus は libnice を使用して、すべての送信パケットにその値を設定しようとします。 # 通常は音声、ビデオ、データのいずれを使用ときに応じて異なる値を使用しろと言われていますが、 # Janus ではすべてのピア接続がが束ねられているため、使用できるのは 1 つだけです。 # 詳細については、次の文書を参照してください。 # https://tools.ietf.org/html/draft-ietf-tsvwg-rtcweb-qos-18#page-6 # 意味がわからない場合は、この設定に触れないでください。 #dscp = 46 }…
# exit
$
$ su1-6. Janus を起動する。
# firewall-cmd --permanent --add-port=8080/tcp --add-port=8443/tcp # デモサイト表示用
# firewall-cmd --permanent --add-port=8088/tcp --add-port=8188/tcp # Janus 本体用
# firewall-cmd --permanent --add-port=8089/tcp --add-port=8989/tcp # Janus 本体用 (secure)
# firewall-cmd --permanent --add-port=10000-10009/udp # Janus 本体用
# firewall-cmd --reload
# firewall-cmd --list-ports
# exit
8080/tcp 8088/tcp 8089/tcp 8188/tcp 8443/tcp 8989/tcp 10000-10009/udp
$
$ /opt/janus/bin/janus &
• 起動を確認する。(1)
$ curl -s http://192.168.11.20:8088/janus/info | head
• 起動を確認する。(2)
{ "janus": "server_info", "transaction": "ijB64zwFjbD", "name": "Janus WebRTC Server", "version": 1203, "version_string": "1.2.3", "author": "Meetecho s.r.l.", "commit-hash": "not-a-git-repo", "compile-time": "2025年 10月 25日 土曜日 11:34:16 JST", "log-to-stdout": true,
$ curl -s http://192.168.11.20:8188/ | tidy -q -i 2> /dev/null
<!DOCTYPE html> <html> <head> <meta name="generator" content= "HTML Tidy for HTML5 for Linux version 5.8.0"> <link rel="stylesheet" type="text/css" href="/error.css"> <title></title> </head> <body> <h1>403</h1> </body> </html>
2. 証明書の発行
LAN なので正規の証明書は使用できない。自己発行の証明書を作成する。
2-1. 自己証明書を作成する。
$ su2-2. 証明書を組み込む。
# mkdir -p /opt/janus/etc/janus/certs/
# cd /opt/janus/etc/janus/certs/
/opt/janus/etc/janus/certs/# openssl req -x509 -newkey rsa:2048 -nodes \
-keyout ./janus.key -out ./janus.pem \
-days 3650 -subj /CN=192.168.11.20
/opt/janus/etc/janus/certs/# chmod 600 ./janus.key
/opt/janus/etc/janus/certs/# ls -ogh
/opt/janus/etc/janus/certs/# openssl x509 -in ./janus.pem -text -noout | head
Certificate: Data: Version: 3 (0x2) Serial Number: 5b:3a:a6:de:aa:93:dd:c6:93:ee:50:ae:95:aa:66:eb:c7:c5:7a:5a Signature Algorithm: sha256WithRSAEncryption Issuer: CN=192.168.11.20 Validity Not Before: Nov 10 06:44:14 2025 GMT Not After : Nov 8 06:44:14 2035 GMT
/opt/janus/etc/janus/certs/# cd /opt/janus/etc/janus/2-3. Janus を再起動する。
Janus 全体の設定ファイルに公開鍵ペアのファイル位置を記述する。
/opt/janus/etc/janus/# vim janus.jcfg
• janus.jcfghttp 通信の設定ファイルに公開鍵ペアのファイル位置と https の許可を記述する。
certificates: { cert_pem = "/opt/janus/etc/janus/certs/janus.pem" cert_key = "/opt/janus/etc/janus/certs/janus.key" #cert_pwd = "secretpassphrase" # …… }
/opt/janus/etc/janus/# vim janus.transport.http.jcfg
• janus.transport.http.jcfgwebsocket 通信の設定ファイルに公開鍵ペアのファイル位置と wss の許可を記述する。
general: { #events = true json = "indented" base_path = "/janus" http = true port = 8088 #interface = "eth0" #ip = "192.168.0.1" https = true secure_port = 8089 #secure_interface = "eth0" #secure_ip = "192.168.0.1" #acl = "127.,192.168.0." #acl_forwarded = true #mhd_connection_limit = 1020 #mhd_debug = false } # …… certificates: { cert_pem = "/opt/janus/etc/janus/certs/janus.pem" cert_key = "/opt/janus/etc/janus/certs/janus.key" #cert_pwd = "secretpassphrase" # …… }
/opt/janus/etc/janus/# vim janus.transport.websockets.jcfg
• janus.transport.websockets.jcfg
general: { #events = true json = "indented" #pingpong_trigger = 30 #pingpong_timeout = 10 ws = true ws_port = 8188 #ws_interface = "eth0" #ws_ip = "192.168.0.1" #ws_unix = "/run/ws.sock" wss = true wss_port = 8989 #wss_interface = "eth0" #wss_ip = "192.168.0.1" #wss_unix = "/run/wss.sock" #ws_logging = "err,warn" #ws_acl = "127.,192.168.0." #ws_acl_forwarded = true } # …… certificates: { cert_pem = "/opt/janus/etc/janus/certs/janus.pem" cert_key = "/opt/janus/etc/janus/certs/janus.key" #cert_pwd = "secretpassphrase" # …… }
• Janus を停止する。2-4. デフォルトルートの変更について (必要なら)
/opt/janus/etc/janus/# ps ax | grep janus
/opt/janus/etc/janus/# kill 159676
159676 pts/0 Sl 0:00 /opt/janus/bin/janus ← これ 159700 pts/0 S+ 0:00 grep --color=auto janus
(プロセスが 1 つしかないと分かっているなら pkill janus でも可)
• Janus を起動する。(公開鍵を root で作成したため root で起動する)
/opt/janus/etc/janus/# /opt/janus/bin/janus &
/opt/janus/etc/janus/# exit
$
起動時のメッセージが以下のように表示される。
Using 192.168.11.20 as local IP... はデフォルトルートを指しているので、
これを変更する場合は (設定ファイルではなく) OS のデフォルトルートを変更する。
Janus version: 1203 (1.2.3) Janus commit: not-a-git-repo Compiled on: 2025? 10? 25? ??? 11:34:16 JST Logger plugins folder: /opt/janus/lib/janus/loggers [WARN] Couldn't access logger plugins folder... --------------------------------------------------- Starting Meetecho Janus (WebRTC Server) v1.2.3 --------------------------------------------------- Checking command line arguments... Debug/log level is 4 Debug/log timestamps are disabled Debug/log colors are enabled Adding 'vmnet' to the ICE ignore list... Using 192.168.11.20 as local IP... ← これはデフォルトルート Token based authentication disabled Initializing recorder code RTP port range: 10000 -- 10009 ……
3. 動作確認 (http / https)
3-1. Linux クライアントから動作確認する。
トランザクションを生成する。3-2. Windows クライアントから動作確認する。
$ curl -k -X POST https://192.168.11.20:8089/janus \
-H 'Content-Type: application/json' \
-d '{"janus":"create", "transaction":"test1"}'
{ "janus": "success", "transaction": "test1", "data": { "id": 0123456789012345 ← 生成されたトランザクション ID (毎回異なる値) } }
トランザクションにプラグインを接続する。(上記で生成されたトランザクション ID を指定)
$ curl -k -X POST https://192.168.11.20:8089/janus/0123456789012345 \
-H 'Content-Type: application/json' \
-d '{"janus":"attach", "transaction":"test2", "plugin":"janus.plugin.echotest"}'
{ "janus": "success", "session_id": 0123456789012345, "transaction": "test2", "data": { "id": 1123456789012345 } }
エラーにならなければ OK
この例では二つとも "janus": "success" になっている。
Windows で標準の curl は異常なので正常へ変更してから実行する。
PoorShell ではアホみたいにダブルクォートを記入しなければならない。
− □ × >_ Windows PowerShell × + | ∨
Windows PowerShell Copyright (C) Microsoft Corporation. All rights reserved. 新機能と改善のために最新の PowerShell をインストールしてください!https://aka.ms/PSWindows PS C:\> # トランザクションを作成する PS C:\> curl -k -X POST https://192.168.11.20:8089/janus ` -H 'Content-Type: application/json' ` -d '{"""janus""":"""create""","""transaction""":"""test1"""}' ⏎ { "janus": "success", "transaction": "test1", "data": { "id": 2123456789012345 ← 生成されたトランザクション ID (毎回異なる値) } } PS C:\> # トランザクションにプラグインを接続する (上記で生成されたトランザクション ID を指定) PS C:\> curl -k -X POST https://192.168.11.20:8089/janus/2123456789012345 ` -H 'Content-Type: application/json' ` -d '{"""janus""":"""attach""", """transaction""":"""test2""", """plugin""":"""janus.plugin.echotest"""}' ⏎ { "janus": "success", "session_id": 2123456789012345, "transaction": "test2", "data": { "id": 3123456789012345 } } PS C:\> exit ⏎
エラーにならなければ OK
この例では二つとも "janus": "success" になっている。
4. 動作確認 (websocket wss)
websocket は tcp だがプロトコルが単純でないため curl や wsbsocat では動作確認できない。
Python で動作確認する。
4-1. Linux クライアントから動作確認する。
4-1-1. Python のモジュール websocket-client をインストールする。4-2. Windows クライアントから動作確認する。
websocket と websocket-client の衝突を回避するために、両方を4-1-2. Python で動作確認する。
一旦アンインストールしてから websocket-client をインストールし直す。
(なぜか、両方とも同じモジュール名「websocket」を名乗っている)
$ pip uninstall -y websocket websocket-client
$ pip install websocket-client
$ python << EOF | head
import websocket, ssl, uuid, json # WebSocket で接続 (証明書の整合性を無視) ws = websocket.create_connection( "wss://192.168.11.20:8989/janus", sslopt={"cert_reqs": ssl.CERT_NONE}, subprotocols=["janus-protocol"] ) # info リクエストを送信 tran_id = str(uuid.uuid4()) # トランザクション ID を生成 ws.send(json.dumps({"janus": "info", "transaction": tran_id})) response = ws.recv() # 応答を受信 ws.close() print(response) # 応答を出力 EOF結果表示はこんな感じ
{ "janus": "server_info", "transaction": "39705530-3dfb-4c1c-9c95-2b79be0caf1f", "name": "Janus WebRTC Server", "version": 1203, "version_string": "1.2.3", "author": "Meetecho s.r.l.", "commit-hash": "not-a-git-repo", "compile-time": "2025年 11月 17日 月曜日 11:33:34 JST", "log-to-stdout": true,
4-2-1. Python のモジュール websocket-client をインストールする。
4-2-2. Python で動作確認する。
− □ × >_ Windows PowerShell × + | ∨
Windows PowerShell Copyright (C) Microsoft Corporation. All rights reserved. 新機能と改善のために最新の PowerShell をインストールしてください!https://aka.ms/PSWindows PS C:\> # pip を最新バージョンにする PS C:\> python -m pip install --upgrade pip ⏎ Requirement already satisfied: pip in c:\users\who\appdata\local\programs\python\python313\ lib\site-packages (25.3) PS C:\> # websocket, websocket-client をアンインストールする PS C:\> pip uninstall -y websocket websocket-client ⏎ Found existing installation: websocket 0.2.1 Uninstalling websocket-0.2.1: Successfully uninstalled websocket-0.2.1 WARNING: Skipping websocket-client as it is not installed. PS C:\> # websocket-client をインストールする PS C:\> pip install websocket-client ⏎ Collecting websocket-client Using cached websocket_client-1.9.0-py3-none-any.whl.metadata (8.3 kB) Using cached websocket_client-1.9.0-py3-none-any.whl (82 kB) Installing collected packages: websocket-client Successfully installed websocket-client-1.9.0 PS C:\> exit ⏎
− □ × >_ Windows PowerShell × + | ∨
Windows PowerShell Copyright (C) Microsoft Corporation. All rights reserved. 新機能と改善のために最新の PowerShell をインストールしてください!https://aka.ms/PSWindows PS C:\> @" import websocket, ssl, uuid, json # WebSocket で接続 (証明書の整合性を無視) ws = websocket.create_connection( "wss://192.168.11.20:8989/janus", sslopt={"cert_reqs": ssl.CERT_NONE}, subprotocols=["janus-protocol"] ) # info リクエストを送信 tran_id = str(uuid.uuid4()) # トランザクション ID を生成 ws.send(json.dumps({"janus": "info", "transaction": tran_id})) response = ws.recv() # 応答を受信 ws.close() print(response) # 応答を出力 "@ | python | Select-Object -First 10 ⏎ ↓ 実行結果 ↓
{ "janus": "server_info", "transaction": "d1ab0781-964d-4e52-9ede-757e71851940", "name": "Janus WebRTC Server", "version": 1203, "version_string": "1.2.3", "author": "Meetecho s.r.l.", "commit-hash": "not-a-git-repo", "compile-time": "2025年 11月 17日 月曜日 11:33:34 JST", "log-to-stdout": true,
PS C:\> exit ⏎
5. デモサーバを起動
Janus は通常の Web サーバを提供しないため、他の手段で Web サーバを用意する必要がある。
5-1. 設置手順に従ったデモサーバの場合。(http)
5-1-1. 対象ディレクトリへ移動5-2. https を使ったデモサーバの場合。
janus-gateway-1.2.3/$ cd /opt/janus/share/janus/html/5-1-2. ポート 8080 でデモサーバを起動
/opt/janus/share/janus/html/$ python -m http.server 8080 &5-1-3. w3m でデモサーバをアクセス (http)
/opt/janus/share/janus/html/$ w3m -dump http://192.168.11.20:8080/demos/ | head
python -m http.server からの出力 (上記 5-1-2 の出力)
192.168.11.20 - - [07/Nov/2025 16:06:35] "GET /demos/ HTTP/1.0" 200 -
w3m の表示
Fork me on GitHub Janus WebRTC Server: Demo Tests Plugin demos Echo Test A simple Echo Test demo, with knobs to control the bitrate. Streaming A media Streaming demo, with sample live and on-demand streams. Video Call A Video Call demo, a bit like AppRTC but with media passing
5-2-1. 対象ディレクトリへ移動
janus-gateway-1.2.3/$ cd /opt/janus/share/janus/html/5-2-2. ポート 8443 でデモサーバを起動
公開鍵を root で作成したため root で起動する)5-2-3. w3m でデモサーバをアクセス (https)
/opt/janus/share/janus/html/$ su
/opt/janus/share/janus/html/# (python << EOF
import http.server, ssl SERV_PORT = ('0.0.0.0', 8443) crt = '/opt/janus/etc/janus/certs/janus.pem' key = '/opt/janus/etc/janus/certs/janus.key' # 証明書のコンテキストを用意 context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) context.load_cert_chain(certfile=crt, keyfile=key) # HTTP ハンドラを用意 class Handler(http.server.SimpleHTTPRequestHandler): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # HTTP サーバを作成して HTTPS にラップ httpd = http.server.HTTPServer(SERV_PORT, Handler) httpd.socket = context.wrap_socket(httpd.socket, server_side=True) print(f'Serving HTTPS on {SERV_PORT}') httpd.serve_forever() EOF ) &/opt/janus/share/janus/html/# exit
/opt/janus/share/janus/html/$
/opt/janus/share/janus/html/$ yes | w3m -dump https://192.168.11.20:8443/demos/ | head
自己証明書を使用しているので以下の警告(質問)が表示される。ここで y を答えるため yes コマンドを使用している。
• self-signed certificate: accept? (y/n)
python << EOF からの出力 (上記 5-2-2 の出力)
192.168.11.20 - - [16/Nov/2025 16:15:35] "GET /demos/ HTTP/1.0" 200 -
w3m からの出力
Fork me on GitHub Janus WebRTC Server: Demo Tests Plugin demos Echo Test A simple Echo Test demo, with knobs to control the bitrate. Streaming A media Streaming demo, with sample live and on-demand streams. Video Call A Video Call demo, a bit like AppRTC but with media passing
6. 動作確認 (スマートフォン)
デモサーバ https://192.168.11.20:8443/demos/ を下記ブラウザで開き、動作確認する。
LAN での動作確認なので、それぞれの端末は当該 LAN に (Wifi で) 接続しておく。
スマートフォン ブラウザ Android 15 Chrome 147.0.7727.137 iOS 18.7.8 Chrome 147.0.7727.99
6-1. Echo Test (独立テスト)
スマートフォンを 1 台用意し Echo Test ページから ボタンをクリックする。6-2. Audio Room (相互テスト)
(Echo Test は https://…/demos/echotest.html)
⇒ マイクで入力した音声がエコーバックされる。
スマートフォンを 2 台用意し Audio Room ページから ボタンをクリックする。
(Audio Room は https://…/demos/audiobridge.html)
ユーザ名 (display name) を入力し ボタンをクリックする。
(Audio Room は 1 つだけ。個人情報はしゃべらないように)
⇒ マイクで入力した音声が参加者に流れる。(自分へはエコーバックされない)