Improve recorder device change handling
This commit is contained in:
parent
6ab3705123
commit
2944e4ce5c
@ -29,32 +29,6 @@ class AudioEngineRecorder: ObservableObject {
|
||||
// Callback to notify parent class of runtime recording errors
|
||||
var onRecordingError: ((Error) -> Void)?
|
||||
|
||||
init() {
|
||||
setupNotifications()
|
||||
}
|
||||
|
||||
private func setupNotifications() {
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(handleConfigurationChange),
|
||||
name: .AVAudioEngineConfigurationChange,
|
||||
object: nil
|
||||
)
|
||||
}
|
||||
|
||||
@objc private func handleConfigurationChange(notification: Notification) {
|
||||
Task { @MainActor in
|
||||
guard isRecording else { return }
|
||||
logger.info("⚠️ AVAudioEngine configuration change detected (e.g. sample rate change). Restarting engine...")
|
||||
do {
|
||||
try restartRecordingPreservingFile()
|
||||
} catch {
|
||||
logger.error("Failed to recover from configuration change: \(error.localizedDescription)")
|
||||
stopRecording()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func startRecording(toOutputFile url: URL) throws {
|
||||
stopRecording()
|
||||
|
||||
@ -131,52 +105,6 @@ class AudioEngineRecorder: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
private func restartRecordingPreservingFile() throws {
|
||||
if let input = inputNode {
|
||||
input.removeTap(onBus: tapBusNumber)
|
||||
}
|
||||
audioEngine?.stop()
|
||||
|
||||
// Drain queue to prevent old-format buffers racing with new converter
|
||||
audioProcessingQueue.sync { }
|
||||
|
||||
let engine = AVAudioEngine()
|
||||
audioEngine = engine
|
||||
|
||||
let input = engine.inputNode
|
||||
inputNode = input
|
||||
|
||||
let inputFormat = input.outputFormat(forBus: tapBusNumber)
|
||||
logger.info("Restarting with new input format - Sample Rate: \(inputFormat.sampleRate)")
|
||||
|
||||
guard inputFormat.sampleRate > 0 else {
|
||||
throw AudioEngineRecorderError.invalidInputFormat
|
||||
}
|
||||
|
||||
guard let format = recordingFormat else {
|
||||
throw AudioEngineRecorderError.invalidRecordingFormat
|
||||
}
|
||||
|
||||
guard let newConverter = AVAudioConverter(from: inputFormat, to: format) else {
|
||||
throw AudioEngineRecorderError.failedToCreateConverter
|
||||
}
|
||||
|
||||
fileWriteLock.lock()
|
||||
converter = newConverter
|
||||
fileWriteLock.unlock()
|
||||
|
||||
input.installTap(onBus: tapBusNumber, bufferSize: tapBufferSize, format: inputFormat) { [weak self] (buffer, time) in
|
||||
guard let self = self else { return }
|
||||
self.audioProcessingQueue.async {
|
||||
self.processAudioBuffer(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
engine.prepare()
|
||||
try engine.start()
|
||||
logger.info("✅ Audio engine successfully restarted after configuration change")
|
||||
}
|
||||
|
||||
func stopRecording() {
|
||||
guard isRecording else {
|
||||
return
|
||||
@ -307,10 +235,6 @@ class AudioEngineRecorder: ObservableObject {
|
||||
var currentRecordingURL: URL? {
|
||||
return recordingURL
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Error Types
|
||||
|
||||
@ -36,20 +36,15 @@ class Recorder: NSObject, ObservableObject {
|
||||
|
||||
private func handleDeviceChange() async {
|
||||
guard !isReconfiguring else { return }
|
||||
|
||||
isReconfiguring = true
|
||||
|
||||
if recorder != nil {
|
||||
let currentURL = recorder?.currentRecordingURL
|
||||
stopRecording()
|
||||
|
||||
if let url = currentURL {
|
||||
do {
|
||||
try await startRecording(toOutputFile: url)
|
||||
} catch {
|
||||
logger.error("❌ Failed to restart recording after device change: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
|
||||
try? await Task.sleep(nanoseconds: 200_000_000)
|
||||
|
||||
await MainActor.run {
|
||||
NotificationCenter.default.post(name: .toggleMiniRecorder, object: nil)
|
||||
}
|
||||
|
||||
isReconfiguring = false
|
||||
}
|
||||
|
||||
|
||||
@ -526,8 +526,6 @@ class AudioDeviceManager: ObservableObject {
|
||||
}
|
||||
|
||||
private func notifyDeviceChange() {
|
||||
if !isRecordingActive {
|
||||
NotificationCenter.default.post(name: NSNotification.Name("AudioDeviceChanged"), object: nil)
|
||||
}
|
||||
NotificationCenter.default.post(name: NSNotification.Name("AudioDeviceChanged"), object: nil)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user