# Hardware Configuration

**URL:** <https://discourse.libretime.org/t/hardware-configuration/1229>\
**Category:** Uncategorized\
**Created:** [May 25, 2022, 11:13pm UTC](https://discourse.libretime.org/t/hardware-configuration/1229 "2022-05-25T23:13:47Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![maxtimbo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.libretime.org/maxtimbo/32/611_2.png) [@maxtimbo](https://discourse.libretime.org/u/maxtimbo)\
**Post date:** [May 25, 2022, 11:13pm UTC](https://discourse.libretime.org/t/hardware-configuration/1229/1 "2022-05-25T23:13:47Z")

</div>

I have two Audio Science ASI6044 cards installed to an Ubuntu 20.04 server. This gives me 16 mono channels out, or 8 stereo channels. How can I configure the LibreTime to use a specific output? (I have installed the official driver from AudioScience, which recommends ALSA. I can only select `output type` in the settings page.) Note that I’m not afraid of tweaking database entries, config settings, etc.

---

<div class="post-metadata">

**Author:** ![maxtimbo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.libretime.org/maxtimbo/32/611_2.png) [@maxtimbo](https://discourse.libretime.org/u/maxtimbo)\
**Post date:** [May 27, 2022, 2:32am UTC](https://discourse.libretime.org/t/hardware-configuration/1229/2 "2022-05-27T02:32:04Z")

</div>

So maybe a good starting point might be; what is the mechanism that outputs audio to the hardware device? Is that liquidsoap?

---

<div class="post-metadata">

**Author:** ![joola](https://avatars.discourse-cdn.com/v4/letter/j/cab0a1/32.png) [@joola](https://discourse.libretime.org/u/joola)\
**Post date:** [August 25, 2022, 12:56pm UTC](https://discourse.libretime.org/t/hardware-configuration/1229/3 "2022-08-25T12:56:02Z")

</div>

Currently the system outputs configuration are really basic, and does not provide any options.

I expect this to change once we merged [feat: use file based stream configuration by jooola · Pull Request #1986 · libretime/libretime · GitHub](https://github.com/libretime/libretime/pull/1986) which should allow to add options more easily.  
This is for no power users though.

You could dig into the liquidsoap scripts and add you own output by hand.

> **[Liquidsoap - Audio & Video Streaming Language](https://www.liquidsoap.info/doc-1.4.4/reference.html#output.alsa)**
>
> Swiss-army knife for multimedia streaming

---

<div class="post-metadata">

**Author:** ![maxtimbo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.libretime.org/maxtimbo/32/611_2.png) [@maxtimbo](https://discourse.libretime.org/u/maxtimbo)\
**Post date:** [July 29, 2023, 3:18am UTC](https://discourse.libretime.org/t/hardware-configuration/1229/4 "2023-07-29T03:18:32Z")

</div>

I am once again exploring this idea, except I am using docker containers rather than installing it to the system. Ideally, I’d like to have six containers running at the same time. Is it yet possible to define an alsa output? Using mplayer, I’d define `alsa:device=hw=2.0.0` or `alsa:device=hw=3.0.1`, etc. Is such a mechanism possible here?

---

<div class="post-metadata">

**Author:** ![joola](https://avatars.discourse-cdn.com/v4/letter/j/cab0a1/32.png) [@joola](https://discourse.libretime.org/u/joola)\
**Post date:** [July 29, 2023, 8:54am UTC](https://discourse.libretime.org/t/hardware-configuration/1229/5 "2023-07-29T08:54:38Z")

</div>

> **[How to setup a PulseAudio output inside containers | LibreTime](https://libretime.org/docs/admin-manual/tutorials/setup-a-pulseaudio-output-inside-containers/)**
>
> This tutorials walks you though the steps required to setup a PulseAudio output when running LibreTime inside containers.

---

<div class="post-metadata">

**Author:** ![maxtimbo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.libretime.org/maxtimbo/32/611_2.png) [@maxtimbo](https://discourse.libretime.org/u/maxtimbo)\
**Post date:** [July 29, 2023, 4:11pm UTC](https://discourse.libretime.org/t/hardware-configuration/1229/6 "2023-07-29T16:11:04Z")

</div>

I’ve read through that tutorial but I’m not seeing where I would specify which output for which socket, assuming I would create a different socket per output/container.

---

<div class="post-metadata">

**Author:** ![maxtimbo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.libretime.org/maxtimbo/32/611_2.png) [@maxtimbo](https://discourse.libretime.org/u/maxtimbo)\
**Post date:** [August 2, 2023, 1:47pm UTC](https://discourse.libretime.org/t/hardware-configuration/1229/7 "2023-08-02T13:47:53Z")

</div>

I was reading through the source code and found that the system outputs are generated by a Jinja2 template

outputs.liq.j2:

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

{% endif -%}
{% endfor -%}

```

According to the liquidsoap docs:

> [`output.alsa`](https://www.liquidsoap.info/doc-1.4.4/reference.html#output.alsa)
> 
> Output the source’s stream to an ALSA output device.
> 
> Type:
> 
> ```auto
> (?id : string, ?bufferize : bool, ?clock_safe : bool,
> ?device : string, ?fallible : bool,
> ?on_start : (() -> unit), ?on_stop : (() -> unit),
> ?start : bool, source(audio='#a+1, video='#b, midi='#c)) ->
> active_source(audio='#a+1, video='#b, midi='#c)
> 
> ```

So if I specified `alsa` in `config.yml`, `outputs.liq.j2` would output `output.alsa(id=alsa...` because the output and the id are coupled. Which isn’t great. Is it possible to decouple those two variables so I can specify the correct hardware output? I haven’t figured out how the `outputs.liq.j2` file interacts with the `config.yml` file yet.

Edit: The ID doesn’t matter so much. There would need to be an additional variable for `device`. The final config would look like `output.alsa(id="alsa", device="hw:3,0,0")` where `device="hw:<card_number>,<device_number>,<subdevice_number>"`

---

<div class="post-metadata">

**Author:** ![maxtimbo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.libretime.org/maxtimbo/32/611_2.png) [@maxtimbo](https://discourse.libretime.org/u/maxtimbo)\
**Post date:** [August 4, 2023, 11:49pm UTC](https://discourse.libretime.org/t/hardware-configuration/1229/8 "2023-08-04T23:49:18Z")

</div>

I tried tweaking the outputs.liq.j2 file and the shared/libretime\_shared/config/\_models.py files to accept a `device` field:

`libretime/playout/libretime/libretime_playout/liquidsoap/templates/outputs.liq.j2`

```auto
120 {% for output in config.stream.outputs.system -%}
121 {% if output.enabled -%}
122 # {{ output.kind.value }}:{{ loop.index }}
123 %ifndef output.{{ output.kind.value }}
124 log("output.{{ output.kind.value }} is not defined!")
125 %endif
126 %ifdef output.{{ output.kind.value }}
127 output.{{ output.kind.value }}(
128 id="{{ output.kind.value }}:{{ loop.index }}",
129 device="{{ output.device.value }}",
130 s
131 )
132 %endif

```

`libretime/share/libretime_shared/config/_models.py`

```auto
256 class SystemOutput(BaseModel):
257 enabled: bool = False
258 kind: SystemOutputKind = SystemOutputKind.ALSA
259 device: Optional[str] = None

```

This was to allow the device to be set in `config.yml`

```auto
    system:
      - # Whether the output is enabled.
        # > default is false
        enabled: true
        # System output kind.
        # > must be one of (alsa, ao, oss, portaudio, pulseaudio)
        # > default is alsa
        kind: alsa
        device: hw:2,0,3

```

Unfortunately, I think I’m missing something during the ingest or an entry to the postgres database. The resulting `radio.liq` file looks like:  
`/var/lib/docker/volumes/stat1_libretime_playout/_data/radio.liq`

```auto
# alsa:1
%ifndef output.alsa
log("output.alsa is not defined!")
%endif
%ifdef output.alsa
output.alsa(
  id="alsa:1",
  device="",
  s
)
%endif

```

Any advice would be appreciated…

---

<div class="post-metadata">

**Author:** ![maxtimbo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.libretime.org/maxtimbo/32/611_2.png) [@maxtimbo](https://discourse.libretime.org/u/maxtimbo)\
**Post date:** [August 5, 2023, 1:42pm UTC](https://discourse.libretime.org/t/hardware-configuration/1229/9 "2023-08-05T13:42:28Z")

</div>

Just to update my “notes” here; I was able to make the device parameter populate the radio.liq file by removing `.value`:

`libretime/playout/libretime/libretime_playout/liquidsoap/templates/outputs.liq.j2`

```auto
120 {% for output in config.stream.outputs.system -%}
121 {% if output.enabled -%}
122 # {{ output.kind.value }}:{{ loop.index }}
123 %ifndef output.{{ output.kind.value }}
124 log("output.{{ output.kind.value }} is not defined!")
125 %endif
126 %ifdef output.{{ output.kind.value }}
127 output.{{ output.kind.value }}(
128 id="{{ output.kind.value }}:{{ loop.index }}",
129 device="{{ output.device }}",
130 s
131 )
132 %endif

```

At this point I am having trouble finding the correct parameter to populate the `config.yml` files. Some settings that I have tried:

| setting | | result |
| --- | --- | --- |
| hw:2,0,0 | | Thread “alsa:1” aborts with exception Alsa error: No such file or directory! |
| hw:2.0.0 | | Thread “alsa:1” aborts with exception Alsa error: Device or resource busy! |
| hw:2.0 | | Thread “alsa:1” aborts with exception Alsa error: Device or resource busy! |
| hw:CARD=ASI6500,DEV=0 | | Thread “alsa:1” aborts with exception Alsa error: Device or resource busy! |

Any other variants of these settings for the other card or other outputs result in the same output here. I have attempted to add the `libretime` user to the `audio` group by adding a line in the Dockerfile:

`libretime/Dockerfile`

```auto
 26 # Custom user
 27 ARG USER=libretime
 28 ARG UID=1000
 29 ARG GID=1000
 30 
 31 RUN set -eux \
 32 && adduser --disabled-password --uid=$UID --gecos '' --no-create-home ${USER} \
 33 && install --directory --owner=${USER} /etc/libretime /srv/libretime \
 34 && usermod -aG audio libretime

```

That did not change anything at all. I may not have done that correctly.

---

<div class="post-metadata">

**Author:** ![joola](https://avatars.discourse-cdn.com/v4/letter/j/cab0a1/32.png) [@joola](https://discourse.libretime.org/u/joola)\
**Post date:** [August 12, 2023, 12:57pm UTC](https://discourse.libretime.org/t/hardware-configuration/1229/10 "2023-08-12T12:57:04Z")

</div>

Being able to extand the different output option was on my todo list. But I didnt find time to extend this yet. You did it the rigt way.

Maybe you should look into using/extending the pulseaudio output instead ? You probably will have a better chance to route you audio to the right place.

---

<div class="post-metadata">

**Author:** ![joola](https://avatars.discourse-cdn.com/v4/letter/j/cab0a1/32.png) [@joola](https://discourse.libretime.org/u/joola)\
**Post date:** [August 12, 2023, 12:58pm UTC](https://discourse.libretime.org/t/hardware-configuration/1229/11 "2023-08-12T12:58:23Z")

</div>

Aah and for docker to stream audio, you have to mount the hardward into docker or mount the socket of pulseaudio.

Look at the docs to have an example on how to set this up using docker and pulseaudio.

---

<div class="post-metadata">

**Author:** ![maxtimbo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.libretime.org/maxtimbo/32/611_2.png) [@maxtimbo](https://discourse.libretime.org/u/maxtimbo)\
**Post date:** [August 13, 2023, 3:16am UTC](https://discourse.libretime.org/t/hardware-configuration/1229/12 "2023-08-13T03:16:47Z")

</div>

> [@joola](#):
>
> Being able to extand the different output option was on my todo list. But I didnt find time to extend this yet. You did it the rigt way.

Despite this, I am still receiving thefollowing error when I try to navigate to [host]:[port]:

`could not parse configuration: Unrecognized option "device" under ".stream.outputs.system.0". Available options are "enabled", "kind".`

This made me think the issue is with the old php code, so I dug into that and found:  
`libretime/legacy/application/models/StreamSettings.php`:

```auto
141 public static function getStreamSetting()
142 {
143 $settings = [];
144 $numStreams = MAX_NUM_STREAMS;
145 for ($streamIdx = 1; $streamIdx <= $numStreams; ++$streamIdx) {
146 $settings = array_merge($settings, self::getStreamData('s' . $streamIdx));
147 }
148 $settings['master_live_stream_port'] = self::getMasterLiveStreamPort();
149 $settings['master_live_stream_mp'] = self::getMasterLiveStreamMountPoint();
150 $settings['dj_live_stream_port'] = self::getDjLiveStreamPort();
151 $settings['dj_live_stream_mp'] = self::getDjLiveStreamMountPoint();
152 $settings['off_air_meta'] = Application_Model_Preference::getOffAirMeta();
153 $settings['icecast_vorbis_metadata'] = self::getIcecastVorbisMetadata();
154 $settings['output_sound_device'] = self::getOutputSoundDevice();
155 $settings['output_sound_device_type'] = self::getOutputSoundDeviceType();
156 $settings['output_sound_device_device'] = self::getOutputSoundDeviceDevice();
157 
158 return $settings;
159 }

[. . .]

235 public static function getOutputSoundDevice()
236 {
237 return Config::get('stream.outputs.system.0.enabled') ?? 'false';
238 }
239 
240 public static function getOutputSoundDeviceType()
241 {
242 return Config::get('stream.outputs.system.0.kind') ?? '';
243 }
244 
245 public static function getOutputSoundDeviceDevice()
246 {
247 return Config::get('stream.outputs.system.0.device') ?? '';
248 }
249 }

```

I added line 156 and lines 245 to 248. This still hasn’t worked, so I’m wondering if there is another place where I need to call the function or add something somewhere else. (getOutputSoundDeviceDevice seems like a dumb function name lol).

> [@joola](#):
>
> Maybe you should look into using/extending the pulseaudio output instead ?

The main reason I’ve been focusing my effort toward ALSA is because the Audio Science cards I’m using; I’m not sure if they will play nice with PulseAudio. Although, since Pulse is just a wrapper for ALSA, it ~should~ work.

---

<div class="post-metadata">

**Author:** ![joola](https://avatars.discourse-cdn.com/v4/letter/j/cab0a1/32.png) [@joola](https://discourse.libretime.org/u/joola)\
**Post date:** [August 13, 2023, 9:14am UTC](https://discourse.libretime.org/t/hardware-configuration/1229/13 "2023-08-13T09:14:39Z")

</div>

The config validation happens in 2 places, in the shared models as well as in php config schema. You need to edit both so they match.

Though the php code is not required for the radio.liq file generztion. Only the python shared models

If you want me to help you out for this, I propose that you open a Pull Request on Github so I can review and guide you through the required steps to get this working. We should also be able to make this available to other once its working!

I prefer pulseaudio also because it doesn’t lock the sound card to a specific client, going through the pulseaudio server allows you more flexibility.

---

<div class="post-metadata">

**Author:** ![joola](https://avatars.discourse-cdn.com/v4/letter/j/cab0a1/32.png) [@joola](https://discourse.libretime.org/u/joola)\
**Post date:** [August 14, 2023, 5:19pm UTC](https://discourse.libretime.org/t/hardware-configuration/1229/14 "2023-08-14T17:19:00Z")

</div>

I’ll check the PR tomorrow morning, I already have a small idea why it is not working.

You might need to follow the pattern using by the AudioFormat for the Output and apply to the SystemOutputs models. I’ll push changes tomorrow morning as well if you didnt catch that.

---

<div class="post-metadata">

**Author:** ![maxtimbo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.libretime.org/maxtimbo/32/611_2.png) [@maxtimbo](https://discourse.libretime.org/u/maxtimbo)\
**Post date:** [August 15, 2023, 2:22pm UTC](https://discourse.libretime.org/t/hardware-configuration/1229/15 "2023-08-15T14:22:27Z")

</div>

I was actually able to get the legacy code to recognize the `device` setting. See my PR for the changes in the code. However, I am still seeing `ALSA device busy` error, which means I am not mounting the device properly with docker. I am curious to see how this might run with just installing it, though.

So, when the radio.liq file is generated, that’s it, right? I mean, if you want to make a change, you would have to regenerate that file and then restart playout/liquidsoap in order to take the new config. I noticed that the settings for system output are now gone in the web gui. If we got this to work, would we be able to add this functionality back into the web gui with the addition of `device`? Maybe add a print out in some clever way of `aplay -lL` to show which device can be assigned, or maybe even format them into a dropdown or something to make it easier for users to find the device they want to use and use it.

Might be a pipe dream there, but I think worth exploring once this works.

---

<div class="post-metadata">

**Author:** ![joola](https://avatars.discourse-cdn.com/v4/letter/j/cab0a1/32.png) [@joola](https://discourse.libretime.org/u/joola)\
**Post date:** [August 15, 2023, 4:25pm UTC](https://discourse.libretime.org/t/hardware-configuration/1229/16 "2023-08-15T16:25:21Z")

</div>

Have a look at this guide [Container sound: ALSA or Pulseaudio · mviereck/x11docker Wiki · GitHub](https://github.com/mviereck/x11docker/wiki/Container-sound:-ALSA-or-Pulseaudio#alsa)

I think I used this guide to write: [How to setup a PulseAudio output inside containers | LibreTime](https://libretime.org/docs/admin-manual/tutorials/setup-a-pulseaudio-output-inside-containers/)

I really prefer pulseaudio as you don’t lock the sound card for this single process.

---

<div class="post-metadata">

**Author:** ![joola](https://avatars.discourse-cdn.com/v4/letter/j/cab0a1/32.png) [@joola](https://discourse.libretime.org/u/joola)\
**Post date:** [August 15, 2023, 4:27pm UTC](https://discourse.libretime.org/t/hardware-configuration/1229/17 "2023-08-15T16:27:02Z")

</div>

Editing the config from the UI is not supported, and will not be supported. A readonly view might be considered in a future change though, but I think we should focus on the python/yaml/liquidsoap for now, and leave the UI stuff for a future change.
