just_audio icon indicating copy to clipboard operation
just_audio copied to clipboard

Inconsistent SequenceState -> RangeError on accessing `effectiveSequence`

Open Coronon opened this issue 2 years ago • 7 comments

Which API doesn't behave as documented, and how does it misbehave? The sequenceStateStream emits inconsistent SequenceState instances. When I switch between two shuffled playlists (ConcatenatingAudioSource) the sequenceStateStream emits a SequenceState where calling effectiveSequence will throw when the new AudioSource is shorter than the old one. This is because the SequenceState.shuffleIndices will still contain the old indices (in my case 164) and SequenceState.sequence the actual new AudioSources (in my case 48). When using the shuffleIndices.map((i) => sequence[i]) this will result in an error like this:

RangeError (RangeError (index): Invalid value: Not in inclusive range 0..47: 91)

Minimal reproduction project My play function boils down to this (without any UI code):

  /// Play a list of [Song] optionally starting at [initial] **OR** [shuffle]d
  /// from [source] list
  ///
  /// Internally used to reduce code duplication
  Future<void> _play(
    List<Song> songs, {
    String? source,
    int? initial,
    bool shuffle = false,
  }) async {
    // Only initial song OR shuffled is allowed
    assert((initial == null && shuffle) || (initial != null && !shuffle));

    // Generate AudioSource's from Song's
    final audioSources = _songsToAudiSources(
      songs,
      source: source,
      shuffled: shuffle,
    );

    // Handle shuffle (we need to shuffle the audioSources directly because the
    // first song would always stay the same) (it would stay to allow manual
    // selection of single song while in shuffle mode)
    if (shuffle) audioSources.shuffle();
    await player.setShuffleModeEnabled(shuffle);

    // Prepare playlist
    final playlist = ConcatenatingAudioSource(
      useLazyPreparation: true,
      shuffleOrder: DefaultShuffleOrder(),
      children: audioSources,
    );

    // Set playlist and play
    await player.setAudioSource(
      playlist,
      initialIndex: initial,
      initialPosition: Duration.zero,
    );
    // ignore: unawaited_futures
    player.play();

My sequenceStateStream callback (attached using .listen:

@action // <--- I am using MobX, but this should not result in an inconsistent `SequenceState` where all fields are `final`
void setSequenceState(SequenceState? sequenceState) {
    if (sequenceState == null) {
      return;
    }

    effectiveSequence = sequenceState.effectiveSequence; // <--- This will throw!
    // ...
   
}

To Reproduce (i.e. user steps, not code) Steps to reproduce the behavior:

  1. Play a number of songs shuffled
  2. Play another smaller number of songs shuffled
  3. Access SequenceState.effectiveSequence in a callback attached to sequenceStateStream

Error messages

RangeError (RangeError (index): Invalid value: Not in inclusive range 0..47: 91)

Expected behavior The SequenceState is consistent and the shuffleIndices match sequence.

Screenshots N.a.

Smartphone (please complete the following information):

  • Device: iPhone 14 Pro Max
  • OS: iOS 14.6

Flutter SDK version

[✓] Flutter (Channel stable, 3.7.8, on macOS 12.5.1 21G83 darwin-x64, locale de-DE)
[✗] Android toolchain - develop for Android devices
    ✗ Unable to locate Android SDK.
      Install Android Studio from: https://developer.android.com/studio/index.html
      On first launch it will assist you in installing the Android SDK components.
      (or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).
      If the Android SDK has been installed to a custom location, please use
      `flutter config --android-sdk` to update to that location.

[✓] Xcode - develop for iOS and macOS (Xcode 14.1)
[!] Android Studio (not installed)
[✓] VS Code (version 1.78.0)
[✓] Connected device (1 available)
    ! Error: IOS is busy: Fetching debug symbols for IOS. Xcode will continue when IOS is finished. (code -10)
[✓] HTTP Host Availability

! Doctor found issues in 2 categories.

Coronon avatar May 07 '23 20:05 Coronon

@Coronon Have you found a workaround for this issue? I get the same error when trying to load a new playlist.

kaciula avatar May 23 '24 09:05 kaciula

This bug report doesn't have a minimal reproduction project (as per the instructions). Who would like to provide one?

ryanheise avatar May 23 '24 09:05 ryanheise

No, sadly I have not :( My app is currently in maintenance mode and not really being actively developed right now. I also currently don't have the time to build a minimal reproducible example - sorry.

Coronon avatar May 26 '24 21:05 Coronon

@ryanheise I've created a demo project where you can see this issue.

https://github.com/kaciula/just_audio_sequence_bug

Start playing the long shuffled playlist first and then start playing the short shuffled playlist and you'll see the error in the logs. It happens on both Android and iOS.

Let me know if you need anything else from me.

kaciula avatar Jun 15 '24 05:06 kaciula

@ryanheise Please let me know if you intend to work on this issue in the near future based on the demo project I've linked above. I want to know if I should switch to implementing my own shuffle logic to avoid this bug.

kaciula avatar Jul 01 '24 08:07 kaciula

It turns out that even a manual shuffle logic does not resolve this issue. Rearranging tracks from a playlist triggers a similar bug in just_audio_background plugin.

[RangeError (index): Invalid value: Only valid value is 0: 7] #0 List.[] (dart:core-patch/growable_array.dart:264:36) #1 AudioSourceExtension.shuffleIndices (package:just_audio_background/just_audio_background.dart:904:40) #2 _PlayerAudioHandler._updateShuffleIndices (package:just_audio_background/just_audio_background.dart:589:32) #3 _PlayerAudioHandler.customConcatenatingRemoveRange (package:just_audio_background/just_audio_background.dart:524:5) #4 _JustAudioPlayer.concatenatingRemoveRange (package:just_audio_background/just_audio_background.dart:306:27) #5 ConcatenatingAudioSource.removeRange (package:just_audio/just_audio.dart:2644:40) <asynchronous suspension>

kaciula avatar Jul 01 '24 09:07 kaciula

I'm having this problem, is there any solution?

imagination24 avatar Dec 31 '24 01:12 imagination24