I use this script all the time to change my sound output (and sometimes input).
I just had to update it for Ventura because they completely redid System Preferences (and renamed it System Settings)
Exactly as it stands, I’m sure this isn’t useful to anyone else, because it’s customized for my environment. But it would be easy to adapt. Also, I thought someone wanting to do similar things might find it useful as a reference.
In particular, finding the correct syntax to GUI script some of these things is a bit of a PITA, so thought I might save someone else the trouble.
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
tell application "System Events"
set userName to the name of the current user
end tell
set sysVersion to system version of (system info)
set mainVers to text 1 through ((offset of "." in sysVersion) - 1) of sysVersion as number
set newUI to mainVers > 12
if newUI then
tell application "System Events"
tell application process "System Settings"
set soundPane to the first row of outline 1 of scroll area 1 of group 1 of splitter group 1 of group 1 of window 1 whose value of the first static text of UI element 1 is "Sound"
set selected of soundPane to true
repeat
try
window "Sound"
exit repeat
end try
end repeat
-- Select output tab
perform action "AXPress" of radio button 1 of tab group 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound"
set currentOutputName to (the value of the first static text of group 1 of UI element 1) of (the first row of table 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound" whose selected is true)
end tell
end tell
else
tell application "System Preferences" to reveal anchor "output" of pane id "com.apple.preference.sound"
delay 0.3
tell application "System Events"
tell process "System Preferences"
set currentOutput to the first row of table 1 of scroll area 1 of tab group 1 of window "Sound" whose selected is true
set currentOutputName to the value of text field 1 of currentOutput
end tell
end tell
end if
set headSetName to "Mpow HC4"
set ComputerSoundbarName to "LG HDR 4K"
set HomeTheaterReceiverName to "SC-75"
set HeadphoneAmpName to "External Headphones"
if currentOutputName is ComputerSoundbarName then
set currentOutputName to "Computer Soundbar"
else if currentOutputName is HomeTheaterReceiverName then
set currentOutputName to "Home Theater Receiver"
else if currentOutputName is HeadphoneAmpName then
set currentOutputName to "Headphone Amp"
else if currentOutputName is headSetName then
set currentOutputName to "USB Headset"
end if
set soundOptionsList to {"Phone Headset", "Computer Soundbar", "Headphone Amp", "Home Theater Receiver", "Living Room", "Master Bedroom", "Ellies Room"}
if userName is not "work" then set soundOptionsList to soundOptionsList & "iPhone(s) / Airfoil"
if (currentOutputName is not headSetName) and (currentOutputName is not in soundOptionsList) then copy currentOutputName to the beginning of soundOptionsList
if currentOutputName is "Computer Soundbar" then
set defaultChoice to "Headphone Amp"
else if currentOutputName is "Headphone Amp" then
set defaultChoice to "Computer Soundbar"
else
set defaultChoice to currentOutputName
end if
set soundChoice to (choose from list soundOptionsList with prompt "Select sound output" default items defaultChoice OK button name {"Go"} cancel button name {"Cancel"}) as text
set newSoundInput to false
if soundChoice is "false" then
return
else if soundChoice is "Phone Headset" then
set newSoundOutput to headSetName
set newSoundInput to headSetName
else if soundChoice is "Computer Soundbar" then
set newSoundOutput to ComputerSoundbarName
else if soundChoice is "Headphone Amp" then
set newSoundOutput to HeadphoneAmpName
else if soundChoice is "Home Theater Receiver" then
set newSoundOutput to HomeTheaterReceiverName
else if soundChoice is "iPhone(s) / Airfoil" then
run script "tell application \"Airfoil.app\" to activate"
else
set newSoundOutput to soundChoice
end if
try
if newUI then
tell application "System Events" to tell application process "System Settings"
set selected of ((the first row of table 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound") whose (value of the first static text of group 1 of UI element 1) is newSoundOutput) to true
if newSoundInput is not false then
perform action "AXPress" of radio button 2 of tab group 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound"
set selected of ((the first row of table 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound") whose (value of the first static text of group 1 of UI element 1) is newSoundInput) to true
end if
end tell
else
tell application "System Events" to tell process "System Preferences" to select (row 1 of table 1 of scroll area 1 of tab group 1 of window "Sound" whose value of text field 1 is newSoundOutput)
if newSoundInput is not false then
tell application "System Preferences" to reveal anchor "input" of pane id "com.apple.preference.sound"
tell application "System Events" to tell process "System Preferences" to select (row 1 of table 1 of scroll area 1 of tab group 1 of window "Sound" whose value of text field 1 is newSoundInput)
end if
tell application "System Preferences" to quit
end if
on error
display dialog "There was a problem selecting \"" & soundChoice & "\" in the Sound Control Panel." buttons {"Cancel"} default button "Cancel"
end try
I changed some line in your script so as not to be hardcoded soundOptionList
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
set {sysVersion, userName} to {system version, short user name} of (system info)
set mainVers to text 1 through ((offset of "." in sysVersion) - 1) of sysVersion as number
set newUI to mainVers > 12
if newUI then
tell application "System Events"
if "System Settings" is not in (name of processes) then
launch application "System Settings"
repeat until "System Settings" is in (name of processes)
delay 0.2
end repeat
end if
tell application process "System Settings"
repeat with i from 10 to 0 by -1 --will try for 5 seconds
if exists window 1 then exit repeat
delay 0.2
end repeat
if i = 0 then return -- timed-out
set soundPane to row 1 of outline 1 of scroll area 1 of group 1 of splitter group 1 of group 1 of window 1 whose value of the first static text of UI element 1 is "Sound"
if not (selected of soundPane) then set selected of soundPane to true
repeat with i from 25 to 0 by -1 --will try for 5 seconds
try
window "Sound"
exit repeat
end try
delay 0.5
end repeat
if i = 0 then return -- timed-out
-- Select output tab
set myButton to (first radio button of tab group 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound" whose description is "Output")
if value of myButton = 0 then
perform action "AXPress" of item 1 of myButton --(radio buttons of tab group 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound" whose description is "Output")
end if
--perform action "AXPress" of radio button 1 of tab group 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound"
set currentOutputName to (value of static text 1 of group 1 of UI element 1) of (first row of table 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound" whose selected is true)
set soundOptionsList to value of static text 1 of group 1 of UI element 1 of rows of table 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound"
end tell
end tell
else
tell application "System Settings" to reveal anchor "output" of pane id "com.apple.preference.sound"
delay 0.3
tell application "System Events"
tell process "System Preferences"
set currentOutput to the first row of table 1 of scroll area 1 of tab group 1 of window "Sound" whose selected is true
set currentOutputName to the value of text field 1 of currentOutput
end tell
end tell
end if
set headSetName to "Mpow HC4"
set ComputerSoundbarName to "LG HDR 4K"
set HomeTheaterReceiverName to "SC-75"
set HeadphoneAmpName to "External Headphones"
if currentOutputName is ComputerSoundbarName then
set currentOutputName to "Computer Soundbar"
else if currentOutputName is HomeTheaterReceiverName then
set currentOutputName to "Home Theater Receiver"
else if currentOutputName is HeadphoneAmpName then
set currentOutputName to "Headphone Amp"
else if currentOutputName is headSetName then
set currentOutputName to "USB Headset"
end if
--set soundOptionsList to {"Phone Headset", "Computer Soundbar", "Headphone Amp", "Home Theater Receiver", "Living Room", "Master Bedroom", "Ellies Room"}
if userName is not "work" then set end of soundOptionsList to "iPhone(s) / Airfoil"
if (currentOutputName is not headSetName) and (currentOutputName is not in soundOptionsList) then copy currentOutputName to the beginning of soundOptionsList
if currentOutputName is "Computer Soundbar" then
set defaultChoice to "Headphone Amp"
else if currentOutputName is "Headphone Amp" then
set defaultChoice to "Computer Soundbar"
else
set defaultChoice to currentOutputName
end if
set soundChoice to (choose from list soundOptionsList with prompt "Select sound output" default items defaultChoice OK button name {"Go"} cancel button name {"Cancel"}) as text
set newSoundInput to false
if soundChoice is "false" then
return
else if soundChoice is "Phone Headset" then
set newSoundOutput to headSetName
set newSoundInput to headSetName
else if soundChoice is "Computer Soundbar" then
set newSoundOutput to ComputerSoundbarName
else if soundChoice is "Headphone Amp" then
set newSoundOutput to HeadphoneAmpName
else if soundChoice is "Home Theater Receiver" then
set newSoundOutput to HomeTheaterReceiverName
else if soundChoice is "iPhone(s) / Airfoil" then
run script "tell application \"Airfoil.app\" to activate"
else
set newSoundOutput to soundChoice
end if
try
if newUI then
tell application "System Events" to tell application process "System Settings"
set selected of ((first row of table 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound") whose (value of the first static text of group 1 of UI element 1) is newSoundOutput) to true
if newSoundInput is not false then
perform action "AXPress" of radio button 2 of tab group 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound"
set selected of (first row of table 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound" whose (value of the first static text of group 1 of UI element 1) is newSoundInput) to true
end if
end tell
else
tell application "System Events" to tell process "System Preferences" to select (row 1 of table 1 of scroll area 1 of tab group 1 of window "Sound" whose value of text field 1 is newSoundOutput)
if newSoundInput is not false then
tell application "System Settings" to reveal anchor "input" of pane id "com.apple.preference.sound"
tell application "System Events" to tell process "System Preferences" to select (row 1 of table 1 of scroll area 1 of tab group 1 of window "Sound" whose value of text field 1 is newSoundInput)
end if
tell application "System Settings" to quit
end if
on error
display dialog "There was a problem selecting \"" & soundChoice & "\" in the Sound Control Panel." buttons {"Cancel"} default button "Cancel"
end try
I’ve got options that show up that I never use that I didn’t want cluttering my list, so for me, the hard coded list was best. If for any reason the currently selected output wasn’t on my list, I did have the script just adding it to the list for that run.
I also forgot to mention - while I can send my sound all over the place, 99% of the time when I run this, I’m just switching between my computer speakers and headphones, so I have it automatically switch the default there. I keep this script on a command key via Fastscripts, so to swap between my headphones and speakers, I don’t even need to select off the list. It’s just my shortcut for the script and then immediately hit enter - so it’s almost always just two keystrokes to the change I want to make.
Feel free to edit away - I notice that after your changes, there are still a lot of hardcoded values that are only applicable to my setup in there.
I hadn’t done any work to generalize this for anyone else’s use case - I just wanted to get those wonky lines like:
set selected of ((the first row of table 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound") whose (value of the first static text of group 1 of UI element 1) is newSoundInput) to true
out there, so nobody else has to puzzle through that UI mess.
Unfortunately, it doesn’t work in Sonoma, they’ve changed the UI yet again! It worked without changes for something like a dozen OS releases, then they broke it two versions in a row. I’ve been meaning to update it, I’ll post it when I fix it again.
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
tell application "System Events"
set userName to the name of the current user
end tell
set sysVersion to system version of (system info)
set mainVers to text 1 through ((offset of "." in sysVersion) - 1) of sysVersion as number
if mainVers > 12 then
tell application "System Settings" to launch
tell application "System Events"
tell application process "System Settings"
repeat
try
window 1
exit repeat
end try
end repeat
delay 0.1
set soundPane to the first row of outline 1 of scroll area 1 of group 1 of splitter group 1 of group 1 of window 1 whose value of the first static text of UI element 1 is "Sound"
set selected of soundPane to true
repeat
try
window "Sound"
exit repeat
end try
end repeat
-- Select output tab
perform action "AXPress" of radio button 1 of tab group 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound"
if mainVers > 13 then
set currentOutputName to (the value of the first static text of group 1 of UI element 1) of (the first row of outline 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound" whose selected is true)
else
set currentOutputName to (the value of the first static text of group 1 of UI element 1) of (the first row of table 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound" whose selected is true)
end if
end tell
end tell
else
tell application "System Settings" to reveal anchor "output" of pane id "com.apple.preference.sound"
delay 0.3
tell application "System Events"
tell process "System Preferences"
set currentOutput to the first row of table 1 of scroll area 1 of tab group 1 of window "Sound" whose selected is true
set currentOutputName to the value of text field 1 of currentOutput
end tell
end tell
end if
set headSetName to "Mpow HC4"
set ComputerSoundbarName to "LG HDR 4K"
set HomeTheaterReceiverName to "SC-75"
set HeadphoneAmpName to "External Headphones"
if currentOutputName is ComputerSoundbarName then
set currentOutputName to "Computer Soundbar"
else if currentOutputName is HomeTheaterReceiverName then
set currentOutputName to "Home Theater Receiver"
else if currentOutputName is HeadphoneAmpName then
set currentOutputName to "Headphone Amp"
else if currentOutputName is headSetName then
set currentOutputName to "USB Headset"
end if
set soundOptionsList to {"Phone Headset", "Computer Soundbar", "Headphone Amp", "Home Theater Receiver", "Living Room", "Master Bedroom", "Ellies Room"}
if userName is not "work" then set soundOptionsList to soundOptionsList & "iPhone(s) / Airfoil"
if (currentOutputName is not headSetName) and (currentOutputName is not in soundOptionsList) then copy currentOutputName to the beginning of soundOptionsList
if currentOutputName is "Computer Soundbar" then
set defaultChoice to "Headphone Amp"
else if currentOutputName is "Headphone Amp" then
set defaultChoice to "Computer Soundbar"
else
set defaultChoice to currentOutputName
end if
set soundChoice to (choose from list soundOptionsList with prompt "Select sound output" default items defaultChoice OK button name {"Go"} cancel button name {"Cancel"}) as text
set newSoundInput to false
if soundChoice is "false" then
return
else if soundChoice is "Phone Headset" then
set newSoundOutput to headSetName
set newSoundInput to headSetName
else if soundChoice is "Computer Soundbar" then
set newSoundOutput to ComputerSoundbarName
else if soundChoice is "Headphone Amp" then
set newSoundOutput to HeadphoneAmpName
else if soundChoice is "Home Theater Receiver" then
set newSoundOutput to HomeTheaterReceiverName
else if soundChoice is "iPhone(s) / Airfoil" then
run script "tell application \"Airfoil.app\" to activate"
else
set newSoundOutput to soundChoice
end if
try
if mainVers > 12 then
tell application "System Events" to tell application process "System Settings"
if mainVers > 13 then
set selected of ((the first row of outline 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound") whose (value of the first static text of group 1 of UI element 1) is newSoundOutput) to true
if newSoundInput is not false then
perform action "AXPress" of radio button 2 of tab group 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound"
set selected of ((the first row of outline 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound") whose (value of the first static text of group 1 of UI element 1) is newSoundInput) to true
end if
else
set selected of ((the first row of table 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound") whose (value of the first static text of group 1 of UI element 1) is newSoundOutput) to true
if newSoundInput is not false then
perform action "AXPress" of radio button 2 of tab group 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound"
set selected of ((the first row of table 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound") whose (value of the first static text of group 1 of UI element 1) is newSoundInput) to true
end if
end if
end tell
else
tell application "System Events" to tell process "System Preferences" to select (row 1 of table 1 of scroll area 1 of tab group 1 of window "Sound" whose value of text field 1 is newSoundOutput)
if newSoundInput is not false then
tell application "System Settings" to reveal anchor "input" of pane id "com.apple.preference.sound"
tell application "System Events" to tell process "System Preferences" to select (row 1 of table 1 of scroll area 1 of tab group 1 of window "Sound" whose value of text field 1 is newSoundInput)
end if
end if
-- tell application "System Settings" to quit
on error
display dialog "There was a problem selecting \"" & soundChoice & "\" in the Sound Control Panel." buttons {"Cancel"} default button "Cancel"
end try
Incidentally, I don't have it closing System Setting after it's done anymore, because for some reason, if I quit System Settings via Applescript on Sonoma, the next time it launches, it has not window and can not do anything until I manually quit it and launch it again? Very strange. At least, that's the behavior I'm experiencing now.