Post

Replies

Boosts

Views

Activity

AVAudioEngine stops running when changing input to AirPods
I have trouble understanding AVAudioEngine's behaviour when switching audio input sources. Expected Behaviour When switching input sources, AVAudioEngine's inputNode should adopt the new input source seamlessly. Actual Behaviour When switching from AirPods to the iPhone speaker, AVAudioEngine stops working. No audio is routed through anymore. Querying engine.isRunning still returns true. When subsequently switching back to AirPods, it still isn't working, but now engine.isRunning returns false. Stopping and starting the engine on a route change does not help. Neither does calling reset(). Disconnecting and reconnecting the input node does not help, either. The only thing that reliably helps is discarding the whole engine and creating a new one. OS This is on iOS 14, beta 5. I can't test this on previous versions I'm afraid; I only have one device around. Code to Reproduce Here is a minimum code example. Create a simple app project in Xcode (doesn't matter whether you choose SwiftUI or Storyboard), and give it permissions to access the microphone in Info.plist. Create the following file Conductor.swift: import AVFoundation class Conductor { 		static let shared: Conductor = Conductor() 		 		private let _engine = AVAudioEngine? 		 		init() { 				// Session 				let session = AVAudioSession.sharedInstance() 				try? session.setActive(false) 				try! session.setCategory(.playAndRecord, options: [.defaultToSpeaker, 																													 .allowBluetooth, 																													 .allowAirPlay]) 				try! session.setActive(true) 				_engine.connect(_engine.inputNode, to: _engine.mainMixerNode, format: nil) 				_engine.prepare() 		} 		func start() { _engine.start() } } And in AppDelegate, call: Conductor.shared.start() This example will route the input straight to the output. If you don't have headphones, it will trigger a feedback loop. Question What am I missing here? Is this expected behaviour? If so, it does not seem to be documented anywhere.
2
1
2.6k
Feb ’22
UIViewPropertyAnimator and application lifecycle
I'm trying to use UIViewPropertyAnimator to animate a progress bar. The progress bar displays the playback time of an audio file. Approach 0) Given a progress bar and a playback duration let progressBar: UIViewSubclass = ProgressBar(...) let duration: TimeInterval = ... 1) Create an animator from start to finish on the progress bar: let animator = UIViewPropertyAnimator(duration: duration, curve: .linear) animator.pausesOnCompletion = true progressBar.setProgress(0) animator.addAnimations { [weak self] in 		guard let self = self else { return } 		self.setProgress(1) } animator.pauseAnimation() 2) When a file is played, start it with: let startTime: TimeInterval = ... animator.fractionComplete = startTime / duration animator.continueAnimation(withTimingParameters: nil, durationFactor: 0) This works well. It is CPU efficient, and, with a bit of extra code, supports more things, such as dragging the progress bar to a different playback position. Problem: App/View Lifecycle Unfortunately, this approach breaks when sending the app into the background and reopening it. After that, animator.continueAnimation() doesn't work anymore, and the animation is stuck at the finish state. Here is an example project that reproduces this problem: https://github.com/JanNash/AnimationTest/tree/apple-developer-forum-660767 The main logic is in the ViewController: https://github.com/JanNash/AnimationTest/blob/apple-developer-forum-660767/AnimationTest/ViewController.swift In this project, a simple progress bar is animated after a button press, and the button press restarts the animation from the beginning. After the app was sent to the background and restored to the foreground, the animation doesn't work anymore. Question How do I fix this problem? Is there maybe something inherent to animations that I didn't understand? I could, for example, imagine that the render server loses the animation when the app goes into background, and that as such, animations always have to be recreated when the app - or even a view - enters the foreground. But it would be good to know whether this just requires a simple code change to fix, or whether I have misunderstood something conceptually.
2
0
2.9k
Jan ’22
AVAudioEngine stops running when changing input to AirPods
I have trouble understanding AVAudioEngine's behaviour when switching audio input sources. Expected Behaviour When switching input sources, AVAudioEngine's inputNode should adopt the new input source seamlessly. Actual Behaviour When switching from AirPods to the iPhone speaker, AVAudioEngine stops working. No audio is routed through anymore. Querying engine.isRunning still returns true. When subsequently switching back to AirPods, it still isn't working, but now engine.isRunning returns false. Stopping and starting the engine on a route change does not help. Neither does calling reset(). Disconnecting and reconnecting the input node does not help, either. The only thing that reliably helps is discarding the whole engine and creating a new one. OS This is on iOS 14, beta 5. I can't test this on previous versions I'm afraid; I only have one device around. Code to Reproduce Here is a minimum code example. Create a simple app project in Xcode (doesn't matter whether you choose SwiftUI or Storyboard), and give it permissions to access the microphone in Info.plist. Create the following file Conductor.swift: import AVFoundation class Conductor { 		static let shared: Conductor = Conductor() 		 		private let _engine = AVAudioEngine? 		 		init() { 				// Session 				let session = AVAudioSession.sharedInstance() 				try? session.setActive(false) 				try! session.setCategory(.playAndRecord, options: [.defaultToSpeaker, 																													 .allowBluetooth, 																													 .allowAirPlay]) 				try! session.setActive(true) 				_engine.connect(_engine.inputNode, to: _engine.mainMixerNode, format: nil) 				_engine.prepare() 		} 		func start() { _engine.start() } } And in AppDelegate, call: Conductor.shared.start() This example will route the input straight to the output. If you don't have headphones, it will trigger a feedback loop. Question What am I missing here? Is this expected behaviour? If so, it does not seem to be documented anywhere.
Replies
2
Boosts
1
Views
2.6k
Activity
Feb ’22
UIViewPropertyAnimator and application lifecycle
I'm trying to use UIViewPropertyAnimator to animate a progress bar. The progress bar displays the playback time of an audio file. Approach 0) Given a progress bar and a playback duration let progressBar: UIViewSubclass = ProgressBar(...) let duration: TimeInterval = ... 1) Create an animator from start to finish on the progress bar: let animator = UIViewPropertyAnimator(duration: duration, curve: .linear) animator.pausesOnCompletion = true progressBar.setProgress(0) animator.addAnimations { [weak self] in 		guard let self = self else { return } 		self.setProgress(1) } animator.pauseAnimation() 2) When a file is played, start it with: let startTime: TimeInterval = ... animator.fractionComplete = startTime / duration animator.continueAnimation(withTimingParameters: nil, durationFactor: 0) This works well. It is CPU efficient, and, with a bit of extra code, supports more things, such as dragging the progress bar to a different playback position. Problem: App/View Lifecycle Unfortunately, this approach breaks when sending the app into the background and reopening it. After that, animator.continueAnimation() doesn't work anymore, and the animation is stuck at the finish state. Here is an example project that reproduces this problem: https://github.com/JanNash/AnimationTest/tree/apple-developer-forum-660767 The main logic is in the ViewController: https://github.com/JanNash/AnimationTest/blob/apple-developer-forum-660767/AnimationTest/ViewController.swift In this project, a simple progress bar is animated after a button press, and the button press restarts the animation from the beginning. After the app was sent to the background and restored to the foreground, the animation doesn't work anymore. Question How do I fix this problem? Is there maybe something inherent to animations that I didn't understand? I could, for example, imagine that the render server loses the animation when the app goes into background, and that as such, animations always have to be recreated when the app - or even a view - enters the foreground. But it would be good to know whether this just requires a simple code change to fix, or whether I have misunderstood something conceptually.
Replies
2
Boosts
0
Views
2.9k
Activity
Jan ’22