KEF LS60: Difference between revisions

Created page with "I acquired a pair of [https://us.kef.com/products/ls60-wireless 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..."
 
No edit summary
 
(8 intermediate revisions by the same user not shown)
Line 6: Line 6:
* Pulseaudio 16.1
* Pulseaudio 16.1
* KEF firmware 2.0
* KEF firmware 2.0
As a first observation, setting up an EQ profile for my small office seemed to <i>substantially</i> improve listening experience. I used Normal Mode (as opposed to expert).


==Requirements==
==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 <i>did not</i> 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 was using [[Mpd|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 <i>did not</i> 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.
I might end up using the HDMI if I can't eliminate the latency of my wireless solution.
Line 17: Line 19:
* DAC at speakers
* DAC at speakers
* minimal latency
* minimal latency
* output automatically waking the speakers from standby mode


==Wireless==
==Wireless==
Using the app, set the input to "Wi-Fi".
The specs list the following "wireless streaming features":
The specs list the following "wireless streaming features":
* AirPlay 2
* AirPlay 2
Line 25: Line 29:
* UPnP Compatible
* UPnP Compatible
* Bluetooth 4.2
* Bluetooth 4.2
As far as I'm aware, [[Bluetooth]] audio is always going to involve a lossy compression.
As far as I'm aware, [[Bluetooth]] audio is always going to involve a lossy compression, so I won't be using it. I did set up Bluetooth just to see that it worked, which it did. You'll have to pair the devices, and connect them.
 
Running <tt>avahi-browse -a -t</tt> 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 <tt>-r</tt> for resolution generated more details:
<pre>
=  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 = []
</pre>
 
I first tried pipewire+AirPlay using the [https://docs.pipewire.org/page_module_raop_discover.html raop-discover] module. This was able to find the speakers, and created a device visible in <tt>pavucontrol</tt>, but I was unable to produce any audible output using it. The monitor showed signal going to the sink, but I heard nothing.
 
I disabled pipewire and pipewire-pulse, and brought up true pulseaudio. Using <tt>pulseaudio-dlna</tt>, I got a working sink that generated sound:
 
<pre>
Sink #2
State: RUNNING
Name: lilypadspeaker_dlna
Description: lilypad speaker (DLNA)
Driver: module-null-sink.c
Sample Specification: s16le 2ch 44100Hz
Channel Map: front-left,front-right
Owner Module: 25
Mute: no
Volume: front-left: 65536 / 100% / 0.00 dB,  front-right: 65536 / 100% / 0.00 dB
      balance 0.00
Base Volume: 65536 / 100% / 0.00 dB
Monitor Source: lilypadspeaker_dlna.monitor
Latency: 26367 usec, configured 40000 usec
Flags: DECIBEL_VOLUME LATENCY SET_FORMATS
Properties:
device.description = "lilypad speaker (DLNA)"
device.class = "abstract"
device.icon_name = "audio-card"
Formats:
pcm
</pre>
 
The first number reported for <b>Latency:</b> changed with each run.