{"id":21196273,"url":"https://github.com/neildavis/alsa_volume_from_usb_hid","last_synced_at":"2025-04-13T19:23:31.802Z","repository":{"id":64450665,"uuid":"493431646","full_name":"neildavis/alsa_volume_from_usb_hid","owner":"neildavis","description":"A daemon to control ALSA volume from USB HID Consumer Control events","archived":false,"fork":false,"pushed_at":"2023-07-14T10:31:21.000Z","size":27,"stargazers_count":3,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-27T10:03:58.943Z","etag":null,"topics":["alsa","alsamixer","amixer","daemon","linux","python","systemd-service","usb","usb-hid","usb-hid-devices"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/neildavis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-17T22:26:33.000Z","updated_at":"2024-11-06T16:46:17.000Z","dependencies_parsed_at":"2024-11-20T19:35:30.697Z","dependency_job_id":"af4713ff-b4ba-4867-a3d6-9e49729105d0","html_url":"https://github.com/neildavis/alsa_volume_from_usb_hid","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neildavis%2Falsa_volume_from_usb_hid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neildavis%2Falsa_volume_from_usb_hid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neildavis%2Falsa_volume_from_usb_hid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neildavis%2Falsa_volume_from_usb_hid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/neildavis","download_url":"https://codeload.github.com/neildavis/alsa_volume_from_usb_hid/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248766687,"owners_count":21158302,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alsa","alsamixer","amixer","daemon","linux","python","systemd-service","usb","usb-hid","usb-hid-devices"],"created_at":"2024-11-20T19:35:11.993Z","updated_at":"2025-04-13T19:23:31.784Z","avatar_url":"https://github.com/neildavis.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ALSA Volume From USB HID #\n\n## Overview ##\n\nThis is a small Python based daemon for Linux systems using the Advanced Linux Sound Architecture ([ALSA](https://alsa-project.org/wiki/Main_Page)) to allow [USB HID](https://www.usb.org/hid) 'Consumer Control' volume events to adjust the ALSA mixer volume. These events are typically sent by USB peripheral devices like keyboards which include volume controls.\n\nAs far as I know, this should 'just work' without the need for this daemon, and indeed this is the case on most modern Linux Desktops.\nHowever, it seems some environments and/or ALSA configurations break this,\nor are otherwise not supported. e.g. minimal CLI systems.\nIn my case I was using a Raspberry Pi in CLI boot mode with the [ALSA SoftVol](https://alsa.opensrc.org/Softvol) plugin to enable a volume control for an [Adafruit MAX98357 I2S Class-D Mono Amp](https://learn.adafruit.com/adafruit-max98357-i2s-class-d-mono-amp?view=all) PCM device which has no volume control itself.\n\nThe daemon installs as a [systemd](https://www.linux.com/training-tutorials/understanding-and-using-systemd/) service.\n\n\n## Prerequisites ##\n\n### Python envronment ###\n\nSince the daemon runs using [Python](https://www.python.org/) we need to setup the Python environment. In particular we require Python version 3, not the deprecated Python 2. Most modern Linux distros include Python3 by default, but the commands below will install it if it's missing.\n\nThese commands are for [Debian](https://www.debian.org/) based Linux distros  (e.g. [Ubuntu](https://ubuntu.com/), [Linux Mint](https://linuxmint.com/) and [Raspberry Pi OS](https://www.raspberrypi.com/documentation/computers/os.html)) using the Debian [`apt` package manager](https://wiki.debian.org/Apt). If you are using a non-Debian system you will need to find the best way to install these packages using your system.\n\nA note on Python versions.\nDebian repositories tend to lag Python versions, sometimes by a number of years! If you want to use the latest/greatest version of Python 3 I'm assuming you know how to build/install it for your system.\nI'm not sure what the absolute minimum version of Python is required to run the daemon, but I have tested on v3.7.3 which dates to early 2019 and is included in [Debian 10 ('Buster')](https://www.debian.org/releases/buster/)\n\nAlong with the base Python language \u0026 runtime support, we will need a few more tools. Namely:\n\n* [pip](https://pypi.org/project/pip/) for easy Python package management\n* [venv](https://docs.python.org/3/library/venv.html) to create virtual Python environments.\n\n    ```shell\n    sudo apt install python3 python3-pip python3-venv\n    ```\n\n### User group requirements ###\n\nAdd your user to the `input` group if necessary. This is required to allow the daemon to receive Linux evdev input events from USB HID devices.\n\n```shell\nsudo usermod -a -G input $USER\n```\n\nYou will need to log out and log in again (or reboot) for this change to take effect. Again, this only has to be done once.\n\n## Running manually ##\n\nYou can run daemon manually in a terminal using the steps below.\nHowever most of the time you will want the daemon to install and start automatically instead of starting it manually like this. In that case, skip the rest of this section and see the following sections below including:\n\n* ['Identifying ALSA cards and mixers'](#identifying-alsa-cards-and-mixers)\n* ['Identifying USB HID input devices](#identifying-usb-hid-input-devices)\n* ['Installing'](#installing)\n\nBut back to running manually in a terminal:\n\n1. Create \u0026 activate a new Python virtual environment (venv). This step is optional but recommended, to avoid polluting your system's base Python environment with otherwise unnecessary packages.\n\n    ```shell\n    python3 -m venv env\n    source env/bin/activate\n    ```\n\n    The first line to create the venv only has to be done once, although you will need to activate the env each time you login with the second line.\n2. Install some Python library dependencies using pip. in particular we require:\n    * [evdev](https://python-evdev.readthedocs.io/en/latest/) - for receiving USB HID events from the Linux kernel.\n    * [pyalsaaudio](https://larsimmisch.github.io/pyalsaaudio/) - for controlling ALSA audio mixers.\n\n    ```shell\n    pip install evdev pyalsaaudio\n    ```\n\n    Again, this only has to be done once.\n\n3. Finally, run the daemon. Without any args it will try to find the best ALSA mixer device and USB HID device automatically. These, and other options can be specified manually on the command line with the `-h` flag. See the help for details:\n\n```monospace\n    python3 src/alsa_vol_from_usb_hid.py -h\n    usage: alsa_vol_from_usb_hid.py [-h] [-d ALSA_DEV] [-c ALSA_CTRL]\n                                    [-i INPUT_DEV] [-v {5,10,15,20,25}]\n                                    [-l {critical,error,warning,info,debug}]\n\n    Adjust ALSA mixer volume from USB HID Consumer Control device events\n\n    optional arguments:\n    -h, --help            show this help message and exit\n    -d ALSA_DEV, --alsa-dev ALSA_DEV\n                            ALSA device to use, e.g. \"hw:0\" (uses 'default' device\n                            if not specified)\n    -c ALSA_CTRL, --alsa-ctrl ALSA_CTRL\n                            ALSA control to use, e.g. \"Master\" (defaults to first\n                            playback capable control on the device)\n    -i INPUT_DEV, --input-dev INPUT_DEV\n                            Device to use for USB input (defaults to first USB HID\n                            device found under /dev/input/)\n    -v {5,10,15,20,25}, --volume-delta {5,10,15,20,25}\n                            Set the volume delta increments/decrements as a\n                            percentage (default=10%)\n    -l {critical,error,warning,info,debug}, --log-level {critical,error,warning,info,debug}\n                            Set the logging level (default='info')\n```\n\nPress CTRL+C to exit.\n\n## Identifying ALSA cards and mixers ##\n\nWithout any `-d` argument, the daemon will attempt to use the '`default`' ALSA device.\nThis is often a 'virtual device' with a 'Master' mixer control and exactly what you want!\nHowever, sometimes the default behaviour isn't what you want and you need to override this.\n\nThe `-d` option will allow you to specify the ALSA device to use. But how do you find these?\nWell, to get a list of all sound-card devices on the system you can use this command:\n\n```shell\ncat /proc/asound/cards\n```\n\nThis will produce output something like this:\n\n```monospace\n0 [Headphones     ]: bcm2835_headpho - bcm2835 Headphones\n                      bcm2835 Headphones\n1 [T20402MB       ]: USB-Audio - Tiny 2040 (2MB)\n                      Pimoroni Tiny 2040 (2MB) at usb-0000:01:00.0-1.3, full speed\n```\n\nThe number of cards and their details will vary wildly based on your system hardware\nand what devices you have plugged in, but what's important is the 'card index' number\non the left. Make a note of this index number for the device you want to use.\n\nOnce you know the 'card index' of the device you can simply pass this as an option\nto the daemon using the `-d` argument like this:\n\n```shell\npython3 src/alsa_vol_from_usb_hid.py -d hw:N\n```\n\nwhere `N` is the card index, e.g. if I wanted to use the BCM2835 headphones output\nI would use `hw:0`\n\nWithout any `-c` argument, the daemon will look for a suitable 'playback' control\non the specified card and use the first one it finds.\nAgain, this default behaviour may be exactly what you want, but you have the option\nto override this.\n\nYou can find a list of the 'simple mixer controls' on your chosen card with a command\nlike this:\n\n```shell\namixer -D hw:0 scontrols\n```\n\nAgain, substitute `hw:0` with your chosen device id as above. This will list the\navailable mixer controls in a format something like this:\n\n```monospace\nSimple mixer control 'Headphone',0\n```\n\nAgain, your output will vary. I have only one result here but you may have more.\nThe important bit is the name in quotes after '`Simple mixer control`',\ni.e. '`Headphone`' which is the name of the ALSA mixer control you use with `-c` e.g.\n\n```shell\npython3 src/alsa_vol_from_usb_hid.py -d hw:0 -c Headphone\n```\n\n## Identifying USB HID input devices ##\n\nWithout any `-i` argument, the daemon will attempt to find a suitable input device automatically.\nIt does this by iterating all available USB input devices which identify themselves as\n'device class 3' which corresponds to USB HID devices. These are further queried to find those\nwhich declare a capability to send the relevant volume events:\n(`KEY_VOLUMEUP`, `KEY_VOLUMEDOWN`, `KEY_MUTE`)\n\nYou can manually select an input device by passing its path using `-i` e.g.\n\n```shell\npython3 src/alsa_vol_from_usb_hid.py -i /dev/input/event2\n```\n\nTo find the input device you want, you may try looking at the output of this command\nbefore and after adding \u0026 removing the device\n\n```shell\nls -l /dev/input/by-id\n```\n\nFor example, my Raspberry Pi which has a Logitech Gamepad and an Apple keyboard attached lists these:\n\n```monspace\ntotal 0\nlrwxrwxrwx 1 root root 9 Dec  8 14:08 usb-Apple_Inc._Apple_Keyboard-event-if01 -\u003e ../event4\nlrwxrwxrwx 1 root root 9 Dec  8 14:08 usb-Apple_Inc._Apple_Keyboard-event-kbd -\u003e ../event3\nlrwxrwxrwx 1 root root 9 Dec  8 11:08 usb-Logitech_Logitech_Dual_Action_D4BEAFFB-event-joystick -\u003e ../event0\nlrwxrwxrwx 1 root root 6 Dec  8 11:08 usb-Logitech_Logitech_Dual_Action_D4BEAFFB-joystick -\u003e ../js0\n```\n\nIf I wanted to use the Apple keyboard I would try to use `/dev/input/event3` or `/dev/input/event4`\nand see which works. (Spoiler: it's `event4`)\n\n## Installing ##\n\nBefore installing, make sure you have\n[added your user to the ```input``` group](#user-group-requirements)\nif necessary, as described above.\n\nTo install with automatic ALSA device/control \u0026 USB HID device selection\n\n```sh\nmake install\n```\n\nTo install specifying any additional command line args as described above, pass `ARGS` to make. e.g:\n\n```shell\nmake install ARGS=\"-d hw:0 -c Headphone -v 5 -l warning\"\n```\n\nTo uninstall:\n\n```shell\nmake uninstall\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneildavis%2Falsa_volume_from_usb_hid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fneildavis%2Falsa_volume_from_usb_hid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneildavis%2Falsa_volume_from_usb_hid/lists"}