Ejemplo n.º 1
0
        /// <summary>
        /// <para>Events:</para>
        /// <para>@emits died - (error: Error)</para>
        /// <para>@emits @success</para>
        /// <para>@emits @failure - (error: Error)</para>
        /// <para>Observer events:</para>
        /// <para>@emits close</para>
        /// <para>@emits newrouter - (router: Router)</para>
        /// </summary>
        /// <param name="loggerFactory"></param>
        /// <param name="hostEnvironment"></param>
        /// <param name="mediasoupOptions"></param>
        public Worker(ILoggerFactory loggerFactory, MediasoupOptions mediasoupOptions)
        {
            _loggerFactory = loggerFactory;
            _logger        = loggerFactory.CreateLogger <Worker>();
            _closeLock.Set();

            var workerPath = mediasoupOptions.MediasoupStartupSettings.WorkerPath;

            if (workerPath.IsNullOrWhiteSpace())
            {
                // 见:https://docs.microsoft.com/en-us/dotnet/core/rid-catalog
                string rid;
                if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                {
                    rid = "linux";
                }
                else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                {
                    rid = "osx";
                }
                else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    rid = "win";
                }
                else
                {
                    throw new NotSupportedException("Unsupported platform");
                }

                var location  = Assembly.GetEntryAssembly().Location;
                var directory = Path.GetDirectoryName(location);
                workerPath = Path.Combine(directory, "runtimes", rid, "native", "mediasoup-worker");
            }

            var workerSettings = mediasoupOptions.MediasoupSettings.WorkerSettings;

            AppData = workerSettings.AppData;

            var env = new[] { $"MEDIASOUP_VERSION={mediasoupOptions.MediasoupStartupSettings.MediasoupVersion}" };

            var args = new List <string>
            {
                workerPath
            };

            if (workerSettings.LogLevel.HasValue)
            {
                args.Add($"--logLevel={workerSettings.LogLevel.GetEnumStringValue()}");
            }
            if (!workerSettings.LogTags.IsNullOrEmpty())
            {
                workerSettings.LogTags.ForEach(m => args.Add($"--logTag={m.GetEnumStringValue()}"));
            }
            if (workerSettings.RtcMinPort.HasValue)
            {
                args.Add($"--rtcMinPort={workerSettings.RtcMinPort}");
            }
            if (workerSettings.RtcMaxPort.HasValue)
            {
                args.Add($"--rtcMaxPort={workerSettings.RtcMaxPort}");
            }
            if (!workerSettings.DtlsCertificateFile.IsNullOrWhiteSpace())
            {
                args.Add($"--dtlsCertificateFile={workerSettings.DtlsCertificateFile}");
            }
            if (!workerSettings.DtlsPrivateKeyFile.IsNullOrWhiteSpace())
            {
                args.Add($"--dtlsPrivateKeyFile={workerSettings.DtlsPrivateKeyFile}");
            }

            _logger.LogDebug($"Worker() | Spawning worker process: {args.Join(" ")}");

            _pipes = new Pipe[StdioCount];

            // 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.
            for (var i = 1; i < StdioCount; i++)
            {
                _pipes[i] = new Pipe()
                {
                    Writeable = true, Readable = true
                };
            }

            try
            {
                // 和 Node.js 不同,_child 没有 error 事件。不过,Process.Spawn 可抛出异常。
                _child = Process.Spawn(new ProcessOptions()
                {
                    File        = workerPath,
                    Arguments   = args.ToArray(),
                    Environment = env,
                    Detached    = false,
                    Streams     = _pipes,
                }, OnExit);

                ProcessId = _child.Id;
            }
            catch (Exception ex)
            {
                _child = null;
                CloseAsync().ConfigureAwait(false).GetAwaiter().GetResult();

                if (!_spawnDone)
                {
                    _spawnDone = true;
                    _logger.LogError(ex, $"Worker() | Worker process failed [pid:{ProcessId}]");
                    Emit("@failure", ex);
                }
                else
                {
                    // 执行到这里的可能性?
                    _logger.LogError(ex, $"Worker() | Worker process error [pid:{ProcessId}]");
                    Emit("died", ex);
                }
            }

            _channel = new Channel(_loggerFactory.CreateLogger <Channel>(), _pipes[3], _pipes[4], ProcessId);
            _channel.MessageEvent += OnChannelMessage;

            _payloadChannel = new PayloadChannel(_loggerFactory.CreateLogger <PayloadChannel>(), _pipes[5], _pipes[6], ProcessId);

            _pipes.ForEach(m => m?.Resume());
        }
Ejemplo n.º 2
0
        /// <summary>
        /// <para>Events:</para>
        /// <para>@emits died - (error: Error)</para>
        /// <para>@emits @success</para>
        /// <para>@emits @failure - (error: Error)</para>
        /// <para>Observer events:</para>
        /// <para>@emits close</para>
        /// <para>@emits newrouter - (router: Router)</para>
        /// </summary>
        /// <param name="loggerFactory"></param>
        /// <param name="mediasoupOptions"></param>
        public Worker(ILoggerFactory loggerFactory, MediasoupOptions mediasoupOptions)
        {
            _loggerFactory = loggerFactory;
            _logger        = loggerFactory.CreateLogger <Worker>();

            var workerSettings = mediasoupOptions.MediasoupSettings.WorkerSettings;

            AppData = workerSettings.AppData;

            var env = new[] { $"MEDIASOUP_VERSION={mediasoupOptions.MediasoupStartupSettings.MediasoupVersion}" };

            var args = new List <string>
            {
                mediasoupOptions.MediasoupStartupSettings.WorkerPath
            };

            if (workerSettings.LogLevel.HasValue)
            {
                args.Add($"--logLevel={Enum.GetName(typeof(WorkerLogLevel), workerSettings.LogLevel).ToLowerInvariant()}");
            }
            if (!workerSettings.LogTags.IsNullOrEmpty())
            {
                workerSettings.LogTags.ForEach(m => args.Add($"--logTag={m}"));
            }
            if (workerSettings.RtcMinPort.HasValue)
            {
                args.Add($"--rtcMinPort={workerSettings.RtcMinPort}");
            }
            if (workerSettings.RtcMaxPort.HasValue)
            {
                args.Add($"--rtcMaxPort={workerSettings.RtcMaxPort}");
            }
            if (!workerSettings.DtlsCertificateFile.IsNullOrWhiteSpace())
            {
                args.Add($"--dtlsCertificateFile={workerSettings.DtlsCertificateFile}");
            }
            if (!workerSettings.DtlsPrivateKeyFile.IsNullOrWhiteSpace())
            {
                args.Add($"--dtlsPrivateKeyFile={workerSettings.DtlsPrivateKeyFile}");
            }

            _logger.LogDebug($"Worker() | spawning worker process: {args.ToArray().Join(" ")}");

            _pipes = new Pipe[StdioCount];
            // 备注:忽略标准输入
            for (var i = 1; i < StdioCount; i++)
            {
                _pipes[i] = new Pipe()
                {
                    Writeable = true, Readable = true
                };
            }

            try
            {
                // 备注:和 Node.js 不同,_child 没有 error 事件。不过,Process.Spawn 可抛出异常。
                _child = Process.Spawn(new ProcessOptions()
                {
                    File        = mediasoupOptions.MediasoupStartupSettings.WorkerPath,
                    Arguments   = args.ToArray(),
                    Environment = env,
                    Detached    = false,
                    Streams     = _pipes,
                }, OnExit);

                ProcessId = _child.Id;
            }
            catch (Exception ex)
            {
                _child = null;
                Close();

                if (!_spawnDone)
                {
                    _spawnDone = true;
                    _logger.LogError($"Worker() | worker process failed [pid:{ProcessId}]: {ex.Message}");
                    Emit("@failure", ex);
                }
                else
                {
                    // 执行到这里的可能性?
                    _logger.LogError($"Worker() | worker process error [pid:{ProcessId}]: {ex.Message}");
                    Emit("died", ex);
                }
            }

            _channel = new Channel(_loggerFactory.CreateLogger <Channel>(), _pipes[3], _pipes[4], ProcessId);
            _channel.RunningEvent += OnChannelRunning;

            _pipes.ForEach(m => m?.Resume());
        }