Skip to content

Commit

Permalink
feat(playout): configure device for alsa and pulseaudio system outputs (
Browse files Browse the repository at this point in the history
#2654)

### Description

Add hardware configuration to liquidsoap so that users may
set hardware output in config.yml.

---------

Co-authored-by: jo <ljonas@riseup.net>
  • Loading branch information
maxtimbo and jooola committed Dec 29, 2023
1 parent 9d6061e commit 06af18b
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 11 deletions.
4 changes: 4 additions & 0 deletions docker/config.template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -326,3 +326,7 @@ stream:
# > must be one of (alsa, ao, oss, portaudio, pulseaudio)
# > default is pulseaudio
kind: pulseaudio

# System output device.
# > only available for kind=(alsa, pulseaudio)
device:
4 changes: 4 additions & 0 deletions docker/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -326,3 +326,7 @@ stream:
# > must be one of (alsa, ao, oss, portaudio, pulseaudio)
# > default is pulseaudio
kind: pulseaudio

# System output device.
# > only available for kind=(alsa, pulseaudio)
device:
4 changes: 4 additions & 0 deletions docker/example/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -326,3 +326,7 @@ stream:
# > must be one of (alsa, ao, oss, portaudio, pulseaudio)
# > default is pulseaudio
kind: pulseaudio

# System output device.
# > only available for kind=(alsa, pulseaudio)
device:
6 changes: 5 additions & 1 deletion docs/admin-manual/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -526,11 +526,15 @@ stream:
system:
- # Whether the output is enabled.
# > default is false
enabled: false
enabled: true
# System output kind.
# > must be one of (alsa, ao, oss, portaudio, pulseaudio)
# > default is 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
Expand Down
4 changes: 4 additions & 0 deletions installer/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -326,3 +326,7 @@ stream:
# > must be one of (alsa, ao, oss, portaudio, pulseaudio)
# > default is pulseaudio
kind: pulseaudio

# System output device.
# > only available for kind=(alsa, pulseaudio)
device:
1 change: 1 addition & 0 deletions legacy/application/configs/conf.php
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ public function getConfigTreeBuilder()
/* */->validate()->ifNotInArray(["alsa", "ao", "oss", "portaudio", "pulseaudio"])
/* */->thenInvalid('invalid stream.outputs.system.kind %s')
/* */->end()->end()
/* */->scalarNode('device')->end()
/**/->end()->end()->end()

->end()->end()
Expand Down
31 changes: 26 additions & 5 deletions playout/libretime_playout/liquidsoap/templates/outputs.liq.j2
Original file line number Diff line number Diff line change
Expand Up @@ -117,20 +117,41 @@ output.shoutcast(
)
{%- endmacro -%}

{% for output in config.stream.outputs.system -%}
{% if output.enabled -%}
# {{ output.kind.value }}:{{ loop.index }}
{#-
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 }}:{{ 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
{%- 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 -%}
{%- for output in config.stream.outputs.icecast -%}
{% if output.enabled -%}
{{ output_icecast(loop.index, output) }}

Expand Down
54 changes: 53 additions & 1 deletion playout/tests/liquidsoap/__snapshots__/entrypoint_test.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,10 @@
log("output.pulseaudio is not defined!")
%endif
%ifdef output.pulseaudio
output.pulseaudio(id="pulseaudio:1", s)
output.pulseaudio(
id="pulseaudio:1",
s
)
%endif


Expand Down Expand Up @@ -355,6 +358,55 @@

%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")
Expand Down
11 changes: 11 additions & 0 deletions playout/tests/liquidsoap/fixtures/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,17 @@ def make_config_with_stream(**kwargs) -> Config:
"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(
outputs={
"system": [{"enabled": False, "kind": "alsa"}],
Expand Down
41 changes: 37 additions & 4 deletions shared/libretime_shared/config/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,24 +216,57 @@ class ShoutcastOutput(BaseModel):
mobile: bool = False


class SystemOutputKind(str, Enum):
class SystemOutput(str, Enum):
ALSA = "alsa"
AO = "ao"
OSS = "oss"
PORTAUDIO = "portaudio"
PULSEAUDIO = "pulseaudio"


class SystemOutput(BaseModel):
class BaseSystemOutput(BaseModel):
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
class Outputs(BaseModel):
icecast: List[IcecastOutput] = Field([], max_length=3)
shoutcast: List[ShoutcastOutput] = Field([], max_length=1)
system: List[SystemOutput] = Field([], max_length=1)
system: List[AnySystemOutput] = Field([], max_length=1)

@property
def merged(self) -> List[Union[IcecastOutput, ShoutcastOutput]]:
Expand Down

0 comments on commit 06af18b

Please sign in to comment.