@tellescope/video-chat 0.0.16 → 0.0.20

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.
Files changed (46) hide show
  1. package/lib/cjs/controls.d.ts +17 -2
  2. package/lib/cjs/controls.d.ts.map +1 -1
  3. package/lib/cjs/controls.js +42 -7
  4. package/lib/cjs/controls.js.map +1 -1
  5. package/lib/cjs/video.d.ts +4 -27
  6. package/lib/cjs/video.d.ts.map +1 -1
  7. package/lib/cjs/video.js +18 -14
  8. package/lib/cjs/video.js.map +1 -1
  9. package/lib/cjs/video.native.d.ts +3 -2
  10. package/lib/cjs/video.native.d.ts.map +1 -1
  11. package/lib/cjs/video.native.js +29 -21
  12. package/lib/cjs/video.native.js.map +1 -1
  13. package/lib/cjs/video_shared.d.ts +49 -0
  14. package/lib/cjs/video_shared.d.ts.map +1 -0
  15. package/lib/cjs/video_shared.js +9 -0
  16. package/lib/cjs/video_shared.js.map +1 -0
  17. package/lib/esm/controls.d.ts +17 -2
  18. package/lib/esm/controls.d.ts.map +1 -1
  19. package/lib/esm/controls.js +42 -10
  20. package/lib/esm/controls.js.map +1 -1
  21. package/lib/esm/shared.d.ts +1 -0
  22. package/lib/esm/shared.d.ts.map +1 -0
  23. package/lib/esm/shared.js +2 -0
  24. package/lib/esm/shared.js.map +1 -0
  25. package/lib/esm/video.d.ts +4 -27
  26. package/lib/esm/video.d.ts.map +1 -1
  27. package/lib/esm/video.js +15 -11
  28. package/lib/esm/video.js.map +1 -1
  29. package/lib/esm/video.native.d.ts +3 -2
  30. package/lib/esm/video.native.d.ts.map +1 -1
  31. package/lib/esm/video.native.js +26 -17
  32. package/lib/esm/video.native.js.map +1 -1
  33. package/lib/esm/video_shared.d.ts +49 -0
  34. package/lib/esm/video_shared.d.ts.map +1 -0
  35. package/lib/esm/video_shared.js +3 -0
  36. package/lib/esm/video_shared.js.map +1 -0
  37. package/lib/tsconfig.tsbuildinfo +1 -1
  38. package/package.json +9 -9
  39. package/src/controls.tsx +58 -7
  40. package/src/video.native.tsx +14 -11
  41. package/src/video.tsx +18 -25
  42. package/src/video_shared.tsx +48 -0
  43. package/lib/esm/components.d.ts +0 -1
  44. package/lib/esm/components.d.ts.map +0 -1
  45. package/lib/esm/components.js +0 -3
  46. package/lib/esm/components.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tellescope/video-chat",
3
- "version": "0.0.16",
3
+ "version": "0.0.20",
4
4
  "description": "",
5
5
  "main": "./lib/cjs/index.js",
6
6
  "module": "./lib/esm/index.js",
@@ -33,13 +33,13 @@
33
33
  "@fontsource/roboto": "^4.5.1",
34
34
  "@mui/icons-material": "^5.0.1",
35
35
  "@mui/material": "^5.0.2",
36
- "@tellescope/constants": "^0.0.16",
37
- "@tellescope/react-components": "^0.0.16",
38
- "@tellescope/sdk": "^0.0.16",
39
- "@tellescope/types-client": "^0.0.16",
40
- "@tellescope/types-models": "^0.0.16",
41
- "@tellescope/types-utilities": "^0.0.16",
42
- "@tellescope/utilities": "^0.0.16",
36
+ "@tellescope/constants": "^0.0.20",
37
+ "@tellescope/react-components": "^0.0.20",
38
+ "@tellescope/sdk": "^0.0.20",
39
+ "@tellescope/types-client": "^0.0.20",
40
+ "@tellescope/types-models": "^0.0.20",
41
+ "@tellescope/types-utilities": "^0.0.20",
42
+ "@tellescope/utilities": "^0.0.20",
43
43
  "@typescript-eslint/eslint-plugin": "^4.33.0",
44
44
  "@typescript-eslint/parser": "^4.33.0",
45
45
  "amazon-chime-sdk-component-library-react": "^2.12.0",
@@ -54,7 +54,7 @@
54
54
  "react": "^17.0.2",
55
55
  "react-dom": "^17.0.2"
56
56
  },
57
- "gitHead": "06e581f4d3a6c5b57fd0cfcc22103b94125f9da4",
57
+ "gitHead": "99ef9475f430b7021166b8f47f9863c2e1fed8aa",
58
58
  "publishConfig": {
59
59
  "access": "public"
60
60
  }
package/src/controls.tsx CHANGED
@@ -6,28 +6,79 @@ import {
6
6
  VideoOffIcon,
7
7
  MicrophoneIcon,
8
8
  MicrophoneOffIcon,
9
+ CallEndIcon,
10
+
11
+ Paper,
12
+
13
+ Styled,
9
14
  } from "@tellescope/react-components/lib/esm/mui"
10
15
  import { LabeledIconButton } from "@tellescope/react-components/lib/esm/controls"
11
- import {
12
- CurrentCallContext,
13
- } from "./video"
16
+ import { Flex } from "@tellescope/react-components/lib/esm/layout"
17
+ import { CurrentCallContext } from "./video_shared"
18
+ import { useStartVideoCall } from "./video"
14
19
 
15
- export const VideoToggle = () => {
20
+ const DEFAULT_BUTTON_SIZE = 30
21
+ interface ButtonProps {
22
+ size?: number,
23
+ }
24
+ export const VideoToggle = ({ size=DEFAULT_BUTTON_SIZE } : ButtonProps) => {
16
25
  const { toggleVideo, videoIsEnabled } = React.useContext(CurrentCallContext)
17
26
 
18
27
  return (
19
- <LabeledIconButton Icon={videoIsEnabled ? VideoIcon : VideoOffIcon} onClick={toggleVideo}
28
+ <LabeledIconButton size={size} Icon={videoIsEnabled ? VideoIcon : VideoOffIcon} onClick={toggleVideo}
20
29
  label={videoIsEnabled ? "Turn Camera Off" : "Turn Camera On"}
21
30
  />
22
31
  )
23
32
  }
24
33
 
25
- export const MicrophoneToggle = () => {
34
+ export const MicrophoneToggle = ({ size=DEFAULT_BUTTON_SIZE }: ButtonProps) => {
26
35
  const { microphoneIsEnabled, toggleMicrophone } = React.useContext(CurrentCallContext)
27
36
 
28
37
  return (
29
- <LabeledIconButton Icon={microphoneIsEnabled ? MicrophoneIcon : MicrophoneOffIcon} onClick={toggleMicrophone}
38
+ <LabeledIconButton size={size} Icon={microphoneIsEnabled ? MicrophoneIcon : MicrophoneOffIcon} onClick={toggleMicrophone}
30
39
  label={microphoneIsEnabled ? "Turn Microphone Off" : "Turn Microphone On"}
31
40
  />
32
41
  )
42
+ }
43
+
44
+ // ends meeting if host, otherwise leaves meeting
45
+ export const EndMeeting = ({ size=DEFAULT_BUTTON_SIZE }: ButtonProps) => {
46
+ const { endMeeting } = useStartVideoCall()
47
+
48
+ return (
49
+ <LabeledIconButton size={size} Icon={CallEndIcon} onClick={endMeeting} label="End Meeting"/>
50
+ )
51
+ }
52
+
53
+ interface LeaveMeetingProps {
54
+ onLeave?: () => void,
55
+ }
56
+ export const LeaveMeeting = ({ onLeave, size=DEFAULT_BUTTON_SIZE } : LeaveMeetingProps & ButtonProps) => (
57
+ <LabeledIconButton size={size} Icon={CallEndIcon} onClick={onLeave} label="Leave Meeting"/>
58
+ )
59
+
60
+ interface ControlbarProps {
61
+ spacing?: number,
62
+ size?: number,
63
+
64
+ }
65
+ export const ControlBar = ({ onLeave, style, spacing=15, size } : ControlbarProps & LeaveMeetingProps & Styled) => {
66
+ const { isHost } = React.useContext(CurrentCallContext)
67
+ const itemStyle = { marginLeft: spacing, marginRight: spacing }
68
+
69
+ return (
70
+ <Flex flex={1} alignItems="center" justifyContent="center" style={style}>
71
+ <Paper elevation={5} style={{ display: 'flex', flexDirection: 'row', padding: spacing }}>
72
+ <Flex style={itemStyle}>
73
+ <VideoToggle size={size}/>
74
+ </Flex>
75
+ <Flex style={itemStyle}>
76
+ <MicrophoneToggle size={size}/>
77
+ </Flex>
78
+ <Flex style={itemStyle}>
79
+ {isHost ? <EndMeeting size={size}/> : <LeaveMeeting size={size} onLeave={onLeave}/>}
80
+ </Flex>
81
+ </Paper>
82
+ </Flex>
83
+ )
33
84
  }
@@ -20,12 +20,7 @@ import { Flex } from "@tellescope/react-components/lib/esm/layout"
20
20
  import {
21
21
  Button,
22
22
  Typography,
23
- convert_CSS_to_RNStyles,
24
-
25
- VideoIcon,
26
- VideoOffIcon,
27
- MicrophoneIcon,
28
- MicrophoneOffIcon,
23
+ convert_CSS_to_RNStyles, // requires mui.native
29
24
  } from "@tellescope/react-components/lib/esm/mui.native"
30
25
 
31
26
  import {
@@ -35,7 +30,7 @@ import {
35
30
  VideoProps,
36
31
  AttendeeDisplayInfo,
37
32
  VideoViewProps,
38
- } from "./video.js"
33
+ } from "./video_shared"
39
34
 
40
35
  import {
41
36
  getSDKEventEmitter,
@@ -44,6 +39,8 @@ import {
44
39
  } from "./native/bridge"
45
40
  import { RNVideoView } from "./native/RNVideoRenderView"
46
41
 
42
+ export { CurrentCallContext }
43
+
47
44
  interface TileState {
48
45
  isLocal: boolean,
49
46
  isScreenShare: boolean,
@@ -52,6 +49,7 @@ interface TileState {
52
49
 
53
50
  export const WithVideo = ({ children } : VideoProps) => {
54
51
  const [meeting, setMeeting] = useState(undefined as MeetingInfo | undefined)
52
+ const [isHost, setIsHost] = useState(false)
55
53
 
56
54
  const [inMeeting, setInMeeting] = useState(false)
57
55
  const [isLoading, setIsLoading] = useState(false)
@@ -64,6 +62,9 @@ export const WithVideo = ({ children } : VideoProps) => {
64
62
 
65
63
  const toggleVideo = async () => {
66
64
  NativeFunction.setCameraOn(!videoIsEnabled)
65
+ if (videoIsEnabled) {
66
+ setLocalTileId(null)
67
+ }
67
68
  setVideoIsEnabled(v => !v)
68
69
  }
69
70
  const toggleMic = async () => {
@@ -145,6 +146,7 @@ export const WithVideo = ({ children } : VideoProps) => {
145
146
 
146
147
  return (
147
148
  <CurrentCallContext.Provider value={{
149
+ isHost, setIsHost,
148
150
  attendees,
149
151
  localTileId,
150
152
  videoTiles,
@@ -162,18 +164,18 @@ export const WithVideo = ({ children } : VideoProps) => {
162
164
  }
163
165
 
164
166
 
165
- export const useRemoteViews = ({ style } : { style: React.CSSProperties }) => {
167
+ export const useRemoteViews = (props={} as { style: React.CSSProperties }) => {
166
168
  const { localTileId, videoTiles } = React.useContext(CurrentCallContext)
167
169
  const nonLocal = videoTiles.filter(v => v !== localTileId)
168
170
 
169
171
  return nonLocal.map(tileId =>
170
- <RNVideoView style={convert_CSS_to_RNStyles(style) ?? styles.video} tileId={tileId} />
172
+ <RNVideoView key={tileId} style={convert_CSS_to_RNStyles(props.style) ?? styles.video} tileId={tileId} />
171
173
  )
172
174
  }
173
175
 
174
176
  export const SelfView = ({ style } : VideoViewProps) => {
175
177
  const { localTileId } = React.useContext(CurrentCallContext)
176
- if (!localTileId) return null
178
+ if (localTileId === null) return null // localTileId may be zero, don't return null on simple falsey check
177
179
 
178
180
  return (
179
181
  <RNVideoView style={convert_CSS_to_RNStyles(style) ?? styles.video} tileId={localTileId}/>
@@ -182,7 +184,7 @@ export const SelfView = ({ style } : VideoViewProps) => {
182
184
 
183
185
  export const useStartVideoCall = (): StartVideoCallReturnType => {
184
186
  const session = useSession()
185
- const { meeting, setMeeting, videoIsEnabled, toggleVideo } = React.useContext(CurrentCallContext)
187
+ const { meeting, setMeeting, setIsHost, videoIsEnabled, toggleVideo } = React.useContext(CurrentCallContext)
186
188
 
187
189
  const [starting, setStarting] = useState(false)
188
190
  const [ending, setEnding] = useState(false)
@@ -198,6 +200,7 @@ export const useStartVideoCall = (): StartVideoCallReturnType => {
198
200
  NativeFunction.startMeeting(meeting.Meeting, host.Attendee)
199
201
 
200
202
  setMeeting(meeting.Meeting)
203
+ setIsHost(true)
201
204
  } catch(err) {
202
205
  console.error(err)
203
206
  }
package/src/video.tsx CHANGED
@@ -35,24 +35,18 @@ import {
35
35
  // useRemoteVideoTileState,
36
36
  // useContentShareControls, // screen sharing
37
37
  } from 'amazon-chime-sdk-component-library-react';
38
- import { } from "../../../types-client/node_modules/@tellescope/types-models/src"
39
-
40
- export type AttendeeDisplayInfo = { attendeeId: string, externalUserId: string }
41
-
42
- export const CurrentCallContext = React.createContext({} as {
43
- meeting: MeetingInfo | undefined, setMeeting: (m: MeetingInfo | undefined) => void,
44
- videoIsEnabled: boolean, toggleVideo: () => Promise<void>,
45
- microphoneIsEnabled: boolean, toggleMicrophone: () => Promise<void>,
46
- attendees: AttendeeDisplayInfo[], shareScreenId: number | null,
47
- localTileId: number | null,
48
- videoTiles: (number)[],
49
- })
50
- export interface VideoProps {
51
- children?: React.ReactNode,
52
- theme?: typeof darkTheme,
53
- }
38
+
39
+ import {
40
+ CurrentCallContext,
41
+
42
+ AttendeeDisplayInfo,
43
+ VideoProps,
44
+ VideoViewProps,
45
+ } from "./video_shared"
46
+
54
47
  const WithContext = ({ children } : { children: React.ReactNode }) => {
55
48
  const [meeting, setMeeting] = useState(undefined as MeetingInfo | undefined)
49
+ const [isHost, setIsHost] = useState(false)
56
50
  const { toggleVideo, isVideoEnabled: videoIsEnabled, tileId: localTileId } = useLocalVideo();
57
51
  const { roster } = useRosterState()
58
52
  const { tileId } = useContentShareState()
@@ -67,6 +61,7 @@ const WithContext = ({ children } : { children: React.ReactNode }) => {
67
61
 
68
62
  return (
69
63
  <CurrentCallContext.Provider value={{
64
+ isHost, setIsHost,
70
65
  attendees,
71
66
  localTileId,
72
67
  videoTiles: tiles,
@@ -82,8 +77,8 @@ const WithContext = ({ children } : { children: React.ReactNode }) => {
82
77
  </CurrentCallContext.Provider>
83
78
  )
84
79
  }
85
- export const WithVideo = ({ children, theme=darkTheme }: VideoProps) => (
86
- <ThemeProvider theme={theme}>
80
+ export const WithVideo = ({ children }: VideoProps) => (
81
+ <ThemeProvider theme={darkTheme}>
87
82
  <MeetingProvider>
88
83
  <WithContext>
89
84
  {children}
@@ -95,9 +90,9 @@ export const WithVideo = ({ children, theme=darkTheme }: VideoProps) => (
95
90
  export const useStartVideoCall = () => {
96
91
  const [starting, setStarting] = useState(false)
97
92
  const [ending, setEnding] = useState(false)
98
- const { meeting, setMeeting, toggleVideo, videoIsEnabled } = React.useContext(CurrentCallContext)
93
+ const { meeting, setMeeting, toggleVideo, videoIsEnabled, setIsHost } = React.useContext(CurrentCallContext)
99
94
 
100
- const session = useSession()
95
+ const session = useSession() // meetings can only be started by users, not endusers (for now)
101
96
  const meetingManager = useMeetingManager();
102
97
 
103
98
  const createAndStartMeeting = async (initialAttendees?: UserIdentity[]) => {
@@ -114,6 +109,7 @@ export const useStartVideoCall = () => {
114
109
  }
115
110
 
116
111
  setMeeting(meeting.Meeting)
112
+ setIsHost(true)
117
113
  } catch(err) {
118
114
  console.error(err)
119
115
  }
@@ -157,17 +153,14 @@ export const useJoinVideoCall = () => {
157
153
  }
158
154
  export type JoinVideoCallReturnType = ReturnType<typeof useJoinVideoCall>
159
155
 
160
- export interface VideoViewProps {
161
- style?: CSSProperties,
162
- }
163
156
  export const SelfView = ({ style }: VideoViewProps) => <div style={style}><LocalVideo/></div>
164
157
 
165
- export const useRemoteViews = ({ style } : VideoViewProps) => {
158
+ export const useRemoteViews = (props={} as VideoViewProps) => {
166
159
  const { localTileId, videoTiles } = React.useContext(CurrentCallContext)
167
160
  const nonLocal = videoTiles.filter(v => v !== localTileId)
168
161
 
169
162
  return nonLocal.map(tileId =>
170
- <RemoteVideo style={style} tileId={tileId} />
163
+ <RemoteVideo key={tileId} style={props.style} tileId={tileId} />
171
164
  )
172
165
  }
173
166
 
@@ -0,0 +1,48 @@
1
+ import React, { CSSProperties } from "react"
2
+
3
+ import {
4
+ AttendeeInfo,
5
+ MeetingInfo,
6
+ } from '@tellescope/types-models'
7
+
8
+ import {
9
+ UserIdentity,
10
+ } from '@tellescope/types-utilities'
11
+
12
+ export type AttendeeDisplayInfo = { attendeeId: string, externalUserId: string }
13
+ export interface CallContext {
14
+ meeting: MeetingInfo | undefined, setMeeting: (m: MeetingInfo | undefined) => void,
15
+ videoIsEnabled: boolean, toggleVideo: () => Promise<void>,
16
+ microphoneIsEnabled: boolean, toggleMicrophone: () => Promise<void>,
17
+ attendees: AttendeeDisplayInfo[], shareScreenId: number | null,
18
+ localTileId: number | null,
19
+ isHost: boolean, setIsHost: (b: boolean) => void;
20
+ videoTiles: (number)[],
21
+ }
22
+
23
+ export const CurrentCallContext = React.createContext({} as CallContext)
24
+ export interface VideoProps {
25
+ children?: React.ReactNode,
26
+ }
27
+
28
+ export interface VideoViewProps {
29
+ style?: CSSProperties,
30
+ }
31
+
32
+ export interface JoinVideoCallReturnType {
33
+ meeting: CallContext['meeting'],
34
+ videoIsEnabled: CallContext['videoIsEnabled'],
35
+ toggleVideo: CallContext['toggleVideo'],
36
+ joinMeeting: (meetingInfo: { Meeting: MeetingInfo }, attendeeInfo: { Attendee: AttendeeInfo }) => Promise<void>,
37
+ }
38
+
39
+ export interface StartVideoCallReturnType {
40
+ starting: boolean,
41
+ ending: boolean,
42
+ meeting: CallContext['meeting'],
43
+ videoIsEnabled: CallContext['videoIsEnabled'],
44
+ toggleVideo: CallContext['toggleVideo'],
45
+ createAndStartMeeting: (initialAttendees?: UserIdentity[]) => Promise<void>,
46
+ addAttendees: (attendees: UserIdentity[]) => Promise<void>,
47
+ endMeeting: () => Promise<void>,
48
+ }
@@ -1 +0,0 @@
1
- //# sourceMappingURL=components.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/components.tsx"],"names":[],"mappings":""}
@@ -1,3 +0,0 @@
1
- "use strict";
2
- // components that work with web or native
3
- //# sourceMappingURL=components.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"components.js","sourceRoot":"","sources":["../../src/components.tsx"],"names":[],"mappings":";AAAA,0CAA0C"}