Bluetooth: Difference between revisions

imported>Samueldr
m Adds a troubleshooting section for bad bluetooth usb dongles.
m Enabling A2DP Sink: Added ellipses to match other code blocks
 
(55 intermediate revisions by 34 users not shown)
Line 1: Line 1:
== Enabling ==
==Setup==
To enable support for Bluetooth devices, amend your system configuration as follows and apply changes:
{{file|/etc/nixos/configuration.nix|nix|<nowiki>
hardware.bluetooth.enable = true;
</nowiki>}}
==Usage==
In order to use Bluetooth devices, they must be paired with your NixOS machine. Heavier [[:Category:Desktop_environment|desktop environments]] will usually provide a Bluetooth management GUI which you can use to pair devices.


Enabling bluetooth support is as simple as adding {{nixos:option|hardware.bluetooth.enable}} to configuration.nix
If your desktop environment does not provide such a GUI, you can additionally enable the blueman service, which provides blueman-applet and blueman-manager with the snippet below.
<syntaxhighlight lang="nix">
services.blueman.enable = true;
</syntaxhighlight>Another option for a GUI based Bluetooth management GUI can be [https://search.nixos.org/packages?channel=unstable&show=overskride&from=0&size=50&sort=relevance&type=packages&query=overskride overskirde]
 
Alternatively if you wish to use a TUI<ref>https://en.wikipedia.org/wiki/Text-based_user_interface</ref> then check out [https://github.com/bluetuith-org/bluetuith bluetuith] or [https://github.com/pythops/bluetui bluetui]
 
===Pairing devices from the command line===
Alternatively, Bluetooth devices can be paired from the command line using <tt>bluetoothctl</tt>.
 
<syntaxhighlight lang="console">$ bluetoothctl
[bluetooth] # power on
[bluetooth] # agent on
[bluetooth] # default-agent
[bluetooth] # scan on
...put device in pairing mode and wait [hex-address] to appear here...
[bluetooth] # pair [hex-address]
[bluetooth] # connect [hex-address]</syntaxhighlight>
 
Bluetooth devices automatically connect with <tt>bluetoothctl</tt> as well:
 
<syntaxhighlight lang="console">
$ bluetoothctl
[bluetooth] # trust [hex-address]
</syntaxhighlight>
 
== Tips and tricks ==
 
=== Using Bluetooth headsets with PulseAudio ===
To allow Bluetooth audio devices to be used with [[PulseAudio]], amend <tt>/etc/nixos/configuration.nix</tt> as follows:


<syntaxhighlight lang="nix">{
<syntaxhighlight lang="nix">{
  hardware.pulseaudio.enable = true;
   hardware.bluetooth.enable = true;
   hardware.bluetooth.enable = true;
}</syntaxhighlight>
}</syntaxhighlight>
Line 9: Line 45:
{{evaluate}}
{{evaluate}}


== Pairing ==
You will need to restart PulseAudio; try <tt>systemctl --user daemon-reload; systemctl --user restart pulseaudio</tt>.
 
You can verify that PulseAudio has loaded the Bluetooth module by running <tt>pactl list | grep -i 'Name.*module.*blue'</tt>; Bluetooth modules should be present in the list.
 
=== Using Bluetooth headset buttons to control media player ===
Many bluetooth headsets have buttons for  pause/play or to skip to the next track.
To make these buttons usable with media players supporting the dbus-based [https://specifications.freedesktop.org/mpris-spec/latest/ MPRIS] standard,
one can use <code>mpris-proxy</code> that is part of bluez package.
The following snippet can be used in [[Home Manager]] to start this program as a daemon:
 
<syntaxHighlight lang="nix">
systemd.user.services.mpris-proxy = {
    description = "Mpris proxy";
    after = [ "network.target" "sound.target" ];
    wantedBy = [ "default.target" ];
    serviceConfig.ExecStart = "${pkgs.bluez}/bin/mpris-proxy";
};
</syntaxHighlight>
 
Or, starting with Home Manager 21.05, enable the <code>mpris-proxy</code> service.
 
Some headsets (such as Sony's WH-1000XM series) also support AVRCP directly and as such <code>mpris-proxy</code> is not required for this functionality, as headset button presses will register as media key presses. If you are using a WM or a desktop environment which doesn't support media keys, you will have to set up keybindigs yourself; the keys are typically called <code>XF86AudioPlay</code>, <code>XF86AudioPause</code>, <code>XF86AudioNext</code>, and <code>XF86AudioPrev</code>. However, note that some functionality, such as "take off headphones to pause" on WH-1000XM4/5 requires two-way AVRCP communication to work properly, so `mpris-proxy` is still recommended if you wish to use it. It also may or may not help with Bluetooth multipoint.
 
==== System-Wide PulseAudio ====
{{Expansion|When setting up pulseaudio systemWide extra policies needs to be deployed for pulse to be able to connect to the bluetooth stack. The Info below is not enough.}}
 
When you are running PulseAudio system-wide then you will need to add the following modules to your <code>default.pa</code> configuration:
<syntaxHighlight lang="nix">
hardware.pulseaudio.configFile = pkgs.writeText "default.pa" ''
  load-module module-bluetooth-policy
  load-module module-bluetooth-discover
  ## module fails to load with
  ##  module-bluez5-device.c: Failed to get device path from module arguments
  ##  module.c: Failed to load module "module-bluez5-device" (argument: ""): initialization failed.
  # load-module module-bluez5-device
  # load-module module-bluez5-discover
'';
</syntaxHighlight>
 
==== Enabling extra codecs ====
While pulseaudio itself only has support for the SBC bluetooth codec there is out-of-tree support for AAC, APTX, APTX-HD and LDAC.
 
To enable extra codecs add the following to <tt>/etc/nixos/configuration.nix</tt>:
<syntaxhighlight lang="nix">
{
...
  services.pulseaudio = {
    enable = true;
    package = pkgs.pulseaudioFull;
  };
...
}
</syntaxhighlight>


Bigger desktop environments will usually provide a bluetooth management system.
==== Enabling A2DP Sink ====
Modern headsets will generally try to connect using the A2DP profile. To enable this for your bluetooth connection, add the following to <tt>/etc/nixos/configuration.nix</tt>


{{expansion}}
<syntaxhighlight lang="nix">{
...
  hardware.bluetooth.settings = {
    General = {
      Enable = "Source,Sink,Media,Socket";
    };
  };
...
}</syntaxhighlight>
This configuration may be unnecessary and does not work with bluez5 (<tt>Unknown key Enable for group General</tt> ).


Alternatively, using <code>pkgs.blueman</code>, it is possible to get a tray icon <code>blueman-applet</code> or use the manager directly using <code>blueman-manager</code>.
==== Managing audio devices ====
<tt>pavucontrol</tt> can be used to reconfigure the device:
* To enable A2DP, change the profile to &#8220;High Fidelity Playback (A2DP Sink)&#8221; on the &#8220;Configuration&#8221; tab.
* To set the device as the default audio output, select &#8220;set as fallback&#8221; on the &#8220;Output Devices&#8221; tab.


=== Pairing without GUI tools ===
Alternatively, the device can be configured via the command line:


When not using a desktop-manager, configuring the device from the command line can be done following the [https://wiki.archlinux.org/index.php/Bluetooth#Configuration_via_the_CLI ArchWiki instructions], as follows.
* To enable A2DP, run: <syntaxhighlight lang="console">$ pacmd set-card-profile "$(pactl list cards short | egrep -o bluez_card[[:alnum:]._]+)" a2dp_sink</syntaxhighlight>
* To set the device as the default audio output, run: <syntaxhighlight lang="console">$ pacmd set-default-sink "$(pactl list sinks short | egrep -o bluez_sink[[:alnum:]._]+)"</syntaxhighlight>


<syntaxhighlight lang="console">$ bluetoothctl
You can also set pulseaudio to automatically switch audio to the connected bluetooth device when it connects, in order to do this add the following entry into the pulseaudio config
[bluetooth] # power on
[bluetooth] # agent on
[bluetooth] # default-agent
[bluetooth] # scan on
...put device in pairing mode and wait [hex-address] to appear here...
[bluetooth] # pair [hex-address]
[bluetooth] # connect [hex-address]</syntaxhighlight>


== Bluetooth headsets with PulseAudio ==
<syntaxhighlight lang="nix">{
...
hardware.pulseaudio.extraConfig = "
  load-module module-switch-on-connect
";
...
}</syntaxhighlight>


The package used for PulseAudio has to be <code>pkgs.pulseaudioFull</code>, which includes bluetooth support.
Note that you may need to clear the pulseaudio config located at ~/.config/pulse to get this to work. Also you may have to unset and then set the default audio device to the bluetooth device, see https://github.com/NixOS/nixpkgs/issues/86441 for more info


=== Showing battery charge of bluetooth devices ===
If you want to see what charge your bluetooth devices have you have to enable experimental features, which might lead to bugs (according to [https://wiki.archlinux.org/title/Bluetooth_headset#Battery_level_reporting Arch Wiki]). You can add the following to your config to enable experimental feature for bluetooth:
<syntaxhighlight lang="nix">{
<syntaxhighlight lang="nix">{
   hardware.pulseaudio = {
...
hardware.bluetooth.settings = {
General = {
Experimental = true;
};
};
...
}</syntaxhighlight>
Afterwards rebuild your system and then restart your bluetooth service by executing  <syntaxhighlight lang="console">$ systemctl restart bluetooth</syntaxhighlight>
 
=== Pairing hearing aids using the ASHA protocol ===
The upstream bluez project [https://github.com/thewierdnut/asha_pipewire_sink#alternatives-are-coming has not yet implemented audio support for the ASHA protocol]. As an alternative it is possible to enable audio streaming using the [https://github.com/thewierdnut/asha_pipewire_sink asha-pipewire-sink] project.
 
Add following to your system config and apply it:
 
<syntaxhighlight lang="nix">
boot.extraModprobeConfig = ''
   options bluetooth enable_ecred=1
'';
 
hardware = {
  bluetooth = {
     enable = true;
     enable = true;
     package = pkgs.pulseaudioFull;
     settings = {
      LE = {
        MinConnectionInterval = 16;
        MaxConnectionInterval = 16;
        ConnectionLatency = 10;
        ConnectionSupervisionTimeout = 100;
      };
    };
   };
   };
  hardware.bluetooth.enable = true;
};
 
environment.systemPackages = [ pkgs.asha-pipewire-sink ];
</syntaxhighlight>Ensure that profiles <code>LE2MTX LE2MRX</code> are part of <code>Selected phys</code> when running <code>sudo btmgmt phy</code>, otherwise follow the instruction [https://github.com/thewierdnut/asha_pipewire_sink#enable-2m-phy-optional here].
 
Pair and connect to both of your hearing aids.
 
Run the command <code>asha_pipewire_sink</code> and choose your hearing aids as audio sink in your sound mixer application, for example <code>pavucontrol</code>.
 
=== File Transfer from/to Mobile Device ===
 
Use Case: When you're not using a desktop/window manager who supports accepting files the GUI (e.g. sway, etc)
 
<code>systemctl --user edit obex</code>
 
<syntaxhighlight lang="ini">{
### Editing /home/<youruser>/.config/systemd/user/obex.service.d/override.conf
### Anything between here and the comment below will become the contents of the drop-in file
 
[Service]
ExecStart=
ExecStart=/nix/store/...-bluez-5.78/libexec/bluetooth/obexd --root=./Downloads --auto-accept
 
### Edits below this comment will be discarded
 
...
}</syntaxhighlight>
}</syntaxhighlight>


{{evaluate}}
With this config, after pairing (and - I suspect - trusting) your mobile device, you should be able to receive files from your phone.
 
Caveat: When sending files to the phone, take into account that not all file extensions are accepted. Renaming the file before transfer did the trick.


Either restart the system for PulseAudio to load the bluetooth module, or restart your local instance of PulseAudio by running <code>pkill ^pulseaudio$</code>.
<code>sudo journalctl -f -t obexd</code> be your friend.


Ensure PulseAudio has loaded bluetooth modules by using <code>pactl list | grep -i Name.*module.*blue</code>. Bluetooth modules should be present in the list.
==Troubleshooting==
===USB device needs to be unplugged/re-plugged after suspend===
Some USB device/host combinations don't play well with the suspend/resume cycle, and need to be unplugged and then re-plugged to work again.


=== Managing the audio interface ===
It is possible to simulate a unplug/re-plug cycle using the <tt>/sys</tt> filesystem.


Using <code>pavucontrol</code>, the headset profile can be changed to ''"High Fidelity Playback (A2DP Sink)"'' in the ''Configuration'' tab.
[https://gist.github.com/samueldr/356e65374d452e4fd45314f818ae3545 This gist] provides a script and instructions to set-up a workaround for these devices.


The default sink can be changed in the ''Output Devices'' tab. clicking on the right most button, which it title ''Set as fallback''.
===When connecting to an audio device: Failed to connect: org.bluez.Error.Failed===


==== Managing the audio interface using <code>pacmd</code> ====
You need to use pulseaudioFull, see [[#Using Bluetooth headsets with PulseAudio]].


Setting the card to A2DP
===Bluetooth fails to power on with Failed to set power on: org.bluez.Error.Blocked===
 
If <tt>journalctl -eu bluetooth</tt> shows <tt>Failed to set mode: Blocked through rfkill (0x12)</tt>, rfkill might be blocking it:


<syntaxhighlight lang="console">
<syntaxhighlight lang="console">
$ pacmd set-card-profile "$(pactl list cards short | egrep -o bluez_card[[:alnum:]._]+)" a2dp_sink
$ rfkill
ID TYPE      DEVICE      SOFT      HARD
1 wlan      phy0  unblocked unblocked
37 bluetooth hci0  blocked unblocked
</syntaxhighlight>
</syntaxhighlight>


Setting the bluetooth sink as default
Unblock it first:


<syntaxhighlight lang="console">
<syntaxhighlight lang="console">
$ pacmd set-default-sink "$(pactl list sinks short | egrep -o bluez_sink[[:alnum:]._]+)"
$ sudo rfkill unblock bluetooth
</syntaxhighlight>
</syntaxhighlight>


== Troubleshooting ==
=== Cannot use bluetooth while it previously worked ===
 
Symptoms:
 
* When using <code>bluetoothctl</code>, getting "No agent is registered".
* When using <code>blueman</code> or anything using dbus to talk to bluez, getting <code>dbus.exceptions.DBusException: org.freedesktop.DBus.Error.AccessDenied: Rejected send message"</code>
 
This possibly can be fixed by restarting the display-manager session. The session management may have had an issue with registering your current session and doesn't allow you to control bluetooth.
 
<syntaxhighlight lang="console">
$ sudo systemctl restart display-manager.service
</syntaxhighlight>


=== USB device needs to be unplugged/re-plugged after suspend ===
=== No audio when using headset in HSP/HFP mode ===


Some USB devices/hosts combinations don't play well with the suspend/resume cycle, and needs to be unplugged and then re-plugged to work again.
If the output of <code>dmesg | grep Bluetooth</code> shows a line similar to <code>Bluetooth: hci0: BCM: Patch brcm/BCM-0a5c-6410.hcd not found</code> then your machine uses a Broadcom chipset without the required firmware installed.


It is possible to simulate a unplug/re-plug cycle using the <code>/sys/</code> filesystem.
To fix this, add <code>hardware.enableAllFirmware = true;</code> to your <tt>/etc/nixos/configuration.nix</tt> then reboot.


[https://gist.github.com/samueldr/356e65374d452e4fd45314f818ae3545 This gist] provides a script and instructions to set-up a workaround for these devices.


== External resources ==
==See also==
* [https://web.archive.org/web/20170609072208/http://anderspapitto.com/posts/2016-11-07-scripting_pulseaudio_bluetooth_jack.html Scripting PulseAudio, Bluetooth, JACK]
* [https://wiki.gentoo.org/wiki/Bluetooth Bluetooth (Gentoo Wiki)]
* [https://wiki.archlinux.org/index.php/Bluetooth Bluetooth (Arch Linux Wiki)]


* [http://anderspapitto.com/posts/2016-11-07-scripting_pulseaudio_bluetooth_jack.html Scripting pulseaudio, bluetooth, jack]
[[Category:Audio]][[Category:Configuration]][[Category:Hardware]]