lunes, marzo 22, 2021

Support for HSP/HFP headset profiles on Ubuntu and Debian

A few months ago I was given a "remote work toolset" that includes a bluetooth headset simply referred as "EC717". To be honest, they come in handy for me, because I was using the hands-free kit of my phone, and it is not the same in quality or comfort.

However, I found it impossible to get them to work on Ubuntu 20.04 and Debian 10, two of the platforms that I regularly use. They do work for listening to music, as A2DP profile, but they don't work as a microphone for video calls, thus losing their main function. When trying to set the profile from a2dp_sink to headset_head_unit, I get this error:

W: [pulseaudio] module-bluez5-device.c: Refused to switch profile to headset_head_unit: Not connected

This issue is extensively documented in lots of bugs and pulseaudio tickets at bugs.freedesktop.org (93898, 9731673325) and in the new gitlab.freedesktop.org (84, 122, 742, 776, 960).

In short, there's no complete support for the variety of HandSet Profile / Hands Free Profile / HSP&HFP profiles by which the audio and control channels are coordinated in Bluetooth. Actually there was support, but changes to the architecture of Bluez and PulseAudio made it disappear. And this affects some headsets that implement only one of these profiles.

Around 2017, James Bottomley coded support for those profiles in pulseaudio 11, 12 and 13, but unfortunately those patches were not incorporated into the stable branch of the pulseaudio library when he published them, and they were only added a few days ago, thus they are not available in current releases of modern distributions.

Fortunately, he segmented two branches of work in which he neatly documents the code changes in order to make this type of headsets work with pulseaudio 12 and pulseaudio 13, and from them I was able to modify and compile two versions of the pulseaudio-module-bluetooth package with HSP/HFP support for both Debian and Ubuntu:

By the way, and before you complain, according to the Bluetooth specification the HSP/HFP profile is single channel (mono) and in 8 khz (Volume 2, Section 6.12, of the Bluetooth Core 2.0 specification), so the audio quality is similar to that of a landline phone (well, that's the spirit of HSP). In short, it sounds awful just like an analog phone. If you want to listen to music, use the A2DP profile, but with this profile it is not possible to use the headset as a microphone. Newer versions of the patch bring support for multiple codecs that improve audio quality, but of course these improvements are only available on newer, higher-quality hardware.

As for me, I also opted to make a passthru module using python3-bluez and pulseaudio virtual sources/sinks, in a script of about 600 lines, so as to communicate directly with the headset and pass the audio as new inputs and outputs on the pulseaudio stack, but the latency it added to the spoken voice made it unusable. Bottomley patches, on the other hand, worked great.

Finally, regarding code quality, if you've worked on SCSI, Secure Boot, TPMs and UEFI, then there is a very high probability that you've come across James code. So, James, cheers to you!

Soporte para headsets HSP/HFP en Ubuntu y Debian

Hace unos meses me obsequiaron un set de trabajo remoto que incluye unos auriculares bluetooth denominados simplemente "EC717". La verdad que me vienen muy bien, pues estaba utilizando el manos libres del celular, y no es lo mismo en calidad ni comodidad.

Sin embargo, encontré imposible hacerlos funcionar en Ubuntu 20.04 y en Debian 10, dos de las plataformas que utilizo habitualmente. En realidad sí funcionan para escuchar música, con el perfil A2DP, pero no funcionan como micrófono para videollamadas, con lo cual pierde bastante el sentido de ser un "set de trabajo remoto". Al intentar establecer el perfil de a2dp_sink a headset_head_unit, obtengo este error:

W: [pulseaudio] module-bluez5-device.c: Refused to switch profile to headset_head_unit: Not connected

Este problema está documentado ampliamente en un montón de bugs y tickets de pulseaudio en bugs.freedesktop.org (93898, 9731673325) y en el nuevo gitlab.freedesktop.org (84, 122, 742, 776, 960

Básicamente, no hay soporte completo para la variedad de HandSet Profile / Hands Free Profile / HSP&HFP profiles mediante los cuales se coordinan los canales de audio y control en Bluetooth. En realidad lo había, pero cambios en la arquitectura de Bluez y PulseAudio hicieron que desaparezcan. Y esto afecta de forma variada a algunos headset que implementan uno solo de dichos perfiles.

James Bottomley estuvo trabajando en 2017 en la incorporación de soporte para las versiones de pulseaudio 11, 12 y 13, pero lamentablemente esos parches no llegaron a incorporarse a la rama estable de la biblioteca pulseaudio cuando los publicó, y recién fueron incorporados hace pocos días, con lo cual no figuran ni de casualidad en las releases actuales de las distribuciones modernas.

Afortunadamente, él ha segmentado dos ramas de trabajo en las cuales marca prolijamente cuales son los cambios a incorporar para poder hacer andar este tipo de headsets con pulseaudio 12 y pulseaudio 13 , y a partir de ellos pude modificar y compilar dos versiones del paquete pulseaudio-module-bluetooth con soporte para HSP/HFP tanto en Debian como en Ubuntu:

Por cierto, y antes de que se quejen, el perfil HSP/HFP según la especificación Bluetooth es monocanal y en 8 khz (Volume 2, Section 6.12, de la especificación Bluetooth Core 2.0), por lo cual la calidad de audio es similar a la de un teléfono de línea (bueno, que en espíritu eso es HSP). En resumen, se escucha feo como en un teléfono analógico. Si quieren escuchar música, establezcan perfil A2DP, pero con ese perfil no es posible utilizar el headset como micrófono. Las versiones más nuevas del parche incorporan soporte para múltiples codecs que mejoran la calidad de audio, pero desde luego estas mejoras sólo están disponibles en hardware más moderno y de mejor calidad.

Por mi parte, también opté por hacer un passthru mediante python3-bluez y sources/sinks virtuales de pulseaudio, un script de unas 600 líneas, de forma tal de dialogar directamente con el headset y pasar el audio como entradas y salidas nuevas en el stack de la biblioteca de sonido, pero la latencia que incorporaba al sonido lo hacía inusable. Los parches de Bottomley, en cambio, funcionan perfecto.

Finalmente, respecto a la calidad del código, si estuvieron trabajando en cuestiones de SCSI, Secure Boot, TPMs y UEFI, hay una muy alta probabilidad de que estén utilizando y se hayan cruzado con código de James. Va mi agradecimiento por todos sus aportes.