React-native-track-player: [iOS] playback-state sometimes returns 'ready' but the audio is playing

Created on 7 May 2019  路  6Comments  路  Source: react-native-kit/react-native-track-player

Configuration

[email protected]
react-native info:

React Native Environment Info:
    System:
      OS: macOS 10.14.4
      CPU: (8) x64 Intel(R) Core(TM) i7-4850HQ CPU @ 2.30GHz
      Memory: 55.21 MB / 16.00 GB
      Shell: 5.3 - /bin/zsh
    Binaries:
      Node: 12.1.0 - /usr/local/bin/node
      Yarn: 1.15.2 - /usr/local/bin/yarn
      npm: 6.9.0 - /usr/local/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    SDKs:
      iOS SDK:
        Platforms: iOS 12.1, macOS 10.14, tvOS 12.1, watchOS 5.1
    IDEs:
      Android Studio: 3.4 AI-183.5429.30.34.5452501
      Xcode: 10.1/10B61 - /usr/bin/xcodebuild
    npmPackages:
      react: 16.6.3 => 16.6.3
      react-native: 0.57.8 => 0.57.8
    npmGlobalPackages:
      react-native-cli: 2.0.1

Issue

The playback-state listener will constantly update whenever the track player changes playback state, however occasionally it will return ready and while the track player is playing audio and not return a playing state.

This is a problem because we should be relying on this listener to be the source of truth for the playback state otherwise playback buttons on the UI will be out of sync with what's really going on.

Code

TrackPlayer.addEventListener('playback-state', 
  async (data) => {
    console.log('playback-state: ', data.state)
    store.dispatch(updatePlaybackState(data.state));
  }
)

When we have a queue of 2 tracks. When the first track ends the usual result is:

playback-state:  loading
playback-state:  paused
playback-state:  ready
playback-state:  playing

However there is some sort of race condition going on because sometimes under the same situation I get this result:

playback-state:  loading
playback-state:  paused
playback-state:  ready

In both scenarios the audio is playing, so the the playback-state should be emitted with a playing state.

I don't have much more information than that. Writing this up so I don't lose track of it and to see if others are experiencing this as well or any thoughts on what might be going on here. When I get time I'll test it out on the latest 1.1.4 and try to put together a simplified repro to narrow down what's the cause

As always thanks for maintaining this repo!

iOS

Most helpful comment

We currently have this issue as well, version 1.1.8

All 6 comments

I'm having this same situation, did you find a fix for this?

We currently have this issue as well, version 1.1.8

I am seeing the same behavior. In addition, sometimes I get:

loading
playing
ready

Similar to other cases, the track is playing, but the last state reported is ready.

Why is ready coming through AFTER playing? @dcvz

I think this is related to the single value reported as the playback-state is actually related to 2 different values of the swift AVPlayer. Both AVPlayer.timeControlStatus and AVPlayer.Status are being observed, and both change when a track starts playing.

This bug is still happening in v1.2.6. For me it happens about 3/4 times after skip / skipToNext / skipToPrevious but only when the function is called rapidly at least twice within about 500-100ms. I'd assume it seems to be a race-condition where the state-updates from different skip- (and possibly seek-)actions interfere with eachother or similar.

Another state, the hook returns falsy (ios only) is 'buffering' which is an undocumented state and not equal to RNTrackplayer.STATE_BUFFERING which is equal to 'loading' on ios.

the falsy states ('ready' and 'buffering') are set after the state 'playing' while the player keeps on playing as normal.

This might also be caused by seeking right after skipping, which I currently do to implement the 'continue-listening-at-the-last-position'-functionality. I will try and find out more about this soon.

Strangely it only happens on physical device (iPhone XR and others) and not on the simulator.

Still present on v1.2.7. A call to play (in my apps case pressing the play button) corrects the issue but it is a rather annoying bug. Occurs in both background mode and with the app foregrounded.

WORK AROUND SOLUTION: After a few minutes of putting on my critical thinking cap and after the first paragraph was written I came up with the following and it seems to have completely abated the problem.

Using the useTrackPlayerEvents hook listen for PLAYBACK_TRACK_CHANGED, then call TrackPlayer.play()

useTrackPlayerEvents(events, (event) => {
    if (event.type === TrackPlayerEvents.PLAYBACK_TRACK_CHANGED) {
       TrackPlayer.play();
    }
};
Was this page helpful?
0 / 5 - 0 ratings