PulseAudio on OpenWRT with MPD and other Stuff

READ THIS FIRST: ALSA Basics - Wiki.TerraBase.info

First of all, good to be back. Issues with MediaWiki, along with time constraints on fixing it, have prevented new articles from being created.

Anyway, working on several different Routers running OpenWRT 23.05.03 using PulseAudio, MPD (MPC), Bluetooth (BlueZ), and a bunch of other stuff including PulseMixer (works great on OpenWRT, even though the 'required' version is above the version of Python3 available in OpenWRT).

Starting Thoughts

The PulseAudio people are brilliant. But their documentation is a bit questionable. Case in point is the https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/Network/ page. It starts off on a big tangent, then seems to go off on other tangents before addressing the main concepts. That's cool and not a complaint against the PulseAudio people. It's just a little note to let people know who are reading it and just want to get RTP to work that they shouldn't get frustrated. Just keep reading, ignore most of the stuff at the beginning and you'll get there.

A Deep, Deep Hole with PulseAudio at the Very Beginning (on OpenWRT)

The nice people with the OpenWRT project and all their hard work is very much appreciated. But there are also the head scratching (and head exploding) moments too. For instance: How can so much effort be put into something, yet one little item is allowed to (or isn't configured correctly) remain in place that prevents the PulseAudio service from operating properly?

Short Answer: Configure and / or compile the PulseAudio Service in such way that it requires whatever user (including the ROOT User!) be a member of the audio Group. And then don't put that User in the Audio Group as part of the installation. There you go, problem created! And all the work done to include PulseAudio in OpenWRT? Pointless (until the issue is corrected).

The issue? As noted, the root User is not included in the audio Group. Add it in there using groupadd (which in and of itself is interesting to install) or just edit the /etc/group File.

Ready? Let's Install PulseAudio (and dependencies, plus other tools, and see what happens)

Installation of Software

opkg update

opkg install pulseaudio-daemon-avahi pulseaudio-profiles pulseaudio-tools

Do NOT install pulseaudio-daemon (plain), if you want to use Bluetooth to connect to Speakers. The pulseaudio-daemon-avahi contains the necessary bluetooth modules, pulseaudio-daemon (plain) does NOT. One can always disable the avahi service too, without affecting PulseAudio.

Dependencies include some basic ALSA (Advanced Linux Sound Architecture) stuff, but a couple of more items are nice to have for several reason, including testing, so;

opkg install alsa-utils alsa-ucm-conf mpd-full mpd-avahi-service mpc libmpdclient

...and maybe opkg install madplay mpg123 (they don't install any services, so they're just there if you need them)

And some other tools related to hardware: opkg install usbutils pciutils

A nice graphical way to control some aspects of PulseAudio is PulseMixer: https://github.com/GeorgeFilipkin/pulsemixer?tab=readme-ov-file

...but first: opkg install python3 (don't worry that the OpenWRT version of Python 3 is lower than the required version of PulseMixer, as it seems to work fine)

The Errors

Are these the errors referred to earlier as the "show stopper" for PulseAudio. Nope. Just an annoyance that can be fixed.

chown: /dev/mixer: No such file or directory
chown: /dev/dsp: No such file or directory
chmod: /dev/mixer: No such file or directory
chmod: /dev/dsp: No such file or directory

Will this fix it (spoiler alert, NO, so like Frankie said "don't do it")?: opkg install gst1-mod-dvdspu gst1-mod-audiomixer (a bunch of dependencies would be installed too). We'll get to the fix later, let's focus on the "Show Stopper". Just kidding, fix is below;

  • ...just make sure the Audio Device is plugged in.
The "Show Stopper" for PulseAudio

Issue this command (it is for 'talking' to the PulseAudio Service): pactl list short sinks

The result: Connection failure: Access denied

Why (as noted earlier, but more details and a solution later): The root User (that's right, the ROOT user) doesn't have the privileges to execute the command. WTF!?

How long did it take to figure out and what was the anger level: 10 Page Diatribe DELETED

Solution: Add the root user to the Audio Group: nano /etc/group;

Before: audio:x:29:
After: audio:x:29:root,mpd

Result: It forking works now: pactl list short sinks

There's a bunch of stuff about Cookies (one of PulseAudio's security methods), anonymous authentication, etc., but this is the simplest and works without changing PulseAudio's default configuration.

Surround Sound

First thing to do is this, enable or put this item in the /etc/pulse/default.conf file: default-sample-channels = 6

Then add all of the below instead (to cut down on any pops and hisses;

Bluetooth (AKA Bluez)

Installation

opkg install bluez-daemon bluez-libs bluez-tools bluez-utils bluez-utils-btmon bluez-utils-extra kmod-input-uinput (other dependencies will install too)

...and that's just the basic Bluetooth stuff. It doesn't include the firmware and driver for any specific hardware

Hardware

Bluetooth hardware is fairly inexpensive these days. To 'future-proof' things as much as possible, order hardware with the latest and greatest version of Bluetooth. As of this writing, summer 2024, Bluetooth 5.3 is the contemporary version.

A nice feature to have is a removable antenna. There are more compact devices that don't have removable antennas. And if you want super cheap device, step down to Bluetooth 4.x (still works great with speakers).

 
Bluetooth Controller - A nice feature to have is a removable Antenna.

Oh, one obnoxious note with Bluez and PulseAudio on OpenWRT is that as of this writing, even though Bluetooth 5.x supports two sets of speakers, just can't make a single controller connect to more than one speaker. Woof!

Example of installing firmware and drivers for Bluetooth Hardware: opkg install rtl8761bu-firmware (bu is the version of the rtl8761 that was designed to work with USB 2.0, so if you're hooking up to a USB 3.0 port, this will work, but according to documentation, won't be optimized. PS: Bluetooth to Speaker will not exceed USB 2.0 speeds).

Example to install Firmware and Drivers: opkg install rtl8761bu-firmware kmod-bluetooth kmod-usb-core kmod-usb2 kmod-usb3 kmod-usb-ohci kmod-usb-uhci kmod-usb-hid  kmod-hid kmod-cfg80211

FIRST! (or rather the next thing to do)

Because OpenWRT doesn't include of the Bluez Tools (nope, not Blues Clues), make sure PulseAudio has the Bluetooth Modules loaded up and ready to go!


Crap that Does NOT work

btmgmt "connect" (doesn't exist)

hcitool cc WhatEverMACaddress (doesn't work)


ALSA Related Commands

Starting and Stopping ALSA

Good luck! Ain't no ALSA service. Oh, wait, try the following (it's the only solution besides restarting that seems to work, because modpropbe seems to be 'neutered' on OpenWRT with no additional 'modprobe package' available);

  • "Stop ALSA Service": echo '1-1' > /sys/bus/usb/drivers/usb/unbind
  • "Start ALSA Service": echo '1-1' > /sys/bus/usb/drivers/usb/bind
  • ...followed by: alsactl restore
  • ...and just as a note, stopping and starting pulseaudio has the net effect of re-reading the /etc/asound.conf file.
  • ...and pkill -9 pulseaudio (works great if the process is 'stuck', and don't forget okpg install procps-ng-pkill)

/usr/share/pulseaudio/alsa-mixer/paths/ : Path to ALSAMIXER settings (yup, PulseAudio is in the path!)

/proc/asound/card0/usbmixer : possible location where ALSAMIXER gets names for different controls

alsactl : Good for testing basic sound device settings (Top Tip: By default, for whatever reason, the "state" (AKA stored configuration) Directory (/var/lib/alsa) does not exist, so create it.

aplay -D stereoB BeeGees.wav

aplay -D hw:0,0 -c 6 BeeGees.wav -vv : Will show information and a 'meter', along with playing the song.

speaker-test -D hw:0,0 -c 4 --chmap=FL,FR,FC,LFE -t wav : Tests the speaker output (make sure alsa-utils-tests is installed), --chmap "allows for putting things in a different order".

/var/lib/alsa/asound.state : Filie in a Directory (gonna have to create the 'alsa' sub-directory manually as it isn't created during ALSA installation) that preserves settings in ALSA Mixer

alsactl store

speaker-test -D hw:0,0 -c 8 --chmap=FL,FR,FC,LFE,SL,SR,SL,SR -t wav : For testing 7.1 surround sound, with a catch: Ain't no RL (Rear Left) or RR (Rear Right), there are two SL (Side Left(s)) and two SR (Side Right(s)). Hey, it is what it is. Now you know.

amixer -c 0 sset 'PCM Capture Source' 'Line' : A handy command to change the input of a USB Audio Device that support more than one input / source. Keep in mind the two items in the quotes ( 'PCM Capture Source' and 'Line' ) are potentially unique to every USB Audio Device. How can one get that information? A couple commands (some noted below with details, but for now, just the commands): amixer scontrols (that's two words / commands typed together) and then: amixer -c 0 get 'PCM Capture Source' ( again, modify the item in ' ' (quotes) to the name obtained in the previous command)

alsamixer: shows a text GUI of controls

cat /sys/kernel/debug/usb/devices : shows details about various USB Devices

aplay -l : shows list of sound devices

aplay -L : Shows a list of the various output ports

arecord -l : Shows a list of input / source devices (note, if PulseAudio is running and / or using a device it will show the device as 0, IE, 'unavailable')

arecord -L : Shows a 'limited' list of the input / source devices

amixer scontrols : Shows a 'brief' list of devices

amixer scontents : Shows a detailed list of devices

alsactl info : Shows information about sound device

amixer -c 0 controls : Shows detailed information about the controls_count variable from alsactl info

amixer -c 0 cget numid=1 : Shows even more detailed information about the 'control' from amixer command above

amixer -c 0 get 'WhatEverNameOfDevice' : 'Gets' the 'capabilities' of an 'item' / device ( WhatEverNameOfDevice can be obtained with the amixer scontents command above)

Example below;

amixer scontrols

Simple mixer control 'Speaker',0
Simple mixer control 'PCM',0
Simple mixer control 'PCM Capture Source',0
Simple mixer control 'Line',0
Simple mixer control 'Mic',0
Simple mixer control 'IEC958 In',0


amixer sdevices

Simple mixer control 'Speaker',0
  Capabilities: pvolume pswitch pswitch-joined
  Playback channels: Front Left - Front Right - Rear Left - Rear Right - Front Center - Woofer - Side Left - Side Right
  Limits: Playback 0 - 197
  Mono:
  Front Left: Playback 184 [93%] [-2.44dB] [on]
  Front Right: Playback 184 [93%] [-2.44dB] [on]
  Rear Left: Playback 196 [99%] [-0.19dB] [on]
  Rear Right: Playback 196 [99%] [-0.19dB] [on]
  Front Center: Playback 196 [99%] [-0.19dB] [on]
  Woofer: Playback 196 [99%] [-0.19dB] [on]
  Side Left: Playback 196 [99%] [-0.19dB] [on]
  Side Right: Playback 196 [99%] [-0.19dB] [on]
Simple mixer control 'PCM',0
  Capabilities: cvolume cswitch cswitch-joined
  Capture channels: Front Left - Front Right
  Limits: Capture 0 - 6928
  Front Left: Capture 4096 [59%] [-0.01dB] [on]
  Front Right: Capture 4096 [59%] [-0.01dB] [on]
Simple mixer control 'PCM Capture Source',0
  Capabilities: enum
  Items: 'Mic' 'Line' 'IEC958 In' 'Mixer'
  Item0: 'Line'
Simple mixer control 'Line',0
  Capabilities: pvolume cvolume pswitch pswitch-joined cswitch cswitch-joined
  Playback channels: Front Left - Front Right
  Capture channels: Front Left - Front Right
  Limits: Playback 0 - 8065 Capture 0 - 6928
  Front Left: Playback 4781 [59%] [-5.33dB] [off] Capture 4507 [65%] [1.60dB] [on]
  Front Right: Playback 4781 [59%] [-5.33dB] [off] Capture 4507 [65%] [1.60dB] [on]
Simple mixer control 'Mic',0
  Capabilities: pvolume cvolume pswitch pswitch-joined cswitch cswitch-joined
  Playback channels: Front Left - Front Right
  Capture channels: Front Left - Front Right
  Limits: Playback 0 - 8065 Capture 0 - 6928
  Front Left: Playback 5046 [63%] [-4.30dB] [off] Capture 2451 [35%] [-6.43dB] [on]
  Front Right: Playback 5046 [63%] [-4.30dB] [off] Capture 2451 [35%] [-6.43dB] [on]
Simple mixer control 'IEC958 In',0
  Capabilities: cswitch cswitch-joined
  Capture channels: Mono
  Mono: Capture [on]

The above output from the amixer scontrols and amixer sdevices command shows the following;

The 'Speaker' is actually a 7.1 Surround Sound USB Audio Device with several physical AUX / 1/8" / 3.5mm Output Jacks

The 'PCM' is a equates to a "Master Volume" control
The 'PCM Capture Source' is the currently selected input / source (mic, line, or SPDIF)
The 'Line' is represented physically by an AUX / 1/8" / 3.5mm Input Jack ("traditionally" blue)
The 'Mic' is represented physically by an AUX / 1/8" / 3.5mm Input Jack ("traditionally" pink), and on this device, there are actually two physical Jacks, but the software doesn't know this because the Jacks are simply wired in parallel.
The 'IEC958' is represented physically by the SPDIF Jack for a Fiber Optic Cable
...and for this device, the SPDIF output isn't represented to software and apparently is just 'wired' up like a "monitor", where it gets constant full output and cannot be controlled in software (oh, well)
...another oddity of the above specific device, that one wouldn't readily see from the configuration, but becomes apparent in use is that the Line and Mic levels do nothing, but the Capture Source levels do allow for adjustment of levels (oh, well, each sound device will have it's own oddities)

Some WTF? Holes One Can Fall Into

module-detect

In /etc/pulse/system.pa load-module module-detect (Works great, but can also cause some unexpected issues)

Try adding this to the system.pa file: load-module module-alsa-sink device=hw:0,0

...and: Error opening PCM device hw:0: Resource busy, Failed to load module "module-alsa-source" (argument: "device_id=0"): initialization failed.

Why? Because module-detect found it first!

Experiments showed that even loading module-detect after module-alsa-sink still produces an error. So either module-detect always runs first OR module-detect doesn't check and see if an ALSA device is already loaded.

module-native-protocol-unix

If the module-native-protocol-unix isn't loaded ( load-module module-native-protocol-unix ) then the PACTL Command won't work.

The error will be: pa_context_connect() failed: Connection refused

Web / HTML GUIs

amixer-webui

opkg install git git-http libmbedtls python3 python3-pip (assumes ALSA is installed already) (substitute python2 for older versions of OpenWRT)

pip3 install flask

git clone https://github.com/JiriSko/amixer-webui.git

./alsamixer_webui.py -p 8080 -l W.X.Y.Z (where W.X.Y.Z is the IP Address of the router)

amixer-web

...won't work as OpenWRT doesn't have the ALSA Mixer "library.so" files or packages

viacast - alsamixer

Looks great. Doesn't work (even though it shows the correct USB realtek chip). On a side note, REACT installs and works on OpenWRT (Hmmm, a good thing???)

Useful Commands for Testing (from a live file, hence the # Comment Tags)

Multi-Channel Testing (first need a multi-channel file)

sox CominUnderFire.mp3 --show-progress -t wav CominUnderFire_6ch.wav remix 1v0.8 2v0.8 1v0.5 2v0.5 1v0.3 2v0.3

Input File     : 'CominUnderFire.mp3'

Channels       : 2

Sample Rate    : 44100

Precision      : 16-bit

Duration       : 00:04:14.49 = 11223097 samples = 19086.9 CDDA sectors

File Size      : 10.2M

Bit Rate       : 320k

Sample Encoding: MPEG audio (layer I, II or III)

Comments       :

Title=08 - Comin' Under Fire

Artist=Def Leppard

Album=Pyromania

Tracknumber=8

Genre=Power Metal

In:100%  00:04:14.48 [00:00:00.01] Out:11.2M [      |      ] Hd:2.6 Clip:0   

Done.

...and what channels are available from a device, well, use this command: amixer -c 0 scontents

Below is the output for a 7.1 surround USB Audio Device;

Simple mixer control 'PCM',0
  Capabilities: pvolume pswitch pswitch-joined
  Playback channels: Front Left - Front Right - Rear Left - Rear Right - Front Center - Woofer - Side Left - Side Right
  Limits: Playback 0 - 87
  Mono:
  Front Left: Playback 37 [43%] [-37.50dB] [on]
  Front Right: Playback 37 [43%] [-37.50dB] [on]
  Rear Left: Playback 60 [69%] [-20.25dB] [on]
  Rear Right: Playback 60 [69%] [-20.25dB] [on]
  Front Center: Playback 60 [69%] [-20.25dB] [on]
  Woofer: Playback 60 [69%] [-20.25dB] [on]
  Side Left: Playback 60 [69%] [-20.25dB] [on]
  Side Right: Playback 60 [69%] [-20.25dB] [on]
Simple mixer control 'PCM',1
  Capabilities: pvolume pswitch pswitch-joined
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 87
  Mono:
  Front Left: Playback 4 [5%] [-62.25dB] [on]
  Front Right: Playback 4 [5%] [-62.25dB] [on]
Simple mixer control 'Line',0
  Capabilities: cvolume cswitch cswitch-joined
  Capture channels: Front Left - Front Right
  Limits: Capture 0 - 56
  Front Left: Capture 16 [29%] [0.00dB] [on]
  Front Right: Capture 16 [29%] [0.00dB] [on]
Simple mixer control 'Mic',0
  Capabilities: cvolume cswitch cswitch-joined
  Capture channels: Front Left - Front Right
  Limits: Capture 0 - 56
  Front Left: Capture 16 [29%] [0.00dB] [on]
  Front Right: Capture 16 [29%] [0.00dB] [on]
root@PandoraWRT:/MP3#


### Useful Commands for testing stuff;

### /usr/bin/mpd --no-daemon /etc/mpd.conf --verbose

### /usr/bin/pulseaudio --system --disallow-exit --disable-shm --exit-idle-time=-1 --realtime=false --verbose

### bluetoothctl connect FC:58:FA:2E:BA:7C

### bluetoothctl connect F4:4E:FC:EA:3B:33 for the Bluetooth Transceiver Device in Rx Mode

###

### bluetoothctl devices Connected (the C in Connected has to be capitalized)

###

### btmgmt is another command.

###

### btmgmt --index 0 connectable on

### btmgmt bondable on

### btmgmt discov yes

### btmgmt find on OR just plain find

###

### ...after playing with btmgmt, is is very busted on OpenWRT

###

### pactl set-sink-volume bluez_sink.FC_58_FA_2E_BA_7C.a2dp_sink 10%

### alsamixer

### ls /usr/lib/pulse-*/modules/

### pactl list modules short

### pactl list short sinks

###

### pactl info

### pactl list sources short

### pactl load-module module-loopback source=WhatEverNameOfSink

###

### pactl load-module module-loopback source=3 sink=0

### pactl set-sink-volume 0 100%

### pactl set-source-volume 3 100%

### pactl list modules

### pactl list sink-inputs

###

### pacmd is a command too

###

### /usr/bin/pulseaudio --system --disallow-exit --disable-shm --exit-idle-time=-1 --verbose

### /usr/bin/pulseaudio --system --disallow-exit --disable-shm --exit-idle-time=-1 --verbose --log-level=debug --log-target=stderr

### /usr/bin/pulseaudio --system --disallow-exit --disable-shm --exit-idle-time=-1 -vvvvvv --log-level=debug --log-target=stderr

###

### Device F4:4E:FC:EA:3B:33 BT17

### Device FC:58:FA:2E:BA:7C Gemini GHSI-W650BT

###

### aplay WhatEverSongAsLongAsItIs.WAV <-- PulseAudio service must be stopped! (same for sox)

###

### hcitool dev

### hciconfig -a

###

### ...inside of bluetoothctl

###### list (to show bluetooth controllers)

###### devices

######

###### select... one of the following;

###### 5C:F3:70:9C:2B:20 ( ASUS 4.0 )

###### 8A:88:4B:80:F5:CB ( RealTek 5.3 )

######

######

######

### mpc -h password@10.100.100.47 lsplaylist

### mpc -h password@10.100.100.47 playlist

### mpc -h password@10.100.100.47 add

### mpc -h password@10.100.100.47 del

### mpc -h password@10.100.100.47 clear

### mpc -h password@10.100.100.47 load

### mpc -h password@10.100.100.47 save

### mpc -h password@10.100.100.47 status

### mpc -h password@10.100.100.47 current (current song playing)

### mpc -h password@10.100.100.47 queued (next song up)

### mpc -h password@10.100.100.47

### mpc -h password@10.100.100.47

### mpc -h password@10.100.100.47

### mpc -h password@10.100.100.47 update ("Update" the fact there are new songs in the physical directory.  After adding song to physical directory, can't play or add to playlist without UPDATE)

###

### opkg install bluez-daemon bluez-libs bluez-tools bluez-utils bluez-utils-btmon bluez-utils-extra kmod-input-uinput

### opkg install pulseaudio-daemon-avahi pulseaudio-profiles pulseaudio-tools

### opkg install mpd-avahi-service mpd-full mpc libmpdclient

### opkg install alsa-lib alsa-ucm-conf alsa-utils gst1-mod-alsa

###

### opkg install rtl8761bu-firmware kmod-bluetooth kmod-usb-core kmod-usb2 kmod-usb3 kmod-usb-ohci kmod-usb-uhci kmod-usb-hid  kmod-hid kmod-cfg80211

###

### opkg install shadow-groupadd shadow-useradd shadow-usermod

### usermod

### ...OR: nano /etc/group: audio:x:29:root,mpd

###

### opkg install coreutils-stat procps-ng-pgrep (for the bt-reconnect service)

###

### Files to modify (from previously configured devices): /etc/init.d/pulseaudio, /etc/pulse/system.pa, /etc/mpd.conf, asound.conf (maybe)

### ^^^ Remember to adjust the source sinks and bluetooth sinks for devices

### Configuration Services and Scripts (by me): /etc/init.d/bt-reconnect, /etc/bluetooth.sh, /etc/pulse/pulseaudio.sh


Rough Notes;

The below two items are functionally equivalent;


pcm.LINE {

    type plug

    slave.pcm {

        type route

        slave.pcm "hw:0,0"

        slave.channels 2

        ttable.0.0 1

        ttable.1.1 1

    }

}



pcm.line {

    type dmix

    ipc_key 1024

    slave {

        pcm "hw:0,0"

        channels 2

    }

}

# Line Test

pcm.LINE {

    type plug

    slave.pcm {

        type route

        slave.pcm "line"

        slave.channels 2

        ttable.0.0 1

        ttable.1.1 1

    }

}