forked from mirrors/nixpkgs
the conversion procedure is simple: - find all things that look like options, ie calls to either `mkOption` or `lib.mkOption` that take an attrset. remember the attrset as the option - for all options, find a `description` attribute who's value is not a call to `mdDoc` or `lib.mdDoc` - textually convert the entire value of the attribute to MD with a few simple regexes (the set from mdize-module.sh) - if the change produced a change in the manual output, discard - if the change kept the manual unchanged, add some text to the description to make sure we've actually found an option. if the manual changes this time, keep the converted description this procedure converts 80% of nixos options to markdown. around 2000 options remain to be inspected, but most of those fail the "does not change the manual output check": currently the MD conversion process does not faithfully convert docbook tags like <code> and <package>, so any option using such tags will not be converted at all.
418 lines
13 KiB
Nix
418 lines
13 KiB
Nix
{ config, lib, pkgs, ... }:
|
|
|
|
with lib;
|
|
|
|
let
|
|
cfg = config.services.jibri;
|
|
|
|
# Copied from the jitsi-videobridge.nix file.
|
|
toHOCON = x:
|
|
if isAttrs x && x ? __hocon_envvar then ("\${" + x.__hocon_envvar + "}")
|
|
else if isAttrs x then "{${ concatStringsSep "," (mapAttrsToList (k: v: ''"${k}":${toHOCON v}'') x) }}"
|
|
else if isList x then "[${ concatMapStringsSep "," toHOCON x }]"
|
|
else builtins.toJSON x;
|
|
|
|
# We're passing passwords in environment variables that have names generated
|
|
# from an attribute name, which may not be a valid bash identifier.
|
|
toVarName = s: "XMPP_PASSWORD_" + stringAsChars (c: if builtins.match "[A-Za-z0-9]" c != null then c else "_") s;
|
|
|
|
defaultJibriConfig = {
|
|
id = "";
|
|
single-use-mode = false;
|
|
|
|
api = {
|
|
http.external-api-port = 2222;
|
|
http.internal-api-port = 3333;
|
|
|
|
xmpp.environments = flip mapAttrsToList cfg.xmppEnvironments (name: env: {
|
|
inherit name;
|
|
|
|
xmpp-server-hosts = env.xmppServerHosts;
|
|
xmpp-domain = env.xmppDomain;
|
|
control-muc = {
|
|
domain = env.control.muc.domain;
|
|
room-name = env.control.muc.roomName;
|
|
nickname = env.control.muc.nickname;
|
|
};
|
|
|
|
control-login = {
|
|
domain = env.control.login.domain;
|
|
username = env.control.login.username;
|
|
password.__hocon_envvar = toVarName "${name}_control";
|
|
};
|
|
|
|
call-login = {
|
|
domain = env.call.login.domain;
|
|
username = env.call.login.username;
|
|
password.__hocon_envvar = toVarName "${name}_call";
|
|
};
|
|
|
|
strip-from-room-domain = env.stripFromRoomDomain;
|
|
usage-timeout = env.usageTimeout;
|
|
trust-all-xmpp-certs = env.disableCertificateVerification;
|
|
});
|
|
};
|
|
|
|
recording = {
|
|
recordings-directory = "/tmp/recordings";
|
|
finalize-script = "${cfg.finalizeScript}";
|
|
};
|
|
|
|
streaming.rtmp-allow-list = [ ".*" ];
|
|
|
|
chrome.flags = [
|
|
"--use-fake-ui-for-media-stream"
|
|
"--start-maximized"
|
|
"--kiosk"
|
|
"--enabled"
|
|
"--disable-infobars"
|
|
"--autoplay-policy=no-user-gesture-required"
|
|
]
|
|
++ lists.optional cfg.ignoreCert
|
|
"--ignore-certificate-errors";
|
|
|
|
|
|
stats.enable-stats-d = true;
|
|
webhook.subscribers = [ ];
|
|
|
|
jwt-info = { };
|
|
|
|
call-status-checks = {
|
|
no-media-timout = "30 seconds";
|
|
all-muted-timeout = "10 minutes";
|
|
default-call-empty-timout = "30 seconds";
|
|
};
|
|
};
|
|
# Allow overriding leaves of the default config despite types.attrs not doing any merging.
|
|
jibriConfig = recursiveUpdate defaultJibriConfig cfg.config;
|
|
configFile = pkgs.writeText "jibri.conf" (toHOCON { jibri = jibriConfig; });
|
|
in
|
|
{
|
|
options.services.jibri = with types; {
|
|
enable = mkEnableOption "Jitsi BRoadcasting Infrastructure. Currently Jibri must be run on a host that is also running <option>services.jitsi-meet.enable</option>, so for most use cases it will be simpler to run <option>services.jitsi-meet.jibri.enable</option>";
|
|
config = mkOption {
|
|
type = attrs;
|
|
default = { };
|
|
description = lib.mdDoc ''
|
|
Jibri configuration.
|
|
See <https://github.com/jitsi/jibri/blob/master/src/main/resources/reference.conf>
|
|
for default configuration with comments.
|
|
'';
|
|
};
|
|
|
|
finalizeScript = mkOption {
|
|
type = types.path;
|
|
default = pkgs.writeScript "finalize_recording.sh" ''
|
|
#!/bin/sh
|
|
|
|
RECORDINGS_DIR=$1
|
|
|
|
echo "This is a dummy finalize script" > /tmp/finalize.out
|
|
echo "The script was invoked with recordings directory $RECORDINGS_DIR." >> /tmp/finalize.out
|
|
echo "You should put any finalize logic (renaming, uploading to a service" >> /tmp/finalize.out
|
|
echo "or storage provider, etc.) in this script" >> /tmp/finalize.out
|
|
|
|
exit 0
|
|
'';
|
|
defaultText = literalExpression ''
|
|
pkgs.writeScript "finalize_recording.sh" ''''''
|
|
#!/bin/sh
|
|
|
|
RECORDINGS_DIR=$1
|
|
|
|
echo "This is a dummy finalize script" > /tmp/finalize.out
|
|
echo "The script was invoked with recordings directory $RECORDINGS_DIR." >> /tmp/finalize.out
|
|
echo "You should put any finalize logic (renaming, uploading to a service" >> /tmp/finalize.out
|
|
echo "or storage provider, etc.) in this script" >> /tmp/finalize.out
|
|
|
|
exit 0
|
|
'''''';
|
|
'';
|
|
example = literalExpression ''
|
|
pkgs.writeScript "finalize_recording.sh" ''''''
|
|
#!/bin/sh
|
|
RECORDINGS_DIR=$1
|
|
''${pkgs.rclone}/bin/rclone copy $RECORDINGS_DIR RCLONE_REMOTE:jibri-recordings/ -v --log-file=/var/log/jitsi/jibri/recording-upload.txt
|
|
exit 0
|
|
'''''';
|
|
'';
|
|
description = lib.mdDoc ''
|
|
This script runs when jibri finishes recording a video of a conference.
|
|
'';
|
|
};
|
|
|
|
ignoreCert = mkOption {
|
|
type = bool;
|
|
default = false;
|
|
example = true;
|
|
description = lib.mdDoc ''
|
|
Whether to enable the flag "--ignore-certificate-errors" for the Chromium browser opened by Jibri.
|
|
Intended for use in automated tests or anywhere else where using a verified cert for Jitsi-Meet is not possible.
|
|
'';
|
|
};
|
|
|
|
xmppEnvironments = mkOption {
|
|
description = lib.mdDoc ''
|
|
XMPP servers to connect to.
|
|
'';
|
|
example = literalExpression ''
|
|
"jitsi-meet" = {
|
|
xmppServerHosts = [ "localhost" ];
|
|
xmppDomain = config.services.jitsi-meet.hostName;
|
|
|
|
control.muc = {
|
|
domain = "internal.''${config.services.jitsi-meet.hostName}";
|
|
roomName = "JibriBrewery";
|
|
nickname = "jibri";
|
|
};
|
|
|
|
control.login = {
|
|
domain = "auth.''${config.services.jitsi-meet.hostName}";
|
|
username = "jibri";
|
|
passwordFile = "/var/lib/jitsi-meet/jibri-auth-secret";
|
|
};
|
|
|
|
call.login = {
|
|
domain = "recorder.''${config.services.jitsi-meet.hostName}";
|
|
username = "recorder";
|
|
passwordFile = "/var/lib/jitsi-meet/jibri-recorder-secret";
|
|
};
|
|
|
|
usageTimeout = "0";
|
|
disableCertificateVerification = true;
|
|
stripFromRoomDomain = "conference.";
|
|
};
|
|
'';
|
|
default = { };
|
|
type = attrsOf (submodule ({ name, ... }: {
|
|
options = {
|
|
xmppServerHosts = mkOption {
|
|
type = listOf str;
|
|
example = [ "xmpp.example.org" ];
|
|
description = lib.mdDoc ''
|
|
Hostnames of the XMPP servers to connect to.
|
|
'';
|
|
};
|
|
xmppDomain = mkOption {
|
|
type = str;
|
|
example = "xmpp.example.org";
|
|
description = lib.mdDoc ''
|
|
The base XMPP domain.
|
|
'';
|
|
};
|
|
control.muc.domain = mkOption {
|
|
type = str;
|
|
description = lib.mdDoc ''
|
|
The domain part of the MUC to connect to for control.
|
|
'';
|
|
};
|
|
control.muc.roomName = mkOption {
|
|
type = str;
|
|
default = "JibriBrewery";
|
|
description = lib.mdDoc ''
|
|
The room name of the MUC to connect to for control.
|
|
'';
|
|
};
|
|
control.muc.nickname = mkOption {
|
|
type = str;
|
|
default = "jibri";
|
|
description = lib.mdDoc ''
|
|
The nickname for this Jibri instance in the MUC.
|
|
'';
|
|
};
|
|
control.login.domain = mkOption {
|
|
type = str;
|
|
description = lib.mdDoc ''
|
|
The domain part of the JID for this Jibri instance.
|
|
'';
|
|
};
|
|
control.login.username = mkOption {
|
|
type = str;
|
|
default = "jvb";
|
|
description = lib.mdDoc ''
|
|
User part of the JID.
|
|
'';
|
|
};
|
|
control.login.passwordFile = mkOption {
|
|
type = str;
|
|
example = "/run/keys/jibri-xmpp1";
|
|
description = lib.mdDoc ''
|
|
File containing the password for the user.
|
|
'';
|
|
};
|
|
|
|
call.login.domain = mkOption {
|
|
type = str;
|
|
example = "recorder.xmpp.example.org";
|
|
description = lib.mdDoc ''
|
|
The domain part of the JID for the recorder.
|
|
'';
|
|
};
|
|
call.login.username = mkOption {
|
|
type = str;
|
|
default = "recorder";
|
|
description = lib.mdDoc ''
|
|
User part of the JID for the recorder.
|
|
'';
|
|
};
|
|
call.login.passwordFile = mkOption {
|
|
type = str;
|
|
example = "/run/keys/jibri-recorder-xmpp1";
|
|
description = lib.mdDoc ''
|
|
File containing the password for the user.
|
|
'';
|
|
};
|
|
disableCertificateVerification = mkOption {
|
|
type = bool;
|
|
default = false;
|
|
description = lib.mdDoc ''
|
|
Whether to skip validation of the server's certificate.
|
|
'';
|
|
};
|
|
|
|
stripFromRoomDomain = mkOption {
|
|
type = str;
|
|
default = "0";
|
|
example = "conference.";
|
|
description = lib.mdDoc ''
|
|
The prefix to strip from the room's JID domain to derive the call URL.
|
|
'';
|
|
};
|
|
usageTimeout = mkOption {
|
|
type = str;
|
|
default = "0";
|
|
example = "1 hour";
|
|
description = lib.mdDoc ''
|
|
The duration that the Jibri session can be.
|
|
A value of zero means indefinitely.
|
|
'';
|
|
};
|
|
};
|
|
|
|
config =
|
|
let
|
|
nick = mkDefault (builtins.replaceStrings [ "." ] [ "-" ] (
|
|
config.networking.hostName + optionalString (config.networking.domain != null) ".${config.networking.domain}"
|
|
));
|
|
in
|
|
{
|
|
call.login.username = nick;
|
|
control.muc.nickname = nick;
|
|
};
|
|
}));
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
users.groups.jibri = { };
|
|
users.groups.plugdev = { };
|
|
users.users.jibri = {
|
|
isSystemUser = true;
|
|
group = "jibri";
|
|
home = "/var/lib/jibri";
|
|
extraGroups = [ "jitsi-meet" "adm" "audio" "video" "plugdev" ];
|
|
};
|
|
|
|
systemd.services.jibri-xorg = {
|
|
description = "Jitsi Xorg Process";
|
|
|
|
after = [ "network.target" ];
|
|
wantedBy = [ "jibri.service" "jibri-icewm.service" ];
|
|
|
|
preStart = ''
|
|
cp --no-preserve=mode,ownership ${pkgs.jibri}/etc/jitsi/jibri/* /var/lib/jibri
|
|
mv /var/lib/jibri/{,.}asoundrc
|
|
'';
|
|
|
|
environment.DISPLAY = ":0";
|
|
serviceConfig = {
|
|
Type = "simple";
|
|
|
|
User = "jibri";
|
|
Group = "jibri";
|
|
KillMode = "process";
|
|
Restart = "on-failure";
|
|
RestartPreventExitStatus = 255;
|
|
|
|
StateDirectory = "jibri";
|
|
|
|
ExecStart = "${pkgs.xorg.xorgserver}/bin/Xorg -nocursor -noreset +extension RANDR +extension RENDER -config ${pkgs.jibri}/etc/jitsi/jibri/xorg-video-dummy.conf -logfile /dev/null :0";
|
|
};
|
|
};
|
|
|
|
systemd.services.jibri-icewm = {
|
|
description = "Jitsi Window Manager";
|
|
|
|
requires = [ "jibri-xorg.service" ];
|
|
after = [ "jibri-xorg.service" ];
|
|
wantedBy = [ "jibri.service" ];
|
|
|
|
environment.DISPLAY = ":0";
|
|
serviceConfig = {
|
|
Type = "simple";
|
|
|
|
User = "jibri";
|
|
Group = "jibri";
|
|
Restart = "on-failure";
|
|
RestartPreventExitStatus = 255;
|
|
|
|
StateDirectory = "jibri";
|
|
|
|
ExecStart = "${pkgs.icewm}/bin/icewm-session";
|
|
};
|
|
};
|
|
|
|
systemd.services.jibri = {
|
|
description = "Jibri Process";
|
|
|
|
requires = [ "jibri-icewm.service" "jibri-xorg.service" ];
|
|
after = [ "network.target" ];
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
path = with pkgs; [ chromedriver chromium ffmpeg-full ];
|
|
|
|
script = (concatStrings (mapAttrsToList
|
|
(name: env: ''
|
|
export ${toVarName "${name}_control"}=$(cat ${env.control.login.passwordFile})
|
|
export ${toVarName "${name}_call"}=$(cat ${env.call.login.passwordFile})
|
|
'')
|
|
cfg.xmppEnvironments))
|
|
+ ''
|
|
${pkgs.jre8_headless}/bin/java -Djava.util.logging.config.file=${./logging.properties-journal} -Dconfig.file=${configFile} -jar ${pkgs.jibri}/opt/jitsi/jibri/jibri.jar --config /var/lib/jibri/jibri.json
|
|
'';
|
|
|
|
environment.HOME = "/var/lib/jibri";
|
|
|
|
serviceConfig = {
|
|
Type = "simple";
|
|
|
|
User = "jibri";
|
|
Group = "jibri";
|
|
Restart = "always";
|
|
RestartPreventExitStatus = 255;
|
|
|
|
StateDirectory = "jibri";
|
|
};
|
|
};
|
|
|
|
systemd.tmpfiles.rules = [
|
|
"d /var/log/jitsi/jibri 755 jibri jibri"
|
|
];
|
|
|
|
|
|
|
|
# Configure Chromium to not show the "Chrome is being controlled by automatic test software" message.
|
|
environment.etc."chromium/policies/managed/managed_policies.json".text = builtins.toJSON { CommandLineFlagSecurityWarningsEnabled = false; };
|
|
warnings = [ "All security warnings for Chromium have been disabled. This is necessary for Jibri, but it also impacts all other uses of Chromium on this system." ];
|
|
|
|
boot = {
|
|
extraModprobeConfig = ''
|
|
options snd-aloop enable=1,1,1,1,1,1,1,1
|
|
'';
|
|
kernelModules = [ "snd-aloop" ];
|
|
};
|
|
};
|
|
|
|
meta.maintainers = lib.teams.jitsi.members;
|
|
}
|