diff --git a/CHANGELOG.md b/CHANGELOG.md index 3beb9051..dd827741 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## 2.1.0 (#unreleased) - Feature [#468](https://github.com/SimformSolutionsPvtLtd/audio_waveforms/pull/468) - Add macOS support +- Fixed [#487](https://github.com/SimformSolutionsPvtLtd/audio_waveforms/issues/487) - iOS crash `nullptr == Tap()` when starting bytes streaming with a stale/leaked input tap ## 2.0.2 diff --git a/ios/Classes/RecorderBytesStreamEngine.swift b/ios/Classes/RecorderBytesStreamEngine.swift index 68841c73..be34c6c6 100644 --- a/ios/Classes/RecorderBytesStreamEngine.swift +++ b/ios/Classes/RecorderBytesStreamEngine.swift @@ -21,6 +21,17 @@ class RecorderBytesStreamEngine { func attach(result: @escaping FlutterResult, sampleRate: Int) { let inputNode = audioEngine.inputNode + + // Reset any previous engine/tap state before installing a new tap. + // Installing a tap on a bus that already has one throws a fatal + // `nullptr == Tap()` exception (see issue #487). This also cleans up + // a tap leaked when a prior `audioEngine.start()` failed. + if audioEngine.isRunning { + audioEngine.stop() + } + inputNode.removeTap(onBus: 0) + totalFrames = 0 + inputNode.installTap(onBus: 0, bufferSize: 1024, format: nil) { (buffer, time) in if self.paused { return @@ -40,6 +51,9 @@ class RecorderBytesStreamEngine { do { try audioEngine.start() } catch { + // Remove the tap so a failed start doesn't leak it onto the bus, + // which would crash the next `attach` with `nullptr == Tap()`. + inputNode.removeTap(onBus: 0) result(FlutterError(code: Constants.audioWaveforms, message: "Error starting Audio Engine", details: error.localizedDescription)) } }