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

ios14 showing floating pictureInPicture by default #2177

Closed anshul-kai closed 2 years ago

anshul-kai commented 3 years ago

Bug

Platform

Environment info

System:
    OS: macOS 10.15.6
    CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 74.54 MB / 32.00 GB
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 11.15.0 - ~/.nvm/versions/node/v11.15.0/bin/node
    Yarn: 1.19.1 - /usr/local/bin/yarn
    npm: 6.7.0 - ~/.nvm/versions/node/v11.15.0/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  SDKs:
    iOS SDK:
      Platforms: iOS 14.0, DriverKit 19.0, macOS 10.15, tvOS 14.0, watchOS 7.0
    Android SDK:
      API Levels: 23, 25, 26, 28, 29
      Build Tools: 27.0.3, 28.0.3, 29.0.0, 29.0.2
      System Images: android-23 | Intel x86 Atom, android-25 | Google Play Intel x86 Atom, android-26 | Google Play Intel x86 Atom, android-27 | Google APIs Intel x86 Atom, android-27 | Google Play Intel x86 Atom, android-28 | Google Play Intel x86 Atom
  IDEs:
    Android Studio: 4.0 AI-193.6911.18.40.6626763
    Xcode: 12.0.1/12A7300 - /usr/bin/xcodebuild
  npmPackages:
    react: 16.11.0 => 16.11.0
    react-native: 0.61.5 => 0.61.5
  npmGlobalPackages:
    react-native-cli: 2.0.1

Library version: Latest master branch

Steps To Reproduce

Play a local video file using code similar to below. Try to put the app in background and the video file floats around.

             <Video
                source={{ uri: `${FileSystem.BACKGROUND_VIDEO_DIR}/${filename}` }}
                rate={rate}
                volume={0}
                muted
                paused={paused}
                onLoadStart={() => {}}
                onLoad={() => {}}
                onEnd={() => {}}
                repeat
                playInBackground={false}
                playWhenInactive
                resizeMode='cover'
                style={styles.bg}
              />
flexgrip commented 3 years ago

Ha. I wish I had this bug. On my published apps, they try to play the video in PiP but then quickly disappear.

snamstorm commented 3 years ago

I am also having this issue

RN Version: 63.3 iOS: 14 react-native-video 5.1.0-alpha8

Only a floating picture is shown with no video controls

mbrimmer83 commented 3 years ago

I am not getting picture in picture at all.

RN Version: 61.4 iOS: 14 react-native-video 5.0.2

dmitryusikriseapps commented 3 years ago

I faced the same error.

RN Version: 63.3 iOS: 14 react-native-video: 5.0.2

joeyscarim commented 3 years ago

@flexgrip do you have playInBackground enabled? When I disabled this I stopped having that problem

joebernard commented 3 years ago

Any updates on this? Whenever a user backgrounds our app while playing a video it automatically starts PiP. We need a way to turn this off. Looks like PR #2191 may fix this? Can we get it reviewed?

nkeebaugh commented 3 years ago

Watching this issue - running into the same problem.

Lyubomyr commented 3 years ago

Also, have the same problem. After switching to another app on my phone it shows PiP for 1 sec and then disappears. Background sound works properly at that time. Maybe some additional permissions should be requested to make it work?

pictureInPicture={ true } IOS 14.2 react-native-video 5.1.0-alpha8

nikolaigeorgie commented 3 years ago

@Lyubomyr just remove the logic in applicationDidEnterBackground, that's clearly the issue.

the file is ios/Video/RCTVideo.m

- (void)applicationDidEnterBackground:(NSNotification *)notification
{
  if (_playInBackground) {
    // Needed to play sound in background. See https://developer.apple.com/library/ios/qa/qa1668/_index.html
    [_playerLayer setPlayer:nil];
    [_playerViewController setPlayer:nil];
  }
}
Lyubomyr commented 3 years ago

@nikolaigeorgie Thank you I'll try.

KingAmo commented 3 years ago

@Lyubomyr just remove the logic in applicationDidEnterBackground, that's clearly the issue.

the file is ios/Video/RCTVideo.m

- (void)applicationDidEnterBackground:(NSNotification *)notification
{
  if (_playInBackground) {
    // Needed to play sound in background. See https://developer.apple.com/library/ios/qa/qa1668/_index.html
    [_playerLayer setPlayer:nil];
    [_playerViewController setPlayer:nil];
  }
}

this works for me, thanks a lot!

marf commented 3 years ago

@Lyubomyr just remove the logic in applicationDidEnterBackground, that's clearly the issue. the file is ios/Video/RCTVideo.m

- (void)applicationDidEnterBackground:(NSNotification *)notification
{
  if (_playInBackground) {
    // Needed to play sound in background. See https://developer.apple.com/library/ios/qa/qa1668/_index.html
    [_playerLayer setPlayer:nil];
    [_playerViewController setPlayer:nil];
  }
}

this works for me, thanks a lot!

Thank you! Does it play the audio also in the background when PiP is not enabled with this fix? Because I read in the docs that they placed those lines in order to play the song/sound in the background.

nikolaigeorgie commented 3 years ago

@marf that's a good point... i don't see yet an application that implements both PiP and also playsInBackground... if you look at youtube they prefer playsInBackground... if you look at safari web player they prefer PiP...

TBH what i just did is i didn't remove any props.. i just added a button to my app to opt in for controls and then toggle the controls to true... i then had playInBackground rely on the controls states.. that way i get playInBackground out the gate but if a user wants PiP they turn on the controls and deal with the fact that they have to click the play button after closing to the home screen

... this is def not ideal... but i just don't have the time to adjust the native code to add support for both... hope this helps


      playInBackground={!props.controls}
      controls={props.controls}
      fullscreenAutorotate
      fullscreenOrientation="landscape"
      ignoreSilentSwitch="ignore"
      playWhenInactive
      allowsExternalPlayback
      ref={props.videoPlayerRef}
      onLoad={props.onLoad}
      onLoadStart={props.onLoadStart}
      onProgress={props.onProgress}
      paused={props.paused}
      volume={props.volume}
      rate={props.speed}
      onEnd={handleOnEnd}
      onError={onError}
      pictureInPicture```
olivierlesnicki commented 3 years ago

There's a PR open addressing this issue https://github.com/react-native-video/react-native-video/pull/2297

joebernard commented 3 years ago

One way to work around this issue until the PR is accepted is to disable Picture in Picture in the XCode Signing & Capabilities tab for your target (under Background Modes). This also disables background audio and AirPlay so it might not be an option for everyone. If you don't need those other capabilities, unchecking that box gets you past this bug.

Aaron46 commented 3 years ago

@marf Wouldn't adding "&& !_pictureInPicture" work?


{
  if (_playInBackground && !_pictureInPicture) {
    // Needed to play sound in background. See https://developer.apple.com/library/ios/qa/qa1668/_index.html
    [_playerLayer setPlayer:nil];
    [_playerViewController setPlayer:nil];
  }
}
HeppokoNeet commented 2 years ago

Hi. I had the problem like @a-koka.

I wanted to disable picture in picture, but needed play in background. However when app goes to background, picture in picture temporary open, then close.

At the time, my code was:

<Video
  ref={videoPlayer}
  paused={movie_pause_status}
  source={vimeo}
  autoplay={true}
  muted={false}
  repeat={false}
  volume={1.0}
  resizeMode="cover"
  onLoadStart={onLoadStart}
  onLoad={onLoad}
  rate={videoSpeed}
  onProgress={onProgress}
  style={styles.mediaPlayer}
  ignoreSilentSwitch={'ignore'}
  playInBackground={true}
  pictureInPicture={false}
  getCurrentTimeFromFullscreen={getCurrentTimeFromFullscreen()}
  />

For fixing, i changed ignoreSilentSwitch={'obey'}. And changed category = AVAudioSessionCategoryMultiRoute;on RCTVideo.m

    if([_ignoreSilentSwitch isEqualToString:@"ignore"]) {
      category = AVAudioSessionCategoryPlayback;
    } else if([_ignoreSilentSwitch isEqualToString:@"obey"]) {
      category = AVAudioSessionCategoryAmbient;
    }

If you are interested, plz check the document of AVAudioSessionCategoryMultiRoute;

But I'm not familiar with objective-c, so I'm not sure it's correct way. However it worked.

anshul-kai commented 2 years ago

Thanks for your finding @HeppokoNeet. I didn't have to change any Objective-C code but `ignoreSilentSwitch={'obey'} seems to do the trick.

This is clearly a bug as the pip seems correlated to ignoreSilentSwitch, but for others looking for a fix, this works!

const playInBackground = true; // or false
playInBackground={playInBackground}
playWhenInactive={playInBackground}
ignoreSilentSwitch={playInBackground ? 'ignore' : 'obey'}
jrhager84 commented 2 years ago

Thanks for your finding @HeppokoNeet. I didn't have to change any Objective-C code but `ignoreSilentSwitch={'obey'} seems to do the trick.

This is clearly a bug as the pip seems correlated to ignoreSilentSwitch, but for others looking for a fix, this works!

const playInBackground = true; // or false
playInBackground={playInBackground}
playWhenInactive={playInBackground}
ignoreSilentSwitch={playInBackground ? 'ignore' : 'obey'}

This isn't working for me. Is there a list of steps you did to make it work? Thanks!

Pnlvfx commented 1 year ago

2022, and this is bug is still here?

Pnlvfx commented 1 year ago

<Video className='w-full h-full' source={video} repeat playWhenInactive={false} pictureInPicture={false} resizeMode='cover' muted onPictureInPictureStatusChanged={(e) => { setSilentSwitch(!silentSwitch); }} ignoreSilentSwitch={silentSwitch ? 'ignore' : 'obey'} volume={0} paused={!playing} allowsExternalPlayback={false} playInBackground={false} />

It doesn't work event if I have pictureInPicture disabled! My expected result is to close the video when I close the app I use the video as a backround so I need to use 'ignore' for the silentSwitch.

freeboub commented 1 year ago

@Pnlvfx on which version, V6 alpha ?

Pnlvfx commented 1 year ago

No I have 5.2.1. Do you suggest me to upgrade to v6 alpha?

MaxJadav commented 1 year ago

Thanks for your finding @HeppokoNeet. I didn't have to change any Objective-C code but `ignoreSilentSwitch={'obey'} seems to do the trick.

This is clearly a bug as the pip seems correlated to ignoreSilentSwitch, but for others looking for a fix, this works!

const playInBackground = true; // or false
playInBackground={playInBackground}
playWhenInactive={playInBackground}
ignoreSilentSwitch={playInBackground ? 'ignore' : 'obey'}

This is not working for me. Any one have soltion? https://github.com/react-native-video/react-native-video/issues/2118#issuecomment-1306683866

c0rnonthec0bb commented 1 year ago

Just opened #3045 which fixes this issue for my use case. Not thoroughly tested for different use cases.

Use yarn add react-native-video@https://github.com/c0rnonthec0bb/react-native-video-fix-pip#fix-5.2.X-ios-pip for the fixed version until it gets merged