Check out my first novel, midnight's simulacra!

KEF LS60

From dankwiki
Revision as of 04:59, 19 January 2024 by Dank (talk | contribs) (→‎Wireless)

I acquired a pair of KEF LS60 active wireless speakers in January 2024. The speakers are awesome, but getting them working well with Linux was not completely trivial, and is not quite complete.

At the time, I had the following versions of crap:

  • Linux 6.7
  • Pipewire 1.0.1
  • Pulseaudio 16.1
  • KEF firmware 2.0

Requirements

I was using MPD 0.23.14 for my music, but I needed a solution at the audio device level, so that video, system sounds, and everything else would use the speakers. So I was looking at pulseaudio or pipewire. I wanted to create a virtual device into which I could dump digital data (probably PWM). The speakers have a line in, but I did not want to do the digital-to-analog conversion on my machine, but rather to use the DAC of the $7,000 speakers. They also have an HDMI input, which could happily accept stereo PCM at up to 24 bits at 192 kHz, but I wanted wireless.

I might end up using the HDMI if I can't eliminate the latency of my wireless solution.

An ideal solution would involve:

  • no cables between computer and speakers
  • lossless transfer to speakers (either as unpacked PCM or packed FLAC/AAC/etc.)
  • DAC at speakers
  • minimal latency

Wireless

The specs list the following "wireless streaming features":

  • AirPlay 2
  • Google Chromecast
  • Roon Ready
  • UPnP Compatible
  • Bluetooth 4.2

As far as I'm aware, Bluetooth audio is always going to involve a lossy compression.

Running avahi-browse -a -t showed numerous zeroconf services:

  • ax200 IPv6 ls60w-eb17fe57-5688-4f03-b2a9-4ef78be95abf _spotify-connect._tcp local
  • ax200 IPv6 8417151A1273@lilypad speaker AirTunes Remote Audio local
  • ax200 IPv6 lilypad speaker AirPlay Remote Video local
  • ax200 IPv6 ls60w-eb17fe57-5688-4f03-b2a9-4ef78be95abf _suegrouping._tcp local
  • ax200 IPv6 LS60 Wireless-490b3a50ff76a5f16a56b25fa9ca18fe _tidalconnect._tcp local
  • ax200 IPv6 8417151A1273@LS60W _kef-info._tcp local
  • ax200 IPv6 ls60w-eb17fe57-5688-4f03-b2a9-4ef78be95abf _sues800device._tcp local
  • ax200 IPv6 lilypad speaker Web Site local

adding -r for resolution generated more details:

=  ax200 IPv6 ls60w-xxx    _spotify-connect._tcp local
   hostname = [ls60w-xxx.local]
   address = [192.168.88.77]
   port = [80]
   txt = ["VERSION=2.9.0" "CPath=/api/stream/spotify:zeroconf"]
=  ax200 IPv6 8417151A1273@lilypad speaker                  AirTunes Remote Audio local
   hostname = [ls60w-xxxx.local]
   address = [192.168.88.77]
   port = [7000]
   txt = ["pk=xxx" "vs=366.0" "vn=65537" "tp=UDP" "sf=0x4" "am=LS60 Wireless" "md=0,1,2" "fv=p20.2.0.66.0x187653b" "ft=0x445F8A00,0x1C340" "et=0,4" "da=true" "cn=0,1"]
=  ax200 IPv6 lilypad speaker                               AirPlay Remote Video local
   hostname = [ls60w-xxx.local]
   address = [192.168.88.77]
   port = [7000]
   txt = ["pk=xxx" "gcgl=0" "gid=xxx" "pi=xxx" "srcvers=366.0" "protovers=1.1" "serialNumber=xxx" "manufacturer=KEF" "model=LS60 Wireless" "flags=0x4" "fv=p20.2.0.66.0x187653b" "rsf=0x0" "features=0x445F8A00,0x1C340" "deviceid=xxx" "acl=0"]
=  ax200 IPv6 ls60w-xxx    _suegrouping._tcp    local
   hostname = [ls60w-xxx.local]
   address = [192.168.88.77]
   port = [80]
   txt = ["ip=192.168.88.77" "groupTimestamp=0" "groupName=" "groupMembers=0" "spotify=true" "transcoder=true" "manufacturer=KEF" "uuid=ls60w-xxx" "name=lilypad speaker"]
=  ax200 IPv6 LS60 Wireless-xxx _tidalconnect._tcp   local
   hostname = [ls60w-xxx.local]
   address = [192.168.88.77]
   port = [2019]
   txt = ["fn=lilypad speaker" "ve=1" "id=xxx" "ca=2" "mn=LS60 Wireless"]
=  ax200 IPv6 xxx@LS60W                            _kef-info._tcp       local
   hostname = [ls60w-xxx.local]
   address = [192.168.88.77]
   port = [80]
   txt = ["groupRole=N/A" "groupName=N/A" "groupId=N/A" "kefId=xxx" "version=2.0.66.0x187653b" "serialNumberSlave=" "serialNumber=xxx" "manufacturer=KEF" "modelName=LS60 Wireless" "model=SP4017" "mac=xxx" "name=lilypad speaker"]
=  ax200 IPv6 ls60w-xxx    _sues800device._tcp  local
   hostname = [ls60w-xxx.local]
   address = [192.168.88.77]
   port = [80]
   txt = ["ip=192.168.88.77" "manufacturer=KEF" "uuid=ls60w-xxx" "serial=xxx" "name=lilypad speaker"]
=  ax200 IPv6 lilypad speaker                               Web Site             local
   hostname = [ls60w-xxx.local]
   address = [192.168.88.77]
   port = [80]
   txt = []
=  ax200 IPv6 Music Player @ schwarzgerat[1574275]          Music Player Daemon  local
   hostname = [schwarzgerat.local]
   address = [fe80::3e9c:fff:fe4f:34e5]
   port = [6600]
   txt = []
=  ax200 IPv4 Music Player @ schwarzgerat[1574275]          Music Player Daemon  local
   hostname = [schwarzgerat.local]
   address = [192.168.88.100]
   port = [6600]
   txt = []

I first tried pipewire+AirPlay using the raop-discover module. This was able to find the speakers, and created a device visible in pavucontrol, but I was unable to produce any audible output using it. The monitor showed signal going to the sink, but I heard nothing.