#!/usr/bin/env bash # Tee muxer targets: local file, named pipe, HLS dir, RTMP sinks list. set -euo pipefail # shellcheck disable=SC1091 source "$(dirname "${BASH_SOURCE[0]}")/common.sh" read_sinks() { SINKS=() [[ -f "${SINKS_LIST}" ]] || return 0 while IFS= read -r line; do line="${line%%#*}" line="$(echo "${line}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" [[ -n "${line}" ]] && SINKS+=("${line}") done < "${SINKS_LIST}" } pipe_tee_entry() { local pipe="$1" printf "[select='v:0,a':f=flv:onfail=ignore:use_fifo=1:fifo_options='fifo_format=flv:drop_pkts_on_overflow=1:attempt_recovery=1:recovery_wait_time=1']%s" "${pipe}" } file_tee_entry() { local path="$1" local fmt="${RECORD_FORMAT}" case "${fmt}" in mkv) printf "[select='v:0,a':f=matroska:onfail=ignore]%s" "${path}" ;; flv|*) printf "[select='v:0,a':f=flv:onfail=ignore]%s" "${path}" ;; esac } hls_tee_entry() { local dir="$1" mkdir -p "${dir}" printf "[select='v:0,a':f=hls:onfail=ignore:hls_time=2:hls_list_size=6:hls_flags=delete_segments+append_list]%s/index.m3u8" "${dir}" } rtmp_tee_entry() { local url="$1" printf "[select='v:0,a':f=flv:onfail=ignore]%s" "${url}" } # Encode stage: record + pipe (+ optional HLS). RTMP fanout is copy stage. build_encode_tee_spec() { local record="$1" local pipe="$2" local parts=() parts+=("$(file_tee_entry "${record}")") parts+=("$(pipe_tee_entry "${pipe}")") if [[ -n "${HLS_OUTPUT_DIR}" ]]; then parts+=("$(hls_tee_entry "${HLS_OUTPUT_DIR}")") fi local IFS='|' echo "${parts[*]}" } # Fanout stage: copy from pipe to all sinks (no re-encode). build_fanout_tee_spec() { read_sinks local parts=() local s for s in "${SINKS[@]}"; do parts+=("$(rtmp_tee_entry "${s}")") done [[ ${#parts[@]} -gt 0 ]] || die "no sinks in ${SINKS_LIST}" local IFS='|' echo "${parts[*]}" }