Skip to content

Commit 9ee6ea6

Browse files
committed
added mutex lock to driver io, tabbed design for EQ types and other minor changes
1 parent 2424b9c commit 9ee6ea6

14 files changed

Lines changed: 253 additions & 69 deletions

File tree

native/app/Source/Extensions/AudioDevice.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,9 @@ extension AudioDevice {
199199

200200
static public var builtInOutputDevice: AudioDevice {
201201
get {
202-
let device: AudioDevice? = AudioDevice.allOutputDevices().first( where: { (device) -> Bool in
202+
let outputDevices = AudioDevice.allOutputDevices()
203+
Console.log(outputDevices)
204+
let device: AudioDevice? = outputDevices.first( where: { (device) -> Bool in
203205
device.transportType == TransportType.builtIn
204206
})
205207
return device!

native/app/eqMac.xcodeproj/project.pbxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1032,7 +1032,7 @@
10321032
SWIFT_COMPILATION_MODE = singlefile;
10331033
SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR) $(PROJECT_DIR)/Source/Vendor";
10341034
SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/Source/Helpers/ExceptionCatcher.h";
1035-
SWIFT_OPTIMIZATION_LEVEL = "-O";
1035+
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
10361036
SWIFT_VERSION = 4.2;
10371037
USER_HEADER_SEARCH_PATHS = "";
10381038
};

native/driver/Driver.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
7838E35F26C8A4190039D466 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7838E35E26C8A4190039D466 /* Utilities.swift */; };
1919
7838E36426C9CC430039D466 /* ArrayExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7838E36326C9CC430039D466 /* ArrayExtensions.swift */; };
2020
7838E36726C9CFA10039D466 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7838E36626C9CFA10039D466 /* Helpers.swift */; };
21+
784763FA26EF760B00CF9394 /* EQMClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 784763F926EF760B00CF9394 /* EQMClient.swift */; };
22+
784763FD26EF764B00CF9394 /* VolumeConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 784763FC26EF764B00CF9394 /* VolumeConverter.swift */; };
2123
78A8049E26C4866D0021981C /* EQMDriverBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 78A8049D26C4866D0021981C /* EQMDriverBridge.m */; };
2224
78A804D726C4903E0021981C /* EQMDriver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78A804D626C4903E0021981C /* EQMDriver.swift */; };
2325
78A804DD26C563860021981C /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78A804DC26C563860021981C /* Constants.swift */; };
@@ -42,6 +44,8 @@
4244
7838E35E26C8A4190039D466 /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Utilities.swift; path = ../shared/Utilities.swift; sourceTree = "<group>"; };
4345
7838E36326C9CC430039D466 /* ArrayExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ArrayExtensions.swift; path = ../shared/ArrayExtensions.swift; sourceTree = "<group>"; };
4446
7838E36626C9CFA10039D466 /* Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = "<group>"; };
47+
784763F926EF760B00CF9394 /* EQMClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = EQMClient.swift; path = ../shared/EQMClient.swift; sourceTree = "<group>"; };
48+
784763FC26EF764B00CF9394 /* VolumeConverter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = VolumeConverter.swift; path = ../shared/VolumeConverter.swift; sourceTree = "<group>"; };
4549
78A8049D26C4866D0021981C /* EQMDriverBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EQMDriverBridge.m; sourceTree = "<group>"; };
4650
78A804A026C486820021981C /* EQMDriverBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EQMDriverBridge.h; sourceTree = "<group>"; };
4751
78A804D526C4903E0021981C /* EQMDriver-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "EQMDriver-Bridging-Header.h"; sourceTree = "<group>"; };
@@ -123,6 +127,8 @@
123127
7838E34E26C897560039D466 /* SharedConstants.swift */,
124128
7838E35026C897560039D466 /* StringExtensions.swift */,
125129
7838E35E26C8A4190039D466 /* Utilities.swift */,
130+
784763F926EF760B00CF9394 /* EQMClient.swift */,
131+
784763FC26EF764B00CF9394 /* VolumeConverter.swift */,
126132
);
127133
name = Shared;
128134
sourceTree = "<group>";
@@ -247,6 +253,7 @@
247253
files = (
248254
78A8049E26C4866D0021981C /* EQMDriverBridge.m in Sources */,
249255
7838E35826C898D60039D466 /* EQMStream.swift in Sources */,
256+
784763FD26EF764B00CF9394 /* VolumeConverter.swift in Sources */,
250257
78A804D726C4903E0021981C /* EQMDriver.swift in Sources */,
251258
7838E36726C9CFA10039D466 /* Helpers.swift in Sources */,
252259
7838E35426C897560039D466 /* StringExtensions.swift in Sources */,
@@ -261,6 +268,7 @@
261268
7838E35B26C898F30039D466 /* EQMControl.swift in Sources */,
262269
78A804DD26C563860021981C /* Constants.swift in Sources */,
263270
781FD6D126DADCE7006CAAEA /* EQMClients.swift in Sources */,
271+
784763FA26EF760B00CF9394 /* EQMClient.swift in Sources */,
264272
7838E35526C897560039D466 /* NumericTypesConversions.swift in Sources */,
265273
);
266274
runOnlyForDeploymentPostprocessing = 0;

native/driver/Source/EQMClients.swift

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,38 +13,42 @@ class EQMClients {
1313
static var clients: [UInt32: EQMClient] = [:]
1414

1515
static func add (_ client: EQMClient) {
16-
clients[client.mClientID] = client
16+
clients[client.clientId] = client
1717
}
1818

1919
static func remove (_ client: EQMClient) {
20-
clients.removeValue(forKey: client.mClientID)
20+
clients.removeValue(forKey: client.clientId)
2121
}
2222

2323
static func get (by clientId: UInt32) -> EQMClient? {
2424
return clients[clientId]
2525
}
2626

2727
static func get (by processId: pid_t) -> EQMClient? {
28-
return clients.values.first { $0.mProcessID == processId }
28+
return clients.values.first { $0.processId == processId }
2929
}
3030

31-
static func get (by bundleId: String) -> EQMClient? {
32-
return clients.values.first { client in
31+
static func get (by bundleId: String) -> [EQMClient] {
32+
return clients.values.filter { client in
3333
return client.bundleId == bundleId
3434
}
3535
}
36-
}
3736

38-
class EQMClient {
39-
var mClientID: UInt32
40-
var mProcessID: pid_t
41-
var mIsNativeEndian: DarwinBoolean
42-
var bundleId: String?
43-
44-
init (from clientInfo: AudioServerPlugInClientInfo) {
45-
mClientID = clientInfo.mClientID
46-
mProcessID = clientInfo.mProcessID
47-
mIsNativeEndian = clientInfo.mIsNativeEndian
48-
bundleId = clientInfo.mBundleID?.takeUnretainedValue() as String?
37+
static func get (by client: EQMClient) -> EQMClient? {
38+
if let byClient = get(by: client.clientId) {
39+
return byClient
40+
}
41+
42+
if let byProcessId = get(by: client.processId) {
43+
return byProcessId
44+
}
45+
46+
if let bundleId = client.bundleId {
47+
let bundles = get(by: bundleId)
48+
return bundles[0]
49+
}
50+
51+
return nil
4952
}
5053
}
54+

native/driver/Source/EQMControl.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ class EQMControl: EQMObject {
171171
default: return 0
172172
}
173173
})()
174-
return .float32(Volume.toScalar(volume))
174+
return .float32(VolumeConverter.toScalar(volume))
175175
case kAudioLevelControlPropertyDecibelValue:
176176
// This returns the dB value of the control.
177177
// Note that we need to take the state lock to examine the value.
@@ -181,7 +181,7 @@ class EQMControl: EQMObject {
181181
default: return 0
182182
}
183183
})()
184-
return .float32(Volume.toDecibel(volume))
184+
return .float32(VolumeConverter.toDecibel(volume))
185185
case kAudioLevelControlPropertyDecibelRange:
186186
// This returns the dB range of the control.
187187
return .valueRange(
@@ -198,7 +198,7 @@ class EQMControl: EQMObject {
198198

199199
scalar = clamp(value: scalar, min: 0, max: 1)
200200

201-
let decibel = Volume.toDecibel(Volume.fromScalar(scalar))
201+
let decibel = VolumeConverter.toDecibel(VolumeConverter.fromScalar(scalar))
202202

203203
return .float32(decibel)
204204
case kAudioLevelControlPropertyConvertDecibelsToScalar:
@@ -210,7 +210,7 @@ class EQMControl: EQMObject {
210210

211211
decibel = clamp(value: decibel, min: kMinVolumeDB, max: kMaxVolumeDB)
212212

213-
let scalar = Volume.toScalar(Volume.fromDecibel(decibel))
213+
let scalar = VolumeConverter.toScalar(VolumeConverter.fromDecibel(decibel))
214214

215215
return .float32(scalar)
216216
default: return nil
@@ -310,7 +310,7 @@ class EQMControl: EQMObject {
310310
// value changes, it implies that the dB value changed too.
311311
let scalar = data.load(as: Float32.self)
312312

313-
var newVolume = Volume.fromScalar(scalar)
313+
var newVolume = VolumeConverter.fromScalar(scalar)
314314
newVolume = clamp(value: newVolume, min: 0.0, max: 1.0)
315315

316316
if volume != newVolume {
@@ -341,7 +341,7 @@ class EQMControl: EQMObject {
341341
var decibel = data.load(as: Float32.self)
342342
decibel = clamp(value: decibel, min: kMinVolumeDB, max: kMaxVolumeDB)
343343

344-
var newVolume = Volume.fromDecibel(decibel)
344+
var newVolume = VolumeConverter.fromDecibel(decibel)
345345
newVolume = clamp(value: newVolume, min: 0.0, max: 1.0)
346346

347347
if volume != newVolume {

native/driver/Source/EQMDevice.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class EQMDevice: EQMObject {
2121
static var anchorHostTime: UInt64 = 0
2222
static var anchorSampleTime: UInt64 = 0
2323
static var timestampCount: UInt64 = 0
24+
static let ioMutex = Mutex()
2425

2526
static let ringBufferSize: UInt32 = 16384
2627
static var ringBuffer = UnsafeMutablePointer<Float32>.allocate(capacity: Int(ringBufferSize * kChannelCount))
@@ -523,6 +524,9 @@ class EQMDevice: EQMObject {
523524
}
524525

525526
static func getZeroTimeStamp (outSampleTime: UnsafeMutablePointer<Float64>, outHostTime: UnsafeMutablePointer<UInt64>, outSeed: UnsafeMutablePointer<UInt64>) -> OSStatus {
527+
528+
ioMutex.lock()
529+
526530
// get the current host time
527531
let currentHostTime = mach_absolute_time()
528532

@@ -539,11 +543,15 @@ class EQMDevice: EQMObject {
539543
outHostTime.pointee = anchorHostTime + timestampCount * UInt64(hostTicksPerRingBuffer)
540544
outSeed.pointee = 1
541545

546+
ioMutex.unlock()
547+
542548
return noErr
543549
}
544550

545551
static func doIO (clientID: UInt32, operationID: UInt32, sample: UnsafeMutablePointer<Float32>, cycleInfo: AudioServerPlugInIOCycleInfo, frameSize: UInt32) -> OSStatus {
546552

553+
ioMutex.lock()
554+
547555
switch operationID {
548556
// Store
549557
case AudioServerPlugInIOOperation.writeMix.rawValue:
@@ -599,6 +607,8 @@ class EQMDevice: EQMObject {
599607
default: break
600608
}
601609

610+
ioMutex.unlock()
611+
602612
return noErr
603613
}
604614
}

native/driver/Source/EQMDriver.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ import Atomics
1818
static private var _interfacePtr: UnsafeMutablePointer<AudioServerPlugInDriverInterface>?
1919

2020
static var refCounter = ManagedAtomic<UInt32>(0)
21-
2221
@objc public static var ref: AudioServerPlugInDriverRef?
22+
23+
static var mutex = Mutex()
2324

2425
@objc
2526
public static func create (allocator: CFAllocator!, requestedTypeUUID: CFUUID!) -> UnsafeMutableRawPointer? {
@@ -125,4 +126,16 @@ import Atomics
125126
theHostClockFrequency *= 1000000000.0
126127
hostTicksPerFrame = theHostClockFrequency / EQMDevice.sampleRate
127128
}
129+
130+
static func propertiesUpdated (objectId: AudioObjectID, changedProperties: [AudioObjectPropertyAddress]) {
131+
guard let host = host, changedProperties.count > 0 else {
132+
return
133+
}
134+
_ = host.pointee.PropertiesChanged(
135+
host,
136+
objectId,
137+
UInt32(changedProperties.count),
138+
changedProperties
139+
)
140+
}
128141
}

native/driver/Source/EQMInterface.swift

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ func EQM_AddDeviceClient (inDriver: AudioServerPlugInDriverRef, inDeviceObjectID
107107
// successfully.
108108
guard EQMDriver.validateDriver(inDriver) else { return kAudioHardwareBadObjectError }
109109

110+
EQMDriver.mutex.lock()
110111
EQMClients.add(EQMClient(from: inClientInfo.pointee))
112+
EQMDriver.mutex.unlock()
111113

112114
return noErr
113115
}
@@ -119,7 +121,9 @@ func EQM_RemoveDeviceClient (inDriver: AudioServerPlugInDriverRef, inDeviceObjec
119121
// successfully.
120122
guard EQMDriver.validateDriver(inDriver) else { return kAudioHardwareBadObjectError }
121123

124+
EQMDriver.mutex.lock()
122125
EQMClients.remove(EQMClient(from: inClientInfo.pointee))
126+
EQMDriver.mutex.unlock()
123127

124128
return noErr
125129
}
@@ -148,10 +152,13 @@ func EQM_PerformDeviceConfigurationChange (
148152
guard EQMDriver.validateDriver(inDriver) else { return kAudioHardwareBadObjectError }
149153
// log("Invoked EQM_PerformDeviceConfigurationChange()")
150154
if !kEQMDeviceSupportedSampleRates.contains(where: { UInt64($0) == inChangeAction }) { return kAudioHardwareBadObjectError }
155+
156+
EQMDriver.mutex.lock()
151157

152158
EQMDevice.sampleRate = Float64(inChangeAction)
153159
EQMDriver.calculateHostTicksPerFrame()
154-
160+
161+
EQMDriver.mutex.unlock()
155162
// log("EQM_PerformDeviceConfigurationChange() - EQMDevice.sampleRate = \(EQMDevice.sampleRate) | hostTicksPerFrame = \(String(describing: EQMDriver.hostTicksPerFrame))")
156163

157164
return noErr
@@ -321,14 +328,7 @@ func EQM_SetPropertyData (
321328
changedProperties: &changedProperties
322329
)
323330

324-
if changedProperties.count > 0 {
325-
_ = EQMDriver.host!.pointee.PropertiesChanged(
326-
EQMDriver.host!,
327-
inObjectID,
328-
UInt32(changedProperties.count),
329-
changedProperties
330-
)
331-
}
331+
EQMDriver.propertiesUpdated(objectId: inObjectID, changedProperties: changedProperties)
332332

333333
log("\(EQMDriver.getEQMObjectClassName(from: inObjectID)).setPropertyData(\(propertyName(address.mSelector)), \(scopeName(address.mScope))) - Status: \(status) - Changed Properties: \(changedProperties)")
334334

@@ -347,7 +347,9 @@ func EQM_StartIO (inDriver: AudioServerPlugInDriverRef, inDeviceObjectID: AudioO
347347
// increment the counter.
348348
guard EQMDriver.validateDriver(inDriver) else { return kAudioHardwareBadObjectError }
349349

350+
EQMDriver.mutex.lock()
350351
let status = EQMDevice.startIO()
352+
EQMDriver.mutex.unlock()
351353

352354
return status
353355
}
@@ -357,8 +359,10 @@ func EQM_StopIO (inDriver: AudioServerPlugInDriverRef, inDeviceObjectID: AudioOb
357359
// once all clients have stopped.
358360
guard EQMDriver.validateDriver(inDriver) else { return kAudioHardwareBadObjectError }
359361

362+
EQMDriver.mutex.lock()
360363
let status = EQMDevice.stopIO()
361-
364+
EQMDriver.mutex.unlock()
365+
362366
return status
363367
}
364368

native/driver/Source/Helpers.swift

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,34 @@
99
import Foundation
1010
import CoreAudio.AudioServerPlugIn
1111

12-
class Volume {
13-
static func toDecibel (_ volume: Float32) -> Float32 {
14-
if (volume <= powf(10.0, kMinVolumeDB / 20.0)) {
15-
return kMinVolumeDB
16-
} else {
17-
return 20.0 * log10f(volume)
12+
class Mutex {
13+
var mutex = pthread_mutex_t()
14+
15+
init () {
16+
var attributes = pthread_mutexattr_t()
17+
guard pthread_mutexattr_init(&attributes) == 0 else {
18+
preconditionFailure()
1819
}
19-
}
2020

21-
static func fromDecibel (_ decibel: Float32) -> Float32 {
22-
if (decibel <= kMinVolumeDB) {
23-
return 0.0
24-
} else {
25-
return powf(10.0, decibel / 20.0)
21+
pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_NORMAL)
22+
23+
guard pthread_mutex_init(&mutex, &attributes) == 0 else {
24+
preconditionFailure()
2625
}
26+
27+
pthread_mutexattr_destroy(&attributes)
28+
}
29+
30+
func lock () {
31+
pthread_mutex_lock(&mutex)
2732
}
2833

29-
static func toScalar (_ volume: Float32) -> Float32 {
30-
let decibel = toDecibel(volume);
31-
return (decibel - kMinVolumeDB) / (kMaxVolumeDB - kMinVolumeDB);
34+
func unlock () {
35+
pthread_mutex_unlock(&mutex)
3236
}
3337

34-
static func fromScalar (_ scalar: Float32) -> Float32 {
35-
let decibel = scalar * (kMaxVolumeDB - kMinVolumeDB) + kMinVolumeDB
36-
return fromDecibel(decibel)
38+
deinit {
39+
pthread_mutex_destroy(&mutex)
3740
}
3841
}
3942

0 commit comments

Comments
 (0)