feat(playout): configure device for alsa and pulseaudio system outputs (#2654)
### Description Add hardware configuration to liquidsoap so that users may set hardware output in config.yml. --------- Co-authored-by: jo <ljonas@riseup.net>
This commit is contained in:
parent
9d6061e42e
commit
06af18b84e
|
@ -326,3 +326,7 @@ stream:
|
||||||
# > must be one of (alsa, ao, oss, portaudio, pulseaudio)
|
# > must be one of (alsa, ao, oss, portaudio, pulseaudio)
|
||||||
# > default is pulseaudio
|
# > default is pulseaudio
|
||||||
kind: pulseaudio
|
kind: pulseaudio
|
||||||
|
|
||||||
|
# System output device.
|
||||||
|
# > only available for kind=(alsa, pulseaudio)
|
||||||
|
device:
|
||||||
|
|
|
@ -326,3 +326,7 @@ stream:
|
||||||
# > must be one of (alsa, ao, oss, portaudio, pulseaudio)
|
# > must be one of (alsa, ao, oss, portaudio, pulseaudio)
|
||||||
# > default is pulseaudio
|
# > default is pulseaudio
|
||||||
kind: pulseaudio
|
kind: pulseaudio
|
||||||
|
|
||||||
|
# System output device.
|
||||||
|
# > only available for kind=(alsa, pulseaudio)
|
||||||
|
device:
|
||||||
|
|
|
@ -326,3 +326,7 @@ stream:
|
||||||
# > must be one of (alsa, ao, oss, portaudio, pulseaudio)
|
# > must be one of (alsa, ao, oss, portaudio, pulseaudio)
|
||||||
# > default is pulseaudio
|
# > default is pulseaudio
|
||||||
kind: pulseaudio
|
kind: pulseaudio
|
||||||
|
|
||||||
|
# System output device.
|
||||||
|
# > only available for kind=(alsa, pulseaudio)
|
||||||
|
device:
|
||||||
|
|
|
@ -526,11 +526,15 @@ stream:
|
||||||
system:
|
system:
|
||||||
- # Whether the output is enabled.
|
- # Whether the output is enabled.
|
||||||
# > default is false
|
# > default is false
|
||||||
enabled: false
|
enabled: true
|
||||||
# System output kind.
|
# System output kind.
|
||||||
# > must be one of (alsa, ao, oss, portaudio, pulseaudio)
|
# > must be one of (alsa, ao, oss, portaudio, pulseaudio)
|
||||||
# > default is pulseaudio
|
# > default is pulseaudio
|
||||||
kind: "pulseaudio"
|
kind: "pulseaudio"
|
||||||
|
|
||||||
|
# System output device.
|
||||||
|
# > only available for kind=(alsa, pulseaudio)
|
||||||
|
device: "alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__hw_sofhdadsp__sink"
|
||||||
```
|
```
|
||||||
|
|
||||||
## LDAP
|
## LDAP
|
||||||
|
|
|
@ -326,3 +326,7 @@ stream:
|
||||||
# > must be one of (alsa, ao, oss, portaudio, pulseaudio)
|
# > must be one of (alsa, ao, oss, portaudio, pulseaudio)
|
||||||
# > default is pulseaudio
|
# > default is pulseaudio
|
||||||
kind: pulseaudio
|
kind: pulseaudio
|
||||||
|
|
||||||
|
# System output device.
|
||||||
|
# > only available for kind=(alsa, pulseaudio)
|
||||||
|
device:
|
||||||
|
|
|
@ -211,6 +211,7 @@ class Schema implements ConfigurationInterface
|
||||||
/* */->validate()->ifNotInArray(["alsa", "ao", "oss", "portaudio", "pulseaudio"])
|
/* */->validate()->ifNotInArray(["alsa", "ao", "oss", "portaudio", "pulseaudio"])
|
||||||
/* */->thenInvalid('invalid stream.outputs.system.kind %s')
|
/* */->thenInvalid('invalid stream.outputs.system.kind %s')
|
||||||
/* */->end()->end()
|
/* */->end()->end()
|
||||||
|
/* */->scalarNode('device')->end()
|
||||||
/**/->end()->end()->end()
|
/**/->end()->end()->end()
|
||||||
|
|
||||||
->end()->end()
|
->end()->end()
|
||||||
|
|
|
@ -117,20 +117,41 @@ output.shoutcast(
|
||||||
)
|
)
|
||||||
{%- endmacro -%}
|
{%- endmacro -%}
|
||||||
|
|
||||||
{% for output in config.stream.outputs.system -%}
|
{#-
|
||||||
{% if output.enabled -%}
|
Build a system output configuration.
|
||||||
# {{ output.kind.value }}:{{ loop.index }}
|
#}
|
||||||
|
{%- macro output_system(output_id, output) -%}
|
||||||
|
# {{ output.kind.value }}:{{ output_id }}
|
||||||
%ifndef output.{{ output.kind.value }}
|
%ifndef output.{{ output.kind.value }}
|
||||||
log("output.{{ output.kind.value }} is not defined!")
|
log("output.{{ output.kind.value }} is not defined!")
|
||||||
%endif
|
%endif
|
||||||
%ifdef output.{{ output.kind.value }}
|
%ifdef output.{{ output.kind.value }}
|
||||||
output.{{ output.kind.value }}(id="{{ output.kind.value }}:{{ loop.index }}", s)
|
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
|
%endif
|
||||||
|
{%- endmacro -%}
|
||||||
|
|
||||||
|
{# ############################### #}
|
||||||
|
|
||||||
|
{%- for output in config.stream.outputs.system -%}
|
||||||
|
{% if output.enabled -%}
|
||||||
|
{{ output_system(loop.index, output) }}
|
||||||
|
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
{% endfor -%}
|
{% endfor -%}
|
||||||
|
|
||||||
{% for output in config.stream.outputs.icecast -%}
|
{%- for output in config.stream.outputs.icecast -%}
|
||||||
{% if output.enabled -%}
|
{% if output.enabled -%}
|
||||||
{{ output_icecast(loop.index, output) }}
|
{{ output_icecast(loop.index, output) }}
|
||||||
|
|
||||||
|
|
|
@ -315,7 +315,10 @@
|
||||||
log("output.pulseaudio is not defined!")
|
log("output.pulseaudio is not defined!")
|
||||||
%endif
|
%endif
|
||||||
%ifdef output.pulseaudio
|
%ifdef output.pulseaudio
|
||||||
output.pulseaudio(id="pulseaudio:1", s)
|
output.pulseaudio(
|
||||||
|
id="pulseaudio:1",
|
||||||
|
s
|
||||||
|
)
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -355,6 +358,55 @@
|
||||||
|
|
||||||
%include "/fake/1.4/ls_script.liq"
|
%include "/fake/1.4/ls_script.liq"
|
||||||
|
|
||||||
|
# pulseaudio:1
|
||||||
|
%ifndef output.pulseaudio
|
||||||
|
log("output.pulseaudio is not defined!")
|
||||||
|
%endif
|
||||||
|
%ifdef output.pulseaudio
|
||||||
|
output.pulseaudio(
|
||||||
|
id="pulseaudio:1",
|
||||||
|
device="alsa_output.pci-0000_00_sink",
|
||||||
|
s
|
||||||
|
)
|
||||||
|
%endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
gateway("started")
|
||||||
|
|
||||||
|
'''
|
||||||
|
# ---
|
||||||
|
# name: test_generate_entrypoint[stream_config7-1.4]
|
||||||
|
'''
|
||||||
|
# THIS FILE IS AUTO GENERATED. PLEASE DO NOT EDIT!
|
||||||
|
###########################################################
|
||||||
|
# The ignore() lines are to squash unused variable warnings
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
input_main_mount = "main"
|
||||||
|
input_main_port = 8001
|
||||||
|
input_main_secure = false
|
||||||
|
input_show_mount = "show"
|
||||||
|
input_show_port = 8002
|
||||||
|
input_show_secure = false
|
||||||
|
|
||||||
|
# Settings
|
||||||
|
set("log.file.path", "/var/log/radio.log")
|
||||||
|
|
||||||
|
set("server.telnet", true)
|
||||||
|
set("server.telnet.bind_addr", "127.0.0.1")
|
||||||
|
set("server.telnet.port", 1234)
|
||||||
|
|
||||||
|
set("harbor.bind_addrs", ["0.0.0.0"])
|
||||||
|
|
||||||
|
station_name = interactive.string("station_name", "LibreTime")
|
||||||
|
|
||||||
|
message_offline = interactive.string("message_offline", "LibreTime - offline")
|
||||||
|
message_format = interactive.string("message_format", "0")
|
||||||
|
input_fade_transition = interactive.float("input_fade_transition", 0.0)
|
||||||
|
|
||||||
|
%include "/fake/1.4/ls_script.liq"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
gateway("started")
|
gateway("started")
|
||||||
|
|
|
@ -92,6 +92,17 @@ TEST_STREAM_CONFIGS: List[Config] = [
|
||||||
"system": [{"enabled": True, "kind": "pulseaudio"}],
|
"system": [{"enabled": True, "kind": "pulseaudio"}],
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
make_config_with_stream(
|
||||||
|
outputs={
|
||||||
|
"system": [
|
||||||
|
{
|
||||||
|
"enabled": True,
|
||||||
|
"kind": "pulseaudio",
|
||||||
|
"device": "alsa_output.pci-0000_00_sink",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
),
|
||||||
make_config_with_stream(
|
make_config_with_stream(
|
||||||
outputs={
|
outputs={
|
||||||
"system": [{"enabled": False, "kind": "alsa"}],
|
"system": [{"enabled": False, "kind": "alsa"}],
|
||||||
|
|
|
@ -216,7 +216,7 @@ class ShoutcastOutput(BaseModel):
|
||||||
mobile: bool = False
|
mobile: bool = False
|
||||||
|
|
||||||
|
|
||||||
class SystemOutputKind(str, Enum):
|
class SystemOutput(str, Enum):
|
||||||
ALSA = "alsa"
|
ALSA = "alsa"
|
||||||
AO = "ao"
|
AO = "ao"
|
||||||
OSS = "oss"
|
OSS = "oss"
|
||||||
|
@ -224,16 +224,49 @@ class SystemOutputKind(str, Enum):
|
||||||
PULSEAUDIO = "pulseaudio"
|
PULSEAUDIO = "pulseaudio"
|
||||||
|
|
||||||
|
|
||||||
class SystemOutput(BaseModel):
|
class BaseSystemOutput(BaseModel):
|
||||||
enabled: bool = False
|
enabled: bool = False
|
||||||
kind: SystemOutputKind = SystemOutputKind.PULSEAUDIO
|
|
||||||
|
|
||||||
|
class ALSASystemOutput(BaseSystemOutput):
|
||||||
|
kind: Literal[SystemOutput.ALSA] = SystemOutput.ALSA
|
||||||
|
device: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
|
class AOSystemOutput(BaseSystemOutput):
|
||||||
|
kind: Literal[SystemOutput.AO] = SystemOutput.AO
|
||||||
|
|
||||||
|
|
||||||
|
class OSSSystemOutput(BaseSystemOutput):
|
||||||
|
kind: Literal[SystemOutput.OSS] = SystemOutput.OSS
|
||||||
|
|
||||||
|
|
||||||
|
class PortAudioSystemOutput(BaseSystemOutput):
|
||||||
|
kind: Literal[SystemOutput.PORTAUDIO] = SystemOutput.PORTAUDIO
|
||||||
|
|
||||||
|
|
||||||
|
class PulseAudioSystemOutput(BaseSystemOutput):
|
||||||
|
kind: Literal[SystemOutput.PULSEAUDIO] = SystemOutput.PULSEAUDIO
|
||||||
|
device: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
|
AnySystemOutput = Annotated[
|
||||||
|
Union[
|
||||||
|
ALSASystemOutput,
|
||||||
|
AOSystemOutput,
|
||||||
|
OSSSystemOutput,
|
||||||
|
PortAudioSystemOutput,
|
||||||
|
PulseAudioSystemOutput,
|
||||||
|
],
|
||||||
|
Field(discriminator="kind", default=SystemOutput.PULSEAUDIO),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=too-few-public-methods
|
# pylint: disable=too-few-public-methods
|
||||||
class Outputs(BaseModel):
|
class Outputs(BaseModel):
|
||||||
icecast: List[IcecastOutput] = Field([], max_length=3)
|
icecast: List[IcecastOutput] = Field([], max_length=3)
|
||||||
shoutcast: List[ShoutcastOutput] = Field([], max_length=1)
|
shoutcast: List[ShoutcastOutput] = Field([], max_length=1)
|
||||||
system: List[SystemOutput] = Field([], max_length=1)
|
system: List[AnySystemOutput] = Field([], max_length=1)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def merged(self) -> List[Union[IcecastOutput, ShoutcastOutput]]:
|
def merged(self) -> List[Union[IcecastOutput, ShoutcastOutput]]:
|
||||||
|
|
Loading…
Reference in New Issue