From 911301acdb38c7558fd459480936797114b8ea04 Mon Sep 17 00:00:00 2001 From: radionoise Date: Thu, 29 Nov 2018 18:24:23 +0400 Subject: [PATCH] Implemented a feature to keep audio alive only when the built-in audio device is set as default output --- README.md | 6 ++- antipopd | Bin 38360 -> 38868 bytes antipopd.m | 117 +++++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 96 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index e0ef3a5..fa41657 100755 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Build `antipopd` can be built in a terminal using the following command: - clang -framework AppKit -framework IOKit -arch i386 -arch x86_64 -o antipopd antipopd.m + clang -framework AppKit -framework IOKit -framework CoreAudio -arch i386 -arch x86_64 -o antipopd antipopd.m A built version (`i386` and `x86_64`) of `antipopd` is included in the repository. @@ -42,6 +42,10 @@ at `/usr/local/share/antipop/ac_only`. If the first byte of the configuration file is a `1` the audio system will only be kept alive when on AC power. +If you want to allow `antipopd` to work only when the default output device is set to built-in +you can create a configuration file at `/usr/local/share/antipop/built_in_only` as described above. +This may be helpful when you have a bluetooth headset connected and don't want to drain it's battery. + The configuration file is only read once when `antipopd` launches. Changing the configuration file will not take effect until `antipopd` is restarted. diff --git a/antipopd b/antipopd index 79c86c44b2b516b8b9327fc94866edd023454fbc..1890d771f8f18e5f3883e1404fbf601ea2fbf712 100755 GIT binary patch literal 38868 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 #import #import +#import #import -#define ANTIPOPD_CONFIG "/usr/local/share/antipop/ac_only" +#define ANTIPOPD_AC_ONLY_CONFIG "/usr/local/share/antipop/ac_only" +#define ANTIPOPD_BUILT_IN_ONLY_CONFIG "/usr/local/share/antipop/built_in_only" + #define BATTERY_STATE CFSTR("State:/IOKit/PowerSources/InternalBattery-0") #define POWER_SOURCE CFSTR("Power Source State") #define INTERVAL 10 // seconds static BOOL runOnACOnly = NO; +static BOOL runOnBuiltInOnly = NO; void banner() { printf("antipopd\n\n"); - - printf("Copyright (c) Matthew Robinson 2010, 2018\n"); + + printf("Copyright (c) Matthew Robinson 2010, 2018\n"); printf("Email: matt@blendedcocoa.com\n\n"); - + printf("antipopd is a drop in replacement for Robert Tomsick's antipopd 1.0.2 bash\n"); printf("script which is available at http://www.tomsick.net/projects/antipop\n\n"); - + printf("antipopd is a utility program which keeps the audio system active to stop\n"); printf("the popping sound that can occur when OS X puts the audio system to sleep.\n"); printf("This is achieved by using the Speech Synthesizer system to speak a space,\n"); printf("which results in no audio output but keeps the audio system awake.\n\n"); - + printf("The benefit of this compiled version over the bash script is a reduction\n"); printf("in resource overheads. The bash script executes two expensive processes \n"); printf("(pmset and say) every ten seconds (one process if ac_only is set to 0).\n\n"); - + printf("This version of antipopd is released, like Robert Tomsick's version, under\n"); printf("a Creative Commons Attribution Noncommercial Share Alike License 3.0,\n"); printf("http://creativecommons.org/licenses/by-nc-sa/3.0/us\n\n"); - + } NSSpeechSynthesizer *speech = nil; +void *preparePropertyAddress(AudioObjectPropertyAddress *propertyAddress, UInt32 prop) { + propertyAddress->mSelector = prop; + propertyAddress->mScope = kAudioObjectPropertyScopeGlobal; + propertyAddress->mElement = kAudioObjectPropertyElementMaster; + + return propertyAddress; +} + +OSStatus getDeviceTransportType(AudioDeviceID deviceId, UInt32 *transportType) { + AudioObjectPropertyAddress propertyAddress; + preparePropertyAddress(&propertyAddress, kAudioDevicePropertyTransportType); + UInt32 dataSize = sizeof(UInt32); + + return AudioObjectGetPropertyData(deviceId, &propertyAddress, 0, NULL, &dataSize, transportType); +} + +OSStatus getDefaultOutputDevice(AudioDeviceID *deviceId) { + AudioObjectPropertyAddress propertyAddress; + preparePropertyAddress(&propertyAddress, kAudioHardwarePropertyDefaultOutputDevice); + UInt32 dataSize = sizeof(AudioDeviceID); + + return AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize, deviceId); +} + +OSStatus isDefaultOutputDeviceBuiltIn(BOOL *result) { + AudioDeviceID defaultOutputId; + OSStatus error = getDefaultOutputDevice(&defaultOutputId); + + if (error) { + NSLog(@"Error getting default output device (code: %d)", (int) error); + return error; + } + + UInt32 transportType; + error = getDeviceTransportType(defaultOutputId, &transportType); + + if (error) { + NSLog(@"Error getting transport type for device ID: %d (code: %d)", (int) defaultOutputId, (int) error); + return error; + } + + *result = transportType == kAudioDeviceTransportTypeBuiltIn; + + return kAudioServicesNoError; +} + // Timer callback that actually speaks the space void speak(CFRunLoopTimerRef timer, void *info) { if (!speech) { speech = [[NSSpeechSynthesizer alloc] initWithVoice:nil]; } - + // If we are only supposed to run on AC power if (runOnACOnly) { // and we don't have unlimited power remaining @@ -70,33 +120,48 @@ void speak(CFRunLoopTimerRef timer, void *info) { return; } } - + + if (runOnBuiltInOnly) { + BOOL defaultOutputIsBuiltIn; + OSStatus error = isDefaultOutputDeviceBuiltIn(&defaultOutputIsBuiltIn); + + if (error) { + NSLog(@"Error while trying to determine default output device. Code: %d", (int) error); + exit(error); + } + + if (!defaultOutputIsBuiltIn) { + return; + } + } + [speech startSpeakingString:@" "]; } -// Check for the existance of the ac_only file, check the contents -// and set runOnACOnly as appropriate -void loadACOnlyConfig() { - // Try to open the ac_only config file - int fd = open(ANTIPOPD_CONFIG, O_RDONLY); - - // If succesful look inside, otherwise proceed with runOnACOnly default +// Check for the existence of the config file, check the contents +// and set parameter as appropriate +void loadConfigAndSetParameter(BOOL *parameter, char *config) { + // Try to open the config file + int fd = open(config, O_RDONLY); + + // If succesful look inside, otherwise proceed with default parameter if (fd != -1) { char buffer; - + ssize_t result = read(fd, &buffer, 1); - + // ...the first byte of the file is 1 if (result == 1 && buffer == '1') { - runOnACOnly = YES; + *parameter = YES; } - + close(fd); } } int main(int argc, char *argv[]) { - loadACOnlyConfig(); + loadConfigAndSetParameter(&runOnACOnly, ANTIPOPD_AC_ONLY_CONFIG); + loadConfigAndSetParameter(&runOnBuiltInOnly, ANTIPOPD_BUILT_IN_ONLY_CONFIG); // Put an AutoreleasePool in place in case NSSpeechSynthesizer expects it @autoreleasepool { @@ -104,11 +169,11 @@ int main(int argc, char *argv[]) { banner(); exit(EXIT_SUCCESS); } - + CFRunLoopTimerContext context = { 0, NULL, NULL, NULL, NULL, }; - + CFRunLoopTimerRef timer = CFRunLoopTimerCreate( NULL, 0, @@ -118,9 +183,9 @@ int main(int argc, char *argv[]) { speak, &context ); - + CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode); - + CFRunLoopRun(); }