Scripting The Sound Pane in System Preferences

Hello All,

I have used the below script from within a FileMaker Pro database to find the possible input sources for recording a sound.

It worked perfectly until I upgraded to Big Sur, but now it fails at:

set InputSource1 to (get value of text field 1 of row 1 of table 1 of scroll area 1 of tab group 1 of window Sound_loc)", as it can't get Value of text field 1

Any thoughts?

Kevin

-- Get input sources available from Sound Pane of System Preferences

tell application "System Preferences"
   activate
   --open sound pane and select input tab
   reveal anchor "input" of pane id "com.apple.preference.sound"
end tell

tell application "System Events" to tell process "System Preferences"
   set frontmost to true
   set Sound_loc to my getLocalWindowName()
   set InputSource1 to (get value of text field 1 of row 1 of table 1 of scroll area 1 of tab group 1 of window Sound_loc)
   --Row 1 is always "Internal Microphone"
   try
      set InputSource2 to (get value of text field 1 of row 2 of table 1 of scroll area 1 of tab group 1 of window Sound_loc)
      --Row 2, if it exists, is the just attached external microphone name
   on error number -1719
      --trap for error when no USB microphone attached
      set InputSource2 to "External Mic not attached"
   end try
end tell

quit application "System Preferences"

-- Get Users choice of audio input

set userCanceled to false

try
   set dialogResult to display dialog ¬
      "Please select your input source" buttons {InputSource1, InputSource2, "Cancel"} ¬
      default button "Cancel" cancel button ¬
      "Cancel"
on error number -128
   set userCanceled to true
end try
if userCanceled then
   set InputChoice to "User cancelled."
   -- statements to execute when user cancels
   display notification InputChoice with title "Alert"
   setFilemakerpro(InputChoice)
   
else if button returned of dialogResult is InputSource1 then
   set InputChoice to InputSource1
   -- statements to process input source is InputSource1
   SetInputChoice(InputChoice)
   setFilemakerpro(InputChoice)
else if button returned of dialogResult is InputSource2 then
   
   set InputChoice to InputSource2
   -- statements to process input source is InputSource2
   if InputChoice is "External Mic not attached" then
      display notification "There is no external microphone connected. Please connect one and try again later." with title "Alert"
      setFilemakerpro(InputChoice)
   else
      SetInputChoice(InputChoice)
      setFilemakerpro(InputChoice)
   end if
end if

on SetInputChoice(InputChoice)
   
   tell application "System Preferences"
      reveal anchor "input" of pane id "com.apple.preference.sound"
   end tell
   tell application "System Events" to tell process "System Preferences"
      set frontmost to true
      set Sound_loc to my getLocalWindowName()
      set InputSource1 to (get value of text field 1 of row 1 of table 1 of scroll area 1 of tab group 1 of window Sound_loc)
      --Row 1 is always "Internal Microphone"
      if InputChoice is InputSource1 then
         
         select text field 1 of row 1 of table 1 of scroll area 1 of tab group 1 of window Sound_loc
         -- make sure ambient noise reduction is checked
         if (get value of checkbox 1 of tab group 1 of window Sound_loc) = 0 then
            -- the value of the checkbox is 0 if unchecked; 1 if checked
            click checkbox 1 of tab group 1 of window Sound_loc
         end if
      else
         select text field 1 of row 2 of table 1 of scroll area 1 of tab group 1 of window Sound_loc
         --Row 2 is the external microphone
      end if
   end tell
   tell application "System Preferences"
      if InputChoice is InputSource1 then
         set volume input volume 100 -- set to maximum for interanl microphone
      else
         set volume input volume 75 -- set volume lower for external microphones
      end if
      
      (* other optional settings in sound pane
        
set volumeSettings to (get volume settings)
if (output muted of volumeSettings) then
    display dialog "Volume: Muted"
else
    set theVolume to (output volume of volumeSettings)
    display dialog (("Volume: " & theVolume) as string)
end if

set volume alert volume 75
set volume input volume 50
set volume output volume 50
set volume without output muted
get volume settings
*)
      
   end tell
   quit application "System Preferences"
   
end SetInputChoice

on setFilemakerpro(InputChoice)
   
   tell application "FileMaker Pro Advanced"
      tell table "Preferences"
         tell record 1
            set cell "recordoptions1" to InputChoice --let Filemaker pro know which input to use
         end tell
      end tell
   end tell
end setFilemakerpro

-- Allows user independent window location
on getLocalWindowName()
   set p2pane to (path to library folder from system domain as text) & "PreferencePanes:Sound.prefPane:"
   return localized string "CFBundleName" from table "InfoPlist" in bundle (p2pane as «class furl»)
end getLocalWindowName

Model: MacBook Pro (Retina, 13-inch, Late 2013)
AppleScript: 2.7
Browser: Safari 605.1.15
Operating System: macOS 10.14

It failed on my system also. Adding a few delays did the trick.

tell application "System Preferences"
	activate
	reveal anchor "input" of pane id "com.apple.preference.sound"
end tell
tell application "System Events" to tell process "System Preferences"
	set frontmost to true
	repeat until frontmost
		delay 0.1
	end repeat
	set Sound_loc to my getLocalWindowName()
	repeat until exists of text field 1 of row 1 of table 1 of scroll area 1 of tab group 1 of window Sound_loc
		delay 0.1
	end repeat
	set InputSource1 to (get value of text field 1 of row 1 of table 1 of scroll area 1 of tab group 1 of window Sound_loc)
end tell

Hi,

Without GUI scripting you can get names of audio-video input devices using AsObjC:


use AppleScript version "2.4"
use scripting additions
use framework "AVFoundation"

on getAudioVideoInputDevicesNames()
	set inputDevices to current application's AVCaptureDevice's devices()
	set inputDevicesNames to (inputDevices's valueForKeyPath:"localizedName") as list
end getAudioVideoInputDevicesNames

tell my getAudioVideoInputDevicesNames()
	set InputSource1 to item 1
	set InputSource2 to missing value
	try
		set InputSource2 to item 2
		set InputSource3 to missing value
		try
			set InputSource3 to item 3
		end try
	end try
end tell
return {InputSource1, InputSource2, InputSource3}

hello wch1zpink

the delays worked for me, but…
the first time I power up my laptop and use the script it doesn’t open system preferences fast enough and fails at the reveal step. I suspect it is because the the system preferences is in the “protected” part of the Hard Drive. I will try some delays to see if that makes it work on the First use.

Hello KniazidisR

that is a great Idea, but can you use the same framework to set the input source?

Kevin

You can create audio or video session (shared instance) and control it fully. Example setting as preferable my Built-In Microphone instead of Pro Tools Aggregate (checked in the Sound Preferences):


use AppleScript version "2.4"
use scripting additions
use framework "AVFoundation"

-- get all media devices
set inputDevices to current application's AVCaptureDevice's devices()

-- get 1st of them (on my MAC it is Pro Tools Aggregate)
set ProToolsAggregate to item 1 of inputDevices
-- get 2nd of them (on my MAC it is Built-in Microphone)
set internalMicrophone to item 2 of inputDevices
-- get 3rd of them (on my MAC it is Built-in Camera)
set frontCamera to item 3 of inputDevices

-- open new audio session and activate it
set session to (current application's AVAudioSession's sharedInstance())
(session's setActive:yes |error|:(missing value))

-- check before changing the active audio input source
return session's preferredInput()
--> <AVCaptureHALDevice: 0x600000e94e00 [Pro Tools Aggregate I/O][com.Avid.ProToolsAnalogIOAggregateDevice]>

-- THIS: set intenal microfone as prefered input source
session's setPreferredInput:internalMicrophone |error|:(missing value)

-- check after changing the active audio input source
get session's preferredInput()
--> <AVCaptureHALDevice: 0x600000e80780 [Built-in Microphone][AppleHDAEngineInput:1B,0,1,0:1]>

Why not try to use the same delay concept? Like this…

tell application "System Preferences"
	activate
	repeat while not (exists of pane id "com.apple.preference.sound")
		delay 0.1
	end repeat
	reveal anchor "input" of pane id "com.apple.preference.sound"
end tell

Just for my own information:

if system preferences is not currently open…

Is there a difference between the script step

Activate and Launch

Kevin

Telling an application to “Launch” should open the app but not bring it to the foreground.

Telling an application to “Activate” should open the app and bring it to the foreground. (Use this especially if the following code will be using UI Scripting)

My solution, as I wrote it, was only making the code as you posted it… work for you.

Without being able to test your entire code and without knowing why you chose to use or not use certain commands, I would have used this…

tell application "System Preferences" to reveal anchor ¬
	"input" of pane id "com.apple.preference.sound"

Instead of…

tell application "System Preferences"
   activate
   repeat while not (exists of pane id "com.apple.preference.sound")
       delay 0.1
   end repeat
   reveal anchor "input" of pane id "com.apple.preference.sound"
end tell

In fact, with just a few quick edits to your code, you can eliminate the getLocalWindowName() handler and use the following, without the need for adding any delays AND without bringing “System Preferences” to the front.

tell application "System Preferences" to reveal anchor ¬
	"input" of pane id "com.apple.preference.sound"
tell application "System Events" to tell process "System Preferences"
	set InputSource1 to (get value of text field 1 of row 1 of table 1 of scroll area 1 of tab group 1 of window 1)
end tell

Hello,

I updated to Ventura 13.3.1 and it broke my script to activate the sound pane. Any ideas of how to script access to the sound pane

@Beeman. The following worked on my Ventura 13.3.1 computer:

-- If you just want to activate sound system settings
tell application "System Settings"
	activate
	reveal pane id "com.apple.Sound-Settings.extension"
end tell

-- If you want to activate something within sound system settings (Input in this example):
tell application "System Settings"
	activate
	reveal anchor "input" of pane id "com.apple.Sound-Settings.extension"
end tell

I updated to Sonoma and my old script is broken. Using the Framework “AVFoundation” worked to get the input sources, but I am not clear how I would select the device the user has chosen

Hello all

I have appreciated all the help. I have simplified my script to just see if I can get the first row of the Input anchor of the sound pane, but it still fails in Sonoma. I am able to select the first row, but not get the text out of it

any thoughts

Kevin

Screenshot 2024-02-11 at 6.37.46 PM.png.pdf (302.5 KB)

@Beeman

Have you ever tried my command line interface?