The callback of AVAudioSession.requestRecordPermission may not be called on main thread, so the timer in start method may doesn't start, due to absence of runloop.
The solution:
AVAudioSession.sharedInstance().requestRecordPermission() { allowed in
DispatchQueue.main.async {
if allowed {
self.start(url)
} else {
self.update(nil)
}
}
}