agora-appbuilder-core 4.0.19 → 4.0.20-beta.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agora-appbuilder-core",
3
- "version": "4.0.19",
3
+ "version": "4.0.20-beta.1",
4
4
  "description": "React Native template for RTE app builder",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -72,3 +72,6 @@ export type {
72
72
  ToolbarCustomItem,
73
73
  ToolbarPresetProps,
74
74
  } from '../src/atoms/ToolbarPreset';
75
+ export {default as TranscriptPanel} from '../src/subComponents/caption/Transcript';
76
+ export type {TranscriptProps} from '../src/subComponents/caption/Transcript';
77
+ export {default as CaptionPanel} from '../src/subComponents/caption/CaptionContainer';
@@ -68,6 +68,8 @@ export interface VideoCallInterface extends BeforeAndAfterInterface {
68
68
  //settingsPanel?: React.ComponentType;
69
69
  participantsPanel?: React.ComponentType;
70
70
  chat?: ChatCmpInterface;
71
+ captionPanel?: React.ComponentType;
72
+ transcriptPanel?: React.ComponentType;
71
73
  customLayout?: (layouts: LayoutItem[]) => LayoutItem[];
72
74
  wrapper?: React.ComponentType;
73
75
  invitePopup?: {
@@ -32,3 +32,6 @@ export {isWeb, isIOS, isAndroid, isDesktop} from '../src/utils/common';
32
32
  export {default as isMobileOrTablet} from '../src/utils/isMobileOrTablet';
33
33
  export {useLocalUid} from '../agora-rn-uikit';
34
34
  export {default as useLocalAudio} from '../src/utils/useLocalAudio';
35
+ export {default as useLocalVideo} from '../src/utils/useLocalVideo';
36
+ export type {LanguageType} from '../src/subComponents/caption/utils';
37
+ export {default as useSpeechToText} from '../src/utils/useSpeechToText';
@@ -61,6 +61,8 @@ const DefaultConfig = {
61
61
  ENABLE_IDP_AUTH: false,
62
62
  ENABLE_TOKEN_AUTH: false,
63
63
  ENABLE_STT: false,
64
+ ENABLE_CAPTION: true,
65
+ ENABLE_MEETING_TRANSCRIPT: true,
64
66
  ENABLE_NOISE_CANCELLATION: true,
65
67
  ENABLE_VIRTUAL_BACKGROUND: true,
66
68
  ENABLE_WHITEBOARD: false,
@@ -69,7 +71,7 @@ const DefaultConfig = {
69
71
  WHITEBOARD_APPIDENTIFIER: '',
70
72
  WHITEBOARD_REGION: '',
71
73
  ENABLE_NOISE_CANCELLATION_BY_DEFAULT: false,
72
- CHAT_ORG_NAME:'',
74
+ CHAT_ORG_NAME: '',
73
75
  CHAT_APP_NAME: '',
74
76
  CHAT_URL: '',
75
77
  };
@@ -104,6 +104,8 @@ interface ConfigInterface {
104
104
  ENABLE_IDP_AUTH: boolean;
105
105
  PROJECT_ID: string;
106
106
  ENABLE_STT: boolean;
107
+ ENABLE_CAPTION: boolean;
108
+ ENABLE_MEETING_TRANSCRIPT: boolean;
107
109
  ENABLE_NOISE_CANCELLATION: boolean;
108
110
  ENABLE_VIRTUAL_BACKGROUND: boolean;
109
111
  ENABLE_WHITEBOARD: boolean;
@@ -465,12 +465,16 @@ const MoreButton = () => {
465
465
 
466
466
  // host can see stt options and attendee can view only when stt is enabled by a host in the channel
467
467
 
468
- if ($config.ENABLE_STT) {
468
+ if ($config.ENABLE_STT && $config.ENABLE_CAPTION) {
469
469
  actionMenuitems.push({
470
470
  icon: `${isCaptionON ? 'captions-off' : 'captions'}`,
471
471
  iconColor: $config.SECONDARY_ACTION_COLOR,
472
472
  textColor: $config.FONT_COLOR,
473
- disabled: !($config.ENABLE_STT && (isHost || (!isHost && isSTTActive))),
473
+ disabled: !(
474
+ $config.ENABLE_STT &&
475
+ $config.ENABLE_CAPTION &&
476
+ (isHost || (!isHost && isSTTActive))
477
+ ),
474
478
  title: captionLabel(isCaptionON),
475
479
  callback: () => {
476
480
  setActionMenuVisible(false);
@@ -489,31 +493,38 @@ const MoreButton = () => {
489
493
  },
490
494
  });
491
495
 
492
- actionMenuitems.push({
493
- icon: 'transcript',
494
- iconColor: $config.SECONDARY_ACTION_COLOR,
495
- textColor: $config.FONT_COLOR,
496
- disabled: !($config.ENABLE_STT && (isHost || (!isHost && isSTTActive))),
497
- title: transcriptLabel(isTranscriptON),
498
- callback: () => {
499
- setActionMenuVisible(false);
500
- STT_clicked.current = !isTranscriptON ? 'transcript' : null;
501
- if (isSTTError) {
502
- !isTranscriptON
503
- ? setSidePanel(SidePanelType.Transcript)
504
- : setSidePanel(SidePanelType.None);
505
- return;
506
- }
507
- if (isSTTActive) {
508
- !isTranscriptON
509
- ? setSidePanel(SidePanelType.Transcript)
510
- : setSidePanel(SidePanelType.None);
511
- } else {
512
- isFirstTimePopupOpen.current = true;
513
- setLanguagePopup(true);
514
- }
515
- },
516
- });
496
+ if ($config.ENABLE_MEETING_TRANSCRIPT) {
497
+ actionMenuitems.push({
498
+ icon: 'transcript',
499
+ iconColor: $config.SECONDARY_ACTION_COLOR,
500
+ textColor: $config.FONT_COLOR,
501
+ disabled: !(
502
+ $config.ENABLE_STT &&
503
+ $config.ENABLE_CAPTION &&
504
+ $config.ENABLE_MEETING_TRANSCRIPT &&
505
+ (isHost || (!isHost && isSTTActive))
506
+ ),
507
+ title: transcriptLabel(isTranscriptON),
508
+ callback: () => {
509
+ setActionMenuVisible(false);
510
+ STT_clicked.current = !isTranscriptON ? 'transcript' : null;
511
+ if (isSTTError) {
512
+ !isTranscriptON
513
+ ? setSidePanel(SidePanelType.Transcript)
514
+ : setSidePanel(SidePanelType.None);
515
+ return;
516
+ }
517
+ if (isSTTActive) {
518
+ !isTranscriptON
519
+ ? setSidePanel(SidePanelType.Transcript)
520
+ : setSidePanel(SidePanelType.None);
521
+ } else {
522
+ isFirstTimePopupOpen.current = true;
523
+ setLanguagePopup(true);
524
+ }
525
+ },
526
+ });
527
+ }
517
528
  }
518
529
 
519
530
  // view recordings
@@ -880,7 +891,9 @@ export const MoreButtonToolbarItem = () => {
880
891
  }, [isHost]);
881
892
 
882
893
  return width < BREAKPOINTS.md ||
883
- ($config.ENABLE_STT && (isHost || (!isHost && isSTTActive))) ||
894
+ ($config.ENABLE_STT &&
895
+ $config.ENABLE_CAPTION &&
896
+ (isHost || (!isHost && isSTTActive))) ||
884
897
  $config.ENABLE_NOISE_CANCELLATION ||
885
898
  ($config.ENABLE_VIRTUAL_BACKGROUND && !$config.AUDIO_ROOM) ||
886
899
  (isHost && $config.ENABLE_WHITEBOARD && isWebInternal()) ? (
@@ -235,6 +235,9 @@ const TranscriptIconBtn = (props: TranscriptIconProps) => {
235
235
  $config.ENABLE_STT &&
236
236
  (isHost || (!isHost && isSTTActive))
237
237
  );
238
+ if (!$config.ENABLE_MEETING_TRANSCRIPT) {
239
+ return null;
240
+ }
238
241
  return (
239
242
  <ToolbarItem>
240
243
  <TranscriptIcon isOnActionSheet={true} showLabel={true} />
@@ -29,12 +29,15 @@ import {useRoomInfo} from '../../components/room-info/useRoomInfo';
29
29
  import {
30
30
  ToolbarCustomItem,
31
31
  controlMessageEnum,
32
+ useCaption,
32
33
  useUserName,
33
34
  } from 'customization-api';
34
35
  import events, {PersistanceLevel} from '../../rtm-events-api';
35
36
  import VideoCallMobileView from './VideoCallMobileView';
36
37
  import CaptionContainer from '../../subComponents/caption/CaptionContainer';
37
- import Transcript from '../../subComponents/caption/Transcript';
38
+ import Transcript, {
39
+ TranscriptProps,
40
+ } from '../../subComponents/caption/Transcript';
38
41
  import Spacer from '../../atoms/Spacer';
39
42
  import Leftbar, {LeftbarProps} from '../../components/Leftbar';
40
43
  import Rightbar, {RightbarProps} from '../../components/Rightbar';
@@ -50,11 +53,14 @@ const VideoCallScreen = () => {
50
53
  const {
51
54
  data: {meetingTitle, isHost},
52
55
  } = useRoomInfo();
56
+ const {isCaptionON} = useCaption();
53
57
  const {
54
58
  ChatComponent,
55
59
  VideocallComponent,
56
60
  BottombarComponent,
57
61
  ParticipantsComponent,
62
+ TranscriptComponent,
63
+ CaptionComponent,
58
64
  SettingsComponent,
59
65
  TopbarComponent,
60
66
  VideocallBeforeView,
@@ -73,6 +79,8 @@ const VideoCallScreen = () => {
73
79
  ChatComponent: React.ComponentType<ChatProps>;
74
80
  BottombarComponent: React.ComponentType<ControlsProps>;
75
81
  ParticipantsComponent: React.ComponentType;
82
+ TranscriptComponent: React.ComponentType<TranscriptProps>;
83
+ CaptionComponent: React.ComponentType;
76
84
  SettingsComponent: React.ComponentType;
77
85
  TopbarComponent: React.ComponentType<NavbarProps>;
78
86
  VideocallBeforeView: React.ComponentType;
@@ -88,6 +96,8 @@ const VideoCallScreen = () => {
88
96
  TopbarComponent: Navbar,
89
97
  ChatComponent: Chat,
90
98
  ParticipantsComponent: ParticipantsView,
99
+ TranscriptComponent: Transcript,
100
+ CaptionComponent: CaptionContainer,
91
101
  SettingsComponent: SettingsView,
92
102
  VideocallAfterView: React.Fragment,
93
103
  VideocallBeforeView: React.Fragment,
@@ -206,6 +216,23 @@ const VideoCallScreen = () => {
206
216
  data?.components?.videoCall.participantsPanel;
207
217
  }
208
218
 
219
+ if (
220
+ data?.components?.videoCall.transcriptPanel &&
221
+ typeof data?.components?.videoCall.transcriptPanel !== 'object' &&
222
+ isValidReactComponent(data?.components?.videoCall.transcriptPanel)
223
+ ) {
224
+ components.TranscriptComponent =
225
+ data?.components?.videoCall.transcriptPanel;
226
+ }
227
+
228
+ if (
229
+ data?.components?.videoCall.captionPanel &&
230
+ typeof data?.components?.videoCall.captionPanel !== 'object' &&
231
+ isValidReactComponent(data?.components?.videoCall.captionPanel)
232
+ ) {
233
+ components.CaptionComponent = data?.components?.videoCall.captionPanel;
234
+ }
235
+
209
236
  //todo hari - need to remove wrapper
210
237
  if (
211
238
  data?.components?.videoCall.wrapper &&
@@ -313,7 +340,15 @@ const VideoCallScreen = () => {
313
340
  ) : (
314
341
  <></>
315
342
  )}
316
- {sidePanel === SidePanelType.Transcript ? <Transcript /> : <></>}
343
+ {sidePanel === SidePanelType.Transcript ? (
344
+ $config.ENABLE_MEETING_TRANSCRIPT ? (
345
+ <TranscriptComponent />
346
+ ) : (
347
+ <></>
348
+ )
349
+ ) : (
350
+ <></>
351
+ )}
317
352
  {sidePanel === SidePanelType.VirtualBackground ? (
318
353
  <VBPanel />
319
354
  ) : (
@@ -331,7 +366,7 @@ const VideoCallScreen = () => {
331
366
  />
332
367
  ) : (
333
368
  <>
334
- <CaptionContainer />
369
+ {isCaptionON ? <CaptionComponent /> : <></>}
335
370
  <Spacer size={10} />
336
371
  <View
337
372
  style={
@@ -57,7 +57,11 @@ const EndcallPopup = (props: EndcallPopupProps) => {
57
57
  const leaveMeetingPopupActionButton = useString(leavePopupPrimaryBtnText)();
58
58
  const cancelLabel = useString(cancelText)();
59
59
  const {isSTTActive} = useCaption();
60
- const isTranscriptAvailable = $config.ENABLE_STT && isSTTActive;
60
+ const isTranscriptAvailable =
61
+ $config.ENABLE_STT &&
62
+ $config.ENABLE_CAPTION &&
63
+ $config.ENABLE_MEETING_TRANSCRIPT &&
64
+ isSTTActive;
61
65
 
62
66
  const stayBtnLabel = cancelLabel;
63
67
  const leaveBtnLabel = leaveMeetingPopupActionButton;
@@ -41,7 +41,7 @@ import {
41
41
  sttTranscriptPanelViewLatestText,
42
42
  } from '../../../src/language/default-labels/videoCallScreenLabels';
43
43
 
44
- interface TranscriptProps {
44
+ export interface TranscriptProps {
45
45
  showHeader?: boolean;
46
46
  }
47
47
 
@@ -27,9 +27,9 @@ const TranscriptIcon = (props: TranscriptIconProps) => {
27
27
  isMobileView = false,
28
28
  } = props;
29
29
 
30
- const {start, restart, isAuthorizedSTTUser} = useSTTAPI();
30
+ const {start, restart, isAuthorizedTranscriptUser} = useSTTAPI();
31
31
  const {isSTTActive, language: prevLang, isSTTError} = useCaption();
32
- const isDisabled = !isAuthorizedSTTUser();
32
+ const isDisabled = !isAuthorizedTranscriptUser();
33
33
  const [isLanguagePopupOpen, setLanguagePopup] =
34
34
  React.useState<boolean>(false);
35
35
  const isFirstTimePopupOpen = React.useRef(false);
@@ -15,6 +15,7 @@ interface IuseSTTAPI {
15
15
  stop: () => Promise<void>;
16
16
  restart: (lang: LanguageType[]) => Promise<void>;
17
17
  isAuthorizedSTTUser: () => boolean;
18
+ isAuthorizedTranscriptUser: () => boolean;
18
19
  }
19
20
 
20
21
  const useSTTAPI = (): IuseSTTAPI => {
@@ -213,9 +214,23 @@ const useSTTAPI = (): IuseSTTAPI => {
213
214
 
214
215
  // attendee can view option if any host has started STT
215
216
  const isAuthorizedSTTUser = () =>
216
- $config.ENABLE_STT && (isHost || (!isHost && isSTTActive));
217
+ $config.ENABLE_STT &&
218
+ $config.ENABLE_CAPTION &&
219
+ (isHost || (!isHost && isSTTActive));
217
220
 
218
- return {start, stop, restart, isAuthorizedSTTUser};
221
+ const isAuthorizedTranscriptUser = () =>
222
+ $config.ENABLE_STT &&
223
+ $config.ENABLE_CAPTION &&
224
+ $config.ENABLE_MEETING_TRANSCRIPT &&
225
+ (isHost || (!isHost && isSTTActive));
226
+
227
+ return {
228
+ start,
229
+ stop,
230
+ restart,
231
+ isAuthorizedSTTUser,
232
+ isAuthorizedTranscriptUser,
233
+ };
219
234
  };
220
235
 
221
236
  export default useSTTAPI;
@@ -139,7 +139,11 @@ const RecordingProvider = (props: RecordingProviderProps) => {
139
139
  setSidePanel(SidePanelType.Chat);
140
140
  setChatType(ChatType.Group);
141
141
  }
142
- if (recordingBotUIConfig.stt && $config.ENABLE_STT) {
142
+ if (
143
+ recordingBotUIConfig.stt &&
144
+ $config.ENABLE_STT &&
145
+ $config.ENABLE_CAPTION
146
+ ) {
143
147
  setIsCaptionON(true);
144
148
  }
145
149
  }
@@ -12,6 +12,7 @@
12
12
 
13
13
  import {DispatchContext, RtcContext} from '../../agora-rn-uikit';
14
14
  import {useContext} from 'react';
15
+ import {isWeb} from './common';
15
16
 
16
17
  function useLocalAudio() {
17
18
  const {dispatch} = useContext(DispatchContext);
@@ -32,7 +33,37 @@ function useLocalAudio() {
32
33
  });
33
34
  };
34
35
 
35
- return {enableAudioButton, disableAudioButton};
36
+ const getLocalAudioStream = () => {
37
+ try {
38
+ return isWeb() ? window?.engine?.localStream?.audio : null;
39
+ } catch (error) {
40
+ throw error;
41
+ }
42
+ };
43
+
44
+ const getRemoteAudioStream = (uid: number) => {
45
+ try {
46
+ return isWeb() ? window?.engine?.remoteStreams?.get(uid)?.audio : null;
47
+ } catch (error) {
48
+ throw error;
49
+ }
50
+ };
51
+
52
+ const getLocalScreenshareAudioStream = () => {
53
+ try {
54
+ return isWeb() ? window?.engine?.screenStream?.audio : null;
55
+ } catch (error) {
56
+ throw error;
57
+ }
58
+ };
59
+
60
+ return {
61
+ enableAudioButton,
62
+ disableAudioButton,
63
+ getLocalAudioStream,
64
+ getRemoteAudioStream,
65
+ getLocalScreenshareAudioStream,
66
+ };
36
67
  }
37
68
 
38
69
  export default useLocalAudio;
@@ -0,0 +1,69 @@
1
+ /*
2
+ ********************************************
3
+ Copyright © 2021 Agora Lab, Inc., all rights reserved.
4
+ AppBuilder and all associated components, source code, APIs, services, and documentation
5
+ (the “Materials”) are owned by Agora Lab, Inc. and its licensors. The Materials may not be
6
+ accessed, used, modified, or distributed for any purpose without a license from Agora Lab, Inc.
7
+ Use without a license or in violation of any license terms and conditions (including use for
8
+ any purpose competitive to Agora Lab, Inc.’s business) is strictly prohibited. For more
9
+ information visit https://appbuilder.agora.io.
10
+ *********************************************
11
+ */
12
+
13
+ import {DispatchContext, RtcContext} from '../../agora-rn-uikit';
14
+ import {useContext} from 'react';
15
+ import {isWeb} from './common';
16
+
17
+ function useLocalVideo() {
18
+ const {dispatch} = useContext(DispatchContext);
19
+ const {RtcEngineUnsafe} = useContext(RtcContext);
20
+
21
+ const disableVideoButton = () => {
22
+ RtcEngineUnsafe.muteLocalVideoStream(true);
23
+ dispatch({
24
+ type: 'LocalMuteVideo',
25
+ value: [0, true],
26
+ });
27
+ };
28
+
29
+ const enableVideoButton = () => {
30
+ dispatch({
31
+ type: 'LocalMuteVideo',
32
+ value: [0, false],
33
+ });
34
+ };
35
+
36
+ const getLocalVideoStream = () => {
37
+ try {
38
+ return isWeb() ? window?.engine?.localStream?.video : null;
39
+ } catch (error) {
40
+ throw error;
41
+ }
42
+ };
43
+
44
+ const getRemoteVideoStream = (uid: number) => {
45
+ try {
46
+ return isWeb() ? window?.engine?.remoteStreams?.get(uid)?.video : null;
47
+ } catch (error) {
48
+ throw error;
49
+ }
50
+ };
51
+
52
+ const getLocalScreenshareVideoStream = () => {
53
+ try {
54
+ return isWeb() ? window?.engine?.screenStream?.video : null;
55
+ } catch (error) {
56
+ throw error;
57
+ }
58
+ };
59
+
60
+ return {
61
+ enableVideoButton,
62
+ disableVideoButton,
63
+ getLocalVideoStream,
64
+ getRemoteVideoStream,
65
+ getLocalScreenshareVideoStream,
66
+ };
67
+ }
68
+
69
+ export default useLocalVideo;
@@ -0,0 +1,102 @@
1
+ import {useEffect, useRef} from 'react';
2
+ import {
3
+ SidePanelType,
4
+ customEvents,
5
+ useContent,
6
+ useSTTAPI,
7
+ useSidePanel,
8
+ } from 'customization-api';
9
+ import useTranscriptDownload from '../subComponents/caption/useTranscriptDownload';
10
+ import {useCaption} from '../subComponents/caption/useCaption';
11
+ import {LanguageType} from '../subComponents/caption/utils';
12
+
13
+ const useSpeechToText = () => {
14
+ const {
15
+ isCaptionON: isSpeechToTextOn,
16
+ setIsCaptionON,
17
+ meetingTranscript: transcriptData,
18
+ captionObj: captionData,
19
+ prevSpeakerRef,
20
+ activeSpeakerRef,
21
+ } = useCaption();
22
+ const {setSidePanel} = useSidePanel();
23
+
24
+ const {start, restart, stop, isAuthorizedSTTUser} = useSTTAPI();
25
+ const {defaultContent} = useContent();
26
+
27
+ const isAuthorizedSTTUserRef = useRef(isAuthorizedSTTUser);
28
+ const defaultContentRef = useRef(defaultContent);
29
+
30
+ const showTranscriptPanel = (show: boolean) => {
31
+ show
32
+ ? setSidePanel(SidePanelType.Transcript)
33
+ : setSidePanel(SidePanelType.None);
34
+ };
35
+
36
+ const showCaptionPanel = (show: boolean) => {
37
+ show ? setIsCaptionON(true) : setIsCaptionON(false);
38
+ };
39
+
40
+ useEffect(() => {
41
+ if (!$config.ENABLE_STT) {
42
+ throw new Error('Speech To Text is not enabled');
43
+ }
44
+ }, []);
45
+
46
+ useEffect(() => {
47
+ isAuthorizedSTTUserRef.current = isAuthorizedSTTUser;
48
+ }, [isAuthorizedSTTUser]);
49
+
50
+ useEffect(() => {
51
+ defaultContentRef.current = defaultContent;
52
+ }, [defaultContent]);
53
+
54
+ const {downloadTranscript} = useTranscriptDownload();
55
+
56
+ const getActiveSpeakerName = (): string => {
57
+ return defaultContentRef.current[activeSpeakerRef.current]?.name || '';
58
+ };
59
+
60
+ const getPrevSpeakerName = (): string => {
61
+ return defaultContentRef.current[prevSpeakerRef.current]?.name || '';
62
+ };
63
+
64
+ const startSpeechToText = async (language: LanguageType[]) => {
65
+ if (!isAuthorizedSTTUserRef.current) {
66
+ throw new Error('Invalid user');
67
+ }
68
+ return await start(language);
69
+ };
70
+
71
+ const stopSpeechToText = async () => {
72
+ if (!isAuthorizedSTTUserRef.current) {
73
+ throw new Error('Invalid user');
74
+ }
75
+ return await stop();
76
+ };
77
+
78
+ const changeSpeakingLanguage = async (language: LanguageType[]) => {
79
+ if (!isAuthorizedSTTUserRef.current) {
80
+ throw new Error('Invalid user');
81
+ }
82
+ return await restart(language);
83
+ };
84
+
85
+ return $config.ENABLE_STT
86
+ ? {
87
+ isSpeechToTextOn,
88
+ startSpeechToText,
89
+ stopSpeechToText,
90
+ changeSpeakingLanguage,
91
+ downloadTranscript,
92
+ getActiveSpeakerName,
93
+ getPrevSpeakerName,
94
+ showTranscriptPanel,
95
+ showCaptionPanel,
96
+ transcriptData,
97
+ captionData,
98
+ }
99
+ : {};
100
+ };
101
+
102
+ export default useSpeechToText;