TheWidlarzGroup / react-native-video

A <Video /> component for react-native

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

fabienbouchez opened this issue · comments

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,

  • when playing a streamed video, if we lose the network connectivity and we reach the end of buffer, the video stops but the onPlaybackStateChanged event is not triggered.
  • This happens as well when the bandwidth is too low to stream the content, the video is paused while buffering, the onBuffer event is well triggered, but not the onPlaybackStateChanged

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}

Thanks for your help