volumecontrol
A cross-platform Rust library for querying and controlling system audio volume.
volumecontrol exposes a single, unified API that works on Linux (PulseAudio), Windows (WASAPI), and macOS (CoreAudio). The correct backend is selected automatically at compile time — no feature flags or platform-specific imports are needed in your code.
Table of Contents
- Repository Structure
- Getting Started
- Installation
- Usage
- How to Collaborate
- License
- Contact / Further Information
Repository Structure
volumecontrol/ ← workspace root
├── Cargo.toml ← workspace manifest & cross-compilation config
├── Cargo.lock ← locked dependency versions
├── LICENSE ← MIT license
├── README.md ← this file
├── AGENTS.md ← AI agent contribution instructions
│
├── volumecontrol-core/ ← platform-independent traits & error types
│ └── src/
│ ├── lib.rs ← public re-exports
│ ├── traits.rs ← AudioDevice trait definition
│ └── error.rs ← AudioError enum
│
├── volumecontrol-linux/ ← PulseAudio backend (feature: pulseaudio)
├── volumecontrol-windows/ ← WASAPI backend (feature: wasapi)
├── volumecontrol-macos/ ← CoreAudio backend (feature: coreaudio)
│
└── volumecontrol/ ← cross-platform wrapper crate
└── src/lib.rs ← selects the right backend via #[cfg(target_os)]
| Crate | Purpose |
|---|---|
volumecontrol-core |
AudioDevice trait, AudioError enum, shared utilities |
volumecontrol-linux |
AudioDevice impl using PulseAudio |
volumecontrol-windows |
AudioDevice impl using WASAPI |
volumecontrol-macos |
AudioDevice impl using CoreAudio |
volumecontrol |
Selects the right backend at compile time via #[cfg(target_os)] |
Getting Started
volumecontrol lets you read and change the system audio volume from Rust with a single, cross-platform API:
use AudioDevice;
Platform requirements
| Platform | Backend | System library required |
|---|---|---|
| Linux | PulseAudio | libpulse-dev (e.g. via apt) |
| Windows | WASAPI | built into Windows — nothing extra |
| macOS | CoreAudio | built into macOS — nothing extra |
Installation
Add volumecontrol to your Cargo.toml:
[]
= "0.1"
Linux users: install the PulseAudio development headers before building:
# Debian / Ubuntu # Fedora / RHEL # Arch Linux
Once the system library is in place, build as usual:
Usage
Open the default audio device
use AudioDevice;
let device = from_default?;
Look up a device by ID or name
// By exact device identifier returned from list()
let device = from_id?;
// By a partial name match (case-insensitive substring search)
let device = from_name?;
List all available audio devices
let devices = list?;
for info in &devices
Read device ID and name
// Display shows "name (id)" — useful for logs and CLI output
println!;
// id() returns the opaque platform identifier used by from_id() and list()
println!;
// name() returns the human-readable label used by from_name() and list()
println!;
Both values are guaranteed to be non-empty.
Read and change the volume
// Volume is always in the range 0..=100
let vol = device.get_vol?;
println!;
device.set_vol?; // set to 50 %
Mute / unmute
if device.is_mute?
device.set_mute?; // mute
device.set_mute?; // unmute
Error handling
All methods return Result<_, AudioError>. The error variants are:
| Variant | Meaning |
|---|---|
DeviceNotFound |
No device matched the given id or name |
InitializationFailed |
The audio subsystem could not be initialised |
ListFailed |
Listing available devices failed |
GetVolumeFailed |
Could not read the current volume |
SetVolumeFailed |
Could not change the volume |
GetMuteFailed |
Could not read the mute state |
SetMuteFailed |
Could not change the mute state |
Unsupported |
Operation not supported on this platform |
EndpointLockPoisoned |
A thread panicked while holding the audio endpoint lock (Windows) |
How to Collaborate
Contributions are very welcome! Please follow these steps:
1. Open an issue first
For non-trivial changes (new features, API changes, new platform backends) open a GitHub issue to discuss the idea before investing time in a pull request.
2. Fork & clone
3. Create a feature branch
4. Make your changes
- Follow the Rust API Guidelines.
- Document every public item with a
///doc comment. - Add
# Errorssections to fallible functions. - Never use
unwrap()orexpect()— propagate errors with?. - All
unsafecode must be hidden behind a safe wrapper and annotated with a// SAFETY:comment. - Use
thiserrorfor any new error types.
5. Run the toolchain
# Check the whole workspace
# Run all tests
# Lint (no warnings allowed)
# Format
All four commands must pass before submitting a pull request.
6. Submit a pull request
Push your branch and open a pull request against main. Describe what you changed and why. Link the relevant issue if one exists.
Coding style summary
| Topic | Rule |
|---|---|
| Formatting | cargo fmt defaults (enforced by CI) |
| Naming | snake_case for files and modules |
| Errors | thiserror-derived enums; no unwrap/expect |
| Unsafe code | Private helpers only; // SAFETY: required |
| Tests | #[cfg(test)] mod tests block in the same file |
| Documentation | /// for every public item; //! for crates |
License
This project is licensed under the MIT License.
See the LICENSE file for the full text.
Contact / Further Information
- Issues & feature requests: GitHub Issues
- Pull requests: GitHub Pull Requests
- Maintainer: @SomaticIT
If you have a question that is not suited for a public issue, you can reach the maintainer through their GitHub profile.