Windows上でSFUサーバを構築する手順

今回、ローカルネットワーク内にSFUサーバを構築する機会があったので、ビデオ通話ができるようになるまでに行った手順と詰まったポイントを記事にしてみました。
今回はmediasoupというOSS(オープンソースソフトウェア)を使用しています。

環境情報

構築した際のOSとインストールしたソフトウェアは以下になります。

  • Windows10
  • Node.js
  • Python3
  • Apache

NodeとPythonはあらかじめインストーラーからインストールしておきます。

Apacheのインストール

ブラウザ上で接続確認するために、まずはwebサーバのApacheをインストールします。
インストール先は任意のフォルダにインストールしてください。
今回はC:直下にインストールしました

mediasoupのインストール

まずは以下のpackage.jsonを先ほどインストールしたApacheのフォルダに配置します。

package.json

{
  "dependencies": {
    "browserify": "^17.0.0",
    "cors": "^2.8.5",
    "express": "^4.19.2",
    "mediasoup": "^3.13.24",
    "socket.io": "^4.7.5"
  },
  "devDependencies": {
    "mediasoup-client": "^3.7.6"
  }
}

次に、PowerShellを管理者権限で実行し、先ほどインストールしたApacheのフォルダに移動して以下のコマンドを実行します。

npm init
npm install

SSL証明書の作成

WebRTCでカメラの映像などを使用する際に、SSL通信が必須になるためSSL証明書を作成します。
SSL証明書を作成するのに、mkcertというツールを使いますが、Windowsでインストールするために Chocolateryというツールが必要になります。
Chocolateyのインストール方法は公式サイトに記載されています。
Chocolateyのインストールが完了したら、証明書を配置したいフォルダに移動して以下のコマンドを実行します。

mkcert -install
mkcert 192.168.1.65

SFUサーバの実行

mediasoupのdemoなどにサーバ用のjsがあるので、そちらをベースに作るのが早いと思います。
今回はPort3000で起動しました。

const http = require('http');
const express = require('express');
const app = express();
app.use(express.static('public'));

// --- SSL ---
const fs = require('fs');
const ssloptions = {
  key: fs.readFileSync('C:\\cert\\192.168.1.65-key.pem'),
  cert: fs.readFileSync('C:\\cert\\192.168.1.65.pem')
};
const webServer = http.Server(ssloptions,app).listen(3000);

const io = require('socket.io')(webServer);

io.on('connection', (socket) => {

~~~~~~~~~~~~~~~~~~~~~~~~~~

上記のような形でserver.jsを準備したら、PowerShell上で以下のコマンドを実行します。

node .\server.js

エラーがなければサーバの起動は成功です。

mediasoup-client のインストールとビルド

クライアントサイドで使用するmediasoup-clientをビルドします。
インストールしたApacheのDocumentRootにフォルダを作成し、PowerShellでそのフォルダに移動したら、以下のコマンドを実行します。

node_modules/browserify/bin/cmd.js node_modules/mediasoup-client/lib/index.js -s MediasoupClient -o public/js/mediasoup-client.js

接続テスト

ビデオチャットを試すためのhtmlをDocumentRoot配下に配置して、Apacheを起動したらブラウザでアクセスしてみます。
サンプルに今回使用したhtmlを置いておきます。
192.168.1.65はローカルIPに置き換えてください。


カメラ付きの端末でhttps://[ローカルIP]/room.htmlにアクセスすると、以下のようなエラーが出ると思います。

これはwebSocket用のURLにPort指定が入っているため、originと異なるために発生しているCORSエラーです。
server.jsのrequire('socket.io’)の箇所を以下にすることで解消できました。

// CORS対策
const socketOptions = {
  cors: {
    origin: function (origin, fn) {
      const isTarget = origin !== undefined && origin.match(/^https?:\/\/192\.168\.1\.65/) !== null;
      return isTarget ? fn(null, origin) : fn('error invalid domain');
    },
    credentials: true
  }
};
const io = require('socket.io')(webServer,socketOptions);

編集後、server.jsを再起動して、再度https://[ローカルIP]/room.htmlにアクセスしてみます。

無事、ブラウザ上でスマホとノートPCでビデオ通話ができました。