Why does this applescript not actually set the input volume to zero?

I have this command that builds a script to mute the input volume. The input volume is not fully muted, though. It seems to be closer to 10% than 0%.

osacompile -x -e 'tell application "System Events" to set volume input volume 0' -o ~/bin/mute_mic.scpt

This is odd, because the slider bar is as far left as it can go, but as you can see from the attached image, sound still is registering. However, if I use the mouse to click on the slider at zero, then it does actually mute the input.

Why does this happen? Am I using applescript improperly here?

Proof of script not muting.

I can even replicate this with the basic AppleScript Editor, so I know it's not a problem with the compilation.

applescript not working

(Note: I originally took my cue for the solution to this problem from this question's answer.)


As far as I can tell, the script works as expected, the problem is in the OS X audio input code. When I run it, the slider goes to 0%, verified by mousing over the slider until the tooltip appears:

tooltip

This is the same as if I drag the volume slider manually.

The problem is seemingly that "0%" doesn't actually mean off, but rather a very low threshold. In some quick testing, I could record the sound of my finger tapping on my MacBook Pro's casing near the mic (on most machines I believe it's around the right speaker grill) when the volume was set to 0. I could replicate that regardless of whether I set the slider manually or via AppleScript. It did seem to be low enough that virtually any other sound isn't picked up, but clearly the microphone isn't truly off.

As far as I can tell, there's no way to properly mute the built-in mic. The best I can suggest is changing the audio input to use the line in, if your Mac is equipped with a line in port. Doing that via AppleScript requires some GUI scripting unfortunately, but this should do it (source):

tell application "System Preferences"
   activate
   set current pane to pane id "com.apple.preference.sound"
end tell
tell application "System Events"
   tell process "System Preferences"
       set frontmost to true
       --get properties of UI element of tab group of window "Sound"
       click radio button "input" of tab group of window "Sound"
       tell row 2 of table 1 of scroll area 1 of tab group 1 of window "Sound" to set selected to true
   end tell
end tell

If you have more than the two standard audio inputs (Mic and Line In), you may need to change the number in row 2 to whichever is appropriate, according to the order in your Input preferences.


This builds off of @robmathers GUI scripting piece and my question about if you can "click" the slider with applescript. I did some digging into AppleScript and UI actions and it turns out you can.

This uses GUI scripting which is sad, but it WORKS.

tell application "System Events"
    set volume input volume 0
end tell
tell application "System Preferences"
    activate
    set current pane to pane id "com.apple.preference.sound"
end tell
tell application "System Events"
    tell process "System Preferences"
        set frontmost to true
        click radio button "input" of tab group 1 of window "Sound"
        perform action "AXDecrement" of slider 1 of group 2 of tab group 1 of window "Sound"
    end tell
end tell
tell application "System Preferences"
    quit
end tell

Here's what's happening in this script:

  1. Sets the input volume to 0 -- this moves the slider all the way to the left
  2. "Clicks" the slider to do whatever behind-the-scenes voodoo that Apple has deemed necessary to actually "mute" the input line (this is getting ridiculous)
  3. Quits the System Preferences Application.

One thing to note: The Sound Preferences window cannot already be open before running this or the first set volume input volume 0 doesn't work.

It's also trivial to edit the script to unmute (which also suffers from the same issue). (Use "AXIncrement" for the action)

Huge props to @robmathers on getting me as far as I needed to figure this last piece out. I'll still wait to award the bounty in case someone else has a more elegant solution, but otherwise, it's his for the taking.