通过配置文件cpu数量创建worker,再createRouter,然后创建房间
server.js中
async function runMediasoupWorkers()
{
const { numWorkers } = config.mediasoup;
logger.info('running %d mediasoup Workers...', numWorkers);
for (let i = 0; i < numWorkers; ++i)
{
const worker = await mediasoup.createWorker(
{
logLevel : config.mediasoup.workerSettings.logLevel,
logTags : config.mediasoup.workerSettings.logTags,
rtcMinPort : Number(config.mediasoup.workerSettings.rtcMinPort),
rtcMaxPort : Number(config.mediasoup.workerSettings.rtcMaxPort)
});
worker.on('died', () =>
{
logger.error(
'mediasoup Worker died, exiting in 2 seconds... [pid:%d]', worker.pid);
setTimeout(() => process.exit(1), 2000);
});
mediasoupWorkers.push(worker);
实例createRouter:
static async create({ mediasoupWorker, roomId, consumerReplicas })
{
logger.info('create() [roomId:%s]', roomId);
// Create a protoo Room instance.
const protooRoom = new protoo.Room();
// Router media codecs.
const { mediaCodecs } = config.mediasoup.routerOptions;
// Create a mediasoup Router.
const mediasoupRouter = await mediasoupWorker.createRouter({ mediaCodecs });
Worker.js中
async createRouter({ mediaCodecs, appData } = {}) {
logger.debug('createRouter()');
if (appData && typeof appData !== 'object') {
throw new TypeError('if given, appData must be an object');
}
// This may throw.
const rtpCapabilities = ortc.generateRouterRtpCapabilities(mediaCodecs);
const reqData = { routerId: (0, uuid_1.v4)() };
await this.#channel.request('worker.createRouter', undefined, reqData);
const data = { rtpCapabilities };
const router = new Router_1.Router({
internal: {
routerId: reqData.routerId
},
data,
channel: this.#channel,
payloadChannel: this.#payloadChannel,
appData
});
this.#routers.add(router);
router.on('@close', () => this.#routers.delete(router));
// Emit observer event.
this.#observer.safeEmit('newrouter', router);
return router;
}
constructor({ logLevel, logTags, rtcMinPort, rtcMaxPort, dtlsCertificateFile, dtlsPrivateKeyFile, libwebrtcFieldTrials, bweAllowableNotifyThreshold, appData }) {
super();
logger.debug('constructor()');
let spawnBin = workerBin;
let spawnArgs = [];
if (process.env.MEDIASOUP_USE_VALGRIND === 'true') {
spawnBin = process.env.MEDIASOUP_VALGRIND_BIN || 'valgrind';
if (process.env.MEDIASOUP_VALGRIND_OPTIONS) {
spawnArgs = spawnArgs.concat(process.env.MEDIASOUP_VALGRIND_OPTIONS.split(/\s+/));
}
spawnArgs.push(workerBin);
}
this.#child = (0, child_process_1.spawn)(
// command
spawnBin,
// args
spawnArgs,
// options
{
env: {
MEDIASOUP_VERSION: '3.11.13',
// Let the worker process inherit all environment variables, useful
// if a custom and not in the path GCC is used so the user can set
// LD_LIBRARY_PATH environment variable for runtime.
...process.env
},
detached: false,
// fd 0 (stdin) : Just ignore it.
// fd 1 (stdout) : Pipe it for 3rd libraries that log their own stuff.
// fd 2 (stderr) : Same as stdout.
// fd 3 (channel) : Producer Channel fd.
// fd 4 (channel) : Consumer Channel fd.
// fd 5 (channel) : Producer PayloadChannel fd.
// fd 6 (channel) : Consumer PayloadChannel fd.
stdio: ['ignore', 'pipe', 'pipe', 'pipe', 'pipe', 'pipe', 'pipe'],
windowsHide: true
});
this.#pid = this.#child.pid;
this.#channel = new Channel_1.Channel({
producerSocket: this.#child.stdio[3],
consumerSocket: this.#child.stdio[4],
pid: this.#pid
});
worker.js构造函数中创建父子进程,通过socket可以实现 JavaScript 与 C++ 之间的相互收发消息
this._child = child_process_1.spawn( spawnBin, spawnArgs,
使用 child_process.spawn() 方法创建了一个子进程,并将它赋值给 this.#child。spawn() 方法接受三个参数:
spawnBin:要执行的命令或可执行文件的路径。
spawnArgs:传递给命令的参数数组。
options:一个对象,用于配置子进程的选项。
options 对象中的一些重要配置包括:
env:指定子进程的环境变量。这里设置了 MEDIASOUP_VERSION 变量,并将父进程的环境变量继承给子进程。
detached:指定子进程是否独立运行,即与父进程无关。
stdio:指定子进程的标准输入、输出和错误流的处理方式。这里使用管道 (pipe) 来处理子进程的输出和错误。
windowsHide:在 Windows 系统中隐藏子进程的控制台窗口
this.#channel = new Channel_1.Channel({
producerSocket: this.#child.stdio[3],
consumerSocket: this.#child.stdio[4],
pid: this.#pid
});
await this.#channel.request('worker.createRouter', undefined, reqData);
调用channel的request与C++进程通信