Search code examples
javascriptreact-nativeexpofreezeexpo-av

Autoplay of an array videos in expo-av causes app freezes


I was trying to create an app that loads videos from an ARRAY on loop. I am using UseState to change the URI index after the video ends.
The player works perfectly for around 1-2 hours then it freezes the video and throws onError() which gives player error null and sometimes Player release time out.
I am thinking that it might be happening because of useState because it re-renders the component every time when index changes. Maybe this could be memory leakage or something else I am not sure.

please help me I seriously spent a week to find the solution. I even tried caching the videos using the filesystem. but still, it doesn't stop freezing.


const VideoPlayer = ({ wholeResult }) => {
  const focuspoint = React.useRef(null);
  const [index, setIndex] = React.useState(0);
  const [progress, setProgress] = React.useState(false);

  React.useEffect(() => {
    if (wholeResult !== undefined) {
      setProgress(true);
    }
  }, []);

  const navigation = useNavigation();
  return (
    <View style={styles.container}>
      <TouchableOpacity
        onLongPress={() => {
          navigation.navigate("Home");
        }}
        delayLongPress={3000}
      >
        {progress &&
        wholeResult[index] !== "" &&
        wholeResult[index] !== undefined
          ? <Video
          ref={focuspoint}
          style={styles.video}
          source={{
            uri: wholeResult.length == 1 ? wholeResult[0] : wholeResult[index],
          }}
          useNativeControls={false}
          shouldPlay
          resizeMode="stretch"
          isLooping={wholeResult.length == 1 ? true : false}
          onError={(error) => 
            alert(error)
          }
          onPlaybackStatusUpdate={(status) =>
            status?.didJustFinish == true
              ? setIndex((idx) => (idx == wholeResult.length - 1 ? 0 : idx + 1))
              : null
          }
        />
          : null}
      </TouchableOpacity>
    </View>
  );
};

export default VideoPlayer;

EDIT: I think this is the issue with expo-av only or it might be a bug with it. I tried with imageBackground and it's working is perfectly with the same pattern of code.


Solution

  • Answering my Own Question
    So I couldn't find the solution to this problem but I got a trick to play, I used Webview to run Html containing a video looping function. But I have to use some parameters that could run in every device by enabling hardware acceleration. and it works for me.

     <WebView
             style={styles.container}
             originWhitelist={["*"]}
             allowFileAccess={true}
             allowUniversalAccessFromFileURLs={true}
             allowFileAccessFromFileURLs={true}
             javaScriptEnabled={true}
             domStorageEnabled={true}
             allowsFullscreenVideo={true}
             mixedContentMode='always'
             androidLayerType="hardware"
             androidHardwareAccelerationDisabled={false}
             mediaPlaybackRequiresUserAction={false}
            source={{
              html: `<!DOCTYPE html>
    
          <html lang="en">
            <head>
              <meta charset="UTF-8" />
              <meta http-equiv="X-UA-Compatible" content="IE=edge" />
              <meta name="viewport" content="width=device-width, initial-scale=1.0" />
              <title>Document</title>
              <style>
                body {
                  margin: 0;
                  padding: 0;
                  overflow: hidden;
                  box-sizing: border-box;
                  background: #000;
                }
                video {
                  width: 100vw;
                  height: 100vh;
                  object-fit: cover;
                }
              </style>
            </head>
            
            <body>
              <video id="myVideo" autoplay muted></video>
              <script>
                var videoSource = new Array();
                videoSource = ${JSON.stringify(vid)};
                
                var videoCount = videoSource.length;
                var elem = document.getElementById("myVideo");
                if (elem.requestFullscreen) {
                  elem.requestFullscreen();
                } else if (elem.mozRequestFullScreen) {
                  elem.mozRequestFullScreen();
                } else if (elem.webkitRequestFullscreen) {
                  elem.webkitRequestFullscreen();
                } else if (elem.msRequestFullscreen) {
                  elem.msRequestFullscreen();
                }
                document.getElementById("myVideo").setAttribute("src", videoSource[0]);
          
                function videoPlay(videoNum) {
                  document
                    .getElementById("myVideo")
                    .setAttribute("src", videoSource[videoNum]);
                  document.getElementById("myVideo").load();
                  document.getElementById("myVideo").play();
                }
                document
                  .getElementById("myVideo")
                  .addEventListener("ended", myHandler, false);
                var incr = (function () {
                  var i = 0;
          
                  return function () {
                    if (i > videoCount - 1) {
                      i = 0;
                    }
                    return i++;
                  };
                })();
                function myHandler() {
                  videoPlay(incr());
                }
              </script>
            </body>
          </html>
          `,
            }}
          />