Skip to content

Резервирование источников

media.source.failover

У потока может быть несколько источников. Sapsan следит за активным источником и при его деградации автоматически переключается на следующий, а при восстановлении основного — возвращается на него. Эта логика называется LSI (Live Source Input).

Несколько входов

Входы перечисляются в порядке приоритета — первый в списке главный:

streams:
  - name: tv1
    inputs:
    - udp:
        host: 239.0.0.1
        port: 5000
    - tshttp:
        url: http://backup-origin.example.com/tv1/mpegts

Как происходит переключение

Ключевые свойства алгоритма, важные для эфира:

  • Источник становится активным только по готовности: он должен отдать параметры потока (MediaInfo) и подходящую стартовую точку (ключевой кадр, аудиокадр или границу фрагмента). До этого зрителям продолжает идти текущий источник.
  • Возврат на основной после чистого окна: восстановившийся приоритетный вход проверяется в фоне. Для входов, которые открывает Sapsan, переключение требует подходящей стартовой точки и приёма без нарушений правил в течение return_alive_secs.
  • Упавший вход переподключается с нарастающей задержкой (reconnect_initial_delay → reconnect_delay_step → reconnect_max_delay); когда истекли все входы, ротация начинается с первого.
  • Источник, чей битрейт превысил max_bitrate, принудительно останавливается.
  • Отдельные таймауты на отсутствие видео и аудио: пропавший звук при живом видео тоже считается деградацией.

Политика переключения

Секция lsi задаёт политику для потока в целом. В source_options конкретного входа можно переопределить его таймауты, ограничения битрейта и чистое окно; задержки переподключения и интервал фоновой проверки задаются только в lsi:

streams:
  - name: tv1
    inputs:
    - udp: {host: 239.0.0.1, port: 5000}
    - udp:
        host: 239.0.0.2
        port: 5000
      source_options:
        source_timeout: 10
    lsi:
      source_timeout: 5
      video_timeout: 3
      audio_timeout: 3

Таймауты и интервал фоновой проверки задаются в секундах, задержки переподключения — в миллисекундах. Основные параметры:

Параметр Описание
source_timeout, video_timeout, audio_timeout таймауты отсутствия данных/видео/аудио
max_bitrate ограничение битрейта источника
reconnect_initial_delay, reconnect_delay_step, reconnect_max_delay политика переподключения (только lsi), миллисекунды
recheck_secondary_inputs_interval интервал фоновой проверки неактивных входов (только lsi), секунды
allow_if, deny_if (только source_options) включать/выключать вход по внешнему файлу-флагу

allow_if/deny_if позволяют управлять входами извне без правки конфига: вход используется, только пока файл-флаг разрешает.

Состояние вторичного источника

Примените конфиг через central. Интервал фоновой проверки задайте явно в lsi; пример проверяет неактивные входы с интервалом 10 секунд:

streams:
- name: tv1
  inputs:
  - udp: {host: 239.0.0.1, port: 5000}
  - udp: {host: 239.0.0.2, port: 5000}
  lsi:
    source_timeout: 5
    recheck_secondary_inputs_interval: 10

Снимите состояние через management API central. В примере настроены два входа, поэтому inputs[1] — второй, а current показывает, кормит ли он стрим прямо сейчас:

curl -fsS -u "$ADMIN_USER:$ADMIN_PASSWORD" \
  http://central:8080/central/api-v4/streams/stats/tv1 \
  | jq '{active: [.inputs[] | select(.current)], secondary: .inputs[1] | {url, current, status, problems, checked_at, error, failure_cause}}'

status — состояние последнего наблюдения, а не обещание бесшовного переключения. checked_at содержит время наблюдения RFC 3339 UTC; отсутствие поля означает, что проверки ещё не было. Значения состояния:

  • working — кадры идут, чистое окно без нарушений.
  • starting — вход открыт, кадров ещё нет.
  • degraded — кадры идут, нарушено правило качества.
  • dead — нет кадров из-за ошибки или таймаута.
  • unchecked — вход ещё не наблюдался.

Для причины смотрите problems, error и failure_cause. current: false само по себе не означает отказ: исправный резерв не выбран для эфира. Проверяйте давность checked_at и сравнивайте media_info обоих входов: разные кодеки или геометрия не дают основания ожидать бесшовную смену.

Время на основном и резервных входах

Подробную секцию input читайте прямым запросом к стримеру, который принимает tv1. Central отдаёт компактное текущее состояние и эту секцию не запрашивает у стримера:

curl -fsS -u "$ADMIN_USER:$ADMIN_PASSWORD" \
  http://streamer:8080/streamer/api-v4/streams/stats/tv1 \
  | jq '.input | {primary_s: (.num_sec_on_primary_input // 0), secondary_s: (.num_sec_on_secondary_input // 0), no_data_s: (.num_sec_no_data // 0), switches: (.input_switches // 0), retries: (.retries // 0)}'

Эти накопительные значения считаются секундными тиками за время жизни статистики стрима. num_sec_on_secondary_input суммирует все входы после первого, а не только второй. num_sec_no_data считает секунды после таймаута отсутствия данных. Нулевые поля могут отсутствовать; // 0 допустим только внутри реально полученной секции input. Отсутствие самой секции не означает нулевое время.

Пример двух замеров:

{"t0":{"primary_s":3600,"secondary_s":120,"no_data_s":0},
 "t1":{"primary_s":3640,"secondary_s":140,"no_data_s":0}}

За интервал основной вход использовался 40 с, резервные — 20 с; доля резерва среди времени с данными — 20 / (40 + 20) = 33.3%. Считайте разность последовательных снимков. Если счёт уменьшился после перезапуска или переноса стрима, начните новый интервал; не складывайте отрицательные разности.

Что дальше