171 lines
4.8 KiB
Django/Jinja
171 lines
4.8 KiB
Django/Jinja
{#-
|
|
Build an audio encoder usable by the icecast or shoutcast output functions,
|
|
using the output audio configuration
|
|
#}
|
|
{%- macro icecast_encoder(audio) -%}
|
|
|
|
{%- if audio.format == "ogg" -%}
|
|
{%- set quality_mapping = {
|
|
32: "-0.1", 48: "-0.1", 64: "0", 96: "0.2", 128: "0.4",
|
|
160: "0.5", 192: "0.6", 224: "0.7", 256: "0.8", 320: "0.9",
|
|
} -%}
|
|
%ogg(%vorbis(
|
|
quality={{ quality_mapping[audio.bitrate] }},
|
|
channels={{ 2 if audio.channels == "stereo" else 1 }}
|
|
))
|
|
|
|
{%- elif audio.format == "mp3" -%}
|
|
%mp3(
|
|
bitrate={{ audio.bitrate }},
|
|
stereo={{ "true" if audio.channels == "stereo" else "false" }}
|
|
)
|
|
|
|
{%- elif audio.format == "opus" -%}
|
|
%opus(
|
|
bitrate={{ audio.bitrate }},
|
|
channels={{ 2 if audio.channels == "stereo" else 1 }},
|
|
signal="music",
|
|
application="audio",
|
|
complexity=10,
|
|
vbr="constrained"
|
|
)
|
|
|
|
{%- elif audio.format == "aac" -%}
|
|
%fdkaac(
|
|
bitrate={{ audio.bitrate }},
|
|
aot={{ ("mpeg4_he_aac_v2" if audio.bitrate <= 64 else "mpeg4_aac_lc") | quote }},
|
|
afterburner={{ "false" if audio.bitrate <= 128 else "true" }},
|
|
sbr_mode=true
|
|
)
|
|
|
|
{%- endif -%}
|
|
{%- endmacro -%}
|
|
|
|
{#-
|
|
Build an icecast output the output configuration.
|
|
#}
|
|
{%- macro output_icecast(output_id, output) -%}
|
|
# icecast:{{ output_id }}
|
|
{#- Handle stereo or mono output #}
|
|
{% if output.audio.channels == "stereo" -%}
|
|
output_icecast_{{ output_id }}_source = s
|
|
{% else -%}
|
|
output_icecast_{{ output_id }}_source = mean(s)
|
|
{% endif -%}
|
|
|
|
{#- Add per output stream modifications. -#}
|
|
{% if output.audio.format == "ogg" and not output.audio.enable_metadata -%}
|
|
# Disable ogg metadata
|
|
output_icecast_{{ output_id }}_source = add(normalize=false, [amplify(0.00001, noise()), output_icecast_{{ output_id }}_source])
|
|
{% endif -%}
|
|
|
|
output.icecast(
|
|
id="icecast:{{ output_id }}",
|
|
host={{ output.host | quote }},
|
|
port={{ output.port }},
|
|
mount={{ output.mount | quote }},
|
|
user={{ output.source_user | quote }},
|
|
password={{ output.source_password | quote }},
|
|
fallible = true,
|
|
name={{ (output.name or '') | quote }},
|
|
description={{ (output.description or '') | quote }},
|
|
genre={{ (output.genre or '') | quote }},
|
|
url={{ (output.website or '') | quote }},
|
|
on_connect=make_ouput_on_connect_handler("{{ output_id }}"),
|
|
on_error=make_ouput_on_error_handler("{{ output_id }}"),
|
|
{{ icecast_encoder(output.audio) | indent(width=2) }},
|
|
output_icecast_{{ output_id }}_source,
|
|
)
|
|
{%- endmacro -%}
|
|
|
|
{#-
|
|
Build a shoutcast output the output configuration.
|
|
#}
|
|
{%- macro output_shoutcast(output_id, output) -%}
|
|
# shoutcast:{{ output_id }}
|
|
{#- Handle stereo or mono output #}
|
|
{% if output.audio.channels == "stereo" -%}
|
|
output_shoutcast_{{ output_id }}_source = s
|
|
{% else -%}
|
|
output_shoutcast_{{ output_id }}_source = mean(s)
|
|
{% endif -%}
|
|
|
|
output.shoutcast(
|
|
id="shoutcast:{{ output_id }}",
|
|
host={{ output.host | quote }},
|
|
port={{ output.port }},
|
|
{#- Shoutcast does not have any mount
|
|
mount={{ output.mount | quote }},
|
|
#}
|
|
user={{ output.source_user | quote }},
|
|
password={{ output.source_password | quote }},
|
|
fallible = true,
|
|
{#- Pass output.description to name and ignore output.name
|
|
name={{ (output.name or '') | quote }},
|
|
description={{ (output.description or '') | quote }},
|
|
#}
|
|
name={{ (output.description or '') | quote }},
|
|
genre={{ (output.genre or '') | quote }},
|
|
url={{ (output.website or '') | quote }},
|
|
on_connect=make_ouput_on_connect_handler("{{ output_id }}"),
|
|
on_error=make_ouput_on_error_handler("{{ output_id }}"),
|
|
{#-
|
|
The config validation will prevent from using incompatible audio encoders
|
|
#}
|
|
{{ icecast_encoder(output.audio) | indent(width=2) }},
|
|
output_shoutcast_{{ output_id }}_source,
|
|
)
|
|
{%- endmacro -%}
|
|
|
|
{#-
|
|
Build a system output configuration.
|
|
#}
|
|
{%- macro output_system(output_id, output) -%}
|
|
# {{ output.kind.value }}:{{ output_id }}
|
|
%ifndef output.{{ output.kind.value }}
|
|
log("output.{{ output.kind.value }} is not defined!")
|
|
%endif
|
|
%ifdef output.{{ output.kind.value }}
|
|
output.{{ output.kind.value }}(
|
|
id="{{ output.kind.value }}:{{ output_id }}",
|
|
{%- if output.kind.value == "alsa" %}
|
|
{%- if output.device is not none %}
|
|
device="{{ output.device }}",
|
|
{%- endif %}
|
|
{%- elif output.kind.value == "pulseaudio" %}
|
|
{%- if output.device is not none %}
|
|
device="{{ output.device }}",
|
|
{%- endif %}
|
|
{%- endif %}
|
|
s
|
|
)
|
|
%endif
|
|
{%- endmacro -%}
|
|
|
|
{# ############################### #}
|
|
|
|
{%- for output in config.stream.outputs.system -%}
|
|
{% if output.enabled -%}
|
|
{{ output_system(loop.index, output) }}
|
|
|
|
{% endif -%}
|
|
{% endfor -%}
|
|
|
|
{%- for output in config.stream.outputs.icecast -%}
|
|
{% if output.enabled -%}
|
|
{{ output_icecast(loop.index, output) }}
|
|
|
|
{% endif -%}
|
|
{% endfor -%}
|
|
|
|
{% for output in config.stream.outputs.shoutcast -%}
|
|
{% if output.enabled -%}
|
|
{#
|
|
Icecast and Shoutcast streams are merged in legacy, so we need to use a custom index
|
|
as stream id.
|
|
-#}
|
|
{{ output_shoutcast((config.stream.outputs.icecast | length) + loop.index, output) }}
|
|
|
|
{% endif -%}
|
|
{% endfor -%}
|