CLI tool
Oppzippy/OpenSCQ30 avatar
Oppzippy/OpenSCQ30

OpenSCQ30: a Rust CLI and GUI for Soundcore headphones and earbuds

Cross platform application for controlling settings of Soundcore headphones, earbuds, and speakers. Supports desktop (CLI and GUI) and Android.

527 stars68 forksRustGPL-3.0

At a glance

What is it?
OpenSCQ30 controls settings on Soundcore headphones, earbuds and speakers over Bluetooth, with a Rust core shared by a CLI, a libcosmic desktop GUI and an Android app built on Kotlin. The device list covers close to forty models, and the project ships signed releases, a Flathub package and an IzzyOnDroid build.
Who is it for?
OpenSCQ30 fits a user of a listed Soundcore model on Linux or Android who wants the desktop application installed from Flathub or an F-Droid style store, or who wants to script the settings through the CLI. It is the wrong choice if your exact model is not in the supported device table, and the wrong choice if you need every firmware option, since the vendor application is the more complete and the more durable answer.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Named after the first device it controlled

OpenSCQ30 is free software for controlling settings for Soundcore headphones and earbuds. The README is upfront about the origin: it was originally intended for the Soundcore Life Q30, after which the project was named, but a range of devices are now supported. That naming detail is worth knowing because it explains both the strength and the limit of the project. The Q30 protocol became the reference implementation, and everything since has been an accumulation of device-specific quirks on top of that base. The repository description calls it a cross platform application for controlling settings of Soundcore headphones, earbuds and speakers, supporting desktop with both a CLI and a GUI, plus Android. The primary language is Rust, the licence is GPL-3.0, and the last push was on 2026-10-19 with v2.13.0 tagged on 2026-10-17, so this is a project with a steady release rhythm.

Three platforms, and a note about what Ready means

The supported platforms section is a three-line checklist. Windows is marked Ready, Linux is marked Ready, and Android is marked Ready. The word Ready is doing quiet work, since a checkmark in a table says nothing about which versions, which distributions, or which devices. The topic list gives more of the picture, with libcosmic in the list for the Linux GUI, jetpack-compose and kotlin for Android, and rust as the main language, so the desktop side is a Rust GUI built on the COSMIC toolkit while the Android side is a Kotlin app. The Android side also uses uniffi, since the `uniffi-bindgen/` directory and the `uniffi-bindgen` workspace member are for generating the bindings between the Rust core and the Kotlin front end. That is the standard way to share a Rust library with a mobile app without writing the protocol twice.

The device table is the feature list in practice

The README lists supported devices as a table of model numbers and names, and it runs to nearly forty entries. The Soundcore Life Q30 and the A3030 Life Tune Pro are there, the Space One and Space One Pro, the Liberty range from 2 Pro through 3 Pro, 4, 4 Pro and 4 NC up to Liberty 5, the Liberty Air 2 Pro, the Life P3 and the P20i, P25i, R50i and P30i line, the Vortex, the Motion+, the AeroClip, the Space A40, and the C30i and C50i earbuds. The naming convention is that the A-prefixed numbers are the Bluetooth product codes for the larger headphones and the D-prefixed numbers for the earbuds, and the table shows how wide the coverage has become. The way to request a new device is spelled out in the README too: check if there is an issue for it, and give it a thumbs up so the maintainer can sort by reactions and prioritise, otherwise open an issue asking for support.

Installing means a signed release, Flathub or IzzyOnDroid

The Installing section points at GitHub Releases and notes that all files are signed with the author's GPG key, which is the thing to check if you are going to run a program that talks to your headphones over Bluetooth. There are also badges for Flathub and for IzzyOnDroid, the F-Droid derivative that carries the Android build, and a Repology packaging status badge showing the project is packaged for a range of distributions. The Linux route through Flathub is the one that fits the project's model, since it is a flatpak and therefore sidesteps the desktop-environment-specific packaging that a Bluetooth control panel otherwise runs into. The mobile route through IzzyOnDroid is the standard way to get an app outside the Play Store, which matters for an app whose whole function is talking to proprietary hardware.

The build is a Cargo workspace with separate GUI, CLI and Android crates

The repository layout is a Rust workspace with the members listed in Cargo.toml: cli, lib, lib-macros, android, uniffi-bindgen, gui, i18n, i18n-macros and lib-has. The version is set once in `[workspace.package]` at 2.13.0, and the shared internal crates are declared as workspace path dependencies with the `openscq30-lib`, `openscq30-lib-has`, `openscq30-lib-macros`, `openscq30-i18n` and `openscq30-i18n-macros` names. The interesting split is between `lib` and `lib-has`. The name suggests a trait for the hardware abstraction, which is the natural way to support forty devices without forty code paths, and the presence of `lib-macros` next to it suggests some of that is generated by procedural macros. The `i18n` and `i18n-macros` pair is the translation layer, and the README points to a translate.codeberg.org widget for the translation status, so translations are contributed through a web interface rather than edited in the source tree.

A justfile drives the builds, with per-profile optimisation

The build system is `just`, and the justfile is more readable than a Makefile for this layout. It starts by declaring the same module list as the workspace, then defines a `build-output-dir` of `build-output`, and the `default` recipe just lists the available recipes. The build recipes come in pairs, because there are two optimisation profiles. `build-gui` runs a fully optimized release build and copies `target/release/openscq30-gui` into the output directory, and `build-gui-fast` does the same with the `release-fast` profile, which the recipe description calls a release build with excessively slow optimizations disabled. The same pairing exists for the CLI, producing `openscq30` rather than `openscq30-gui`. The Cargo.toml explains the profiles: `release` strips symbols and turns on full LTO, `release-fast` inherits from it and switches to thin LTO, and `release-android` also inherits from `release` but keeps symbols, because uniffi-bindgen requires debug info. The Windows installer recipe is separate and marked as a Windows-only group, running `./packaging/windows/build.sh` after the GUI has been built, and the Android recipes build an APK per architecture, starting with x86 and x86_64.

The list recipe is the smallest of them:

bash
[doc("List available recipes")]
list:
    @just --list

And a build recipe copies the binary into the output directory:

bash
build-gui features='': create-build-output-dir
    just gui::build release '{{ features }}'
    cp target/release/openscq30-gui '{{ build-output-dir }}/'

Tests run through just, and package granularity is the point

The test entry point is a single line in the README. `just test` will run all unit and integration tests, and to run tests for a specific package you use `just gui/ test`, the trailing slash being the just syntax for a module-qualified recipe. That syntax is why the justfile declares `mod android`, `mod cli`, `mod gui`, `mod i18n`, `mod i18n-macros`, `mod lib`, `mod lib-macros` and `mod lib-has` at the top. Each of those modules has its own justfile with its own build and test recipes, and the root justfile calls into them with `just gui::build release`. The result is that the GUI, the CLI, the core library and the Android app are built and tested independently, which is what you want in a project where the Android and desktop front ends are different languages over a shared Rust core. The `i18n` module also fits here, since a translation change should not require rebuilding the desktop application.

The command itself is one line:

bash
`just test` will run all unit and integration tests. To run tests for a specific package, use `just gui/ test` for example.

Where OpenSCQ30 is the wrong tool, and how the vendor app differs

Three limits are concrete. The first is the device coverage. Forty models is a lot for a hobby project, but the list is closed, and a device outside it does not work at all, so a buyer should check the table for their exact model before anything else. The second is the protocol itself. The project talks to the headphones over Bluetooth using vendor-specific protocols, which means the application depends on firmware behaviour that the vendor can change, and the README's request for thumbs-up reactions on device issues is a reasonable way to prioritise but not a guarantee. The third is the platform story for the desktop GUI. The GUI is built on libcosmic, so on a system without COSMIC components the desktop experience may be worse than the CLI, and the CLI, which the topic list and the justfile both confirm is a first-class target, is the safer path for a scripted or remote use. There is also a licensing consideration to check before shipping anything based on this code, since it is GPL-3.0.

The realistic alternative is the Soundcore application the vendor ships with the headphones, and the difference in approach is where the settings live. The vendor app is what the device was designed around, so it is likely to expose every option the firmware has, including ones OpenSCQ30 has not implemented, and it is likely to keep working when a firmware update adds a new setting. OpenSCQ30 is a separate implementation that talks to the device over the same Bluetooth protocol, which means it can work without the vendor app, can be scripted through the CLI, and can be used on a platform the vendor app does not support, including Linux desktops and Flathub. The price is that it may lag behind the firmware in coverage, and that the protocol is reverse-engineered rather than documented, so it depends on the maintainer keeping up. For a user on a supported platform who wants the full range of firmware options, the vendor app is the safer answer.

Editorial conclusion

OpenSCQ30 fits a user of a listed Soundcore model on Linux or Android who wants the desktop application installed from Flathub or an F-Droid style store, or who wants to script the settings through the CLI. It is the wrong choice if your exact model is not in the supported device table, and the wrong choice if you need every firmware option, since the vendor application is the more complete and the more durable answer. Before you adopt it, confirm your model number appears in the table, check that the release binary you download matches the GPG signature, and decide whether the libcosmic desktop GUI suits your desktop environment or whether the CLI is the more dependable route.

Frequently asked questions

Which Soundcore devices does OpenSCQ30 support?

The README lists close to forty models with their Bluetooth product codes, from the Soundcore Life Q30 that gave the project its name through the Liberty range, the Space One and Space A40, the Life P3 and P2 Mini, and the C30i and C50i earbuds. Unsupported devices are requested by opening an issue or reacting to an existing one.

How do I install OpenSCQ30?

Download from GitHub Releases, where all files are signed with the author's GPG key, or use the Flathub package for Linux or the IzzyOnDroid build for Android. There is also a Repology badge showing packaging across distributions.

How do I run the OpenSCQ30 tests?

Run `just test` for all unit and integration tests, or target a single package with `just gui/ test`. The justfile declares a module for each workspace member, so the GUI, CLI, core library and Android app are built and tested separately.

Does OpenSCQ30 have a command line interface?

Yes. The workspace has a separate `cli` member producing an `openscq30` binary, with its own just module and its own build recipes for both the release and release-fast profiles, alongside the `openscq30-gui` desktop application.

Official sources

  1. Issues
  2. License: GPL-3.0
  3. Oppzippy/OpenSCQ30 on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/oppzippy-openscq30.svg)](https://hysenlabs.com/projects/oppzippy-openscq30)