@stream-io/video-react-native-sdk 1.0.0-rc2.0 → 1.0.1
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.
- package/CHANGELOG.md +14 -83
- package/dist/commonjs/components/Call/CallContent/CallContent.js +10 -5
- package/dist/commonjs/components/Call/CallContent/CallContent.js.map +1 -1
- package/dist/commonjs/components/Call/CallContent/RTCViewPipIOS.js +109 -0
- package/dist/commonjs/components/Call/CallContent/RTCViewPipIOS.js.map +1 -0
- package/dist/commonjs/components/Call/CallContent/index.js +11 -0
- package/dist/commonjs/components/Call/CallContent/index.js.map +1 -1
- package/dist/commonjs/components/Call/CallLayout/CallParticipantsGrid.js +4 -3
- package/dist/commonjs/components/Call/CallLayout/CallParticipantsGrid.js.map +1 -1
- package/dist/commonjs/components/Call/CallLayout/CallParticipantsSpotlight.js +4 -3
- package/dist/commonjs/components/Call/CallLayout/CallParticipantsSpotlight.js.map +1 -1
- package/dist/commonjs/hooks/useAutoEnterPiPEffect.js +3 -3
- package/dist/commonjs/hooks/useAutoEnterPiPEffect.js.map +1 -1
- package/dist/commonjs/hooks/useIsInPiPMode.js +4 -4
- package/dist/commonjs/hooks/useIsInPiPMode.js.map +1 -1
- package/dist/commonjs/providers/StreamCall.js +5 -2
- package/dist/commonjs/providers/StreamCall.js.map +1 -1
- package/dist/commonjs/utils/internal/shouldDisableIOSLocalVideoOnBackground.js +10 -0
- package/dist/commonjs/utils/internal/shouldDisableIOSLocalVideoOnBackground.js.map +1 -0
- package/dist/commonjs/version.js +1 -1
- package/dist/commonjs/version.js.map +1 -1
- package/dist/module/components/Call/CallContent/CallContent.js +10 -5
- package/dist/module/components/Call/CallContent/CallContent.js.map +1 -1
- package/dist/module/components/Call/CallContent/RTCViewPipIOS.js +101 -0
- package/dist/module/components/Call/CallContent/RTCViewPipIOS.js.map +1 -0
- package/dist/module/components/Call/CallContent/index.js +1 -0
- package/dist/module/components/Call/CallContent/index.js.map +1 -1
- package/dist/module/components/Call/CallLayout/CallParticipantsGrid.js +4 -3
- package/dist/module/components/Call/CallLayout/CallParticipantsGrid.js.map +1 -1
- package/dist/module/components/Call/CallLayout/CallParticipantsSpotlight.js +4 -3
- package/dist/module/components/Call/CallLayout/CallParticipantsSpotlight.js.map +1 -1
- package/dist/module/hooks/useAutoEnterPiPEffect.js +3 -3
- package/dist/module/hooks/useAutoEnterPiPEffect.js.map +1 -1
- package/dist/module/hooks/useIsInPiPMode.js +4 -4
- package/dist/module/hooks/useIsInPiPMode.js.map +1 -1
- package/dist/module/providers/StreamCall.js +5 -2
- package/dist/module/providers/StreamCall.js.map +1 -1
- package/dist/module/utils/internal/shouldDisableIOSLocalVideoOnBackground.js +4 -0
- package/dist/module/utils/internal/shouldDisableIOSLocalVideoOnBackground.js.map +1 -0
- package/dist/module/version.js +1 -1
- package/dist/module/version.js.map +1 -1
- package/dist/typescript/components/Call/CallContent/CallContent.d.ts +6 -1
- package/dist/typescript/components/Call/CallContent/CallContent.d.ts.map +1 -1
- package/dist/typescript/components/Call/CallContent/RTCViewPipIOS.d.ts +7 -0
- package/dist/typescript/components/Call/CallContent/RTCViewPipIOS.d.ts.map +1 -0
- package/dist/typescript/components/Call/CallContent/index.d.ts +1 -0
- package/dist/typescript/components/Call/CallContent/index.d.ts.map +1 -1
- package/dist/typescript/components/Call/CallLayout/CallParticipantsGrid.d.ts +2 -2
- package/dist/typescript/components/Call/CallLayout/CallParticipantsGrid.d.ts.map +1 -1
- package/dist/typescript/components/Call/CallLayout/CallParticipantsSpotlight.d.ts +2 -2
- package/dist/typescript/components/Call/CallLayout/CallParticipantsSpotlight.d.ts.map +1 -1
- package/dist/typescript/hooks/useAutoEnterPiPEffect.d.ts +1 -1
- package/dist/typescript/hooks/useAutoEnterPiPEffect.d.ts.map +1 -1
- package/dist/typescript/hooks/useIsInPiPMode.d.ts +1 -1
- package/dist/typescript/hooks/useIsInPiPMode.d.ts.map +1 -1
- package/dist/typescript/providers/StreamCall.d.ts.map +1 -1
- package/dist/typescript/utils/internal/shouldDisableIOSLocalVideoOnBackground.d.ts +4 -0
- package/dist/typescript/utils/internal/shouldDisableIOSLocalVideoOnBackground.d.ts.map +1 -0
- package/dist/typescript/version.d.ts +1 -1
- package/dist/typescript/version.d.ts.map +1 -1
- package/ios/PictureInPicture/SampleBufferVideoCallView.swift +52 -0
- package/ios/PictureInPicture/StreamAVPictureInPictureVideoCallViewController.swift +83 -0
- package/ios/PictureInPicture/StreamBufferTransformer.swift +96 -0
- package/ios/PictureInPicture/StreamPictureInPictureController.swift +185 -0
- package/ios/PictureInPicture/StreamPictureInPictureTrackStateAdapter.swift +68 -0
- package/ios/PictureInPicture/StreamPictureInPictureVideoRenderer.swift +250 -0
- package/ios/PictureInPicture/StreamPixelBufferPool.swift +118 -0
- package/ios/PictureInPicture/StreamPixelBufferRepository.swift +98 -0
- package/ios/PictureInPicture/StreamRTCYUVBuffer.swift +249 -0
- package/ios/PictureInPicture/StreamYUVToARGBConversion.swift +128 -0
- package/ios/PictureInPicture/WindowSizePolicy/StreamPictureInPictureAdaptiveWindowSizePolicy.swift +25 -0
- package/ios/PictureInPicture/WindowSizePolicy/StreamPictureInPictureFixedWindowSizePolicy.swift +29 -0
- package/ios/PictureInPicture/WindowSizePolicy/StreamPictureInPictureWindowSizePolicy.swift +14 -0
- package/ios/PictureInPicture/YpCbCrPixelRange+Default.swift +32 -0
- package/ios/RTCViewPip.swift +69 -0
- package/ios/RTCViewPipManager.mm +16 -0
- package/ios/RTCViewPipManager.swift +34 -0
- package/ios/StreamVideoReactNative-Bridging-Header.h +11 -0
- package/package.json +4 -4
- package/src/components/Call/CallContent/CallContent.tsx +58 -40
- package/src/components/Call/CallContent/RTCViewPipIOS.tsx +138 -0
- package/src/components/Call/CallContent/index.ts +1 -0
- package/src/components/Call/CallLayout/CallParticipantsGrid.tsx +7 -3
- package/src/components/Call/CallLayout/CallParticipantsSpotlight.tsx +7 -3
- package/src/hooks/useAutoEnterPiPEffect.tsx +7 -3
- package/src/hooks/useIsInPiPMode.tsx +6 -4
- package/src/providers/StreamCall.tsx +5 -2
- package/src/utils/internal/shouldDisableIOSLocalVideoOnBackground.ts +3 -0
- package/src/version.ts +1 -1
- package/stream-video-react-native.podspec +27 -4
- package/ios/StreamVideoReactNative.xcodeproj/project.pbxproj +0 -274
- package/ios/StreamVideoReactNative.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/ios/StreamVideoReactNative.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
ScreenShareOverlay as DefaultScreenShareOverlay,
|
|
38
38
|
ScreenShareOverlayProps,
|
|
39
39
|
} from '../../utility/ScreenShareOverlay';
|
|
40
|
+
import RTCViewPipIOS from './RTCViewPipIOS';
|
|
40
41
|
|
|
41
42
|
export type StreamReactionType = StreamReaction & {
|
|
42
43
|
icon: string;
|
|
@@ -88,6 +89,14 @@ export type CallContentProps = Pick<
|
|
|
88
89
|
* This will apply the landscape mode styles to the component.
|
|
89
90
|
*/
|
|
90
91
|
landscape?: boolean;
|
|
92
|
+
/*
|
|
93
|
+
* If true, includes the local participant video in the PiP mode for iOS
|
|
94
|
+
*/
|
|
95
|
+
iOSPiPIncludeLocalParticipantVideo?: boolean;
|
|
96
|
+
/**
|
|
97
|
+
* If true, disables the Picture-in-Picture mode for iOS and Android
|
|
98
|
+
*/
|
|
99
|
+
disablePictureInPicture?: boolean;
|
|
91
100
|
};
|
|
92
101
|
|
|
93
102
|
export const CallContent = ({
|
|
@@ -109,6 +118,8 @@ export const CallContent = ({
|
|
|
109
118
|
layout = 'grid',
|
|
110
119
|
landscape = false,
|
|
111
120
|
supportedReactions,
|
|
121
|
+
iOSPiPIncludeLocalParticipantVideo,
|
|
122
|
+
disablePictureInPicture,
|
|
112
123
|
}: CallContentProps) => {
|
|
113
124
|
const [
|
|
114
125
|
showRemoteParticipantInFloatingView,
|
|
@@ -124,7 +135,7 @@ export const CallContent = ({
|
|
|
124
135
|
useLocalParticipant,
|
|
125
136
|
} = useCallStateHooks();
|
|
126
137
|
|
|
127
|
-
useAutoEnterPiPEffect();
|
|
138
|
+
useAutoEnterPiPEffect(disablePictureInPicture);
|
|
128
139
|
|
|
129
140
|
const callSettings = useCallSettings();
|
|
130
141
|
const isVideoEnabledInCall = callSettings?.video.enabled;
|
|
@@ -132,7 +143,7 @@ export const CallContent = ({
|
|
|
132
143
|
const _remoteParticipants = useRemoteParticipants();
|
|
133
144
|
const remoteParticipants = useDebouncedValue(_remoteParticipants, 300); // we debounce the remote participants to avoid unnecessary rerenders that happen when participant tracks are all subscribed simultaneously
|
|
134
145
|
const localParticipant = useLocalParticipant();
|
|
135
|
-
const isInPiPMode = useIsInPiPMode();
|
|
146
|
+
const isInPiPMode = useIsInPiPMode(disablePictureInPicture);
|
|
136
147
|
const hasScreenShare = useHasOngoingScreenShare();
|
|
137
148
|
const showSpotlightLayout = hasScreenShare || layout === 'spotlight';
|
|
138
149
|
|
|
@@ -195,48 +206,55 @@ export const CallContent = ({
|
|
|
195
206
|
};
|
|
196
207
|
|
|
197
208
|
return (
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
<
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
>
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
209
|
+
<>
|
|
210
|
+
{!disablePictureInPicture && (
|
|
211
|
+
<RTCViewPipIOS
|
|
212
|
+
includeLocalParticipantVideo={iOSPiPIncludeLocalParticipantVideo}
|
|
213
|
+
/>
|
|
214
|
+
)}
|
|
215
|
+
<View style={[styles.container, landscapeStyles, callContent.container]}>
|
|
216
|
+
<View style={[styles.container, callContent.callParticipantsContainer]}>
|
|
217
|
+
<View
|
|
218
|
+
style={[styles.view, callContent.topContainer]}
|
|
219
|
+
// "box-none" disallows the container view to be not take up touches
|
|
220
|
+
// and allows only the top and floating view (its child views) to take up the touches
|
|
221
|
+
pointerEvents="box-none"
|
|
222
|
+
>
|
|
223
|
+
{!isInPiPMode && CallTopView && (
|
|
224
|
+
<CallTopView
|
|
225
|
+
onBackPressed={onBackPressed}
|
|
226
|
+
onParticipantInfoPress={onParticipantInfoPress}
|
|
227
|
+
ParticipantsInfoBadge={ParticipantsInfoBadge}
|
|
228
|
+
/>
|
|
229
|
+
)}
|
|
230
|
+
{showFloatingView && FloatingParticipantView && (
|
|
231
|
+
<FloatingParticipantView
|
|
232
|
+
participant={
|
|
233
|
+
isRemoteParticipantInFloatingView
|
|
234
|
+
? remoteParticipants[0]
|
|
235
|
+
: localParticipant
|
|
236
|
+
}
|
|
237
|
+
onPressHandler={handleFloatingViewParticipantSwitch}
|
|
238
|
+
supportedReactions={supportedReactions}
|
|
239
|
+
{...participantViewProps}
|
|
240
|
+
/>
|
|
241
|
+
)}
|
|
242
|
+
</View>
|
|
243
|
+
{showSpotlightLayout ? (
|
|
244
|
+
<CallParticipantsSpotlight {...callParticipantsSpotlightProps} />
|
|
245
|
+
) : (
|
|
246
|
+
<CallParticipantsGrid {...callParticipantsGridProps} />
|
|
224
247
|
)}
|
|
225
248
|
</View>
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
249
|
+
|
|
250
|
+
{!isInPiPMode && CallControls && (
|
|
251
|
+
<CallControls
|
|
252
|
+
onHangupCallHandler={onHangupCallHandler}
|
|
253
|
+
landscape={landscape}
|
|
254
|
+
/>
|
|
230
255
|
)}
|
|
231
256
|
</View>
|
|
232
|
-
|
|
233
|
-
{!isInPiPMode && CallControls && (
|
|
234
|
-
<CallControls
|
|
235
|
-
onHangupCallHandler={onHangupCallHandler}
|
|
236
|
-
landscape={landscape}
|
|
237
|
-
/>
|
|
238
|
-
)}
|
|
239
|
-
</View>
|
|
257
|
+
</>
|
|
240
258
|
);
|
|
241
259
|
};
|
|
242
260
|
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CallingState,
|
|
3
|
+
hasScreenShare,
|
|
4
|
+
speakerLayoutSortPreset,
|
|
5
|
+
} from '@stream-io/video-client';
|
|
6
|
+
import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
|
|
7
|
+
import type { MediaStream } from '@stream-io/react-native-webrtc';
|
|
8
|
+
import React, { useEffect } from 'react';
|
|
9
|
+
import {
|
|
10
|
+
findNodeHandle,
|
|
11
|
+
HostComponent,
|
|
12
|
+
Platform,
|
|
13
|
+
requireNativeComponent,
|
|
14
|
+
UIManager,
|
|
15
|
+
} from 'react-native';
|
|
16
|
+
import { useDebouncedValue } from '../../../utils/hooks/useDebouncedValue';
|
|
17
|
+
import { shouldDisableIOSLocalVideoOnBackgroundRef } from '../../../utils/internal/shouldDisableIOSLocalVideoOnBackground';
|
|
18
|
+
|
|
19
|
+
const COMPONENT_NAME = 'RTCViewPip';
|
|
20
|
+
|
|
21
|
+
type RTCViewPipNativeProps = {
|
|
22
|
+
streamURL?: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// workaround to support hot reloading
|
|
26
|
+
// https://medium.com/tribalscale/beyond-the-framework-using-react-native-with-swift-and-kotlin-cfccf4bb9a03
|
|
27
|
+
let RTCViewPipNative: HostComponent<RTCViewPipNativeProps>;
|
|
28
|
+
|
|
29
|
+
if (__DEV__) {
|
|
30
|
+
/* @ts-ignore */
|
|
31
|
+
const cachedView = global.RTCViewPipNative as
|
|
32
|
+
| HostComponent<RTCViewPipNativeProps>
|
|
33
|
+
| undefined;
|
|
34
|
+
if (!cachedView) {
|
|
35
|
+
RTCViewPipNative = requireNativeComponent(COMPONENT_NAME);
|
|
36
|
+
/* @ts-ignore */
|
|
37
|
+
global.RTCViewPipNative = RTCViewPipNative;
|
|
38
|
+
} else {
|
|
39
|
+
RTCViewPipNative = cachedView;
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
RTCViewPipNative = requireNativeComponent(COMPONENT_NAME);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Wrapper for the native view
|
|
46
|
+
* meant to stay private and not exposed */
|
|
47
|
+
const RTCViewPip = React.forwardRef<
|
|
48
|
+
React.Ref<any>,
|
|
49
|
+
{
|
|
50
|
+
streamURL?: string;
|
|
51
|
+
}
|
|
52
|
+
>((props, ref) => {
|
|
53
|
+
if (Platform.OS !== 'ios') return null;
|
|
54
|
+
// @ts-ignore
|
|
55
|
+
return <RTCViewPipNative streamURL={props.streamURL} ref={ref} />;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
type Props = {
|
|
59
|
+
includeLocalParticipantVideo?: boolean;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const RTCViewPipIOS = ({ includeLocalParticipantVideo }: Props) => {
|
|
63
|
+
const call = useCall();
|
|
64
|
+
const { useParticipants } = useCallStateHooks();
|
|
65
|
+
const _allParticipants = useParticipants({
|
|
66
|
+
sortBy: speakerLayoutSortPreset,
|
|
67
|
+
});
|
|
68
|
+
const allParticipants = useDebouncedValue(_allParticipants, 300); // we debounce the participants to avoid unnecessary rerenders that happen when participant tracks are all subscribed simultaneously
|
|
69
|
+
|
|
70
|
+
const [participantInSpotlight] = allParticipants.filter((participant) =>
|
|
71
|
+
includeLocalParticipantVideo ? true : !participant.isLocalParticipant
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
shouldDisableIOSLocalVideoOnBackgroundRef.current =
|
|
76
|
+
!includeLocalParticipantVideo;
|
|
77
|
+
}, [includeLocalParticipantVideo]);
|
|
78
|
+
|
|
79
|
+
const [videoStreamToRender, setVideoStreamToRender] =
|
|
80
|
+
React.useState<MediaStream>();
|
|
81
|
+
|
|
82
|
+
const nativeRef = React.useRef<any>(null);
|
|
83
|
+
|
|
84
|
+
React.useEffect(() => {
|
|
85
|
+
if (!participantInSpotlight) {
|
|
86
|
+
setVideoStreamToRender(undefined);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const { videoStream, screenShareStream } = participantInSpotlight;
|
|
90
|
+
|
|
91
|
+
const isScreenSharing = hasScreenShare(participantInSpotlight);
|
|
92
|
+
|
|
93
|
+
const _videoStreamToRender = (isScreenSharing
|
|
94
|
+
? screenShareStream
|
|
95
|
+
: videoStream) as unknown as MediaStream | undefined;
|
|
96
|
+
|
|
97
|
+
setVideoStreamToRender(_videoStreamToRender);
|
|
98
|
+
}, [participantInSpotlight]);
|
|
99
|
+
|
|
100
|
+
React.useEffect(() => {
|
|
101
|
+
let callClosedInvokedOnce = false;
|
|
102
|
+
const onCallClosed = () => {
|
|
103
|
+
if (callClosedInvokedOnce) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
callClosedInvokedOnce = true;
|
|
107
|
+
const node = findNodeHandle(nativeRef.current);
|
|
108
|
+
if (node !== null) {
|
|
109
|
+
UIManager.dispatchViewManagerCommand(
|
|
110
|
+
node,
|
|
111
|
+
// @ts-ignore
|
|
112
|
+
UIManager.getViewManagerConfig(COMPONENT_NAME).Commands.onCallClosed,
|
|
113
|
+
[]
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
shouldDisableIOSLocalVideoOnBackgroundRef.current = true;
|
|
117
|
+
};
|
|
118
|
+
const unsubFunc = call?.on('call.ended', () => {
|
|
119
|
+
onCallClosed();
|
|
120
|
+
});
|
|
121
|
+
const subscription = call?.state.callingState$.subscribe((state) => {
|
|
122
|
+
if (state === CallingState.LEFT || state === CallingState.IDLE) {
|
|
123
|
+
onCallClosed();
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
return () => {
|
|
127
|
+
onCallClosed();
|
|
128
|
+
unsubFunc?.();
|
|
129
|
+
subscription?.unsubscribe();
|
|
130
|
+
};
|
|
131
|
+
}, [call]);
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<RTCViewPip streamURL={videoStreamToRender?.toURL()} ref={nativeRef} />
|
|
135
|
+
);
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export default RTCViewPipIOS;
|
|
@@ -10,14 +10,17 @@ import { ComponentTestIds } from '../../../constants/TestIds';
|
|
|
10
10
|
import { useTheme } from '../../../contexts/ThemeContext';
|
|
11
11
|
import { CallContentProps } from '../CallContent';
|
|
12
12
|
import { ParticipantViewComponentProps } from '../../Participant';
|
|
13
|
-
import { useIsInPiPMode } from '../../../hooks';
|
|
13
|
+
import { useIsInPiPMode } from '../../../hooks/useIsInPiPMode';
|
|
14
14
|
import { StreamVideoParticipant } from '@stream-io/video-client';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Props for the CallParticipantsGrid component.
|
|
18
18
|
*/
|
|
19
19
|
export type CallParticipantsGridProps = ParticipantViewComponentProps &
|
|
20
|
-
Pick<
|
|
20
|
+
Pick<
|
|
21
|
+
CallContentProps,
|
|
22
|
+
'supportedReactions' | 'CallParticipantsList' | 'disablePictureInPicture'
|
|
23
|
+
> &
|
|
21
24
|
Pick<CallParticipantsListComponentProps, 'ParticipantView'> & {
|
|
22
25
|
/**
|
|
23
26
|
* Boolean to decide if local participant will be visible in the grid when there is 1:1 call.
|
|
@@ -44,6 +47,7 @@ export const CallParticipantsGrid = ({
|
|
|
44
47
|
showLocalParticipant = false,
|
|
45
48
|
supportedReactions,
|
|
46
49
|
landscape,
|
|
50
|
+
disablePictureInPicture,
|
|
47
51
|
}: CallParticipantsGridProps) => {
|
|
48
52
|
const {
|
|
49
53
|
theme: { colors, callParticipantsGrid },
|
|
@@ -60,7 +64,7 @@ export const CallParticipantsGrid = ({
|
|
|
60
64
|
flexDirection: landscape ? 'row' : 'column',
|
|
61
65
|
};
|
|
62
66
|
|
|
63
|
-
const isInPiPMode = useIsInPiPMode();
|
|
67
|
+
const isInPiPMode = useIsInPiPMode(disablePictureInPicture);
|
|
64
68
|
|
|
65
69
|
const showFloatingView =
|
|
66
70
|
!isInPiPMode &&
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
} from '../../Participant';
|
|
18
18
|
import { useTheme } from '../../../contexts/ThemeContext';
|
|
19
19
|
import { CallContentProps } from '../CallContent';
|
|
20
|
-
import { useIsInPiPMode } from '../../../hooks';
|
|
20
|
+
import { useIsInPiPMode } from '../../../hooks/useIsInPiPMode';
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Props for the CallParticipantsSpotlight component.
|
|
@@ -25,7 +25,10 @@ import { useIsInPiPMode } from '../../../hooks';
|
|
|
25
25
|
export type CallParticipantsSpotlightProps = ParticipantViewComponentProps &
|
|
26
26
|
Pick<
|
|
27
27
|
CallContentProps,
|
|
28
|
-
|
|
28
|
+
| 'supportedReactions'
|
|
29
|
+
| 'CallParticipantsList'
|
|
30
|
+
| 'ScreenShareOverlay'
|
|
31
|
+
| 'disablePictureInPicture'
|
|
29
32
|
> &
|
|
30
33
|
Pick<CallParticipantsListComponentProps, 'ParticipantView'> & {
|
|
31
34
|
/**
|
|
@@ -50,6 +53,7 @@ export const CallParticipantsSpotlight = ({
|
|
|
50
53
|
VideoRenderer,
|
|
51
54
|
supportedReactions,
|
|
52
55
|
landscape,
|
|
56
|
+
disablePictureInPicture,
|
|
53
57
|
}: CallParticipantsSpotlightProps) => {
|
|
54
58
|
const {
|
|
55
59
|
theme: { colors, callParticipantsSpotlight },
|
|
@@ -64,7 +68,7 @@ export const CallParticipantsSpotlight = ({
|
|
|
64
68
|
participantInSpotlight && hasScreenShare(participantInSpotlight);
|
|
65
69
|
const isUserAloneInCall = _allParticipants?.length === 1;
|
|
66
70
|
|
|
67
|
-
const isInPiP = useIsInPiPMode();
|
|
71
|
+
const isInPiP = useIsInPiPMode(disablePictureInPicture);
|
|
68
72
|
|
|
69
73
|
const participantViewProps: ParticipantViewComponentProps = {
|
|
70
74
|
ParticipantLabel,
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
2
|
import { NativeModules, Platform } from 'react-native';
|
|
3
3
|
|
|
4
|
-
export function useAutoEnterPiPEffect(
|
|
4
|
+
export function useAutoEnterPiPEffect(
|
|
5
|
+
disablePictureInPicture: boolean | undefined
|
|
6
|
+
) {
|
|
5
7
|
useEffect(() => {
|
|
6
8
|
if (Platform.OS !== 'android') {
|
|
7
9
|
return;
|
|
8
10
|
}
|
|
9
11
|
|
|
10
|
-
NativeModules.StreamVideoReactNative.canAutoEnterPipMode(
|
|
12
|
+
NativeModules.StreamVideoReactNative.canAutoEnterPipMode(
|
|
13
|
+
!disablePictureInPicture
|
|
14
|
+
);
|
|
11
15
|
|
|
12
16
|
return () => {
|
|
13
17
|
NativeModules.StreamVideoReactNative.canAutoEnterPipMode(false);
|
|
14
18
|
};
|
|
15
|
-
}, []);
|
|
19
|
+
}, [disablePictureInPicture]);
|
|
16
20
|
}
|
|
@@ -10,9 +10,11 @@ const PIP_CHANGE_EVENT = 'StreamVideoReactNative_PIP_CHANGE_EVENT';
|
|
|
10
10
|
|
|
11
11
|
const isAndroid8OrAbove = Platform.OS === 'android' && Platform.Version >= 26;
|
|
12
12
|
|
|
13
|
-
export function useIsInPiPMode() {
|
|
13
|
+
export function useIsInPiPMode(disablePictureInPicture: boolean | undefined) {
|
|
14
14
|
const [isInPiPMode, setIsInPiPMode] = useState(
|
|
15
|
-
|
|
15
|
+
disablePictureInPicture &&
|
|
16
|
+
isAndroid8OrAbove &&
|
|
17
|
+
AppState.currentState === 'background'
|
|
16
18
|
);
|
|
17
19
|
|
|
18
20
|
useEffect(() => {
|
|
@@ -39,7 +41,7 @@ export function useIsInPiPMode() {
|
|
|
39
41
|
'change',
|
|
40
42
|
(nextAppState) => {
|
|
41
43
|
if (nextAppState === 'background') {
|
|
42
|
-
setIsInPiPMode(
|
|
44
|
+
setIsInPiPMode(!disablePictureInPicture); // set with an assumption that its enabled so that UI disabling happens faster
|
|
43
45
|
// if PiP was not enabled anyway, then in the next code we ll set it to false and UI wont be shown anyway
|
|
44
46
|
}
|
|
45
47
|
setFromNativeMethod();
|
|
@@ -52,7 +54,7 @@ export function useIsInPiPMode() {
|
|
|
52
54
|
subscriptionPiPChange.remove();
|
|
53
55
|
subscriptionAppState.remove();
|
|
54
56
|
};
|
|
55
|
-
}, []);
|
|
57
|
+
}, [disablePictureInPicture]);
|
|
56
58
|
|
|
57
59
|
return isInPiPMode;
|
|
58
60
|
}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
} from '../utils/push/utils';
|
|
9
9
|
import { useAndroidKeepCallAliveEffect } from '../hooks/useAndroidKeepCallAliveEffect';
|
|
10
10
|
import { AppState, NativeModules, Platform } from 'react-native';
|
|
11
|
+
import { shouldDisableIOSLocalVideoOnBackgroundRef } from '../utils/internal/shouldDisableIOSLocalVideoOnBackground';
|
|
11
12
|
|
|
12
13
|
export type StreamCallProps = {
|
|
13
14
|
/**
|
|
@@ -77,7 +78,9 @@ const AppStateListener = () => {
|
|
|
77
78
|
}
|
|
78
79
|
);
|
|
79
80
|
} else {
|
|
80
|
-
|
|
81
|
+
if (shouldDisableIOSLocalVideoOnBackgroundRef.current) {
|
|
82
|
+
call?.camera?.disable();
|
|
83
|
+
}
|
|
81
84
|
}
|
|
82
85
|
appState.current = nextAppState;
|
|
83
86
|
}
|
|
@@ -92,7 +95,7 @@ const AppStateListener = () => {
|
|
|
92
95
|
};
|
|
93
96
|
|
|
94
97
|
/**
|
|
95
|
-
* This is a renderless component
|
|
98
|
+
* This is a renderless component to keep the call alive on Android device using useAndroidKeepCallAliveEffect.
|
|
96
99
|
* useAndroidKeepCallAliveEffect needs to called inside a child of StreamCallProvider.
|
|
97
100
|
*/
|
|
98
101
|
const AndroidKeepCallAlive = () => {
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.0.
|
|
1
|
+
export const version = '1.0.1';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require "json"
|
|
2
2
|
|
|
3
3
|
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
+
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
|
|
4
5
|
|
|
5
6
|
Pod::Spec.new do |s|
|
|
6
7
|
s.name = "stream-video-react-native"
|
|
@@ -10,11 +11,33 @@ Pod::Spec.new do |s|
|
|
|
10
11
|
s.license = package["license"]
|
|
11
12
|
s.authors = package["author"]
|
|
12
13
|
|
|
13
|
-
s.platforms = { :ios =>
|
|
14
|
+
s.platforms = { :ios => (min_ios_version_supported || '12.0') }
|
|
14
15
|
s.source = { :git => "https://github.com/GetStream/stream-video-js/tree/main/packages/react-native-sdk.git", :tag => "#{s.version}" }
|
|
15
16
|
|
|
16
|
-
s.source_files = "ios/**/*.{h,m,mm}"
|
|
17
|
-
|
|
18
|
-
s.dependency "React-Core"
|
|
17
|
+
s.source_files = "ios/**/*.{h,m,mm,swift}"
|
|
19
18
|
s.dependency "stream-react-native-webrtc"
|
|
19
|
+
|
|
20
|
+
# Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
|
|
21
|
+
# See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
|
|
22
|
+
if respond_to?(:install_modules_dependencies, true)
|
|
23
|
+
install_modules_dependencies(s)
|
|
24
|
+
else
|
|
25
|
+
s.dependency "React-Core"
|
|
26
|
+
|
|
27
|
+
# Don't install the dependencies when we run `pod install` in the old architecture.
|
|
28
|
+
if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
|
|
29
|
+
s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
|
|
30
|
+
s.pod_target_xcconfig = {
|
|
31
|
+
"HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
|
|
32
|
+
"OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
|
|
33
|
+
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
|
|
34
|
+
}
|
|
35
|
+
s.dependency "React-RCTFabric"
|
|
36
|
+
s.dependency "React-Codegen"
|
|
37
|
+
s.dependency "RCT-Folly"
|
|
38
|
+
s.dependency "RCTRequired"
|
|
39
|
+
s.dependency "RCTTypeSafety"
|
|
40
|
+
s.dependency "ReactCommon/turbomodule/core"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
20
43
|
end
|