agora-appbuilder-core 2.3.0-beta.2 → 2.3.0-beta.22
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/Readme.md +11 -6
- package/package.json +2 -2
- package/template/Gulpfile.js +112 -13
- package/template/_package-lock.json +13011 -13288
- package/template/agora-rn-uikit/src/Contexts/PropsContext.tsx +2 -0
- package/template/agora-rn-uikit/src/Controls/BtnTemplate.tsx +4 -5
- package/template/agora-rn-uikit/src/Controls/ImageIcon.tsx +3 -1
- package/template/agora-rn-uikit/src/Reducer/UserJoined.ts +3 -1
- package/template/agora-rn-uikit/src/Rtc/Create.tsx +64 -33
- package/template/agora-rn-uikit/src/Rtc/Join.tsx +11 -2
- package/template/agora-rn-uikit/src/RtcConfigure.tsx +23 -4
- package/template/agora-rn-uikit/src/Utils/permission.ts +17 -6
- package/template/bridge/rtc/webNg/RtcEngine.ts +51 -26
- package/template/esbuild.rsdk.go +20 -6
- package/template/fpe-api/components.ts +15 -0
- package/template/fpe-api/context.ts +2 -3
- package/template/fpe-api/install.ts +19 -9
- package/template/fpe-api/typeDefinition.ts +7 -6
- package/template/fpe-api/utils.ts +32 -25
- package/template/global.d.ts +3 -2
- package/template/index.rsdk.tsx +15 -4
- package/template/index.wsdk.tsx +13 -3
- package/template/package.json +4 -2
- package/template/react-native-toast-message/src/index.js +3 -7
- package/template/react-native-toast-message/src/{index.wsdk.js → index.sdk.tsx} +1 -1
- package/template/react-native-toast-message/src/styles.sdk.ts +17 -0
- package/template/src/SDKAppWrapper.tsx +1 -1
- package/template/src/components/Chat.tsx +23 -5
- package/template/src/components/ChatContext.ts +15 -4
- package/template/src/components/Controls.native.tsx +10 -6
- package/template/src/components/Controls.tsx +6 -4
- package/template/src/components/HostControlView.tsx +5 -3
- package/template/src/components/Navbar.tsx +15 -13
- package/template/src/components/RTMConfigure.tsx +20 -50
- package/template/src/components/chat-messages/useChatMessages.tsx +369 -70
- package/template/src/components/contexts/LiveStreamDataContext.tsx +3 -3
- package/template/src/components/contexts/ScreenShareContext.tsx +2 -0
- package/template/src/components/livestream/LiveStreamContext.tsx +9 -6
- package/template/src/components/participants/MeParticipant.tsx +5 -3
- package/template/src/components/participants/RemoteParticipants.tsx +9 -7
- package/template/src/components/precall/LocalMute.native.tsx +12 -8
- package/template/src/components/precall/LocalMute.tsx +5 -3
- package/template/src/components/precall/textInput.tsx +1 -1
- package/template/src/components/useShareLink.tsx +37 -39
- package/template/src/components/useUserPreference.tsx +125 -0
- package/template/src/custom-events/CustomEvents.ts +39 -23
- package/template/src/custom-events/types.ts +3 -3
- package/template/src/language/default-labels/videoCallScreenLabels.ts +4 -2
- package/template/src/pages/Create.tsx +10 -3
- package/template/src/pages/Join.tsx +4 -1
- package/template/src/pages/VideoCall.tsx +61 -56
- package/template/src/pages/video-call/CustomUserContextHolder.tsx +13 -5
- package/template/src/pages/video-call/VideoCallScreen.tsx +18 -15
- package/template/src/rtm/RTMEngine.ts +13 -0
- package/template/src/rtm/utils.ts +1 -1
- package/template/src/rtm-events/EventUtils.ts +3 -0
- package/template/src/rtm-events/EventsQueue.ts +9 -3
- package/template/src/rtm-events/constants.ts +3 -1
- package/template/src/subComponents/ChatBubble.tsx +22 -4
- package/template/src/subComponents/ChatContainer.tsx +30 -19
- package/template/src/subComponents/ChatInput.tsx +38 -26
- package/template/src/subComponents/SelectDevice.tsx +1 -1
- package/template/src/subComponents/recording/useRecording.tsx +15 -4
- package/template/src/subComponents/recording/useRecordingLayoutQuery.tsx +11 -5
- package/template/src/subComponents/screenshare/ScreenshareConfigure.native.tsx +35 -26
- package/template/src/subComponents/screenshare/ScreenshareConfigure.tsx +83 -33
- package/template/src/utils/SdkEvents.ts +3 -3
- package/template/src/utils/getMeetingInvite.ts +38 -15
- package/template/src/utils/getUniqueID.ts +5 -0
- package/template/src/utils/useDeleteMessage.ts +36 -0
- package/template/src/utils/useEditMessage.ts +41 -0
- package/template/src/utils/useGetName.ts +2 -3
- package/template/src/utils/useJoinMeeting.ts +22 -14
- package/template/src/utils/useLocalShareScreenUid.ts +19 -0
- package/template/src/utils/useSendMessage.ts +4 -5
- package/template/src/utils/useSetName.ts +2 -4
- package/template/webpack.rsdk.config.js +3 -2
- package/template/webpack.wsdk.config.js +0 -1
|
@@ -106,6 +106,7 @@ export interface RtcPropsInterface {
|
|
|
106
106
|
// useBeforeCreate?: () => () => Promise<void>;
|
|
107
107
|
// };
|
|
108
108
|
geoFencing?: boolean;
|
|
109
|
+
audioRoom?: boolean;
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
export interface CallbacksInterface {
|
|
@@ -142,6 +143,7 @@ const initialValue: PropsInterface = {
|
|
|
142
143
|
appId: '',
|
|
143
144
|
channel: '',
|
|
144
145
|
geoFencing: true,
|
|
146
|
+
audioRoom: false,
|
|
145
147
|
},
|
|
146
148
|
};
|
|
147
149
|
|
|
@@ -62,11 +62,10 @@ const BtnTemplate: React.FC<BtnTemplateInterface> = (props) => {
|
|
|
62
62
|
tintColor: disabled ? 'grey' : props.color || theme || '#fff',
|
|
63
63
|
}}
|
|
64
64
|
resizeMode={'contain'}
|
|
65
|
-
source={
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
65
|
+
source={{
|
|
66
|
+
uri:
|
|
67
|
+
props.name && icons[props.name] ? icons[props.name] : props.icon,
|
|
68
|
+
}}
|
|
70
69
|
/>
|
|
71
70
|
</View>
|
|
72
71
|
<Text
|
|
@@ -49,7 +49,9 @@ const ImageIcon: React.FC<ImageIconInterface> = (props) => {
|
|
|
49
49
|
props.style as object,
|
|
50
50
|
]}
|
|
51
51
|
resizeMode={'contain'}
|
|
52
|
-
source={
|
|
52
|
+
source={{
|
|
53
|
+
uri: props.name && icons[props.name] ? icons[props.name] : props.icon,
|
|
54
|
+
}}
|
|
53
55
|
/>
|
|
54
56
|
);
|
|
55
57
|
};
|
|
@@ -32,7 +32,9 @@ export default function UserJoined(
|
|
|
32
32
|
...typeData,
|
|
33
33
|
},
|
|
34
34
|
};
|
|
35
|
-
let renderPosition =
|
|
35
|
+
let renderPosition = state.renderPosition.filter((i) => i === newUid).length
|
|
36
|
+
? [...state.renderPosition]
|
|
37
|
+
: [...state.renderPosition, newUid];
|
|
36
38
|
const [maxUid] = renderPosition;
|
|
37
39
|
if (renderPosition.length === 2 && maxUid === localUid) {
|
|
38
40
|
//Only one remote and local is maximized
|
|
@@ -22,7 +22,7 @@ const Create = ({
|
|
|
22
22
|
}) => {
|
|
23
23
|
const [ready, setReady] = useState(false);
|
|
24
24
|
const {callbacks, rtcProps, mode} = useContext(PropsContext);
|
|
25
|
-
const {geoFencing = true} = rtcProps || {};
|
|
25
|
+
const {geoFencing = true, audioRoom = false} = rtcProps || {};
|
|
26
26
|
let engine = useRef<RtcEngine>({} as RtcEngine);
|
|
27
27
|
// commented for v1 release
|
|
28
28
|
// const beforeCreate = rtcProps?.lifecycle?.useBeforeCreate
|
|
@@ -33,15 +33,23 @@ const Create = ({
|
|
|
33
33
|
|
|
34
34
|
const enableVideoAndAudioWithDisabledState = async () => {
|
|
35
35
|
try {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
if (audioRoom === true) {
|
|
37
|
+
await engine.current.enableAudio();
|
|
38
|
+
dispatch({
|
|
39
|
+
type: 'LocalMuteAudio',
|
|
40
|
+
value: [ToggleState.disabled],
|
|
41
|
+
});
|
|
42
|
+
} else {
|
|
43
|
+
await engine.current.enableVideo();
|
|
44
|
+
dispatch({
|
|
45
|
+
type: 'LocalMuteAudio',
|
|
46
|
+
value: [ToggleState.disabled],
|
|
47
|
+
});
|
|
48
|
+
dispatch({
|
|
49
|
+
type: 'LocalMuteVideo',
|
|
50
|
+
value: [ToggleState.disabled],
|
|
51
|
+
});
|
|
52
|
+
}
|
|
45
53
|
} catch (error) {
|
|
46
54
|
const {status} = error as any;
|
|
47
55
|
// App Builder web only
|
|
@@ -57,7 +65,7 @@ const Create = ({
|
|
|
57
65
|
console.error('No audio device', audioError);
|
|
58
66
|
}
|
|
59
67
|
|
|
60
|
-
if (!videoError) {
|
|
68
|
+
if (!videoError && !audioRoom) {
|
|
61
69
|
dispatch({
|
|
62
70
|
type: 'LocalMuteVideo',
|
|
63
71
|
value: [ToggleState.disabled],
|
|
@@ -71,15 +79,23 @@ const Create = ({
|
|
|
71
79
|
};
|
|
72
80
|
const enableVideoAndAudioWithEnabledState = async () => {
|
|
73
81
|
try {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
if (audioRoom === true) {
|
|
83
|
+
await engine.current.enableAudio();
|
|
84
|
+
dispatch({
|
|
85
|
+
type: 'LocalMuteAudio',
|
|
86
|
+
value: [ToggleState.enabled],
|
|
87
|
+
});
|
|
88
|
+
} else {
|
|
89
|
+
await engine.current.enableVideo();
|
|
90
|
+
dispatch({
|
|
91
|
+
type: 'LocalMuteAudio',
|
|
92
|
+
value: [ToggleState.enabled],
|
|
93
|
+
});
|
|
94
|
+
dispatch({
|
|
95
|
+
type: 'LocalMuteVideo',
|
|
96
|
+
value: [ToggleState.enabled],
|
|
97
|
+
});
|
|
98
|
+
}
|
|
83
99
|
} catch (e) {
|
|
84
100
|
const {status} = e as any;
|
|
85
101
|
|
|
@@ -96,7 +112,7 @@ const Create = ({
|
|
|
96
112
|
console.error('No audio device', audioError);
|
|
97
113
|
}
|
|
98
114
|
|
|
99
|
-
if (!videoError) {
|
|
115
|
+
if (!videoError && !audioRoom) {
|
|
100
116
|
dispatch({
|
|
101
117
|
type: 'LocalMuteVideo',
|
|
102
118
|
value: [ToggleState.enabled],
|
|
@@ -123,7 +139,7 @@ const Create = ({
|
|
|
123
139
|
async function init() {
|
|
124
140
|
if (Platform.OS === 'android') {
|
|
125
141
|
//Request required permissions from Android
|
|
126
|
-
await requestCameraAndAudioPermission();
|
|
142
|
+
await requestCameraAndAudioPermission(audioRoom);
|
|
127
143
|
}
|
|
128
144
|
// commented for v1 release
|
|
129
145
|
// try {
|
|
@@ -247,7 +263,14 @@ const Create = ({
|
|
|
247
263
|
}
|
|
248
264
|
init();
|
|
249
265
|
return () => {
|
|
250
|
-
|
|
266
|
+
/**
|
|
267
|
+
* if condition add for websdk issue
|
|
268
|
+
* For some reason even if engine.current is defined somehow destroy gets undefined and
|
|
269
|
+
* causes a crash so thats why this check is needed before we call the method
|
|
270
|
+
*/
|
|
271
|
+
if (engine.current.destroy) {
|
|
272
|
+
engine.current!.destroy();
|
|
273
|
+
}
|
|
251
274
|
};
|
|
252
275
|
}, [rtcProps.appId]);
|
|
253
276
|
|
|
@@ -264,16 +287,20 @@ const Create = ({
|
|
|
264
287
|
if (isVideoEnabledRef.current) {
|
|
265
288
|
// This unpublishes the current track
|
|
266
289
|
await engine.current?.muteLocalAudioStream(true);
|
|
267
|
-
|
|
290
|
+
if (!audioRoom) {
|
|
291
|
+
await engine.current?.muteLocalVideoStream(true);
|
|
292
|
+
}
|
|
268
293
|
// This updates the uid interface
|
|
269
294
|
dispatch({
|
|
270
295
|
type: 'LocalMuteAudio',
|
|
271
296
|
value: [ToggleState.disabled],
|
|
272
297
|
});
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
298
|
+
if (!audioRoom) {
|
|
299
|
+
dispatch({
|
|
300
|
+
type: 'LocalMuteVideo',
|
|
301
|
+
value: [ToggleState.disabled],
|
|
302
|
+
});
|
|
303
|
+
}
|
|
277
304
|
}
|
|
278
305
|
}
|
|
279
306
|
if (rtcProps.role == ClientRole.Audience) {
|
|
@@ -282,15 +309,19 @@ const Create = ({
|
|
|
282
309
|
* Otherwise the setClientRole method call fails and throws an exception.
|
|
283
310
|
*/
|
|
284
311
|
await engine.current?.muteLocalAudioStream(true);
|
|
285
|
-
|
|
312
|
+
if (!audioRoom) {
|
|
313
|
+
await engine.current?.muteLocalVideoStream(true);
|
|
314
|
+
}
|
|
286
315
|
dispatch({
|
|
287
316
|
type: 'LocalMuteAudio',
|
|
288
317
|
value: [ToggleState.disabled],
|
|
289
318
|
});
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
319
|
+
if (!audioRoom) {
|
|
320
|
+
dispatch({
|
|
321
|
+
type: 'LocalMuteVideo',
|
|
322
|
+
value: [ToggleState.disabled],
|
|
323
|
+
});
|
|
324
|
+
}
|
|
294
325
|
await engine.current?.setClientRole(ClientRole.Audience);
|
|
295
326
|
}
|
|
296
327
|
}
|
|
@@ -13,6 +13,7 @@ const Join: React.FC<{
|
|
|
13
13
|
}> = ({children, precall, engineRef, uidState, dispatch}) => {
|
|
14
14
|
let joinState = useRef(false);
|
|
15
15
|
const {rtcProps} = useContext(PropsContext);
|
|
16
|
+
const {audioRoom = false} = rtcProps;
|
|
16
17
|
//commented for v1 release
|
|
17
18
|
// const beforeJoin = rtcProps?.lifecycle?.useBeforeJoin
|
|
18
19
|
// ? rtcProps.lifecycle.useBeforeJoin()
|
|
@@ -44,7 +45,11 @@ const Join: React.FC<{
|
|
|
44
45
|
encryptionMode: rtcProps.encryption.mode,
|
|
45
46
|
});
|
|
46
47
|
}
|
|
47
|
-
if (
|
|
48
|
+
if (
|
|
49
|
+
!audioRoom &&
|
|
50
|
+
videoState === ToggleState.enabled &&
|
|
51
|
+
Platform.OS === 'ios'
|
|
52
|
+
) {
|
|
48
53
|
dispatch({
|
|
49
54
|
type: 'LocalMuteVideo',
|
|
50
55
|
value: [ToggleState.disabling],
|
|
@@ -70,7 +75,11 @@ const Join: React.FC<{
|
|
|
70
75
|
null,
|
|
71
76
|
rtcProps.uid || 0,
|
|
72
77
|
);
|
|
73
|
-
if (
|
|
78
|
+
if (
|
|
79
|
+
!audioRoom &&
|
|
80
|
+
videoState === ToggleState.enabled &&
|
|
81
|
+
Platform.OS === 'ios'
|
|
82
|
+
) {
|
|
74
83
|
dispatch({
|
|
75
84
|
type: 'LocalMuteVideo',
|
|
76
85
|
value: [ToggleState.enabling],
|
|
@@ -203,16 +203,30 @@ const RtcConfigure = (props: {children: React.ReactNode}) => {
|
|
|
203
203
|
|
|
204
204
|
const swapVideo = useCallback(
|
|
205
205
|
(state: RenderStateInterface, newMaxUid: UidType) => {
|
|
206
|
+
if (state?.renderPosition?.indexOf(newMaxUid) === -1) {
|
|
207
|
+
//skip the update if new max uid is not joined yet.
|
|
208
|
+
return {};
|
|
209
|
+
}
|
|
206
210
|
let renderPosition: RenderStateInterface['renderPosition'] = [
|
|
207
211
|
...state.renderPosition,
|
|
208
212
|
];
|
|
209
213
|
let renderList: RenderStateInterface['renderList'] = {
|
|
210
214
|
...state.renderList,
|
|
211
215
|
};
|
|
216
|
+
|
|
212
217
|
// Element which is currently maximized
|
|
213
218
|
const [currentMaxUid] = renderPosition;
|
|
214
219
|
|
|
215
220
|
if (currentMaxUid === newMaxUid) {
|
|
221
|
+
//skip the update if new max uid is already maximized
|
|
222
|
+
return {};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const newMaxUidOldPosition = renderPosition.findIndex(
|
|
226
|
+
(i) => i === newMaxUid,
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
if (!newMaxUidOldPosition) {
|
|
216
230
|
return {};
|
|
217
231
|
}
|
|
218
232
|
|
|
@@ -228,10 +242,6 @@ const RtcConfigure = (props: {children: React.ReactNode}) => {
|
|
|
228
242
|
* else push newMaxUid at last position
|
|
229
243
|
*/
|
|
230
244
|
|
|
231
|
-
const newMaxUidOldPosition = renderPosition.findIndex(
|
|
232
|
-
(i) => i === newMaxUid,
|
|
233
|
-
);
|
|
234
|
-
|
|
235
245
|
renderPosition[0] = newMaxUid;
|
|
236
246
|
renderPosition[newMaxUidOldPosition] = currentMaxUid;
|
|
237
247
|
|
|
@@ -248,16 +258,25 @@ const RtcConfigure = (props: {children: React.ReactNode}) => {
|
|
|
248
258
|
*/
|
|
249
259
|
const dequeVideo = useCallback(
|
|
250
260
|
(state: RenderStateInterface, newMaxUid: UidType) => {
|
|
261
|
+
if (state?.renderPosition?.indexOf(newMaxUid) === -1) {
|
|
262
|
+
//skip the update if new max uid is not joined yet.
|
|
263
|
+
return {};
|
|
264
|
+
}
|
|
251
265
|
let renderPosition: RenderStateInterface['renderPosition'] = [
|
|
252
266
|
...state.renderPosition,
|
|
253
267
|
];
|
|
254
268
|
let renderList: RenderStateInterface['renderList'] = {
|
|
255
269
|
...state.renderList,
|
|
256
270
|
};
|
|
271
|
+
if (!(newMaxUid in renderList)) {
|
|
272
|
+
//skip the update if new max uid is not joined yet.
|
|
273
|
+
return {};
|
|
274
|
+
}
|
|
257
275
|
// Element which is currently maximized
|
|
258
276
|
const [currentMaxUid] = renderPosition;
|
|
259
277
|
|
|
260
278
|
if (currentMaxUid === newMaxUid) {
|
|
279
|
+
//skip the update if new max uid is already maximized
|
|
261
280
|
return {};
|
|
262
281
|
}
|
|
263
282
|
|
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
import {PermissionsAndroid} from 'react-native';
|
|
1
|
+
import {Permission, PermissionsAndroid} from 'react-native';
|
|
2
2
|
/**
|
|
3
3
|
* @name requestCameraAndAudioPermission
|
|
4
4
|
* @description Function to request permission for Audio and Camera
|
|
5
5
|
*/
|
|
6
|
-
export default async function requestCameraAndAudioPermission(
|
|
6
|
+
export default async function requestCameraAndAudioPermission(
|
|
7
|
+
audioRoom: boolean,
|
|
8
|
+
) {
|
|
7
9
|
try {
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
const permissionsToRequest: Permission[] = [];
|
|
11
|
+
permissionsToRequest.push(PermissionsAndroid.PERMISSIONS.RECORD_AUDIO);
|
|
12
|
+
if (!audioRoom) {
|
|
13
|
+
permissionsToRequest.push(PermissionsAndroid.PERMISSIONS.CAMERA);
|
|
14
|
+
}
|
|
15
|
+
const granted = await PermissionsAndroid.requestMultiple(
|
|
16
|
+
permissionsToRequest,
|
|
17
|
+
);
|
|
12
18
|
if (
|
|
13
19
|
granted['android.permission.RECORD_AUDIO'] ===
|
|
14
20
|
PermissionsAndroid.RESULTS.GRANTED &&
|
|
@@ -16,6 +22,11 @@ export default async function requestCameraAndAudioPermission() {
|
|
|
16
22
|
PermissionsAndroid.RESULTS.GRANTED
|
|
17
23
|
) {
|
|
18
24
|
console.log('You can use the cameras & mic');
|
|
25
|
+
} else if (
|
|
26
|
+
granted['android.permission.RECORD_AUDIO'] ===
|
|
27
|
+
PermissionsAndroid.RESULTS.GRANTED
|
|
28
|
+
) {
|
|
29
|
+
console.log('You can use mic');
|
|
19
30
|
} else {
|
|
20
31
|
console.log('Permission denied');
|
|
21
32
|
}
|
|
@@ -31,6 +31,10 @@ import type {
|
|
|
31
31
|
import {VideoProfile} from '../quality';
|
|
32
32
|
import {ChannelProfile, ClientRole} from '../../../agora-rn-uikit';
|
|
33
33
|
import {role, mode} from './Types';
|
|
34
|
+
import {LOG_ENABLED, GEO_FENCING} from '../../../config.json';
|
|
35
|
+
import {Platform} from 'react-native';
|
|
36
|
+
import isMobileOrTablet from '../../../src/utils/isMobileOrTablet';
|
|
37
|
+
|
|
34
38
|
interface MediaDeviceInfo {
|
|
35
39
|
readonly deviceId: string;
|
|
36
40
|
readonly label: string;
|
|
@@ -127,7 +131,7 @@ export enum RnEncryptionEnum {
|
|
|
127
131
|
*
|
|
128
132
|
* @since v3.3.1
|
|
129
133
|
*/
|
|
130
|
-
AES256GCM = 6
|
|
134
|
+
AES256GCM = 6,
|
|
131
135
|
}
|
|
132
136
|
|
|
133
137
|
export enum VideoStreamType {
|
|
@@ -161,11 +165,6 @@ if ($config.LOG_ENABLED) {
|
|
|
161
165
|
AgoraRTC.disableLogUpload();
|
|
162
166
|
}
|
|
163
167
|
|
|
164
|
-
interface CustomEvents {
|
|
165
|
-
ScreenshareStopped: callbackType
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
169
168
|
export default class RtcEngine {
|
|
170
169
|
public appId: string;
|
|
171
170
|
// public AgoraRTC: any;
|
|
@@ -214,20 +213,42 @@ export default class RtcEngine {
|
|
|
214
213
|
this.videoProfile = profile;
|
|
215
214
|
}
|
|
216
215
|
|
|
216
|
+
async enableAudio(): Promise<void> {
|
|
217
|
+
try {
|
|
218
|
+
let localAudio = await AgoraRTC.createMicrophoneAudioTrack({});
|
|
219
|
+
this.localStream.audio = localAudio;
|
|
220
|
+
} catch (e) {
|
|
221
|
+
let audioError = e;
|
|
222
|
+
e.status = {audioError};
|
|
223
|
+
throw e;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
217
227
|
async enableVideo(): Promise<void> {
|
|
228
|
+
/**
|
|
229
|
+
* Issue: Backgrounding the browser or app causes the audio streaming to be cut off.
|
|
230
|
+
* Impact: All browsers and apps that use WKWebView on iOS 15.x, such as Safari and Chrome.
|
|
231
|
+
* Solution:
|
|
232
|
+
* Upgrade to the Web SDK v4.7.3 or later versions.
|
|
233
|
+
* When calling createMicrophoneAudioTrack, set bypassWebAudio as true.
|
|
234
|
+
* The Web SDK directly publishes the local audio stream without processing it through WebAudio.
|
|
235
|
+
*/
|
|
236
|
+
|
|
237
|
+
const audioConfig =
|
|
238
|
+
Platform.OS == 'web' && isMobileOrTablet() ? {bypassWebAudio: true} : {};
|
|
218
239
|
try {
|
|
219
240
|
let [localAudio, localVideo] =
|
|
220
|
-
await AgoraRTC.createMicrophoneAndCameraTracks(
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
);
|
|
241
|
+
await AgoraRTC.createMicrophoneAndCameraTracks(audioConfig, {
|
|
242
|
+
encoderConfig: this.videoProfile,
|
|
243
|
+
});
|
|
224
244
|
this.localStream.audio = localAudio;
|
|
225
245
|
this.localStream.video = localVideo;
|
|
226
246
|
} catch (e) {
|
|
227
247
|
let audioError = false;
|
|
228
248
|
let videoError = false;
|
|
229
249
|
try {
|
|
230
|
-
let localAudio = await AgoraRTC.createMicrophoneAudioTrack(
|
|
250
|
+
let localAudio = await AgoraRTC.createMicrophoneAudioTrack(audioConfig);
|
|
251
|
+
|
|
231
252
|
this.localStream.audio = localAudio;
|
|
232
253
|
} catch (error) {
|
|
233
254
|
audioError = error;
|
|
@@ -673,6 +694,8 @@ export default class RtcEngine {
|
|
|
673
694
|
break;
|
|
674
695
|
case RnEncryptionEnum.SM4128ECB:
|
|
675
696
|
mode = 'sm4-128-ecb';
|
|
697
|
+
default:
|
|
698
|
+
mode = 'none';
|
|
676
699
|
}
|
|
677
700
|
} else {
|
|
678
701
|
mode = 'none';
|
|
@@ -688,7 +711,7 @@ export default class RtcEngine {
|
|
|
688
711
|
},
|
|
689
712
|
): Promise<void> {
|
|
690
713
|
let mode: EncryptionMode;
|
|
691
|
-
mode = this.getEncryptionMode(enabled, config
|
|
714
|
+
mode = this.getEncryptionMode(enabled, config?.encryptionMode);
|
|
692
715
|
try {
|
|
693
716
|
await Promise.all([
|
|
694
717
|
this.client.setEncryptionConfig(mode, config.encryptionKey),
|
|
@@ -784,20 +807,22 @@ export default class RtcEngine {
|
|
|
784
807
|
try {
|
|
785
808
|
console.log('[screenshare]: creating stream');
|
|
786
809
|
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
810
|
+
if (encryption && encryption.screenKey && encryption.mode) {
|
|
811
|
+
let mode: EncryptionMode;
|
|
812
|
+
mode = this.getEncryptionMode(true, encryption?.mode);
|
|
813
|
+
try {
|
|
814
|
+
/**
|
|
815
|
+
* Since version 4.7.0, if client leaves a call
|
|
816
|
+
* and joins again the encryption needs to be
|
|
817
|
+
* set again
|
|
818
|
+
*/
|
|
819
|
+
await this.screenClient.setEncryptionConfig(
|
|
820
|
+
mode,
|
|
821
|
+
encryption.screenKey,
|
|
822
|
+
);
|
|
823
|
+
} catch (e) {
|
|
824
|
+
console.log('e: Encryption for screenshare failed', e);
|
|
825
|
+
}
|
|
801
826
|
}
|
|
802
827
|
|
|
803
828
|
const screenTracks = await AgoraRTC.createScreenVideoTrack(
|
package/template/esbuild.rsdk.go
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package main
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
+
"flag"
|
|
4
5
|
"log"
|
|
5
6
|
"os"
|
|
6
7
|
"path/filepath"
|
|
@@ -9,6 +10,11 @@ import (
|
|
|
9
10
|
"github.com/evanw/esbuild/pkg/api"
|
|
10
11
|
)
|
|
11
12
|
|
|
13
|
+
type ioPaths struct {
|
|
14
|
+
outPath string
|
|
15
|
+
configTransformerPath string
|
|
16
|
+
}
|
|
17
|
+
|
|
12
18
|
func commonAliasResolver() api.Plugin {
|
|
13
19
|
aliasResolvers := api.Plugin{
|
|
14
20
|
Name: "importAliases",
|
|
@@ -152,7 +158,7 @@ func commonLoader() map[string]api.Loader {
|
|
|
152
158
|
return loader
|
|
153
159
|
}
|
|
154
160
|
|
|
155
|
-
func common() api.BuildOptions {
|
|
161
|
+
func common(iopath *ioPaths) api.BuildOptions {
|
|
156
162
|
commonBuildOpts := api.BuildOptions{
|
|
157
163
|
// we can safely ignore (webpack) plugins for now because they seem to be used only for not reactsdk
|
|
158
164
|
|
|
@@ -164,14 +170,14 @@ func common() api.BuildOptions {
|
|
|
164
170
|
Define: map[string]string{
|
|
165
171
|
"$config": "config",
|
|
166
172
|
},
|
|
167
|
-
Inject: []string{
|
|
173
|
+
Inject: []string{iopath.configTransformerPath},
|
|
168
174
|
}
|
|
169
175
|
|
|
170
176
|
return commonBuildOpts
|
|
171
177
|
}
|
|
172
178
|
|
|
173
|
-
func rsdk() api.BuildResult {
|
|
174
|
-
commonBuildOpts := common()
|
|
179
|
+
func rsdk(iopath *ioPaths) api.BuildResult {
|
|
180
|
+
commonBuildOpts := common(iopath)
|
|
175
181
|
rsdkBuildOpts := api.BuildOptions{
|
|
176
182
|
// build options common to rsdk and other components
|
|
177
183
|
Plugins: commonBuildOpts.Plugins,
|
|
@@ -197,7 +203,7 @@ func rsdk() api.BuildResult {
|
|
|
197
203
|
// bundle in cjs format because this index.js is meant to be used by other host applications
|
|
198
204
|
// like webpack which runs on node
|
|
199
205
|
Format: api.FormatCommonJS,
|
|
200
|
-
Outfile:
|
|
206
|
+
Outfile: iopath.outPath,
|
|
201
207
|
|
|
202
208
|
// other esbuild options
|
|
203
209
|
Write: true,
|
|
@@ -215,7 +221,15 @@ func rsdk() api.BuildResult {
|
|
|
215
221
|
}
|
|
216
222
|
|
|
217
223
|
func main() {
|
|
218
|
-
|
|
224
|
+
outPath := flag.String("outpath", "../Builds/react-sdk/index.js", "path to write bundled js file")
|
|
225
|
+
configTransformerPath := flag.String("configtransformerpath", "./esbuildConfigTransform.js", "path to inject file")
|
|
226
|
+
flag.Parse()
|
|
227
|
+
iopath := &ioPaths{
|
|
228
|
+
outPath: *outPath,
|
|
229
|
+
configTransformerPath: *configTransformerPath,
|
|
230
|
+
}
|
|
231
|
+
log.Println("esbuild args = ", iopath)
|
|
232
|
+
rsdkRes := rsdk(iopath)
|
|
219
233
|
if len(rsdkRes.Errors) > 0 {
|
|
220
234
|
spew.Dump(rsdkRes)
|
|
221
235
|
log.Fatalln("build failed")
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
//Common components
|
|
2
|
+
export {default as HorizontalRule} from '../src/atoms/HorizontalRule';
|
|
3
|
+
export {default as PrimaryButton} from '../src/atoms/PrimaryButton';
|
|
4
|
+
export {default as SecondaryButton} from '../src/atoms/SecondaryButton';
|
|
5
|
+
export {default as TextInput} from '../src/atoms/TextInput';
|
|
1
6
|
//Icons
|
|
2
7
|
export {default as icons} from '../src/assets/icons';
|
|
3
8
|
|
|
@@ -18,6 +23,12 @@ export {
|
|
|
18
23
|
ParticipantsView,
|
|
19
24
|
Controls,
|
|
20
25
|
ControlsComponentsArray,
|
|
26
|
+
Navbar,
|
|
27
|
+
NavBarComponentsArray,
|
|
28
|
+
ChatBubble,
|
|
29
|
+
ChatSendButton,
|
|
30
|
+
ChatTextInput,
|
|
31
|
+
Chat,
|
|
21
32
|
} from '../src/pages/video-call/index';
|
|
22
33
|
export {default as GridLayout} from '../src/components/GridVideo';
|
|
23
34
|
export {default as PinnedLayout} from '../src/components/PinnedVideo';
|
|
@@ -40,3 +51,7 @@ export {default as VideocallScreen} from '../src/pages/video-call/VideoCallScree
|
|
|
40
51
|
|
|
41
52
|
//Sidepanel buttons
|
|
42
53
|
export {SidePanelButtonsArray} from '../src/subComponents/SidePanelButtons';
|
|
54
|
+
export {
|
|
55
|
+
ImageIcon as UiKitImageIcon,
|
|
56
|
+
MaxVideoView as UiKitMaxVideoView,
|
|
57
|
+
} from '../agora-rn-uikit';
|
|
@@ -40,6 +40,5 @@ export {useRecording} from '../src/subComponents/recording/useRecording';
|
|
|
40
40
|
export type {RecordingContextInterface} from '../src/subComponents/recording/useRecording';
|
|
41
41
|
export {useMeetingInfo} from '../src/components/meeting-info/useMeetingInfo';
|
|
42
42
|
export type {MeetingInfoContextInterface} from '../src/components/meeting-info/useMeetingInfo';
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// export type {ChatUIControlInterface} from '../src/components/chat-ui/useChatUIControl';
|
|
43
|
+
export {useChatUIControl} from '../src/components/chat-ui/useChatUIControl';
|
|
44
|
+
export type {ChatUIControlInterface} from '../src/components/chat-ui/useChatUIControl';
|
|
@@ -45,18 +45,28 @@ function isComponent(data: any) {
|
|
|
45
45
|
return false;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
//These keys value are not react component. so doing indexOf and checking whether its function or not
|
|
49
|
+
const ignoreTheseKeys = ['customLayout', 'useUserContext'];
|
|
50
|
+
|
|
48
51
|
function validateComponents(components: any) {
|
|
49
52
|
for (const key in components) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (
|
|
53
|
-
if (isObject(comp)) {
|
|
54
|
-
|
|
53
|
+
if (ignoreTheseKeys.indexOf(key) === -1) {
|
|
54
|
+
let comp = components[key];
|
|
55
|
+
if (comp) {
|
|
56
|
+
if (isComponent(comp) || isObject(comp)) {
|
|
57
|
+
if (isObject(comp)) {
|
|
58
|
+
validateComponents(comp);
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
console.error(
|
|
62
|
+
`InstallFPE:Error ${key} should be a react component or object`,
|
|
63
|
+
);
|
|
55
64
|
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
let comp = components[key];
|
|
68
|
+
if (comp && !isFunction(comp)) {
|
|
69
|
+
console.error(`InstallFPE:Error ${key} should be an function`);
|
|
60
70
|
}
|
|
61
71
|
}
|
|
62
72
|
}
|