Permalink
Browse files

Fix an issue with non-built-in default devices

When no audio devices for input, output, or ringtone have been
selected, we want to use first met built-in devices with appropriate
capabilities (with non-zero number of input channels for import, and
similar rule for output).

Originally, the OS API didn't allow to tell if the device is
built-in. Not it allows.

Fixes #71
  • Loading branch information...
eofster committed Nov 3, 2013
1 parent 48c4704 commit d31bf2bfc3e3ff9372e1802a03e8ca431de3ae28
Showing with 72 additions and 59 deletions.
  1. +1 −0 Classes/AppController.h
  2. +46 −56 Classes/AppController.m
  3. +25 −3 Classes/SoundPreferencesViewController.m
View
@@ -40,6 +40,7 @@ extern NSString * const kAudioDeviceUID;
extern NSString * const kAudioDeviceName;
extern NSString * const kAudioDeviceInputsCount;
extern NSString * const kAudioDeviceOutputsCount;
+extern NSString * const kAudioDeviceBuiltIn;
// Growl notification names.
extern NSString * const kGrowlNotificationIncomingCall;
View
@@ -60,6 +60,7 @@
NSString * const kAudioDeviceName = @"AudioDeviceName";
NSString * const kAudioDeviceInputsCount = @"AudioDeviceInputsCount";
NSString * const kAudioDeviceOutputsCount = @"AudioDeviceOutputsCount";
+NSString * const kAudioDeviceBuiltIn = @"AudioDeviceBuiltIn";
NSString * const kGrowlNotificationIncomingCall = @"Incoming Call";
NSString * const kGrowlNotificationCallEnded = @"Call Ended";
@@ -440,6 +441,17 @@ - (void)updateAudioDevices {
CFRelease(nameStringRef);
}
+ // Get transport type and set built-in flag.
+ UInt32 transportType = 0;
+ address.mSelector = kAudioDevicePropertyTransportType;
+ address.mScope = kAudioObjectPropertyScopeGlobal;
+ address.mScope = kAudioObjectPropertyElementMaster;
+ size = sizeof(UInt32);
+ err = AudioObjectGetPropertyData(devices[loopCount], &address, 0, NULL, &size, &transportType);
+ if (err == noErr) {
+ deviceDict[kAudioDeviceBuiltIn] = transportType == kAudioDeviceTransportTypeBuiltIn ? @YES : @NO;
+ }
+
// Get number of input channels.
size = 0;
NSUInteger inputChannelsCount = 0;
@@ -467,7 +479,9 @@ - (void)updateAudioDevices {
// Get number of output channels.
size = 0;
NSUInteger outputChannelsCount = 0;
+ address.mSelector = kAudioDevicePropertyStreamConfiguration;
address.mScope = kAudioObjectPropertyScopeOutput;
+ address.mElement = 0;
err = AudioObjectGetPropertyDataSize(devices[loopCount], &address, 0, NULL, &size);
if((err == noErr) && (size != 0)) {
theBufferList = (AudioBufferList *)malloc(size);
@@ -509,82 +523,58 @@ - (void)updateAudioDevices {
}
// Selects appropriate sound IO from the list of available audio devices.
-// Searches the defaults database for devices selected earlier. If not found, uses first matched. Selects sound IO in
-// the user agent if there are active calls.
+//
+// Searches the defaults database for devices selected earlier. If not found, uses first built-in matched. If that is
+// not found, uses the first device.
+//
+// Selects sound IO in the user agent if there are active calls.
- (void)selectSoundIO {
NSArray *devices = [self audioDevices];
NSInteger newSoundInput, newSoundOutput, newRingtoneOutput;
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- NSDictionary *deviceDict;
- NSInteger i;
-
- // Lookup devices records in the defaults.
-
newSoundInput = newSoundOutput = newRingtoneOutput = NSNotFound;
-
+ NSInteger firstBuiltInInput, firstBuiltInOutput;
+ firstBuiltInInput = firstBuiltInOutput = NSNotFound;
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *lastSoundInputString = [defaults stringForKey:kSoundInput];
- if (lastSoundInputString != nil) {
- for (i = 0; i < [devices count]; ++i) {
- deviceDict = [devices objectAtIndex:i];
- if ([[deviceDict objectForKey:kAudioDeviceName] isEqual:lastSoundInputString] &&
- [[deviceDict objectForKey:kAudioDeviceInputsCount] integerValue] > 0) {
+ NSString *lastSoundOutputString = [defaults stringForKey:kSoundOutput];
+ NSString *lastRingtoneOutputString = [defaults stringForKey:kRingtoneOutput];
+ NSUInteger deviceCount = [devices count];
+
+ for (NSUInteger i = 0; i < deviceCount; i++) {
+ if (newSoundInput != NSNotFound && newSoundOutput != NSNotFound && newRingtoneOutput != NSNotFound &&
+ firstBuiltInInput != NSNotFound && firstBuiltInOutput != NSNotFound) {
+ break;
+ }
+ NSDictionary *device = devices[i];
+ if ([device[kAudioDeviceInputsCount] unsignedIntegerValue] > 0) {
+ if (newSoundInput == NSNotFound && [device[kAudioDeviceName] isEqualToString:lastSoundInputString]) {
newSoundInput = i;
- break;
+ }
+ if (firstBuiltInInput == NSNotFound && [device[kAudioDeviceBuiltIn] boolValue]) {
+ firstBuiltInInput = i;
}
}
- }
-
- NSString *lastSoundOutputString = [defaults stringForKey:kSoundOutput];
- if (lastSoundOutputString != nil) {
- for (i = 0; i < [devices count]; ++i) {
- deviceDict = [devices objectAtIndex:i];
- if ([[deviceDict objectForKey:kAudioDeviceName] isEqual:lastSoundOutputString] &&
- [[deviceDict objectForKey:kAudioDeviceOutputsCount] integerValue] > 0) {
+ if ([device[kAudioDeviceOutputsCount] unsignedIntegerValue] > 0) {
+ if (newSoundOutput == NSNotFound && [device[kAudioDeviceName] isEqualToString:lastSoundOutputString]) {
newSoundOutput = i;
- break;
}
- }
- }
-
- NSString *lastRingtoneOutputString = [defaults stringForKey:kRingtoneOutput];
- if (lastRingtoneOutputString != nil) {
- for (i = 0; i < [devices count]; ++i) {
- deviceDict = [devices objectAtIndex:i];
- if ([[deviceDict objectForKey:kAudioDeviceName] isEqual:lastRingtoneOutputString] &&
- [[deviceDict objectForKey:kAudioDeviceOutputsCount] integerValue] > 0) {
+ if (newRingtoneOutput == NSNotFound && [device[kAudioDeviceName] isEqualToString:lastRingtoneOutputString]) {
newRingtoneOutput = i;
- break;
+ }
+ if (firstBuiltInOutput == NSNotFound && [device[kAudioDeviceBuiltIn] boolValue]) {
+ firstBuiltInOutput = i;
}
}
}
- // If still not found, select first matched.
-
if (newSoundInput == NSNotFound) {
- for (i = 0; i < [devices count]; ++i) {
- if ([[[devices objectAtIndex:i] objectForKey:kAudioDeviceInputsCount] integerValue] > 0) {
- newSoundInput = i;
- break;
- }
- }
+ newSoundInput = (firstBuiltInInput != NSNotFound) ? firstBuiltInInput : 0;
}
-
if (newSoundOutput == NSNotFound) {
- for (i = 0; i < [devices count]; ++i) {
- if ([[[devices objectAtIndex:i] objectForKey:kAudioDeviceOutputsCount] integerValue] > 0) {
- newSoundOutput = i;
- break;
- }
- }
+ newSoundOutput = (firstBuiltInOutput != NSNotFound) ? firstBuiltInOutput : 0;
}
-
if (newRingtoneOutput == NSNotFound) {
- for (i = 0; i < [devices count]; ++i) {
- if ([[[devices objectAtIndex:i] objectForKey:kAudioDeviceOutputsCount] integerValue] > 0) {
- newRingtoneOutput = i;
- break;
- }
- }
+ newRingtoneOutput = (firstBuiltInOutput != NSNotFound) ? firstBuiltInOutput : 0;
}
[self setSoundInputDeviceIndex:newSoundInput];
@@ -77,6 +77,8 @@ - (void)updateAudioDevices {
NSMenu *soundInputMenu = [[NSMenu alloc] init];
NSMenu *soundOutputMenu = [[NSMenu alloc] init];
NSMenu *ringtoneOutputMenu = [[NSMenu alloc] init];
+ NSString *firstBuiltInInputName = nil;
+ NSString *firstBuiltInOutputName = nil;
for (NSUInteger i = 0; i < [audioDevices count]; ++i) {
NSDictionary *deviceDict = [audioDevices objectAtIndex:i];
@@ -87,11 +89,19 @@ - (void)updateAudioDevices {
if ([[deviceDict objectForKey:kAudioDeviceInputsCount] integerValue] > 0) {
[soundInputMenu addItem:[aMenuItem copy]];
+
+ if ([deviceDict[kAudioDeviceBuiltIn] boolValue] && firstBuiltInInputName == nil) {
+ firstBuiltInInputName = [aMenuItem title];
+ }
}
if ([[deviceDict objectForKey:kAudioDeviceOutputsCount] integerValue] > 0) {
[soundOutputMenu addItem:[aMenuItem copy]];
[ringtoneOutputMenu addItem:[aMenuItem copy]];
+
+ if ([deviceDict[kAudioDeviceBuiltIn] boolValue] && firstBuiltInOutputName == nil) {
+ firstBuiltInOutputName = [aMenuItem title];
+ }
}
}
@@ -104,20 +114,32 @@ - (void)updateAudioDevices {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ NSString *soundInputItemTitle = nil;
NSString *lastSoundInput = [defaults stringForKey:kSoundInput];
if (lastSoundInput != nil && [[self soundInputPopUp] itemWithTitle:lastSoundInput] != nil) {
- [[self soundInputPopUp] selectItemWithTitle:lastSoundInput];
+ soundInputItemTitle = lastSoundInput;
+ } else if (firstBuiltInInputName != nil) {
+ soundInputItemTitle = firstBuiltInInputName;
}
+ [[self soundInputPopUp] selectItemWithTitle:soundInputItemTitle];
+ NSString *soundOutputItemTitle = nil;
NSString *lastSoundOutput = [defaults stringForKey:kSoundOutput];
if (lastSoundOutput != nil && [[self soundOutputPopUp] itemWithTitle:lastSoundOutput] != nil) {
- [[self soundOutputPopUp] selectItemWithTitle:lastSoundOutput];
+ soundOutputItemTitle = lastSoundOutput;
+ } else if (firstBuiltInOutputName != nil) {
+ soundOutputItemTitle = firstBuiltInOutputName;
}
+ [[self soundOutputPopUp] selectItemWithTitle:soundOutputItemTitle];
+ NSString *ringtoneOutputItemTitle = nil;
NSString *lastRingtoneOutput = [defaults stringForKey:kRingtoneOutput];
if (lastRingtoneOutput != nil && [[self ringtoneOutputPopUp] itemWithTitle:lastRingtoneOutput] != nil) {
- [[self ringtoneOutputPopUp] selectItemWithTitle:lastRingtoneOutput];
+ ringtoneOutputItemTitle = lastRingtoneOutput;
+ } else if (firstBuiltInOutputName != nil) {
+ ringtoneOutputItemTitle = firstBuiltInOutputName;
}
+ [[self ringtoneOutputPopUp] selectItemWithTitle:ringtoneOutputItemTitle];
}
- (void)updateAvailableSounds {

0 comments on commit d31bf2b

Please sign in to comment.