Custom Audio Control on Linux: Switch Between Headphones, Speakers, and Dual Audio with a Single Command

Published: (December 7, 2025 at 01:32 PM EST)
3 min read
Source: Dev.to

Source: Dev.to

Cover image for Custom Audio Control on Linux: Switch Between Headphones, Speakers, and Dual Audio with a Single Command

TL;DR: I created a script called audioctl that, with a single command, lets me switch between headphones (via HDMI), analog speakers, or play audio through both at the same time. All using pactl, some Bash, and the power of Linux.

What is pactl?

pactl (short for PulseAudio Control) is a command‑line tool used to control audio servers such as PulseAudio and, with full compatibility, PipeWire — the modern successor to PulseAudio, now default in distros like Fedora, Ubuntu 22.04+, Arch, and NixOS.

With it you can:

  • List audio devices (sinks and sources)
  • Change volume
  • Switch between outputs
  • Move audio streams between devices
  • Load or unload modules (such as module-combine-sink)

It’s the “Swiss Army knife” of terminal audio — and the foundation for everything we’ll build in this tutorial.

The Problem

I use a simple but common setup:

  • Headphones are connected to the monitor, which is connected to the PC via HDMI.
  • Speakers are connected to the analog audio output of the computer.

My father‑in‑law needed to switch between speakers and headphones — something he could already do in the UI — but he also needed the ability to enable both at the same time (for accessibility reasons).

So I thought: Linux gives me full system control — why not create my own audio controller?

That’s exactly what I did. Below is a step‑by‑step guide to building the tool and adapting it to your own setup.

VScode Terminal with program interface

Prerequisites

  • A modern Linux system (Ubuntu, Fedora, Arch, NixOS, etc.) with PulseAudio or PipeWire.
  • Terminal and a text editor.
  • At least two working audio outputs.

💡 To check whether you’re using PipeWire or PulseAudio:

pactl info | grep "Server Name"

If it shows “PipeWire” or “PulseAudio,” you’re good to go!

Step 1: Understand Your Audio Setup

List sinks (audio outputs)

pactl list sinks short

Example output

52  alsa_output.pci-0000_01_00.1.hdmi-stereo     ...  RUNNING
57  alsa_output.pci-0000_09_00.6.analog-stereo   ...  SUSPENDED
  • RUNNING = currently in use
  • SUSPENDED = available but idle

List audio cards

pactl list cards

Look for the analog device and confirm the active profile (e.g., output:analog-stereo).

Step 2: Basic Volume Control

pactl can control the default sink’s volume using the special identifier @DEFAULT_SINK@.

# Increase volume by 5%
pactl set-sink-volume @DEFAULT_SINK@ +5%

# Decrease volume by 5%
pactl set-sink-volume @DEFAULT_SINK@ -5%

Step 3: Switch Audio Outputs

Set the default sink:

pactl set-default-sink SINK_NAME

Move active streams manually:

pactl list short sink-inputs
pactl move-sink-input STREAM_ID NEW_SINK

Step 4: Audio on Two Devices at the Same Time (Dual Mode)

Create a combined sink that forwards audio to both HDMI and analog outputs:

pactl load-module module-combine-sink \
    sink_name=combined_output \
    slaves=alsa_output.hdmi,alsa_output.analog \
    sink_properties=device.description="Dual_HDMI+Analog"

Step 5: The Final Script — audioctl

#!/usr/bin/env bash
# audioctl – simple audio output switcher
# (Full script omitted for brevity; see the “Full Code” section for the complete version)

# Example skeleton:
#   - Detect available sinks
#   - Accept commands: toggle, speakers, headphones, dual
#   - Use pactl to set default sink or load combined sink

Installation

chmod +x ~/projects/audioctl
mkdir -p ~/bin
ln -sf ~/projects/audioctl ~/bin/audioctl

Make sure ~/bin is in your PATH:

export PATH="$HOME/bin:$PATH"

Reload your shell configuration:

source ~/.bashrc

Extra Tips

Test with continuous audio:

speaker-test -t wav -c 2

Keyboard shortcuts (GNOME/KDE/i3)

  • Super + F11audioctl toggle
  • Super + F12audioctl dual

Debug & Useful References

Quick debug commands:

pactl list sinks short
pactl get-default-sink
pactl list short sink-inputs
pactl list cards

Official References

  • PulseAudio CLI docs
  • PipeWire docs
  • module-combine-sink docs

Conclusion

With less than 60 lines of Bash, I solved a real problem — and gained flexibility no graphical app offers.

Control is in your hands — and in the terminal.

Full Code

https://gist.github.com/igorgbr/8031267dee77acf6d7d298ec72a37f94

Back to Blog

Related posts

Read more »

12 Days of Shell

Article URL: https://12days.cmdchallenge.com Comments URL: https://news.ycombinator.com/item?id=46190577 Points: 31 Comments: 8...

My Dev Tool List 2025

TL;DR macOS bash AeroSpace window manager brew install --cask nikitabobko/tap/aerospace Core utilities brew install atuin chezmoi gh fzf eza bat ripgrep st...