TheWidlarzGroup / react-native-video

A <Video /> component for react-native
https://docs.thewidlarzgroup.com/react-native-video/
MIT License
7.23k stars 2.91k forks source link

[Feature]: Video Player play/pause during incoming calling #3871

Open Sumeeth-24 opened 6 months ago

Sumeeth-24 commented 6 months ago

Description

We need functionality where the video player pauses when a call is incoming and resumes when the call ends. This should not happen automatically but should be controlled via a prop value so that our custom functionality can handle the play/pause actions.

There is an old npm package named react-native-call-detection which is outdated (last updated 4 years ago) and incompatible with the newer Android/iOS versions. This package detects different call states like Incoming, Disconnected, Dialing, and Connected for iOS. For Android, it provides states like Offhook, Incoming, Disconnected, and Missed.

Our goal is to handle at least the Incoming and Disconnected events to implement custom controls for playing and pausing the video.

Why it is needed ?

Every ott platform like Amazon Prime, Netflix, Disney plus HotStar has this functionality where any video is playing and call is coming in between then automatically the player pause and when its disconnected then it automatically starts playing. Atleast need those two event listener (Incoming and Disconnected) and then video player would be completed. Its a much needed functionality for any video player. If possible please release it as early as possible as we have made an ott platform completed with this package and react-native and only this functionality and android pip support is missing.

Possible implementation

Refer this package for idea " react-native-call-detection".

Code sample

Code sample

MdAbubakar commented 6 months ago

@Sumeeth-24 Bro I have tried this approach after lots of tries using the library you provided and finally this approach works for me,

Add this line in the video component

onAudioFocusChanged={event => { if (!event.hasAudioFocus) { setPaused(true); setActiveCall(true); } else { setPaused(false); setActiveCall(false); } }}

And disable your play pause button

<Pressable style={{ marginHorizontal: moderateScale(50), padding: scale(10), borderRadius: 100, justifyContent: "center", alignItems: "center", // backgroundColor: "rgba(0,0,0, 0.3)", display: isLoading ? "none" : "flex", }} disabled={activeCall} onPress={() => { setPaused(!paused); handleControlInteraction(true); }}> {paused ? ( <Icon name="play" type="ionicon" size={showFullscreen ? moderateScale(30) : moderateScale(35)} color={"#FFFFFF"} /> ) : ( <Icon name="pause" type="ionicon" size={showFullscreen ? moderateScale(30) : moderateScale(35)} color={"#FFFFFF"} /> )}

paulrinaldi commented 6 months ago

The player works already as you describe in Android @Sumeeth-24 . See the example/basic. Run it by: yarn install cd examples/basic yarn install yarn run android yarn run start a

However, I'm on 6.1.2 and my video player in my pure RN app I'm developing keeps playing on Android when it receives a call in simulator which is different from what the basic app does.

It looks like they handle it with this.onAudioFocusChanged in examples/basic...

paulrinaldi commented 6 months ago

For iOS, there is started work on refactoring so that iOS audio category can be set more easily so that interruptions are handled well. https://github.com/TheWidlarzGroup/react-native-video/pull/3850 For now, see https://github.com/TheWidlarzGroup/react-native-video/issues/3652 for a patch I made.

paul-rinaldi commented 5 months ago

@Sumeeth-24 On Android, you can simply follow their examples/basic's implementation:

  onAudioBecomingNoisy = () => {
    this.setState({paused: true});
  };

  onAudioFocusChanged = (event: OnAudioFocusChangedData) => {
    this.setState({paused: !event.hasAudioFocus});
  };
  ...
  <Video
    onAudioBecomingNoisy={this.onAudioBecomingNoisy}
    onAudioFocusChanged={this.onAudioFocusChanged}
    .../>

https://github.com/TheWidlarzGroup/react-native-video/blob/master/examples/basic/src/VideoPlayer.tsx#L387

paulrinaldi commented 1 month ago

This would be a great addition.

seyedmostafahasani commented 1 month ago

I will work on it this weekend.

paulrinaldi commented 1 month ago

One way that this can be implemented partially is by breaking other functionality fyi @Sumeeth-24. You can let exoplayer manage its own audioFocus. If you don't need to know when audio focus is lost/gained, this is an easy solution.

Edit node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java

@@ -1256,10 +1273,10 @@ public class ReactExoplayerView extends FrameLayout implements
         }

         if (playWhenReady) {
-            this.hasAudioFocus = requestAudioFocus();
-            if (this.hasAudioFocus) {
-                player.setPlayWhenReady(true);
-            }
+            // this.hasAudioFocus = requestAudioFocus();
+            // if (this.hasAudioFocus) {
+            player.setPlayWhenReady(true);
+            // }
         } else {
             // ensure playback is not ENDED, else it will trigger another ended event
             if (player.getPlaybackState() != Player.STATE_ENDED) {
@@ -2134,7 +2151,7 @@ public class ReactExoplayerView extends FrameLayout implements
             AudioAttributes audioAttributes = new AudioAttributes.Builder().setUsage(usage)
                     .setContentType(contentType)
                     .build();
-            player.setAudioAttributes(audioAttributes, false);
+            player.setAudioAttributes(audioAttributes, true);
             AudioManager audioManager = (AudioManager) themedReactContext.getSystemService(Context.AUDIO_SERVICE);
             boolean isSpeakerOutput = output == AudioOutput.SPEAKER;
             audioManager.setMode(

Then onPlaybackStateChange, set your pause state (which you can pass as a prop to the RNV Video component) as !data.isPlaying.