agora-appbuilder-core 4.0.0-api.7 → 4.0.0-api.9
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/package.json +3 -3
- package/template/_package-lock.json +5911 -4861
- package/template/agora-rn-uikit/.eslintrc.js +5 -0
- package/template/agora-rn-uikit/package.json +14 -14
- package/template/agora-rn-uikit/src/Contexts/PropsContext.tsx +41 -22
- package/template/agora-rn-uikit/src/Contexts/RtcContext.tsx +2 -2
- package/template/agora-rn-uikit/src/Rtc/Create.tsx +90 -57
- package/template/agora-rn-uikit/src/Rtc/Join.tsx +20 -16
- package/template/agora-rn-uikit/src/RtcConfigure.tsx +10 -10
- package/template/agora-rn-uikit/src/Utils/isBotUser.ts +15 -0
- package/template/agora-rn-uikit/src/Utils/quality.tsx +8 -0
- package/template/agora-rn-uikit/src/Views/MaxVideoView.native.tsx +32 -16
- package/template/agora-rn-uikit/src/Views/MaxVideoView.tsx +25 -14
- package/template/agora-rn-uikit/src/Views/MinVideoView.tsx +15 -9
- package/template/agora-rn-uikit/src/index.ts +1 -1
- package/template/bridge/rtc/webNg/RtcEngine.ts +73 -58
- package/template/bridge/rtc/webNg/{SurfaceView.tsx → RtcSurfaceView.tsx} +20 -26
- package/template/bridge/rtc/webNg/Types.ts +20 -5
- package/template/bridge/rtc/webNg/index.ts +9 -13
- package/template/customization-api/temp.ts +2 -2
- package/template/customization-api/typeDefinition.ts +1 -2
- package/template/customization-api/utils.ts +1 -2
- package/template/index.js +1 -0
- package/template/ios/HelloWorld/HelloWorldDebug.entitlements +10 -0
- package/template/ios/HelloWorld.xcodeproj/project.pbxproj +4 -0
- package/template/ios/Podfile +1 -1
- package/template/ios/Podfile.lock +72 -140
- package/template/package.json +5 -4
- package/template/src/App.tsx +58 -1
- package/template/src/AppRoutes.tsx +16 -3
- package/template/src/AppWrapper.tsx +21 -19
- package/template/src/components/Chat.tsx +17 -8
- package/template/src/components/ChatContext.ts +0 -2
- package/template/src/components/Controls.tsx +5 -5
- package/template/src/components/Controls1.native.tsx +7 -3
- package/template/src/components/DeviceConfigure.native.tsx +2 -2
- package/template/src/components/DeviceConfigure.tsx +2 -2
- package/template/src/components/EventsConfigure.tsx +13 -22
- package/template/src/components/GraphQLProvider.tsx +47 -30
- package/template/src/components/GridVideo.tsx +6 -2
- package/template/src/components/NetworkQualityContext.tsx +11 -5
- package/template/src/components/ParticipantsView.tsx +3 -3
- package/template/src/components/PinnedVideo.tsx +2 -2
- package/template/src/components/Precall.native.tsx +9 -6
- package/template/src/components/Precall.tsx +9 -6
- package/template/src/components/StorageContext.tsx +5 -2
- package/template/src/components/ToastComponent.tsx +7 -1
- package/template/src/components/contexts/LiveStreamDataContext.tsx +3 -3
- package/template/src/components/livestream/LiveStreamContext.tsx +42 -33
- package/template/src/components/livestream/Types.ts +2 -2
- package/template/src/components/participants/Participant.tsx +1 -1
- package/template/src/components/participants/UserActionMenuOptions.tsx +7 -2
- package/template/src/components/recording-bot/RecordingBotRoute.tsx +42 -0
- package/template/src/components/virtual-background/useVB.native.tsx +16 -19
- package/template/src/components/virtual-background/useVB.tsx +1 -1
- package/template/src/components/whiteboard/WhiteboardConfigure.native.tsx +11 -0
- package/template/src/components/whiteboard/WhiteboardConfigure.tsx +5 -0
- package/template/src/components/whiteboard/WhiteboardView.native.tsx +91 -12
- package/template/src/components/whiteboard/WhiteboardWidget.tsx +15 -4
- package/template/src/language/default-labels/precallScreenLabels.ts +5 -3
- package/template/src/language/default-labels/videoCallScreenLabels.ts +93 -41
- package/template/src/pages/VideoCall.tsx +39 -37
- package/template/src/pages/video-call/ActionSheetContent.tsx +4 -3
- package/template/src/pages/video-call/NameWithMicIcon.tsx +2 -1
- package/template/src/pages/video-call/VideoCallMobileView.tsx +26 -2
- package/template/src/pages/video-call/VideoCallScreen.tsx +32 -12
- package/template/src/pages/video-call/VideoCallScreenWrapper.tsx +41 -0
- package/template/src/pages/video-call/VideoComponent.tsx +5 -2
- package/template/src/pages/video-call/VideoRenderer.tsx +55 -34
- package/template/src/rtm-events/constants.ts +0 -2
- package/template/src/subComponents/ChatBubble.tsx +2 -0
- package/template/src/subComponents/LocalAudioMute.tsx +8 -47
- package/template/src/subComponents/LocalEndCall.tsx +5 -52
- package/template/src/subComponents/LocalSwitchCamera.tsx +3 -3
- package/template/src/subComponents/LocalVideoMute.tsx +8 -50
- package/template/src/subComponents/SelectDevice.tsx +5 -2
- package/template/src/subComponents/SelectDeviceSettings.backup.tsx +9 -6
- package/template/src/subComponents/caption/Caption.tsx +12 -10
- package/template/src/subComponents/caption/Transcript.tsx +13 -10
- package/template/src/subComponents/caption/useTranscriptDownload.native.ts +11 -16
- package/template/src/subComponents/caption/utils.ts +1 -0
- package/template/src/subComponents/livestream/ApprovedLiveStreamControlsView.tsx +2 -2
- package/template/src/subComponents/livestream/CurrentLiveStreamRequestsView.tsx +3 -2
- package/template/src/subComponents/livestream/controls/LocalRaiseHand.tsx +1 -1
- package/template/src/subComponents/recording/useIsRecordingBot.tsx +38 -0
- package/template/src/subComponents/recording/useRecording.tsx +176 -135
- package/template/src/subComponents/screenshare/ScreenshareButton.tsx +3 -3
- package/template/src/subComponents/screenshare/ScreenshareConfigure.tsx +1 -22
- package/template/src/utils/index.tsx +16 -5
- package/template/src/utils/useEndCall.ts +65 -0
- package/template/src/utils/useIsLocalUserSpeaking.ts +6 -1
- package/template/{bridge/rtc/webNg/LocalView.tsx → src/utils/useLocalAudio.ts} +24 -6
- package/template/src/utils/useMuteToggleLocal.ts +10 -5
- package/template/src/utils/useSearchParams.tsx +18 -0
- package/template/src/wasms/agora-virtual-background.wasm +0 -0
- package/template/src/utils/endCallEveryOne.ts +0 -7
- package/template/src/utils/useDisableButton.tsx +0 -37
|
@@ -16,26 +16,43 @@ import React, {
|
|
|
16
16
|
useEffect,
|
|
17
17
|
useRef,
|
|
18
18
|
useState,
|
|
19
|
+
useCallback,
|
|
19
20
|
} from 'react';
|
|
20
|
-
import {gql, useMutation} from '@apollo/client';
|
|
21
|
-
import {useParams} from '../../components/Router';
|
|
22
|
-
import {PropsContext} from '../../../agora-rn-uikit';
|
|
23
21
|
import Toast from '../../../react-native-toast-message';
|
|
24
22
|
import {createHook} from 'customization-implementation';
|
|
25
23
|
import {useString} from '../../utils/useString';
|
|
26
24
|
import ChatContext from '../../components/ChatContext';
|
|
27
25
|
import events, {PersistanceLevel} from '../../rtm-events-api';
|
|
28
26
|
import {EventActions, EventNames} from '../../rtm-events';
|
|
29
|
-
import useRecordingLayoutQuery from './useRecordingLayoutQuery';
|
|
30
|
-
import {useScreenContext} from '../../components/contexts/ScreenShareContext';
|
|
31
27
|
import {useContent} from 'customization-api';
|
|
32
28
|
import {trimText} from '../../utils/common';
|
|
33
29
|
import {useRoomInfo} from 'customization-api';
|
|
30
|
+
import StorageContext from '../../components/StorageContext';
|
|
31
|
+
import {useSidePanel} from '../../utils/useSidePanel';
|
|
32
|
+
import {useCaption} from '../caption/useCaption';
|
|
33
|
+
import {SidePanelType} from '../SidePanelEnum';
|
|
34
|
+
import {
|
|
35
|
+
ChatType,
|
|
36
|
+
useChatUIControls,
|
|
37
|
+
} from '../../components/chat-ui/useChatUIControls';
|
|
38
|
+
import {useIsRecordingBot} from './useIsRecordingBot';
|
|
34
39
|
import {
|
|
35
40
|
videoRoomRecordingToastHeading,
|
|
36
41
|
videoRoomRecordingToastSubHeading,
|
|
37
42
|
videoRoomUserFallbackText,
|
|
43
|
+
videoRoomRecordingStartErrorToastHeading,
|
|
44
|
+
videoRoomRecordingStopErrorToastHeading,
|
|
45
|
+
videoRoomRecordingErrorToastSubHeading,
|
|
38
46
|
} from '../../language/default-labels/videoCallScreenLabels';
|
|
47
|
+
import {getOriginURL} from '../../auth/config';
|
|
48
|
+
|
|
49
|
+
const getFrontendUrl = (url: string) => {
|
|
50
|
+
// check if it doesn't contains the https protocol
|
|
51
|
+
if (url.indexOf('https://') !== 0) {
|
|
52
|
+
url = `https://${url}`;
|
|
53
|
+
}
|
|
54
|
+
return url;
|
|
55
|
+
};
|
|
39
56
|
|
|
40
57
|
export interface RecordingContextInterface {
|
|
41
58
|
startRecording: () => void;
|
|
@@ -51,26 +68,6 @@ const RecordingContext = createContext<RecordingContextInterface>({
|
|
|
51
68
|
inProgress: false,
|
|
52
69
|
});
|
|
53
70
|
|
|
54
|
-
const START_RECORDING = gql`
|
|
55
|
-
mutation startRecordingSession(
|
|
56
|
-
$passphrase: String!
|
|
57
|
-
$secret: String
|
|
58
|
-
$config: recordingConfig!
|
|
59
|
-
) {
|
|
60
|
-
startRecordingSession(
|
|
61
|
-
passphrase: $passphrase
|
|
62
|
-
secret: $secret
|
|
63
|
-
config: $config
|
|
64
|
-
)
|
|
65
|
-
}
|
|
66
|
-
`;
|
|
67
|
-
|
|
68
|
-
const STOP_RECORDING = gql`
|
|
69
|
-
mutation stopRecordingSession($passphrase: String!) {
|
|
70
|
-
stopRecordingSession(passphrase: $passphrase)
|
|
71
|
-
}
|
|
72
|
-
`;
|
|
73
|
-
|
|
74
71
|
/**
|
|
75
72
|
* Component to start / stop Agora cloud recording.
|
|
76
73
|
* Sends a control message to all users in the channel over RTM to indicate that
|
|
@@ -100,17 +97,13 @@ interface RecordingProviderProps {
|
|
|
100
97
|
*/
|
|
101
98
|
|
|
102
99
|
const RecordingProvider = (props: RecordingProviderProps) => {
|
|
103
|
-
const {rtcProps} = useContext(PropsContext);
|
|
104
100
|
const {setRecordingActive, isRecordingActive, callActive} = props?.value;
|
|
105
101
|
const {
|
|
106
|
-
data: {isHost},
|
|
102
|
+
data: {isHost, roomId},
|
|
107
103
|
} = useRoomInfo();
|
|
108
104
|
const [inProgress, setInProgress] = useState(false);
|
|
109
105
|
const [uidWhoStarted, setUidWhoStarted] = useState(0);
|
|
110
106
|
const {defaultContent, activeUids} = useContent();
|
|
111
|
-
const {phrase} = useParams<{phrase: string}>();
|
|
112
|
-
const [startRecordingQuery] = useMutation(START_RECORDING);
|
|
113
|
-
const [stopRecordingQuery] = useMutation(STOP_RECORDING);
|
|
114
107
|
const prevRecordingState = usePrevious<{isRecordingActive: boolean}>({
|
|
115
108
|
isRecordingActive,
|
|
116
109
|
});
|
|
@@ -118,36 +111,41 @@ const RecordingProvider = (props: RecordingProviderProps) => {
|
|
|
118
111
|
videoRoomRecordingToastHeading,
|
|
119
112
|
);
|
|
120
113
|
const subheading = useString(videoRoomRecordingToastSubHeading);
|
|
114
|
+
|
|
115
|
+
const headingStartError = useString(
|
|
116
|
+
videoRoomRecordingStartErrorToastHeading,
|
|
117
|
+
)();
|
|
118
|
+
const headingStopError = useString(videoRoomRecordingStopErrorToastHeading)();
|
|
119
|
+
const subheadingError = useString(videoRoomRecordingErrorToastSubHeading)();
|
|
120
|
+
|
|
121
121
|
const userlabel = useString(videoRoomUserFallbackText)();
|
|
122
122
|
|
|
123
|
-
const {executePresenterQuery, executeNormalQuery} = useRecordingLayoutQuery();
|
|
124
123
|
const {localUid} = useContext(ChatContext);
|
|
125
|
-
const {
|
|
124
|
+
const {store} = React.useContext(StorageContext);
|
|
126
125
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
case EventActions.RECORDING_STOPPED:
|
|
138
|
-
setRecordingActive(false);
|
|
139
|
-
break;
|
|
140
|
-
case EventActions.RECORDING_STOP_REQUEST:
|
|
141
|
-
stopRecording();
|
|
142
|
-
break;
|
|
143
|
-
default:
|
|
144
|
-
break;
|
|
126
|
+
const {setChatType} = useChatUIControls();
|
|
127
|
+
const {setSidePanel} = useSidePanel();
|
|
128
|
+
const {setIsCaptionON} = useCaption();
|
|
129
|
+
const {isRecordingBot, recordingBotUIConfig} = useIsRecordingBot();
|
|
130
|
+
|
|
131
|
+
const setRecordingBotUI = () => {
|
|
132
|
+
if (isRecordingBot) {
|
|
133
|
+
if (recordingBotUIConfig?.chat && $config.CHAT) {
|
|
134
|
+
setSidePanel(SidePanelType.Chat);
|
|
135
|
+
setChatType(ChatType.Group);
|
|
145
136
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
}
|
|
137
|
+
if (recordingBotUIConfig.stt && $config.ENABLE_STT) {
|
|
138
|
+
setIsCaptionON(true);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
if (callActive) {
|
|
145
|
+
setRecordingBotUI();
|
|
146
|
+
}
|
|
147
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
148
|
+
}, [callActive]);
|
|
151
149
|
|
|
152
150
|
useEffect(() => {
|
|
153
151
|
/**
|
|
@@ -180,25 +178,54 @@ const RecordingProvider = (props: RecordingProviderProps) => {
|
|
|
180
178
|
}
|
|
181
179
|
}, [isRecordingActive, callActive, isHost]);
|
|
182
180
|
|
|
181
|
+
const showErrorToast = (text1: string, text2?: string) => {
|
|
182
|
+
Toast.show({
|
|
183
|
+
leadingIconName: 'alert',
|
|
184
|
+
type: 'error',
|
|
185
|
+
text1: text1,
|
|
186
|
+
text2: text2 ? text2 : '',
|
|
187
|
+
visibilityTime: 3000,
|
|
188
|
+
primaryBtn: null,
|
|
189
|
+
secondaryBtn: null,
|
|
190
|
+
leadingIcon: null,
|
|
191
|
+
});
|
|
192
|
+
};
|
|
193
|
+
|
|
183
194
|
const startRecording = () => {
|
|
195
|
+
const passphrase = roomId.host || '';
|
|
196
|
+
let recordinghostURL = getOriginURL();
|
|
197
|
+
console.log('web-recording - start recording API called');
|
|
198
|
+
|
|
199
|
+
if (inProgress) {
|
|
200
|
+
console.error('web-recording - start recording API already in progress');
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (recordinghostURL.includes('localhost')) {
|
|
204
|
+
console.error(
|
|
205
|
+
'web-recording - Recording url cannot be localhost. It should be a valid deployed URL',
|
|
206
|
+
);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
recordinghostURL = getFrontendUrl(recordinghostURL);
|
|
210
|
+
console.log('web-recording - recordinghostURL: ', recordinghostURL);
|
|
211
|
+
|
|
184
212
|
setInProgress(true);
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
rtcProps.encryption && rtcProps.encryption.key
|
|
191
|
-
? rtcProps.encryption.key
|
|
192
|
-
: '',
|
|
193
|
-
config: {
|
|
194
|
-
resolution: 'SD360p',
|
|
195
|
-
trigger: 'AUTO',
|
|
196
|
-
},
|
|
213
|
+
fetch(`${$config.BACKEND_ENDPOINT}/v1/recording/start`, {
|
|
214
|
+
method: 'POST',
|
|
215
|
+
headers: {
|
|
216
|
+
'Content-Type': 'application/json',
|
|
217
|
+
authorization: store.token ? `Bearer ${store.token}` : '',
|
|
197
218
|
},
|
|
219
|
+
body: JSON.stringify({
|
|
220
|
+
passphrase: roomId.host,
|
|
221
|
+
url: `${recordinghostURL}/${passphrase}`,
|
|
222
|
+
webpage_ready_timeout: 10,
|
|
223
|
+
encryption: $config.ENCRYPTION_ENABLED,
|
|
224
|
+
}),
|
|
198
225
|
})
|
|
199
|
-
.then(res => {
|
|
226
|
+
.then((res: any) => {
|
|
200
227
|
setInProgress(false);
|
|
201
|
-
if (res.
|
|
228
|
+
if (res.status === 200) {
|
|
202
229
|
/**
|
|
203
230
|
* 1. Once the backend sucessfuly starts recording, send message
|
|
204
231
|
* in the channel indicating that cloud recording is now active.
|
|
@@ -214,22 +241,10 @@ const RecordingProvider = (props: RecordingProviderProps) => {
|
|
|
214
241
|
// 2. set the local recording state to true to update the UI
|
|
215
242
|
setUidWhoStarted(localUid);
|
|
216
243
|
setRecordingActive(true);
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
.sort((a, b) => b[1].ts - a[1].ts);
|
|
222
|
-
|
|
223
|
-
const activeScreenshareUid = sorted.length > 0 ? sorted[0][0] : 0;
|
|
224
|
-
if (activeScreenshareUid) {
|
|
225
|
-
console.log(
|
|
226
|
-
'screenshare: Executing presenter query for screenuid',
|
|
227
|
-
activeScreenshareUid,
|
|
228
|
-
);
|
|
229
|
-
executePresenterQuery(parseInt(activeScreenshareUid));
|
|
230
|
-
} else {
|
|
231
|
-
executeNormalQuery();
|
|
232
|
-
}
|
|
244
|
+
} else if (res.status === 500) {
|
|
245
|
+
showErrorToast(headingStartError, subheadingError);
|
|
246
|
+
} else {
|
|
247
|
+
showErrorToast(headingStartError);
|
|
233
248
|
}
|
|
234
249
|
})
|
|
235
250
|
.catch(err => {
|
|
@@ -238,60 +253,86 @@ const RecordingProvider = (props: RecordingProviderProps) => {
|
|
|
238
253
|
});
|
|
239
254
|
};
|
|
240
255
|
|
|
241
|
-
const stopRecording = () => {
|
|
256
|
+
const stopRecording = useCallback(() => {
|
|
242
257
|
/**
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
* user 1 and user 2 in the call
|
|
246
|
-
* user 1 start the recording
|
|
247
|
-
* user 2 stops the recording
|
|
248
|
-
* user 2 join the call getting stop recording notification which is not needed
|
|
249
|
-
*
|
|
250
|
-
* solution
|
|
251
|
-
* case 1 - if recording is not started by the host then we will send level1 message to host who started the recording
|
|
252
|
-
* case 2 - if person who started the recording no longer available in the call then will stop the recording
|
|
258
|
+
* Any host in the channel can stop recording.
|
|
253
259
|
*/
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
setInProgress(true);
|
|
259
|
-
// If recording is already going on, stop the recording by executing the graphql query.
|
|
260
|
-
stopRecordingQuery({variables: {passphrase: phrase}})
|
|
261
|
-
.then(res => {
|
|
262
|
-
setInProgress(false);
|
|
263
|
-
if (res.data.stopRecordingSession === 'success') {
|
|
264
|
-
/**
|
|
265
|
-
* 1. Once the backend sucessfuly starts recording, send message
|
|
266
|
-
* in the channel indicating that cloud recording is now inactive.
|
|
267
|
-
*/
|
|
268
|
-
events.send(
|
|
269
|
-
EventNames.RECORDING_ATTRIBUTE,
|
|
270
|
-
JSON.stringify({
|
|
271
|
-
action: EventActions.RECORDING_STOPPED,
|
|
272
|
-
value: '',
|
|
273
|
-
}),
|
|
274
|
-
PersistanceLevel.Session,
|
|
275
|
-
);
|
|
276
|
-
// 2. set the local recording state to false to update the UI
|
|
277
|
-
setRecordingActive(false);
|
|
278
|
-
}
|
|
279
|
-
})
|
|
280
|
-
.catch(err => {
|
|
281
|
-
setInProgress(false);
|
|
282
|
-
console.log(err);
|
|
283
|
-
});
|
|
284
|
-
} else {
|
|
285
|
-
events.send(
|
|
286
|
-
EventNames.RECORDING_ATTRIBUTE,
|
|
287
|
-
JSON.stringify({
|
|
288
|
-
action: EventActions.RECORDING_STOP_REQUEST,
|
|
289
|
-
value: '',
|
|
290
|
-
}),
|
|
291
|
-
PersistanceLevel.None,
|
|
260
|
+
console.log('web-recording - stop recording API called');
|
|
261
|
+
if (inProgress) {
|
|
262
|
+
console.error(
|
|
263
|
+
'web-recording - stop recording already in progress. Aborting..',
|
|
292
264
|
);
|
|
265
|
+
return;
|
|
293
266
|
}
|
|
294
|
-
|
|
267
|
+
setInProgress(true);
|
|
268
|
+
// If recording is already going on, stop the recording by executing the below query.
|
|
269
|
+
fetch(`${$config.BACKEND_ENDPOINT}/v1/recording/stop`, {
|
|
270
|
+
method: 'POST',
|
|
271
|
+
headers: {
|
|
272
|
+
'Content-Type': 'application/json',
|
|
273
|
+
authorization: store.token ? `Bearer ${store.token}` : '',
|
|
274
|
+
},
|
|
275
|
+
body: JSON.stringify({
|
|
276
|
+
passphrase: roomId.host,
|
|
277
|
+
}),
|
|
278
|
+
})
|
|
279
|
+
.then(res => {
|
|
280
|
+
setInProgress(false);
|
|
281
|
+
if (res.status === 200) {
|
|
282
|
+
/**
|
|
283
|
+
* 1. Once the backend sucessfuly stops recording, send message
|
|
284
|
+
* in the channel indicating that cloud recording is now inactive.
|
|
285
|
+
*/
|
|
286
|
+
events.send(
|
|
287
|
+
EventNames.RECORDING_ATTRIBUTE,
|
|
288
|
+
JSON.stringify({
|
|
289
|
+
action: EventActions.RECORDING_STOPPED,
|
|
290
|
+
value: '',
|
|
291
|
+
}),
|
|
292
|
+
PersistanceLevel.Session,
|
|
293
|
+
);
|
|
294
|
+
// 2. set the local recording state to false to update the UI
|
|
295
|
+
setRecordingActive(false);
|
|
296
|
+
} else if (res.status === 500) {
|
|
297
|
+
showErrorToast(headingStopError, subheadingError);
|
|
298
|
+
} else {
|
|
299
|
+
showErrorToast(headingStopError);
|
|
300
|
+
}
|
|
301
|
+
})
|
|
302
|
+
.catch(err => {
|
|
303
|
+
setInProgress(false);
|
|
304
|
+
console.log(err);
|
|
305
|
+
});
|
|
306
|
+
}, [
|
|
307
|
+
headingStopError,
|
|
308
|
+
inProgress,
|
|
309
|
+
roomId.host,
|
|
310
|
+
setRecordingActive,
|
|
311
|
+
store.token,
|
|
312
|
+
subheadingError,
|
|
313
|
+
]);
|
|
314
|
+
|
|
315
|
+
React.useEffect(() => {
|
|
316
|
+
events.on(EventNames.RECORDING_ATTRIBUTE, data => {
|
|
317
|
+
const payload = JSON.parse(data.payload);
|
|
318
|
+
const action = payload.action;
|
|
319
|
+
const value = payload.value;
|
|
320
|
+
switch (action) {
|
|
321
|
+
case EventActions.RECORDING_STARTED:
|
|
322
|
+
setUidWhoStarted(parseInt(value));
|
|
323
|
+
setRecordingActive(true);
|
|
324
|
+
break;
|
|
325
|
+
case EventActions.RECORDING_STOPPED:
|
|
326
|
+
setRecordingActive(false);
|
|
327
|
+
break;
|
|
328
|
+
default:
|
|
329
|
+
break;
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
return () => {
|
|
333
|
+
events.off(EventNames.RECORDING_ATTRIBUTE);
|
|
334
|
+
};
|
|
335
|
+
}, [roomId.host, setRecordingActive]);
|
|
295
336
|
|
|
296
337
|
return (
|
|
297
338
|
<RecordingContext.Provider
|
|
@@ -16,7 +16,7 @@ import Styles from '../../components/styles';
|
|
|
16
16
|
import {useString} from '../../utils/useString';
|
|
17
17
|
import {useScreenshare} from './useScreenshare';
|
|
18
18
|
import hexadecimalTransparency from '../../utils/hexadecimalTransparency';
|
|
19
|
-
import {PropsContext,
|
|
19
|
+
import {PropsContext, ClientRoleType} from '../../../agora-rn-uikit';
|
|
20
20
|
import {useLocalUserInfo, useRoomInfo} from 'customization-api';
|
|
21
21
|
import useIsHandRaised from '../../utils/useIsHandRaised';
|
|
22
22
|
import {isAndroid, isIOS} from '../../utils/common';
|
|
@@ -83,7 +83,7 @@ const ScreenshareButton = (props: ScreenshareButtonProps) => {
|
|
|
83
83
|
};
|
|
84
84
|
iconButtonProps.isOnActionSheet = isOnActionSheet;
|
|
85
85
|
if (
|
|
86
|
-
rtcProps.role ==
|
|
86
|
+
rtcProps.role == ClientRoleType.ClientRoleAudience &&
|
|
87
87
|
$config.EVENT_MODE &&
|
|
88
88
|
!$config.RAISE_HAND
|
|
89
89
|
) {
|
|
@@ -91,7 +91,7 @@ const ScreenshareButton = (props: ScreenshareButtonProps) => {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
if (
|
|
94
|
-
rtcProps.role ==
|
|
94
|
+
rtcProps.role == ClientRoleType.ClientRoleAudience &&
|
|
95
95
|
$config.EVENT_MODE &&
|
|
96
96
|
$config.RAISE_HAND &&
|
|
97
97
|
!isHost
|
|
@@ -18,12 +18,10 @@ import {
|
|
|
18
18
|
useChangeDefaultLayout,
|
|
19
19
|
useSetPinnedLayout,
|
|
20
20
|
} from '../../pages/video-call/DefaultLayouts';
|
|
21
|
-
import {useRecording} from '../recording/useRecording';
|
|
22
21
|
import {useScreenContext} from '../../components/contexts/ScreenShareContext';
|
|
23
22
|
import events, {PersistanceLevel} from '../../rtm-events-api';
|
|
24
23
|
import {EventActions, EventNames} from '../../rtm-events';
|
|
25
24
|
import {IAgoraRTC} from 'agora-rtc-sdk-ng';
|
|
26
|
-
import useRecordingLayoutQuery from '../recording/useRecordingLayoutQuery';
|
|
27
25
|
import {timeNow} from '../../rtm/utils';
|
|
28
26
|
import {
|
|
29
27
|
controlMessageEnum,
|
|
@@ -50,8 +48,6 @@ export const ScreenshareConfigure = (props: {children: React.ReactNode}) => {
|
|
|
50
48
|
const {defaultContent, activeUids, pinnedUid, secondaryPinnedUid} =
|
|
51
49
|
useContent();
|
|
52
50
|
const isPinned = useRef(0);
|
|
53
|
-
const {isRecordingActive} = useRecording();
|
|
54
|
-
const {executeNormalQuery, executePresenterQuery} = useRecordingLayoutQuery();
|
|
55
51
|
const {setScreenShareData, screenShareData} = useScreenContext();
|
|
56
52
|
const setPinnedLayout = useSetPinnedLayout();
|
|
57
53
|
const changeLayout = useChangeDefaultLayout();
|
|
@@ -232,7 +228,6 @@ export const ScreenshareConfigure = (props: {children: React.ReactNode}) => {
|
|
|
232
228
|
const ScreenshareStoppedCallback = () => {
|
|
233
229
|
setScreenshareActive(false);
|
|
234
230
|
console.log('STOPPED SHARING');
|
|
235
|
-
executeNormalQuery();
|
|
236
231
|
events.send(
|
|
237
232
|
EventNames.SCREENSHARE_ATTRIBUTE,
|
|
238
233
|
JSON.stringify({
|
|
@@ -268,22 +263,11 @@ export const ScreenshareConfigure = (props: {children: React.ReactNode}) => {
|
|
|
268
263
|
useEffect(() => {
|
|
269
264
|
// @ts-ignore
|
|
270
265
|
rtc.RtcEngineUnsafe.addListener(
|
|
271
|
-
'
|
|
266
|
+
'onScreenshareStopped',
|
|
272
267
|
ScreenshareStoppedCallback,
|
|
273
268
|
);
|
|
274
269
|
}, []);
|
|
275
270
|
|
|
276
|
-
const executeRecordingQuery = (isScreenActive: boolean) => {
|
|
277
|
-
if (isScreenActive) {
|
|
278
|
-
console.log('screenshare: Executing presenter query');
|
|
279
|
-
// If screen share is not going on, start the screen share by executing the graphql query
|
|
280
|
-
executePresenterQuery(screenShareUid);
|
|
281
|
-
} else {
|
|
282
|
-
// If recording is already going on, stop the recording by executing the graphql query.
|
|
283
|
-
executeNormalQuery();
|
|
284
|
-
}
|
|
285
|
-
};
|
|
286
|
-
|
|
287
271
|
const stopUserScreenShare = () => {
|
|
288
272
|
if (!isScreenshareActive) {
|
|
289
273
|
return;
|
|
@@ -298,10 +282,6 @@ export const ScreenshareConfigure = (props: {children: React.ReactNode}) => {
|
|
|
298
282
|
};
|
|
299
283
|
|
|
300
284
|
const userScreenshare = async (isActive: boolean) => {
|
|
301
|
-
if (isRecordingActive) {
|
|
302
|
-
executeRecordingQuery(isActive);
|
|
303
|
-
}
|
|
304
|
-
console.log('screenshare query executed');
|
|
305
285
|
try {
|
|
306
286
|
// @ts-ignore
|
|
307
287
|
await rtc.RtcEngineUnsafe.startScreenshare(
|
|
@@ -341,7 +321,6 @@ export const ScreenshareConfigure = (props: {children: React.ReactNode}) => {
|
|
|
341
321
|
}
|
|
342
322
|
} catch (e) {
|
|
343
323
|
console.error("can't start the screen share", e);
|
|
344
|
-
executeNormalQuery();
|
|
345
324
|
Toast.show({
|
|
346
325
|
leadingIconName: 'alert',
|
|
347
326
|
type: 'error',
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import {isWebInternal} from './common';
|
|
2
|
+
|
|
1
3
|
const Buffer = require('buffer/').Buffer;
|
|
2
4
|
type Entry<T> = {
|
|
3
5
|
[K in keyof T]: [K, T[K]];
|
|
@@ -90,10 +92,19 @@ export const base64ToUint8Array = (base64Str: string) => {
|
|
|
90
92
|
|
|
91
93
|
decodedData = Buffer.from(base64Str, 'base64').toString('binary');
|
|
92
94
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
95
|
+
if (isWebInternal()) {
|
|
96
|
+
const result: Uint8Array = new Uint8Array(
|
|
97
|
+
new ArrayBuffer(decodedData.length),
|
|
98
|
+
);
|
|
99
|
+
for (let i = 0; i < decodedData.length; i += 1) {
|
|
100
|
+
result[i] = decodedData.charCodeAt(i);
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
} else {
|
|
104
|
+
const result: number[] = [];
|
|
105
|
+
for (let i = 0; i < decodedData.length; i++) {
|
|
106
|
+
result.push(decodedData.charCodeAt(i));
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
96
109
|
}
|
|
97
|
-
|
|
98
|
-
return result;
|
|
99
110
|
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {useContext} from 'react';
|
|
2
|
+
import {useCustomization} from 'customization-implementation';
|
|
3
|
+
import {useCaption, useContent, useRoomInfo} from 'customization-api';
|
|
4
|
+
import {PropsContext, DispatchContext} from '../../agora-rn-uikit';
|
|
5
|
+
import {useHistory} from '../components/Router';
|
|
6
|
+
import {stopForegroundService} from '../subComponents/LocalEndCall';
|
|
7
|
+
import RTMEngine from '../rtm/RTMEngine';
|
|
8
|
+
import {ENABLE_AUTH} from '../auth/config';
|
|
9
|
+
import {useAuth} from '../auth/AuthProvider';
|
|
10
|
+
|
|
11
|
+
const useEndCall = () => {
|
|
12
|
+
const history = useHistory();
|
|
13
|
+
const {defaultContent} = useContent();
|
|
14
|
+
const {isSTTActive} = useCaption();
|
|
15
|
+
const {
|
|
16
|
+
data: {isHost},
|
|
17
|
+
} = useRoomInfo();
|
|
18
|
+
const {authLogin} = useAuth();
|
|
19
|
+
|
|
20
|
+
const {rtcProps} = useContext(PropsContext);
|
|
21
|
+
const {dispatch} = useContext(DispatchContext);
|
|
22
|
+
|
|
23
|
+
const beforeEndCall = useCustomization(
|
|
24
|
+
data =>
|
|
25
|
+
data?.lifecycle?.useBeforeEndCall && data?.lifecycle?.useBeforeEndCall(),
|
|
26
|
+
);
|
|
27
|
+
const afterEndCall = useCustomization(
|
|
28
|
+
data =>
|
|
29
|
+
data?.lifecycle?.useAfterEndCall && data?.lifecycle?.useAfterEndCall(),
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
return async () => {
|
|
33
|
+
try {
|
|
34
|
+
await beforeEndCall(isHost, history as unknown as History);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.log('debugging error on beforeEndCall');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
setTimeout(() => {
|
|
40
|
+
dispatch({
|
|
41
|
+
type: 'EndCall',
|
|
42
|
+
value: [],
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
// stopping foreground servie on end call
|
|
46
|
+
stopForegroundService();
|
|
47
|
+
// stopping STT on call end,if only last user is remaining in call
|
|
48
|
+
const usersInCall = Object.entries(defaultContent).filter(
|
|
49
|
+
item => item[1].type === 'rtc',
|
|
50
|
+
);
|
|
51
|
+
usersInCall.length === 1 && isSTTActive && stop();
|
|
52
|
+
RTMEngine.getInstance().engine.leaveChannel(rtcProps.channel);
|
|
53
|
+
if (!ENABLE_AUTH) {
|
|
54
|
+
// await authLogout();
|
|
55
|
+
await authLogin();
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
await afterEndCall(isHost, history as unknown as History);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.log('debugging error on afterEndCall');
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export default useEndCall;
|
|
@@ -5,6 +5,7 @@ import {useAsyncEffect} from './useAsyncEffect';
|
|
|
5
5
|
import LocalEventEmitter, {
|
|
6
6
|
LocalEventsEnum,
|
|
7
7
|
} from '../rtm-events-api/LocalEvents';
|
|
8
|
+
import {useIsRecordingBot} from '../subComponents/recording/useIsRecordingBot';
|
|
8
9
|
|
|
9
10
|
const useIsLocalUserSpeaking = () => {
|
|
10
11
|
const log: (arg1: string, ...args: any[]) => void = (arg1, ...args) => {
|
|
@@ -15,6 +16,7 @@ const useIsLocalUserSpeaking = () => {
|
|
|
15
16
|
const speechRef = useRef(null);
|
|
16
17
|
const audioRef = useRef(audio);
|
|
17
18
|
const audioTrackRef = useRef(null);
|
|
19
|
+
const {isRecordingBot} = useIsRecordingBot();
|
|
18
20
|
|
|
19
21
|
useEffect(() => {
|
|
20
22
|
audioRef.current = audio;
|
|
@@ -40,6 +42,9 @@ const useIsLocalUserSpeaking = () => {
|
|
|
40
42
|
|
|
41
43
|
useEffect(() => {
|
|
42
44
|
LocalEventEmitter.on(LocalEventsEnum.MIC_CHANGED, () => {
|
|
45
|
+
if (isRecordingBot) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
43
48
|
listenForSpeaker();
|
|
44
49
|
});
|
|
45
50
|
}, []);
|
|
@@ -75,7 +80,7 @@ const useIsLocalUserSpeaking = () => {
|
|
|
75
80
|
};
|
|
76
81
|
|
|
77
82
|
useAsyncEffect(async () => {
|
|
78
|
-
if ($config.ACTIVE_SPEAKER) {
|
|
83
|
+
if ($config.ACTIVE_SPEAKER && !isRecordingBot) {
|
|
79
84
|
await listenForSpeaker();
|
|
80
85
|
return () => {
|
|
81
86
|
try {
|
|
@@ -9,12 +9,30 @@
|
|
|
9
9
|
information visit https://appbuilder.agora.io.
|
|
10
10
|
*********************************************
|
|
11
11
|
*/
|
|
12
|
-
import React from 'react';
|
|
13
|
-
import SurfaceView, {RtcSurfaceViewProps, StyleProps} from './SurfaceView';
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
import {DispatchContext, RtcContext} from '../../agora-rn-uikit';
|
|
14
|
+
import {useContext} from 'react';
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
function useLocalAudio() {
|
|
17
|
+
const {dispatch} = useContext(DispatchContext);
|
|
18
|
+
const {RtcEngineUnsafe} = useContext(RtcContext);
|
|
19
|
+
|
|
20
|
+
const disableAudioButton = () => {
|
|
21
|
+
RtcEngineUnsafe.muteLocalAudioStream(true);
|
|
22
|
+
dispatch({
|
|
23
|
+
type: 'LocalMuteAudio',
|
|
24
|
+
value: [0, true],
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const enableAudioButton = () => {
|
|
29
|
+
dispatch({
|
|
30
|
+
type: 'LocalMuteAudio',
|
|
31
|
+
value: [0, false],
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return {enableAudioButton, disableAudioButton};
|
|
20
36
|
}
|
|
37
|
+
|
|
38
|
+
export default useLocalAudio;
|