-
-
Notifications
You must be signed in to change notification settings - Fork 178
Development 1 ‐ Adding a device
This document describes how you can implement a new device into HeadsetControl
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.
For example, if you have the wireless version of an implemented wired device, you might get it working by simply adding the ID of your headset to the current implementation.
Run headsetcontrol with this parameters: headsetcontrol --dev -- --list
You should get an output with a lot of devices. There should be your headset. E.g. for Corsair Void:
Device Found
VendorID: 0x1b1c
ProductID: 0x1b27
path: IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/XHC1@14/XHC1@14000000/HS02@14200000/USB2.0 Hub @14200000/AppleUSB20Hub@14200000/AppleUSB20HubPort@14220000/USB2.0 Hub @14220000/AppleUSB20Hub@14220000/AppleUSB20HubPort@14224000/Corsair VOID Wireless Gaming Dongle@14224000/Hid Interface@3/AppleUserUSBHostHIDDevice
serial_number:
Manufacturer: Corsair
Product: Corsair VOID Wireless Gaming Dongle
Interface: 3
Usage-Page: 0xff00 Usageid: 0x1
Take note of the ProductID. (0x1b27 in this case)
- Open the implementation of the similar device
src/devices/the_similar_device.c
create a new#define
for your device where your specify the new device id. - Insert the name of the define into the array PRODUCT_IDS.
- Recompile, by cd'ing back to your build folder and simply type
make
(and possiblymake install
). - If it works, please also contribute by opening an issue or creating a pull request.
If your device works, you can contribute like this: (This will help us greatly!)
- Fork the repository
- Apply your changes to your fork (Please don't do any other changes - do them in a separate request)
- If you have no git knowledge, simply edit it online at GitHub in your fork.
- Do a pull request https://help.github.com/en/articles/creating-a-pull-request-from-a-fork
Don't hesitate to ask questions by opening up an issue.
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.
Sidetone set to 0 (big version)
Sidetone set to full (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
: