diff --git a/native/app/Embedded/eqMac.driver/Contents/Info.plist b/native/app/Embedded/eqMac.driver/Contents/Info.plist
index 761c233..9cff9e1 100644
--- a/native/app/Embedded/eqMac.driver/Contents/Info.plist
+++ b/native/app/Embedded/eqMac.driver/Contents/Info.plist
@@ -7,7 +7,7 @@
com.bitgapp.eqmac.xpc
BuildMachineOSBuild
- 20A5354i
+ 19G2021
CFBundleDevelopmentRegion
en
CFBundleExecutable
@@ -45,17 +45,19 @@
DTCompiler
com.apple.compilers.llvm.clang.1_0
DTPlatformBuild
- 11E708
+ 12A7300
+ DTPlatformName
+ macosx
DTPlatformVersion
- GM
+ 10.15.6
DTSDKBuild
19G68
DTSDKName
macosx10.15
DTXcode
- 1160
+ 1201
DTXcodeBuild
- 11E708
+ 12A7300
LSMinimumSystemVersion
10.9
NSHumanReadableCopyright
diff --git a/native/app/Embedded/eqMac.driver/Contents/MacOS/eqMac b/native/app/Embedded/eqMac.driver/Contents/MacOS/eqMac
index 009b956..32f6651 100755
Binary files a/native/app/Embedded/eqMac.driver/Contents/MacOS/eqMac and b/native/app/Embedded/eqMac.driver/Contents/MacOS/eqMac differ
diff --git a/native/app/Source/Application.swift b/native/app/Source/Application.swift
index 0df1f61..300a1747 100644
--- a/native/app/Source/Application.swift
+++ b/native/app/Source/Application.swift
@@ -110,15 +110,27 @@ class Application {
}
private static func checkDriver (_ completion: @escaping() -> Void) {
- if !Driver.isInstalled {
- Alert.confirm(
- title: "The eqMac Audio Driver is not installed", message: "For unknown reason the Audio Driver needed for eqMac to work corrently is not installed. Please try re-installing eqMac from our website.", okText: "Re-install eqMac", cancelText: "Quit") { restart in
- if restart {
- NSWorkspace.shared.open(Constants.WEBSITE_URL)
- return
- } else {
- return self.quit()
+ if !Driver.isInstalled || Driver.isMismatched {
+ let isJustMismatched = Driver.isInstalled && Driver.isMismatched
+ let message = isJustMismatched ?
+ "For unknown reason the version of Audio Driver needed for eqMac to work corrently is not correct. Try restarting your computer and run eqMac again. In that doesn't work, try re-installing eqMac from our website."
+ : "For unknown reason the Audio Driver needed for eqMac to work corrently is not installed. Try restarting your computer and run eqMac again. In that doesn't work, try re-installing eqMac from our website."
+ let title = isJustMismatched ? "The eqMac Audio Driver is Outdated" : "The eqMac Audio Driver is not installed"
+ Alert.withButtons(
+ title: title,
+ message: message,
+ buttons: ["Restart Mac", "Re-install eqMac", "Quit"]
+ ) { buttonPressed in
+ Console.log(buttonPressed)
+ switch NSApplication.ModalResponse(buttonPressed) {
+ case .alertFirstButtonReturn:
+ self.restartMac()
+ break
+ case .alertSecondButtonReturn:
+ NSWorkspace.shared.open(Constants.WEBSITE_URL)
+ default: break
}
+ return self.quit()
}
} else {
completion()
diff --git a/native/app/Source/ApplicationDataBus.swift b/native/app/Source/ApplicationDataBus.swift
index 737be6b..3fcdcc2 100644
--- a/native/app/Source/ApplicationDataBus.swift
+++ b/native/app/Source/ApplicationDataBus.swift
@@ -24,7 +24,7 @@ class ApplicationDataBus: DataBus {
"name": host.localizedName as AnyObject,
"model": Sysctl.model as String,
"version": Bundle.main.infoDictionary?["CFBundleVersion"] as Any,
-// "driverVersion": Driver.bundledVersion
+ "driverVersion": Driver.installedVersion
]
}
diff --git a/native/app/Source/Audio/Outputs/Output.swift b/native/app/Source/Audio/Outputs/Output.swift
index c11d69b..5a74748 100644
--- a/native/app/Source/Audio/Outputs/Output.swift
+++ b/native/app/Source/Audio/Outputs/Output.swift
@@ -15,7 +15,10 @@ import AVFoundation
class Output {
static func isDeviceAllowed(_ device: AudioDevice) -> Bool {
- return device.transportType != nil && Constants.SUPPORTED_TRANSPORT_TYPES.contains(device.transportType!) && !device.isInputOnlyDevice()
+ return device.transportType != nil
+ && Constants.SUPPORTED_TRANSPORT_TYPES.contains(device.transportType!)
+ && !device.isInputOnlyDevice()
+ && !device.name.contains("CADefaultDeviceAggregate")
}
static func autoSelect (_ device: AudioDevice) -> Bool {
diff --git a/native/app/Source/Audio/Sources/System/Driver.swift b/native/app/Source/Audio/Sources/System/Driver.swift
index 74539b7..b63cd58 100644
--- a/native/app/Source/Audio/Sources/System/Driver.swift
+++ b/native/app/Source/Audio/Sources/System/Driver.swift
@@ -25,6 +25,7 @@ enum CustomProperties: String {
case kAudioDeviceCustomPropertyLatency = "cltc"
case kAudioDeviceCustomPropertySafetyOffset = "csfo"
case kAudioDeviceCustomPropertyShown = "shwn"
+ case kAudioDeviceCustomPropertyVersion = "vrsn"
}
class Driver {
@@ -55,13 +56,7 @@ class Driver {
static var bundledVersion: String {
return info["CFBundleVersion"] as! String
}
-//
-// static var isOutdated: Bool {
-// get {
-// return bundledVersion != lastInstalledVersion
-// }
-// }
-//
+
static var sampleRates: [Double] {
return [
8_000,
@@ -190,10 +185,10 @@ class Driver {
var size: UInt32 = UInt32(MemoryLayout.size)
- var shown = kCFBooleanFalse
+ var shownBool = kCFBooleanFalse
- checkErr(AudioObjectGetPropertyData(Driver.device!.id, &address, 0, nil, &size, &shown))
- return CFBooleanGetValue(shown!)
+ checkErr(AudioObjectGetPropertyData(Driver.device!.id, &address, 0, nil, &size, &shownBool))
+ return CFBooleanGetValue(shownBool!)
}
set {
if Driver.device == nil { return }
@@ -205,12 +200,32 @@ class Driver {
)
let size: UInt32 = UInt32(MemoryLayout.size)
- var shown: CFBoolean = newValue.cfBooleanValue
+ var shownBool: CFBoolean = newValue.cfBooleanValue
- checkErr(AudioObjectSetPropertyData(Driver.device!.id, &address, 0, nil, size, &shown))
+ checkErr(AudioObjectSetPropertyData(Driver.device!.id, &address, 0, nil, size, &shownBool))
}
}
+ static var installedVersion: String? {
+ if Driver.device == nil { return nil }
+ var address = AudioObjectPropertyAddress(
+ mSelector: getPropertySelectorFromString(CustomProperties.kAudioDeviceCustomPropertyVersion.rawValue),
+ mScope: kAudioObjectPropertyScopeGlobal,
+ mElement: kAudioObjectPropertyElementMaster
+ )
+
+ var size: UInt32 = UInt32(MemoryLayout.size)
+
+ var version: CFString? = nil
+
+ checkErr(AudioObjectGetPropertyData(Driver.device!.id, &address, 0, nil, &size, &version))
+ return version as String?
+ }
+
+ static var isMismatched: Bool {
+ return bundledVersion != installedVersion
+ }
+
static var hidden: Bool {
get { return !shown }
set { shown = !newValue }
diff --git a/native/app/Source/Helpers/Alert.swift b/native/app/Source/Helpers/Alert.swift
index 79c4989..0b4ad8e 100644
--- a/native/app/Source/Helpers/Alert.swift
+++ b/native/app/Source/Helpers/Alert.swift
@@ -25,11 +25,8 @@ class Alert {
cancelText: String = "Cancel",
callback: @escaping (Bool) -> Void
) {
- DispatchQueue.main.async {
- let alert = getAlert(title, message)
- alert.addButton(withTitle: okText)
- alert.addButton(withTitle: cancelText)
- let result = alert.runModal() == .alertFirstButtonReturn
+ withButtons(title: title, message: message, buttons: [okText, cancelText]) { buttonPressed in
+ let result = NSApplication.ModalResponse(buttonPressed) == .alertFirstButtonReturn
callback(result)
}
}
@@ -57,6 +54,23 @@ class Alert {
}
+ static func withButtons (
+ title: String,
+ message: String,
+ buttons: [String],
+ callback: @escaping (Int) -> Void
+ ) {
+ DispatchQueue.main.async {
+ let alert = getAlert(title, message)
+ for text in buttons {
+ alert.addButton(withTitle: text)
+ }
+ let result = alert.runModal()
+ callback(result.rawValue)
+ }
+
+ }
+
static private func getAlert (_ title: String, _ message: String) -> NSAlert {
let alert = NSAlert()
alert.messageText = title
diff --git a/native/driver/Source/EQM_Device.cpp b/native/driver/Source/EQM_Device.cpp
index 35faa2c..c2198c3 100644
--- a/native/driver/Source/EQM_Device.cpp
+++ b/native/driver/Source/EQM_Device.cpp
@@ -325,6 +325,7 @@ bool EQM_Device::Device_HasProperty(AudioObjectID inObjectID, pid_t inClientPID,
case kAudioDeviceCustomPropertyLatency:
case kAudioDeviceCustomPropertySafetyOffset:
case kAudioDeviceCustomPropertyShown:
+ case kAudioDeviceCustomPropertyVersion:
theAnswer = true;
break;
@@ -360,6 +361,7 @@ bool EQM_Device::Device_IsPropertySettable(AudioObjectID inObjectID, pid_t inCli
case kAudioObjectPropertyCustomPropertyInfoList:
case kAudioDeviceCustomPropertyDeviceAudibleState:
case kAudioDeviceCustomPropertyDeviceIsRunningSomewhereOtherThanEQMApp:
+ case kAudioDeviceCustomPropertyVersion:
theAnswer = false;
break;
@@ -457,7 +459,7 @@ UInt32 EQM_Device::Device_GetPropertyDataSize(AudioObjectID inObjectID, pid_t in
break;
case kAudioObjectPropertyCustomPropertyInfoList:
- theAnswer = sizeof(AudioServerPlugInCustomPropertyInfo) * 9;
+ theAnswer = sizeof(AudioServerPlugInCustomPropertyInfo) * 10;
break;
case kAudioDeviceCustomPropertyDeviceAudibleState:
@@ -495,6 +497,10 @@ UInt32 EQM_Device::Device_GetPropertyDataSize(AudioObjectID inObjectID, pid_t in
theAnswer = sizeof(CFBooleanRef);
break;
+ case kAudioDeviceCustomPropertyVersion:
+ theAnswer = sizeof(CFStringRef);
+ break;
+
default:
theAnswer = EQM_AbstractDevice::GetPropertyDataSize(inObjectID, inClientPID, inAddress, inQualifierDataSize, inQualifierData);
break;
@@ -910,9 +916,9 @@ void EQM_Device::Device_GetPropertyData(AudioObjectID inObjectID, pid_t inClient
theNumberItemsToFetch = inDataSize / sizeof(AudioServerPlugInCustomPropertyInfo);
// clamp it to the number of items we have
- if(theNumberItemsToFetch > 9)
+ if(theNumberItemsToFetch > 10)
{
- theNumberItemsToFetch = 9;
+ theNumberItemsToFetch = 10;
}
if(theNumberItemsToFetch > 0)
@@ -972,6 +978,13 @@ void EQM_Device::Device_GetPropertyData(AudioObjectID inObjectID, pid_t inClient
((AudioServerPlugInCustomPropertyInfo*)outData)[6].mQualifierDataType = kAudioServerPlugInCustomPropertyDataTypeNone;
}
+ if(theNumberItemsToFetch > 9)
+ {
+ ((AudioServerPlugInCustomPropertyInfo*)outData)[7].mSelector = kAudioDeviceCustomPropertyVersion;
+ ((AudioServerPlugInCustomPropertyInfo*)outData)[7].mPropertyDataType = kAudioServerPlugInCustomPropertyDataTypeCFString;
+ ((AudioServerPlugInCustomPropertyInfo*)outData)[7].mQualifierDataType = kAudioServerPlugInCustomPropertyDataTypeNone;
+ }
+
outDataSize = theNumberItemsToFetch * sizeof(AudioServerPlugInCustomPropertyInfo);
break;
@@ -1006,6 +1019,23 @@ void EQM_Device::Device_GetPropertyData(AudioObjectID inObjectID, pid_t inClient
}
break;
+ case kAudioDeviceCustomPropertyVersion:
+ {
+ ThrowIf(inDataSize < sizeof(CFStringRef), CAException(kAudioHardwareBadPropertySizeError), "EQM_Device::Device_GetPropertyData: not enough space for the return value of kAudioDeviceCustomPropertyVersion for the device");
+ CAMutex::Locker theStateLocker(mStateMutex);
+
+ CFStringRef version = CFCopyDescription(
+ CFBundleGetValueForInfoDictionaryKey(
+ CFBundleGetBundleWithIdentifier(CFSTR(kEQMDriverBundleID)),
+ kCFBundleVersionKey
+ )
+ );
+// DebugMsg("EQM_LOG: %s", CFStringGetCStringPtr(CFCopyDescription(CFBundleGetMainBundle()), kCFStringEncodingMacRoman));
+ *reinterpret_cast(outData) = version;
+ outDataSize = sizeof(CFStringRef);
+ }
+ break;
+
case kAudioDeviceCustomPropertyDeviceIsRunningSomewhereOtherThanEQMApp:
ThrowIf(inDataSize < sizeof(CFBooleanRef), CAException(kAudioHardwareBadPropertySizeError), "EQM_Device::Device_GetPropertyData: not enough space for the return value of kAudioDeviceCustomPropertyDeviceIsRunningSomewhereOtherThanEQMApp for the device");
*reinterpret_cast(outData) = mClients.ClientsOtherThanEQMAppRunningIO() ? kCFBooleanTrue : kCFBooleanFalse;
diff --git a/native/driver/Source/EQM_Types.h b/native/driver/Source/EQM_Types.h
index 532fb24..02ad775 100644
--- a/native/driver/Source/EQM_Types.h
+++ b/native/driver/Source/EQM_Types.h
@@ -106,7 +106,8 @@ enum
kAudioDeviceCustomPropertyEnabledOutputControls = 'bgct',
kAudioDeviceCustomPropertyLatency = 'cltc',
kAudioDeviceCustomPropertySafetyOffset = 'csfo',
- kAudioDeviceCustomPropertyShown = 'shwn'
+ kAudioDeviceCustomPropertyShown = 'shwn',
+ kAudioDeviceCustomPropertyVersion = 'vrsn'
};
// The number of silent/audible frames before EQMDriver will change kAudioDeviceCustomPropertyDeviceAudibleState