Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 47 additions & 1 deletion audio_switch.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ void showUsage(const char * appName) {
" -n : cycles the audio device to the next one\n"
" -i device_id : sets the audio device to the given device by id\n"
" -u device_uid : sets the audio device to the given device by uid or a substring of the uid\n"
" -s device_name : sets the audio device to the given device by name\n\n",appName);
" -s device_name : sets the audio device to the given device by name\n\n"
" -t system follow : restore alerts \"follow main output\" mode\n"
" (\"Selected sound output device\" in System Settings)\n\n",appName);
}

int runAudioSwitch(int argc, const char * argv[]) {
Expand Down Expand Up @@ -170,6 +172,20 @@ int runAudioSwitch(int argc, const char * argv[]) {
return 0;
}

if (typeRequested == kAudioTypeSystemOutput && optind < argc && strcmp(argv[optind], "follow") == 0) {
AudioDeviceID mainOutput = getCurrentlySelectedDeviceID(kAudioTypeOutput);
if (mainOutput != kAudioDeviceUnknown) {
setOneDevice(mainOutput, kAudioTypeSystemOutput);
}
result = setAlertsFollowMain(true);
if (result == 0) {
char name[256];
getDeviceName(mainOutput, name);
printf("alerts follow main output (\"%s\"); reopen System Settings to refresh UI\n", name);
}
return result;
}

if (typeRequested == kAudioTypeUnknown) typeRequested = kAudioTypeOutput;

if (function == kFunctionCycleNext) {
Expand Down Expand Up @@ -588,6 +604,15 @@ int setOneDevice(AudioDeviceID newDeviceID, ASDeviceType typeRequested) {
printf("Failed to set %s", deviceTypeName(typeRequested));
}

if (typeRequested == kAudioTypeOutput && getAlertsFollowMain()) {
AudioObjectPropertyAddress sysAddr = {
kAudioHardwarePropertyDefaultSystemOutputDevice,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
AudioObjectSetPropertyData(kAudioObjectSystemObject, &sysAddr, 0, NULL, propertySize, &newDeviceID);
}

return 0;
}

Expand Down Expand Up @@ -796,3 +821,24 @@ void showAllDevices(ASDeviceType typeRequested, ASOutputType outputRequested) {
}
}
}

int setAlertsFollowMain(bool follow) {
CFStringRef domain = CFSTR("com.apple.soundpref");
CFStringRef key = CFSTR("AlertsUseMainDevice");
CFBooleanRef value = follow ? kCFBooleanTrue : kCFBooleanFalse;
CFPreferencesSetValue(key, value, domain, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
if (!CFPreferencesSynchronize(domain, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost)) {
printf("Failed to write com.apple.soundpref preference\n");
return 1;
}
return 0;
}

bool getAlertsFollowMain(void) {
CFStringRef domain = CFSTR("com.apple.soundpref");
CFStringRef key = CFSTR("AlertsUseMainDevice");
Boolean valid = false;
Boolean result = CFPreferencesGetAppBooleanValue(key, domain, &valid);
if (!valid) return false;
return (bool)result;
}
2 changes: 2 additions & 0 deletions audio_switch.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ AudioDeviceID getRequestedDeviceID(char * requestedDeviceName, ASDeviceType type
AudioDeviceID getNextDeviceID(AudioDeviceID currentDeviceID, ASDeviceType typeRequested);
int setDevice(AudioDeviceID newDeviceID, ASDeviceType typeRequested);
int setOneDevice(AudioDeviceID newDeviceID, ASDeviceType typeRequested);
int setAlertsFollowMain(bool follow);
bool getAlertsFollowMain(void);
int setAllDevicesByName(char * requestedDeviceName);
int cycleNext(ASDeviceType typeRequested);
int cycleNextForOneDevice(ASDeviceType typeRequested);
Expand Down