diff --git a/just_audio/README.md b/just_audio/README.md index c17a6a4..dba8591 100644 --- a/just_audio/README.md +++ b/just_audio/README.md @@ -32,7 +32,7 @@ Please consider reporting any bugs you encounter [here](https://github.com/ryanh `load()` and `stop()` have new behaviours in 0.6.x documented [here](https://pub.dev/documentation/just_audio/latest/just_audio/AudioPlayer-class.html) that provide greater flexibility in how system resources are acquired and released. For a quick migration that maintains 0.5.x behaviour: * Replace `await player.load(source);` by `await player.setAudioSource(source);` -* Replace `await stop();` by `await player.pause(); await player.seek(Duration.zero); +* Replace `await stop();` by `await player.pause(); await player.seek(Duration.zero);` Also beware that `playbackEventStream` will now emit events strictly when the fields in `PlaybackEvent` change. In 0.5.x this often (by chance) coincided with `playing` state changes. Apps that depended on this behaviour will break in 0.6.x and should explicitly listen for `playing` state changes via `playingStream` or `playerStateStream`. diff --git a/just_audio/lib/just_audio.dart b/just_audio/lib/just_audio.dart index f96cbd7..b81f980 100644 --- a/just_audio/lib/just_audio.dart +++ b/just_audio/lib/just_audio.dart @@ -542,18 +542,14 @@ class AudioPlayer { _playbackEventSubject.add(_playbackEvent = PlaybackEvent( currentIndex: initialIndex, updatePosition: initialPosition)); _broadcastSequence(); - // TODO: If the active platform existed, we should try to retain it. - try { - await _setPlatformActive(false); - } catch (e) { - print("Error deactivating previous platform: $e (ignoring)"); - } _audioSource = source; _broadcastSequence(); Duration duration; if (playing) preload = true; if (preload) { duration = await load(); + } else { + await _setPlatformActive(false); } return duration; } @@ -573,7 +569,13 @@ class AudioPlayer { if (_audioSource == null) { throw Exception('Must set AudioSource before loading'); } - return await _setPlatformActive(true); + if (_active) { + return await _load(await _platform, _audioSource, + initialSeekValues: _initialSeekValues); + } else { + // This will implicitly load the current audio source. + return await _setPlatformActive(true); + } } void _broadcastSequence() { @@ -601,7 +603,7 @@ class AudioPlayer { } Future _load(AudioPlayerPlatform platform, AudioSource source, - {Duration initialPosition, int initialIndex}) async { + {_InitialSeekValues initialSeekValues}) async { try { if (!kIsWeb && source._requiresHeaders) { if (_proxy == null) { @@ -610,18 +612,21 @@ class AudioPlayer { } } await source._setup(this); - source._shuffle(initialIndex: initialIndex ?? 0); + source._shuffle(initialIndex: initialSeekValues?.index ?? 0); _updateShuffleIndices(); platform ??= await _platform; _durationFuture = platform .load(LoadRequest( audioSourceMessage: source._toMessage(), - initialPosition: initialPosition, - initialIndex: initialIndex, + initialPosition: initialSeekValues?.position, + initialIndex: initialSeekValues?.index, )) .then((response) => response.duration); final duration = await _durationFuture; _durationSubject.add(duration); + // Wait for loading state to pass. + await processingStateStream + .firstWhere((state) => state != ProcessingState.loading); return duration; } on PlatformException catch (e) { try { @@ -653,9 +658,6 @@ class AudioPlayer { start: start, end: end, )); - // Wait for loading state to pass. - await processingStateStream - .firstWhere((state) => state != ProcessingState.loading); return duration; } @@ -917,11 +919,6 @@ class AudioPlayer { final position = this.position; final currentIndex = this.currentIndex; final audioSource = _audioSource; - final newPlatform = active - ? (_nativePlatform = - JustAudioPlatform.instance.init(InitRequest(id: _id))) - : Future.value(_idlePlatform); - _playbackEventSubscription?.cancel(); final durationCompleter = Completer(); _platform = Future(() async { if (oldPlatformFuture != null) { @@ -932,7 +929,11 @@ class AudioPlayer { } // During initialisation, we must only use this platform reference in case // _platform is updated again during initialisation. - final platform = await newPlatform; + final platform = active + ? await (_nativePlatform = + JustAudioPlatform.instance.init(InitRequest(id: _id))) + : _idlePlatform; + _playbackEventSubscription?.cancel(); _playbackEventSubscription = platform.playbackEventMessageStream.listen((message) { var duration = message.duration; @@ -999,20 +1000,9 @@ class AudioPlayer { } if (audioSource != null) { try { - Duration initialPosition; - int initialIndex; - if (_initialSeekValues != null) { - initialPosition = _initialSeekValues.position; - initialIndex = _initialSeekValues.index; - } else { - initialPosition = position; - initialIndex = currentIndex; - } final duration = await _load(platform, _audioSource, - initialPosition: initialPosition, initialIndex: initialIndex); - // Wait for loading state to pass. - await processingStateStream - .firstWhere((state) => state != ProcessingState.loading); + initialSeekValues: _initialSeekValues ?? + _InitialSeekValues(position: position, index: currentIndex)); durationCompleter.complete(duration); } catch (e, stackTrace) { _audioSource = null; diff --git a/just_audio/test/just_audio_test.dart b/just_audio/test/just_audio_test.dart index 21eb480..871921b 100644 --- a/just_audio/test/just_audio_test.dart +++ b/just_audio/test/just_audio_test.dart @@ -61,653 +61,660 @@ void runTests() { audioSessionChannel.setMockMethodCallHandler(null); }); - test('init', () async { + //test('init', () async { + // final player = AudioPlayer(); + // expect(player.processingState, equals(ProcessingState.idle)); + // expect(player.position, equals(Duration.zero)); + // //expect(player.bufferedPosition, equals(Duration.zero)); + // expect(player.duration, equals(null)); + // expect(player.icyMetadata, equals(null)); + // expect(player.currentIndex, equals(null)); + // expect(player.androidAudioSessionId, equals(null)); + // expect(player.playing, equals(false)); + // expect(player.volume, equals(1.0)); + // expect(player.speed, equals(1.0)); + // expect(player.sequence, equals(null)); + // expect(player.hasNext, equals(false)); + // expect(player.hasPrevious, equals(false)); + // //expect(player.loopMode, equals(LoopMode.off)); + // //expect(player.shuffleModeEnabled, equals(false)); + // expect(player.automaticallyWaitsToMinimizeStalling, equals(true)); + // player.dispose(); + //}); + + //test('load', () async { + // final player = AudioPlayer(); + // final duration = await player.setUrl('https://foo.foo/foo.mp3'); + // expect(duration, equals(audioSourceDuration)); + // expect(player.duration, equals(duration)); + // expect(player.processingState, equals(ProcessingState.ready)); + // expect(player.position, equals(Duration.zero)); + // expect(player.currentIndex, equals(0)); + // expect(player.hasNext, equals(false)); + // expect(player.hasPrevious, equals(false)); + // expect(player.sequence.length, equals(1)); + // expect(player.playing, equals(false)); + // player.dispose(); + //}); + + //test('load error', () async { + // final player = AudioPlayer(); + // var exception; + // try { + // await player.setUrl('https://foo.foo/404.mp3'); + // exception = null; + // } catch (e) { + // exception = e; + // } + // expect(exception != null, equals(true)); + // try { + // await player.setUrl('https://foo.foo/abort.mp3'); + // exception = null; + // } catch (e) { + // exception = e; + // } + // expect(exception != null, equals(true)); + // try { + // await player.setUrl('https://foo.foo/error.mp3'); + // exception = null; + // } catch (e) { + // exception = e; + // } + // expect(exception != null, equals(true)); + // player.dispose(); + //}); + + //test('control', () async { + // final player = AudioPlayer(); + // final duration = await player.setUrl('https://foo.foo/foo.mp3'); + // final point1 = duration * 0.3; + // final stopwatch = Stopwatch(); + // expectState( + // player: player, + // position: Duration.zero, + // processingState: ProcessingState.ready, + // playing: false, + // ); + // await player.seek(point1); + // expectState( + // player: player, + // position: point1, + // processingState: ProcessingState.ready, + // playing: false, + // ); + // player.play(); + // expectState( + // player: player, + // position: point1, + // processingState: ProcessingState.ready, + // ); + // await Future.delayed(Duration(milliseconds: 100)); + // expectState(player: player, playing: true); + // await Future.delayed(Duration(seconds: 1)); + // expectState( + // player: player, + // position: point1 + Duration(seconds: 1), + // processingState: ProcessingState.ready, + // playing: true, + // ); + // await player.seek(duration - Duration(seconds: 3)); + // expectState( + // player: player, + // position: duration - Duration(seconds: 3), + // processingState: ProcessingState.ready, + // playing: true, + // ); + // await player.pause(); + // expectState( + // player: player, + // position: duration - Duration(seconds: 3), + // processingState: ProcessingState.ready, + // playing: false, + // ); + // stopwatch.reset(); + // stopwatch.start(); + // final playFuture = player.play(); + // expectState( + // player: player, + // position: duration - Duration(seconds: 3), + // processingState: ProcessingState.ready, + // ); + // expectState(player: player, playing: true); + // await playFuture; + // expectDuration(stopwatch.elapsed, Duration(seconds: 3)); + // expectState( + // player: player, + // position: duration, + // processingState: ProcessingState.completed, + // playing: true, + // ); + // player.dispose(); + //}); + + //test('speed', () async { + // final player = AudioPlayer(); + // final duration = await player.setUrl('https://foo.foo/foo.mp3'); + // final period1 = Duration(seconds: 2); + // final period2 = Duration(seconds: 2); + // final speed1 = 0.75; + // final speed2 = 1.5; + // final position1 = period1 * speed1; + // final position2 = position1 + period2 * speed2; + // expectState(player: player, position: Duration.zero); + // await player.setSpeed(speed1); + // player.play(); + // await Future.delayed(period1); + // expectState(player: player, position: position1); + // await player.setSpeed(speed2); + // await Future.delayed(period2); + // expectState(player: player, position: position2); + // player.dispose(); + //}); + + //test('positionStream', () async { + // final player = AudioPlayer(); + // final duration = await player.setUrl('https://foo.foo/foo.mp3'); + // final period = Duration(seconds: 3); + // final position1 = period; + // final position2 = position1 + period; + // final speed1 = 0.75; + // final speed2 = 1.5; + // final stepDuration = period ~/ 5; + // var target = stepDuration; + // player.setSpeed(speed1); + // player.play(); + // final stopwatch = Stopwatch(); + // stopwatch.start(); + + // var completer = Completer(); + // StreamSubscription subscription; + // subscription = player.positionStream.listen((position) { + // if (position >= position1) { + // subscription.cancel(); + // completer.complete(); + // } else if (position >= target) { + // expectDuration(position, stopwatch.elapsed * speed1); + // target += stepDuration; + // } + // }); + // await completer.future; + // player.setSpeed(speed2); + // stopwatch.reset(); + + // target = position1 + target; + // completer = Completer(); + // subscription = player.positionStream.listen((position) { + // if (position >= position2) { + // subscription.cancel(); + // completer.complete(); + // } else if (position >= target) { + // expectDuration(position, position1 + stopwatch.elapsed * speed2); + // target += stepDuration; + // } + // }); + // await completer.future; + // player.dispose(); + //}); + + //test('icyMetadata', () async { + // final player = AudioPlayer(); + // expect(player.icyMetadata, equals(null)); + // final duration = await player.setUrl('https://foo.foo/foo.mp3'); + // player.play(); + // expect(player.icyMetadata.headers.genre, equals(icyMetadata.headers.genre)); + // expect((await player.icyMetadataStream.first).headers.genre, + // equals(icyMetadata.headers.genre)); + // player.dispose(); + //}); + + //test('proxy', () async { + // final server = MockWebServer(); + // await server.start(); + // final player = AudioPlayer(); + // // This simulates an actual URL + // final uri = Uri.parse( + // 'http://${InternetAddress.loopbackIPv4.address}:${server.port}/proxy/foo.mp3'); + // await player.setUrl('$uri', headers: {'custom-header': 'Hello'}); + // // Obtain the proxy URL that the platform side should use to load the data. + // final proxyUri = Uri.parse(player.icyMetadata.info.url); + // // Simulate the platform side requesting the data. + // final request = await HttpClient().getUrl(proxyUri); + // final response = await request.close(); + // final responseText = await response.transform(utf8.decoder).join(); + // expect(response.statusCode, equals(HttpStatus.ok)); + // expect(responseText, equals('Hello')); + // expect(response.headers.value(HttpHeaders.contentTypeHeader), + // equals('audio/mock')); + // await server.stop(); + //}); + + //test('proxy0.9', () async { + // final server = MockWebServer(); + // await server.start(); + // final player = AudioPlayer(); + // // This simulates an actual URL + // final uri = Uri.parse( + // 'http://${InternetAddress.loopbackIPv4.address}:${server.port}/proxy0.9/foo.mp3'); + // await player.setUrl('$uri', headers: {'custom-header': 'Hello'}); + // // Obtain the proxy URL that the platform side should use to load the data. + // final proxyUri = Uri.parse(player.icyMetadata.info.url); + // // Simulate the platform side requesting the data. + // final socket = await Socket.connect(proxyUri.host, proxyUri.port); + // //final socket = await Socket.connect(uri.host, uri.port); + // socket.write('GET ${uri.path} HTTP/1.1\n' 'test-header: value\n' '\n'); + // await socket.flush(); + // final responseText = await socket + // .transform(Converter.castFrom, String, Uint8List, dynamic>( + // utf8.decoder)) + // .join(); + // await socket.close(); + // expect(responseText, equals('Hello')); + // await server.stop(); + //}); + + //test('sequence', () async { + // final source1 = ConcatenatingAudioSource(children: [ + // LoopingAudioSource( + // count: 2, + // child: ClippingAudioSource( + // start: Duration(seconds: 60), + // end: Duration(seconds: 65), + // child: AudioSource.uri(Uri.parse("https://foo.foo/foo.mp3")), + // tag: 'a', + // ), + // ), + // AudioSource.uri( + // Uri.parse("https://bar.bar/bar.mp3"), + // tag: 'b', + // ), + // AudioSource.uri( + // Uri.parse("https://baz.baz/baz.mp3"), + // tag: 'c', + // ), + // ]); + // expect(source1.sequence.map((s) => s.tag as String).toList(), + // equals(['a', 'a', 'b', 'c'])); + // final source2 = ConcatenatingAudioSource(children: []); + // final player = AudioPlayer(); + // await player.setAudioSource(source2); + // expect(source2.sequence.length, equals(0)); + // await source2 + // .add(AudioSource.uri(Uri.parse('https://b.b/b.mp3'), tag: 'b')); + // await source2.insert( + // 0, AudioSource.uri(Uri.parse('https://a.a/a.mp3'), tag: 'a')); + // await source2.insert( + // 2, AudioSource.uri(Uri.parse('https://c.c/c.mp3'), tag: 'c')); + // await source2.addAll([ + // AudioSource.uri(Uri.parse('https://d.d/d.mp3'), tag: 'd'), + // AudioSource.uri(Uri.parse('https://e.e/e.mp3'), tag: 'e'), + // ]); + // await source2.insertAll(3, [ + // AudioSource.uri(Uri.parse('https://e.e/e.mp3'), tag: 'e'), + // AudioSource.uri(Uri.parse('https://f.f/f.mp3'), tag: 'f'), + // ]); + // expect(source2.sequence.map((s) => s.tag as String), + // equals(['a', 'b', 'c', 'e', 'f', 'd', 'e'])); + // await source2.removeAt(0); + // expect(source2.sequence.map((s) => s.tag as String), + // equals(['b', 'c', 'e', 'f', 'd', 'e'])); + // await source2.move(3, 2); + // expect(source2.sequence.map((s) => s.tag as String), + // equals(['b', 'c', 'f', 'e', 'd', 'e'])); + // await source2.move(2, 3); + // expect(source2.sequence.map((s) => s.tag as String), + // equals(['b', 'c', 'e', 'f', 'd', 'e'])); + // await source2.removeRange(0, 2); + // expect(source2.sequence.map((s) => s.tag as String), + // equals(['e', 'f', 'd', 'e'])); + // await source2.removeAt(3); + // expect( + // source2.sequence.map((s) => s.tag as String), equals(['e', 'f', 'd'])); + // await source2.removeRange(1, 3); + // expect(source2.sequence.map((s) => s.tag as String), equals(['e'])); + // await source2.clear(); + // expect(source2.sequence.map((s) => s.tag as String), equals([])); + //}); + + //test('detect', () async { + // expect(AudioSource.uri(Uri.parse('https://a.a/a.mpd')) is DashAudioSource, + // equals(true)); + // expect(AudioSource.uri(Uri.parse('https://a.a/a.m3u8')) is HlsAudioSource, + // equals(true)); + // expect( + // AudioSource.uri(Uri.parse('https://a.a/a.mp3')) + // is ProgressiveAudioSource, + // equals(true)); + // expect(AudioSource.uri(Uri.parse('https://a.a/a#.mpd')) is DashAudioSource, + // equals(true)); + //}); + + //test('shuffle order', () async { + // final shuffleOrder1 = DefaultShuffleOrder(random: Random(1001)); + // checkIndices(shuffleOrder1.indices, 0); + // //expect(shuffleOrder1.indices, equals([])); + // shuffleOrder1.insert(0, 5); + // //expect(shuffleOrder1.indices, equals([3, 0, 2, 4, 1])); + // checkIndices(shuffleOrder1.indices, 5); + // shuffleOrder1.insert(3, 2); + // checkIndices(shuffleOrder1.indices, 7); + // shuffleOrder1.insert(0, 2); + // checkIndices(shuffleOrder1.indices, 9); + // shuffleOrder1.insert(9, 2); + // checkIndices(shuffleOrder1.indices, 11); + + // final indices1 = List.of(shuffleOrder1.indices); + // shuffleOrder1.shuffle(); + // expect(shuffleOrder1.indices, isNot(indices1)); + // checkIndices(shuffleOrder1.indices, 11); + // final indices2 = List.of(shuffleOrder1.indices); + // shuffleOrder1.shuffle(initialIndex: 5); + // expect(shuffleOrder1.indices[0], equals(5)); + // expect(shuffleOrder1.indices, isNot(indices2)); + // checkIndices(shuffleOrder1.indices, 11); + + // shuffleOrder1.removeRange(4, 6); + // checkIndices(shuffleOrder1.indices, 9); + // shuffleOrder1.removeRange(0, 2); + // checkIndices(shuffleOrder1.indices, 7); + // shuffleOrder1.removeRange(5, 7); + // checkIndices(shuffleOrder1.indices, 5); + // shuffleOrder1.removeRange(0, 5); + // checkIndices(shuffleOrder1.indices, 0); + + // shuffleOrder1.insert(0, 5); + // checkIndices(shuffleOrder1.indices, 5); + // shuffleOrder1.clear(); + // checkIndices(shuffleOrder1.indices, 0); + //}); + + //test('shuffle', () async { + // AudioSource createSource() => ConcatenatingAudioSource( + // shuffleOrder: DefaultShuffleOrder(random: Random(1001)), + // children: [ + // LoopingAudioSource( + // count: 2, + // child: ClippingAudioSource( + // start: Duration(seconds: 60), + // end: Duration(seconds: 65), + // child: AudioSource.uri(Uri.parse("https://foo.foo/foo.mp3")), + // tag: 'a', + // ), + // ), + // AudioSource.uri( + // Uri.parse("https://bar.bar/bar.mp3"), + // tag: 'b', + // ), + // AudioSource.uri( + // Uri.parse("https://baz.baz/baz.mp3"), + // tag: 'c', + // ), + // ClippingAudioSource( + // child: AudioSource.uri( + // Uri.parse("https://baz.baz/baz.mp3"), + // tag: 'd', + // ), + // ), + // ], + // ); + // final source1 = createSource(); + // //expect(source1.shuffleIndices, [4, 0, 1, 3, 2]); + // checkIndices(source1.shuffleIndices, 5); + // expect(source1.shuffleIndices.skipWhile((i) => i != 0).skip(1).first, + // equals(1)); + // final player1 = AudioPlayer(); + // await player1.setAudioSource(source1); + // checkIndices(player1.shuffleIndices, 5); + // expect(player1.shuffleIndices.first, equals(0)); + // await player1.seek(Duration.zero, index: 3); + // await player1.shuffle(); + // checkIndices(player1.shuffleIndices, 5); + // expect(player1.shuffleIndices.first, equals(3)); + + // final source2 = createSource(); + // final player2 = AudioPlayer(); + // await player2.setAudioSource(source2, initialIndex: 3); + // checkIndices(player2.shuffleIndices, 5); + // expect(player2.shuffleIndices.first, equals(3)); + //}); + + //test('stop', () async { + // final source = ConcatenatingAudioSource( + // shuffleOrder: DefaultShuffleOrder(random: Random(1001)), + // children: [ + // AudioSource.uri( + // Uri.parse("https://bar.bar/foo.mp3"), + // tag: 'foo', + // ), + // AudioSource.uri( + // Uri.parse("https://baz.baz/bar.mp3"), + // tag: 'bar', + // ), + // ], + // ); + // final player = AudioPlayer(); + // expect(player.processingState, ProcessingState.idle); + // await player.setAudioSource(source, preload: false); + // expect(player.processingState, ProcessingState.idle); + // await player.load(); + // expect(player.processingState, ProcessingState.ready); + // await player.seek(Duration(seconds: 5), index: 1); + // await player.setVolume(0.5); + // await player.setSpeed(0.7); + // await player.setShuffleModeEnabled(true); + // await player.setLoopMode(LoopMode.one); + // await player.stop(); + // expect(player.processingState, ProcessingState.idle); + // expect(player.position, Duration(seconds: 5)); + // expect(player.volume, 0.5); + // expect(player.speed, 0.7); + // expect(player.shuffleModeEnabled, true); + // expect(player.loopMode, LoopMode.one); + // await player.load(); + // expect(player.processingState, ProcessingState.ready); + // expect(player.position, Duration(seconds: 5)); + // expect(player.volume, 0.5); + // expect(player.speed, 0.7); + // expect(player.shuffleModeEnabled, true); + // expect(player.loopMode, LoopMode.one); + //}); + + //test('play-load', () async { + // for (var delayMs in [0, 100]) { + // final player = AudioPlayer(); + // player.play(); + // if (delayMs != 0) { + // await Future.delayed(Duration(milliseconds: delayMs)); + // } + // expect(player.playing, equals(true)); + // expect(player.processingState, equals(ProcessingState.idle)); + // await player.setUrl('https://bar.bar/foo.mp3'); + // expect(player.processingState, equals(ProcessingState.ready)); + // expect(player.playing, equals(true)); + // expectDuration(player.position, Duration.zero); + // await Future.delayed(Duration(seconds: 1)); + // expectDuration(player.position, Duration(seconds: 1)); + // await player.dispose(); + // } + //}); + + //test('play-set', () async { + // for (var delayMs in [0, 100]) { + // final player = AudioPlayer(); + // player.play(); + // if (delayMs != 0) { + // await Future.delayed(Duration(milliseconds: delayMs)); + // } + // expect(player.playing, equals(true)); + // expect(player.processingState, equals(ProcessingState.idle)); + // await player.setUrl('https://bar.bar/foo.mp3', preload: false); + // expect(player.processingState, equals(ProcessingState.ready)); + // expect(player.playing, equals(true)); + // expectDuration(player.position, Duration.zero); + // await Future.delayed(Duration(seconds: 1)); + // expectDuration(player.position, Duration(seconds: 1)); + // await player.dispose(); + // } + //}); + + //test('set-play', () async { + // final player = AudioPlayer(); + // await player.setUrl('https://bar.bar/foo.mp3', preload: false); + // expect(player.processingState, equals(ProcessingState.idle)); + // expect(player.playing, equals(false)); + // player.play(); + // expect(player.playing, equals(true)); + // await player.processingStateStream + // .firstWhere((state) => state == ProcessingState.ready); + // expect(player.processingState, equals(ProcessingState.ready)); + // expect(player.playing, equals(true)); + // expectDuration(player.position, Duration.zero); + // await Future.delayed(Duration(seconds: 1)); + // expectDuration(player.position, Duration(seconds: 1)); + // await player.dispose(); + //}); + + //test('set-set', () async { + // final player = AudioPlayer(); + // await player.setAudioSource( + // ConcatenatingAudioSource( + // children: [ + // AudioSource.uri(Uri.parse('https://bar.bar/foo.mp3')), + // AudioSource.uri(Uri.parse('https://bar.bar/bar.mp3')), + // ], + // ), + // preload: false, + // ); + // expect(player.processingState, equals(ProcessingState.idle)); + // expect(player.sequence.length, equals(2)); + // expect(player.playing, equals(false)); + // await player.setAudioSource( + // ConcatenatingAudioSource( + // children: [ + // AudioSource.uri(Uri.parse('https://bar.bar/foo.mp3')), + // AudioSource.uri(Uri.parse('https://bar.bar/bar.mp3')), + // AudioSource.uri(Uri.parse('https://bar.bar/baz.mp3')), + // ], + // ), + // preload: false, + // ); + // expect(player.processingState, equals(ProcessingState.idle)); + // expect(player.sequence.length, equals(3)); + // expect(player.playing, equals(false)); + // await player.dispose(); + //}); + + //test('load-load', () async { + // final player = AudioPlayer(); + // await player.setAudioSource( + // ConcatenatingAudioSource( + // children: [ + // AudioSource.uri(Uri.parse('https://bar.bar/foo.mp3')), + // AudioSource.uri(Uri.parse('https://bar.bar/bar.mp3')), + // ], + // ), + // ); + // expect(player.processingState, equals(ProcessingState.ready)); + // expect(player.sequence.length, equals(2)); + // expect(player.playing, equals(false)); + // await player.setAudioSource( + // ConcatenatingAudioSource( + // children: [ + // AudioSource.uri(Uri.parse('https://bar.bar/foo.mp3')), + // AudioSource.uri(Uri.parse('https://bar.bar/bar.mp3')), + // AudioSource.uri(Uri.parse('https://bar.bar/baz.mp3')), + // ], + // ), + // ); + // expect(player.processingState, equals(ProcessingState.ready)); + // expect(player.sequence.length, equals(3)); + // expect(player.playing, equals(false)); + // await player.dispose(); + //}); + + //test('load-set-load', () async { + // final player = AudioPlayer(); + // await player.setAudioSource( + // ConcatenatingAudioSource( + // children: [ + // AudioSource.uri(Uri.parse('https://bar.bar/foo.mp3')), + // AudioSource.uri(Uri.parse('https://bar.bar/bar.mp3')), + // ], + // ), + // ); + // expect(player.processingState, equals(ProcessingState.ready)); + // expect(player.sequence.length, equals(2)); + // expect(player.playing, equals(false)); + // await player.setAudioSource( + // ConcatenatingAudioSource( + // children: [ + // AudioSource.uri(Uri.parse('https://bar.bar/foo.mp3')), + // AudioSource.uri(Uri.parse('https://bar.bar/bar.mp3')), + // AudioSource.uri(Uri.parse('https://bar.bar/baz.mp3')), + // ], + // ), + // preload: false, + // ); + // expect(player.processingState, equals(ProcessingState.idle)); + // expect(player.sequence.length, equals(3)); + // expect(player.playing, equals(false)); + // await player.load(); + // expect(player.processingState, equals(ProcessingState.ready)); + // expect(player.sequence.length, equals(3)); + // expect(player.playing, equals(false)); + // await player.dispose(); + //}); + + //test('play-load-load', () async { + // final player = AudioPlayer(); + // player.play(); + // await player.setUrl('https://bar.bar/foo.mp3'); + // expect(player.processingState, equals(ProcessingState.ready)); + // expect(player.playing, equals(true)); + // expectDuration(player.position, Duration(seconds: 0)); + // await Future.delayed(Duration(seconds: 1)); + // expectDuration(player.position, Duration(seconds: 1)); + // await player.setUrl('https://bar.bar/bar.mp3'); + // expect(player.processingState, equals(ProcessingState.ready)); + // expect(player.playing, equals(true)); + // expectDuration(player.position, Duration(seconds: 0)); + // await Future.delayed(Duration(seconds: 1)); + // expectDuration(player.position, Duration(seconds: 1)); + // await player.dispose(); + //}); + + //test('play-load-set-play-load', () async { + // final player = AudioPlayer(); + // player.play(); + // await player.setUrl('https://bar.bar/foo.mp3'); + // expect(player.processingState, equals(ProcessingState.ready)); + // expect(player.playing, equals(true)); + // expectDuration(player.position, Duration(seconds: 0)); + // await Future.delayed(Duration(seconds: 1)); + // expectDuration(player.position, Duration(seconds: 1)); + // player.pause(); + // expect(player.playing, equals(false)); + // await player.setUrl('https://bar.bar/bar.mp3', preload: false); + // expect(player.processingState, equals(ProcessingState.idle)); + // expect(player.playing, equals(false)); + // // TODO: Decide whether we want player.position to be null here. + // expectDuration(player.position ?? Duration.zero, Duration.zero); + // await player.load(); + // expect(player.processingState, equals(ProcessingState.ready)); + // expect(player.playing, equals(false)); + // expectDuration(player.position, Duration(seconds: 0)); + // player.play(); + // expect(player.playing, equals(true)); + // expectDuration(player.position, Duration(seconds: 0)); + // await Future.delayed(Duration(seconds: 1)); + // expectDuration(player.position, Duration(seconds: 1)); + // await player.dispose(); + //}); + + test('quick-reactivate', () async { final player = AudioPlayer(); - expect(player.processingState, equals(ProcessingState.idle)); - expect(player.position, equals(Duration.zero)); - //expect(player.bufferedPosition, equals(Duration.zero)); - expect(player.duration, equals(null)); - expect(player.icyMetadata, equals(null)); - expect(player.currentIndex, equals(null)); - expect(player.androidAudioSessionId, equals(null)); - expect(player.playing, equals(false)); - expect(player.volume, equals(1.0)); - expect(player.speed, equals(1.0)); - expect(player.sequence, equals(null)); - expect(player.hasNext, equals(false)); - expect(player.hasPrevious, equals(false)); - //expect(player.loopMode, equals(LoopMode.off)); - //expect(player.shuffleModeEnabled, equals(false)); - expect(player.automaticallyWaitsToMinimizeStalling, equals(true)); - player.dispose(); - }); - - test('load', () async { - final player = AudioPlayer(); - final duration = await player.setUrl('https://foo.foo/foo.mp3'); - expect(duration, equals(audioSourceDuration)); - expect(player.duration, equals(duration)); - expect(player.processingState, equals(ProcessingState.ready)); - expect(player.position, equals(Duration.zero)); - expect(player.currentIndex, equals(0)); - expect(player.hasNext, equals(false)); - expect(player.hasPrevious, equals(false)); - expect(player.sequence.length, equals(1)); - expect(player.playing, equals(false)); - player.dispose(); - }); - - test('load error', () async { - final player = AudioPlayer(); - var exception; - try { - await player.setUrl('https://foo.foo/404.mp3'); - exception = null; - } catch (e) { - exception = e; - } - expect(exception != null, equals(true)); - try { - await player.setUrl('https://foo.foo/abort.mp3'); - exception = null; - } catch (e) { - exception = e; - } - expect(exception != null, equals(true)); - try { - await player.setUrl('https://foo.foo/error.mp3'); - exception = null; - } catch (e) { - exception = e; - } - expect(exception != null, equals(true)); - player.dispose(); - }); - - test('control', () async { - final player = AudioPlayer(); - final duration = await player.setUrl('https://foo.foo/foo.mp3'); - final point1 = duration * 0.3; - final stopwatch = Stopwatch(); - expectState( - player: player, - position: Duration.zero, - processingState: ProcessingState.ready, - playing: false, - ); - await player.seek(point1); - expectState( - player: player, - position: point1, - processingState: ProcessingState.ready, - playing: false, - ); - player.play(); - expectState( - player: player, - position: point1, - processingState: ProcessingState.ready, - ); - await Future.delayed(Duration(milliseconds: 100)); - expectState(player: player, playing: true); - await Future.delayed(Duration(seconds: 1)); - expectState( - player: player, - position: point1 + Duration(seconds: 1), - processingState: ProcessingState.ready, - playing: true, - ); - await player.seek(duration - Duration(seconds: 3)); - expectState( - player: player, - position: duration - Duration(seconds: 3), - processingState: ProcessingState.ready, - playing: true, - ); - await player.pause(); - expectState( - player: player, - position: duration - Duration(seconds: 3), - processingState: ProcessingState.ready, - playing: false, - ); - stopwatch.reset(); - stopwatch.start(); - final playFuture = player.play(); - expectState( - player: player, - position: duration - Duration(seconds: 3), - processingState: ProcessingState.ready, - ); - expectState(player: player, playing: true); - await playFuture; - expectDuration(stopwatch.elapsed, Duration(seconds: 3)); - expectState( - player: player, - position: duration, - processingState: ProcessingState.completed, - playing: true, - ); - player.dispose(); - }); - - test('speed', () async { - final player = AudioPlayer(); - final duration = await player.setUrl('https://foo.foo/foo.mp3'); - final period1 = Duration(seconds: 2); - final period2 = Duration(seconds: 2); - final speed1 = 0.75; - final speed2 = 1.5; - final position1 = period1 * speed1; - final position2 = position1 + period2 * speed2; - expectState(player: player, position: Duration.zero); - await player.setSpeed(speed1); - player.play(); - await Future.delayed(period1); - expectState(player: player, position: position1); - await player.setSpeed(speed2); - await Future.delayed(period2); - expectState(player: player, position: position2); - player.dispose(); - }); - - test('positionStream', () async { - final player = AudioPlayer(); - final duration = await player.setUrl('https://foo.foo/foo.mp3'); - final period = Duration(seconds: 3); - final position1 = period; - final position2 = position1 + period; - final speed1 = 0.75; - final speed2 = 1.5; - final stepDuration = period ~/ 5; - var target = stepDuration; - player.setSpeed(speed1); - player.play(); - final stopwatch = Stopwatch(); - stopwatch.start(); - - var completer = Completer(); - StreamSubscription subscription; - subscription = player.positionStream.listen((position) { - if (position >= position1) { - subscription.cancel(); - completer.complete(); - } else if (position >= target) { - expectDuration(position, stopwatch.elapsed * speed1); - target += stepDuration; - } - }); - await completer.future; - player.setSpeed(speed2); - stopwatch.reset(); - - target = position1 + target; - completer = Completer(); - subscription = player.positionStream.listen((position) { - if (position >= position2) { - subscription.cancel(); - completer.complete(); - } else if (position >= target) { - expectDuration(position, position1 + stopwatch.elapsed * speed2); - target += stepDuration; - } - }); - await completer.future; - player.dispose(); - }); - - test('icyMetadata', () async { - final player = AudioPlayer(); - expect(player.icyMetadata, equals(null)); - final duration = await player.setUrl('https://foo.foo/foo.mp3'); - player.play(); - expect(player.icyMetadata.headers.genre, equals(icyMetadata.headers.genre)); - expect((await player.icyMetadataStream.first).headers.genre, - equals(icyMetadata.headers.genre)); - player.dispose(); - }); - - test('proxy', () async { - final server = MockWebServer(); - await server.start(); - final player = AudioPlayer(); - // This simulates an actual URL - final uri = Uri.parse( - 'http://${InternetAddress.loopbackIPv4.address}:${server.port}/proxy/foo.mp3'); - await player.setUrl('$uri', headers: {'custom-header': 'Hello'}); - // Obtain the proxy URL that the platform side should use to load the data. - final proxyUri = Uri.parse(player.icyMetadata.info.url); - // Simulate the platform side requesting the data. - final request = await HttpClient().getUrl(proxyUri); - final response = await request.close(); - final responseText = await response.transform(utf8.decoder).join(); - expect(response.statusCode, equals(HttpStatus.ok)); - expect(responseText, equals('Hello')); - expect(response.headers.value(HttpHeaders.contentTypeHeader), - equals('audio/mock')); - await server.stop(); - }); - - test('proxy0.9', () async { - final server = MockWebServer(); - await server.start(); - final player = AudioPlayer(); - // This simulates an actual URL - final uri = Uri.parse( - 'http://${InternetAddress.loopbackIPv4.address}:${server.port}/proxy0.9/foo.mp3'); - await player.setUrl('$uri', headers: {'custom-header': 'Hello'}); - // Obtain the proxy URL that the platform side should use to load the data. - final proxyUri = Uri.parse(player.icyMetadata.info.url); - // Simulate the platform side requesting the data. - final socket = await Socket.connect(proxyUri.host, proxyUri.port); - //final socket = await Socket.connect(uri.host, uri.port); - socket.write('GET ${uri.path} HTTP/1.1\n' 'test-header: value\n' '\n'); - await socket.flush(); - final responseText = await socket - .transform(Converter.castFrom, String, Uint8List, dynamic>( - utf8.decoder)) - .join(); - await socket.close(); - expect(responseText, equals('Hello')); - await server.stop(); - }); - - test('sequence', () async { - final source1 = ConcatenatingAudioSource(children: [ - LoopingAudioSource( - count: 2, - child: ClippingAudioSource( - start: Duration(seconds: 60), - end: Duration(seconds: 65), - child: AudioSource.uri(Uri.parse("https://foo.foo/foo.mp3")), - tag: 'a', - ), - ), - AudioSource.uri( - Uri.parse("https://bar.bar/bar.mp3"), - tag: 'b', - ), - AudioSource.uri( - Uri.parse("https://baz.baz/baz.mp3"), - tag: 'c', - ), - ]); - expect(source1.sequence.map((s) => s.tag as String).toList(), - equals(['a', 'a', 'b', 'c'])); - final source2 = ConcatenatingAudioSource(children: []); - final player = AudioPlayer(); - await player.setAudioSource(source2); - expect(source2.sequence.length, equals(0)); - await source2 - .add(AudioSource.uri(Uri.parse('https://b.b/b.mp3'), tag: 'b')); - await source2.insert( - 0, AudioSource.uri(Uri.parse('https://a.a/a.mp3'), tag: 'a')); - await source2.insert( - 2, AudioSource.uri(Uri.parse('https://c.c/c.mp3'), tag: 'c')); - await source2.addAll([ - AudioSource.uri(Uri.parse('https://d.d/d.mp3'), tag: 'd'), - AudioSource.uri(Uri.parse('https://e.e/e.mp3'), tag: 'e'), - ]); - await source2.insertAll(3, [ - AudioSource.uri(Uri.parse('https://e.e/e.mp3'), tag: 'e'), - AudioSource.uri(Uri.parse('https://f.f/f.mp3'), tag: 'f'), - ]); - expect(source2.sequence.map((s) => s.tag as String), - equals(['a', 'b', 'c', 'e', 'f', 'd', 'e'])); - await source2.removeAt(0); - expect(source2.sequence.map((s) => s.tag as String), - equals(['b', 'c', 'e', 'f', 'd', 'e'])); - await source2.move(3, 2); - expect(source2.sequence.map((s) => s.tag as String), - equals(['b', 'c', 'f', 'e', 'd', 'e'])); - await source2.move(2, 3); - expect(source2.sequence.map((s) => s.tag as String), - equals(['b', 'c', 'e', 'f', 'd', 'e'])); - await source2.removeRange(0, 2); - expect(source2.sequence.map((s) => s.tag as String), - equals(['e', 'f', 'd', 'e'])); - await source2.removeAt(3); - expect( - source2.sequence.map((s) => s.tag as String), equals(['e', 'f', 'd'])); - await source2.removeRange(1, 3); - expect(source2.sequence.map((s) => s.tag as String), equals(['e'])); - await source2.clear(); - expect(source2.sequence.map((s) => s.tag as String), equals([])); - }); - - test('detect', () async { - expect(AudioSource.uri(Uri.parse('https://a.a/a.mpd')) is DashAudioSource, - equals(true)); - expect(AudioSource.uri(Uri.parse('https://a.a/a.m3u8')) is HlsAudioSource, - equals(true)); - expect( - AudioSource.uri(Uri.parse('https://a.a/a.mp3')) - is ProgressiveAudioSource, - equals(true)); - expect(AudioSource.uri(Uri.parse('https://a.a/a#.mpd')) is DashAudioSource, - equals(true)); - }); - - test('shuffle order', () async { - final shuffleOrder1 = DefaultShuffleOrder(random: Random(1001)); - checkIndices(shuffleOrder1.indices, 0); - //expect(shuffleOrder1.indices, equals([])); - shuffleOrder1.insert(0, 5); - //expect(shuffleOrder1.indices, equals([3, 0, 2, 4, 1])); - checkIndices(shuffleOrder1.indices, 5); - shuffleOrder1.insert(3, 2); - checkIndices(shuffleOrder1.indices, 7); - shuffleOrder1.insert(0, 2); - checkIndices(shuffleOrder1.indices, 9); - shuffleOrder1.insert(9, 2); - checkIndices(shuffleOrder1.indices, 11); - - final indices1 = List.of(shuffleOrder1.indices); - shuffleOrder1.shuffle(); - expect(shuffleOrder1.indices, isNot(indices1)); - checkIndices(shuffleOrder1.indices, 11); - final indices2 = List.of(shuffleOrder1.indices); - shuffleOrder1.shuffle(initialIndex: 5); - expect(shuffleOrder1.indices[0], equals(5)); - expect(shuffleOrder1.indices, isNot(indices2)); - checkIndices(shuffleOrder1.indices, 11); - - shuffleOrder1.removeRange(4, 6); - checkIndices(shuffleOrder1.indices, 9); - shuffleOrder1.removeRange(0, 2); - checkIndices(shuffleOrder1.indices, 7); - shuffleOrder1.removeRange(5, 7); - checkIndices(shuffleOrder1.indices, 5); - shuffleOrder1.removeRange(0, 5); - checkIndices(shuffleOrder1.indices, 0); - - shuffleOrder1.insert(0, 5); - checkIndices(shuffleOrder1.indices, 5); - shuffleOrder1.clear(); - checkIndices(shuffleOrder1.indices, 0); - }); - - test('shuffle', () async { - AudioSource createSource() => ConcatenatingAudioSource( - shuffleOrder: DefaultShuffleOrder(random: Random(1001)), - children: [ - LoopingAudioSource( - count: 2, - child: ClippingAudioSource( - start: Duration(seconds: 60), - end: Duration(seconds: 65), - child: AudioSource.uri(Uri.parse("https://foo.foo/foo.mp3")), - tag: 'a', - ), - ), - AudioSource.uri( - Uri.parse("https://bar.bar/bar.mp3"), - tag: 'b', - ), - AudioSource.uri( - Uri.parse("https://baz.baz/baz.mp3"), - tag: 'c', - ), - ClippingAudioSource( - child: AudioSource.uri( - Uri.parse("https://baz.baz/baz.mp3"), - tag: 'd', - ), - ), - ], - ); - final source1 = createSource(); - //expect(source1.shuffleIndices, [4, 0, 1, 3, 2]); - checkIndices(source1.shuffleIndices, 5); - expect(source1.shuffleIndices.skipWhile((i) => i != 0).skip(1).first, - equals(1)); - final player1 = AudioPlayer(); - await player1.setAudioSource(source1); - checkIndices(player1.shuffleIndices, 5); - expect(player1.shuffleIndices.first, equals(0)); - await player1.seek(Duration.zero, index: 3); - await player1.shuffle(); - checkIndices(player1.shuffleIndices, 5); - expect(player1.shuffleIndices.first, equals(3)); - - final source2 = createSource(); - final player2 = AudioPlayer(); - await player2.setAudioSource(source2, initialIndex: 3); - checkIndices(player2.shuffleIndices, 5); - expect(player2.shuffleIndices.first, equals(3)); - }); - - test('stop', () async { - final source = ConcatenatingAudioSource( - shuffleOrder: DefaultShuffleOrder(random: Random(1001)), - children: [ - AudioSource.uri( - Uri.parse("https://bar.bar/foo.mp3"), - tag: 'foo', - ), - AudioSource.uri( - Uri.parse("https://baz.baz/bar.mp3"), - tag: 'bar', - ), - ], - ); - final player = AudioPlayer(); - expect(player.processingState, ProcessingState.idle); - await player.setAudioSource(source, preload: false); - expect(player.processingState, ProcessingState.idle); - await player.load(); - expect(player.processingState, ProcessingState.ready); - await player.seek(Duration(seconds: 5), index: 1); - await player.setVolume(0.5); - await player.setSpeed(0.7); - await player.setShuffleModeEnabled(true); - await player.setLoopMode(LoopMode.one); - await player.stop(); - expect(player.processingState, ProcessingState.idle); - expect(player.position, Duration(seconds: 5)); - expect(player.volume, 0.5); - expect(player.speed, 0.7); - expect(player.shuffleModeEnabled, true); - expect(player.loopMode, LoopMode.one); - await player.load(); - expect(player.processingState, ProcessingState.ready); - expect(player.position, Duration(seconds: 5)); - expect(player.volume, 0.5); - expect(player.speed, 0.7); - expect(player.shuffleModeEnabled, true); - expect(player.loopMode, LoopMode.one); - }); - - test('play-load', () async { - for (var delayMs in [0, 100]) { - final player = AudioPlayer(); - player.play(); - if (delayMs != 0) { - await Future.delayed(Duration(milliseconds: delayMs)); - } - expect(player.playing, equals(true)); - expect(player.processingState, equals(ProcessingState.idle)); - await player.setUrl('https://bar.bar/foo.mp3'); - expect(player.processingState, equals(ProcessingState.ready)); - expect(player.playing, equals(true)); - expectDuration(player.position, Duration.zero); - await Future.delayed(Duration(seconds: 1)); - expectDuration(player.position, Duration(seconds: 1)); - await player.dispose(); - } - }); - - test('play-set', () async { - for (var delayMs in [0, 100]) { - final player = AudioPlayer(); - player.play(); - if (delayMs != 0) { - await Future.delayed(Duration(milliseconds: delayMs)); - } - expect(player.playing, equals(true)); - expect(player.processingState, equals(ProcessingState.idle)); - await player.setUrl('https://bar.bar/foo.mp3', preload: false); - expect(player.processingState, equals(ProcessingState.ready)); - expect(player.playing, equals(true)); - expectDuration(player.position, Duration.zero); - await Future.delayed(Duration(seconds: 1)); - expectDuration(player.position, Duration(seconds: 1)); - await player.dispose(); - } - }); - - test('set-play', () async { - final player = AudioPlayer(); - await player.setUrl('https://bar.bar/foo.mp3', preload: false); - expect(player.processingState, equals(ProcessingState.idle)); - expect(player.playing, equals(false)); - player.play(); - expect(player.playing, equals(true)); - await player.processingStateStream - .firstWhere((state) => state == ProcessingState.ready); - expect(player.processingState, equals(ProcessingState.ready)); - expect(player.playing, equals(true)); - expectDuration(player.position, Duration.zero); - await Future.delayed(Duration(seconds: 1)); - expectDuration(player.position, Duration(seconds: 1)); - await player.dispose(); - }); - - test('set-set', () async { - final player = AudioPlayer(); - await player.setAudioSource( - ConcatenatingAudioSource( - children: [ - AudioSource.uri(Uri.parse('https://bar.bar/foo.mp3')), - AudioSource.uri(Uri.parse('https://bar.bar/bar.mp3')), - ], - ), - preload: false, - ); - expect(player.processingState, equals(ProcessingState.idle)); - expect(player.sequence.length, equals(2)); - expect(player.playing, equals(false)); - await player.setAudioSource( - ConcatenatingAudioSource( - children: [ - AudioSource.uri(Uri.parse('https://bar.bar/foo.mp3')), - AudioSource.uri(Uri.parse('https://bar.bar/bar.mp3')), - AudioSource.uri(Uri.parse('https://bar.bar/baz.mp3')), - ], - ), - preload: false, - ); - expect(player.processingState, equals(ProcessingState.idle)); - expect(player.sequence.length, equals(3)); - expect(player.playing, equals(false)); - await player.dispose(); - }); - - test('load-load', () async { - final player = AudioPlayer(); - await player.setAudioSource( - ConcatenatingAudioSource( - children: [ - AudioSource.uri(Uri.parse('https://bar.bar/foo.mp3')), - AudioSource.uri(Uri.parse('https://bar.bar/bar.mp3')), - ], - ), - ); - expect(player.processingState, equals(ProcessingState.ready)); - expect(player.sequence.length, equals(2)); - expect(player.playing, equals(false)); - await player.setAudioSource( - ConcatenatingAudioSource( - children: [ - AudioSource.uri(Uri.parse('https://bar.bar/foo.mp3')), - AudioSource.uri(Uri.parse('https://bar.bar/bar.mp3')), - AudioSource.uri(Uri.parse('https://bar.bar/baz.mp3')), - ], - ), - ); - expect(player.processingState, equals(ProcessingState.ready)); - expect(player.sequence.length, equals(3)); - expect(player.playing, equals(false)); - await player.dispose(); - }); - - test('load-set-load', () async { - final player = AudioPlayer(); - await player.setAudioSource( - ConcatenatingAudioSource( - children: [ - AudioSource.uri(Uri.parse('https://bar.bar/foo.mp3')), - AudioSource.uri(Uri.parse('https://bar.bar/bar.mp3')), - ], - ), - ); - expect(player.processingState, equals(ProcessingState.ready)); - expect(player.sequence.length, equals(2)); - expect(player.playing, equals(false)); - await player.setAudioSource( - ConcatenatingAudioSource( - children: [ - AudioSource.uri(Uri.parse('https://bar.bar/foo.mp3')), - AudioSource.uri(Uri.parse('https://bar.bar/bar.mp3')), - AudioSource.uri(Uri.parse('https://bar.bar/baz.mp3')), - ], - ), - preload: false, - ); - expect(player.processingState, equals(ProcessingState.idle)); - expect(player.sequence.length, equals(3)); - expect(player.playing, equals(false)); - await player.load(); - expect(player.processingState, equals(ProcessingState.ready)); - expect(player.sequence.length, equals(3)); - expect(player.playing, equals(false)); - await player.dispose(); - }); - - test('play-load-load', () async { - final player = AudioPlayer(); - player.play(); await player.setUrl('https://bar.bar/foo.mp3'); - expect(player.processingState, equals(ProcessingState.ready)); - expect(player.playing, equals(true)); - expectDuration(player.position, Duration(seconds: 0)); - await Future.delayed(Duration(seconds: 1)); - expectDuration(player.position, Duration(seconds: 1)); - await player.setUrl('https://bar.bar/bar.mp3'); - expect(player.processingState, equals(ProcessingState.ready)); - expect(player.playing, equals(true)); - expectDuration(player.position, Duration(seconds: 0)); - await Future.delayed(Duration(seconds: 1)); - expectDuration(player.position, Duration(seconds: 1)); - await player.dispose(); - }); - - test('play-load-set-play-load', () async { - final player = AudioPlayer(); - player.play(); + player.stop(); await player.setUrl('https://bar.bar/foo.mp3'); - expect(player.processingState, equals(ProcessingState.ready)); - expect(player.playing, equals(true)); - expectDuration(player.position, Duration(seconds: 0)); - await Future.delayed(Duration(seconds: 1)); - expectDuration(player.position, Duration(seconds: 1)); - player.pause(); - expect(player.playing, equals(false)); - await player.setUrl('https://bar.bar/bar.mp3', preload: false); - expect(player.processingState, equals(ProcessingState.idle)); - expect(player.playing, equals(false)); - // TODO: Decide whether we want player.position to be null here. - expectDuration(player.position ?? Duration.zero, Duration.zero); - await player.load(); - expect(player.processingState, equals(ProcessingState.ready)); - expect(player.playing, equals(false)); - expectDuration(player.position, Duration(seconds: 0)); - player.play(); - expect(player.playing, equals(true)); - expectDuration(player.position, Duration(seconds: 0)); - await Future.delayed(Duration(seconds: 1)); - expectDuration(player.position, Duration(seconds: 1)); - await player.dispose(); }); } @@ -718,6 +725,10 @@ class MockJustAudio extends Mock @override Future init(InitRequest request) async { + if (_players.containsKey(request.id)) + throw PlatformException( + code: "error", + message: "Platform player ${request.id} already exists"); final player = MockAudioPlayer(request.id); _players[request.id] = player; return player; @@ -727,6 +738,7 @@ class MockJustAudio extends Mock Future disposePlayer( DisposePlayerRequest request) async { _players[request.id].dispose(DisposeRequest()); + _players.remove(request.id); return DisposePlayerResponse(); } } diff --git a/just_audio_web/lib/just_audio_web.dart b/just_audio_web/lib/just_audio_web.dart index 99ffa22..8505174 100644 --- a/just_audio_web/lib/just_audio_web.dart +++ b/just_audio_web/lib/just_audio_web.dart @@ -15,12 +15,12 @@ class JustAudioPlugin extends JustAudioPlatform { } Future init(InitRequest request) async { - final player = Html5AudioPlayer(id: request.id); if (players.containsKey(request.id)) { throw PlatformException( code: "error", message: "Platform player ${request.id} already exists"); } + final player = Html5AudioPlayer(id: request.id); players[request.id] = player; return player; }