📖   Chapter 7

Automatically mute your audio on wake

Learn to use a system watcher to react to your laptop waking up.

Next Chapter
APIs used today Description
hs.alertDraws an alert message on the screen.
hs.audiodeviceAllows you to interact with your computer's audio devices.
hs.caffeinate.watcherAllows you to react to system wake/sleep/screensaver events.

What you’re building #

One busy weekend day, I went to my neighborhood cafe to grab an espresso and play around on my laptop for a while. You know, just a normal Saturday afternoon. When I opened my laptop, my speakers started blaring the last song I was playing on Spotify at maximum volume. It was something ostentatious and embarrassing. Think Vengaboys - Boom, Boom, Boom, Boom, coming in right at the chorus. Half the cafe started laughing as I frantically tried to unlock my laptop to silence this beast. Naturally, I mistyped my password 4 times in a row out of nervousness, which just extended my morning stint in hell.

That instant, I vowed this would never happen to me again. I opened up Hammerspoon and wrote myself a script that would automatically mute my speakers when my laptop woke up, no matter what. Today, we’re going to build a version of that script so you can avoid my fate.

Create a new config file #

First, make a config file to hold all your audio switcher code.

copy
touch ~/.hammerspoon/mute-on-wake.lua

And require it in your main config:

copy
require("mute-on-wake")

Create a sleep watcher #

The hs.caffeinate API lets you control system power states, such as sleeping, preventing sleep, screen locking, and more. You can use it to programatically toggle shutdown, sleep, or restart.

Today, we’re going to use a submodule of hs.caffeinate, hs.caffeinate.watcher. You can create a watcher and pass it a function to be called whenever any of the system states change.

These are the system states provided by hs.caffeinate:

State Description
screensaverDidStart The screensaver just activated.
screensaverDidStop The screensaver just stopped.
screensaverWillStop The screensaver is about to stop.
screensDidLock The displays have just locked.
screensDidSleep The displays have just gone to sleep.
screensDidUnlock The displays just unlocked.
screensDidWake The displays just woke up from sleep.
sessionDidBecomeActive The session became active, due to fast user switching
sessionDidResignActive The session is no longer active, due to fast user switching
systemDidWake The system woke from sleep.
systemWillPowerOff The user requested a logout or shutdown
systemWillSleep The system is preparing to sleep

Today, we’re going to use the systemDidWake state to detect when the laptop comes back out of sleep.

To test it out, put this snippet in the config file and reload Hammerspoon:

copy
sleepWatcher = hs.caffeinate.watcher.new(function(state)
  local isWakingUp = state == hs.caffeinate.watcher.systemDidWake

  if isWakingUp then
    hs.alert.show("Woke up from sleep")
  end
end)

sleepWatcher:start()

Put your laptop to sleep, then wake it again. You should see this alert:

Next, we'll wire up audio muting to this watcher.

Mute your audio device #

Next, modify the watcher function to grab the current audio device and mute it. You’ll show an alert message indicating that the operation was successful.

copy
sleepWatcher = hs.caffeinate.watcher.new(function(state)
  local isWakingUp = state == hs.caffeinate.watcher.systemDidWake or
    state == hs.caffeinate.watcher.screensDidWake

  if isWakingUp then
    device = hs.audiodevice.defaultOutputDevice()

    if device then
      device:setMuted(true)
      hs.alert.show("Muted " .. device:name())
    end
  end
end)

sleepWatcher:start()

Reload Hammerspoon again, put your laptop to sleep, and wake it up. You should see an alert, and if you inspect System Preferences > Sound, your speakers should be muted:

Voila, your speakers are automatically muted.

Silence embarrassing notifications

Get the entire script #

Want to just paste in this whole project to your mute-on-wake.lua file?

copy
TK fill this in at the very end once we're sure all the code is solid
Silence embarrassing notifications