Skip to content

Commit 5d164d1

Browse files
authored
fix: Timeout on setting same source twice (#1520)
# Description When setting the same source twice for a player, the `onPrepared` event was not sent on most platform implementations. Also fixing listening and canceling event stream on Android multiple times.
1 parent 9f39e95 commit 5d164d1

6 files changed

Lines changed: 77 additions & 11 deletions

File tree

packages/audioplayers/example/integration_test/lib_test.dart

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ void main() {
2121
final isAndroid = !kIsWeb && Platform.isAndroid;
2222
final isLinux = !kIsWeb && Platform.isLinux;
2323

24+
// FIXME(gustl22): Cannot reuse event channel with same id on Linux (flutter/flutter#126209)
25+
var linuxPlayerCount = 0;
26+
2427
final wavUrl1TestData = LibSourceTestData(
2528
source: UrlSource(wavUrl1),
2629
duration: const Duration(milliseconds: 451),
@@ -245,8 +248,7 @@ void main() {
245248
testWidgets('Emit platform log', (tester) async {
246249
final logCompleter = Completer<String>();
247250

248-
// FIXME(gustl22): Cannot reuse event channel with same id on Linux (flutter/flutter#126209)
249-
final playerId = isLinux ? 'somePlayerId0' : 'somePlayerId';
251+
final playerId = 'somePlayerId${isLinux ? linuxPlayerCount++ : ''}';
250252
final player = AudioPlayer(playerId: playerId);
251253
final onLogSub = player.onLog.listen(
252254
logCompleter.complete,
@@ -331,8 +333,7 @@ void main() {
331333
testWidgets('#create and #dispose', (tester) async {
332334
final platform = AudioplayersPlatformInterface.instance;
333335

334-
// FIXME(gustl22): Cannot reuse event channel with same id on Linux (flutter/flutter#126209)
335-
final playerId = isLinux ? 'somePlayerId1' : 'somePlayerId';
336+
final playerId = 'somePlayerId${isLinux ? linuxPlayerCount++ : ''}';
336337
await platform.create(playerId);
337338
await tester.pumpAndSettle();
338339
await platform.dispose(playerId);
@@ -353,8 +354,7 @@ void main() {
353354
testWidgets('#setSource #getPosition and #getDuration', (tester) async {
354355
final platform = AudioplayersPlatformInterface.instance;
355356

356-
// FIXME(gustl22): Cannot reuse event channel with same id on Linux (flutter/flutter#126209)
357-
final playerId = isLinux ? 'somePlayerId2' : 'somePlayerId';
357+
final playerId = 'somePlayerId${isLinux ? linuxPlayerCount++ : ''}';
358358
await platform.create(playerId);
359359

360360
final preparedCompleter = Completer<void>();
@@ -392,10 +392,65 @@ void main() {
392392
await platform.dispose(playerId);
393393
}
394394
});
395+
396+
testWidgets('Set same source twice (#1520)', (tester) async {
397+
final platform = AudioplayersPlatformInterface.instance;
398+
399+
final playerId = 'somePlayerId${isLinux ? linuxPlayerCount++ : ''}';
400+
await platform.create(playerId);
401+
402+
final eventStream = platform.getEventStream(playerId);
403+
for (var i = 0; i < 2; i++) {
404+
final preparedCompleter = Completer<void>();
405+
final onPreparedSub = eventStream
406+
.where((event) => event.eventType == AudioEventType.prepared)
407+
.map((event) => event.isPrepared!)
408+
.listen(
409+
(isPrepared) {
410+
if (isPrepared) {
411+
preparedCompleter.complete();
412+
}
413+
},
414+
onError: preparedCompleter.completeError,
415+
);
416+
if (isLinux) {
417+
// FIXME(gustl22): Linux needs additional pump (#1507)
418+
await tester.pump();
419+
}
420+
await platform.setSourceUrl(
421+
playerId,
422+
(wavUrl1TestData.source as UrlSource).url,
423+
);
424+
await preparedCompleter.future.timeout(const Duration(seconds: 30));
425+
await onPreparedSub.cancel();
426+
}
427+
if (!isLinux) {
428+
// FIXME(gustl22): Linux not disposing properly (#1507)
429+
await platform.dispose(playerId);
430+
}
431+
});
395432
});
396433

397434
group('Platform event channel', () {
398-
// TODO(gustl22): remove once https://github.com/flutter/flutter/issues/126209 is fixed
435+
testWidgets('Listen and cancel twice', (tester) async {
436+
final platform = AudioplayersPlatformInterface.instance;
437+
438+
final playerId = 'somePlayerId${isLinux ? linuxPlayerCount++ : ''}';
439+
await platform.create(playerId);
440+
441+
final eventStream = platform.getEventStream(playerId);
442+
for (var i = 0; i < 2; i++) {
443+
final eventSub = eventStream.listen(null);
444+
await eventSub.cancel();
445+
}
446+
if (!isLinux) {
447+
// FIXME(gustl22): Linux not disposing properly (#1507)
448+
await platform.dispose(playerId);
449+
}
450+
});
451+
452+
// TODO(gustl22): remove once https://github.com/flutter/flutter/issues/126209
453+
// is fixed, as tests should cover the problem in flutter engine.
399454
testWidgets(
400455
'Reuse same platform event channel id',
401456
(tester) async {
@@ -425,8 +480,7 @@ void main() {
425480
final errorCompleter = Completer<Object>();
426481
final platform = AudioplayersPlatformInterface.instance;
427482

428-
// FIXME(gustl22): Cannot reuse event channel with same id on Linux (flutter/flutter#126209)
429-
final playerId = isLinux ? 'somePlayerId3' : 'somePlayerId';
483+
final playerId = 'somePlayerId${isLinux ? linuxPlayerCount++ : ''}';
430484
await platform.create(playerId);
431485

432486
final eventStreamSub = platform

packages/audioplayers_android/android/src/main/kotlin/xyz/luan/audioplayers/AudioplayersPlugin.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,6 @@ class EventHandler(private val eventChannel: EventChannel) : EventChannel.Stream
353353

354354
override fun onCancel(arguments: Any?) {
355355
eventSink = null
356-
eventChannel.setStreamHandler(null)
357356
}
358357

359358
fun success(method: String, arguments: Map<String, Any> = HashMap()) {
@@ -369,5 +368,6 @@ class EventHandler(private val eventChannel: EventChannel) : EventChannel.Stream
369368
it.endOfStream()
370369
onCancel(null)
371370
}
371+
eventChannel.setStreamHandler(null)
372372
}
373373
}

packages/audioplayers_android/android/src/main/kotlin/xyz/luan/audioplayers/player/WrappedPlayer.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ class WrappedPlayer internal constructor(
3434
playing = false
3535
player?.release()
3636
}
37+
} else {
38+
ref.handlePrepared(this, true)
3739
}
3840
}
3941

packages/audioplayers_linux/linux/audio_player.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ void AudioPlayer::SetSourceUrl(std::string url) {
7272
}
7373
}
7474
}
75+
} else {
76+
this->OnPrepared(true);
7577
}
7678
}
7779

packages/audioplayers_web/lib/wrapped_player.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,13 @@ class WrappedPlayer {
3030

3131
Future<void> setUrl(String url) async {
3232
if (_currentUrl == url) {
33-
return; // nothing to do
33+
eventStreamController.add(
34+
const AudioEvent(
35+
eventType: AudioEventType.prepared,
36+
isPrepared: true,
37+
),
38+
);
39+
return;
3440
}
3541
_currentUrl = url;
3642

packages/audioplayers_windows/windows/audio_player.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ void AudioPlayer::SetSourceUrl(std::string url) {
6969
// Forward errors to event stream, as this is called asynchronously
7070
this->OnError("WindowsAudioError", "Error setting url to '" + url + "'.", nullptr);
7171
}
72+
} else {
73+
OnPrepared(true);
7274
}
7375
}
7476

0 commit comments

Comments
 (0)