Intel Collaboration Suite for WebRTC Conference Server を新しくする

3 3月

Intel Collaboration Suite for WebRTC Conference Server を利用しています(過去記事)。バージョン 3.5 を利用していたのですが,最新のもの(4.3)にしたいと考えています。まずは, Cent OS の用意。

USB メモリの作り方は,このページに従いました。Ubuntu 18 上で,下記のコマンドを実行します。USB へのアクセスに root の権限が必要だった。

dd if=CentOS-8.1.1911-x86_64-dvd1.iso of=/dev/sde bs=256M

私の環境では USB メモリが /dev/sde だった。時間は1時間以上かかりました。OS は最初,最新版を試しましたが,上手くいかなかったので,結局 version 7 系の最終版 7.7 になりました。その理由は,Guest Addition のインストールなどが上手くいかなかったことも在るのですが,WebRTC Conference Server 本体をインストールするとき( ./init-all.sh –deps を実行する時)mongoDB や RabbitMQ などが自動でインストールされなかったためです(たぶんされなかったと思う)。7.7 を利用するなら,前もって準備することは ドキュメント にあることだけで済みました。

まずは virtualbox で試します。Guest Addition のインストールは,あらかじめ開発ツール等を入れておいたので,特に問題なし。マウス統合も上手くいきました。versiotn 7.5 を virtualbox で使う際に問題になっていたマウスクリックに反応しなくなる問題も生じません。これがあるので最新版の CentOS を試そうと考えていたのですが。

node.js のインストールは以前と同じく /opt/ の中に置きました。version は 8.15.0 です。.bashrc に下記のパスを加えます。root ユーザーのパスは,su コマンドでユーザーを切り替えるとき,一般ユーザーからパスの設定が引き継がれるようで,とくに設定する必要はないようです。

export PATH=/opt/node-v8.15.0/bin:$PATH

そういえば,ドキュメントの 2.3.4 Deploy Cisco OpenH264* Library のところを飛ばしてしまった。問題ないのかな?

先に ffmpeg を入れます。これは本体をインストールする際にも,インストールされているようなのですが,ドキュメントの 2.3.5 にある,下記のコマンドを実行する際に,失敗して ffmpeg_libfdkaac_lib フォルダー内にファイルが数個しか作成されなかったことが多くあって,それを避けるために先に ffmpeg をインストールしています。そのあとで下記のコマンドを実行したら 24個のファイルが作成されました。インストール方法はここにあるとおりにやりました。いくらか事前にリポジトリーなど設定しておく必要があるようです。

compile_ffmpeg_with_libfdkaac.sh

あとは本体のインストールですが,先にファイヤーウォールを開けておきます。CentOS はデフォルトでポートが閉じています。コマンドだけですが,下記を打ちます(たぶん su で)。

firewall-cmd --permanent --add-port=3004/tcp
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --permanent --add-port=30000-60000/udp

udp のポートはデフォルトでは決められていないようです。webrtc_agent/agent.toml に設定があります。the webrtc port range のところを合わせて設定しました。

設定を反映させるために,ファイヤーウォールを再起動します。

firewall-cmd --reload

確認するには,下記。

firewall-cmd --list-all

さて,本体のインストールです。su で実行したほうが良いです。

./bin/init-all.sh --deps

以前のバージョンと異なり途中で,MongoDB や RabbitMQ に関して入力の要求がありました。ユーザー名やパスワードを入力する必要があります。その場で決めるだけですが。次回 init-all.sh を実行する際には,これらのアカウントをアップデートするかどうか質問があります。ただこれは,入力をしなくてもしばらくしたら自動的に先に進んでいくようです(アップデートすると逆に危険かも)。

あとは,サーバーを起動するのみ。

./bin/start-all.sh

なんとか動きました。下にキャプチャーをあげます。

きちんとした https サイトではないので,ポートの 3004 と 8080 に許可を与える必要があります。上記のキャプチャーは, chrome で試した画面です。そういえば,今回は設定ファイルを書いたりする作業をしなかった。もちろんドキュメントになかったからなのですが。

iOS で上手く動かない(20200311ちゃんとしたhttpsサイトとして動かしたらiPadで表示ができました。ポート8080への許可が上手く出せなかったのかな?ちゃんとしたhttpsサイトなら許可を出す必要なし。システムバージョン13.3.1です)。edge は動きました。firefox も動いた。

あとは,管理用サイトの設定ですが,これはとくに何かが必要なわけではなく,すでに動いていて,ファイヤーウォールを開けるぐらいでした。ポートは3300です。

レクチャー型の画面の表示です。最初に繋いだ人が大きく表示されます。変更したら再読み込みではなくて,サーバーを再起動する必要があります(./bin/restart-all.sh)。Apply ボタンを押すのも忘れがち。

(20200317)
ソフトウェアのバージョンをあげるので,新しいものに合わせて extras/basic_example 以下を書き直さないといけない。その中の下記の4つのファイルを修正する予定です。

    samplertcservice.js
    pulic/index.html
    public/scripts/index.js
    public/scripts/rest-sample.js

samplertcservice.js はサーバー側のファイルで,他はクライアント側のファイルです。サーバー側の samplertcservice.js を見ると,古いコードを動かすための部分もあって,ひょっとしてそのまま動くのかもしれませんが,新しいのに合わせて書いてみたいと思います。コードを書いていくうえでポイントとなった点を,以下記録します。

まずメッセージの送り方。 conference = new Owt.Conference.ConferenceClient(); で,作成される conference から

    conference.send('xxxxx');

上記でメッセージを送る場合には,接続している全員に送られますが(2番目の引数に id を指定すると特定の人にだけ送られる), rest-sample.js に記述されている機能を利用して送られる,例えば

    send('POST', '/tokens/', body, callback, host);

上記のようなメッセージは samplertcservice.js が受け取って,その返事は送信した人しか受け取りません。最初,これを全員が受け取るものと誤解していた(以前からそうだったとは思うのですが)。

上の図のようなレクチャー型の画面配置では,誰を一番大きなエリアに配置するかをコントロールしたいです。以前は,conference.unpublishというメソッドがあって,いったんunpublishした後,直ぐにconference.publishでつなぎ直すと,配置の順番が最後尾になって,これを参加者全員がやると最初に接続し直した人が先頭に(一番大きなエリア)に配置されました。しかし今のバージョンでは unpublish がない。そこで色々探して,下記の機能を利用しました。

var jsonPatch = [{
	op: 'remove',
	path: '/info/inViews',
	value: 'common'
}];

send('PATCH', '/rooms/' + myRoom + '/streams/' + myStreamId, jsonPatch,

	function (result){

		var jsonPatch = [{
			op: 'add',
			path: '/info/inViews',
			value: 'common'
		}];

		send('PATCH', '/rooms/' + myRoom + '/streams/' + myStreamId, jsonPatch,

			function (result){次の人へ繋ぐ何かをする}
		);		
	}
);

自分自身の映像(myStreamIdで示されるもの)を一旦 remove して,そのあとすぐ add します。これで順番が最後尾になります。あとは次の人にメッセージを送って,同じことを繰り返させます。このとき streamadded 等のイベントは発生しません。これを全メンバーが繰り返すことで,一番大きなエリアに誰を表示するか,コントロールできます。もっと直接的に,レイアウトを変更する方法もドキュメントに書いてあるのですが,使いこなせない。

順番が変ですが,ここで id などの話を書きます。index.js にある下記の部分(一部元のコードから変更)あたりが,会議に参加するところです。createToken のところで myRoom と指定しているのですが,現在はこの中身は空で,空白を送ると samplertcservice.js が ‘sampleRoom’ に置き換えてくれます。

createToken(myRoom, 'user', 'presenter', function(response) {

	console.log(response);

    var token = response;
    conference.join(token).then(resp => {

	console.log(resp);

        myId = resp.self.id;
        myRoom = resp.id;

createToken で返ってくる response は長々しい文字列です。これを次の conference.join で送って,返事 resp もらいます。この時点で会議に参加しているのではと思います。resp の中身を下記にあげます。

resp.id が参加した会議室を示す文字列です。resp.self.id というのが会議の参加者(自分自身)を識別する文字列です。resp.participants には会議の参加者が列挙されています。そこにもちろん自分自身も在ります。remote.streams には会議の参加者が送ってくる映像と,それを合成した映像(の id)が並んでいます。しかし其処に自分自身が送信している映像はありません。まだ送っていないという事もありますが,送り出したあとも表示されなかったはず。remoteStreams を開いてみます。

会議の参加者は2名です。0 番はサーバーで合成された映像の情報です。origin は undefined となっています。1 番はもう一人の参加者の情報です。origin にはその参加者を識別する文字列が表示されていて, id は映像の id です。自分自身の送信映像の id は,conference.publish した後の返事に含まれているので,そこから得られます。サンプルコードでは publication.id ですね。id が多くてわかりずらいですが,id に関してはこんなものかなと思います。

大きく表示する人の映像を選択するために,これまでのアプリでは,会議に参加している個人を表すボタンを並べていました。上の図では7人分のボタンが並んでいます。このボタンをクリックすることで,ボタンに表示された名前の人を大きく表示するようにしていました。個人を示す id そのままでは誰だか分からないので, id を分かり易い名前に対応させることも必要ですが,今回それはサーバー側に記憶させます。下記のようなコードを index.js に追加して,自分の id と,分かり易い名前(myName),送信している映像の id (myStreamId) をサーバーに送ります。

var body = {
  room: myRoom,
  myId: myId,
  myName: tmpStr,
  myStreamId: myStreamId
};

send('POST', '/addUser/', body, function (result){console.log(JSON.parse(result));conference.send('join:' + result);});

上記を受けるサーバー側のコードです。下記を samplertcservice.js に追加します。

var allUser = new Object();

app.post('/addUser', function(req, res) {
	'use strict';
	var room = req.body.room || sampleRoom;
	var myId = req.body.myId;
	var myName = req.body.myName;
	var myStreamId = req.body.myStreamId;

	allUser[myId] = {name:myName, streamId:myStreamId};

	icsREST.API.getStreams(room,
		function(streams) {
			var layoutAry = streams[0].info.layout;

			var response = new Array();

			for (var idx = 0; idx < layoutAry.length; idx = idx + 1) {

				for (let key in allUser) {
					if (layoutAry[idx]['stream'] == allUser[key]['streamId']) {
						response.push({id:key, name:allUser[key]['name'], streamId:allUser[key]['streamId']});
					}
				}
			}

			res.send(response);

		}, function(err) {
			res.send(err);
		}
	);
});

allUser に個人を特定する id をキーとして,分かり易い名前と送信映像の id を保存します。ただし映像が配置されている順番に合わせた情報にしたいです。上記のコードにおいては,表示の順番は icsREST.API.getStreams で得られる streams の中に含まれています。 streams の中を見てみます。

配列なのですが,0番目には合成された映像に関する情報があります。その下は個々の参加者の映像に関するもので,映像の id や,参加者の id が含まれています。0番目を開いてみます。

この中に layout という項目があって,合成画像に配置されている順に,映像の id が並んでいます。この情報をもとに,先のコードでは個々のユーザーの映像の並び順を得ています。このような icsREST.API.getStreams で得られる情報と同じものをクライアント側で得るには,下記のコードでサバーにリクエストを出せば得られます。

var jsonPatch = [{}];

send('GET', '/rooms/' + myRoom + '/streams', jsonPatch,
	function(result){
		console.log(JSON.parse(result));
	}
);

これで,会議の参加者とその並びに関する情報は得られました。参加するときに id と名前と送信映像の id をサバー側に送り,その時同時に他の参加者に新メンバーが参加したことを伝えて,参加者に関する情報を更新させます。参加者の映像の配置を変更した時も,先の layout の情報を参照して,映像の配置の変化を知ることができます。あと,参加者の映像の並びに関する情報を最新のものに保つうえで残った問題は,参加者が不意にブラウザを閉じる場合です。index.js の conference.addEventListener('streamadded', ... のあたりのコードを下記にあげます。

    conference.addEventListener('streamadded', (event) => {
        console.log('A new stream is added ', event.stream.id);
        isSelf = isSelf?isSelf:event.stream.id != publicationGlobal.id;
        subscribeForward && isSelf && subscribeAndRenderVideo(event.stream);
        mixStream(myRoom, event.stream.id, 'common');
        event.stream.addEventListener('ended', () => {
            console.log(event.stream.id + ' is ended.');
        });
    });

追加された映像にイベントリスナーを定義しているところです。これによると映像が中断したら,そのタイミングで何かをすることが可能なのですが,これは実行される時とされない時があって不安定でした。それで,何か他のタイミングを利用できないかと思って探しました。レイアウトの変化を捉えるイベントが利用できると確実に思えます。JavaScript のマニュアルのここにリモートストリームに関するイベントが記述されていて,イベントとして ended とupdated が挙げられています。index.js では function subscribeAndRenderVideo の中の下記のコードの部分かと思われます。

        stream.addEventListener('ended', () => {
            removeUi(stream.id);
            $(`#${stream.id}resolutions`).remove();
        });
        stream.addEventListener('updated', () => {
            // Update resolution buttons
            $p.children('button').remove();
            createResolutionButtons(stream, subscribeDifferentResolution);
        });

レイアウトに関するイベントとしてはマニュアルのここに layoutchange というイベントがあります。どうもこれは関連しているというふうに読み取れるので上のコードに下記のコードを継ぎ足してみました。

        stream.addEventListener('layoutchange', (resp) => {
		console.log(resp);
        });

このイベントは存在していて,参加者がブラウザを切るときには必ず反応します。参加者が増えるときにも減るときにも,とにかくレイアウトが変化する際には必ずキャッチできるので非常に利用しやすい。これで,現在の参加者情報を常に最新のものに保つことが可能となりました。

録画の機能を加えます。以前から利用していたのですが,これもかなり変化している模様。サンプルが無く,マニュアルが分かりにくい。動画の情報(media: object(MediaSubOptions))をどのように与えれば良いのかが分からない。まだ利用したことがない rest.js を見ていたら 1253 行あたりに,それらしいものがあって,その記述に沿って下記のように与えてみたら録画を開始しました。from に記載しているのは,合成された映像の id で,xxxxxxx-common とかいう名前のやつです。keyFrameInterval: 2 の意味はよくわからない。

var body = {
	coontainer: "auto",
	media: {
		audio:{
			from:subscribeStreamId,
		},
		video:{
			from:subscribeStreamId,
			parameters:{
				keyFrameInterval: 2
			}
		}
	}
};

send('POST', '/rooms/' + myRoom + '/recordings', body, function (result){
		console.log(result);
	}
);

返事は,下記のようなものが返ってきました。

{"id":"728470063085156000","media":{"audio":{"from":"5e61d970a9aa783ede175936-common","format":{"codec":"opus","sampleRate":48000,"channelNum":2},"status":"active"},"video":{"from":"5e61d970a9aa783ede175936-common","parameters":{"keyFrameInterval":2},"format":{"codec":"vp8"},"status":"active"}},"storage":{"host":"192.168.100.4","file":"/tmp/728470063085156000.mkv"}}

録画ファイルはサーバーの /tmp/ 以下に作られます。録画ファイルの場所に関しては /recording_agent/agent.toml に記述があります。録画を止めるのは,先にもらったオブジェクトの中にある録画の id を指定して,下記のリクエストを出します。

var body ={};

send('DELETE', '/rooms/' + myRoom + '/recordings/' + recordingId, body, function (result){
		console.log(result);
	}
);

body も 返事も空です。これで一応以前のアプリの全機能が移植できそうです。このアプリはカメラやマイクが無くても接続して配信映像や音声を受けることができます。講義で使うときには,学生はカメラマイクなしで接続しています。下の図で言うと,streams 6 は映像を送り出しているのが6人で,participants 8 は会議に参加しているのが8人であることを示しています。いまのところ講義中にやるデモの映像を生中継するのに使用しています。

(20200413) クラスターを構築する

このビデオ会議システム用のクラスターを構築したいと考えていて,いくらか前進したので記録します。ビデオの処理が重いのではないかと思って,これを複数台で分担したらよいのではないかと考えています。そこでクラスターを構築したいとなるのですが,例えば,Core i5 9400 あたりを何個か使うと良さそうに思えます。現在はハードウェア処理の対象CPUではないのですが,将来的にはサポートされそうなので,そうなったときに1個のcpuでかなりの人数を捌けそうに思えます。
 ドキュメントはこのあたりです。ここを読んでもよく分からなかったのですが,フォーラムにこんな記事がありました。3台でクラスターを組んでみようとして上手くいかないという話で,以下にインテルの人の返事のところを抜き出します。

Let's make the problem simpler firstly to address your concern on separate audio and video agent to different machines. This can help narrow down the problem. If this simple situation still not work, share us about the zip file on each server node.

Node 1: Is running: rabbit-mq mongodb nuve cluster-manager portal session-agent webrtc-agent avstream-agent sip-agent recording-agent sip-portal app

(Comment out audio agent and video agent start script in start-all.sh)

Node 2: Is running: audio-agent

(Comment out all other components start scripts except audio agent in start-all.sh)

Node 3: Is running: video-agent

(Comment out all other components start scripts except video agent in start-all.sh)

Make sure your edit the video agent and audio agent toml files for correct rabbit-mq server and cluster ip/erthernet configuration.

1台でシステムを動かすときは,最初に init-all.sh を実行して,次に start-all.sh を実行しますが,上記からクラスターでは start-all.sh をコメントアウトするような修正だけで良いと読み取れます。うちでは2台で試しました。片方がクライアントから見えるコンピュータで,もう一台が video-agent のみを動かすコンピューターです。まずは,クライアントから見える方の start-all.sh です。

#!/usr/bin/env bash
# Copyright (C) <2019> Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0

bin=`dirname "$0"`
bin=`cd "$bin"; pwd`
${bin}/daemon.sh start management-api $1
${bin}/daemon.sh start cluster-manager $1
${bin}/daemon.sh start analytics-agent $1
${bin}/daemon.sh start audio-agent $1
${bin}/daemon.sh start conference-agent $1
${bin}/daemon.sh start recording-agent $1
${bin}/daemon.sh start sip-agent $1
${bin}/daemon.sh start streaming-agent $1
#${bin}/daemon.sh start video-agent $1
${bin}/daemon.sh start webrtc-agent $1
${bin}/daemon.sh start management-console $1
${bin}/daemon.sh start portal $1
${bin}/daemon.sh start sip-portal $1
${bin}/daemon.sh start app $1

video-agent 以外を動かしています。次に,video-agent を動かす方の start-all.sh です。

#!/usr/bin/env bash
# Copyright (C) <2019> Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0

bin=`dirname "$0"`
bin=`cd "$bin"; pwd`
#${bin}/daemon.sh start management-api $1
#${bin}/daemon.sh start cluster-manager $1
#${bin}/daemon.sh start analytics-agent $1
#${bin}/daemon.sh start audio-agent $1
#${bin}/daemon.sh start conference-agent $1
#${bin}/daemon.sh start recording-agent $1
#${bin}/daemon.sh start sip-agent $1
#${bin}/daemon.sh start streaming-agent $1
${bin}/daemon.sh start video-agent $1
#${bin}/daemon.sh start webrtc-agent $1
#${bin}/daemon.sh start management-console $1
#${bin}/daemon.sh start portal $1
#${bin}/daemon.sh start sip-portal $1
#${bin}/daemon.sh start app $1

ネットワークの設定は特にしていないのですが,クライアントから見える方のコンピューターのIPアドレスは 192.168.100.192 に固定しました。video-agent を動かす方の video-agent/agent.toml は下記のように修正しました。といっても [rabbit] のところを書き換えただけです。

[agent]
#Max processes that agent can run
maxProcesses = -1 #default: -1, unlimited

#Number of precesses that agent runs when it starts. 1 <= prerunProcesses <= maxProcesses.
prerunProcesses = 2 #default: 2


[cluster]
name = "owt-cluster"

#The number of times to retry joining if the first try fails.
join_retry = 60 #default: 60

#The interval of reporting the work load
report_load_interval = 1000 #default: 1000, unit: millisecond

#The max CPU/GPU load under which this worker can take new tasks.
max_load = 0.85 #default: 0.85


[rabbit]
host = "192.168.100.192" #default: "localhost"
port = 5672 #default: 5672


[internal]
#The IP address used for internal-cluster media spreading. Will use the IP got from the 'network_interface' item if 'ip_address' is not specified or equal to "".
ip_address = "" #default: ""

#The network interface used for internal-cluster media spreading. The first enumerated network interface in the system will be adopted if this item is not specified.
# network_interface = "eth0" # default: undefined

# The internal listening port range, only works for TCP now
maxport = 0 #default: 0
minport = 0 #default: 0

#########################################################################################
[video]
#If true and the machine has the capability, the mixer will be accelerated by hardware graphic chips
hardwareAccelerated = false

#If true and hardwareAccleration is enabled, setting this to true allows GACC HEVC encoder plugin to be used
#for better video quality.
#Warning: enabling this will introduce extra CPU resource consumption.
enableBetterHEVCQuality = false

#Multi Frame Encoding
#timeout[0, 100] in millisecond, setting to "0" disables this feature
MFE_timeout = 0 #default: 0

[avatar]
#widthxheight between the two dot ("180x180" between the "avatar." and ".yuv" in the default) in the location indicates the image size
location = "avatars/avatar_blue.180x180.yuv"

rabbit への localhost 以外からのアクセスは guest ユーザーでは出来ないと何処かに書いてありました。幸いうちでは適当なユーザーを作成していました。このポート 5672 へのアクセスは,ファイヤーウォールを開放して許可する必要はあるだろうと思って,それは先にやりました。そのあとで,両方のサーバーをクライアントから見える方を先にいつも通り起動 (init-all.sh の後 start-all.sh)して,video-agent を動かす方も同じように init-all.sh,start-all.sh の順に起動しました。

[root@localhost Release-v4.3]# ./bin/start-all.sh 
starting video-agent, stdout -> /home/friend/Release-v4.3/logs/video-agent.stdout
2020-04-13 13:05:54.579  - INFO: AmqpClient - Connecting to rabbitMQ server OK, options: { host: '192.168.100.192', port: 5672 }
2020-04-13 13:05:54.591  - INFO: WorkingAgent - video agent join cluster ok.
2020-04-13 13:05:54.595  - INFO: ClusterWorker - Join cluster owt-cluster OK.
2020-04-13 13:05:54.600  - INFO: WorkingAgent - as rpc server ok.
2020-04-13 13:05:54.601  - INFO: WorkingAgent - as monitoring target ok.
[root@localhost Release-v4.3]# 

上記が,video-agent を動かす方の start-all.sh を実行したときのメッセージです。接続は上手くいったように見えるのですが,この段階では映像の処理は上手くいきません。黒い画面がクライアントに表示されます。通信も video-agent の方にはデータが流れていないようでした。そこで念のためと思って,ここを参考にしてファイヤーウォールを完全に止めてみました。コマンドを記録します。まず,すべて止めるとき,

systemctl stop firewalld

その状態を確認する時,

systemctl status firewalld

ファイヤーウォールを完全に停止すると映像の処理が上手くいきました。一応2台が連動して処理をしているようで,試しに video-agent を担当している方だけを停止すると,会議の映像配信も止まりました。

 ビデオの処理や音声の処理がどれぐらいの負荷であるのかを試してみました。上の図にあるように core i5-3570 のパソコンを2台用意して,役割を分けて負荷を見てみました。10台のクライアントを接続します。

最初は1台ですべてをまかなう場合の負荷です。cpu 占有率は平均して 33% 程度でしょうか。通信量が意外に少ないのですが,ほぼ静止画だと通信量が小さくなるようです。

video-agent をもう一台の方に振り分けてみました。cpu 占有率が 22% あたりに下がります。通信量が増えているのですが,これはvideo-agent が動いているパソコンとの通信の分だけ増えていると思われます。

video-agent を担当しているパソコンの負荷です。15% 程の cpu 占有率です。受信と送信の量がかなり違います。

video-agent を分けることは負荷を分散させることにある程度有効です。ただ,フォーラムの記事から察するに,一つの会議のビデオの処理は1台のパソコンでまかなわれるようです。video-agent を2台用意しても残念ながら2台で分担することはないようです。動画の合成があるからでしょうか。たぶん二つ目の会議室を用意したときに2台目の video-agent が利用されるということかと理解しています。ただこの処理はそれほど重くないように見えます。2台目を用意しておくと,片方を停止したときにすぐさま他の方に切り替わって動画の送信が途切れることはありません。良くできています。

 次に音声を分けてみました。本体の方の cpu 占有率は 30% あたりでしょうか。

audio-agent の方の負荷です。cpu 占有率は6% あたりでしょうか。通信量も少なめです。

他も試してみました(設定が良く分からなくて上手く分離できなかったものもあった)。他はもっと負荷が小さくて,ビデオと音声を分けるだけで良いかなと考えています。

network card を複数枚使用する
video-agen をもう一台のパソコンに分けた場合、cpu の負荷は下がりますが、データの通信量は増加しそうです。しかしネットワークカードを複数使用すれば、通信量を下げることができるのではないかと考えました。加えて、グローバルなIPアドレスを1個使用するだけですむかもしれません。それで今度は複数の nic を持つマザーボード(supermicro X9SRL, cpu は Xeon E5-2650 v2)を使います。ネットワークの設定を以下順にあげて行きます。
最初に、クライアントから見えるパソコンですが、下図のように二つの nic があります。eno1 がクライアントから見える方で、eno2 が video-agent と繋ぐ方です。

まず、1枚目のカード(eno1)の設定です。こちらが、クライアントから見える IP アドレス(192.168.100.192)です。デフォルトゲートウェイを指定しています。 DNS をきちんと指定しないと外に繋がらなかった。

次に、2枚目のカードです。別のセグメント(102)を使用しました。デフォルトゲートウェイは指定しません。この nic からvideo-agent を動かすパソコンにつなぎます。

最後に、video-agent を動かすパソコンの設定です。デフォルトーゲートウェイに通信相手を指定しました(これで良いのだろうか?)。

この設定で動きました。サブネットマスクは外も内も同じです。外からは 192.168.100.192 が見えるだけなので、グローバルな IP アドレスはひとつで済みます。

多少時間的に変動するようですが、通信量をモニターしてみます。まず、1台ですべてをまかなった時の通信量を iftop でモニターしました。10台を繋いでいます。

下図は、 1枚のネットワークカードで video-agent を分けて動かした場合です。送信がかなり増加しています。

下図は、二つのネットワークカードを使用して video-agent を分けて動かした場合です。まず eno1 の方。少し増加しているように思えます?しかし1枚の場合とはかなり違います。

次に、eno2 の方です。ネットワークカードが1枚の場合は、この通信データの分も eno1 に加算されていると思います。

とりあえず video-agent を他のパソコンに分けることで増えるはずの通信量を抑えることができているのではないかと思います。

ファイヤーウォールの設定ですが、二つの nic でゾーンを分けてみました。クライアントから見える方を、public として、ポートの設定は以前のように、TCP で 3004 と 8080、UWP で 30000-60000 を開けておきます。もう一方を trusted としました。下記はコマンド

firewall-cmd --list-all-zones

の出力の一部です。

zone を移す場合には、下記のコマンドで。

firewall-cmd --zone=trusted --change-interface=eno2 --permanent

permanent 設定なので firewall-cmd --reload が必要です。video-agent を担当するパソコンの方は nic を trusted にしました。これで動きました。

4台でクラスターを組んで動かしています。それほどの負荷はかからないのですが。

(20200915)
chrome や edge,iOS の safari で動かなくなっています。DTLS 1.2 関係ではないかと思うのですが?何か進展があったら,また書きます。インテルの方でソフトのバージョンをあげてもらうことが必要なのかなと思う。

(20201231)
オープンソースの方を試してみました。記事はこちらです。chrome でも動きます。