<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged pulseaudio</title>
<link>https://coderlegion.com/tag/pulseaudio</link>
<description>Powered by Question2Answer</description>
<item>
<title>Custom Audio Control on Linux: Switch Between Headphones, Speakers, and Dual Output with a Single Co</title>
<link>https://coderlegion.com/8660/custom-audio-control-linux-switch-between-headphones-speakers-and-dual-output-with-single</link>
<description>&lt;h2 id=&quot;custom-audio-control-on-linux-switch-between-headphones-speakers-and-dual-output-with-a-single-command&quot;&gt;Custom Audio Control on Linux: Switch Between Headphones, Speakers, and Dual Output with a Single Command&lt;/h2&gt;
&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;
&lt;p&gt;Linux users know that when it comes to &lt;strong&gt;system-level control&lt;/strong&gt;, almost everything is possible — including building your own solutions for problems that graphical interfaces don’t solve well.&lt;/p&gt;
&lt;p&gt;In this article, I introduce &lt;strong&gt;&lt;code&gt;audioctl&lt;/code&gt;&lt;/strong&gt;, a small &lt;strong&gt;Bash script&lt;/strong&gt; that allows you to switch, with a &lt;strong&gt;single command&lt;/strong&gt;, between:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Headphones connected via &lt;strong&gt;HDMI&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Analog &lt;strong&gt;speakers&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Both outputs at the same time&lt;/strong&gt; (dual mode)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of this is done using &lt;code&gt;pactl&lt;/code&gt;, a bit of Bash, and the flexibility of the Linux audio stack.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt;&lt;br&gt;
With less than 60 lines of Bash, I built a custom audio controller that gives me more flexibility than any GUI tool.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-problem&quot;&gt;The Problem&lt;/h3&gt;
&lt;p&gt;My setup is simple and very common:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;My &lt;strong&gt;headphones are connected to the monitor&lt;/strong&gt;, which connects to the PC via HDMI&lt;/li&gt;
&lt;li&gt;My &lt;strong&gt;speakers are connected to the analog audio output&lt;/strong&gt; of the motherboard&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My father-in-law needed to switch between headphones and speakers — something already possible via the desktop UI — but he also needed to &lt;strong&gt;listen to audio on both devices at the same time&lt;/strong&gt;, for accessibility reasons.&lt;/p&gt;
&lt;p&gt;That’s when I thought:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;“If Linux gives me full system control, why not build my own audio controller?”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-is-pactl-and-why-it-matters&quot;&gt;What Is &lt;code&gt;pactl&lt;/code&gt; and Why It Matters&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;pactl&lt;/code&gt; (&lt;em&gt;PulseAudio Control&lt;/em&gt;) is a command-line utility used to control audio servers such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PulseAudio&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PipeWire&lt;/strong&gt; (fully compatible and now the default on many distributions)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With &lt;code&gt;pactl&lt;/code&gt;, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;List audio devices (sinks and sources)&lt;/li&gt;
&lt;li&gt;Change volume levels&lt;/li&gt;
&lt;li&gt;Switch default outputs&lt;/li&gt;
&lt;li&gt;Move audio streams between devices&lt;/li&gt;
&lt;li&gt;Load audio modules like &lt;code&gt;module-combine-sink&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s essentially the &lt;strong&gt;Swiss Army knife of Linux audio&lt;/strong&gt; — and the foundation of this entire solution.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;
&lt;p&gt;Before continuing, make sure you have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A modern Linux distribution (Ubuntu, Fedora, Arch, NixOS, etc.)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PulseAudio or PipeWire&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;A terminal and text editor&lt;/li&gt;
&lt;li&gt;At least &lt;strong&gt;two working audio outputs&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; To check which audio server you’re using:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pactl info | grep &quot;Server Name&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-1-understand-your-audio-setup&quot;&gt;Step 1: Understand Your Audio Setup&lt;/h3&gt;
&lt;p&gt;Before automating anything, you need to understand which audio devices are available.&lt;/p&gt;
&lt;p&gt;List all sinks (audio outputs):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pactl list sinks short
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Example output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;52 alsa_output.pci-0000_01_00.1.hdmi-stereo     RUNNING
57 alsa_output.pci-0000_09_00.6.analog-stereo   SUSPENDED
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RUNNING&lt;/strong&gt; → currently in use  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SUSPENDED&lt;/strong&gt; → available but idle&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;List audio cards:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pactl list cards
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here you can verify active profiles such as &lt;code&gt;output:analog-stereo&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-2-basic-volume-control-with-pactl&quot;&gt;Step 2: Basic Volume Control with &lt;code&gt;pactl&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;pactl&lt;/code&gt; provides a very useful alias:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;@DEFAULT_SINK@&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Increase volume
pactl set-sink-volume @DEFAULT_SINK@ +5%

# Decrease volume
pactl set-sink-volume @DEFAULT_SINK@ -5%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This allows you to build volume controls that work regardless of the active device.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-3-switching-audio-outputs&quot;&gt;Step 3: Switching Audio Outputs&lt;/h3&gt;
&lt;p&gt;Set a default sink:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pactl set-default-sink SINK_NAME
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Move active audio streams manually:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pactl list short sink-inputs
pactl move-sink-input STREAM_ID NEW_SINK
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These commands are core building blocks for the final script.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-4-playing-audio-on-two-devices-at-the-same-time-dual-mode-&quot;&gt;Step 4: Playing Audio on Two Devices at the Same Time (Dual Mode)&lt;/h3&gt;
&lt;p&gt;This is where things get interesting.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pactl load-module module-combine-sink   sink_name=combined_output   slaves=alsa_output.hdmi,alsa_output.analog   sink_properties=device.description=&quot;Dual_HDMI+Analog&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates a &lt;strong&gt;virtual audio sink&lt;/strong&gt; that mirrors sound to multiple outputs simultaneously.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; PipeWire maintains full compatibility with this module.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-5-the-final-script-audioctl&quot;&gt;Step 5: The Final Script — &lt;code&gt;audioctl&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The final script wraps all of these commands into simple actions like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;audioctl hdmi&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;audioctl analog&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;audioctl dual&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;audioctl toggle&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt; &lt;strong&gt;Full source code:&lt;/strong&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://gist.github.com/igorgbr/8031267dee77acf6d7d298ec72a37f94&quot;&gt;https://gist.github.com/igorgbr/8031267dee77acf6d7d298ec72a37f94&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;installing-the-script&quot;&gt;Installing the Script&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;chmod +x ~/projects/audioctl
mkdir -p ~/bin
ln -sf ~/projects/audioctl ~/bin/audioctl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ensure &lt;code&gt;~/bin&lt;/code&gt; is in your PATH:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;export PATH=&quot;$HOME/bin:$PATH&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reload your shell:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;source ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;extra-tips&quot;&gt;Extra Tips&lt;/h3&gt;
&lt;p&gt;Test with continuous audio:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;speaker-test -t wav -c 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Keyboard shortcuts (GNOME, KDE, i3, etc.):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Super + F11&lt;/code&gt; → &lt;code&gt;audioctl toggle&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Super + F12&lt;/code&gt; → &lt;code&gt;audioctl dual&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;debug-commands-amp-references&quot;&gt;Debug Commands &amp;amp; References&lt;/h3&gt;
&lt;p&gt;Useful debug commands:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pactl list sinks short
pactl get-default-sink
pactl list short sink-inputs
pactl list cards
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Official documentation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PulseAudio CLI:&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/CLI/&quot;&gt;https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/CLI/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PipeWire:&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://pipewire.org/&quot;&gt;https://pipewire.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;module-combine-sink:&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/Modules/#index7h2&quot;&gt;https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/Modules/#index7h2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;With &lt;strong&gt;less than 60 lines of Bash&lt;/strong&gt;, I solved a real-world problem and gained a level of audio control that no graphical application offered me.&lt;/p&gt;
&lt;p&gt;More importantly, this project helped me deeply understand &lt;strong&gt;how Linux audio works under the hood&lt;/strong&gt; and how small automations can dramatically improve everyday workflows.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;✨ &lt;strong&gt;The control is yours — and it lives in the terminal.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</description>
<category>Process Mgmt</category>
<guid isPermaLink="true">https://coderlegion.com/8660/custom-audio-control-linux-switch-between-headphones-speakers-and-dual-output-with-single</guid>
<pubDate>Sat, 20 Dec 2025 21:30:50 +0000</pubDate>
</item>
</channel>
</rss>