Rewrite to C++
Background
At first, HeadsetControl only supported one device and one feature. No device registry, no feature handling, etc.
That's why in the past, there couldn't be a distinction between C and C++ - it would have been the same code.
However, the project grew considerably: supporting multiple devices, multiple output types, and many features. At some point libusb was switched to libhidapi for better cross-platform support. However, there was never a switch from C to C++.
Why Consider C++ Now?
Pros:
- Would save ~20% duplicate code (device init boilerplate, repeated error handling patterns)
- Some parts are already object-oriented (device registry, vtable-like pattern with function pointers)
- Development would be easier (inheritance, RAII, std::string vs manual malloc/free)
- Access to more libraries if needed (e.g., JSON output, CLI parsing)
- Modern C++ has features we currently work around (asprintf, string handling)
Cons:
- Almost none - performance would be the same, C++ compilers are bundled with C compilers
Why Not Other Languages?
- Binary needs to stay small and performant
- HIDAPI would require wrappers
- Modern C++ with the right tools can be just as productive
Options
- Full migration to C++ - rewrite everything
- Hybrid approach - keep C API, migrate device implementations to C++ classes
- Stay in C - refactor to reduce duplication with helper functions
Thoughts are welcome
How do you feel about rust ? Modern, fast and gains more popularity every day.
Rust would be a much bigger rewrite with a completely different toolchain.
On C++ we could also just rewrite for example the devices and keep the rest as is or rewrite later
I believe that hybrid approach is an excellent idea, it would have a more clean/organized code by migrating most implementations to C++, and would maintain universal compatibility by keeping the APIs in C.
Also, it would be amazing if the project could be structured as a Core Library (DLL on Windows / .so on Linux / idk in Mac) that contains all the device logic, and a separate CLI Executable that simply links to this library.
libheadsetcontrol -> a lib file exposing api (battery, lights, sidetone, etc...) headsetcontrol-cli -> single-shot executable (exactly how it works now)
This would allow developers to link against libheadsetcontrol directly in their own UI applications. We could keep a single USB handle open and query the battery status instantly without the overhead of spawning processes or re-initializing the USB stack constantly (which causes a little overhead, noticeable mainly when playing competitive games).
Also, it would be amazing if the project could be structured as a Core Library (DLL on Windows / .so on Linux / idk in Mac) that contains all the device logic, and a separate CLI Executable that simply links to this library.
Thank you for your feedback. Indeed that is an excellent idea which I did not consider yet. I fully agree that it makes sense and see how it can be implemented in the best way.
I fully agree with the idea of splitting it into a separate library!
See here: https://github.com/Sapd/HeadsetControl/pull/443