@100mslive/roomkit-react 0.1.8-alpha.0 → 0.1.9-alpha.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. package/dist/{HLSView-IQRPLYNH.js → HLSView-U53QN3AC.js} +3 -3
  2. package/dist/Modal/Dialog.d.ts +402 -1706
  3. package/dist/Prebuilt/App.d.ts +6 -0
  4. package/dist/Prebuilt/AppContext.d.ts +2 -0
  5. package/dist/Prebuilt/AppStateContext.d.ts +16 -0
  6. package/dist/Prebuilt/components/ConferenceScreen.d.ts +2 -0
  7. package/dist/Prebuilt/components/Footer/PaginatedParticipants.d.ts +5 -0
  8. package/dist/Prebuilt/components/Footer/PollsToggle.d.ts +2 -0
  9. package/dist/Prebuilt/components/Footer/RoleAccordion.d.ts +10 -3
  10. package/dist/Prebuilt/components/LeaveScreen.d.ts +2 -0
  11. package/dist/Prebuilt/components/MwebLandscapePrompt.d.ts +2 -0
  12. package/dist/Prebuilt/components/Notifications/AutoplayBlockedModal.d.ts +2 -0
  13. package/dist/Prebuilt/components/Notifications/HLSFailureModal.d.ts +2 -0
  14. package/dist/Prebuilt/components/Notifications/InitErrorModal.d.ts +2 -0
  15. package/dist/Prebuilt/components/Notifications/Notifications.d.ts +2 -0
  16. package/dist/Prebuilt/components/Notifications/PeerNotifications.d.ts +1 -0
  17. package/dist/Prebuilt/components/Notifications/PermissionErrorModal.d.ts +2 -0
  18. package/dist/Prebuilt/components/Notifications/ReconnectNotifications.d.ts +2 -0
  19. package/dist/Prebuilt/components/Notifications/TrackBulkUnmuteModal.d.ts +2 -0
  20. package/dist/Prebuilt/components/Notifications/TrackNotifications.d.ts +1 -0
  21. package/dist/Prebuilt/components/Notifications/TrackUnmuteModal.d.ts +2 -0
  22. package/dist/Prebuilt/components/Polls/Polls.d.ts +2 -0
  23. package/dist/Prebuilt/components/Preview/PreviewJoin.d.ts +1 -2
  24. package/dist/Prebuilt/components/Preview/PreviewScreen.d.ts +2 -0
  25. package/dist/Prebuilt/components/hooks/useRedirectToLeave.d.ts +1 -1
  26. package/dist/{VirtualBackground-GP4ATXD3.js → VirtualBackground-PMLQPJB6.js} +3 -5
  27. package/dist/{VirtualBackground-GP4ATXD3.js.map → VirtualBackground-PMLQPJB6.js.map} +1 -1
  28. package/dist/chunk-ANQRGVIX.js +14441 -0
  29. package/dist/chunk-ANQRGVIX.js.map +7 -0
  30. package/dist/{chunk-Z3O2WGWV.js → chunk-XQ2NRKIW.js} +66 -3
  31. package/dist/chunk-XQ2NRKIW.js.map +7 -0
  32. package/dist/context/DialogContext.d.ts +6 -0
  33. package/dist/hooks/useDialogContainerSelector.d.ts +1 -0
  34. package/dist/index.cjs.js +10956 -9818
  35. package/dist/index.cjs.js.map +4 -4
  36. package/dist/index.d.ts +1 -0
  37. package/dist/index.js +6 -2
  38. package/dist/meta.cjs.json +4076 -3201
  39. package/dist/meta.esbuild.json +4391 -3623
  40. package/dist/utils/animations.d.ts +11 -0
  41. package/package.json +6 -7
  42. package/src/AudioLevel/AudioLevel.tsx +1 -1
  43. package/src/Modal/Dialog.tsx +31 -3
  44. package/src/Prebuilt/App.tsx +49 -97
  45. package/src/Prebuilt/AppContext.tsx +6 -0
  46. package/src/Prebuilt/AppStateContext.tsx +71 -0
  47. package/src/Prebuilt/common/constants.js +36 -1
  48. package/src/Prebuilt/common/utils.js +47 -0
  49. package/src/Prebuilt/components/AppData/AppData.jsx +6 -1
  50. package/src/Prebuilt/components/AppData/useSidepane.js +23 -1
  51. package/src/Prebuilt/components/AppData/useUISettings.js +49 -5
  52. package/src/Prebuilt/components/Chip.tsx +6 -2
  53. package/src/Prebuilt/components/{conference.jsx → ConferenceScreen.tsx} +34 -46
  54. package/src/Prebuilt/components/Footer/Footer.tsx +5 -0
  55. package/src/Prebuilt/components/Footer/PaginatedParticipants.tsx +125 -0
  56. package/src/Prebuilt/components/Footer/ParticipantList.jsx +55 -24
  57. package/src/Prebuilt/components/Footer/PollsToggle.tsx +22 -0
  58. package/src/Prebuilt/components/Footer/RoleAccordion.tsx +87 -85
  59. package/src/Prebuilt/components/Footer/RoleOptions.tsx +1 -1
  60. package/src/Prebuilt/components/Header/StreamActions.tsx +5 -3
  61. package/src/Prebuilt/components/Leave/DesktopLeaveRoom.tsx +4 -5
  62. package/src/Prebuilt/components/Leave/LeaveRoom.tsx +0 -4
  63. package/src/Prebuilt/components/{PostLeave.jsx → LeaveScreen.tsx} +6 -13
  64. package/src/Prebuilt/components/MoreSettings/ChangeNameModal.jsx +2 -3
  65. package/src/Prebuilt/components/MoreSettings/EmbedUrl.jsx +2 -3
  66. package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +18 -1
  67. package/src/Prebuilt/components/{MwebLandscapePrompt.jsx → MwebLandscapePrompt.tsx} +10 -11
  68. package/src/Prebuilt/components/Notifications/{AutoplayBlockedModal.jsx → AutoplayBlockedModal.tsx} +2 -1
  69. package/src/Prebuilt/components/Notifications/{HLSFailureModal.jsx → HLSFailureModal.tsx} +10 -8
  70. package/src/Prebuilt/components/Notifications/{InitErrorModal.jsx → InitErrorModal.tsx} +5 -2
  71. package/src/Prebuilt/components/Notifications/{Notifications.jsx → Notifications.tsx} +41 -27
  72. package/src/Prebuilt/components/Notifications/{PeerNotifications.jsx → PeerNotifications.tsx} +3 -0
  73. package/src/Prebuilt/components/Notifications/{PermissionErrorModal.jsx → PermissionErrorModal.tsx} +6 -4
  74. package/src/Prebuilt/components/Notifications/{ReconnectNotifications.jsx → ReconnectNotifications.tsx} +11 -6
  75. package/src/Prebuilt/components/Notifications/{TrackBulkUnmuteModal.jsx → TrackBulkUnmuteModal.tsx} +9 -3
  76. package/src/Prebuilt/components/Notifications/{TrackUnmuteModal.jsx → TrackUnmuteModal.tsx} +9 -3
  77. package/src/Prebuilt/components/Notifications/index.tsx +1 -0
  78. package/src/Prebuilt/components/Polls/CreatePollQuiz/PollsQuizMenu.jsx +229 -0
  79. package/src/Prebuilt/components/Polls/CreatePollQuiz/Timer.jsx +71 -0
  80. package/src/Prebuilt/components/Polls/CreateQuestions/CreateQuestions.jsx +132 -0
  81. package/src/Prebuilt/components/Polls/CreateQuestions/DeleteQuestionModal.jsx +66 -0
  82. package/src/Prebuilt/components/Polls/CreateQuestions/QuestionForm.jsx +251 -0
  83. package/src/Prebuilt/components/Polls/CreateQuestions/SavedQuestion.jsx +57 -0
  84. package/src/Prebuilt/components/Polls/Polls.tsx +28 -0
  85. package/src/Prebuilt/components/Polls/Voting/PollResultSummary.jsx +125 -0
  86. package/src/Prebuilt/components/Polls/Voting/QuestionCard.jsx +249 -0
  87. package/src/Prebuilt/components/Polls/Voting/StandardVoting.jsx +40 -0
  88. package/src/Prebuilt/components/Polls/Voting/TimedVoting.jsx +36 -0
  89. package/src/Prebuilt/components/Polls/Voting/Voting.jsx +99 -0
  90. package/src/Prebuilt/components/Polls/common/MultipleChoiceOptions.jsx +101 -0
  91. package/src/Prebuilt/components/Polls/common/OptionInputWithDelete.jsx +25 -0
  92. package/src/Prebuilt/components/Polls/common/SingleChoiceOptions.jsx +125 -0
  93. package/src/Prebuilt/components/Polls/common/StatusIndicator.jsx +47 -0
  94. package/src/Prebuilt/components/Polls/common/VoteCount.jsx +28 -0
  95. package/src/Prebuilt/components/Polls/common/VoteProgress.jsx +17 -0
  96. package/src/Prebuilt/components/Polls/common/VoterList.jsx +22 -0
  97. package/src/Prebuilt/components/Polls/common/Votes.jsx +72 -0
  98. package/src/Prebuilt/components/Preview/PreviewForm.tsx +3 -2
  99. package/src/Prebuilt/components/Preview/PreviewJoin.tsx +29 -21
  100. package/src/Prebuilt/components/Preview/{PreviewContainer.tsx → PreviewScreen.tsx} +2 -19
  101. package/src/Prebuilt/components/RaiseHand.jsx +1 -1
  102. package/src/Prebuilt/components/RoleChangeModal.jsx +2 -3
  103. package/src/Prebuilt/components/RoleChangeRequest/RequestPrompt.tsx +2 -3
  104. package/src/Prebuilt/components/Settings/SettingsModal.jsx +2 -3
  105. package/src/Prebuilt/components/Settings/StartRecording.jsx +15 -4
  106. package/src/Prebuilt/components/SidePaneTabs.tsx +32 -6
  107. package/src/Prebuilt/components/StatsForNerds.jsx +2 -3
  108. package/src/Prebuilt/components/Streaming/Common.jsx +31 -21
  109. package/src/Prebuilt/components/VideoLayouts/ScreenshareLayout.tsx +8 -9
  110. package/src/Prebuilt/components/VideoTile.jsx +28 -39
  111. package/src/Prebuilt/components/hooks/useAutoStartStreaming.tsx +3 -3
  112. package/src/Prebuilt/components/hooks/useDropdownSelection.jsx +1 -1
  113. package/src/Prebuilt/components/hooks/useRedirectToLeave.tsx +9 -17
  114. package/src/Prebuilt/components/pdfAnnotator/pdfFileOptions.jsx +2 -3
  115. package/src/Prebuilt/components/pdfAnnotator/submitPdf.jsx +1 -1
  116. package/src/Prebuilt/components/pdfAnnotator/uploadedFile.jsx +2 -3
  117. package/src/Prebuilt/layouts/EmbedView.jsx +47 -60
  118. package/src/Prebuilt/layouts/PDFView.jsx +49 -99
  119. package/src/Prebuilt/layouts/SidePane.tsx +9 -4
  120. package/src/Prebuilt/layouts/VideoStreamingSection.tsx +2 -2
  121. package/src/Prebuilt/primitives/DialogContent.jsx +4 -5
  122. package/src/context/DialogContext.tsx +13 -0
  123. package/src/hooks/useDialogContainerSelector.tsx +7 -0
  124. package/src/index.ts +1 -0
  125. package/src/utils/animations.ts +6 -0
  126. package/dist/Prebuilt/components/PrebuiltDialogPortal.d.ts +0 -4
  127. package/dist/Prebuilt/components/Preview/PreviewContainer.d.ts +0 -3
  128. package/dist/chunk-2H5NIZB7.js +0 -70
  129. package/dist/chunk-2H5NIZB7.js.map +0 -7
  130. package/dist/chunk-GLYGPYNS.js +0 -7125
  131. package/dist/chunk-GLYGPYNS.js.map +0 -7
  132. package/dist/chunk-Z3O2WGWV.js.map +0 -7
  133. package/dist/conference-JD35TNH4.js +0 -6503
  134. package/dist/conference-JD35TNH4.js.map +0 -7
  135. package/src/Prebuilt/components/GoLiveButton.jsx +0 -42
  136. package/src/Prebuilt/components/PrebuiltDialogPortal.tsx +0 -6
  137. package/src/Prebuilt/components/Streaming/HLSStreaming.jsx +0 -220
  138. package/src/Prebuilt/components/Streaming/RTMPStreaming.jsx +0 -334
  139. package/src/Prebuilt/components/Streaming/StreamingLanding.jsx +0 -76
  140. /package/dist/{HLSView-IQRPLYNH.js.map → HLSView-U53QN3AC.js.map} +0 -0
  141. /package/{src/Prebuilt/components/Notifications/index.jsx → dist/Prebuilt/components/Notifications/index.d.ts} +0 -0
  142. /package/src/Prebuilt/components/Notifications/{TrackNotifications.jsx → TrackNotifications.tsx} +0 -0
@@ -1,42 +0,0 @@
1
- import React from 'react';
2
- import { useRecordingStreaming } from '@100mslive/react-sdk';
3
- import { GoLiveIcon } from '@100mslive/react-icons';
4
- import { Button } from '../../Button';
5
- import { Tooltip } from '../../Tooltip';
6
- import { useIsSidepaneTypeOpen, useSidepaneToggle } from './AppData/useSidepane';
7
- import { useIsHLSStartedFromUI, useIsRTMPStartedFromUI } from './AppData/useUISettings';
8
- import { SIDE_PANE_OPTIONS } from './../common/constants';
9
-
10
- const GoLiveButton = () => {
11
- const isStreamingSidepaneOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.STREAMING);
12
- const toggleStreaming = useSidepaneToggle(SIDE_PANE_OPTIONS.STREAMING);
13
- const { isStreamingOn, isBrowserRecordingOn } = useRecordingStreaming();
14
- const isHLSStartedFromUI = useIsHLSStartedFromUI();
15
- const isRTMPStartedFromUI = useIsRTMPStartedFromUI();
16
- let tooltipText = 'Start streaming';
17
- if (isHLSStartedFromUI || isRTMPStartedFromUI) {
18
- if (isHLSStartedFromUI) {
19
- tooltipText = 'HLS start in progress';
20
- }
21
- if (isRTMPStartedFromUI) {
22
- tooltipText = 'RTMP start in progress';
23
- }
24
- }
25
- return (
26
- <Tooltip title={tooltipText}>
27
- <Button
28
- data-testid="go_live"
29
- variant={isStreamingSidepaneOpen ? 'standard' : 'primary'}
30
- onClick={toggleStreaming}
31
- icon
32
- loading={isRTMPStartedFromUI || isHLSStartedFromUI}
33
- disabled={isBrowserRecordingOn && !isStreamingOn}
34
- >
35
- <GoLiveIcon />
36
- Go Live
37
- </Button>
38
- </Tooltip>
39
- );
40
- };
41
-
42
- export default GoLiveButton;
@@ -1,6 +0,0 @@
1
- import React, { ReactNode } from 'react';
2
- import { Dialog } from '../../Modal';
3
-
4
- export const PrebuiltDialogPortal = ({ children }: { children: ReactNode }) => (
5
- <Dialog.Portal container={document.getElementById('prebuilt-container')}>{children}</Dialog.Portal>
6
- );
@@ -1,220 +0,0 @@
1
- import React, { Fragment, useCallback, useEffect, useState } from 'react';
2
- import { selectRoomID, useHMSActions, useHMSStore, useRecordingStreaming } from '@100mslive/react-sdk';
3
- import {
4
- EndStreamIcon,
5
- EyeOpenIcon,
6
- GoLiveIcon,
7
- InfoIcon,
8
- LinkIcon,
9
- PeopleIcon,
10
- SupportIcon,
11
- WrenchIcon,
12
- } from '@100mslive/react-icons';
13
- import { Box, Button, Flex, Loading, Text } from '../../../';
14
- import { Container, ContentBody, ContentHeader, ErrorText, RecordStream } from './Common';
15
- import { useSetAppDataByKey } from '../AppData/useUISettings';
16
- import { useFilteredRoles } from '../../common/hooks';
17
- import { APP_DATA } from '../../common/constants';
18
-
19
- const getCardData = (roleName, roomId) => {
20
- let data = {};
21
- const formattedRoleName = roleName[0].toUpperCase() + roleName.slice(1);
22
-
23
- switch (roleName) {
24
- case 'broadcaster': {
25
- data = {
26
- title: formattedRoleName,
27
- content: 'Broadcasters can livestream audio or video, manage stream appearance and control the room via HLS.',
28
- icon: <SupportIcon />,
29
- };
30
- break;
31
- }
32
- case 'hls-viewer': {
33
- data = {
34
- title: 'HLS Viewer',
35
- content:
36
- 'Viewers can view and send chat messages, but need to be made broadcasters to participate with audio or video.',
37
- icon: <EyeOpenIcon />,
38
- };
39
- break;
40
- }
41
- default:
42
- data = {
43
- title: formattedRoleName,
44
- content: `${formattedRoleName} is customised with specific permissions, which will determine how it interacts with this room.`,
45
- icon: <WrenchIcon />,
46
- order: 1,
47
- };
48
- }
49
- data['link'] = `/${roomId}/${roleName}`;
50
- return data;
51
- };
52
-
53
- const Card = ({ title, icon, link, content, isHLSRunning, order = 0 }) => {
54
- const [copied, setCopied] = useState(false);
55
- return isHLSRunning ? (
56
- <Box
57
- key={title}
58
- css={{
59
- backgroundColor: '$surface_bright',
60
- padding: '$10',
61
- order,
62
- borderRadius: '$2',
63
- }}
64
- >
65
- <Flex align="center" gap="2" css={{ color: '$primary_bright' }}>
66
- {icon}
67
- <Text variant="h6" css={{ fontWeight: '$semiBold' }}>
68
- {title}
69
- </Text>
70
- </Flex>
71
- <Text variant="sm" css={{ color: '$on_surface_medium', mt: '$6' }}>
72
- {content}
73
- </Text>
74
- <Button
75
- variant="standard"
76
- onClick={() => {
77
- navigator.clipboard.writeText(`${window.location.origin}${link}`);
78
- setCopied(true);
79
- setTimeout(() => setCopied(false), 2000);
80
- }}
81
- css={{ w: '100%', r: '$1', mt: '$10', fontWeight: '$semiBold' }}
82
- icon
83
- >
84
- {copied ? (
85
- <>Link copied!</>
86
- ) : (
87
- <>
88
- <LinkIcon style={{ color: 'inherit' }} />
89
- Copy Invite Link
90
- </>
91
- )}
92
- </Button>
93
- </Box>
94
- ) : null;
95
- };
96
-
97
- export const HLSStreaming = ({ onBack }) => {
98
- const roleNames = useFilteredRoles();
99
- const roomId = useHMSStore(selectRoomID);
100
- const cards = roleNames.map(roleName => getCardData(roleName, roomId));
101
-
102
- const { isHLSRunning } = useRecordingStreaming();
103
- const [showLinks, setShowLinks] = useState(false);
104
- return !showLinks ? (
105
- <Container rounded>
106
- <ContentHeader title="Start Streaming" content="HLS" onBack={onBack} />
107
- <ContentBody title="HLS Streaming" Icon={GoLiveIcon} removeVerticalPadding>
108
- Stream directly from the browser using any device with multiple hosts and real-time messaging, all within this
109
- platform.
110
- </ContentBody>
111
- {isHLSRunning ? <EndHLS setShowLinks={setShowLinks} /> : <StartHLS />}
112
- </Container>
113
- ) : (
114
- <Container rounded>
115
- <ContentHeader title="Invite People" content="Start the conversation" onBack={() => setShowLinks(false)} />
116
-
117
- <Flex direction="column" css={{ gap: '$10', p: '$0 $10', overflowY: 'auto', mb: '$10' }}>
118
- {cards.map(card => (
119
- <Card key={card.title} {...card} isHLSRunning={isHLSRunning} />
120
- ))}
121
- </Flex>
122
- </Container>
123
- );
124
- };
125
-
126
- const StartHLS = () => {
127
- const [record, setRecord] = useState(false);
128
- const [error, setError] = useState(false);
129
- const hmsActions = useHMSActions();
130
- const [isHLSStarted, setHLSStarted] = useSetAppDataByKey(APP_DATA.hlsStarted);
131
- const startHLS = useCallback(
132
- async variants => {
133
- try {
134
- if (isHLSStarted) {
135
- return;
136
- }
137
- setHLSStarted(true);
138
- setError('');
139
- await hmsActions.startHLSStreaming({
140
- variants,
141
- recording: { hlsVod: record, singleFilePerLayer: record },
142
- });
143
- } catch (error) {
144
- setHLSStarted(false);
145
- setError(error.message);
146
- }
147
- },
148
- [hmsActions, record, isHLSStarted, setHLSStarted],
149
- );
150
-
151
- return (
152
- <Fragment>
153
- <RecordStream record={record} setRecord={setRecord} testId="hls-recording" />
154
- <Box css={{ p: '$4 $10' }}>
155
- <ErrorText error={error} />
156
- <Button
157
- data-testid="start_hls"
158
- css={{ w: '100%', r: '$0' }}
159
- icon
160
- onClick={() => startHLS()}
161
- disabled={isHLSStarted}
162
- >
163
- {isHLSStarted ? <Loading size={24} color="currentColor" /> : <GoLiveIcon />}
164
- {isHLSStarted ? 'Starting stream...' : 'Go Live'}
165
- </Button>
166
- </Box>
167
- <Flex align="center" css={{ p: '$4 $10' }}>
168
- <Text>
169
- <InfoIcon width={16} height={16} />
170
- </Text>
171
- <Text variant="tiny" color="$on_surface_medium" css={{ mx: '$8' }}>
172
- You cannot start recording once the stream starts, you will have to stop the stream to enable recording.
173
- </Text>
174
- </Flex>
175
- </Fragment>
176
- );
177
- };
178
-
179
- const EndHLS = ({ setShowLinks }) => {
180
- const hmsActions = useHMSActions();
181
-
182
- const [inProgress, setInProgress] = useState(false);
183
- const [error, setError] = useState('');
184
- const { isHLSRunning } = useRecordingStreaming();
185
-
186
- useEffect(() => {
187
- if (inProgress && !isHLSRunning) {
188
- setInProgress(false);
189
- }
190
- }, [inProgress, isHLSRunning]);
191
-
192
- return (
193
- <Box css={{ p: '$4 $10' }}>
194
- <ErrorText error={error} />
195
- <Button
196
- data-testid="stop_hls"
197
- variant="danger"
198
- css={{ w: '100%', r: '$0', mt: '$8' }}
199
- icon
200
- loading={inProgress}
201
- disabled={inProgress}
202
- onClick={async () => {
203
- try {
204
- setInProgress(true);
205
- await hmsActions.stopHLSStreaming();
206
- } catch (error) {
207
- setError(error.message);
208
- setInProgress(false);
209
- }
210
- }}
211
- >
212
- <EndStreamIcon />
213
- End Stream
214
- </Button>
215
- <Button icon css={{ w: '100%', r: '$0', mt: '$8' }} onClick={() => setShowLinks(true)}>
216
- <PeopleIcon /> Invite People
217
- </Button>
218
- </Box>
219
- );
220
- };
@@ -1,334 +0,0 @@
1
- import React, { useEffect, useRef, useState } from 'react';
2
- import { useHMSActions, useRecordingStreaming } from '@100mslive/react-sdk';
3
- import { AddCircleIcon, EndStreamIcon, GoLiveIcon, PencilIcon, SettingsIcon, TrashIcon } from '@100mslive/react-icons';
4
- import { Accordion, Box, Button, Flex, Input, Label, Loading, Text } from '../../../';
5
- import { Container, ContentBody, ContentHeader, ErrorText, RecordStream } from './Common';
6
- import { ResolutionInput } from './ResolutionInput';
7
- import { useSetAppDataByKey } from '../AppData/useUISettings';
8
- import { UserPreferencesKeys, useUserPreferences } from '../hooks/useUserPreferences';
9
- import { APP_DATA, RTMP_RECORD_DEFAULT_RESOLUTION } from '../../common/constants';
10
-
11
- export const RTMPStreaming = ({ onBack }) => {
12
- const { isRTMPRunning } = useRecordingStreaming();
13
-
14
- return (
15
- <Container>
16
- <ContentHeader title="Start Streaming" content="Choose a destination" onBack={onBack} />
17
- <ContentBody Icon={SettingsIcon} title="RTMP">
18
- Live Stream your call to Twitch, YouTube, Facebook and any app which supports RTMP, all at the same time
19
- </ContentBody>
20
- {!isRTMPRunning ? <StartRTMP /> : <EndRTMP />}
21
- </Container>
22
- );
23
- };
24
-
25
- const StartRTMP = () => {
26
- const [rtmpPreference = [], setRTMPPreference] = useUserPreferences(UserPreferencesKeys.RTMP_URLS);
27
- const [rtmpStreams, setRTMPStreams] = useState(
28
- rtmpPreference.length > 0
29
- ? rtmpPreference
30
- : [
31
- {
32
- name: 'Stream',
33
- id: Date.now(),
34
- rtmpURL: '',
35
- streamKey: '',
36
- },
37
- ],
38
- );
39
- const hmsActions = useHMSActions();
40
- const [error, setError] = useState(false);
41
- const [record, setRecord] = useState(false);
42
- const [resolution, setResolution] = useState(RTMP_RECORD_DEFAULT_RESOLUTION);
43
- const [isRTMPStarted, setRTMPStarted] = useSetAppDataByKey(APP_DATA.rtmpStarted);
44
- const hasRTMPURL = rtmpStreams.some(value => value.rtmpURL && value.streamKey);
45
-
46
- return (
47
- <Box
48
- css={{ overflowY: 'auto' }}
49
- as="form"
50
- onSubmit={e => {
51
- e.preventDefault();
52
- }}
53
- >
54
- {rtmpStreams.length > 0 && (
55
- <Box css={{ px: '$10' }}>
56
- <Accordion.Root type="single" collapsible defaultValue={rtmpStreams[0].id}>
57
- {rtmpStreams.map((rtmp, index) => {
58
- return (
59
- <Accordion.Item
60
- value={rtmp.id}
61
- key={rtmp.id}
62
- css={{
63
- border: '2px solid $surface_bright !important',
64
- r: '$1',
65
- my: '$4',
66
- }}
67
- >
68
- <AccordionHeader rtmp={rtmp} setRTMPStreams={setRTMPStreams} />
69
- <Accordion.Content css={{ px: '$8', py: 0 }}>
70
- <RTMPForm {...rtmp} setRTMPStreams={setRTMPStreams} testId={`${index}_rtmp`} />
71
- </Accordion.Content>
72
- </Accordion.Item>
73
- );
74
- })}
75
- </Accordion.Root>
76
- </Box>
77
- )}
78
- <ResolutionInput
79
- testId="rtmp_resolution"
80
- onResolutionChange={setResolution}
81
- css={{
82
- flexDirection: 'column',
83
- alignItems: 'start',
84
- px: '$10',
85
- my: '$8',
86
- }}
87
- />
88
- <RecordStream record={record} setRecord={setRecord} testId="rtmp_recording" />
89
- <Box css={{ p: '$8 $10', '@lg': { display: 'flex', gap: '$4' } }}>
90
- {rtmpStreams.length < 3 && (
91
- <Button
92
- data-testid="add_stream"
93
- variant="standard"
94
- outlined
95
- icon
96
- css={{ my: '$4', w: '100%' }}
97
- onClick={() => {
98
- setRTMPStreams(streams => [
99
- ...streams,
100
- {
101
- name: 'Stream',
102
- id: Date.now(),
103
- rtmpURL: '',
104
- streamKey: '',
105
- },
106
- ]);
107
- }}
108
- >
109
- <AddCircleIcon /> Add Stream
110
- </Button>
111
- )}
112
-
113
- <Button
114
- data-testid="start_rtmp"
115
- variant="primary"
116
- icon
117
- type="submit"
118
- css={{ w: '100%', my: '$4' }}
119
- disabled={isRTMPStarted || (rtmpStreams.length === 0 && !record)}
120
- onClick={async () => {
121
- try {
122
- const hasInvalidData = rtmpStreams.find(
123
- value => (value.rtmpURL && !value.streamKey) || (value.streamKey && !value.rtmpURL),
124
- );
125
- if (hasInvalidData || (rtmpStreams.length > 0 && !hasRTMPURL)) {
126
- return;
127
- }
128
- setError('');
129
- setRTMPStarted(true);
130
- const urls = hasRTMPURL ? rtmpStreams.map(value => `${value.rtmpURL}/${value.streamKey}`) : [];
131
- await hmsActions.startRTMPOrRecording({
132
- rtmpURLs: urls,
133
- resolution: getResolution(resolution),
134
- record: record,
135
- });
136
- setRTMPPreference(rtmpStreams);
137
- } catch (error) {
138
- console.error(error);
139
- setError(error.message);
140
- setRTMPStarted(false);
141
- }
142
- }}
143
- >
144
- {isRTMPStarted ? <Loading size={24} color="currentColor" /> : <GoLiveIcon />}
145
- {isRTMPStarted ? 'Starting stream...' : 'Go Live'}
146
- </Button>
147
- <ErrorText error={error} />
148
- </Box>
149
- </Box>
150
- );
151
- };
152
-
153
- const EndRTMP = () => {
154
- const hmsActions = useHMSActions();
155
- const [inProgress, setInProgress] = useState(false);
156
- const [error, setError] = useState('');
157
- const { isRTMPRunning } = useRecordingStreaming();
158
-
159
- useEffect(() => {
160
- if (inProgress && !isRTMPRunning) {
161
- setInProgress(false);
162
- }
163
- }, [inProgress, isRTMPRunning]);
164
-
165
- return (
166
- <Box css={{ p: '$4 $10' }}>
167
- <ErrorText error={error} />
168
- <Button
169
- data-testid="stop_rtmp"
170
- variant="danger"
171
- css={{ w: '100%', r: '$0', my: '$8' }}
172
- icon
173
- loading={inProgress}
174
- disabled={inProgress}
175
- onClick={async () => {
176
- try {
177
- setInProgress(true);
178
- await hmsActions.stopRTMPAndRecording();
179
- } catch (error) {
180
- setError(error.message);
181
- setInProgress(false);
182
- }
183
- }}
184
- >
185
- <EndStreamIcon />
186
- End Stream
187
- </Button>
188
- </Box>
189
- );
190
- };
191
-
192
- const ActionIcon = ({ icon: Icon, onClick }) => {
193
- return (
194
- <Text as="span" css={{ mx: '$2', cursor: 'pointer' }} onClick={onClick}>
195
- <Icon width={16} height={16} />
196
- </Text>
197
- );
198
- };
199
-
200
- const FormLabel = ({ id, children }) => {
201
- return (
202
- <Label htmlFor={id} css={{ color: '$on_surface_high', my: '$4', fontSize: '$sm' }}>
203
- {children}
204
- </Label>
205
- );
206
- };
207
-
208
- const RTMPForm = ({ rtmpURL, id, streamKey, setRTMPStreams, testId }) => {
209
- const formRef = useRef(null);
210
- return (
211
- <Flex id={id} direction="column" css={{ mb: '$8', px: '$8' }} ref={formRef}>
212
- <FormLabel id="rtmpURL">
213
- RTMP URL
214
- <Asterik />
215
- </FormLabel>
216
- <Input
217
- data-testid={`${testId}_url`}
218
- placeholder="Enter RTMP URL"
219
- id="rtmpURL"
220
- name="rtmpURL"
221
- value={rtmpURL}
222
- onChange={e => {
223
- setRTMPStreams(streams =>
224
- updateStream({
225
- streams,
226
- id,
227
- value: e.target.value,
228
- key: e.target.name,
229
- }),
230
- );
231
- }}
232
- required
233
- />
234
- <FormLabel id="streamKey">
235
- Stream Key
236
- <Asterik />
237
- </FormLabel>
238
- <Input
239
- placeholder="Enter Stream Key"
240
- id="streamKey"
241
- name="streamKey"
242
- value={streamKey}
243
- data-testid={`${testId}_key`}
244
- onChange={e => {
245
- setRTMPStreams(streams =>
246
- updateStream({
247
- streams,
248
- id,
249
- value: e.target.value,
250
- key: e.target.name,
251
- }),
252
- );
253
- }}
254
- required
255
- />
256
- </Flex>
257
- );
258
- };
259
-
260
- const Asterik = () => {
261
- return (
262
- <Text variant="sm" as="span" css={{ color: '$alert_error_default', mx: '$2' }}>
263
- *
264
- </Text>
265
- );
266
- };
267
- const AccordionHeader = ({ rtmp, setRTMPStreams }) => {
268
- const [edit, setEdit] = useState(false);
269
- return (
270
- <Accordion.Header css={{ px: '$8' }}>
271
- {edit ? (
272
- <Input
273
- defaultValue={rtmp.name}
274
- autoFocus
275
- onBlur={e => {
276
- const value = e.currentTarget.value.trim();
277
- if (value) {
278
- setRTMPStreams(streams =>
279
- streams.map(stream => {
280
- if (stream.id === rtmp.id) {
281
- stream.name = value;
282
- }
283
- return stream;
284
- }),
285
- );
286
- setEdit(false);
287
- }
288
- }}
289
- />
290
- ) : (
291
- <Text css={{ flex: '1 1 0' }}>{rtmp.name}</Text>
292
- )}
293
- <Flex css={{ mx: '$4', gap: '$2' }}>
294
- <ActionIcon
295
- onClick={e => {
296
- e.stopPropagation();
297
- setEdit(true);
298
- }}
299
- icon={PencilIcon}
300
- />
301
- <ActionIcon
302
- onClick={() => {
303
- setRTMPStreams(streams => streams.filter(stream => stream.id !== rtmp.id));
304
- }}
305
- icon={TrashIcon}
306
- />
307
- </Flex>
308
- </Accordion.Header>
309
- );
310
- };
311
-
312
- const updateStream = ({ streams, id, key, value }) =>
313
- streams.map(stream => {
314
- if (stream.id === id) {
315
- return {
316
- ...stream,
317
- [key]: value,
318
- };
319
- }
320
- return stream;
321
- });
322
-
323
- export function getResolution(recordingResolution) {
324
- const resolution = {};
325
- if (recordingResolution.width) {
326
- resolution.width = recordingResolution.width;
327
- }
328
- if (recordingResolution.height) {
329
- resolution.height = recordingResolution.height;
330
- }
331
- if (Object.keys(resolution).length > 0) {
332
- return resolution;
333
- }
334
- }
@@ -1,76 +0,0 @@
1
- import React, { Fragment, useState } from 'react';
2
- import { selectPermissions, useHMSStore, useRecordingStreaming } from '@100mslive/react-sdk';
3
- import { ColoredHandIcon, CrossIcon, GoLiveIcon } from '@100mslive/react-icons';
4
- import { Box, Flex } from '../../../Layout';
5
- import { Text } from '../../../Text';
6
- import IconButton from '../../IconButton';
7
- import RTMPIcon from '../../images/rtmp.png';
8
- import { StreamCard } from './Common';
9
- import { HLSStreaming } from './HLSStreaming';
10
- import { RTMPStreaming } from './RTMPStreaming';
11
- import { useSidepaneToggle } from '../AppData/useSidepane';
12
- import { SIDE_PANE_OPTIONS } from '../../common/constants';
13
-
14
- export const StreamingLanding = () => {
15
- const toggleStreaming = useSidepaneToggle(SIDE_PANE_OPTIONS.STREAMING);
16
- const { isHLSRunning, isRTMPRunning } = useRecordingStreaming();
17
- const permissions = useHMSStore(selectPermissions);
18
- const [showHLS, setShowHLS] = useState(isHLSRunning);
19
- const [showRTMP, setShowRTMP] = useState(isRTMPRunning);
20
-
21
- if (!permissions?.hlsStreaming && !permissions?.rtmpStreaming) {
22
- toggleStreaming();
23
- return null;
24
- }
25
-
26
- return (
27
- <Fragment>
28
- <Flex css={{ w: '100%', py: '$8' }}>
29
- <Box
30
- css={{
31
- alignSelf: 'center',
32
- p: '$4',
33
- bg: '$surface_bright',
34
- r: '$round',
35
- }}
36
- >
37
- <ColoredHandIcon width={40} height={40} />
38
- </Box>
39
- <Box css={{ flex: '1 1 0', mx: '$8' }}>
40
- <Text variant="sm">Welcome !</Text>
41
- <Text variant="h6">Let’s get you started</Text>
42
- </Box>
43
- <IconButton onClick={toggleStreaming} css={{ alignSelf: 'flex-start' }} data-testid="close_streaming">
44
- <CrossIcon />
45
- </IconButton>
46
- </Flex>
47
- <Text variant="tiny" color="$on_surface_medium">
48
- Start Streaming
49
- </Text>
50
- {permissions?.hlsStreaming && (
51
- <StreamCard
52
- testId="hls_stream"
53
- title="Live Stream with HLS"
54
- subtitle="Stream to millions, edit and control what the viewer sees and more!"
55
- css={{ my: '$8' }}
56
- onClick={() => setShowHLS(true)}
57
- Icon={GoLiveIcon}
58
- />
59
- )}
60
- {permissions?.rtmpStreaming && (
61
- <StreamCard
62
- testId="rtmp_stream"
63
- title="Stream live to Facebook, Twitch, and others"
64
- subtitle="Stream to a specific destination directly from your app."
65
- css={{ my: '$8' }}
66
- onClick={() => {
67
- setShowRTMP(true);
68
- }}
69
- imgSrc={RTMPIcon}
70
- />
71
- )}
72
- {showHLS && <HLSStreaming onBack={() => setShowHLS(false)} />}
73
- {showRTMP && <RTMPStreaming onBack={() => setShowRTMP(false)} />}
74
- </Fragment>
75
- );
76
- };