diff --git a/.changes/fix-audio-visualizer-missing-plugin-exception b/.changes/fix-audio-visualizer-missing-plugin-exception new file mode 100644 index 000000000..d0e10a5c8 --- /dev/null +++ b/.changes/fix-audio-visualizer-missing-plugin-exception @@ -0,0 +1 @@ +patch type="fixed" "MissingPluginException when stopping audio visualizer on Android/iOS" diff --git a/lib/src/track/audio_visualizer_native.dart b/lib/src/track/audio_visualizer_native.dart index a7ed37692..926049c45 100644 --- a/lib/src/track/audio_visualizer_native.dart +++ b/lib/src/track/audio_visualizer_native.dart @@ -53,11 +53,13 @@ class AudioVisualizerNative extends AudioVisualizer { return; } - await Native.stopVisualizer(mediaStreamTrack.id!, visualizerId: visualizerId); - + // Cancel subscription before native stop, otherwise the native + // StreamHandler is already removed and cancel throws MissingPluginException. await _streamSubscription?.cancel(); _streamSubscription = null; _eventChannel = null; + + await Native.stopVisualizer(mediaStreamTrack.id!, visualizerId: visualizerId); } } diff --git a/shared_swift/LiveKitPlugin.swift b/shared_swift/LiveKitPlugin.swift index 8d11d9ef3..a2d8d8639 100644 --- a/shared_swift/LiveKitPlugin.swift +++ b/shared_swift/LiveKitPlugin.swift @@ -201,6 +201,7 @@ public class LiveKitPlugin: NSObject, FlutterPlugin { } for processors in audioProcessors.values { + processors.visualizers[visualizerId]?.stop() processors.visualizers.removeValue(forKey: visualizerId) } diff --git a/shared_swift/Visualizer.swift b/shared_swift/Visualizer.swift index c856ec5ca..19c6bd95d 100644 --- a/shared_swift/Visualizer.swift +++ b/shared_swift/Visualizer.swift @@ -69,8 +69,13 @@ public class Visualizer: NSObject, RTCAudioRenderer, FlutterStreamHandler { channel?.setStreamHandler(self) } - deinit { + public func stop() { _track?.remove(audioRenderer: self) + channel?.setStreamHandler(nil) + } + + deinit { + stop() } public func render(pcmBuffer: AVAudioPCMBuffer) {