Skip to content

Development

Denis Arnst edited this page May 1, 2023 · 15 revisions

See the main README for basic compilation instructions.

Also there is now a dev menu available under ./headsetcontrol --dev -- --dev-help use it after the instructions below.

Contributing

We use the WebKit coding style and clang-format to enforce it. You can usually install clang-format via package managers (clang-format or clang-format-9.0).

If both is installed, you can build the project by creating and going into the build folder and then with
cmake -DENABLE_CLANG_FORMAT=1 -DCMAKE_BUILD_TYPE=Debug ..

Use it like this:

  • make format will automatically format your code to our specification

When you do a Pull Request (PR), the CI will check the format, and will also check for unnecessary whitespaces (you can also check it yourself with git diff --check HEAD^)

Check alsamixer on Linux

If the Sidetone of your headset is available as audio channel, it cannot be implemented here in Headsetcontrol, as HID does not support changing audio channels. You can easily check this with alsamixer.

You can however still implement support for battery etc.

Adding a new headset

You need a bit experience in programming. Start by looking into the devices/ folder, and see how the structure of a device file is set up (ignore the actual raw package bytes for now).

Also you need the original driver-software installed in a Windows machine. This can als be a Windows installation in a virtual machine with USB passthrough.

Use a capturing software like Wireshark or USBLyzer. When installing Wireshark, make sure to select USB support. When Capturing, you will probably see your device in the list as "Composite device". Select "USB Input Device" for capturing and start it; your device is easily identifiable, as it must be named/tagged as "HID" device.

While capturing, start to slide the slider of the sidetone option in your driver's software up and down and stop it afterwards.

Take a look at the following screenshots. Note that Wireshark and USBLyzer show different captures here.

Wireshark Screenshots

Sidetone set to 0 Screenshot Wireshark (big version)

Sidetone set to full Screenshot Wireshark2 (big version)

USBLyzer Screenshot

Screenshot (big version)

For Wireshark, you can use a filter like this: usb.bInterfaceClass == HID && usb.endpoint_address.direction != IN && usb.src == host This will only show HID packets, going from the computer to the headset. Also in the screenshot I added && usb.setup.wLength == 64; as I noticed that a lot of other packets/noise was sent on a different length.

When you look into the WireShark screenshot, you see a SET_REPORT packet with following data:

ff 0b 00 ff  04 0e 01 05
01 04 00 *f4*  00 00 00 00
00 00 00 00  00 00 00 00 
00 00 00 00  00 00 00 00
00 00 00 00  00 00 00 00  
00 00 00 00  00 00 00 00
00 00 00 00  00 00 00 00
00 00 00 00  00 00 00 00

Note that the 12th-byte (counting from 1) is changing when setting sidetone. When it's set to full, it seems to be f4, which is 244 in decimal, when off, it is 0.

Also note that the length is 64-byte (as can be read in wLength).

When it's a Set Report, you need to use hid_send_feature_report, and for a write hid_write !!. You can call those functions directly with the raw data you see at the capturing software. So the following is an example using the data gained:

static int headset_send_sidetone(hid_device* device_handle, uint8_t num)
{
    // num, will be from 0 to 128, we need to map it to the correct value
    // the range of the void seems to be from 200 to 244
    // Note that we don't use 0 as minimal target range, as it would behave weirdly
    //    for the user (lower numbers do nothing then)
    num = map(num, 0, 128, 200, 244);

    // When initialising this way (on stack), missing values will be automatically set to 0
    // The size of the array should be correctly set to the value, the capture software shows
    uint8_t sidetone_data[64] = {0xff, 0x0b, 0, 0xff, 0x04, 0x0e, 0x01, 0x05,
                                 0x01, 0x04, 0x00, num};

    // Errors will be handled by the main function of HeadsetControl
    return hid_send_feature_report(device_handle, sidetone_data, sizeof(sidetone_data)/sizeof(sidetone_data[0]));
}

Note that the code style above is preferred (some code is older and e.g. initialises the array explicitly to 0; however this is unnecessary).

For the full implementation look into other device files, to see how they are set up. When creating new source code, make sure to add your files to src/devices/CMakeLists.txt and call your init function at src/device_registry.c. After creating new files, you'll have to delete your build folder and rerun cmake.

Make sure that you send the correct amount of bytes (like shown in the capturing software), don't cut ending 0-bytes or the Windows implementation will fail. Also try to set idUsagePage and idUsage for the Windows implementation, they can be listed using ./headsetcontrol --dev -- --list --device VENDORID:PRODUCTID (see the Windows section below).

Before implementing it in code, you can also test the packet with the --dev commands. E.g.:

./headsetcontrol --dev -- --device 0x1b1c:0x1b27 --send-feature "
0xff, 0x0B, 0, 0xFF, 0x04, 0x0E, 0xFF, 0x05, 0x01, 0x04, 0x00, 200, 0, 0, 0, 0
0x0, 0x0, 0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x00, 0, 0, 0, 0, 0
0x0, 0x0, 0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x00, 0, 0, 0, 0, 0
0x0, 0x0, 0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x00, 0, 0, 0, 0, 0"

In the dev command line, you can seperate the numbers with spaces, or commas, or new-lines. Also you can write the numbers in either hex (with 0x) or directly as decimal. Also you have the possibility of receiving data, see ./headsetcontrol --dev -- --dev-help:

Windows

Compilation

  1. Download and Install MSYS2
  2. pacman -Syu
  3. Close the msys terminal and start it again
  4. pacman -Syu
  5. pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-hidapi make git
  6. There should be now also a "MSYS2 MinGW 64-bit"-shortcut in your start menu (just use Windows Search), start and use it now
  7. git clone the repository
  8. mkdir build && cd build
  9. cmake -G"MSYS Makefiles" ..
  10. make and if wanted make install

You can also call the application then normally via windows-cmd or bat file etc. The application will be statically linked, so you dont need any dependencies when running it.

Problems

Windows needs different endpoints then the UNIX-implementations. They are called Usages and Usage Pages. There could be multiple different endpoints for different packets (like sidetone <-> leds). However the HeadsetControl software only supports one endpoint for each device for now.

You can see the endpoints with headsetcontrol --dev -- --list --device VENDORID:PRODUCTID They will be shown as Usage-Page: 0xff00 Usageid: 0x1 also the Interface number could be relevant.

Also Windows expects the correct amount of bytes for every packet sent by the software. Linux/MacOS is more forgiving and allows ending 0's to be omitted.

"Incorrect function"

The endpoint (usageid / usagepage) is wrong.

"Incorrect parameter"

You probably didn't send the correct amount of bytes.

Clone this wiki locally