From adb4981cff540558a63f02b05874efce1a3ce5e6 Mon Sep 17 00:00:00 2001 From: Nathan Bolender Date: Thu, 6 Aug 2020 00:47:14 -0400 Subject: [PATCH] Display UID and allow setting by a substring of UID --- README.md | 3 +- audio_switch.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++--- audio_switch.h | 5 ++- 3 files changed, 86 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index aefe58a..ac687a1 100644 --- a/README.md +++ b/README.md @@ -25,13 +25,14 @@ switchaudio-osx requires command line tools to be installed from OS X. To instal Usage ----- -SwitchAudioSource [-a] [-c] [-t type] [-n] -s device\_name | -i device\_id +SwitchAudioSource [-a] [-c] [-t type] [-n] -s device\_name | -i device\_id | -u device\_uid - **-a** : shows all devices - **-c** : shows current device - **-t** _type_ : device type (input/output/system). Defaults to output. - **-n** : cycles the audio device to the next one - **-i** _device_id_ : sets the audio device to the given device by id + - **-u** _device_uid_ : sets the audio device to the given device by uid or a substring of the uid - **-s** _device_name_ : sets the audio device to the given device by name diff --git a/audio_switch.c b/audio_switch.c index ccd9813..efbd108 100644 --- a/audio_switch.c +++ b/audio_switch.c @@ -31,13 +31,14 @@ OTHER DEALINGS IN THE SOFTWARE. void showUsage(const char * appName) { - printf("Usage: %s [-a] [-c] [-t type] [-n] -s device_name | -i device_id\n" + printf("Usage: %s [-a] [-c] [-t type] [-n] -s device_name | -i device_id | -u device_uid\n" " -a : shows all devices\n" " -c : shows current device\n\n" " -t type : device type (input/output/system). Defaults to output.\n" " -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); } @@ -45,12 +46,13 @@ int runAudioSwitch(int argc, const char * argv[]) { char requestedDeviceName[256]; char printableDeviceName[256]; int requestedDeviceID; + char requestedDeviceUID[256]; AudioDeviceID chosenDeviceID = kAudioDeviceUnknown; ASDeviceType typeRequested = kAudioTypeUnknown; int function = 0; int c; - while ((c = getopt(argc, (char **)argv, "hacnt:i:s:")) != -1) { + while ((c = getopt(argc, (char **)argv, "hacnt:i:s:u:")) != -1) { switch (c) { case 'a': // show all @@ -77,6 +79,12 @@ int runAudioSwitch(int argc, const char * argv[]) { requestedDeviceID = atoi(optarg); break; + case 'u': + // set the requestedDeviceUID + function = kFunctionSetDeviceByUID; + strcpy(requestedDeviceUID, optarg); + break; + case 's': // set the requestedDeviceName function = kFunctionSetDeviceByName; @@ -165,6 +173,16 @@ int runAudioSwitch(int argc, const char * argv[]) { strcpy(printableDeviceName, requestedDeviceName); } + if (function == kFunctionSetDeviceByUID) { + // find the id of the requested device + chosenDeviceID = getRequestedDeviceIDFromUIDSubstring(requestedDeviceUID, typeRequested); + if (chosenDeviceID == kAudioDeviceUnknown) { + printf("Could not find an audio device with UID \"%s\" of type %s. Nothing was changed.\n", requestedDeviceUID, deviceTypeName(typeRequested)); + return 1; + } + sprintf(printableDeviceName, "Device with UID: %s", getDeviceUID(chosenDeviceID)); + } + if (!chosenDeviceID) { printf("Please specify audio device.\n"); showUsage(argv[0]); @@ -178,6 +196,64 @@ int runAudioSwitch(int argc, const char * argv[]) { return 0; } +char * getDeviceUID(AudioDeviceID deviceID) { + CFStringRef deviceUID = NULL; + UInt32 dataSize = sizeof(deviceUID); + AudioObjectPropertyAddress propertyAddress = { + kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + + propertyAddress.mSelector = kAudioDevicePropertyDeviceUID; + + AudioObjectGetPropertyData(deviceID, &propertyAddress, 0, NULL, &dataSize, &deviceUID); + + char * deviceUID_string = CFStringGetCStringPtr(deviceUID, kCFStringEncodingASCII); + + CFRelease(deviceUID); + + return deviceUID_string; +} + + +AudioDeviceID getRequestedDeviceIDFromUIDSubstring(char * requestedDeviceUID, ASDeviceType typeRequested) { + UInt32 propertySize; + AudioDeviceID dev_array[64]; + int numberOfDevices = 0; + + AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propertySize, NULL); + // printf("propertySize=%d\n",propertySize); + + AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propertySize, dev_array); + numberOfDevices = (propertySize / sizeof(AudioDeviceID)); + // printf("numberOfDevices=%d\n",numberOfDevices); + + for(int i = 0; i < numberOfDevices; ++i) { + switch(typeRequested) { + case kAudioTypeInput: + if (!isAnInputDevice(dev_array[i])) continue; + break; + + case kAudioTypeOutput: + if (!isAnOutputDevice(dev_array[i])) continue; + break; + + case kAudioTypeSystemOutput: + if (getDeviceType(dev_array[i]) != kAudioTypeOutput) continue; + break; + default: break; + } + + char * deviceUID = getDeviceUID(dev_array[i]); + + if (strstr(deviceUID, requestedDeviceUID) != NULL) { + return dev_array[i]; + } + } + + return kAudioDeviceUnknown; +} AudioDeviceID getCurrentlySelectedDeviceID(ASDeviceType typeRequested) { UInt32 propertySize; @@ -259,7 +335,7 @@ void showCurrentlySelectedDeviceID(ASDeviceType typeRequested) { currentDeviceID = getCurrentlySelectedDeviceID(typeRequested); getDeviceName(currentDeviceID, currentDeviceName); - printf("%s\n",currentDeviceName); + printf("%s (ID: %u) (UID: %s)\n", currentDeviceName, currentDeviceID, getDeviceUID(currentDeviceID)); } @@ -397,6 +473,6 @@ void showAllDevices(ASDeviceType typeRequested) { } getDeviceName(dev_array[i], deviceName); - printf("\"%s\" (ID: %u) (%s)\n", deviceName, dev_array[i], deviceTypeName(device_type)); + printf("\"%s\" (ID: %u) (UID: %s) (%s)\n", deviceName, dev_array[i], getDeviceUID(dev_array[i]), deviceTypeName(device_type)); } } diff --git a/audio_switch.h b/audio_switch.h index 24294f8..d2b9390 100644 --- a/audio_switch.h +++ b/audio_switch.h @@ -47,13 +47,16 @@ enum { kFunctionShowAll = 3, kFunctionShowCurrent = 4, kFunctionCycleNext = 5, - kFunctionSetDeviceByID = 6 + kFunctionSetDeviceByID = 6, + kFunctionSetDeviceByUID = 7 }; void showUsage(const char * appName); int runAudioSwitch(int argc, const char * argv[]); +char * getDeviceUID(AudioDeviceID deviceID); +AudioDeviceID getRequestedDeviceIDFromUIDSubstring(char * requestedDeviceUID, ASDeviceType typeRequested); AudioDeviceID getCurrentlySelectedDeviceID(ASDeviceType typeRequested); void getDeviceName(AudioDeviceID deviceID, char * deviceName); ASDeviceType getDeviceType(AudioDeviceID deviceID);