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 |
Built with AI
This project was built 100% with GitHub Copilot (Claude Opus & Claude Sonnet models) as an experiment in driving an AI to produce a production-ready Rust crate — from architecture and API design to platform-specific backends, CI pipelines, and documentation.
No human wrote any Rust source code directly; every implementation decision, refactor, and fix was produced by the AI under human direction.
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.