Switch Audio Source

OK, thanks for the explanation.

It seems to me that Closure is over-optimizing the code.
I can't imagine that saving 2 char for the occasional use of true would really matter. And on top of that, aren't scripts normally cached by the browser, so they are only downloaded on the first occurrence?

In my System Preferences (System10.11.5), the normal device setting for my computer, an iMac, is “Internal Speakers”, type: “Built-in” (all without quote marks).

But the System Preferences automatically changes that to “Headphones”, type: “Headphone port” (all without quote marks) when I have my headphones plugged in, which is most of the time. So I’ve adjusted the first variable in my version of your macro to “Headphone port” to compensate.

I’d prefer not to keep track of whether the headphones are plugged in before running the macro due to lack of attentive brain. Is there any way to account within the macro for whether I have my headphones plugged in or not?

Or would I need two separate macros and use one or the other depending on whether I’ve got the headphones in (or not).

Thanks.

1 Like

Hey Peter,

Please be specific about what you’re switching between.

My impression is:

Toggle item A:

“Internal Speakers”/“Headphone port”

Toggle item B:

Something else.

If I’m right what’s the something else. If I’m wrong please explain.

-Chris

My impression is:

Toggle item A:

“Internal Speakers”/“Headphone port”

Toggle item B: ?

Thanks for asking, ccstone.

In your format, toggle item A can be one of either:...

“Internal Speakers" or "Headphones”

... in my System Preferences, depending on whether the headphones are physically plugged in or not. The System automatically detects whether they are plugged in, and changes its Preferences text accordingly, and...

Toggle item B: "C_Media USB Audio Device"

The wording of toggle item B doesn't change, unless the device itself isn't plugged into a USB port, in which case your code alerts me to the fact it's not there.

In your code, which works fine as is, if the headphones happen to be plugged in, then the Preferences wording changes and the code fails.

After reading your KM variable settings steps and your code script that follows (I know little about the coding), I was thinking what was needed was that KM, maybe, should do an IF-THEN-ELSE test before invoking your script, something like:

IF the System Preferences is set to "Internal Speakers" OR "Headphones" THEN switch to "C_Media USB Audio Device"

But I don't know how to query the System, by changing your KM steps or code, about the state of the Preferences's current setting, whether it's “Internal Speakers” or "Headphones". I'm guessing that KM should do the IF-Then test and branch accordingly so that it sets up your script properly. But maybe it works better if the script wording is adjusted in some way.

Hey Peter,

That's @ComplexPoint's code rather than mine.  :slight_smile:

I suggest you download and install this command-line tool:

AudioSwitcher.zip (107.1 KB)

Install it here:

/usr/local/bin/

Open a window in the Finder and type G

Paste the path string in the resulting dialog, and hit the GO button.

Drag the executable from the archive into that folder – you will be required to enter your password to do so.

Then you can run this macro and avoid having to mess with System Events.

Toggle Audio Output.kmmacros (2.5 KB)

Although the display in the Sound Preferences changes to reflect whether headphones are connected the actual underlying “Built-in Output” doesn't change, so the shell script doesn't need to check for headphones.

If the macro doesn't work out-of-the-box then the wording for C_Media USB Audio Device may be off.

You can check by switching to that output and then running this in the Terminal.app:

AudioSwitcher -c

The output should look something like this:

C_Media USB Audio Device (output)

If that differs from what I have in the shell script then you'll need to change it:

Remove (output) from the end of what you got from the terminal and replace the relevant string in the shell script in the macro.

All of this may seem a bit intimidating, but it's really simple to get done step-by-step.

Message me if you need help.

TESTED: on OSX 10.11.5 with Keyboard Maestro 7.2

-Chris

2 Likes

The link to AudioSwitcher.zip leads to : Oops! That page doesn’t exist or is private.

Hey Dimo,

That's odd. I'm looking into it.

In the meantime the direct link works – but ONLY if you paste it into your browser's address field – NOT if you click the link in the forum. (Tested only with Safari.)

Strange...

https://forum.keyboardmaestro.com/uploads/default/original/2X/3/3d208a21186eb96aefbc9f6c2ff093296c12722d.zip

-Chris

Another approach I found is based on the fact that if “Sound” appears in the System menu bar, you can hold the option key and click on the Sound icon. That displays all connected output options, including airplay speakers.

I created the following script - which would need to be adjusted based on where the icon appears on a specific monitor, and where the selected output item appears in the sub menu.

Holding the option key - Move and Click without dragging (click on Sound icon)
Duplicate the step and change the down position by a small number and test if you have hit the item. In my case, the number was 50 to hit the fourth item in the list.

Not overly elegant - but it works well. One point - if this is in the middle of other steps - put a Pause in front and after the two macro steps.

1 Like

Hey Folks,

I fixed the download link in post #11.

-Chris

Chris

Thanks for all of this - I followed your instructions and got it working fine. Can you, or someone, help me with 2 questions, as I’m not fluent completely at home with coding, even though the terms are explained in the AudioSwitch documentation.

Firstly, what would the code look like if I wanted it to alter the input device rather than the output device? The default is output, so that changed with F1, but my input isn’t changing. I would ultimately like to change both, so I’m assuming just make a second code and have it run too. I know that -t refers to type, and since the default is output, we don’t see it in the code. So how do you alter the code to work for input?

Secondly, I’d actually like to run these codes triggered by plugging in the usb device. I sort of got that working by changing the trigger, but it seems to go through three steps: Switched to USB, to internal, back to USB. I suspect that’s because the mac is responding anyway when I plug the device in, and that the way around it is to have the KM code simply always run in the one direction (IF) and not have an alternative (ELSE) letting KM do the work. Am I right? Or is this coming across as confusing?

Thanks for any help.

Phil

Hey Phil.

This will change the sound input to the source named in the variable “inputName”.

# REQUIRES: AudioSwitcher Unix Command Line Tool

inputName='Soundflower (2ch)'

export PATH=/opt/local/bin:/opt/local/sbin:/usr/local/bin:$PATH
currentInput=$(AudioSwitcher -t input -c)

if [ ! "$currentInput" = "$inputName" ]; then

   AudioSwitcher -t input -s "$inputName"
   
fi

You can get the available help for AudioSwitcher by inputting the following in the Terminal:

AudioSwitcher -h

This is one-way only.

As for the USB-trigger you’re on your own. I haven’t gone beyond briefly testing them.

-Chris

Chris. Thanks again. Brilliant and I seriously wouldn’t have been able to do it on my own. Because it’s a one-way script, I duplicated it and substituted output for input, so it works exactly as I hoped. Awesome.

1 Like

What would your AppleScript look like if I want it to select a specific audio output, not toggle between two different ones?

Thanks!

You have in mind the JavaScript for Automation in the post below (post 2 of this thread) ?

The variable f gets the name-string of the device to be chosen:

var f = -1 !== c.indexOf(strDeviceA) ? strDeviceB : strDeviceA;

So you should be able to comment out that line, and replace it with something on the pattern of:

var f = "nameStringOfMyPreferredDevice";

where "nameStringOfMyPreferredDevice" is replaced by the real (quoted) name of the device.

That is exactly what I meant! Thanks for a quick reply.

Could you please show me the full script?

I’m still new with programming :wink:

Assuming that you have set a Keyboard Maestro variable called soundDevice to the name of your preferred device (or some distinct part of its name that appears in the System Preferences sound section), then I think a quick patch might look like this:

(For an Execute JavaScript for Automation action, or for prior testing in Script Editor, with the Language tab at top left set to JavaScript rather than AppleScript

(function (strDevice) {
    'use strict';

    var e = Application("System Preferences"),
            b = !1,
            d;
        e.panes["com.apple.preference.sound"].anchors.output.reveal();
        var a = Application("System Events")
            .processes["System Preferences"].windows[
                0].tabGroups[0].scrollAreas[0].tables[0].rows,
            c = a.where({
                selected: !0
            }),
            c = c.length ? c[0].textFields[0].value() : null;
        if (!c) return null;
        var f = strDevice;
        a()
            .forEach(function (a) {
                b || (d = a.textFields[0].value(), -1 !== d.indexOf(f) &&
                    (a.select(), b = !0));
            });
        a = Application.currentApplication();
        a.includeStandardAdditions = !0;
        a.activate();
        a.displayNotification(b ? "->  " + d :
            "Couldn't find a sound device containing this string: \"" + f + '"', {
                withTitle: "Sound Output Device " + (b ? "" : "NOT ") + "Changed"
            });
        e.quit();
        return b;

    })(Application("Keyboard Maestro Engine")
        .getvariable(
            'soundDevice'
        )
    );

I was looking for a way to cycle through audio devices and found many topics in KM forums. After testing some of the solutions, I chose the executable file solution AudioSwitcher.zip (107.1 KB) from @ccstone's reply.

  • Drag the executable file and drop it onto Applications folder, unless you want to keep it somewhere else then you would also need to change the default path of the executable file in the AppleScript below from "/Applications/AudioSwitcher" to your favorite path.

I made a few changes to this AppleScript StackExchange - SwitchAudioSource. The dialogue box seems unnecessary in my opinion so I deleted its line. I replaced it with a notification to know which output device is the current one. Also replaced " -c" with "-n".

Swtich Audio Source

on run
    set theSwitch to "/Applications/AudioSwitcher"
    do shell script theSwitch & "-n"
end run

Swtich Audio Source.kmmacros (1.6 KB)

1 Like

Hey Ali,

The typical place to install 3rd party Unix executables is here:

/usr/local/bin/

Open a window in the Finder, type Cmd-Shift-G, and paste the path into the “Go to the folder” field.

The system will require you to authenticate the move, and that's fine.

Also – there is no point in running a shell script from an AppleScript, unless it's part of a larger AppleScript.

Keyboard Maestro has a Execute a Shell Script action for pure shell scripts.

image

See this topic on the wiki for more information:

https://wiki.keyboardmaestro.com/action/Execute_a_Shell_Script

By using the export command, with the PATH variable, you won't have to use the full path to the executable.

export PATH=/usr/local/bin:$PATH;
AudioSwitcher -a

See brief discussion here: Path to excutables in shell scripts

You can also set a variable in Keyboard Maestro's variable preferences that will globally affect the PATH environment variable in the KM context.

The following link is to a macro that will do that for you.

Create a PATH Environment Variable for Keyboard Maestro and Add /usr/local/bin to the Default Path

This allows you to call your shell executable very simply:

AudioSwitcher -a

-Chris

These are valuable tips, Chris. Thanks

1 Like