TheWidlarzGroup / react-native-video

A <Video /> component for react-native
http://thewidlarzgroup.github.io/react-native-video/
MIT License
7.15k stars 2.88k forks source link

[BUG]: on iOS, onPlaybackStateChanged event is not trigerred when video stops due to lost of connection or limited bandwith #3877

Open fabienbouchez opened 4 months ago

fabienbouchez commented 4 months ago

Version

6.1.2

What platforms are you having the problem on?

iOS

System Version

iOS 17.2

On what device are you experiencing the issue?

Real device, Simulator

Architecture

Old architecture

What happened?

On iOS,

For the same situations with Android, the onPlaybackStateChanged event is well triggered

Here is an example of events triggered, when I close the wifi just after the video has started to play :

Logs for Android :

LOG  Running "reactNativeVideoTest" with {"rootTag":11}
 LOG  video1  onBuffer {"isBuffering": true}
 LOG  video1 onPlaybackStateChanged {"isPlaying": true}
 LOG  video1  onBuffer {"isBuffering": false}
 LOG  video1 onError {"error": {"errorCode": "22001", "errorException": "androidx.media3.exoplayer.ExoPlaybackException: Source error", "errorStackTrace": "androidx.media3.exoplayer.ExoPlaybackException: Source error
        at androidx.media3.exoplayer.ExoPlayerImplInternal.handleIoException(ExoPlayerImplInternal.java:684)
        at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:656)
        at android.os.Handler.dispatchMessage(Handler.java:103)
        at android.os.Looper.loopOnce(Looper.java:232)
        at android.os.Looper.loop(Looper.java:317)
        at android.os.HandlerThread.run(HandlerThread.java:68)
Caused by: androidx.media3.datasource.HttpDataSource$HttpDataSourceException: java.io.IOException: java.util.concurrent.ExecutionException: java.net.UnknownHostException: Unable to resolve host \"[demo.unified-streaming.com](http://demo.unified-streaming.com/)\": No address associated with hostname
        at androidx.media3.datasource.okhttp.OkHttpDataSource.open(OkHttpDataSource.java:321)
        at androidx.media3.datasource.DefaultDataSource.open(DefaultDataSource.java:272)
        at androidx.media3.datasource.StatsDataSource.open(StatsDataSource.java:86)
        at androidx.media3.exoplayer.hls.HlsMediaChunk.prepareExtraction(HlsMediaChunk.java:527)
        at androidx.media3.exoplayer.hls.HlsMediaChunk.feedDataToExtractor(HlsMediaChunk.java:500)
        at androidx.media3.exoplayer.hls.HlsMediaChunk.loadMedia(HlsMediaChunk.java:469)
        at androidx.media3.exoplayer.hls.HlsMediaChunk.load(HlsMediaChunk.java:426)
        at androidx.media3.exoplayer.upstream.Loader$LoadTask.run(Loader.java:414)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
        at java.lang.Thread.run(Thread.java:1012)
Caused by: java.io.IOException: java.util.concurrent.ExecutionException: java.net.UnknownHostException: Unable to resolve host \"[demo.unified-streaming.com](http://demo.unified-streaming.com/)\": No address associated with hostname
        at androidx.media3.datasource.okhttp.OkHttpDataSource.executeCall(OkHttpDataSource.java:489)
        at androidx.media3.datasource.okhttp.OkHttpDataSource.open(OkHttpDataSource.java:316)
        ... 10 more
Caused by: java.util.concurrent.ExecutionException: java.net.UnknownHostException: Unable to resolve host \"[demo.unified-streaming.com](http://demo.unified-streaming.com/)\": No address associated with hostname
        at com.google.common.util.concurrent.AbstractFuture.getDoneValue(AbstractFuture.java:588)
        at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:567)
        at com.google.common.util.concurrent.AbstractFuture$TrustedFuture.get(AbstractFuture.java:113)
        at androidx.media3.datasource.okhttp.OkHttpDataSource.executeCall(OkHttpDataSource.java:484)
        ... 11 more
Caused by: java.net.UnknownHostException: Unable to resolve host \"[demo.unified-streaming.com](http://demo.unified-streaming.com/)\": No address associated with hostname
        at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:156)
        at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:103)
        at java.net.InetAddress.getAllByName(InetAddress.java:1152)
        at okhttp3.Dns$Companion$DnsSystem.lookup(Dns.kt:49)
        at okhttp3.internal.connection.RouteSelector.resetNextInetSocketAddress(RouteSelector.kt:169)
        at okhttp3.internal.connection.RouteSelector.nextProxy(RouteSelector.kt:131)
        at okhttp3.internal.connection.RouteSelector.next(RouteSelector.kt:73)
        at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:205)
        at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
        at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
        at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)
        at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
        at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
        at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
        at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
        at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:517)
        ... 3 more
Caused by: android.system.GaiException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
        at libcore.io.Linux.android_getaddrinfo(Native Method)
        at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:133)
        at libcore.io.BlockGuardOs.android_getaddrinfo(BlockGuardOs.java:222)
        at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:133)
        at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:135)
        ... 23 more
", "errorString": "ExoPlaybackException: ERROR_CODE_IO_NETWORK_CONNECTION_FAILED"}}
 **LOG  video1 onPlaybackStateChanged {"isPlaying": false}**

We have onPlaybackStateChanged {"isPlaying": false} as expected

Logs for iOS:

LOG  Running "reactNativeVideoTest" with {"rootTag":1,"initialProps":{"concurrentRoot":false}}
 LOG  video1 onPlaybackStateChanged {"isPlaying": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1 onPlaybackStateChanged {"isPlaying": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1 onError {"error": {"code": -1009, "domain": "NSURLErrorDomain", "localizedDescription": "The Internet connection appears to be offline.", "localizedFailureReason": "", "localizedRecoverySuggestion": ""}, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}

We don't have onPlaybackStateChanged {"isPlaying": false} as expected

Reproduction

repository link

Reproduction

You can reproduce by running this code and cut the internet connection (ex : by disabling Wifi on the phone) some seconds after the video has started. After a few seconds, due to lack of buffering the video will stop.

import React from 'react';
import { View } from 'react-native';
import Video from 'react-native-video';

function App(): React.JSX.Element {
  return (
    <View  style={{flex:1}}>
     <Video
        source={{ uri: 'https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.mp4/.m3u8' }}
        onBuffer={(onBuffer) => console.log('video1  onBuffer', onBuffer)}
        onError={(onError) => console.log('video1 onError', onError)}
        onPlaybackStateChanged={(onPlaybackStateChanged) => console.log('video1 onPlaybackStateChanged', onPlaybackStateChanged)}
        style={{flex:1}}
      />   
    </View>

  );
}

export default App;

This is the logs on iOS when the bandwidth is limited :

When the videos hangs, the onBuffer is triggered, but not the onPlaybackStateChanged


 LOG  video1 onPlaybackStateChanged {"isPlaying": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1 onPlaybackStateChanged {"isPlaying": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
 LOG  video1  onBuffer {"isBuffering": true, "target": 3}
 LOG  video1  onBuffer {"isBuffering": false, "target": 3}
fabienbouchez commented 4 months ago

Thanks for your help

fabienbouchez commented 3 months ago

Hi @freeboub, did you have a look ? One consequence of this is for iOS we can't detect if the video is stopped while buffering. I would need this to trigger the display of a "loading...." . Or there is another way ?

github-actions[bot] commented 1 month ago

This issue is stale because it has been open for 30 days with no activity. If there won't be any activity in the next 14 days, this issue will be closed automatically.

fabienbouchez commented 1 month ago

Hello, any news on this ?

github-actions[bot] commented 1 week ago

This issue is stale because it has been open for 30 days with no activity. If there won't be any activity in the next 14 days, this issue will be closed automatically.

cordovalegacy commented 1 week ago

Do we have an update on this issue? We are receiving incorrect analytics due to this issue and it is affecting all our customers.