webcodr

Fixing no A2DP with Bluetooth headsets on Linux

Please beware that the following instructions are suitable for media consumption only! After this changes your headset can’t make any calls without a dedicated microphone until you undo them.

Having trouble with the audio quality of your Bluetooth headset on Linux? It sounds awful if you’re listing to music and videos? Well, congratulations, I had the same problem and found a solution. At least if you’re only into listening and won’t make any calls. This works on Ubuntu or Ubuntu-based like Pop_OS! or any other distribution that relies on Blue Z and Pipewire/WirePlumber for Bluetooth audio.

What’s wrong?

Bluetooth has different profiles for different things. If you want to make a call, your headset will switch to the Hands-free Profile (HFP). The available bandwidth will be shared for audio input and output and different audio codecs will be used. It’s good for calls, but really shitty if you want to listen to music. The headset needs to switch to A2DP (Advanced Audio Distribution Profile) for good sound quality. This should happen automatically and HFP should only be active, if you’re making a call. I had never trouble on macOS or Windows with this, but I’m trying Pop_OS! now. It worked for a few days, but today the headset would only connect with the HFP and streaming music or watchig videos was a pleasant as dental treatment with a power drill.

Many searches later, I found out that WirePlumper (the session manager for the Pipewire multimedia framework) has some bugs that will trigger HFP on BT headsets even if there’s no call. That’s pretty annying but at least somewhat easy to solve. There’s a solution in the Arch Linux Wiki, but it needs some modifications for Ubuntu-based distributions.

The solution

First you need to create a directory path in your home directory:

mkdir -p ~/.config/wireplumber/bluetooth.lua.d/

This will create an directory that allows you to override the default WirePlumper Bluetooth config without overwriting the original file.

Now copy the original config to the overwrite directory:

cp /usr/share/wireplumber/bluetooth.lua.d/50-bluez-config.lua ~/.config/wireplumber/bluetooth.lua.d/

You can now edit the file in the override directory.

Beware that the original instructions from the Arch Linux Wiki contain a conf file, but at least with Ubuntu (and Pop_OS!) the config file is written in lua, so it’s a completely different syntax.

Look for bluez5.roles – it should be commented out. I would recommend not replace the comment and just put the following line below. It’s easier to undo if something goes wrong or you need to enable HFS.

["bluez5.roles"] = "[ a2dp_sink a2dp_source ]"

Save the file and restart the Bluetooth service:

sudo systemctl restart bluetooth

Now reconnect your device and A2DP should be working fine.

Awsome CLI Tools

There are some incredibly useful CLI tools out there. Here’s a list with some awesome tools I’m using for my daily work.

atuin

Atuin is a history replacement with a fuzzy finding search and sync/backup options (self-hosted if you need). It’s written in Rust (blazingly fast!) and stores the history entries in a SQLite db. You can even import your current history from your shell. Atuin supports bash, zsh, fish and NuShell.

bat

Need cat a lot? Bat is a cat clone on steroids with syntax highlighting, themes, git integration and much more.

eza

Everyone needs ls ? Nope, eza is much better. Colored output, icons via nerd fonts, git status tracking per file, tons of display options …

tldr

Reading an man page can be frustrating, why can’t I just have the TL;DR version? Well, tldr does exactly that. Just use it like man and enjoy the TL;DR version of a man page.

zoxide

As his siblings cd is a little dated and clunky. With zoxide you can easily jump to directories without typing the full path. It stores a history of your visited paths and you can jump via keywords to your directories.

chezmoi

You’re using multiple computers or just want a simple and reliable way to store your dot files? Chezmoi is your friend and stores your dot files in a git repo with syncing capabilities to other devices. It’s even possible to encrypt your files. If you have secrets in your dot files, chezmoi comes with integrations for many password managers to safely store your passwords, tokens etc.

starship

Your shell looks boring? Just theme it with starship! It’s pretty easy to build your own and if you don’t want to, there many themes available. Starship also has integrations for many dev tools to show the current git status or currently active versions of your runtime environments like NodeJS, Rust, Go, Java etc.

fzf

Finding files with the usual suspects works fine, but fzf can do this faster and much more intuitive. It’s a fuzzy finding search within your current directory, processes, git commits, history (if you don’t like Atuin) and much more.

ripgrep

Ripgrep is a really fast regex-based search tool and can do much more than grep alone.

btop

Another top variant? Yup, but btop is way more like it’s modern GUI-based colleagues on macOS or Windows with CPU and GPU usage, process trees, I/O and disk activities, battery status …

Micro DSLs for builders with Kotlin

The builder pattern is a great tool and it’s heavily used in many Java projects and dependencies. But in a Kotlin code base it’s looks a little odd and out-of-date. In this short post I will show you how to write a micro DSL on top of builder with just a few lines of code.

I’m using Spring’s ResponseCookie class as base for the DSL as it has a builder already on-board.

A little example:

val cookie = ResponseCookie
    .from("cookie name", "cookie value")
    .httpOnly(true)
    .path("/")
    .build()

How would this look like with a micro DSL?

val cookie = createCookie("cookie name", "cookie value") {
    httpOnly(true)
    path("/")
}

Instead of calling the static method ResponseCookie.from() which returns a ResponseCookieBuilder object, you just give the function three parameters: two strings for name and value, and trailing lambda with the builder context. There is also no need to call ResponseCookieBuilder.build() anymore. It’s shorter and better to read. Since this is only a small example the advantages are not that big. Micro DSLs really shine with large and often used builders. They can also help to automate things, see below.

How?

fun createCookie(
    name: String, 
    value: String, 
    lambda: ResponseCookieBuilder.() -> Unit
) = ResponseCookie.from(name, value).apply(lambda).build()

Et voila, a new micro DSL is born. Deriving the trailing lambda function from ResponseCookieBuilder does the trick. The lambda function takes an instance of ResponseCookieBuilder as context of this, so it’s possible to access the methods of the given ResponseCookieBuilder inside the lambda function. All we have to do is to create an instance of ResponseCookieBuilder with ResponseCookie.from() and call Kotlin’s apply method on the builder object with the lambda function. It will automatically inject the current instance of ResponseCookieBuilder into the lambda function and apply the instructions inside the lambda function on the instance. To create a ResponseCookie object from the builder, just call the build method and return the result.

You can use this little trick with all builders. Need more automation? No problem! In my current project we’re using such micro DSLs to create product configurations. The factory method contains sanity checks after the lambda function was applied to the builder object. It will also fetch a YAML file via the product ID given to the builder. This data is parsed into an object and will be put into a property of the builder object. After the configuration object is created, the factory method will add to a map and return the instance to store in a variable. It’s now possible to directly access the configuration via its variable name or to fetch it from the map. The variable is very useful for tests, but if we have to fetch the configuration dynamically by ID from a string, the map is the way to go.

Of course there are other ways of achieving such automation, but the micro DSL approach is simple, improves readability and can also reduce redundant code. You can even easily nest builders to create a more powerful DSL. Spring’s Kotlin extensions also rely on micro DSLs and extension functions. Take Spring Security for example. Their fluent interface for the security configuration is awful to read and difficult to understand, but Spring also provides a Kotlin extension with a micro DSL for that. So much more intuitive and better to read. There are many more extensions like for bean creation, the MVC mock in tests etc.

US International Keyboard Layout Without Dead Keys

Depending on your country’s keyboard layout writing code can be quite annoying. The German ISO layout is an exceptional pain in the ass, as almost all relevant symbols require a modifier key, sometimes even two (I’m looking at you, Apple). German has some special characters (ä. ö, ü, ß) and it makes sense to have them readily available without modifier keys, but it just sucks for programming.

I decided to switch to the US ANSI layout and bought two new keyboards: a Keychron K3 Pro for my MacBook Pro (light and portable, perfect if I have to go to my company’s office) and Keychron Q1 version 2 for my Windows PC. By the way, the Q1 is heavily modded and will be tweaked further in the coming weeks. I will write an article about the mods after the keyboard is finished.

Both keyboards work great, but to type German special characters I have to use the US international layout on Windows and there’s a catch. Who would have thought, if Microsoft is involved? Certain keys like single quote/double quote or accents/tilde are so called dead keys.

If you press them, nothing will happen at first. Only after pressing the next key, the symbol will appear. So, if you want to type a text wrapped in double quotes, you press the the key and the double quote will appear, as soon as you type the first character of the actual text. It’s annoying as fuck and drives me crazy.

Solution

Unfortunately Microsoft does not ship an US international layout without dead keys for Windows. Most Linux distributions do exactly that, but I guess that’s to easy for a big international corporation like Microsoft.

What to do? After a little bit of googling, I found a neat little tool, the Microsoft Keyboard Layout Creator. I’ve never heard of this program before but it’s legit and works fine.

If you’re having trouble with the dead keys like me, I recommend the following steps:

  1. Download the Microsoft Keyboard Layout Creator from Microsoft’s website
  2. Open it and load the US international layout via File -> Load Existing Keyboard...
  3. All dead keys are shown with a light grey background. You can remove their dead key status via the context menu
  4. Don’t forget to activate the shift layer via the checkboxes left of the keyboard layout and disable the dead keys as well
  5. Save your config
  6. Build the layout via Project -> Build DLL and Setup Package
  7. After the build finished, a dialog will ask you to open the build directory. Open it and run setup.exe to install the new layout
  8. Restart Windows. This should not be necessary, but unfortunately Windows is Windows …
  9. Go to Settings -> Time and Language -> Language and Region
  10. Select your preferred language and click the three dots and choose Language options
  11. Use Add a keyboard and select United States International - No Dead Keys
  12. I recommend to remove all other keyboard layouts, so they can’t interfere

Now you should have a working US international layout without those annoying dead keys. Happy typing!

Introducing Server Runner

In my recent adventures with Rust, I planned to write a REST API with the help of the excellent book “Zero To Production In Rest” from Luca Palmieri. That’s still happing, but as small side project, I wanted to write some kind of CLI tool.

A few weeks ago I had wrote a bash script to run some web servers and check their status until they’re up and running. When all servers are ready, a command would be executed and all servers would be closed after this command is finished. Since I hate bash with passion, I asked an friend to help me: ChatGPT.

I would never trust an AI in this day and age to write a code base for me, but for small scripts? Why not. As long as the scope is small and I can understand the code, ChatGPT is a really good tool. That script does exactly what I want and it’s easy enough to understand, even for me as a bash hater.

But I wanted to this properly and so I decided to rewrite this script as a small CLI tool program in Rust: Server Runner. Well, not very creative name, but it does what is says.

Configuration

Server Runner is quite simple and just needs a small YAML file as configuration. Here’s a small example.

servers:
  - name: "Hello World"
    url: "http://localhost:3000"
    command: "node index.js"
command: "node sleep.js"

To start server runner, just run:

server-runner -c servers.yaml

Server Runner will execute all server commands defined in the config section servers and waits until the URLs return HTTP 200. When all servers are up and running, the primary command will be started. After the command finished, all server processes will be killed off.

How do I get it?

Server Runner is available as a Cargo Crate and will be published soon on NPM with executables for macOS (aarch64, x86_64), Linux (aarch64, x86_86) and Windows (x86_64).

Installation via Cargo

cargo add server-runner

The source code is available on GitHub.