Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[iOS] unable to resume track after first play #1225

Closed
AdamSheaHewett opened this issue Aug 11, 2021 · 12 comments
Closed

[iOS] unable to resume track after first play #1225

AdamSheaHewett opened this issue Aug 11, 2021 · 12 comments
Assignees

Comments

@AdamSheaHewett
Copy link

Describe the bug
On iOS, it seems that TrackPlayer.stop() clears the queue and also sets the state to State.None

I add a track as normal, and am able to play it, but the moment I use the stop() function, the queue is cleared, state is State.None, and the player just stops working.

To Reproduce
Using v2.0.0 on iOS, add a track, TrackPlayer.play(), TrackPlayer.stop(), then try to TrackPlayer.play() again. It won't work.

Environment (please complete the following information):

  • react-native-track-player version 2.0.0
  • Testing on iOS simulator
    System:
    OS: macOS 11.5.1
    CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
    Memory: 233.77 MB / 16.00 GB
    Shell: 5.8 - /bin/zsh
    Binaries:
    Node: 14.15.4 - ~/.nvm/versions/node/v14.15.4/bin/node
    Yarn: 1.22.10 - ~/.nvm/versions/node/v14.15.4/bin/yarn
    npm: 6.14.10 - ~/.nvm/versions/node/v14.15.4/bin/npm
    Watchman: 2021.06.07.00 - /usr/local/bin/watchman
    Managers:
    CocoaPods: 1.10.1 - /usr/local/bin/pod
    SDKs:
    iOS SDK:
    Platforms: iOS 14.5, DriverKit 20.4, macOS 11.3, tvOS 14.5, watchOS 7.4
    Android SDK: Not Found
    IDEs:
    Android Studio: 2020.3 AI-203.7717.56.2031.7583922
    Xcode: 12.5.1/12E507 - /usr/bin/xcodebuild
    Languages:
    Java: 11.0.11 - /usr/bin/javac
    npmPackages:
    @react-native-community/cli: Not Found
    react: 17.0.2 => 17.0.2
    react-native: 0.64.1 => 0.64.1
    react-native-macos: Not Found
    npmGlobalPackages:
    react-native: Not Found

Code
Please, share the code that is causing the issue

// Play button
await TrackPlayer.add(url);
await TrackPlayer.play(); // Plays fine

// Stop button
await TrackPlayer.stop();
const tracks: Track[] = await playControls.getQueue();
console.log('queue', tracks); // []

This only happens on iOS

@dcvz
Copy link
Contributor

dcvz commented Aug 11, 2021

Hi @AdamSheaHewett 👋 you seem to be correct.
It looks like there's a mismatch between the docs and what iOS does.

I'll try to take a look sometime in the next days, in the meantime does pausing and seeking to start work for you?

@AdamSheaHewett
Copy link
Author

AdamSheaHewett commented Aug 11, 2021

Yes, pausing works, and I put in a hacky function that syncs the state's playlist with the TrackPlayer queue if the queue is corrupted:

const currentTrack = await TrackPlayer.getCurrentTrack();
...
export function stop() {
  return new Promise<void>((resolve, reject) => {

    TrackPlayer.stop()
      .then(async () => {
        const tracks: Track[] = await TrackPlayer.getQueue();

        const state = UIStore.getRawState();

        if (!isEqual(tracks, state.currentPlaylist)) {
          // Re-add the playlist to the trackplayer queue
          TrackPlayer.add(state.currentPlaylist);

          // Attempt to keep the user at the same index
          if (currentTrack >= 0) TrackPlayer.skip(currentTrack);
        }

        resolve();
      })
      .catch((reason: any) => {
        reject(reason);
      });
  });
}

@AdamSheaHewett
Copy link
Author

@dcvz any updates on this bug? If it's fixed I'd like to stop manually checking if state matches the playlist queue.

@rborn
Copy link

rborn commented Oct 18, 2021

@AdamSheaHewett the bug is still here, thanks for your workaround ❤️

@bradfloodx
Copy link
Collaborator

Thanks for reporting this.

@AdamSheaHewett and @rborn are you able to investigate and/or create a PR to fix this? Would love some extra help.

Cheers

@rborn
Copy link

rborn commented Jan 14, 2022

@bradleyflood I only implemented a version of the hack above, which is a "hack" 😅. Probably this should be fixed at the native level? (an my native-fu is nonexistent 😞)

@bradfloodx
Copy link
Collaborator

Ok thanks @rborn

Perhaps you can help via #1379 ? Cheers

@jspizziri
Copy link
Collaborator

jspizziri commented Apr 30, 2022

@dcvz I can confirm this behavior. Here's a breakdown of the issue:

iOS (v1.2.7 & current)

  1. TrackPlayer.stop() callsQueuedAudioPlayer.stop()
  2. QueuedAudioPlayer.stop() calls AudioPlayer.stop()
  3. AudioPlayer.stop() calls AudioPlayer.reset()
  4. QueuedAudioPlayer.reset() resets the queue clearing all tracks.

So, from that perspective this almost seems like intended behavior. But the documentation doesn't mention anything about clearing the queue.. So I looked at what Kotlin was doing.

Kotlin

Kotlin simply calls pause, meaning stop is really just an alias. This certainly lines up more with the documentation, so I assumed that iOS was just wrong. But I looked at Android just in case.

Note: after further review, I believe Kotlin is behaving correctly.

Android

  1. TrackPlayer.stop called MusicModule.stop
  2. MusicModule.stop called ExoPlayback.stop

Moreover, it doesn't seem that in this case reset is called. Nor does it seem that reset in android messed with the queue at all.

Conclusion

I guess my big question is: How should it work (in a way that's non-breaking)? From my limited perspective, it seems that:

  1. iOS should be made to call pause as that behavior seems in line with both the docs and how I understand both Kotlin & Android work/worked.
  2. All else should be left the same. Effectively, JS stop means pause and native stop means reset and should be called in those contexts.

At this point, I'm relatively convinced this is the correct approach, so I have opened a PR to this effect. LMK if you disagree.

jspizziri added a commit to 5-stones/react-native-track-player that referenced this issue Apr 30, 2022
…ame as the Android API for stop

additionally, fix an issue with Event.PlaybackProgressUpdated causing exceptions when fired after
certain queue manipulations

doublesymmetry#1225
@jspizziri
Copy link
Collaborator

@AdamSheaHewett FYI

  1. A solution is in progress.
  2. In the meantime, just call pause instead of reset. Based on my investigation they are functionally identical (see comment above).

@AdamSheaHewett
Copy link
Author

@AdamSheaHewett FYI

  1. A solution is in progress.
  2. In the meantime, just call pause instead of reset. Based on my investigation they are functionally identical (see comment above).

Fantastic news. Please let us know when the solution is released.

@bradfloodx
Copy link
Collaborator

@dcvz Can you confirm on this logic above?

@jspizziri Has created a PR fix for this which would be sweet to get into production if the above logic is correct.

jspizziri added a commit that referenced this issue May 17, 2022
…ame as the Android API for stop (#1529)

additionally, fix an issue with Event.PlaybackProgressUpdated causing exceptions when fired after
certain queue manipulations

#1225
@jspizziri
Copy link
Collaborator

All, this fix was merged. Now we just need a new release 😁 so I'm going to close this issue. ✌️

hlieb53 added a commit to hlieb53/react-native-track-player that referenced this issue Nov 9, 2023
…ame as the Android API for stop (#1529)

additionally, fix an issue with Event.PlaybackProgressUpdated causing exceptions when fired after
certain queue manipulations

doublesymmetry/react-native-track-player#1225
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

No branches or pull requests

5 participants