Skip to content

Commit 7059b3e

Browse files
committed
fixed dangling engine references
1 parent b97774f commit 7059b3e

12 files changed

Lines changed: 163 additions & 201 deletions

File tree

native/app/Source/Application.swift

Lines changed: 42 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,12 @@ enum VolumeChangeDirection: String {
2525
}
2626

2727
class Application {
28-
// Engine
29-
static var sources: Sources!
30-
static var effects: Effects!
31-
static var volume: Volume!
32-
static var engine: Engine!
33-
static var output: Output!
34-
static var selectedDevice: AudioDevice!
28+
static var engine: Engine?
29+
static var output: Output?
30+
static var engineCreated = EmitterKit.Event<Void>()
31+
static var outputCreated = EmitterKit.Event<Void>()
32+
33+
static var selectedDevice: AudioDevice?
3534
static var selectedDeviceIsAliveListener: EventListener<AudioDevice>?
3635
static var selectedDeviceVolumeChangedListener: EventListener<AudioDevice>?
3736
static var selectedDeviceSampleRateChangedListener: EventListener<AudioDevice>?
@@ -191,7 +190,7 @@ class Application {
191190
}
192191
} else if (list.removed.count > 0) {
193192

194-
let currentDeviceRemoved = list.removed.contains(where: { $0.id == selectedDevice.id })
193+
let currentDeviceRemoved = list.removed.contains(where: { $0.id == selectedDevice?.id })
195194

196195
if (currentDeviceRemoved) {
197196
removeEngines()
@@ -207,7 +206,7 @@ class Application {
207206
AudioDeviceEvents.on(.isJackConnectedChanged) { device in
208207
let connected = device.isJackConnected(direction: .playback)
209208
Console.log("isJackConnectedChanged", device, connected)
210-
if (connected == true && device.id != selectedDevice.id) {
209+
if (connected == true && device.id != selectedDevice?.id) {
211210
selectOutput(device: device)
212211
}
213212
}
@@ -254,7 +253,7 @@ class Application {
254253
static func startPassthrough () {
255254
selectedDevice = AudioDevice.currentOutputDevice
256255

257-
if (selectedDevice.id == Driver.device!.id) {
256+
if (selectedDevice!.id == Driver.device!.id) {
258257
selectOutput(device: AudioDevice.builtInOutputDevice) // TODO: Replace with a known device from a stack
259258
return
260259
}
@@ -267,7 +266,7 @@ class Application {
267266
Application.dispatchAction(VolumeAction.setBalance(Application.store.state.effects.volume.balance, false))
268267

269268
Driver.device!.setVirtualMasterVolume(volume > 1 ? 1 : Float32(volume), direction: .playback)
270-
Driver.latency = selectedDevice.latency(direction: .playback) ?? 0 // Set driver latency to mimic device
269+
Driver.latency = selectedDevice!.latency(direction: .playback) ?? 0 // Set driver latency to mimic device
271270
// Driver.safetyOffset = selectedDevice.safetyOffset(direction: .playback) ?? 0 // Set driver latency to mimic device
272271
self.matchDriverSampleRateToOutput()
273272

@@ -278,61 +277,58 @@ class Application {
278277
AudioDevice.currentOutputDevice = Driver.device!
279278
// TODO: Figure out a better way
280279
Utilities.delay(1000) {
281-
self.createAudioPipeline()
280+
createAudioPipeline()
282281
}
283282
}
284283

285284
private static func matchDriverSampleRateToOutput () {
286-
let outputSampleRate = selectedDevice.actualSampleRate()!
285+
let outputSampleRate = selectedDevice!.actualSampleRate()!
287286
let driverSampleRates = Driver.sampleRates
288287
let closestSampleRate = driverSampleRates.min( by: { abs($0 - outputSampleRate) < abs($1 - outputSampleRate) } )!
289288
Driver.device!.setNominalSampleRate(closestSampleRate)
290289
}
291290

292291
private static func createAudioPipeline () {
293-
_ = Sources() { sources in
294-
self.sources = sources
295-
effects = Effects()
296-
engine = Engine(
297-
sources: sources,
298-
effects: effects
299-
)
300-
volume = Volume()
301-
output = Output(device: selectedDevice, engine: engine, volume: volume)
302-
292+
engine = nil
293+
engine = Engine {
294+
engineCreated.emit()
295+
output = nil
296+
output = Output(device: selectedDevice!)
297+
outputCreated.emit()
298+
303299
selectedDeviceIsAliveListener = AudioDeviceEvents.on(
304300
.isAliveChanged,
305-
onDevice: selectedDevice,
301+
onDevice: selectedDevice!,
306302
retain: false
307303
) {
308304
// If device that we are sending audio to goes offline we need to stop and switch to a different device
309-
if (selectedDevice.isAlive() == false) {
305+
if (selectedDevice!.isAlive() == false) {
310306
Console.log("Current device dies so switching to built it")
311307
selectOutput(device: AudioDevice.builtInOutputDevice) // TODO: Replace with a known device from stack
312308
}
313309
}
314310

315311
selectedDeviceSampleRateChangedListener = AudioDeviceEvents.on(
316312
.nominalSampleRateChanged,
317-
onDevice: selectedDevice,
313+
onDevice: selectedDevice!,
318314
retain: false
319315
) {
320316
stopRemoveEngines()
321-
Utilities.delay(100) {
317+
Utilities.delay(1000) {
322318
// need a delay, because emitter should finish it's work at first
323319
try! AudioDeviceEvents.recreateEventEmitters([.isAliveChanged, .volumeChanged, .nominalSampleRateChanged])
324-
self.setupDriverDeviceEvents()
325-
self.matchDriverSampleRateToOutput()
320+
setupDriverDeviceEvents()
321+
matchDriverSampleRateToOutput()
326322
createAudioPipeline()
327323
}
328324
}
329325

330326
selectedDeviceVolumeChangedListener = AudioDeviceEvents.on(
331327
.volumeChanged,
332-
onDevice: selectedDevice,
328+
onDevice: selectedDevice!,
333329
retain: false
334330
) {
335-
let deviceVolume = selectedDevice.virtualMasterVolume(direction: .playback)!
331+
let deviceVolume = selectedDevice!.virtualMasterVolume(direction: .playback)!
336332
let driverVolume = Driver.device!.virtualMasterVolume(direction: .playback)!
337333
if (deviceVolume != driverVolume) {
338334
Driver.device!.setVirtualMasterVolume(deviceVolume, direction: .playback)
@@ -371,7 +367,7 @@ class Application {
371367

372368
static var overrideNextVolumeEvent = false
373369
static func volumeChangeButtonPressed (direction: VolumeChangeDirection, quarterStep: Bool = false) {
374-
if volume == nil || engine == nil {
370+
if engine == nil || output == nil {
375371
return
376372
}
377373
if direction == .UP {
@@ -380,7 +376,7 @@ class Application {
380376
ignoreNextDriverMuteEvent = false
381377
}
382378
}
383-
let gain = volume.gain
379+
let gain = output!.volume.gain
384380
if (gain >= 1) {
385381
if direction == .DOWN {
386382
overrideNextVolumeEvent = true
@@ -419,34 +415,29 @@ class Application {
419415
ignoreNextDriverMuteEvent = false
420416
}
421417

422-
private static func killEngine () {
423-
engine = nil
424-
}
425-
426418
private static func switchBackToLastKnownDevice () {
427419
// If the active equalizer global gain hass been lowered we need to equalize the volume to avoid blowing people ears our
428-
if (effects != nil && effects.equalizers.active.globalGain < 0) {
429-
if (selectedDevice.canSetVirtualMasterVolume(direction: .playback)) {
430-
var decibels = selectedDevice.virtualMasterVolumeInDecibels(direction: .playback)!
431-
decibels = decibels + Float(self.effects.equalizers.active.globalGain)
432-
selectedDevice.setVirtualMasterVolume(selectedDevice.decibelsToScalar(volume: decibels, channel: 1, direction: .playback)!, direction: .playback)
433-
} else if (selectedDevice.canSetVolume(channel: 1, direction: .playback)) {
434-
var decibels = selectedDevice.volumeInDecibels(channel: 1, direction: .playback)!
435-
decibels = decibels + Float(self.effects.equalizers.active.globalGain)
436-
for channel in 1...selectedDevice.channels(direction: .playback) {
437-
selectedDevice.setVolume(selectedDevice.decibelsToScalar(volume: decibels, channel: channel, direction: .playback)!, channel: channel, direction: .playback)
420+
if (engine == nil || selectedDevice == nil) { return }
421+
if (engine!.effects != nil && engine!.effects.equalizers.active.globalGain < 0) {
422+
if (selectedDevice!.canSetVirtualMasterVolume(direction: .playback)) {
423+
var decibels = selectedDevice!.virtualMasterVolumeInDecibels(direction: .playback)!
424+
decibels = decibels + Float(engine!.effects.equalizers.active.globalGain)
425+
selectedDevice!.setVirtualMasterVolume(selectedDevice!.decibelsToScalar(volume: decibels, channel: 1, direction: .playback)!, direction: .playback)
426+
} else if (selectedDevice!.canSetVolume(channel: 1, direction: .playback)) {
427+
var decibels = selectedDevice!.volumeInDecibels(channel: 1, direction: .playback)!
428+
decibels = decibels + Float(engine!.effects.equalizers.active.globalGain)
429+
for channel in 1...selectedDevice!.channels(direction: .playback) {
430+
selectedDevice!.setVolume(selectedDevice!.decibelsToScalar(volume: decibels, channel: channel, direction: .playback)!, channel: channel, direction: .playback)
438431
}
439432
}
440433
}
441-
if (selectedDevice != nil) {
442-
AudioDevice.currentOutputDevice = selectedDevice
443-
}
434+
AudioDevice.currentOutputDevice = selectedDevice!
444435
}
445436

446437
static func stopSave () {
447438
stopListeners()
448-
stopRemoveEngines()
449439
switchBackToLastKnownDevice()
440+
stopRemoveEngines()
450441
Storage.synchronize()
451442
}
452443

native/app/Source/Audio/Effects/Effect.swift

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import AVFoundation
1313
class Effect {
1414
var node: AVAudioNode!
1515
var enabledChanged = Event<Bool>()
16-
var engine: Engine?
16+
1717
var name: String {
1818
return String(describing: self)
1919
}
@@ -33,12 +33,4 @@ class Effect {
3333
}
3434
}
3535

36-
func wasAttachedTo (engine: Engine) {
37-
self.engine = engine
38-
}
39-
40-
func wasDetachedFrom (engine: Engine) {
41-
self.engine = nil
42-
}
43-
4436
}

native/app/Source/Audio/Engine.swift

Lines changed: 45 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ import AMCoreAudio
1212
import AVFoundation
1313
import Foundation
1414
import AudioToolbox
15+
import EmitterKit
1516

1617
class Engine {
17-
private var eventListeners: [Any] = []
18-
let sources: Sources
19-
let effects: Effects
18+
private var equalizersTypeChangedListener: EventListener<EqualizerType>?
19+
20+
let sources: Sources!
21+
let effects: Effects!
2022
var attachedEqualizer: Equalizer?
2123

2224
var format: AVAudioFormat!
@@ -27,17 +29,21 @@ class Engine {
2729
// Middleware
2830
var buffer: CircularBuffer<Float>!
2931

30-
init (sources: Sources, effects: Effects) {
32+
init (_ completion: @escaping () -> Void) {
3133
Console.log("Creating Engine")
32-
self.sources = sources
33-
self.effects = effects
34-
setupEngine()
35-
setupSink()
36-
setupBuffer()
37-
attach()
38-
chain()
39-
setupListeners()
40-
start()
34+
self.effects = Effects()
35+
self.sources = Sources()
36+
Sources.getInputPermission() {
37+
self.sources.initializeSystem()
38+
self.setupEngine()
39+
self.setupSink()
40+
self.setupBuffer()
41+
self.attach()
42+
self.chain()
43+
self.setupListeners()
44+
self.start()
45+
completion()
46+
}
4147
}
4248

4349
private func setupEngine () {
@@ -59,8 +65,9 @@ class Engine {
5965
}
6066

6167
private func attachSource () {
62-
sources.system.setInputDevice(engine: engine)
68+
engine.setInputDevice(sources.system.device)
6369
format = engine.inputNode.inputFormat(forBus: 0)
70+
Console.log("Set Input Engine format to: \(format.description)")
6471
}
6572

6673
private func attachEffects () {
@@ -70,13 +77,11 @@ class Engine {
7077
private func attachEqualizer () {
7178
engine.attach(effects.equalizers.active.eq)
7279
attachedEqualizer = effects.equalizers.active
73-
effects.equalizers.active.wasAttachedTo(engine: self)
7480
}
7581

7682
private func detachEqualizer () {
7783
if attachedEqualizer != nil {
7884
engine.detach(attachedEqualizer!.eq)
79-
attachedEqualizer?.wasDetachedFrom(engine: self)
8085
attachedEqualizer = nil
8186
}
8287
}
@@ -94,7 +99,7 @@ class Engine {
9499
}
95100

96101
private func chainSourceToEffects () {
97-
Console.log("Chaining Source to Volume")
102+
Console.log("Chaining Source to Effects")
98103
engine.connect(engine.inputNode, to: effects.equalizers.active.eq, format: format)
99104
}
100105

@@ -111,45 +116,47 @@ class Engine {
111116
let lastAVUnit = effects.equalizers.active.eq as AVAudioUnit
112117
if let err = checkErr(AudioUnitAddRenderNotify(lastAVUnit.audioUnit,
113118
renderCallback,
114-
UnsafeMutableRawPointer(Unmanaged<Engine>.passUnretained(self).toOpaque()))) {
119+
nil)) {
115120
Console.log(err)
116121
return
117122
}
118123
}
119124

120125
let renderCallback: AURenderCallback = {
121126
(inRefCon: UnsafeMutableRawPointer,
122-
ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>,
123-
inTimeStamp: UnsafePointer<AudioTimeStamp>,
124-
inBusNumber: UInt32,
125-
inNumberFrames: UInt32,
126-
ioData: UnsafeMutablePointer<AudioBufferList>?) -> OSStatus in
127+
ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>,
128+
inTimeStamp: UnsafePointer<AudioTimeStamp>,
129+
inBusNumber: UInt32,
130+
inNumberFrames: UInt32,
131+
ioData: UnsafeMutablePointer<AudioBufferList>?) -> OSStatus in
127132

128133
if ioActionFlags.pointee == AudioUnitRenderActionFlags.unitRenderAction_PostRender {
129-
let engine = Unmanaged<Engine>.fromOpaque(inRefCon).takeUnretainedValue()
134+
if Application.engine == nil { return noErr }
130135

131136
let sampleTime = inTimeStamp.pointee.mSampleTime
132137

133138
let start = sampleTime.int64Value
134139
let end = start + Int64(inNumberFrames)
135-
if engine.buffer.write(from: ioData!, start: start, end: end) != .noError {
140+
if Application.engine!.buffer.write(from: ioData!, start: start, end: end) != .noError {
136141
return OSStatus()
137142
}
138-
engine.lastSampleTime = sampleTime
143+
Application.engine!.lastSampleTime = sampleTime
139144
}
140145

141146
return noErr
142147
}
143148

144149
private func setupListeners () {
145-
eventListeners.append(Equalizers.typeChanged.on { _ in
146-
self.stop()
147-
Utilities.delay(100) {
148-
self.reattachEqualizer()
149-
self.chain()
150-
self.start()
150+
equalizersTypeChangedListener = Equalizers.typeChanged.on { [weak self] _ in
151+
if self == nil { return }
152+
self!.stop()
153+
Utilities.delay(100) { [weak self] in
154+
if self == nil { return }
155+
self!.reattachEqualizer()
156+
self!.chain()
157+
self!.start()
151158
}
152-
})
159+
}
153160
}
154161

155162
private func start () {
@@ -164,5 +171,9 @@ class Engine {
164171
func stop () {
165172
self.engine.stop()
166173
}
167-
174+
175+
deinit {
176+
equalizersTypeChangedListener?.isListening = false
177+
equalizersTypeChangedListener = nil
178+
}
168179
}

0 commit comments

Comments
 (0)