From 277bfd045f89e3f1037291aa2feda616957b14c7 Mon Sep 17 00:00:00 2001 From: Gustl22 Date: Tue, 20 Dec 2022 23:43:57 +0100 Subject: [PATCH 1/6] feat: set source and get source --- packages/audioplayers/lib/src/audioplayer.dart | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/audioplayers/lib/src/audioplayer.dart b/packages/audioplayers/lib/src/audioplayer.dart index c63db8350..6a2bf41fe 100644 --- a/packages/audioplayers/lib/src/audioplayer.dart +++ b/packages/audioplayers/lib/src/audioplayer.dart @@ -1,4 +1,5 @@ import 'dart:async'; + // TODO(gustl22): remove when upgrading min Flutter version to >=3.3.0 // ignore: unnecessary_import import 'dart:typed_data'; @@ -29,6 +30,10 @@ class AudioPlayer { PlayerState get state => _playerState; + Source? _source; + + Source? get source => _source; + set state(PlayerState state) { if (!_playerStateController.isClosed) { _playerStateController.add(state); @@ -94,6 +99,9 @@ class AudioPlayer { AudioPlayer({String? playerId}) : playerId = playerId ?? _uuid.v4() { _onPlayerCompleteStreamSubscription = onPlayerComplete.listen((_) { state = PlayerState.completed; + if (releaseMode == ReleaseMode.release) { + _source = null; + } }); } @@ -164,6 +172,7 @@ class AudioPlayer { Future release() async { await _platform.release(playerId); state = PlayerState.stopped; + _source = null; } /// Moves the cursor to the desired position. @@ -217,6 +226,7 @@ class AudioPlayer { /// The resources will start being fetched or buffered as soon as you call /// this method. Future setSourceUrl(String url) { + _source = UrlSource(url); return _platform.setSourceUrl(playerId, url, isLocal: false); } @@ -225,6 +235,7 @@ class AudioPlayer { /// The resources will start being fetched or buffered as soon as you call /// this method. Future setSourceDeviceFile(String path) { + _source = DeviceFileSource(path); return _platform.setSourceUrl(playerId, path, isLocal: true); } @@ -234,11 +245,13 @@ class AudioPlayer { /// The resources will start being fetched or buffered as soon as you call /// this method. Future setSourceAsset(String path) async { + _source = AssetSource(path); final url = await audioCache.load(path); return _platform.setSourceUrl(playerId, url.path, isLocal: true); } Future setSourceBytes(Uint8List bytes) { + _source = BytesSource(bytes); return _platform.setSourceBytes(playerId, bytes); } @@ -277,6 +290,8 @@ class AudioPlayer { _onPlayerCompleteStreamSubscription.cancel() ]; + _source = null; + await Future.wait(futures); } } From d8a37336fb09fb71d8ece1c13c0edc7b38bfb93b Mon Sep 17 00:00:00 2001 From: Gustl22 Date: Wed, 21 Dec 2022 20:28:08 +0100 Subject: [PATCH 2/6] feat: button to get source --- .../example/lib/tabs/streams.dart | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/audioplayers/example/lib/tabs/streams.dart b/packages/audioplayers/example/lib/tabs/streams.dart index 3e26382de..51b79f559 100644 --- a/packages/audioplayers/example/lib/tabs/streams.dart +++ b/packages/audioplayers/example/lib/tabs/streams.dart @@ -20,6 +20,7 @@ class _StreamsTabState extends State with AutomaticKeepAliveClientMixin { Duration? position, duration; PlayerState? state; + Source? source; late List streams; Duration? streamDuration, streamPosition; @@ -67,6 +68,10 @@ class _StreamsTabState extends State setState(() => state = widget.player.state); } + Future getSource() async { + setState(() => source = widget.player.source); + } + @override Widget build(BuildContext context) { super.build(context); @@ -114,6 +119,20 @@ class _StreamsTabState extends State ), ], ), + Row( + children: [ + Btn( + key: const Key('getSource'), + txt: 'Get Source', + onPressed: getSource, + ), + const Pad(width: 8.0), + Text( + source?.toString() ?? '-', + key: const Key('sourceText'), + ), + ], + ), const Divider(color: Colors.black), const Text('Streams'), Text( From 580b2ba6d6e9b5648fe70d3a7d14c29bcb798320 Mon Sep 17 00:00:00 2001 From: Gustl22 Date: Thu, 22 Dec 2022 01:29:51 +0100 Subject: [PATCH 3/6] fix: scrollToAndTap --- .../example/integration_test/tabs/source_tab.dart | 3 +-- .../example/integration_test/tabs/stream_tab.dart | 12 ++++++------ .../example/integration_test/test_utils.dart | 5 +++++ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/audioplayers/example/integration_test/tabs/source_tab.dart b/packages/audioplayers/example/integration_test/tabs/source_tab.dart index 1bd7c53d0..1185aa467 100644 --- a/packages/audioplayers/example/integration_test/tabs/source_tab.dart +++ b/packages/audioplayers/example/integration_test/tabs/source_tab.dart @@ -22,8 +22,7 @@ extension ControlsWidgetTester on WidgetTester { printOnFailure('Test setting source: $sourceKey'); final st = StackTrace.current.toString(); final sourceWidgetKey = Key('setSource-$sourceKey'); - await scrollTo(sourceWidgetKey); - await tap(find.byKey(sourceWidgetKey)); + await scrollToAndTap(sourceWidgetKey); await waitOneshot(const Key('toast-source-set'), stackTrace: st); } diff --git a/packages/audioplayers/example/integration_test/tabs/stream_tab.dart b/packages/audioplayers/example/integration_test/tabs/stream_tab.dart index b4b18c044..3fe7dec91 100644 --- a/packages/audioplayers/example/integration_test/tabs/stream_tab.dart +++ b/packages/audioplayers/example/integration_test/tabs/stream_tab.dart @@ -35,7 +35,7 @@ Future testStreamsTab( final timeout = Duration(seconds: audioSourceTestData.isLiveStream ? 8 : 1); await tester.pumpAndSettle(); - await tester.tap(find.byKey(const Key('play_button'))); + await tester.scrollToAndTap(const Key('play_button')); await tester.pumpAndSettle(); // Cannot test more precisely as it is dependent on pollInterval @@ -79,7 +79,7 @@ Future testStreamsTab( await tester.testPlayerState(PlayerState.completed); await tester.testOnPlayerState(PlayerState.completed); } else if (audioSourceTestData.duration > const Duration(seconds: 5)) { - await tester.tap(find.byKey(const Key('pause_button'))); + await tester.scrollToAndTap(const Key('pause_button')); await tester.pumpAndSettle(); await tester.testPlayerState(PlayerState.paused); await tester.testOnPlayerState(PlayerState.paused); @@ -141,7 +141,7 @@ extension StreamWidgetTester on WidgetTester { Future stopStream() async { final st = StackTrace.current.toString(); - await tap(find.byKey(const Key('stop_button'))); + await scrollToAndTap(const Key('stop_button')); await waitOneshot(const Key('toast-player-stopped-0'), stackTrace: st); await pumpAndSettle(); } @@ -154,7 +154,7 @@ extension StreamWidgetTester on WidgetTester { final st = StackTrace.current.toString(); await waitFor( () async { - await tap(find.byKey(const Key('getDuration'))); + await scrollToAndTap(const Key('getDuration')); await pump(); expectWidgetHasDuration( const Key('durationText'), @@ -176,7 +176,7 @@ extension StreamWidgetTester on WidgetTester { final st = StackTrace.current.toString(); await waitFor( () async { - await tap(find.byKey(const Key('getPosition'))); + await scrollToAndTap(const Key('getPosition')); await pump(); expectWidgetHasDuration( const Key('positionText'), @@ -196,7 +196,7 @@ extension StreamWidgetTester on WidgetTester { final st = StackTrace.current.toString(); await waitFor( () async { - await tap(find.byKey(const Key('getPlayerState'))); + await scrollToAndTap(const Key('getPlayerState')); await pump(); expectWidgetHasText( const Key('playerStateText'), diff --git a/packages/audioplayers/example/integration_test/test_utils.dart b/packages/audioplayers/example/integration_test/test_utils.dart index b1553b967..67885a6eb 100644 --- a/packages/audioplayers/example/integration_test/test_utils.dart +++ b/packages/audioplayers/example/integration_test/test_utils.dart @@ -109,6 +109,11 @@ $lastFailureMsg''', } } + Future scrollToAndTap(Key widgetKey) async { + await scrollTo(widgetKey); + await tap(find.byKey(widgetKey)); + } + Future scrollTo(Key widgetKey) async { await dragUntilVisible( find.byKey(widgetKey), From 95a69917abc980e46f9a2101c71573f9199750c6 Mon Sep 17 00:00:00 2001 From: Gustl22 Date: Thu, 22 Dec 2022 02:59:48 +0100 Subject: [PATCH 4/6] feat: scroll to and tap --- .../integration_test/tabs/controls_tab.dart | 18 +++++++++--------- .../example/integration_test/test_utils.dart | 13 ++++++++----- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/audioplayers/example/integration_test/tabs/controls_tab.dart b/packages/audioplayers/example/integration_test/tabs/controls_tab.dart index 9060674ed..2f9aefc75 100644 --- a/packages/audioplayers/example/integration_test/tabs/controls_tab.dart +++ b/packages/audioplayers/example/integration_test/tabs/controls_tab.dart @@ -75,7 +75,7 @@ Future testControlsTab( await tester.resume(); await tester.pump(const Duration(seconds: 1)); // Test pause - await tester.tap(find.byKey(const Key('control-pause'))); + await tester.scrollToAndTap(const Key('control-pause')); await tester.resume(); await tester.pump(const Duration(seconds: 1)); await tester.stop(); @@ -130,14 +130,14 @@ Future testControlsTab( extension ControlsWidgetTester on WidgetTester { Future resume() async { - await tap(find.byKey(const Key('control-resume'))); + await scrollToAndTap(const Key('control-resume')); await pumpAndSettle(); } Future stop() async { final st = StackTrace.current.toString(); - await tap(find.byKey(const Key('control-stop'))); + await scrollToAndTap(const Key('control-stop')); await waitOneshot(const Key('toast-player-stopped-0'), stackTrace: st); await pumpAndSettle(); } @@ -147,7 +147,7 @@ extension ControlsWidgetTester on WidgetTester { Duration timeout = const Duration(seconds: 1), }) async { printOnFailure('Test Volume: $volume'); - await tap(find.byKey(Key('control-volume-$volume'))); + await scrollToAndTap(Key('control-volume-$volume')); await resume(); // TODO(Gustl22): get volume from native implementation await pump(timeout); @@ -159,7 +159,7 @@ extension ControlsWidgetTester on WidgetTester { Duration timeout = const Duration(seconds: 1), }) async { printOnFailure('Test Balance: $balance'); - await tap(find.byKey(Key('control-balance-$balance'))); + await scrollToAndTap(Key('control-balance-$balance')); await resume(); // TODO(novikov): get balance from native implementation await pump(timeout); @@ -171,7 +171,7 @@ extension ControlsWidgetTester on WidgetTester { Duration timeout = const Duration(seconds: 2), }) async { printOnFailure('Test Rate: $rate'); - await tap(find.byKey(Key('control-rate-$rate'))); + await scrollToAndTap(Key('control-rate-$rate')); await resume(); // TODO(Gustl22): get rate from native implementation await pump(timeout); @@ -185,7 +185,7 @@ extension ControlsWidgetTester on WidgetTester { printOnFailure('Test Seek: $seek'); final st = StackTrace.current.toString(); - await tap(find.byKey(Key('control-seek-$seek'))); + await scrollToAndTap(Key('control-seek-$seek')); await waitOneshot(const Key('toast-seek-complete-0'), stackTrace: st); @@ -198,7 +198,7 @@ extension ControlsWidgetTester on WidgetTester { printOnFailure('Test Player Mode: ${mode.name}'); final st = StackTrace.current.toString(); - await tap(find.byKey(Key('control-player-mode-${mode.name}'))); + await scrollToAndTap(Key('control-player-mode-${mode.name}')); await waitFor( () async => expectEnumToggleHasSelected( const Key('control-player-mode'), @@ -212,7 +212,7 @@ extension ControlsWidgetTester on WidgetTester { printOnFailure('Test Release Mode: ${mode.name}'); final st = StackTrace.current.toString(); - await tap(find.byKey(Key('control-release-mode-${mode.name}'))); + await scrollToAndTap(Key('control-release-mode-${mode.name}')); await waitFor( () async => expectEnumToggleHasSelected( const Key('control-release-mode'), diff --git a/packages/audioplayers/example/integration_test/test_utils.dart b/packages/audioplayers/example/integration_test/test_utils.dart index 67885a6eb..75199fd41 100644 --- a/packages/audioplayers/example/integration_test/test_utils.dart +++ b/packages/audioplayers/example/integration_test/test_utils.dart @@ -115,11 +115,14 @@ $lastFailureMsg''', } Future scrollTo(Key widgetKey) async { - await dragUntilVisible( - find.byKey(widgetKey), - find.byType(SingleChildScrollView).first, - const Offset(0, 100), - ); + final finder = find.byKey(widgetKey); + if (finder.hitTestable().evaluate().isEmpty) { + await scrollUntilVisible( + finder, + 100, + scrollable: find.byType(Scrollable).first, + ); + } await pumpAndSettle(); } } From 0e338562e7fa53dd0be8775e6ad49696e4f8b23a Mon Sep 17 00:00:00 2001 From: Gustl22 Date: Thu, 22 Dec 2022 10:26:11 +0100 Subject: [PATCH 5/6] increase timeout --- .../example/integration_test/tabs/controls_tab.dart | 4 ++-- .../example/integration_test/tabs/stream_tab.dart | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/audioplayers/example/integration_test/tabs/controls_tab.dart b/packages/audioplayers/example/integration_test/tabs/controls_tab.dart index 2f9aefc75..596c885a2 100644 --- a/packages/audioplayers/example/integration_test/tabs/controls_tab.dart +++ b/packages/audioplayers/example/integration_test/tabs/controls_tab.dart @@ -17,8 +17,8 @@ Future testControlsTab( await tester.tap(find.byKey(const Key('controlsTab'))); await tester.pumpAndSettle(); - // Live stream takes some time to get initialized - final timeout = Duration(seconds: audioSourceTestData.isLiveStream ? 8 : 1); + // Sources take some time to get initialized + const timeout = Duration(seconds: 8); if (features.hasVolume) { await tester.testVolume('0.5', timeout: timeout); diff --git a/packages/audioplayers/example/integration_test/tabs/stream_tab.dart b/packages/audioplayers/example/integration_test/tabs/stream_tab.dart index 3fe7dec91..08f91d531 100644 --- a/packages/audioplayers/example/integration_test/tabs/stream_tab.dart +++ b/packages/audioplayers/example/integration_test/tabs/stream_tab.dart @@ -31,8 +31,8 @@ Future testStreamsTab( await tester.testDuration(audioSourceTestData.duration); } - // Live stream takes some time to get initialized - final timeout = Duration(seconds: audioSourceTestData.isLiveStream ? 8 : 1); + // Sources take some time to get initialized + const timeout = Duration(seconds: 8); await tester.pumpAndSettle(); await tester.scrollToAndTap(const Key('play_button')); @@ -210,7 +210,7 @@ extension StreamWidgetTester on WidgetTester { Future testOnDuration( Duration duration, { - Duration timeout = const Duration(seconds: 8), + Duration timeout = const Duration(seconds: 10), }) async { printOnFailure('Test OnDuration: $duration'); final st = StackTrace.current.toString(); @@ -227,7 +227,7 @@ extension StreamWidgetTester on WidgetTester { Future testOnPosition( Duration position, { Matcher Function(Duration) matcher = equals, - Duration timeout = const Duration(seconds: 8), + Duration timeout = const Duration(seconds: 10), }) async { printOnFailure('Test OnPosition: $position'); final st = StackTrace.current.toString(); @@ -244,7 +244,7 @@ extension StreamWidgetTester on WidgetTester { Future testOnPlayerState( PlayerState playerState, { - Duration timeout = const Duration(seconds: 8), + Duration timeout = const Duration(seconds: 10), }) async { printOnFailure('Test OnState: $playerState'); final st = StackTrace.current.toString(); From 7740ec0a62a3281597b8cc434dc1c84685957fe5 Mon Sep 17 00:00:00 2001 From: Gustl22 Date: Thu, 22 Dec 2022 11:32:52 +0100 Subject: [PATCH 6/6] add test for #setSource --- packages/audioplayers/test/audioplayers_test.dart | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/audioplayers/test/audioplayers_test.dart b/packages/audioplayers/test/audioplayers_test.dart index 95aa3f9f3..e5ca2a7e1 100644 --- a/packages/audioplayers/test/audioplayers_test.dart +++ b/packages/audioplayers/test/audioplayers_test.dart @@ -27,6 +27,21 @@ void main() { } group('AudioPlayers', () { + test('#setSource', () async { + calls.clear(); + final player = AudioPlayer(); + expect(player.source, null); + + await player.setSource(UrlSource('internet.com/file.mp3')); + expect(popLastCall().method, 'setSourceUrl'); + expect(player.source, isInstanceOf()); + final urlSource = player.source as UrlSource?; + expect(urlSource?.url, 'internet.com/file.mp3'); + + await player.release(); + expect(player.source, null); + }); + test('#play', () async { calls.clear(); final player = AudioPlayer();