ryanheise / just_audio

Audio Player
1.01k stars 620 forks source link

[just_audio] iOS isn't reconnecting to live streams, but Android does. #1277

Open bypass112 opened 6 days ago

bypass112 commented 6 days ago

Which API doesn't behave as documented, and how does it misbehave?

Minimal reproduction project Provide a link here using one of two options:

  1. Fork this repository: https://github.com/bypass112/just_audio, or the main one.
  2. Run the just_audio/example project. It has already the live stream link and the modifications to the onItemStalled. If it uses the main one for testing use one of the above streaming links, like: https://stream-uk1.radioparadise.com/aac-320

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

  1. Start an iOS 17+ simulator and the stream playback.
  2. Disconnect from the internet (either with Network Link Conditioner set to 100% loss, or disconnect the PC). The simulator must think all this time it is still connected to WiFi, so we can simulate package losses through the network for poor conditions.
  3. Wait for onItemStalled to trigger, you can see it in the log.
  4. Wait for onFailToComplete to trigger, you can see it in the log.
  5. Reconnect to the internet.
  6. The stream won't recover after onFailToComplete triggers.

Error messages

onItemStalled
onFailToComplete

Expected behavior Similar to the ExoPlayer Android native side, iOS AVPlayer should also reconnect automatically, regardless of how much the player stays in buffer mode.

Smartphone (please complete the following information):

Flutter SDK version

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.16.8, on macOS 14.0 23A344 darwin-arm64, locale en-RO)
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 15.3)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2023.1)
[✓] VS Code (version 1.90.2)
[✓] Connected device (4 available)
[✓] Network resources

Additional context From my point of view, this is partially treated in the changes I have on the fork for the onItemStalled call, but there still needs an edge case treaded when onFailToComplete get triggered during a network disconnect.

Please, see this threads for more info, as this issue is persistent on multiple native solutions:

Thank you for the help and this awesome Flutter package!

bypass112 commented 6 days ago

I've been looking how native iOS Player libs handle the AVPlayerItemFailedToPlayToEndTimeNotification event. Most of them seem to be just throwing an error and letting the dev/app decide how the error should be handled. This is an example. Regarding the Android Exoplayer not throwing a similar error after a while, I've just noticed that after a long while you get a stream disconnect error. So I guess even on Android you have a similar situation. I'll work on my fork on this issue, and eventually open a PR, but I'm starting to believe that this bug is originating from the fact that onFailToComplete isn't throwing any errors from the native side. Hopefully tomorrow I'll return with a proper solution for this, so that custom native behaviour isn't that noticeable on the Flutter side. Any feedback would be apreciated. Thank you!

bypass112 commented 6 days ago

This is the final result of my investigation on this topic.

  1. iOS isn't throwing any error on socket disconnect for a live stream during a bad network connection. Android is already doing this, so we should mimic this behaviour on both platforms. This can be done by throwing an error to the Flutter side inside onFailToComplete.
  2. iOS isn't attempting to auto-reconnect in the native side, similar to ExoPlayer Android. This can be done by adding a reconnect logic inside onItemStalled. This issue has been a recurring one for iOS and can be found in the StackOverflow links from my original post.
  3. I've already made the changes on my fork, during testing everything seems to be working fine now, as you can also recover from network errors in the Flutter side, if it is needed. -> https://github.com/ryanheise/just_audio/compare/minor...bypass112:just_audio:minor

@ryanheise please let me know if the changes are ok with you and you want me to open a PR.

Thank you!