Skip to content

Commit

Permalink
Logitech Zone: Add two additional capabilities (#141)
Browse files Browse the repository at this point in the history
* Add support for enabling/disabling "voice prompts" and "rotate to mute" features of the Logitech Zone Wired headset

* Add Logitech Zone Wired headset as well as new capabilites to README
  • Loading branch information
s3lph committed Mar 13, 2021
1 parent a2b7336 commit 472d9a8
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 3 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ talking. This differs from a simple loopback via PulseAudio as you won't have an
- Sidetone, Battery, Inactive time, Chat-Mix level
- Logitech G PRO
- Sidetone
- Logitech Zone Wired
- Sidetone, Voice prompts, Rotate to mute

For non-supported headsets on Linux: There is a chance that you can set the sidetone via AlsaMixer

Expand Down
32 changes: 31 additions & 1 deletion src/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ enum capabilities {
CAP_NOTIFICATION_SOUND = 4,
CAP_LIGHTS = 8,
CAP_INACTIVE_TIME = 16,
CAP_CHATMIX_STATUS = 32
CAP_CHATMIX_STATUS = 32,
CAP_VOICE_PROMPTS = 64,
CAP_ROTATE_TO_MUTE = 128,
};

/** @brief Flags for battery status
Expand Down Expand Up @@ -136,4 +138,32 @@ struct device {
* -1 HIDAPI error
*/
int (*request_chatmix)(hid_device* hid_device);

/** @brief Function pointer for enabling or disabling voice
* prompts on the headset
*
* Forwards the request to the device specific implementation
*
* @param device_handle The hidapi handle. Must be the same
* device as defined here (same ids)
* @param on 1 if it should be turned on; 0 otherwise
*
* @returns > 0 success
* -1 HIDAPI error
*/
int (*switch_voice_prompts)(hid_device* hid_device, uint8_t on);

/** @brief Function pointer for enabling or disabling auto-muting
* when rotating the headset microphone
*
* Forwards the request to the device specific implementation
*
* @param device_handle The hidapi handle. Must be the same
* device as defined here (same ids)
* @param on 1 if it should be turned on; 0 otherwise
*
* @returns > 0 success
* -1 HIDAPI error
*/
int (*switch_rotate_to_mute)(hid_device* hid_device, uint8_t on);
};
20 changes: 19 additions & 1 deletion src/devices/logitech_zone_wired.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ static struct device device_zone_wired;
static const uint16_t PRODUCT_ID = 0x0aad;

static int zone_wired_send_sidetone(hid_device* device_handle, uint8_t num);
static int zone_wired_switch_voice_prompts(hid_device* device_handle, uint8_t on);
static int zone_wired_switch_rotate_to_mute(hid_device* device_handle, uint8_t on);

void zone_wired_init(struct device** device)
{
Expand All @@ -26,8 +28,10 @@ void zone_wired_init(struct device** device)

strncpy(device_zone_wired.device_name, "Logitech Zone Wired", sizeof(device_zone_wired.device_name));

device_zone_wired.capabilities = CAP_SIDETONE;
device_zone_wired.capabilities = CAP_SIDETONE | CAP_VOICE_PROMPTS | CAP_ROTATE_TO_MUTE;
device_zone_wired.send_sidetone = &zone_wired_send_sidetone;
device_zone_wired.switch_voice_prompts = &zone_wired_switch_voice_prompts;
device_zone_wired.switch_rotate_to_mute = &zone_wired_switch_rotate_to_mute;

*device = &device_zone_wired;
}
Expand All @@ -40,3 +44,17 @@ static int zone_wired_send_sidetone(hid_device* device_handle, uint8_t num)

return hid_send_feature_report(device_handle, data, MSG_SIZE);
}

static int zone_wired_switch_voice_prompts(hid_device* device_handle, uint8_t on)
{
uint8_t data[MSG_SIZE] = { 0x22, 0xF1, 0x04, 0x00, 0x05, 0x3d, on, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

return hid_send_feature_report(device_handle, data, MSG_SIZE);
}

static int zone_wired_switch_rotate_to_mute(hid_device* device_handle, uint8_t on)
{
uint8_t data[MSG_SIZE] = { 0x22, 0xF1, 0x04, 0x00, 0x05, 0x6d, on, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

return hid_send_feature_report(device_handle, data, MSG_SIZE);
}
54 changes: 53 additions & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,10 @@ int main(int argc, char* argv[])
long lights = -1;
long inactive_time = -1;
long request_chatmix = 0;
long voice_prompts = -1;
long rotate_to_mute = -1;

while ((c = getopt(argc, argv, "bchs:n:l:i:m")) != -1) {
while ((c = getopt(argc, argv, "bchs:n:l:i:mv:r:")) != -1) {
switch (c) {
case 'b':
request_battery = 1;
Expand Down Expand Up @@ -228,6 +230,20 @@ int main(int argc, char* argv[])
return 1;
}
break;
case 'v':
voice_prompts = strtol(optarg, NULL, 10);
if (voice_prompts < 0 || voice_prompts > 1) {
printf("Usage: %s -v 0|1\n", argv[0]);
return 1;
}
break;
case 'r':
rotate_to_mute = strtol(optarg, NULL, 10);
if (rotate_to_mute < 0 || rotate_to_mute > 1) {
printf("Usage: %s -r 0|1\n", argv[0]);
return 1;
}
break;
case 'h':
printf("Headsetcontrol written by Sapd (Denis Arnst)\n\thttps://github.com/Sapd\n\n");
printf("Parameters\n");
Expand All @@ -238,6 +254,8 @@ int main(int argc, char* argv[])
printf(" -c\t\tCut unnecessary output \n");
printf(" -i time\tSets inactive time in minutes, level must be between 0 and 90, 0 disables the feature.\n");
printf(" -m\t\tRetrieves the current chat-mix-dial level setting\n");
printf(" -v 0|1\tTurn voice prompts on or off (0 = off, 1 = on)\n");
printf(" -r 0|1\tTurn rotate to mute feature on or off (0 = off, 1 = on)\n");

printf("\n");
return 0;
Expand Down Expand Up @@ -408,6 +426,40 @@ int main(int argc, char* argv[])
printf("%d", ret);
}

if (voice_prompts != -1) {
if ((device_found.capabilities & CAP_VOICE_PROMPTS) == 0) {
fprintf(stderr, "Error: This headset doesn't support voice prompt switching\n");
terminate_hid(&device_handle, &hid_path);
return 1;
}
ret = device_found.switch_voice_prompts(device_handle, voice_prompts);

if (ret < 0) {
fprintf(stderr, "Failed to switch voice prompt. Error: %d: %ls\n", ret, hid_error(device_handle));
terminate_hid(&device_handle, &hid_path);
return 1;
}

PRINT_INFO("Success!\n");
}

if (rotate_to_mute != -1) {
if ((device_found.capabilities & CAP_ROTATE_TO_MUTE) == 0) {
fprintf(stderr, "Error: This headset doesn't support rotate to mute switching\n");
terminate_hid(&device_handle, &hid_path);
return 1;
}
ret = device_found.switch_rotate_to_mute(device_handle, rotate_to_mute);

if (ret < 0) {
fprintf(stderr, "Failed to switch rotate to mute. Error: %d: %ls\n", ret, hid_error(device_handle));
terminate_hid(&device_handle, &hid_path);
return 1;
}

PRINT_INFO("Success!\n");
}

if (argc <= 1) {
printf("You didn't set any arguments, so nothing happened.\nType %s -h for help.\n", argv[0]);
}
Expand Down

0 comments on commit 472d9a8

Please sign in to comment.