react-native-track-player icon indicating copy to clipboard operation
react-native-track-player copied to clipboard

[Feature Request] Progress Updates Lag During Buffering

Open MrNapcae opened this issue 2 years ago • 21 comments

Hi there, I'm trying to implement an interface like Apple Podcasts (when you move the slider, the time changes in real time). When I change the position on the slider, TrackPlayer.seekTo(val) does not work instantly, because of this the slider twitches. I am using the @react-native-community/slider library. I tried adjusting the onSlidingStart and onSlidingComplete, and setting setTimeout, it improves the situation, but the twitching still remains. All examples available online also have this problem. Replacing the slider library doesn't solve the problem either. Could you please suggest how this problem is solved? Or maybe there is an example of a correct implementation with a slider? Thanks a lot!

Tested on physical iphone 13 pro max, ios 16.

<Slider value={progress.position} minimumValue={0} maximumValue={progress.duration} minimumTrackTintColor={palette.ACTION_PRIMARY} maximumTrackTintColor={palette.BORD} onSlidingComplete={async (val: number) => { await TrackPlayer.seekTo(value) }} />

Version: "react-native-track-player": "^2.1.3",

System: OS: macOS 12.4 CPU: (8) arm64 Apple M1 Memory: 115.11 MB / 16.00 GB Shell: 5.8.1 - /bin/zsh Binaries: Node: 18.0.0 - /opt/homebrew/bin/node Yarn: 1.22.17 - /opt/homebrew/bin/yarn npm: 8.6.0 - /opt/homebrew/bin/npm Watchman: 2022.03.21.00 - /opt/homebrew/bin/watchman Managers: CocoaPods: 1.11.3 - /usr/local/bin/pod SDKs: iOS SDK: Not Found Android SDK: Not Found IDEs: Android Studio: 2020.3 AI-203.7717.56.2031.7678000 Xcode: /undefined - /usr/bin/xcodebuild Languages: Java: 11.0.16 - /usr/bin/javac npmPackages: @react-native-community/cli: Not Found react: 17.0.2 => 17.0.2 react-native: 0.68.1 => 0.68.1 react-native-macos: Not Found npmGlobalPackages: react-native: Not Found

update -> Answer by gavrichards from the discord. But I didn't manage to solve the bug: "Hey, I have the same thing in my app. I have a boolean state isDragging, which I use to set the value of the slider, like this: const showPosition = isDragging ? draggingPosition : trackPosition;

So if it's dragging, the slider shows the dragging position, otherwise it shows the actual track position. onSlidingStart, I call setIsDragging(true) and set the dragging position. onSlidingComplete, I seek to the new position, and then set a 1 second timeout before calling setIsDragging(false). This is the trick. It keeps the slider position in the dragged position for 1 second until the library then reports the correct new track position."

MrNapcae avatar Aug 21 '22 14:08 MrNapcae

@MrNapcae , I've not seen this issue before, and it doesn't seem to exist in the example project. When I run the example project on an iPhone SE Gen 2 with iOS 15.5 , the progress slider is very smooth.

jspizziri avatar Aug 23 '22 17:08 jspizziri

@MrNapcae, я раньше не встречал эту проблему, и похоже, что ее нет в примере проекта. Когда я запускаю пример проекта на iPhone SE Gen 2 с iOS 15.5, ползунок прогресса работает очень плавно.

Try drag and drop with method TrackPlayer.seekTo(val). When moving quickly, a bug will be noticeable.

The guys in the discord faced this problem, but their solution did not help me. It is based on setTimeOut.

MrNapcae avatar Aug 23 '22 17:08 MrNapcae

https://user-images.githubusercontent.com/1452066/186220652-990b2cbb-80dc-45d7-943c-e0573913bdf0.MOV

Here's a recording of me scrubbing quickly. I see no issues.

jspizziri avatar Aug 23 '22 17:08 jspizziri

If you're able to send me a consistent reproduction of this based off of the example app, I'll take another look at it.

jspizziri avatar Aug 23 '22 17:08 jspizziri

@jspizziri > If you're able to send me a consistent reproduction of this based off of the example app, I'll take another look at it.

the only change I made was to put in a longer video from the internet, duration: 1066 sec https://user-images.githubusercontent.com/42024544/186224425-de08d857-0568-44ef-ac48-9b4f979f441a.MP4

MrNapcae avatar Aug 23 '22 17:08 MrNapcae

@MrNapcae what you're seeing looks like its the result of your audio file buffering. I don't think it has anything to do with the .seekTo being slow like you initially thought. When you scrub to the desired position it takes a few MS to actually buffer the file at that position before playback begins. My recommendation would be to observe the playback state, and if it's loading/buffering pausing the update of your progress bar slider.

Because the progress events are asynchronous between the native code and JS we can't guarantee a progress event won't show up during buffering.

@dcvz it's possible we could solve something like this in the useProgress hook?

jspizziri avatar Aug 23 '22 17:08 jspizziri

@jspizziri Is it possible to download the full audio before playing it in order to avoid this?

MrNapcae avatar Aug 23 '22 17:08 MrNapcae

@MrNapcae yes, you can download and play offline. I'm not 100% sure that will solve your problem, buffering the file from disk should be faster than buffering it from network, it just depends on the speed.

jspizziri avatar Aug 23 '22 17:08 jspizziri

@jspizziri then maybe you can find out the status that buffering is in progress?

MrNapcae avatar Aug 23 '22 17:08 MrNapcae

@MrNapcae I'm not sure what you mean by that.

jspizziri avatar Aug 23 '22 17:08 jspizziri

@jspizziri Is there a way to receive a status that audio file is being loaded and it’s not available for playing yet?

MrNapcae avatar Aug 23 '22 17:08 MrNapcae

@MrNapcae yes, this is what I was mentioning here. Please read the documentation for PlaybackState and usePlaybackState.

jspizziri avatar Aug 23 '22 17:08 jspizziri

@jspizziri Statuses other than none / ready / playing / paused do not come export const PlayPauseButton: React.FC = () => { const state = usePlaybackState(); const isPlaying = state === State.Playing; const isLoading = state === State.Connecting || state === State.Buffering; console.log({state})

LOG Running "example" with {"rootTag":1,"initialProps":{}} LOG {"state": "none"} LOG {"state": "none"} LOG {"state": "connecting"} LOG {"state": "connecting"} LOG {"state": "connecting"} LOG {"state": "ready"} LOG {"state": "ready"} LOG {"state": "playing"} LOG {"state": "playing"} LOG {"state": "paused"} LOG {"state": "paused"} LOG {"state": "playing"} LOG {"state": "playing"} LOG {"state": "paused"} LOG {"state": "paused"} LOG {"state": "playing"} LOG {"state": "playing"} LOG {"state": "paused"} LOG {"state": "paused"} LOG {"state": "paused"} LOG {"state": "paused"}

MrNapcae avatar Aug 23 '22 17:08 MrNapcae

@MrNapcae I don't want to be rude. But there's no way I'm going to read through that massive text dump and try and interpret what you're asking me.

jspizziri avatar Aug 23 '22 17:08 jspizziri

@MrNapcae I don't want to be rude. But there's no way I'm going to read through that massive text dump and try and interpret what you're asking me.

sorry, updated

MrNapcae avatar Aug 23 '22 17:08 MrNapcae

Hi @jspizziri I have the same problem when I go from pause to play the status of the player changes from loading/buffering playing/ready/paused

only on iOS on Android no problems and playing a stream

  url: BASE_URL_STREAM,
  title: 'Radio Gospel',
  artist: 'Radio Gospel',
  contentType: 'audio/mpeg',
  isLiveStream: true,
```

mekaVR avatar Aug 24 '22 07:08 mekaVR

Hi , i have the same issue, i never get State.Buffering, am i missing something? It works with TS v2.1.3 but with any higher versions than that it doesnt.

izyspania avatar Sep 10 '22 22:09 izyspania

@mekaVR @MrNapcae @izyspania

Please try the nightly build which we believe resolves the buffering not being emitted issue.

See here for more detail

https://github.com/doublesymmetry/react-native-track-player/issues/1720#issuecomment-1246485024

jspizziri avatar Sep 14 '22 09:09 jspizziri

To restate the ask in this issue:

With long content, or content that takes a long time buffering, progress updates can seem a bit jumpy. This is likely because after scrubbing but before the new position has been buffered, another progress event is emitted with an old position.

We might be able to check for a buffering state in the useProgess hook before we emit events

jspizziri avatar Sep 14 '22 09:09 jspizziri

@jspizziri Sadly it does exactly the same , no Buffering state. "version": "3.1.0-7b247404c2b54df0550379277949a1cab5ddf47c",

izyspania avatar Sep 14 '22 15:09 izyspania

@izyspania we'll deal with the bug on the dedicated bug ticket. Let's keep this discussion moving forward just to the feature request.

jspizziri avatar Sep 14 '22 15:09 jspizziri