I've been experimenting with bluetooth and squeezelite on Alpine Linux. I'm going to use this thread to document my misadventures. My initial goal was to take the Wyse 3030LT (N06D) pictured and have the onboard audio jack at the front, the Apple USB DAC at the rear, and bluetooth headphones all playing the same audio from squeezelite. Further, I wanted to be able to pair my phone and play audio from the phone source (eg. Amazon Prime Music) over the same outputs without interfering with squeezelite.
I was able to accomplish that so I will document what I have so far in case it's of any interest. This may already be well documented here on the forum but I haven't really looked, so forgive me if this is all repeated info. I tried many different variations of the alsa /etc/asound.conf some worked, some didn't. The one I have below will likely change, I'm not really convinced yet of the right approach to take. I know pCP is supporting bluetooth now and I've read the main thread on it but I haven't installed it or looked at any of the scripts to see how they are handling it. It would be cool to get some feedback from Paul and team on that, or feedback in general from anyone! I had a asound.conf that didn't use the Loopback device at all but something was telling me I needed to feed everything through the loopback and have a separate alsaloop process for each device. As I said above, not convinced this is the way to go. I also had a sort of working solution with two local squeezebox processes in a sync group but that felt pretty ugly and I ditched it fairly quickly. The basic idea here is that the default playback device is the Loopback and stereo audio is duplicated across multiple Loopback channels. Each alsaloop instance gets the same audio from a different Loopback output and feeds a different hardware output. The bt-pair.sh script is my clunky solution to managing pairing of new devices though still very much a work in progress. The script uses a LMS response on the status of the local squeezelite player and greps for certain words to decide whether to kick off the pairing process or exit. So to initiate, you select your player in LMS and play a track I added to the library that has "bluetooth-player" in the track name. Then you power off the player from LMS, which fires the script and both criteria are met: the correct track title and power state, then you pair from the phone. I'm going to skip all the standard Alpine setup steps I take and just focus on the squeezelite/bluetooth/alsa stuff. I added the following packages: alsa-utils bluez-alsa squeezelite linux-lts-5.4.49-r0.apk - I had to rebuild the kernel to enable the snd-aloop module. This should be enabled in future stock Alpine kernels, see: https://gitlab.alpinelinux.org/alpine/aports/-/issues/11699 Configure things to run at boot: rc-update add squeezelite rc-update add alsa rc-update add bluealsa rc-update add local I'm using the following squeezelite options set in /etc/conf.d/squeezelite: Code: -------------------- SL_OPTS="-n Desk -S /home/sodface/bt-pair.sh" -------------------- More on the -S option later: Code: -------------------- -S <Power Script> Absolute path to script to launch on power commands from LMS -------------------- Added the following line to the /etc/init.d/bluealsa startup script: Code: -------------------- command_args="-S -p a2dp-source -p a2dp-sink" -------------------- Using the following settings in /etc/bluetooth/main.conf Code: -------------------- Name = Desk AlwaysPairable = true AutoEnable = true -------------------- Added snd-aloop to /etc/modules: Code: -------------------- af_packet ipv6 snd-aloop -------------------- Created a local startup script in /etc/local.d/ with the following commands: Code: -------------------- bluetoothctl discoverable off bluealsa-aplay 00:00:00:00:00:00 & alsaloop -C hw:Loopback,1,0 -P hw:A,0 -t 500000 & alsaloop -C hw:Loopback,1,1 -P hw:PCH,0 -t 500000 & alsaloop -C hw:Loopback,1,2 -P "btheadset" -t 1100000 & -------------------- Contents of /etc/asound.conf Code: -------------------- pcm.!default plug:aloopx ctl.!default { type hw card PCH } pcm.aloopx { type route; slave.pcm { type multi; slaves.a.pcm "aloop0"; slaves.b.pcm "aloop1"; slaves.c.pcm "aloop2"; slaves.d.pcm "aloop3"; slaves.a.channels 2; slaves.b.channels 2; slaves.c.channels 2; slaves.d.channels 2; bindings.0.slave a; bindings.0.channel 0; bindings.1.slave a; bindings.1.channel 1; bindings.2.slave b; bindings.2.channel 0; bindings.3.slave b; bindings.3.channel 1; bindings.4.slave c; bindings.4.channel 0; bindings.5.slave c; bindings.5.channel 1; bindings.6.slave d; bindings.6.channel 0; bindings.7.slave d; bindings.7.channel 1; } ttable.0.0 1; ttable.1.1 1; ttable.0.2 1; ttable.1.3 1; ttable.0.4 1; ttable.1.5 1; ttable.0.6 1; ttable.1.7 1; } pcm.aloop0 { type dmix ipc_key 1024 slave { pcm "hw:Loopback,0,0" period_time 0 period_size 2048 buffer_size 65536 buffer_time 0 periods 128 rate 48000 channels 2 } bindings { 0 0 1 1 } } pcm.aloop1 { type dmix ipc_key 2048 slave { pcm "hw:Loopback,0,1" period_time 0 period_size 2048 buffer_size 65536 buffer_time 0 periods 128 rate 48000 channels 2 } bindings { 0 0 1 1 } } pcm.aloop2 { type dmix ipc_key 4096 slave { pcm "hw:Loopback,0,2" period_time 0 period_size 2048 buffer_size 65536 buffer_time 0 periods 128 rate 48000 channels 2 } bindings { 0 0 1 1 } } pcm.aloop3 { type dmix ipc_key 8092 slave { pcm "hw:Loopback,0,3" period_time 0 period_size 2048 buffer_size 65536 buffer_time 0 periods 128 rate 48000 channels 2 } bindings { 0 0 1 1 } } # Bluetooth headset pcm.btheadset { type plug slave.pcm { type bluealsa device "20:9B:A5:5B:B7:A9" profile "a2dp" } hint { show on description "VMODA Crossfade Bluetooth Headset" } } ctl.aloopx { type hw card "Loopback" } -------------------- Contents of the bt-pair.sh script that is fired on squeezelite power on/off commands: Code: -------------------- #!/bin/sh uptime=$(cat /proc/uptime | cut -d'.' -f1) if [ ${uptime} -le 60 ] then exit fi lmsip=$(netstat -tn | grep 3483 | tr -s ' ' | cut -d ' ' -f5 | cut -d ':' -f1) iface=$(arp -an | grep ${lmsip} | tr -s ' ' | cut -d' ' -f7) read mac < /sys/class/net/${iface}/address btplayer="bluetooth-player" post=$(cat <<END_HEREDOC POST /jsonrpc.js HTTP/1.1 HOST: ${lmsip}:9000 Content-Type: application/json; charset=utf-8 Content-Length: 97 {"id":1,"method":"slim.request","params":["${mac}",["status","-","1","tags:acgltys"]]} END_HEREDOC ) if ! (echo -e "${post}"; sleep .2) | nc ${lmsip} 9000 | grep "${btplayer}" | grep -q '"power":0' then exit fi i=0 bluetoothctl discoverable on while [ $i -le 30 ] do prepair=$(bluetoothctl paired-devices | cut -d' ' -f2) sleep 2 newpair=$(bluetoothctl paired-devices | cut -d' ' -f2) newdev=$(printf "${prepair}\n${newpair}\n" | sort | uniq -u) if [ "${newdev}" ] then echo "${newdev}" bluetoothctl trust ${newdev} bluetoothctl connect ${newdev} break else i=$(( $i +1 )) fi done bluetoothctl discoverable off -------------------- +-------------------------------------------------------------------+ |Filename: IMG_20200630_163325891-rs.jpg | |Download: http://forums.slimdevices.com/attachment.php?attachmentid=30926| +-------------------------------------------------------------------+ ------------------------------------------------------------------------ sodface's Profile: http://forums.slimdevices.com/member.php?userid=19057 View this thread: http://forums.slimdevices.com/showthread.php?t=112536 _______________________________________________ unix mailing list unix@lists.slimdevices.com http://lists.slimdevices.com/mailman/listinfo/unix