@@ -57,6 +57,7 @@ JustAudioPlatform get _pluginPlatform {
57
57
/// player, including any temporary files created to cache assets.
58
58
class AudioPlayer {
59
59
static String _generateId () => _uuid.v4 ();
60
+ final _lock = Lock ();
60
61
61
62
/// The user agent to set on all HTTP requests.
62
63
final String ? _userAgent;
@@ -279,7 +280,7 @@ class AudioPlayer {
279
280
.pairwise ()
280
281
.listen ((rec) {
281
282
if (_seeking) return ;
282
- final [(prevEvent, prevSource), (currEvent, currSource)] = rec;
283
+ final [(prevEvent, prevSource), (currEvent, currSource)] = rec. toList () ;
283
284
if (prevSource == null || currSource == null ) return ;
284
285
if (currSource._id != prevSource._id) {
285
286
// If we've changed item without seeking, it must be an autoAdvance.
@@ -447,7 +448,7 @@ class AudioPlayer {
447
448
AudioSource ? get audioSource => _playlist.children.firstOrNull;
448
449
449
450
/// The latest [PlaybackEvent] .
450
- PlaybackEvent get playbackEvent => _playbackEventSubject.value ;
451
+ PlaybackEvent get playbackEvent => _playbackEventSubject.nvalue ! ;
451
452
452
453
/// A stream of [PlaybackEvent] s.
453
454
Stream <PlaybackEvent > get playbackEventStream => _playbackEventSubject.stream;
@@ -520,14 +521,14 @@ class AudioPlayer {
520
521
Stream <PlayerState > get playerStateStream => _playerStateSubject.stream;
521
522
522
523
/// The current sequence of indexed audio sources.
523
- List <IndexedAudioSource > get sequence => _sequenceSubject.value ;
524
+ List <IndexedAudioSource > get sequence => _sequenceSubject.nvalue ! ;
524
525
525
526
/// A stream broadcasting the current sequence of indexed audio sources.
526
527
Stream <List <IndexedAudioSource >> get sequenceStream =>
527
528
_sequenceSubject.stream;
528
529
529
530
/// The current shuffled sequence of indexed audio sources.
530
- List <int > get shuffleIndices => _shuffleIndicesSubject.value ;
531
+ List <int > get shuffleIndices => _shuffleIndicesSubject.nvalue ! ;
531
532
532
533
/// A stream broadcasting the current shuffled sequence of indexed audio
533
534
/// sources.
@@ -541,7 +542,7 @@ class AudioPlayer {
541
542
Stream <int ?> get currentIndexStream => _currentIndexSubject.stream;
542
543
543
544
/// The current [SequenceState] .
544
- SequenceState get sequenceState => _sequenceStateSubject.value ;
545
+ SequenceState get sequenceState => _sequenceStateSubject.nvalue ! ;
545
546
546
547
/// A stream broadcasting the current [SequenceState] .
547
548
Stream <SequenceState > get sequenceStateStream => _sequenceStateSubject.stream;
@@ -1068,11 +1069,11 @@ class AudioPlayer {
1068
1069
// Broadcast to clients immediately, but revert to false if we fail to
1069
1070
// activate the audio session. This allows setAudioSource to be aware of a
1070
1071
// prior play request.
1072
+ _playingSubject.add (true );
1071
1073
_playbackEventSubject.add (playbackEvent.copyWith (
1072
1074
updatePosition: position,
1073
1075
updateTime: DateTime .now (),
1074
1076
));
1075
- _playingSubject.add (true );
1076
1077
final playCompleter = Completer <dynamic >();
1077
1078
final audioSession = await AudioSession .instance;
1078
1079
if (! _handleAudioSessionActivation || await audioSession.setActive (true )) {
@@ -1108,11 +1109,11 @@ class AudioPlayer {
1108
1109
if (! playing) return ;
1109
1110
_playInterrupted = false ;
1110
1111
// Update local state immediately so that queries aren't surprised.
1112
+ _playingSubject.add (false );
1111
1113
_playbackEventSubject.add (playbackEvent.copyWith (
1112
1114
updatePosition: position,
1113
1115
updateTime: DateTime .now (),
1114
1116
));
1115
- _playingSubject.add (false );
1116
1117
// TODO: perhaps modify platform side to ensure new state is broadcast
1117
1118
// before this method returns.
1118
1119
await (await _platform).pause (PauseRequest ());
@@ -1373,61 +1374,64 @@ class AudioPlayer {
1373
1374
1374
1375
/// Releases all resources associated with this player. You must invoke this
1375
1376
/// after you are done with the player.
1376
- Future <void > dispose () async {
1377
- if (_disposed) return ;
1378
- _disposed = true ;
1379
- if (_nativePlatform != null ) {
1380
- await _disposePlatform (await _nativePlatform! );
1381
- _nativePlatform = null ;
1382
- }
1383
- if (_idlePlatform != null ) {
1384
- await _disposePlatform (_idlePlatform! );
1385
- _idlePlatform = null ;
1386
- }
1387
- _playlist.children.clear ();
1388
- for (var s in _audioSources.values) {
1389
- s._dispose ();
1390
- }
1391
- _audioSources.clear ();
1392
- _proxy.stop ();
1393
- await _playerDataSubscription? .cancel ();
1394
- await _playbackEventSubscription? .cancel ();
1395
- await _androidAudioAttributesSubscription? .cancel ();
1396
- await _becomingNoisyEventSubscription? .cancel ();
1397
- await _interruptionEventSubscription? .cancel ();
1398
- await _positionDiscontinuitySubscription? .cancel ();
1399
- await _currentIndexSubscription? .cancel ();
1400
- await _errorsSubscription? .cancel ();
1401
- await _errorsResetSubscription? .cancel ();
1402
-
1403
- await _playbackEventSubject.close ();
1404
- await _sequenceStateSubject.close ();
1405
- await _playingSubject.close ();
1406
- await _volumeSubject.close ();
1407
- await _speedSubject.close ();
1408
- await _pitchSubject.close ();
1409
-
1410
- await Future <void >.delayed (Duration .zero);
1411
- await _durationSubject.close ();
1412
- await _processingStateSubject.close ();
1413
- await _bufferedPositionSubject.close ();
1414
- await _icyMetadataSubject.close ();
1415
- await _androidAudioSessionIdSubject.close ();
1416
- await _errorSubject.close ();
1417
- await _playerStateSubject.close ();
1418
- await _skipSilenceEnabledSubject.close ();
1419
- await _positionDiscontinuitySubject.close ();
1420
- await _sequenceSubject.close ();
1421
- await _shuffleIndicesSubject.close ();
1422
- await _currentIndexSubject.close ();
1423
- await _loopModeSubject.close ();
1424
- await _shuffleModeEnabledSubject.close ();
1425
- await _shuffleModeEnabledSubject.close ();
1426
-
1427
- if (playbackEvent.processingState != ProcessingState .idle) {
1428
- _playbackEventSubject
1429
- .add (playbackEvent.copyWith (processingState: ProcessingState .idle));
1430
- }
1377
+ Future <void > dispose () {
1378
+ return _lock.synchronized (() async {
1379
+ if (_disposed) return ;
1380
+ await stop ();
1381
+ _disposed = true ;
1382
+ if (_nativePlatform != null ) {
1383
+ await _disposePlatform (await _nativePlatform! );
1384
+ _nativePlatform = null ;
1385
+ }
1386
+ if (_idlePlatform != null ) {
1387
+ await _disposePlatform (_idlePlatform! );
1388
+ _idlePlatform = null ;
1389
+ }
1390
+ _playlist.children.clear ();
1391
+ for (var s in _audioSources.values) {
1392
+ s._dispose ();
1393
+ }
1394
+ _audioSources.clear ();
1395
+ _proxy.stop ();
1396
+ await _playerDataSubscription? .cancel ();
1397
+ await _playbackEventSubscription? .cancel ();
1398
+ await _androidAudioAttributesSubscription? .cancel ();
1399
+ await _becomingNoisyEventSubscription? .cancel ();
1400
+ await _interruptionEventSubscription? .cancel ();
1401
+ await _positionDiscontinuitySubscription? .cancel ();
1402
+ await _currentIndexSubscription? .cancel ();
1403
+ await _errorsSubscription? .cancel ();
1404
+ await _errorsResetSubscription? .cancel ();
1405
+
1406
+ await _playbackEventSubject.close ();
1407
+ await _sequenceStateSubject.close ();
1408
+ await _playingSubject.close ();
1409
+ await _volumeSubject.close ();
1410
+ await _speedSubject.close ();
1411
+ await _pitchSubject.close ();
1412
+
1413
+ await Future <void >.delayed (Duration .zero);
1414
+ await _durationSubject.close ();
1415
+ await _processingStateSubject.close ();
1416
+ await _bufferedPositionSubject.close ();
1417
+ await _icyMetadataSubject.close ();
1418
+ await _androidAudioSessionIdSubject.close ();
1419
+ await _errorSubject.close ();
1420
+ await _playerStateSubject.close ();
1421
+ await _skipSilenceEnabledSubject.close ();
1422
+ await _positionDiscontinuitySubject.close ();
1423
+ await _sequenceSubject.close ();
1424
+ await _shuffleIndicesSubject.close ();
1425
+ await _currentIndexSubject.close ();
1426
+ await _loopModeSubject.close ();
1427
+ await _shuffleModeEnabledSubject.close ();
1428
+ await _shuffleModeEnabledSubject.close ();
1429
+
1430
+ if (playbackEvent.processingState != ProcessingState .idle) {
1431
+ _playbackEventSubject
1432
+ .add (playbackEvent.copyWith (processingState: ProcessingState .idle));
1433
+ }
1434
+ });
1431
1435
}
1432
1436
1433
1437
/// Switches to using the native platform when [active] is `true` and using the
0 commit comments