Question:
When implementing simultaneous video capture and audio processing in an iOS app, does the order of starting these components matter, or can they be initiated in any sequence?
I have an actor responsible for initiating video capture using the setCaptureMode function. In this actor, I also call startAudioEngine to begin the audio engine and register a resultObserver. While the audio engine starts successfully, I notice that the resultObserver is not invoked when startAudioEngine is called synchronously. However, it works correctly when I wrap the call in a Task.
Could you please explain why the synchronous call to startAudioEngine might be blocking the invocation of the resultObserver? What would be the best practice for ensuring both components work effectively together? Additionally, if I were to avoid using Task, what approach would be required? Lastly, is the startAudioEngine effective from the start time of the video capture (00:00)?
Platform: Xcode 16, Swift 6, iOS 18
References:
- Classifying Sounds in an Audio Stream – In my case, the analyzeAudio() method is not invoked.
- Setting Up a Capture Session – Here, the focus is on video capture.
- Classifying Sounds in an Audio File
Code Snippet: (For further details. setVideoCaptureMode()
surfaces the problem.)
// ensures all operations happen off of the `@MainActor`.
actor CaptureService {
...
nonisolated private let resultsObserver1 = ResultsObserver1()
...
private func setUpSession() throws { .. }
...
setVideoCaptureMode() throws {
captureSession.beginConfiguration()
defer { captureSession.commitConfiguration() }
/* -- Works fine (analyseAudio is printed)
Task {
self.resultsObserver1.startAudioEngine()
}
*/
self.resultsObserver1.startAudioEngine() // Does not work - analyzeAudio not printed
captureSession.sessionPreset = .high
try addOutput(movieCapture.output)
if isHDRVideoEnabled {
setHDRVideoEnabled(true)
}
updateCaptureCapabilities()
}
Hey @Blume,
- Why does the audioEngine stop within the configuration block?
Good question, AVCaptureDevice and AVAudioEngine both have access to the same underlying audio capture hardware. It appears that, for whatever reason, this particular pattern is creating a conflict of sorts. You should file a bug report for this issue using Feedback Assistant.
- What specifically makes the “working case” (when called under Task) function correctly, as opposed to the “non-working case” (when called synchronously)?
The Task introduces asynchronous execution. If you add logging to beginConfiguration, commitConfiguration, and inside your Task, you will see that the startAudioEngine (in the Task) does not execute until after the call to commitConfiguration. In contrast, without the Task, startAudioEngine executes between beginConfiguration and commitConfiguration calls (which appears to be problematic).
Best regards,
Greg