Max Glenister

Software & Servers • 3 min read Plain text

Replacing the macOS audio switcher with SwiftBar

The built-in audio output menu in macOS has always felt a bit limited. The icons aren’t very helpful, the device names can’t be customised, and if you’ve got a few different outputs, it becomes tricky to quickly tell what’s what.

I wanted a faster and clearer way to switch devices, ideally without opening System Settings. Since I already use SwiftBar, I wrote a small plugin that gives me exactly that: a dropdown with my own labels and icons for each device, plus one-click switching.

It’s powered by SwitchAudioSource (from switchaudio-osx). You’ll need to install it first:

brew install switchaudio-osx

Once that’s in place, drop the script into your SwiftBar plugins folder and make it executable:

chmod +x audio-switcher.1m.sh

Here’s the script:

#!/usr/bin/env bash
# <bitbar.title>Audio Output Switcher</bitbar.title>
# <bitbar.version>2.7</bitbar.version>
# <bitbar.author>Your Name</bitbar.author>
# <bitbar.desc>SwiftBar-only output switcher using SF Symbols and UID matching. Active item tinted blue.</bitbar.desc>
# <bitbar.dependencies>bash,SwitchAudioSource</bitbar.dependencies>
# <swiftbar.hideAbout>true</swiftbar.hideAbout>
# <swiftbar.hideRunInTerminal>true</swiftbar.hideRunInTerminal>
# <swiftbar.hideLastUpdated>true</swiftbar.hideLastUpdated>
# <swiftbar.hideDisablePlugin>true</swiftbar.hideDisablePlugin>
# <swiftbar.hideSwiftBar>true</swiftbar.hideSwiftBar>

SWITCH_AUDIO_BIN="${SWITCH_AUDIO_BIN:-SwitchAudioSource}"

# ---- Config: one per line: Label|UID|SF Symbol ----
DEVICES='Headset|AppleUSBAudioEngine:Logitech:G635 Gaming Headset:00000000:2|headphones
External Speakers|00-02-3C-99-0B-7C:output|speaker.wave.2.fill
Internal Speakers|BuiltInSpeakerDevice|laptopcomputer'

trim(){ sed 's/^[[:space:]]*//; s/[[:space:]]*$//'; }
die(){ echo "⚠️"; echo "---"; echo "$1"; exit 0; }
command -v "$SWITCH_AUDIO_BIN" >/dev/null 2>&1 || die "SwitchAudioSource not found. Install: brew install switchaudio-osx"

# Click handler
if [ "${1-}" = "set" ] && [ -n "${2-}" ]; then
  "$SWITCH_AUDIO_BIN" -t output -u "$2" >/dev/null 2>&1
  exit 0
fi

# SF Icon config
SFCONFIG="$(printf '%s' '{"renderingMode":"Hierarchical","scale":"medium", "colors":[]}' | base64 | tr -d '\n\r' | trim)"
# echo "$SFCONFIG" | base64 -d

# Current device UID (JSON)
CURRENT_JSON="$("$SWITCH_AUDIO_BIN" -c -t output -f json 2>/dev/null)"
CUR_UID="$(printf '%s\n' "$CURRENT_JSON" | sed -n 's/.*"uid"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | tr -d '\r' | trim)"

# Menubar icon (active device’s symbol, tinted blue)
ACTIVE_SYMBOL="speaker.wave.2.fill"
while IFS='|' read -r LABEL DEV_UID SYMBOL; do
  [ -z "$LABEL$DEV_UID$SYMBOL" ] && continue
  DEV_UID="$(printf '%s' "$DEV_UID" | trim)"
  SYMBOL="$(printf '%s' "$SYMBOL" | trim)"
  if [ -n "$CUR_UID" ] && [ "$DEV_UID" = "$CUR_UID" ]; then
    ACTIVE_SYMBOL="$SYMBOL"
    break
  fi
done <<< "$DEVICES"

echo "| sfimage=$ACTIVE_SYMBOL sfconfig=$SFCONFIG"
echo "---"


# Device rows
while IFS='|' read -r LABEL DEV_UID SYMBOL; do
  [ -z "$LABEL$DEV_UID$SYMBOL" ] && continue
  LABEL="$(printf '%s' "$LABEL" | trim)"
  DEV_UID="$(printf '%s' "$DEV_UID" | trim)"
  SYMBOL="$(printf '%s' "$SYMBOL" | trim)"

  line="$LABEL | bash='$0' param1=set param2='$DEV_UID' terminal=false refresh=true sfimage=$SYMBOL sfconfig=$SFCONFIG"
  if [ -n "$CUR_UID" ] && [ "$DEV_UID" = "$CUR_UID" ]; then
    # Tick it, tint the icon and text blue
    line="$line checked=true"
  fi
  echo "$line"
done <<< "$DEVICES"

echo "---"
echo "Sound Settings… | bash='/usr/bin/open' param1='x-apple.systempreferences:com.apple.preference.sound' terminal=false sfimage=gearshape sfconfig=$SFCONFIG"

The only section you’ll likely want to change is the list of devices:

Label|UID|SF Symbol

You can fetch the UIDs for your outputs with:

SwitchAudioSource -a -f json

Or better still pull out just the label and UID from the json using jq:

SwitchAudioSource -a -f json | jq '.name + "|" + .uid + "|speaker"'

Pick the devices you actually use and enter them with whatever label and SF Symbol you want. The active device is indicated, and the menu bar icon updates to match.

There’s also a “Sound Settings…” shortcut at the bottom of the menu if you need the full system panel.

For convenience, the script is also on GitHub Gist: https://gist.github.com/omgmog/5bb66598c792f98ccdbe39cfd503488c

  • UX & Design · shares #guide
    Launching Sketch Toolbox from inside Sketch

    I’ve been making use of Sketch a lot lately. One of the coolest features of Sketch is it’s plugin support. I’m using a tool called Sketch Toolbox to manage plugins in Sketch – this functions a lot like Package Control for Sublime Text, but it’s a stand-alone application.

    July 2015 • 2 min read
  • Software & Servers · shares #guide
    Compressing PDF files from your Mac or Linux terminal with Ghostscript

    I arrived at this solution recently when looking to compress a massive print-quality PDF for the web. If you search for “compressing pdf files on mac” you’ll get lots of bad results. There are lots of paid applications out there that claim to be able to do this, but they’re (obviously) not free.

    March 2014 • 2 min read
  • Software & Servers · shares #software
    Updates to my 'install all firefox' bash script for Mac OS X

    I wrote briefly about my install-all-firefox shell script back in December last year. Since then the script has received a complete rewrite, and some new features.

    March 2012 • 2 min read

Discussion

No interactions yet

Comments are closed

You can still reply from your own site with a Webmention.

Webmentions last fetched 8 November 2026, 07:10