From efbabf5cb30de0013fe3b67cb7206de602f1dc84 Mon Sep 17 00:00:00 2001 From: Gustl22 Date: Thu, 17 Aug 2023 17:05:08 +0200 Subject: [PATCH] feat: create, dispose & reuse event stream (#1609) # Description Currently if an event stream for a `playerId` is requested, a new stream was created, conflicting with the existing one. Now the `createEventStream`, `disposeEventStream` and `getEventStream` methods allow more control of handling the stream and also reusing the existing stream on `getEventStream`. --- .../lib/src/audioplayers_platform.dart | 33 ++++++++++++++--- .../test/audioplayers_platform_test.dart | 35 +++++++++++++------ .../test/global_platform_test.dart | 20 +++++------ .../test/util.dart | 11 ++++++ 4 files changed, 73 insertions(+), 26 deletions(-) diff --git a/packages/audioplayers_platform_interface/lib/src/audioplayers_platform.dart b/packages/audioplayers_platform_interface/lib/src/audioplayers_platform.dart index ad1c0db09..ffe6cf75f 100644 --- a/packages/audioplayers_platform_interface/lib/src/audioplayers_platform.dart +++ b/packages/audioplayers_platform_interface/lib/src/audioplayers_platform.dart @@ -12,6 +12,18 @@ import 'package:flutter/services.dart'; class AudioplayersPlatform extends AudioplayersPlatformInterface with MethodChannelAudioplayersPlatform, EventChannelAudioplayersPlatform { AudioplayersPlatform(); + + @override + Future create(String playerId) async { + await super.create(playerId); + createEventStream(playerId); + } + + @override + Future dispose(String playerId) async { + await super.dispose(playerId); + disposeEventStream(playerId); + } } mixin MethodChannelAudioplayersPlatform @@ -212,12 +224,12 @@ mixin MethodChannelAudioplayersPlatform mixin EventChannelAudioplayersPlatform implements EventChannelAudioplayersPlatformInterface { - @override - Stream getEventStream(String playerId) { - // Only can be used after have created the event channel on the native side. - final eventChannel = EventChannel('xyz.luan/audioplayers/events/$playerId'); + final Map> streams = {}; - return eventChannel.receiveBroadcastStream().map( + // Only can be used after have created the event channel on the native side. + void createEventStream(String playerId) { + final eventChannel = EventChannel('xyz.luan/audioplayers/events/$playerId'); + streams[playerId] = eventChannel.receiveBroadcastStream().map( (dynamic event) { final map = event as Map; final eventType = map.getString('event'); @@ -260,4 +272,15 @@ mixin EventChannelAudioplayersPlatform }, ); } + + void disposeEventStream(String playerId) { + if (streams.containsKey(playerId)) { + streams.remove(playerId); + } + } + + @override + Stream getEventStream(String playerId) { + return streams[playerId]!; + } } diff --git a/packages/audioplayers_platform_interface/test/audioplayers_platform_test.dart b/packages/audioplayers_platform_interface/test/audioplayers_platform_test.dart index 96ad0cb9a..9ab68da2c 100644 --- a/packages/audioplayers_platform_interface/test/audioplayers_platform_test.dart +++ b/packages/audioplayers_platform_interface/test/audioplayers_platform_test.dart @@ -13,14 +13,6 @@ void main() { final platform = AudioplayersPlatformInterface.instance; final methodCalls = []; - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler( - const MethodChannel('xyz.luan/audioplayers'), - (MethodCall methodCall) async { - methodCalls.add(methodCall); - return 0; - }, - ); void clear() { methodCalls.clear(); @@ -36,7 +28,24 @@ void main() { } group('AudioPlayers Method Channel', () { - setUp(clear); + setUp(() { + clear(); + + createNativeMethodHandler( + channel: 'xyz.luan/audioplayers', + handler: (MethodCall methodCall) async { + methodCalls.add(methodCall); + switch (methodCall.method) { + case 'getDuration': + return 0; + case 'getCurrentPosition': + return 0; + default: + return null; + } + }, + ); + }); test('#setSource', () async { await platform.setSourceUrl('p1', 'internet.com/file.mp3'); @@ -83,14 +92,17 @@ void main() { group('AudioPlayers Event Channel', () { test('emit events', () async { final eventController = StreamController.broadcast(); + const playerId = 'p1'; createNativeEventStream( - channel: 'xyz.luan/audioplayers/events/p1', + channel: 'xyz.luan/audioplayers/events/$playerId', byteDataStream: eventController.stream, ); + await platform.create(playerId); + expect( - platform.getEventStream('p1'), + platform.getEventStream(playerId), emitsInOrder([ const AudioEvent( eventType: AudioEventType.duration, @@ -140,6 +152,7 @@ void main() { } await eventController.close(); + await platform.dispose(playerId); }); }); } diff --git a/packages/audioplayers_platform_interface/test/global_platform_test.dart b/packages/audioplayers_platform_interface/test/global_platform_test.dart index 06ce14e63..c0c588af8 100644 --- a/packages/audioplayers_platform_interface/test/global_platform_test.dart +++ b/packages/audioplayers_platform_interface/test/global_platform_test.dart @@ -30,16 +30,16 @@ void main() { } group('Global Method Channel', () { - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler( - const MethodChannel('xyz.luan/audioplayers.global'), - (MethodCall methodCall) async { - methodCalls.add(methodCall); - return 1; - }, - ); - - setUp(clear); + setUp(() { + clear(); + createNativeMethodHandler( + channel: 'xyz.luan/audioplayers.global', + handler: (MethodCall methodCall) async { + methodCalls.add(methodCall); + return null; + }, + ); + }); test('set AudioContext for Windows', () async { debugDefaultTargetPlatformOverride = TargetPlatform.windows; diff --git a/packages/audioplayers_platform_interface/test/util.dart b/packages/audioplayers_platform_interface/test/util.dart index 105ca6536..f3ac1ceb3 100644 --- a/packages/audioplayers_platform_interface/test/util.dart +++ b/packages/audioplayers_platform_interface/test/util.dart @@ -7,6 +7,17 @@ extension MethodCallParser on MethodCall { Map get args => arguments as Map; } +void createNativeMethodHandler({ + required String channel, + Future? Function(MethodCall message)? handler, +}) { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler( + MethodChannel(channel), + handler, + ); +} + // See: https://github.com/flutter/packages/blob/12609a2abbb0a30b9d32af7b73599bfc834e609e/packages/video_player/video_player_android/test/android_video_player_test.dart#L270 void createNativeEventStream({ required String channel,