ShiromMakkad / LedFxDocker

A Docker Container for LedFx.
56 stars 19 forks source link

Does this project supersede the need for a USB audio card recommended by LedFx? #22

Open mbalasz opened 12 months ago

mbalasz commented 12 months ago

Hi,

First of all, thank you for creating this project. It's awesome and I managed to get it up and running fairly quickly. This is not really an issue, but more of a post with questions.

On the official page of https://ledfx.readthedocs.io/en/latest/installing.html#raspberry-pi-installation, they say I need a USB audio card for a raspberry pi. I am actually running your container on raspberry pi 3 and it works with the built-in audio card. Is the main reason for this that you integrated snapcast into this repository and did some magic to direct the audio to LedFx with use of snapcast (basically the 50 hours of work you mention in the README :))? I haven't tried just running LedFx without your container so I'm not sure if USB audio card is necessary there too, but I assume yes given the documentation.

If the answer to the above is yes, then I'm curious if your work would ever be upstreamed to LedFx to make it work on a stock RPi without extra audio cards. Don't get me wrong, I support your project, but it would be even better if it was used in the original LedFx for the sake of simplicity and lower maintenance.

No call for action here, mere curiosity. Thank you again for this amazing contribution.

ShiromMakkad commented 12 months ago

You were able to get this working with the built in audio card? I tried getting it to work just because people have been asking, but I couldn't get it working. I'm using a Schiit Modi for all my audio anyways. Can you share how you did it so I can put it in the examples section?

I'd guess they updated the drivers or LedFx, and the LedFx doc isn't updated. If it's working, it's working. You don't need an external card.

mbalasz commented 11 months ago

Hi,

Sorry for a delay, but I stumbled upon extra challenges when trying to set up LedFX with a BT streaming. In the original post I only tried Spotify connect, which was easier to set up.

Yes, I just used the built-in audio card, but note that I'm not interested in using an actual microphone (which Pis don't have). I want LedFX to use my BT audio as input. I guess if you want an actual microphone, you need to buy something like this.

I made a small personal note on how to make this setup work and I'm more than happy to share it. Let me paste it here for now. DISCLAIMER: I know very little about sound on Linux and everything in the guide below is based on the knowledge I acquired in the process of building this project. It's possible that my understanding of some concepts (especially ALSA's loopback) is wrong, so take it with a grain of salt and correct me wherever applicable.

Software

How it works

image

Note that I'm using a BT USB dongle as the built-in BT has quality issues especially when you use Wi-Fi at the same time to stream to WLED.

Setup

Bluetooth

bluez-alsa

Follow this very well written wiki to locally build bluez-alsa. Use the --enable-systemd extra option to create a bluealsa systemd service which can be enabled at boot. Once installed, start and enable bluealsa service:

$ sudo systemctl enable --now bluealsa

A2DP

A2DP allows your phone to stream audio via BT. In order to establish the A2DP connection between your phone and Pi, you need an agent that handles pairing and authorization of your device. Follow this gist which is mostly up to date. One change I needed to do is comment out the raise Rejected("Connection rejected") exception in the script, because for some reason the agent didn't think my phone was connecting via A2DP and it would throw. However, bypassing this check doesn't cause any issues and the BT streaming works fine.

Testing

Double check that bluealsa service is running. Start the A2DP agent to pair your phone. Once paired, run bluealsa-aplay. Play a song on your phone and you should hear it in headphones/speakers connected to Pi's mini Jack.

ALSA loopback

We'll need to create an ALSA loopback interface, so that bluealsa-aplay writes the audio stream to the loopback's sink and snapserver reads that stream from the corresponding loopback source. Read this gist for a concise explanation on how loopback works.

Load ALSA loopback module.

$ sudo modprobe snd-aloop

Now, when you run aplay -l you should get a new virtual card with two loopback devices. You will write to one of the devices (sink) and read from the other (source). For example, assuming your loopback card number is 3, you can have the following routing:

bluealsa-aplay ==> hw:3,1,2 [Sink] ==> hw:3,0,2 [Source] ==> snapserver 

Which subdevice to use?

There's usually 8 subdevices per loopback device. If one of the loopback devices shows 7/8 subdevices, make sure to test which ones are working.

Snapcast

Download snapclient_<version>_armhf.deb and snapserver_<version>_armhf.deb from the release page and install with apt install ./path_to_deb_file.

Snapserver

Change the source in /etc/snapserver.conf to ALSA. Change <hw:3,0> to point to your loopback device (run aplay -l to find this information).

source = alsa:///?name=SnapcastAlsa&device=hw:3,0

Restart snapserver with sudo systemctl restart snapserver.

Lastly, make sure you point bluealsa-aplay to the loopback sink with

$ bluealsa-aplay --pcm=hw:3,1

IMPORTANT: The first application opening one of the subdevices will force the second application to use the same set of parameters: sample rate, format, number of channels. Ideally, specify the same parameters on both snapserver and bluealsa-aplay. Otherwise, you might get errors from bluealsa-aplay about invalid arguments.

Couldn't open ALSA playback PCM: Set HW params: Set sampling rate: Invalid argument: 44100

Either specify the same rate in /etc/snapserver.conf, e.g.: sampleformat = 44100:16:2 or start bluealsa-aplay before snapserver as snapserver seems to adapt to whatever format is specified.

Snapclient Now make sure that you have a local snapclient running sudo systemctl enable --now snapclient, which will capture snapserver's audio stream and play it to ALSA's built-in audio device (like a headphone jack in the case of a raspberry pi). It's important that the snapclient uses the correct ALSA PCM device for playback. It's possible that it defaults to Loopback, which will cause all kinds of issues, because you will continuously refeed the loopback with the same stream. Per snapcast's documentation you can specify the soundcard with -s flag:

$ snapclient --player alsa -s Headphones
# or
$ snapclient --player alsa -s 1

To use those settings for systemd's snapclient, edit /etc/default/snapclient

SNAPCLIENT_OPTS="--player alsa -s Headphones"

LedFX

Time to start LedFXDocker. If you're running both the snapserver and the ledfx docker on the same machine, use the host network mode in docker-compose.yml:

version: '3'

services:
  ledfx:
    image: shirom/ledfx 
    container_name: ledfx
    network_mode: host
    environment: 
      - HOST=127.0.0.1
    ports:
      - 8888:8888
    volumes:
      - ~/ledfx-config:/app/ledfx-config

Start the container with docker compose up -d and once it's up and running go to http://<raspberry-pi-ip-address>:8888 which should open LedFX interface. Find your WLED devices and start LedFX for them.

At this point you should be hearing sound from your Rasbperry Pi's audio interface and see the WLED lights run the show.

Bonus: Spotify

Snapcast supports spotify connect. Make sure you have librespot (easily installed via raspotify) installed on your system and simply change snapserver's source to:

source = spotify:///librespot?name=Spotify&devicename=Snapcast&bitrate=320

Restart snapserver and you should now see the Snapcast cast device on your Spotify client.