TheWidlarzGroup / react-native-video

A <Video /> component for react-native
https://thewidlarzgroup.github.io/react-native-video/
MIT License
7.2k stars 2.9k forks source link

Can I get events when the video is automatically paused by closing fullscreen or closing PIP? #2279

Open jcarioti opened 3 years ago

jcarioti commented 3 years ago

Bug

I'm trying to keep my video playing no matter what the user ends up doing: fullscreen, PIP, restoring from PIP, closing fullscreen, etc.

Currently, despite having paused={false} as the video player prop, dismissing fullscreen or dismissing a fullscreen PIP automatically pauses the video.

I can see the playback rate change to 0, but my paused prop is already set to false, so I would expect the video to continue playing instead of ignoring my prop value.

Platform

Which player are you experiencing the problem on:

Environment info

React native info output:

System:
    OS: macOS 10.15.7
    CPU: (12) x64 Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz
    Memory: 719.15 MB / 16.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 12.18.2 - ~/.nvm/versions/node/v12.18.2/bin/node
    Yarn: 1.22.5 - ~/.yarn/bin/yarn
    npm: 6.14.8 - ~/.nvm/versions/node/v12.18.2/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.9.3 - /usr/local/bin/pod
  SDKs:
    iOS SDK:
      Platforms: iOS 14.3, DriverKit 20.2, macOS 11.1, tvOS 14.3, watchOS 7.2
    Android SDK:
      API Levels: 23, 28, 29
      Build Tools: 28.0.3, 29.0.2, 29.0.3
      System Images: android-28 | Intel x86 Atom_64, android-28 | Google APIs Intel x86 Atom
      Android NDK: Not Found
  IDEs:
    Android Studio: 4.0 AI-193.6911.18.40.6626763
    Xcode: 12.3/12C33 - /usr/bin/xcodebuild
  Languages:
    Java: 1.8.0_232 - /usr/bin/javac
    Python: 2.7.16 - /usr/bin/python
  npmPackages:
    @react-native-community/cli: Not Found
    react: ^16.13.1 => 16.13.1 
    react-native: 0.63.2 => 0.63.2 
    react-native-macos: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

Library version: 5.1.1

Steps To Reproduce

  1. Start HLS video stream
  2. Set the paused prop to false
  3. Launch video fullscreen
  4. Close fullscreen viewer ...

Expected behaviour

  1. User closes fullscreen viewer and video continues to play

Reproducible sample code

       <Video
          source={{ uri: 'someHlsStream.m3u8' }}
          muted
          fullscreen={isFullscreen}
          paused={false}
          playInBackground
          ignoreSilentSwitch="ignore"
          onPlaybackRateChange={({ playbackRate }) => {
            if (playbackRate === 0) {
               console.log("I can see here that the video stopped playing, but can't tell if it's from a buffer or if it's because the video was paused externally.");
            }
          }}
          onFullscreenPlayerDidDismiss={() => {
            console.log('At this point, I know the fullscreen viewer is closing and my video will be paused, but I'm assuming the side effect rather than using an event.');
          }}
        />
kadikraman commented 3 years ago

This is super awkward, because the state props and the video state become out of sync, and I can't find a way to resume the video without changing the prop.

My very inelegant solution was to set paused prop to true and then false again šŸ˜•

onFullscreenPlayerDidDismiss={() => {
  // dismissing full screen automatically pauses the video, so we have to "pause" and "resume" in state to resume
  handlePause();
  setTimeout(() => {
    handleResume();
  }, 0);
}}

I found your issue because I was revisiting this code and hoping someone had a better solution. What did you end up doing?

jcarioti commented 3 years ago

I did the same thing for the time being, but it's pretty jarring to see it stop and start again for no reason.

jrhager84 commented 2 years ago

Any solution for this?

jcarioti commented 2 years ago

Any solution for this?

Not that I've found. I think this project is dead considering the last release was over a year ago and there are over a thousand active issues.

dianamelga commented 1 year ago

facing the same issue šŸ‘Ž

gkueny commented 7 months ago

Hello @jcarioti @jrhager84 @dianamelga ,

I will check this issue. We also have issue with fullscreen mode with beta.5

gkueny commented 7 months ago

For now, I can not find any fix in the lib. I can not be sure because I do not know AVPlayer well, but it may be how it work natively (pause after fullscreen exit) https://stackoverflow.com/a/58818395

So, I only can propose a workaround for now:

function App(): React.JSX.Element {
  const videoRef = useRef<VideoRef>();
  const playbackref = useRef<boolean>(true);

  const onError = useCallback((error: OnVideoErrorData) => {
    console.log({error});
  }, []);

  return (
    <View style={styles.container}>
      <View style={styles.videoContainer}>
        <Video
          ref={videoRef}
          source={{
            uri: 'https://storage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
          }}
          onError={onError}
          style={styles.backgroundVideo}
          resizeMode={ResizeMode.CONTAIN}
          controls
          onPlaybackStateChanged={(e: OnPlaybackStateChangedData) => {
            playbackref.current = e.isPlaying;
          }}
          onFullscreenPlayerDidPresent={() => {
            console.log('onFullscreenPlayerDidPresent');
            if (playbackref.current) {
              setTimeout(() => {
                console.log('resume');
                videoRef.current?.resume();
              }, 500);
            }
          }}
          onFullscreenPlayerDidDismiss={() => {
            console.log('onFullscreenPlayerDidDismiss');
            if (playbackref.current) {
              setTimeout(() => {
                console.log('resume');
                videoRef.current?.resume();
              }, 500);
            }
          }}
        />
      </View>
    </View>
  );
}
freeboub commented 7 months ago

@gkueny I have a doubt about this pause call: // Continue playing (or not if paused) after being paused due to hitting an unbuffered zone. func handlePlaybackLikelyToKeepUp(playerItem _: AVPlayerItem, change _: NSKeyValueObservedChange<Bool>) { if (!(_controls || _fullscreenPlayerPresented) || _playerBufferEmpty) && ((_playerItem?.isPlaybackLikelyToKeepUp) == true) { setPaused(_paused) } _playerBufferEmpty = false onVideoBuffer?(["isBuffering": false, "target": reactTag as Any]) }

Can you try to remove it, just for testing please ?

gkueny commented 7 months ago

@freeboub I tried to comment this code, but the bug persist.

I also tried to setup breackpoint on all play() & pause() code that are in react-native-video iOS code, but when I reproduce the issue, none of this line are called

gkueny commented 7 months ago

Expo Video implementation also seems to point out that iOS' default behavior is to pause the video when leaving the full screen.

https://github.com/expo/expo/blob/9c1d9f814e0189f8d7cf576aba87ab37732fd740/packages/expo-video/ios/VideoView.swift#L129

// Platform's behavior is to pause the player when exiting the fullscreen mode. // It seems better to continue playing, so we resume the player once the dismissing animation finishes.

I also think it's better to continue playing, but that means we have to do it manually.

@freeboub Are you OK to keep playing after exit fullscreen even though this seems to be the normal behavior of iOS?

and if so, can you point me where I can start digging to add this behavior ?