@stream-io/video-react-native-sdk 1.7.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +1 -1
  3. package/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNative.kt +23 -11
  4. package/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.kt +71 -23
  5. package/dist/commonjs/components/Call/CallContent/CallContent.js +1 -1
  6. package/dist/commonjs/components/Call/CallContent/CallContent.js.map +1 -1
  7. package/dist/commonjs/components/Call/CallLayout/CallParticipantsGrid.js +2 -3
  8. package/dist/commonjs/components/Call/CallLayout/CallParticipantsGrid.js.map +1 -1
  9. package/dist/commonjs/components/Call/CallLayout/CallParticipantsSpotlight.js +2 -3
  10. package/dist/commonjs/components/Call/CallLayout/CallParticipantsSpotlight.js.map +1 -1
  11. package/dist/commonjs/contexts/BackgroundFilters.js +0 -1
  12. package/dist/commonjs/contexts/BackgroundFilters.js.map +1 -1
  13. package/dist/commonjs/hooks/useAutoEnterPiPEffect.js +5 -3
  14. package/dist/commonjs/hooks/useAutoEnterPiPEffect.js.map +1 -1
  15. package/dist/commonjs/hooks/useIsInPiPMode.js +14 -24
  16. package/dist/commonjs/hooks/useIsInPiPMode.js.map +1 -1
  17. package/dist/commonjs/providers/StreamCall/AppStateListener.js +101 -0
  18. package/dist/commonjs/providers/StreamCall/AppStateListener.js.map +1 -0
  19. package/dist/commonjs/providers/StreamCall/DeviceStats.js +45 -0
  20. package/dist/commonjs/providers/StreamCall/DeviceStats.js.map +1 -0
  21. package/dist/commonjs/providers/StreamCall/index.js +69 -0
  22. package/dist/commonjs/providers/StreamCall/index.js.map +1 -0
  23. package/dist/commonjs/utils/internal/rxSubjects.js +10 -0
  24. package/dist/commonjs/utils/internal/rxSubjects.js.map +1 -0
  25. package/dist/commonjs/version.js +1 -1
  26. package/dist/module/components/Call/CallContent/CallContent.js +1 -1
  27. package/dist/module/components/Call/CallContent/CallContent.js.map +1 -1
  28. package/dist/module/components/Call/CallLayout/CallParticipantsGrid.js +2 -3
  29. package/dist/module/components/Call/CallLayout/CallParticipantsGrid.js.map +1 -1
  30. package/dist/module/components/Call/CallLayout/CallParticipantsSpotlight.js +2 -3
  31. package/dist/module/components/Call/CallLayout/CallParticipantsSpotlight.js.map +1 -1
  32. package/dist/module/contexts/BackgroundFilters.js +1 -3
  33. package/dist/module/contexts/BackgroundFilters.js.map +1 -1
  34. package/dist/module/hooks/useAutoEnterPiPEffect.js +5 -3
  35. package/dist/module/hooks/useAutoEnterPiPEffect.js.map +1 -1
  36. package/dist/module/hooks/useIsInPiPMode.js +14 -24
  37. package/dist/module/hooks/useIsInPiPMode.js.map +1 -1
  38. package/dist/module/providers/StreamCall/AppStateListener.js +94 -0
  39. package/dist/module/providers/StreamCall/AppStateListener.js.map +1 -0
  40. package/dist/module/providers/StreamCall/DeviceStats.js +38 -0
  41. package/dist/module/providers/StreamCall/DeviceStats.js.map +1 -0
  42. package/dist/module/providers/StreamCall/index.js +61 -0
  43. package/dist/module/providers/StreamCall/index.js.map +1 -0
  44. package/dist/module/utils/internal/rxSubjects.js +4 -0
  45. package/dist/module/utils/internal/rxSubjects.js.map +1 -0
  46. package/dist/module/version.js +1 -1
  47. package/dist/typescript/components/Call/CallContent/CallContent.d.ts.map +1 -1
  48. package/dist/typescript/components/Call/CallLayout/CallParticipantsGrid.d.ts +2 -2
  49. package/dist/typescript/components/Call/CallLayout/CallParticipantsGrid.d.ts.map +1 -1
  50. package/dist/typescript/components/Call/CallLayout/CallParticipantsSpotlight.d.ts +2 -2
  51. package/dist/typescript/components/Call/CallLayout/CallParticipantsSpotlight.d.ts.map +1 -1
  52. package/dist/typescript/contexts/BackgroundFilters.d.ts.map +1 -1
  53. package/dist/typescript/hooks/useAutoEnterPiPEffect.d.ts.map +1 -1
  54. package/dist/typescript/hooks/useIsInPiPMode.d.ts +1 -1
  55. package/dist/typescript/hooks/useIsInPiPMode.d.ts.map +1 -1
  56. package/dist/typescript/providers/StreamCall/AppStateListener.d.ts +2 -0
  57. package/dist/typescript/providers/StreamCall/AppStateListener.d.ts.map +1 -0
  58. package/dist/typescript/providers/StreamCall/DeviceStats.d.ts +5 -0
  59. package/dist/typescript/providers/StreamCall/DeviceStats.d.ts.map +1 -0
  60. package/dist/typescript/providers/{StreamCall.d.ts → StreamCall/index.d.ts} +1 -1
  61. package/dist/typescript/providers/StreamCall/index.d.ts.map +1 -0
  62. package/dist/typescript/utils/StreamVideoRN/types.d.ts +2 -2
  63. package/dist/typescript/utils/StreamVideoRN/types.d.ts.map +1 -1
  64. package/dist/typescript/utils/internal/rxSubjects.d.ts +4 -0
  65. package/dist/typescript/utils/internal/rxSubjects.d.ts.map +1 -0
  66. package/dist/typescript/version.d.ts +1 -1
  67. package/expo-config-plugin/dist/common/types.d.ts +1 -4
  68. package/expo-config-plugin/dist/withMainActivity.js +42 -36
  69. package/package.json +5 -5
  70. package/src/components/Call/CallContent/CallContent.tsx +2 -1
  71. package/src/components/Call/CallLayout/CallParticipantsGrid.tsx +2 -6
  72. package/src/components/Call/CallLayout/CallParticipantsSpotlight.tsx +2 -6
  73. package/src/contexts/BackgroundFilters.tsx +2 -5
  74. package/src/hooks/useAutoEnterPiPEffect.tsx +5 -2
  75. package/src/hooks/useIsInPiPMode.tsx +16 -52
  76. package/src/providers/StreamCall/AppStateListener.tsx +125 -0
  77. package/src/providers/StreamCall/DeviceStats.tsx +59 -0
  78. package/src/providers/StreamCall/index.tsx +78 -0
  79. package/src/utils/StreamVideoRN/types.ts +5 -2
  80. package/src/utils/internal/rxSubjects.ts +5 -0
  81. package/src/version.ts +1 -1
  82. package/dist/commonjs/providers/StreamCall.js +0 -155
  83. package/dist/commonjs/providers/StreamCall.js.map +0 -1
  84. package/dist/module/providers/StreamCall.js +0 -146
  85. package/dist/module/providers/StreamCall.js.map +0 -1
  86. package/dist/typescript/providers/StreamCall.d.ts.map +0 -1
  87. package/src/providers/StreamCall.tsx +0 -205
@@ -25,10 +25,7 @@ import { useIsInPiPMode } from '../../../hooks/useIsInPiPMode';
25
25
  export type CallParticipantsSpotlightProps = ParticipantViewComponentProps &
26
26
  Pick<
27
27
  CallContentProps,
28
- | 'supportedReactions'
29
- | 'CallParticipantsList'
30
- | 'ScreenShareOverlay'
31
- | 'disablePictureInPicture'
28
+ 'supportedReactions' | 'CallParticipantsList' | 'ScreenShareOverlay'
32
29
  > &
33
30
  Pick<CallParticipantsListComponentProps, 'ParticipantView'> & {
34
31
  /**
@@ -53,7 +50,6 @@ export const CallParticipantsSpotlight = ({
53
50
  VideoRenderer,
54
51
  supportedReactions,
55
52
  landscape,
56
- disablePictureInPicture,
57
53
  }: CallParticipantsSpotlightProps) => {
58
54
  const {
59
55
  theme: { callParticipantsSpotlight, variants },
@@ -69,7 +65,7 @@ export const CallParticipantsSpotlight = ({
69
65
  participantInSpotlight && hasScreenShare(participantInSpotlight);
70
66
  const isUserAloneInCall = _allParticipants?.length === 1;
71
67
 
72
- const isInPiP = useIsInPiPMode(disablePictureInPicture);
68
+ const isInPiP = useIsInPiPMode();
73
69
 
74
70
  const participantViewProps: ParticipantViewComponentProps = {
75
71
  ParticipantLabel,
@@ -1,6 +1,6 @@
1
1
  import React, {
2
- PropsWithChildren,
3
2
  createContext,
3
+ PropsWithChildren,
4
4
  useCallback,
5
5
  useContext,
6
6
  useMemo,
@@ -9,7 +9,7 @@ import React, {
9
9
  } from 'react';
10
10
  import { MediaStream } from '@stream-io/react-native-webrtc';
11
11
  import { useCall } from '@stream-io/video-react-bindings';
12
- import { Platform } from 'react-native';
12
+ import { Image, Platform } from 'react-native';
13
13
 
14
14
  const isSupported = (function () {
15
15
  if (Platform.OS === 'ios') {
@@ -29,8 +29,6 @@ try {
29
29
  videoFiltersModule = require('@stream-io/video-filters-react-native');
30
30
  } catch (_e) {}
31
31
 
32
- import { Image } from 'react-native';
33
-
34
32
  const resolveAssetSourceFunc = Image.resolveAssetSource;
35
33
 
36
34
  // excluding array of images and only allow one image
@@ -173,7 +171,6 @@ export const BackgroundFiltersProvider = ({ children }: PropsWithChildren) => {
173
171
  (call?.camera.state.mediaStream as MediaStream | undefined)
174
172
  ?.getVideoTracks()
175
173
  .forEach((track) => {
176
- // @ts-expect-error - webrtc typing is wrong, null is supported
177
174
  track._setVideoEffect(null);
178
175
  });
179
176
  setCurrentBackgroundFilter(undefined);
@@ -2,6 +2,7 @@ import { CallingState } from '@stream-io/video-client';
2
2
  import { useCallStateHooks } from '@stream-io/video-react-bindings';
3
3
  import { useEffect } from 'react';
4
4
  import { NativeModules, Platform } from 'react-native';
5
+ import { disablePiPMode$ } from '../utils/internal/rxSubjects';
5
6
 
6
7
  export function useAutoEnterPiPEffect(
7
8
  disablePictureInPicture: boolean | undefined
@@ -10,7 +11,7 @@ export function useAutoEnterPiPEffect(
10
11
 
11
12
  const callingState = useCallCallingState();
12
13
 
13
- // if we need to enable, only enable in joined state
14
+ // if we need to enable autoEnter, only enable in joined state
14
15
  useEffect(() => {
15
16
  if (Platform.OS !== 'android') {
16
17
  return;
@@ -23,12 +24,14 @@ export function useAutoEnterPiPEffect(
23
24
  }
24
25
  }, [callingState, disablePictureInPicture]);
25
26
 
26
- // on unmount always disable PiP mode
27
27
  useEffect(() => {
28
+ disablePiPMode$.next(disablePictureInPicture === true);
29
+
28
30
  if (Platform.OS !== 'android') {
29
31
  return;
30
32
  }
31
33
 
34
+ // on unmount always disable PiP mode auto enter
32
35
  return () => {
33
36
  NativeModules.StreamVideoReactNative.canAutoEnterPipMode(false);
34
37
  };
@@ -1,60 +1,24 @@
1
1
  import { useEffect, useState } from 'react';
2
- import {
3
- AppState,
4
- NativeEventEmitter,
5
- NativeModules,
6
- Platform,
7
- } from 'react-native';
2
+ import { RxUtils } from '@stream-io/video-client';
3
+ import { isInPiPModeAndroid$ } from '../utils/internal/rxSubjects';
8
4
 
9
- const PIP_CHANGE_EVENT = 'StreamVideoReactNative_PIP_CHANGE_EVENT';
10
-
11
- const isAndroid8OrAbove = Platform.OS === 'android' && Platform.Version >= 26;
12
-
13
- export function useIsInPiPMode(disablePictureInPicture: boolean | undefined) {
14
- const [isInPiPMode, setIsInPiPMode] = useState(
15
- disablePictureInPicture &&
16
- isAndroid8OrAbove &&
17
- AppState.currentState === 'background'
18
- );
5
+ export function useIsInPiPMode() {
6
+ const [value, setValue] = useState<boolean>(() => {
7
+ return RxUtils.getCurrentValue(isInPiPModeAndroid$);
8
+ });
19
9
 
20
10
  useEffect(() => {
21
- if (!isAndroid8OrAbove) {
22
- return;
23
- }
24
-
25
- const eventEmitter = new NativeEventEmitter(
26
- NativeModules.StreamVideoReactNative
27
- );
28
-
29
- const subscriptionPiPChange = eventEmitter.addListener(
30
- PIP_CHANGE_EVENT,
31
- setIsInPiPMode
32
- );
33
-
34
- const setFromNativeMethod = async () => {
35
- const isInPiPNativeMethod: boolean | null | undefined =
36
- await NativeModules?.StreamVideoReactNative?.isInPiPMode();
37
- setIsInPiPMode(!!isInPiPNativeMethod);
38
- };
39
-
40
- const subscriptionAppState = AppState.addEventListener(
41
- 'change',
42
- (nextAppState) => {
43
- if (nextAppState === 'background') {
44
- setIsInPiPMode(!disablePictureInPicture); // set with an assumption that its enabled so that UI disabling happens faster
45
- // if PiP was not enabled anyway, then in the next code we ll set it to false and UI wont be shown anyway
46
- }
47
- setFromNativeMethod();
48
- }
49
- );
50
-
51
- setFromNativeMethod();
52
-
11
+ const subscription = isInPiPModeAndroid$.subscribe({
12
+ next: setValue,
13
+ error: (err) => {
14
+ console.log('An error occurred while reading isInPiPModeAndroid$', err);
15
+ setValue(false);
16
+ },
17
+ });
53
18
  return () => {
54
- subscriptionPiPChange.remove();
55
- subscriptionAppState.remove();
19
+ subscription.unsubscribe();
56
20
  };
57
- }, [disablePictureInPicture]);
21
+ }, []);
58
22
 
59
- return isInPiPMode;
23
+ return value;
60
24
  }
@@ -0,0 +1,125 @@
1
+ import { useCall } from '@stream-io/video-react-bindings';
2
+ import { useEffect, useRef } from 'react';
3
+ import {
4
+ AppState,
5
+ NativeEventEmitter,
6
+ NativeModules,
7
+ Platform,
8
+ } from 'react-native';
9
+ import { shouldDisableIOSLocalVideoOnBackgroundRef } from '../../utils/internal/shouldDisableIOSLocalVideoOnBackground';
10
+ import {
11
+ disablePiPMode$,
12
+ isInPiPModeAndroid$,
13
+ } from '../../utils/internal/rxSubjects';
14
+ import { RxUtils } from '@stream-io/video-client';
15
+
16
+ const PIP_CHANGE_EVENT = 'StreamVideoReactNative_PIP_CHANGE_EVENT';
17
+
18
+ const isAndroid8OrAbove = Platform.OS === 'android' && Platform.Version >= 26;
19
+
20
+ // Does 2 functionalities:
21
+ // 1. Resume/Disable video stream tracks when app goes to background/foreground - To save on CPU resources
22
+ // 2. Handle PiP mode in Android
23
+ export const AppStateListener = () => {
24
+ const call = useCall();
25
+ const appState = useRef(AppState.currentState);
26
+
27
+ // on mount: set initial PiP mode and listen to PiP events
28
+ useEffect(() => {
29
+ if (!isAndroid8OrAbove) {
30
+ return;
31
+ }
32
+
33
+ const disablePiP = RxUtils.getCurrentValue(disablePiPMode$);
34
+ isInPiPModeAndroid$.next(
35
+ !disablePiP && AppState.currentState === 'background'
36
+ );
37
+
38
+ const eventEmitter = new NativeEventEmitter(
39
+ NativeModules.StreamVideoReactNative
40
+ );
41
+
42
+ const subscriptionPiPChange = eventEmitter.addListener(
43
+ PIP_CHANGE_EVENT,
44
+ (isInPiPMode: boolean) => {
45
+ isInPiPModeAndroid$.next(isInPiPMode);
46
+ }
47
+ );
48
+
49
+ return () => {
50
+ subscriptionPiPChange.remove();
51
+ };
52
+ }, []);
53
+
54
+ useEffect(() => {
55
+ // due to strange behavior in iOS when app goes to "inactive" state
56
+ // we dont check for inactive states
57
+ // ref: https://www.reddit.com/r/reactnative/comments/15kib42/appstate_behavior_in_ios_when_swiping_down_to/
58
+ const subscription = AppState.addEventListener('change', (nextAppState) => {
59
+ if (appState.current.match(/background/) && nextAppState === 'active') {
60
+ if (
61
+ call?.camera?.state.status === 'enabled' &&
62
+ Platform.OS === 'android'
63
+ ) {
64
+ // when device is locked and resumed, the status isnt made disabled but stays enabled
65
+ // as a workaround we stop the track and enable again if its already in enabled state
66
+ call?.camera?.disable(true).then(() => {
67
+ call?.camera?.enable();
68
+ });
69
+ } else {
70
+ call?.camera?.resume();
71
+ }
72
+ appState.current = nextAppState;
73
+ } else if (
74
+ appState.current === 'active' &&
75
+ nextAppState.match(/background/)
76
+ ) {
77
+ if (Platform.OS === 'android') {
78
+ // in Android, we need to check if we are in PiP mode
79
+ // in PiP mode, we don't want to disable the camera
80
+ const disableCameraIfNeeded = () => {
81
+ if (call?.camera?.state.status === 'enabled') {
82
+ call?.camera?.disable();
83
+ }
84
+ };
85
+ if (isAndroid8OrAbove) {
86
+ // set with an assumption that its enabled so that UI disabling happens faster
87
+ const disablePiP = RxUtils.getCurrentValue(disablePiPMode$);
88
+ isInPiPModeAndroid$.next(!disablePiP);
89
+ // if PiP was not enabled anyway, then in the next code we ll set it to false and UI wont be shown anyway
90
+ NativeModules?.StreamVideoReactNative?.isInPiPMode().then(
91
+ (isInPiP: boolean | null | undefined) => {
92
+ isInPiPModeAndroid$.next(!!isInPiP);
93
+ if (!isInPiP) {
94
+ if (AppState.currentState === 'active') {
95
+ // this is to handle the case that the app became active as soon as it went to background
96
+ // in this case, we dont want to disable the camera
97
+ // this happens on foreground push notifications
98
+ return;
99
+ }
100
+ disableCameraIfNeeded();
101
+ }
102
+ }
103
+ );
104
+ } else {
105
+ disableCameraIfNeeded();
106
+ }
107
+ } else {
108
+ // shouldDisableIOSLocalVideoOnBackgroundRef is false, if local video is enabled on PiP
109
+ if (shouldDisableIOSLocalVideoOnBackgroundRef.current) {
110
+ if (call?.camera?.state.status === 'enabled') {
111
+ call?.camera?.disable();
112
+ }
113
+ }
114
+ }
115
+ appState.current = nextAppState;
116
+ }
117
+ });
118
+
119
+ return () => {
120
+ subscription.remove();
121
+ };
122
+ }, [call]);
123
+
124
+ return null;
125
+ };
@@ -0,0 +1,59 @@
1
+ import { useCallStateHooks } from '@stream-io/video-react-bindings';
2
+ import { useEffect } from 'react';
3
+ import {
4
+ CallingState,
5
+ setThermalState,
6
+ setPowerState,
7
+ } from '@stream-io/video-client';
8
+ import { NativeModules, Platform, NativeEventEmitter } from 'react-native';
9
+
10
+ const eventEmitter = NativeModules?.StreamVideoReactNative
11
+ ? new NativeEventEmitter(NativeModules?.StreamVideoReactNative)
12
+ : undefined;
13
+
14
+ /**
15
+ * This is a renderless component to get the device stats like thermal state and power saver mode.
16
+ */
17
+ export const DeviceStats = () => {
18
+ const { useCallCallingState } = useCallStateHooks();
19
+ const callingState = useCallCallingState();
20
+
21
+ useEffect(() => {
22
+ if (callingState !== CallingState.JOINED) {
23
+ return;
24
+ }
25
+
26
+ NativeModules?.StreamVideoReactNative.isLowPowerModeEnabled().then(
27
+ (initialPowerMode: boolean) => setPowerState(initialPowerMode)
28
+ );
29
+
30
+ let powerModeSubscription = eventEmitter?.addListener(
31
+ 'isLowPowerModeEnabled',
32
+ (isLowPowerMode: boolean) => setPowerState(isLowPowerMode)
33
+ );
34
+
35
+ NativeModules?.StreamVideoReactNative.currentThermalState().then(
36
+ (initialState: string) => setThermalState(initialState)
37
+ );
38
+
39
+ let thermalStateSubscription = eventEmitter?.addListener(
40
+ 'thermalStateDidChange',
41
+ (thermalState: string) => setThermalState(thermalState)
42
+ );
43
+
44
+ // on android we need to explicitly start and stop the thermal status updates
45
+ if (Platform.OS === 'android') {
46
+ NativeModules?.StreamVideoReactNative.startThermalStatusUpdates();
47
+ }
48
+
49
+ return () => {
50
+ powerModeSubscription?.remove();
51
+ thermalStateSubscription?.remove();
52
+ if (Platform.OS === 'android') {
53
+ NativeModules?.StreamVideoReactNative.stopThermalStatusUpdates();
54
+ }
55
+ };
56
+ }, [callingState]);
57
+
58
+ return null;
59
+ };
@@ -0,0 +1,78 @@
1
+ import { StreamCallProvider } from '@stream-io/video-react-bindings';
2
+ import React, { PropsWithChildren, useEffect } from 'react';
3
+ import { Call } from '@stream-io/video-client';
4
+ import { useIosCallkeepWithCallingStateEffect } from '../../hooks/push/useIosCallkeepWithCallingStateEffect';
5
+ import {
6
+ canAddPushWSSubscriptionsRef,
7
+ clearPushWSEventSubscriptions,
8
+ } from '../../utils/push/internal/utils';
9
+ import { useAndroidKeepCallAliveEffect } from '../../hooks/useAndroidKeepCallAliveEffect';
10
+ import { AppStateListener } from './AppStateListener';
11
+ import { DeviceStats } from './DeviceStats';
12
+
13
+ // const PIP_CHANGE_EVENT = 'StreamVideoReactNative_PIP_CHANGE_EVENT';
14
+
15
+ // const isAndroid8OrAbove = Platform.OS === 'android' && Platform.Version >= 26;
16
+
17
+ export type StreamCallProps = {
18
+ /**
19
+ * Stream Call instance propagated to the component's children as a part of StreamCallContext.
20
+ * Children can access it with useCall() hook.
21
+ */
22
+ call: Call;
23
+ };
24
+ /**
25
+ * StreamCall is a wrapper component that orchestrates the call life cycle logic and
26
+ * provides the call object to the children components.
27
+ * @param PropsWithChildren<StreamCallProps>
28
+ *
29
+ * @category Client State
30
+ */
31
+ export const StreamCall = ({
32
+ call,
33
+ children,
34
+ }: PropsWithChildren<StreamCallProps>) => {
35
+ return (
36
+ <StreamCallProvider call={call}>
37
+ <AppStateListener />
38
+ <AndroidKeepCallAlive />
39
+ <IosInformCallkeepCallEnd />
40
+ <ClearPushWSSubscriptions />
41
+ <DeviceStats />
42
+ {children}
43
+ </StreamCallProvider>
44
+ );
45
+ };
46
+
47
+ /**
48
+ * This is a renderless component to keep the call alive on Android device using useAndroidKeepCallAliveEffect.
49
+ * useAndroidKeepCallAliveEffect needs to called inside a child of StreamCallProvider.
50
+ */
51
+ const AndroidKeepCallAlive = () => {
52
+ useAndroidKeepCallAliveEffect();
53
+ return null;
54
+ };
55
+
56
+ /**
57
+ * This is a renderless component to end the call in callkeep for ios.
58
+ * useAndroidKeepCallAliveEffect needs to called inside a child of StreamCallProvider.
59
+ */
60
+ const IosInformCallkeepCallEnd = () => {
61
+ useIosCallkeepWithCallingStateEffect();
62
+ return null;
63
+ };
64
+
65
+ /**
66
+ * This is a renderless component to clear all push ws event subscriptions
67
+ * and set whether push ws subscriptions can be added or not.
68
+ */
69
+ const ClearPushWSSubscriptions = () => {
70
+ useEffect(() => {
71
+ clearPushWSEventSubscriptions();
72
+ canAddPushWSSubscriptionsRef.current = false;
73
+ return () => {
74
+ canAddPushWSSubscriptionsRef.current = true;
75
+ };
76
+ }, []);
77
+ return null;
78
+ };
@@ -1,4 +1,7 @@
1
- import { PublishOptions, StreamVideoClient } from '@stream-io/video-client';
1
+ import {
2
+ ClientPublishOptions,
3
+ StreamVideoClient,
4
+ } from '@stream-io/video-client';
2
5
  import type { AndroidChannel } from '@notifee/react-native';
3
6
 
4
7
  export type NonRingingPushEvent = 'call.live_started' | 'call.notification';
@@ -16,7 +19,7 @@ export type StreamVideoConfig = {
16
19
  *
17
20
  * @internal
18
21
  */
19
- publishOptions?: PublishOptions;
22
+ publishOptions?: ClientPublishOptions;
20
23
  ios: {
21
24
  /**
22
25
  * The name for the alias of push provider used for iOS
@@ -0,0 +1,5 @@
1
+ import { BehaviorSubject } from 'rxjs';
2
+
3
+ export const isInPiPModeAndroid$ = new BehaviorSubject<boolean>(false);
4
+
5
+ export const disablePiPMode$ = new BehaviorSubject<boolean>(false);
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '1.7.0';
1
+ export const version = '1.9.0';
@@ -1,155 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.StreamCall = void 0;
7
- var _videoReactBindings = require("@stream-io/video-react-bindings");
8
- var _react = _interopRequireWildcard(require("react"));
9
- var _videoClient = require("@stream-io/video-client");
10
- var _useIosCallkeepWithCallingStateEffect = require("../hooks/push/useIosCallkeepWithCallingStateEffect");
11
- var _utils = require("../utils/push/internal/utils");
12
- var _useAndroidKeepCallAliveEffect = require("../hooks/useAndroidKeepCallAliveEffect");
13
- var _reactNative = require("react-native");
14
- var _shouldDisableIOSLocalVideoOnBackground = require("../utils/internal/shouldDisableIOSLocalVideoOnBackground");
15
- function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
16
- function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
17
- /**
18
- * StreamCall is a wrapper component that orchestrates the call life cycle logic and
19
- * provides the call object to the children components.
20
- * @param PropsWithChildren<StreamCallProps>
21
- *
22
- * @category Client State
23
- */
24
- const StreamCall = ({
25
- call,
26
- children
27
- }) => {
28
- return /*#__PURE__*/_react.default.createElement(_videoReactBindings.StreamCallProvider, {
29
- call: call
30
- }, /*#__PURE__*/_react.default.createElement(AppStateListener, null), /*#__PURE__*/_react.default.createElement(AndroidKeepCallAlive, null), /*#__PURE__*/_react.default.createElement(IosInformCallkeepCallEnd, null), /*#__PURE__*/_react.default.createElement(ClearPushWSSubscriptions, null), /*#__PURE__*/_react.default.createElement(DeviceStats, null), children);
31
- };
32
-
33
- // Resume/Disable video stream tracks when app goes to background/foreground
34
- // To save on CPU resources
35
- exports.StreamCall = StreamCall;
36
- const AppStateListener = () => {
37
- const call = (0, _videoReactBindings.useCall)();
38
- const appState = (0, _react.useRef)(_reactNative.AppState.currentState);
39
- (0, _react.useEffect)(() => {
40
- // due to strange behavior in iOS when app goes to "inactive" state
41
- // we dont check for inactive states
42
- // ref: https://www.reddit.com/r/reactnative/comments/15kib42/appstate_behavior_in_ios_when_swiping_down_to/
43
- const subscription = _reactNative.AppState.addEventListener('change', nextAppState => {
44
- if (appState.current.match(/background/) && nextAppState === 'active') {
45
- if (call?.camera?.state.status === 'enabled' && _reactNative.Platform.OS === 'android') {
46
- // when device is locked and resumed, the status isnt made disabled but stays enabled
47
- // as a workaround we stop the track and enable again if its already in enabled state
48
- call?.camera?.disable(true).then(() => {
49
- call?.camera?.enable();
50
- });
51
- } else {
52
- call?.camera?.resume();
53
- }
54
- appState.current = nextAppState;
55
- } else if (appState.current === 'active' && nextAppState.match(/background/)) {
56
- if (_reactNative.Platform.OS === 'android') {
57
- // in Android, we need to check if we are in PiP mode
58
- // in PiP mode, we don't want to disable the camera
59
- _reactNative.NativeModules?.StreamVideoReactNative?.isInPiPMode().then(isInPiP => {
60
- if (!isInPiP) {
61
- if (_reactNative.AppState.currentState === 'active') {
62
- // this is to handle the case that the app became active as soon as it went to background
63
- // in this case, we dont want to disable the camera
64
- // this happens on foreground push notifications
65
- return;
66
- }
67
- if (call?.camera?.state.status === 'enabled') {
68
- call?.camera?.disable();
69
- }
70
- }
71
- });
72
- } else {
73
- // shouldDisableIOSLocalVideoOnBackgroundRef is false, if local video is enabled on PiP
74
- if (_shouldDisableIOSLocalVideoOnBackground.shouldDisableIOSLocalVideoOnBackgroundRef.current) {
75
- if (call?.camera?.state.status === 'enabled') {
76
- call?.camera?.disable();
77
- }
78
- }
79
- }
80
- appState.current = nextAppState;
81
- }
82
- });
83
- return () => {
84
- subscription.remove();
85
- };
86
- }, [call]);
87
- return null;
88
- };
89
-
90
- /**
91
- * This is a renderless component to keep the call alive on Android device using useAndroidKeepCallAliveEffect.
92
- * useAndroidKeepCallAliveEffect needs to called inside a child of StreamCallProvider.
93
- */
94
- const AndroidKeepCallAlive = () => {
95
- (0, _useAndroidKeepCallAliveEffect.useAndroidKeepCallAliveEffect)();
96
- return null;
97
- };
98
-
99
- /**
100
- * This is a renderless component to end the call in callkeep for ios.
101
- * useAndroidKeepCallAliveEffect needs to called inside a child of StreamCallProvider.
102
- */
103
- const IosInformCallkeepCallEnd = () => {
104
- (0, _useIosCallkeepWithCallingStateEffect.useIosCallkeepWithCallingStateEffect)();
105
- return null;
106
- };
107
-
108
- /**
109
- * This is a renderless component to clear all push ws event subscriptions
110
- * and set whether push ws subscriptions can be added or not.
111
- */
112
- const ClearPushWSSubscriptions = () => {
113
- (0, _react.useEffect)(() => {
114
- (0, _utils.clearPushWSEventSubscriptions)();
115
- _utils.canAddPushWSSubscriptionsRef.current = false;
116
- return () => {
117
- _utils.canAddPushWSSubscriptionsRef.current = true;
118
- };
119
- }, []);
120
- return null;
121
- };
122
- const eventEmitter = _reactNative.NativeModules?.StreamVideoReactNative ? new _reactNative.NativeEventEmitter(_reactNative.NativeModules?.StreamVideoReactNative) : undefined;
123
-
124
- /**
125
- * This is a renderless component to get the device stats like thermal state and power saver mode.
126
- */
127
- const DeviceStats = () => {
128
- const {
129
- useCallCallingState
130
- } = (0, _videoReactBindings.useCallStateHooks)();
131
- const callingState = useCallCallingState();
132
- (0, _react.useEffect)(() => {
133
- if (callingState !== _videoClient.CallingState.JOINED) {
134
- return;
135
- }
136
- _reactNative.NativeModules?.StreamVideoReactNative.isLowPowerModeEnabled().then(initialPowerMode => (0, _videoClient.setPowerState)(initialPowerMode));
137
- let powerModeSubscription = eventEmitter?.addListener('isLowPowerModeEnabled', isLowPowerMode => (0, _videoClient.setPowerState)(isLowPowerMode));
138
- _reactNative.NativeModules?.StreamVideoReactNative.currentThermalState().then(initialState => (0, _videoClient.setThermalState)(initialState));
139
- let thermalStateSubscription = eventEmitter?.addListener('thermalStateDidChange', thermalState => (0, _videoClient.setThermalState)(thermalState));
140
-
141
- // on android we need to explicitly start and stop the thermal status updates
142
- if (_reactNative.Platform.OS === 'android') {
143
- _reactNative.NativeModules?.StreamVideoReactNative.startThermalStatusUpdates();
144
- }
145
- return () => {
146
- powerModeSubscription?.remove();
147
- thermalStateSubscription?.remove();
148
- if (_reactNative.Platform.OS === 'android') {
149
- _reactNative.NativeModules?.StreamVideoReactNative.stopThermalStatusUpdates();
150
- }
151
- };
152
- }, [callingState]);
153
- return null;
154
- };
155
- //# sourceMappingURL=StreamCall.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["_videoReactBindings","require","_react","_interopRequireWildcard","_videoClient","_useIosCallkeepWithCallingStateEffect","_utils","_useAndroidKeepCallAliveEffect","_reactNative","_shouldDisableIOSLocalVideoOnBackground","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","hasOwnProperty","call","i","set","StreamCall","children","createElement","StreamCallProvider","AppStateListener","AndroidKeepCallAlive","IosInformCallkeepCallEnd","ClearPushWSSubscriptions","DeviceStats","exports","useCall","appState","useRef","AppState","currentState","useEffect","subscription","addEventListener","nextAppState","current","match","camera","state","status","Platform","OS","disable","then","enable","resume","NativeModules","StreamVideoReactNative","isInPiPMode","isInPiP","shouldDisableIOSLocalVideoOnBackgroundRef","remove","useAndroidKeepCallAliveEffect","useIosCallkeepWithCallingStateEffect","clearPushWSEventSubscriptions","canAddPushWSSubscriptionsRef","eventEmitter","NativeEventEmitter","undefined","useCallCallingState","useCallStateHooks","callingState","CallingState","JOINED","isLowPowerModeEnabled","initialPowerMode","setPowerState","powerModeSubscription","addListener","isLowPowerMode","currentThermalState","initialState","setThermalState","thermalStateSubscription","thermalState","startThermalStatusUpdates","stopThermalStatusUpdates"],"sourceRoot":"../../../src","sources":["providers/StreamCall.tsx"],"mappings":"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","ignoreList":[]}