Новости и статьи

Среда разработки встроенных систем или дистрибутивов на основе GNU/Linux. Здесь вы можете найти новости проекта, статьи и заметки, касающиеся разработки дистрибутива Radix cross Linux.

[matrix] Element Call

16 сентября 2025 г.

В предыдущей статье мы рассмотрели установку домашнего сервера Matrix Synapse, а также сервисов, которые обеспечивают текстовые сообщения, голосовые сообщения и управление пользователями. Однако этого не достаточно для организации полноценного home‑сервера.

Element Call

Для обеспечения видео и аудио звонков необходимо инсталлировать еще два сервера:

tags

Кроме того, на стороне сервера Synapse должно быть обеспечено взаимодействие в соответствии с текущими спецификациями (Matrix Specification Proposals):

  • MSC3266: Room Summary API: In Standalone mode Element Call is able to join rooms over federation using knocking. In this context MSC3266 is required as it allows to request a room summary of rooms you are not joined. The summary contains the room join rules. We need that information to decide if the user gets prompted with the option to knock ("Request to join call"), a "cannot join error" or "the join view".
  • MSC4140: Delayed Events: Delayed events are required for proper call participation signalling. If disabled it is very likely that you end up with stuck calls in Matrix rooms.
  • MSC4222: Adding state_after to sync v2: Allow clients to opt-in to a change of the sync v2 API that allows them to correctly track the state of the room. This is required by Element Call to track room state reliably.

MatrixRTC Backend

В общем виде, схему взаимодействия можно представить следующим образом:

Fig.1. Site Deployment.

Итак, нам необходимо инсталлировать еще два сервера. Начнем с сервера LiveKit SFU (Matrix LiveKit Server).

Прежде чем начать сборку, создадим необходимые каталоги:

 mkdir -p /var/run/matrix-rtc
 mkdir -p /var/log/matrix-rtc
 mkdir -p /var/lib/matrix-rtc

Данные каталоги предназначены для хранения log‑файлов, pid‑файлов и имитации домашнего пространства серверов SFU и JWT.

LiveKit SFU

Сервер написан на языке Go и его сборка не представляет никаких трудностей:

 git clone https://github.com/livekit/livekit
 cd livekit
 ./bootstrap.sh
 mage

Результат сборки в виде единственного исполняемого файла livekit‑server будет находиться в каталоге сборки livekit/bin/.

Скопируем его в каталог /usr/bin/:

 cp -a bin/livekit-server /usr/bin/

Для обеспечения запуска сервера при старте системы, составим следующий скрипт:

/etc/rc.d/rc.matrix-sfu:

 #!/bin/sh

 SFU_NAME="livekit-server"
 SFU_PROG=/usr/bin/livekit-server
 PID_DIR=/var/run/matrix-rtc
 LOG_DIR=/var/log/matrix-rtc
 WORKDIR=/var/lib/matrix-rtc

 SFU_CONFIG_FILE=/etc/matrix-synapse/sfu-config.yaml

 SFU_LOG_FILE=${LOG_DIR}/${SFU_NAME}.log
 SFU_PID_FILE=${PID_DIR}/${SFU_NAME}.pid

 case "$1" in
   start)
     # create $PID_DIR with correct access rights
     if [ ! -d ${PID_DIR} ] ; then
       rm -rf ${PID_DIR}
       mkdir -p ${PID_DIR}
     fi
     chmod 0755 ${PID_DIR}

     # create $LOG_DIR with correct access rights
     if [ ! -d ${LOG_DIR} ] ; then
       rm -rf ${LOG_DIR}
       mkdir -p ${LOG_DIR}
     fi
     chmod 0755 ${LOG_DIR}

     # create $WORKDIR with correct access rights
     if [ ! -d ${WORKDIR} ] ; then
       rm -rf ${WORKDIR}
       mkdir -p ${WORKDIR}
     fi
     chmod 0755 ${WORKDIR}

     echo "Starting ${SFU_NAME}..."
     if [ -f "${SFU_PID_FILE}" ]; then
       echo "${SFU_NAME} is already running (PID: $(cat "${SFU_PID_FILE}"))."
       exit 1
     fi

     cd "${WORKDIR}" || exit 1

     ${SFU_PROG} --config ${SFU_CONFIG_FILE}  >>${SFU_LOG_FILE} 2>&1 &
     echo "$!" > ${SFU_PID_FILE}
     ;;
   stop)
     echo "Stopping ${SFU_NAME}..."
     if [ ! -f "${SFU_PID_FILE}" ]; then
       echo "${SFU_NAME} is not running."
       exit 1
     fi
     /bin/kill -9 $(cat "${SFU_PID_FILE}")  1> /dev/null 2>/dev/null
     rm -f "${SFU_PID_FILE}"
     ;;
   restart)
     echo "Restarting ${SFU_NAME}..."
     $0 stop
     sleep 5
     $0 start
     ;;
   status)
     if [ -f "${SFU_PID_FILE}" ]; then
       echo "${SFU_NAME} is running (PID: $(cat "${SFU_PID_FILE}"))."
     else
       echo "${SFU_NAME} is not running."
     fi
     ;;
   *)
     echo "Usage: $0 {start|stop|restart|status}"
     exit 1
     ;;
 esac

 exit 0

Разумеется, необходимо составить конфигурационный файл /etc/matrix‑synapse/sfu‑config.yaml следующего содержания:

/etc/matrix‑synapse/sfu‑config.yaml:

 port: 7880
 bind_addresses:
   - "0.0.0.0"
 rtc:
   tcp_port: 7881
   port_range_start: 50100
   port_range_end: 50200
   use_external_ip: false
 room:
   auto_create: false
 logging:
   level: info
 turn:
   enabled: false
   domain: localhost
   cert_file: ""
   key_file: ""
   tls_port: 5349
   udp_port: 443
   external_tls: true
 keys:
   devkey: "9z1Qv6J3Ky2EiaZToYx2Qdh8MWkykzShdpWeZQeqqwhZ"

Ключ devkey создается с помощью команды:

 # /usr/bin/livekit-server generate-keys
 API Key:  APIqZ3K9pBeN3k3
 API Secret:  9z1Qv6J3Ky2EiaZToYx2Qdh8MWkykzShdpWeZQeqqwhZ

Этот ключ понадобится нам для запуска сервера авторизации далее.

MatrixRTC Authorization Service

Данный сервис также написан на языке Go. Его сборка может быть выполнена с помощью следующих команд:

 wget https://github.com/element-hq/lk-jwt-service/archive/refs/tags/v0.3.0.tar.gz
 tar -xvf v0.3.0.tar.gz
 mv lk-jwt-service-0.3.0 lk-jwt-service

 cd lk-jwt-service
 go build -o lk-jwt-service .

Результат сборки в виде исполняемого файла lk‑jwt‑service будет находиться в каталоге сборки lk‑jwt‑service/. Его также надо скопировать в каталог /usr/bin/:

 cp -a lk-jwt-service /usr/bin/

Для запуска сервиса следует использовать скрипт /etc/rc.d/rc.matrix‑jwt:

/etc/rc.d/rc.matrix‑jwt:

 #!/bin/sh

 JWT_NAME="lk-jwt-service"
 JWT_PROG=/usr/bin/lk-jwt-service
 PID_DIR=/var/run/matrix-rtc
 LOG_DIR=/var/log/matrix-rtc
 WORKDIR=/var/lib/matrix-rtc

 JWT_LOG_FILE=${LOG_DIR}/${JWT_NAME}.log
 JWT_PID_FILE=${PID_DIR}/${JWT_NAME}.pid

 LIVEKIT_URL="https://matrix-rtc.home.ru/livekit/sfu"
 LIVEKIT_KEY=APIqZ3K9pBeN3k3
 LIVEKIT_SECRET=9z1Qv6J3Ky2EiaZToYx2Qdh8MWkykzShdpWeZQeqqwhZ
 LIVEKIT_FULL_ACCESS_HOMESERVERS=*
 LIVEKIT_JWT_PORT=8990

 case "$1" in
   start)
     # create $PID_DIR with correct access rights
     if [ ! -d ${PID_DIR} ] ; then
       rm -rf ${PID_DIR}
       mkdir -p ${PID_DIR}
     fi
     chmod 0755 ${PID_DIR}

     # create $LOG_DIR with correct access rights
     if [ ! -d ${LOG_DIR} ] ; then
       rm -rf ${LOG_DIR}
       mkdir -p ${LOG_DIR}
     fi
     chmod 0755 ${LOG_DIR}

     # create $WORKDIR with correct access rights
     if [ ! -d ${WORKDIR} ] ; then
       rm -rf ${WORKDIR}
       mkdir -p ${WORKDIR}
     fi
     chmod 0755 ${WORKDIR}

     echo "Starting ${JWT_NAME}..."
     if [ -f "${JWT_PID_FILE}" ]; then
       echo "${JWT_NAME} is already running (PID: $(cat "${JWT_PID_FILE}"))."
       exit 1
     fi

     cd "${WORKDIR}" || exit 1

     LIVEKIT_URL="${LIVEKIT_URL}" \
     LIVEKIT_KEY=${LIVEKIT_KEY} \
     LIVEKIT_SECRET=${LIVEKIT_SECRET} \
     LIVEKIT_FULL_ACCESS_HOMESERVERS="${LIVEKIT_FULL_ACCESS_HOMESERVERS}" \
     LIVEKIT_JWT_PORT=${LIVEKIT_JWT_PORT} \
       ${JWT_PROG} >>${JWT_LOG_FILE} 2>&1 &
     echo "$!" > ${JWT_PID_FILE}
     ;;
   stop)
     echo "Stopping ${JWT_NAME}..."
     if [ ! -f "${JWT_PID_FILE}" ]; then
       echo "${JWT_NAME} is not running."
       exit 1
     fi
     /bin/kill -9 $(cat "${JWT_PID_FILE}")  1> /dev/null 2>/dev/null
     rm -f "${JWT_PID_FILE}"
     ;;
   restart)
     echo "Restarting ${JWT_NAME}..."
     $0 stop
     sleep 5
     $0 start
     ;;
   status)
     if [ -f "${JWT_PID_FILE}" ]; then
       echo "${JWT_NAME} is running (PID: $(cat "${JWT_PID_FILE}"))."
     else
       echo "${JWT_NAME} is not running."
     fi
     ;;
   *)
     echo "Usage: $0 {start|stop|restart|status}"
     exit 1
     ;;
 esac

 exit 0

Здесь, значения переменных:

 LIVEKIT_KEY=APIqZ3K9pBeN3k3
 LIVEKIT_SECRET=9z1Qv6J3Ky2EiaZToYx2Qdh8MWkykzShdpWeZQeqqwhZ

Получены нами ранее посредством команды:

 # /usr/bin/livekit-server generate-keys

Как видно по значению переменной LIVEKIT_URL скрипта запуска /etc/rc.d/rc.matrix‑jwt, web‑сервер будет находиться по адресу https://matrix‑rtc.home.ru и нам остается составить конфирурацию виртуального сервера Nginx:

#
# matrix-rtc.home.ru server:
#

    server {
        listen 80;
        listen [::]:80;

        server_name matrix-rtc.home.ru;
        return 301 https://matrix-rtc.home.ru$request_uri;
    }

    server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;

        server_name matrix-rtc.home.ru;

        error_log /var/log/nginx/matrix-rtc.home.ru-error.log;
        access_log /var/log/nginx/matrix-rtc.home.ru-access.log;

        #
        # Comment before getting first Certificates:
        #
        ssl_certificate          /etc/letsencrypt/live/matrix-rtc.home.ru/fullchain.pem;
        ssl_certificate_key      /etc/letsencrypt/live/matrix-rtc.home.ru/privkey.pem;
        ssl_trusted_certificate  /etc/letsencrypt/live/matrix-rtc.home.ru/chain.pem;

        location ^~ /sfu/get {
            add_header Access-Control-Allow-Origin "*";
            add_header Access-Control-Allow-Methods "POST";
            add_header Access-Control-Allow-Headers "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token";

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_pass http://127.0.0.1:8990/sfu/get;
        }

        location ^~ /livekit/sfu/ {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_send_timeout 120;
            proxy_read_timeout 120;

            proxy_set_header Accept-Encoding gzip;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_buffering off;

            proxy_pass http://127.0.0.1:7880/;
        }

    }

Составим еще один файл.

/etc/logrotate.d/rc.matrix‑rtc:

 /var/log/matrix-rtc/livekit-server.log /var/log/matrix-rtc/lk-jwt-service.log {
   rotate 7
   size=5M
   compress
   notifempty
   missingok
 }

Теперь SFU и JWT серверы готовы к работе и нам остается отредактировать конфигурацию Matrix Synapse сервера.

MatrixRTC Backend Announcement

В конфигурационный файл /etc/matrix‑synapse/matrix.home.ru.conf необходимо добавить следующие строки:

#
# matrix-rtc.home.ru:
#
experimental_features:
  # MSC3266: Room summary API. Used for knocking over federation
  msc3266_enabled: true
  # MSC4222 needed for syncv2 state_after. This allow clients to
  # correctly track the state of the room.
  msc4222_enabled: true

# The maximum allowed duration by which sent events can be delayed, as
# per MSC4140.
max_event_delay_duration: 24h

rc_message:
  # This needs to match at least e2ee key sharing frequency plus a bit of headroom
  # Note key sharing events are bursty
  per_second: 0.5
  burst_count: 30

rc_delayed_event_mgmt:
  # This needs to match at least the heart-beat frequency plus a bit of headroom
  # Currently the heart-beat is every 5 seconds which translates into a rate of 0.2s
  per_second: 1
  burst_count: 20

Кроме того, необходимо аннонсировать сервер https://matrix‑rtc.home.ru в файле https://matrix.home.ru/.well‑known/matrix/client так, чтобы его новое содержимое было таким:

https://matrix.home.ru/.well‑known/matrix/client:

 {
   "m.homeserver": {
     "base_url": "https://matrix.home.ru"
   },
   "org.matrix.msc4143.rtc_foci":[
     {
       "type":"livekit",
       "livekit_service_url":"https://matrix-rtc.home.ru"
     }
   ]
 }

В файле /etc/nginx/vhosts/matrix.home.ru.conf это будет выглядеть следующим образом:

    location = /.well-known/matrix/client {
        return 200 '{"m.homeserver": {"base_url": "https://matrix.home.ru"},"org.matrix.msc4143.rtc_foci":[{"type":"livekit","livekit_service_url":"https://matrix-rtc.home.ru"}]}';
        default_type application/json;
        add_header Access-Control-Allow-Origin *;
    }

На этом наши настройки закончены и можно перезагрузить конфирурацию Nginx:

 /etc/rc.d/rc.nginx reload

Теперь наш домашний сервер Synapse в состоянии обеспечить аудио и видео звонки.

Следует отметить, что в случае использования web‑клиента Element, для совершения видеовызова надо использовать Legacy тип звонка. Кроме того, на смартфон следует устанавливать Element Classic, так как [matrix] совершенствуется непрерывно и на данный момент Element X не будет корректно работать с нашим сервером.

Литература:

Links:

Sources:


Поскольку [matrix] – это децентрализованная сеть, вы можете создать аккаунт на любом сервере, а также звонить не только пользователям собственного сервера, но и общаться с людьми, зарегистрированным на любом сервере [matrix] в сети Internet.

Enjoy.