@werxt/livekit-components-react 2.9.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.
- package/LICENSE +201 -0
- package/README.md +36 -0
- package/dist/assets/icons/CameraDisabledIcon.d.ts +11 -0
- package/dist/assets/icons/CameraDisabledIcon.d.ts.map +1 -0
- package/dist/assets/icons/CameraIcon.d.ts +11 -0
- package/dist/assets/icons/CameraIcon.d.ts.map +1 -0
- package/dist/assets/icons/ChatCloseIcon.d.ts +11 -0
- package/dist/assets/icons/ChatCloseIcon.d.ts.map +1 -0
- package/dist/assets/icons/ChatIcon.d.ts +11 -0
- package/dist/assets/icons/ChatIcon.d.ts.map +1 -0
- package/dist/assets/icons/Chevron.d.ts +11 -0
- package/dist/assets/icons/Chevron.d.ts.map +1 -0
- package/dist/assets/icons/FocusToggleIcon.d.ts +11 -0
- package/dist/assets/icons/FocusToggleIcon.d.ts.map +1 -0
- package/dist/assets/icons/GearIcon.d.ts +11 -0
- package/dist/assets/icons/GearIcon.d.ts.map +1 -0
- package/dist/assets/icons/LeaveIcon.d.ts +11 -0
- package/dist/assets/icons/LeaveIcon.d.ts.map +1 -0
- package/dist/assets/icons/LockLockedIcon.d.ts +11 -0
- package/dist/assets/icons/LockLockedIcon.d.ts.map +1 -0
- package/dist/assets/icons/MicDisabledIcon.d.ts +11 -0
- package/dist/assets/icons/MicDisabledIcon.d.ts.map +1 -0
- package/dist/assets/icons/MicIcon.d.ts +11 -0
- package/dist/assets/icons/MicIcon.d.ts.map +1 -0
- package/dist/assets/icons/QualityExcellentIcon.d.ts +11 -0
- package/dist/assets/icons/QualityExcellentIcon.d.ts.map +1 -0
- package/dist/assets/icons/QualityGoodIcon.d.ts +11 -0
- package/dist/assets/icons/QualityGoodIcon.d.ts.map +1 -0
- package/dist/assets/icons/QualityPoorIcon.d.ts +11 -0
- package/dist/assets/icons/QualityPoorIcon.d.ts.map +1 -0
- package/dist/assets/icons/QualityUnknownIcon.d.ts +11 -0
- package/dist/assets/icons/QualityUnknownIcon.d.ts.map +1 -0
- package/dist/assets/icons/ScreenShareIcon.d.ts +11 -0
- package/dist/assets/icons/ScreenShareIcon.d.ts.map +1 -0
- package/dist/assets/icons/ScreenShareStopIcon.d.ts +11 -0
- package/dist/assets/icons/ScreenShareStopIcon.d.ts.map +1 -0
- package/dist/assets/icons/SpinnerIcon.d.ts +11 -0
- package/dist/assets/icons/SpinnerIcon.d.ts.map +1 -0
- package/dist/assets/icons/UnfocusToggleIcon.d.ts +11 -0
- package/dist/assets/icons/UnfocusToggleIcon.d.ts.map +1 -0
- package/dist/assets/icons/index.d.ts +20 -0
- package/dist/assets/icons/index.d.ts.map +1 -0
- package/dist/assets/icons/util.d.ts +11 -0
- package/dist/assets/icons/util.d.ts.map +1 -0
- package/dist/assets/images/ParticipantPlaceholder.d.ts +11 -0
- package/dist/assets/images/ParticipantPlaceholder.d.ts.map +1 -0
- package/dist/assets/images/index.d.ts +2 -0
- package/dist/assets/images/index.d.ts.map +1 -0
- package/dist/components/ChatEntry.d.ts +35 -0
- package/dist/components/ChatEntry.d.ts.map +1 -0
- package/dist/components/ConnectionState.d.ts +23 -0
- package/dist/components/ConnectionState.d.ts.map +1 -0
- package/dist/components/ConnectionStateToast.d.ts +13 -0
- package/dist/components/ConnectionStateToast.d.ts.map +1 -0
- package/dist/components/LiveKitRoom.d.ts +92 -0
- package/dist/components/LiveKitRoom.d.ts.map +1 -0
- package/dist/components/ParticipantLoop.d.ts +28 -0
- package/dist/components/ParticipantLoop.d.ts.map +1 -0
- package/dist/components/RoomAudioRenderer.d.ts +29 -0
- package/dist/components/RoomAudioRenderer.d.ts.map +1 -0
- package/dist/components/RoomName.d.ts +20 -0
- package/dist/components/RoomName.d.ts.map +1 -0
- package/dist/components/SessionProvider.d.ts +13 -0
- package/dist/components/SessionProvider.d.ts.map +1 -0
- package/dist/components/Toast.d.ts +14 -0
- package/dist/components/Toast.d.ts.map +1 -0
- package/dist/components/TrackLoop.d.ts +26 -0
- package/dist/components/TrackLoop.d.ts.map +1 -0
- package/dist/components/controls/ChatToggle.d.ts +19 -0
- package/dist/components/controls/ChatToggle.d.ts.map +1 -0
- package/dist/components/controls/ClearPinButton.d.ts +20 -0
- package/dist/components/controls/ClearPinButton.d.ts.map +1 -0
- package/dist/components/controls/DisconnectButton.d.ts +19 -0
- package/dist/components/controls/DisconnectButton.d.ts.map +1 -0
- package/dist/components/controls/FocusToggle.d.ts +21 -0
- package/dist/components/controls/FocusToggle.d.ts.map +1 -0
- package/dist/components/controls/MediaDeviceSelect.d.ts +40 -0
- package/dist/components/controls/MediaDeviceSelect.d.ts.map +1 -0
- package/dist/components/controls/PaginationControl.d.ts +9 -0
- package/dist/components/controls/PaginationControl.d.ts.map +1 -0
- package/dist/components/controls/PaginationIndicator.d.ts +7 -0
- package/dist/components/controls/PaginationIndicator.d.ts.map +1 -0
- package/dist/components/controls/SettingsMenuToggle.d.ts +13 -0
- package/dist/components/controls/SettingsMenuToggle.d.ts.map +1 -0
- package/dist/components/controls/StartAudio.d.ts +24 -0
- package/dist/components/controls/StartAudio.d.ts.map +1 -0
- package/dist/components/controls/StartMediaButton.d.ts +22 -0
- package/dist/components/controls/StartMediaButton.d.ts.map +1 -0
- package/dist/components/controls/TrackToggle.d.ts +32 -0
- package/dist/components/controls/TrackToggle.d.ts.map +1 -0
- package/dist/components/index.d.ts +30 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/layout/CarouselLayout.d.ts +27 -0
- package/dist/components/layout/CarouselLayout.d.ts.map +1 -0
- package/dist/components/layout/FocusLayout.d.ts +25 -0
- package/dist/components/layout/FocusLayout.d.ts.map +1 -0
- package/dist/components/layout/GridLayout.d.ts +26 -0
- package/dist/components/layout/GridLayout.d.ts.map +1 -0
- package/dist/components/layout/LayoutContextProvider.d.ts +12 -0
- package/dist/components/layout/LayoutContextProvider.d.ts.map +1 -0
- package/dist/components/layout/index.d.ts +4 -0
- package/dist/components/layout/index.d.ts.map +1 -0
- package/dist/components/participant/AudioTrack.d.ts +33 -0
- package/dist/components/participant/AudioTrack.d.ts.map +1 -0
- package/dist/components/participant/AudioVisualizer.d.ts +22 -0
- package/dist/components/participant/AudioVisualizer.d.ts.map +1 -0
- package/dist/components/participant/BarVisualizer.d.ts +77 -0
- package/dist/components/participant/BarVisualizer.d.ts.map +1 -0
- package/dist/components/participant/ConnectionQualityIndicator.d.ts +16 -0
- package/dist/components/participant/ConnectionQualityIndicator.d.ts.map +1 -0
- package/dist/components/participant/ParticipantAudioTile.d.ts +14 -0
- package/dist/components/participant/ParticipantAudioTile.d.ts.map +1 -0
- package/dist/components/participant/ParticipantName.d.ts +17 -0
- package/dist/components/participant/ParticipantName.d.ts.map +1 -0
- package/dist/components/participant/ParticipantTile.d.ts +49 -0
- package/dist/components/participant/ParticipantTile.d.ts.map +1 -0
- package/dist/components/participant/TrackMutedIndicator.d.ts +19 -0
- package/dist/components/participant/TrackMutedIndicator.d.ts.map +1 -0
- package/dist/components/participant/VideoTrack.d.ts +23 -0
- package/dist/components/participant/VideoTrack.d.ts.map +1 -0
- package/dist/components/participant/animationSequences/connectingSequence.d.ts +2 -0
- package/dist/components/participant/animationSequences/connectingSequence.d.ts.map +1 -0
- package/dist/components/participant/animationSequences/listeningSequence.d.ts +2 -0
- package/dist/components/participant/animationSequences/listeningSequence.d.ts.map +1 -0
- package/dist/components/participant/animationSequences/thinkingSequence.d.ts +2 -0
- package/dist/components/participant/animationSequences/thinkingSequence.d.ts.map +1 -0
- package/dist/components/participant/animators/useBarAnimator.d.ts +3 -0
- package/dist/components/participant/animators/useBarAnimator.d.ts.map +1 -0
- package/dist/components-lNrIMTWQ.mjs +1051 -0
- package/dist/components-lNrIMTWQ.mjs.map +1 -0
- package/dist/context/chat-context.d.ts +23 -0
- package/dist/context/chat-context.d.ts.map +1 -0
- package/dist/context/feature-context.d.ts +14 -0
- package/dist/context/feature-context.d.ts.map +1 -0
- package/dist/context/index.d.ts +10 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/layout-context.d.ts +32 -0
- package/dist/context/layout-context.d.ts.map +1 -0
- package/dist/context/participant-context.d.ts +22 -0
- package/dist/context/participant-context.d.ts.map +1 -0
- package/dist/context/pin-context.d.ts +17 -0
- package/dist/context/pin-context.d.ts.map +1 -0
- package/dist/context/room-context.d.ts +22 -0
- package/dist/context/room-context.d.ts.map +1 -0
- package/dist/context/session-context.d.ts +22 -0
- package/dist/context/session-context.d.ts.map +1 -0
- package/dist/context/track-reference-context.d.ts +25 -0
- package/dist/context/track-reference-context.d.ts.map +1 -0
- package/dist/contexts-D4V9wQRc.mjs +4026 -0
- package/dist/contexts-D4V9wQRc.mjs.map +1 -0
- package/dist/hooks/cloud/krisp/useKrispNoiseFilter.d.ts +42 -0
- package/dist/hooks/cloud/krisp/useKrispNoiseFilter.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +54 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/internal/index.d.ts +10 -0
- package/dist/hooks/internal/index.d.ts.map +1 -0
- package/dist/hooks/internal/useMediaQuery.d.ts +7 -0
- package/dist/hooks/internal/useMediaQuery.d.ts.map +1 -0
- package/dist/hooks/internal/useObservableState.d.ts +6 -0
- package/dist/hooks/internal/useObservableState.d.ts.map +1 -0
- package/dist/hooks/internal/useResizeObserver.d.ts +14 -0
- package/dist/hooks/internal/useResizeObserver.d.ts.map +1 -0
- package/dist/hooks/useAgent.d.ts +219 -0
- package/dist/hooks/useAgent.d.ts.map +1 -0
- package/dist/hooks/useAudioPlayback.d.ts +15 -0
- package/dist/hooks/useAudioPlayback.d.ts.map +1 -0
- package/dist/hooks/useChat.d.ts +43 -0
- package/dist/hooks/useChat.d.ts.map +1 -0
- package/dist/hooks/useChatToggle.d.ts +21 -0
- package/dist/hooks/useChatToggle.d.ts.map +1 -0
- package/dist/hooks/useClearPinButton.d.ts +15 -0
- package/dist/hooks/useClearPinButton.d.ts.map +1 -0
- package/dist/hooks/useConnectionQualityIndicator.d.ts +20 -0
- package/dist/hooks/useConnectionQualityIndicator.d.ts.map +1 -0
- package/dist/hooks/useConnectionStatus.d.ts +12 -0
- package/dist/hooks/useConnectionStatus.d.ts.map +1 -0
- package/dist/hooks/useDataChannel.d.ts +38 -0
- package/dist/hooks/useDataChannel.d.ts.map +1 -0
- package/dist/hooks/useDisconnectButton.d.ts +21 -0
- package/dist/hooks/useDisconnectButton.d.ts.map +1 -0
- package/dist/hooks/useEvents.d.ts +9 -0
- package/dist/hooks/useEvents.d.ts.map +1 -0
- package/dist/hooks/useFacingMode.d.ts +10 -0
- package/dist/hooks/useFacingMode.d.ts.map +1 -0
- package/dist/hooks/useFocusToggle.d.ts +26 -0
- package/dist/hooks/useFocusToggle.d.ts.map +1 -0
- package/dist/hooks/useGridLayout.d.ts +27 -0
- package/dist/hooks/useGridLayout.d.ts.map +1 -0
- package/dist/hooks/useIsEncrypted.d.ts +12 -0
- package/dist/hooks/useIsEncrypted.d.ts.map +1 -0
- package/dist/hooks/useIsMuted.d.ts +22 -0
- package/dist/hooks/useIsMuted.d.ts.map +1 -0
- package/dist/hooks/useIsRecording.d.ts +11 -0
- package/dist/hooks/useIsRecording.d.ts.map +1 -0
- package/dist/hooks/useIsSpeaking.d.ts +11 -0
- package/dist/hooks/useIsSpeaking.d.ts.map +1 -0
- package/dist/hooks/useLiveKitRoom.d.ts +19 -0
- package/dist/hooks/useLiveKitRoom.d.ts.map +1 -0
- package/dist/hooks/useLocalParticipant.d.ts +29 -0
- package/dist/hooks/useLocalParticipant.d.ts.map +1 -0
- package/dist/hooks/useLocalParticipantPermissions.d.ts +12 -0
- package/dist/hooks/useLocalParticipantPermissions.d.ts.map +1 -0
- package/dist/hooks/useMediaDeviceSelect.d.ts +41 -0
- package/dist/hooks/useMediaDeviceSelect.d.ts.map +1 -0
- package/dist/hooks/useMediaDevices.d.ts +15 -0
- package/dist/hooks/useMediaDevices.d.ts.map +1 -0
- package/dist/hooks/useMediaTrackBySourceOrName.d.ts +18 -0
- package/dist/hooks/useMediaTrackBySourceOrName.d.ts.map +1 -0
- package/dist/hooks/usePagination.d.ts +24 -0
- package/dist/hooks/usePagination.d.ts.map +1 -0
- package/dist/hooks/useParticipantAttributes.d.ts +30 -0
- package/dist/hooks/useParticipantAttributes.d.ts.map +1 -0
- package/dist/hooks/useParticipantInfo.d.ts +21 -0
- package/dist/hooks/useParticipantInfo.d.ts.map +1 -0
- package/dist/hooks/useParticipantPermissions.d.ts +17 -0
- package/dist/hooks/useParticipantPermissions.d.ts.map +1 -0
- package/dist/hooks/useParticipantTile.d.ts +22 -0
- package/dist/hooks/useParticipantTile.d.ts.map +1 -0
- package/dist/hooks/useParticipantTracks.d.ts +14 -0
- package/dist/hooks/useParticipantTracks.d.ts.map +1 -0
- package/dist/hooks/useParticipants.d.ts +30 -0
- package/dist/hooks/useParticipants.d.ts.map +1 -0
- package/dist/hooks/usePersistentUserChoices.d.ts +35 -0
- package/dist/hooks/usePersistentUserChoices.d.ts.map +1 -0
- package/dist/hooks/usePinnedTracks.d.ts +14 -0
- package/dist/hooks/usePinnedTracks.d.ts.map +1 -0
- package/dist/hooks/useRemoteParticipant.d.ts +35 -0
- package/dist/hooks/useRemoteParticipant.d.ts.map +1 -0
- package/dist/hooks/useRemoteParticipants.d.ts +30 -0
- package/dist/hooks/useRemoteParticipants.d.ts.map +1 -0
- package/dist/hooks/useRoomInfo.d.ts +21 -0
- package/dist/hooks/useRoomInfo.d.ts.map +1 -0
- package/dist/hooks/useSequentialRoomConnectDisconnect.d.ts +27 -0
- package/dist/hooks/useSequentialRoomConnectDisconnect.d.ts.map +1 -0
- package/dist/hooks/useSession.d.ts +130 -0
- package/dist/hooks/useSession.d.ts.map +1 -0
- package/dist/hooks/useSessionMessages.d.ts +29 -0
- package/dist/hooks/useSessionMessages.d.ts.map +1 -0
- package/dist/hooks/useSettingsToggle.d.ts +20 -0
- package/dist/hooks/useSettingsToggle.d.ts.map +1 -0
- package/dist/hooks/useSortedParticipants.d.ts +7 -0
- package/dist/hooks/useSortedParticipants.d.ts.map +1 -0
- package/dist/hooks/useSpeakingParticipants.d.ts +16 -0
- package/dist/hooks/useSpeakingParticipants.d.ts.map +1 -0
- package/dist/hooks/useStartAudio.d.ts +27 -0
- package/dist/hooks/useStartAudio.d.ts.map +1 -0
- package/dist/hooks/useStartVideo.d.ts +26 -0
- package/dist/hooks/useStartVideo.d.ts.map +1 -0
- package/dist/hooks/useSwipe.d.ts +24 -0
- package/dist/hooks/useSwipe.d.ts.map +1 -0
- package/dist/hooks/useTextStream.d.ts +20 -0
- package/dist/hooks/useTextStream.d.ts.map +1 -0
- package/dist/hooks/useToken.d.ts +20 -0
- package/dist/hooks/useToken.d.ts.map +1 -0
- package/dist/hooks/useTrack.d.ts +4 -0
- package/dist/hooks/useTrack.d.ts.map +1 -0
- package/dist/hooks/useTrackByName.d.ts +10 -0
- package/dist/hooks/useTrackByName.d.ts.map +1 -0
- package/dist/hooks/useTrackMutedIndicator.d.ts +18 -0
- package/dist/hooks/useTrackMutedIndicator.d.ts.map +1 -0
- package/dist/hooks/useTrackRefBySourceOrName.d.ts +7 -0
- package/dist/hooks/useTrackRefBySourceOrName.d.ts.map +1 -0
- package/dist/hooks/useTrackSyncTime.d.ts +10 -0
- package/dist/hooks/useTrackSyncTime.d.ts.map +1 -0
- package/dist/hooks/useTrackToggle.d.ts +27 -0
- package/dist/hooks/useTrackToggle.d.ts.map +1 -0
- package/dist/hooks/useTrackTranscription.d.ts +26 -0
- package/dist/hooks/useTrackTranscription.d.ts.map +1 -0
- package/dist/hooks/useTrackVolume.d.ts +49 -0
- package/dist/hooks/useTrackVolume.d.ts.map +1 -0
- package/dist/hooks/useTracks.d.ts +29 -0
- package/dist/hooks/useTracks.d.ts.map +1 -0
- package/dist/hooks/useTranscriptions.d.ts +21 -0
- package/dist/hooks/useTranscriptions.d.ts.map +1 -0
- package/dist/hooks/useVisualStableUpdate.d.ts +27 -0
- package/dist/hooks/useVisualStableUpdate.d.ts.map +1 -0
- package/dist/hooks/useVoiceAssistant.d.ts +43 -0
- package/dist/hooks/useVoiceAssistant.d.ts.map +1 -0
- package/dist/hooks/useWarnAboutMissingStyles.d.ts +5 -0
- package/dist/hooks/useWarnAboutMissingStyles.d.ts.map +1 -0
- package/dist/hooks-hQJmeINB.mjs +1992 -0
- package/dist/hooks-hQJmeINB.mjs.map +1 -0
- package/dist/hooks.d.ts +2 -0
- package/dist/hooks.js +2 -0
- package/dist/hooks.js.map +1 -0
- package/dist/hooks.mjs +64 -0
- package/dist/hooks.mjs.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.docs.d.ts +6 -0
- package/dist/index.docs.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +157 -0
- package/dist/index.mjs.map +1 -0
- package/dist/krisp.d.ts +2 -0
- package/dist/krisp.js +2 -0
- package/dist/krisp.js.map +1 -0
- package/dist/krisp.mjs +45 -0
- package/dist/krisp.mjs.map +1 -0
- package/dist/mergeProps.d.ts +25 -0
- package/dist/mergeProps.d.ts.map +1 -0
- package/dist/prefabs/AudioConference.d.ts +22 -0
- package/dist/prefabs/AudioConference.d.ts.map +1 -0
- package/dist/prefabs/Chat.d.ts +35 -0
- package/dist/prefabs/Chat.d.ts.map +1 -0
- package/dist/prefabs/ControlBar.d.ts +45 -0
- package/dist/prefabs/ControlBar.d.ts.map +1 -0
- package/dist/prefabs/MediaDeviceMenu.d.ts +36 -0
- package/dist/prefabs/MediaDeviceMenu.d.ts.map +1 -0
- package/dist/prefabs/PreJoin.d.ts +59 -0
- package/dist/prefabs/PreJoin.d.ts.map +1 -0
- package/dist/prefabs/VideoConference.d.ts +35 -0
- package/dist/prefabs/VideoConference.d.ts.map +1 -0
- package/dist/prefabs/VoiceAssistantControlBar.d.ts +32 -0
- package/dist/prefabs/VoiceAssistantControlBar.d.ts.map +1 -0
- package/dist/prefabs/index.d.ts +8 -0
- package/dist/prefabs/index.d.ts.map +1 -0
- package/dist/prefabs.d.ts +2 -0
- package/dist/prefabs.js +2 -0
- package/dist/prefabs.js.map +1 -0
- package/dist/prefabs.mjs +579 -0
- package/dist/prefabs.mjs.map +1 -0
- package/dist/room-BP3SCCCd.mjs +191 -0
- package/dist/room-BP3SCCCd.mjs.map +1 -0
- package/dist/shared-88J2fzv7.js +2 -0
- package/dist/shared-88J2fzv7.js.map +1 -0
- package/dist/shared-BDr0qLg4.js +4 -0
- package/dist/shared-BDr0qLg4.js.map +1 -0
- package/dist/shared-CjI_UuOX.js +2 -0
- package/dist/shared-CjI_UuOX.js.map +1 -0
- package/dist/shared-DTHOl3uJ.js +2 -0
- package/dist/shared-DTHOl3uJ.js.map +1 -0
- package/dist/utils.d.ts +19 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +104 -0
- package/src/assets/icons/CameraDisabledIcon.tsx +15 -0
- package/src/assets/icons/CameraIcon.tsx +14 -0
- package/src/assets/icons/ChatCloseIcon.tsx +17 -0
- package/src/assets/icons/ChatIcon.tsx +25 -0
- package/src/assets/icons/Chevron.tsx +19 -0
- package/src/assets/icons/FocusToggleIcon.tsx +16 -0
- package/src/assets/icons/GearIcon.tsx +19 -0
- package/src/assets/icons/LeaveIcon.tsx +25 -0
- package/src/assets/icons/LockLockedIcon.tsx +19 -0
- package/src/assets/icons/MicDisabledIcon.tsx +15 -0
- package/src/assets/icons/MicIcon.tsx +19 -0
- package/src/assets/icons/QualityExcellentIcon.tsx +15 -0
- package/src/assets/icons/QualityGoodIcon.tsx +19 -0
- package/src/assets/icons/QualityPoorIcon.tsx +20 -0
- package/src/assets/icons/QualityUnknownIcon.tsx +17 -0
- package/src/assets/icons/ScreenShareIcon.tsx +25 -0
- package/src/assets/icons/ScreenShareStopIcon.tsx +21 -0
- package/src/assets/icons/SpinnerIcon.tsx +93 -0
- package/src/assets/icons/UnfocusToggleIcon.tsx +16 -0
- package/src/assets/icons/index.ts +19 -0
- package/src/assets/icons/util.tsx +47 -0
- package/src/assets/images/ParticipantPlaceholder.tsx +31 -0
- package/src/assets/images/index.ts +1 -0
- package/src/assets/template.js +21 -0
- package/src/components/ChatEntry.tsx +112 -0
- package/src/components/ConnectionState.tsx +36 -0
- package/src/components/ConnectionStateToast.tsx +47 -0
- package/src/components/LiveKitRoom.tsx +122 -0
- package/src/components/ParticipantLoop.tsx +41 -0
- package/src/components/RoomAudioRenderer.tsx +57 -0
- package/src/components/RoomName.tsx +36 -0
- package/src/components/SessionProvider.tsx +22 -0
- package/src/components/Toast.tsx +18 -0
- package/src/components/TrackLoop.tsx +45 -0
- package/src/components/controls/ChatToggle.tsx +32 -0
- package/src/components/controls/ClearPinButton.tsx +32 -0
- package/src/components/controls/DisconnectButton.tsx +32 -0
- package/src/components/controls/FocusToggle.tsx +54 -0
- package/src/components/controls/MediaDeviceSelect.tsx +144 -0
- package/src/components/controls/PaginationControl.tsx +51 -0
- package/src/components/controls/PaginationIndicator.tsx +26 -0
- package/src/components/controls/SettingsMenuToggle.tsx +26 -0
- package/src/components/controls/StartAudio.tsx +40 -0
- package/src/components/controls/StartMediaButton.tsx +41 -0
- package/src/components/controls/TrackToggle.tsx +54 -0
- package/src/components/index.ts +34 -0
- package/src/components/layout/CarouselLayout.tsx +80 -0
- package/src/components/layout/FocusLayout.tsx +37 -0
- package/src/components/layout/GridLayout.tsx +63 -0
- package/src/components/layout/LayoutContextProvider.tsx +36 -0
- package/src/components/layout/index.ts +3 -0
- package/src/components/participant/AudioTrack.tsx +89 -0
- package/src/components/participant/AudioVisualizer.tsx +67 -0
- package/src/components/participant/BarVisualizer.tsx +164 -0
- package/src/components/participant/ConnectionQualityIndicator.tsx +36 -0
- package/src/components/participant/ParticipantAudioTile.tsx +67 -0
- package/src/components/participant/ParticipantName.tsx +50 -0
- package/src/components/participant/ParticipantTile.tsx +192 -0
- package/src/components/participant/TrackMutedIndicator.tsx +53 -0
- package/src/components/participant/VideoTrack.tsx +92 -0
- package/src/components/participant/animationSequences/connectingSequence.ts +9 -0
- package/src/components/participant/animationSequences/listeningSequence.ts +6 -0
- package/src/components/participant/animationSequences/thinkingSequence.ts +12 -0
- package/src/components/participant/animators/useBarAnimator.ts +55 -0
- package/src/context/chat-context.ts +37 -0
- package/src/context/feature-context.ts +28 -0
- package/src/context/index.ts +27 -0
- package/src/context/layout-context.ts +72 -0
- package/src/context/participant-context.ts +44 -0
- package/src/context/pin-context.ts +27 -0
- package/src/context/room-context.ts +42 -0
- package/src/context/session-context.ts +43 -0
- package/src/context/track-reference-context.ts +47 -0
- package/src/hooks/cloud/krisp/useKrispNoiseFilter.ts +110 -0
- package/src/hooks/index.ts +72 -0
- package/src/hooks/internal/index.ts +10 -0
- package/src/hooks/internal/useMediaQuery.ts +46 -0
- package/src/hooks/internal/useObservableState.ts +24 -0
- package/src/hooks/internal/useResizeObserver.ts +124 -0
- package/src/hooks/useAgent.ts +945 -0
- package/src/hooks/useAudioPlayback.ts +34 -0
- package/src/hooks/useChat.ts +57 -0
- package/src/hooks/useChatToggle.ts +38 -0
- package/src/hooks/useClearPinButton.ts +29 -0
- package/src/hooks/useConnectionQualityIndicator.ts +33 -0
- package/src/hooks/useConnectionStatus.ts +22 -0
- package/src/hooks/useDataChannel.ts +73 -0
- package/src/hooks/useDisconnectButton.ts +36 -0
- package/src/hooks/useEvents.ts +39 -0
- package/src/hooks/useFacingMode.ts +22 -0
- package/src/hooks/useFocusToggle.ts +59 -0
- package/src/hooks/useGridLayout.ts +44 -0
- package/src/hooks/useIsEncrypted.ts +29 -0
- package/src/hooks/useIsMuted.ts +51 -0
- package/src/hooks/useIsRecording.ts +23 -0
- package/src/hooks/useIsSpeaking.ts +21 -0
- package/src/hooks/useLiveKitRoom.ts +186 -0
- package/src/hooks/useLocalParticipant.ts +73 -0
- package/src/hooks/useLocalParticipantPermissions.ts +24 -0
- package/src/hooks/useMediaDeviceSelect.ts +81 -0
- package/src/hooks/useMediaDevices.ts +28 -0
- package/src/hooks/useMediaTrackBySourceOrName.ts +97 -0
- package/src/hooks/usePagination.test.ts +77 -0
- package/src/hooks/usePagination.ts +67 -0
- package/src/hooks/useParticipantAttributes.ts +69 -0
- package/src/hooks/useParticipantInfo.ts +35 -0
- package/src/hooks/useParticipantPermissions.ts +29 -0
- package/src/hooks/useParticipantTile.ts +81 -0
- package/src/hooks/useParticipantTracks.ts +54 -0
- package/src/hooks/useParticipants.ts +42 -0
- package/src/hooks/usePersistentUserChoices.ts +64 -0
- package/src/hooks/usePinnedTracks.ts +24 -0
- package/src/hooks/useRemoteParticipant.ts +79 -0
- package/src/hooks/useRemoteParticipants.ts +45 -0
- package/src/hooks/useRoomInfo.ts +32 -0
- package/src/hooks/useSequentialRoomConnectDisconnect.ts +171 -0
- package/src/hooks/useSession.ts +642 -0
- package/src/hooks/useSessionMessages.ts +158 -0
- package/src/hooks/useSettingsToggle.ts +32 -0
- package/src/hooks/useSortedParticipants.ts +20 -0
- package/src/hooks/useSpeakingParticipants.ts +27 -0
- package/src/hooks/useStartAudio.ts +50 -0
- package/src/hooks/useStartVideo.ts +49 -0
- package/src/hooks/useSwipe.ts +68 -0
- package/src/hooks/useTextStream.ts +35 -0
- package/src/hooks/useToken.ts +54 -0
- package/src/hooks/useTrack.ts +11 -0
- package/src/hooks/useTrackByName.ts +15 -0
- package/src/hooks/useTrackMutedIndicator.ts +44 -0
- package/src/hooks/useTrackRefBySourceOrName.ts +30 -0
- package/src/hooks/useTrackSyncTime.ts +18 -0
- package/src/hooks/useTrackToggle.ts +93 -0
- package/src/hooks/useTrackTranscription.ts +75 -0
- package/src/hooks/useTrackVolume.ts +283 -0
- package/src/hooks/useTracks.test.ts +60 -0
- package/src/hooks/useTracks.ts +154 -0
- package/src/hooks/useTranscriptions.ts +48 -0
- package/src/hooks/useVisualStableUpdate.ts +63 -0
- package/src/hooks/useVoiceAssistant.ts +109 -0
- package/src/hooks/useWarnAboutMissingStyles.ts +11 -0
- package/src/index.docs.ts +12 -0
- package/src/index.ts +32 -0
- package/src/mergeProps.ts +87 -0
- package/src/prefabs/AudioConference.tsx +57 -0
- package/src/prefabs/Chat.tsx +153 -0
- package/src/prefabs/ControlBar.tsx +227 -0
- package/src/prefabs/MediaDeviceMenu.tsx +159 -0
- package/src/prefabs/PreJoin.tsx +439 -0
- package/src/prefabs/VideoConference.tsx +184 -0
- package/src/prefabs/VoiceAssistantControlBar.tsx +109 -0
- package/src/prefabs/index.ts +11 -0
- package/src/utils.ts +78 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { ToggleSource } from '@livekit/components-core';
|
|
2
|
+
import { setupMediaToggle, setupManualToggle, log } from '@livekit/components-core';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { type Room } from 'livekit-client';
|
|
5
|
+
import type { TrackToggleProps } from '../components';
|
|
6
|
+
import { useMaybeRoomContext } from '../context';
|
|
7
|
+
import { mergeProps } from '../mergeProps';
|
|
8
|
+
import { useObservableState } from './internal';
|
|
9
|
+
|
|
10
|
+
/** @public */
|
|
11
|
+
export interface UseTrackToggleProps<T extends ToggleSource>
|
|
12
|
+
extends Omit<TrackToggleProps<T>, 'showIcon'> {
|
|
13
|
+
room?: Room;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The `useTrackToggle` hook is used to implement the `TrackToggle` component and returns state
|
|
18
|
+
* and functionality of the given track.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```tsx
|
|
22
|
+
* const { buttonProps, enabled } = useTrackToggle(trackRef);
|
|
23
|
+
* return <button {...buttonProps}>{enabled ? 'disable' : 'enable'}</button>;
|
|
24
|
+
* ```
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
export function useTrackToggle<T extends ToggleSource>({
|
|
28
|
+
source,
|
|
29
|
+
onChange,
|
|
30
|
+
initialState,
|
|
31
|
+
captureOptions,
|
|
32
|
+
publishOptions,
|
|
33
|
+
onDeviceError,
|
|
34
|
+
room,
|
|
35
|
+
...rest
|
|
36
|
+
}: UseTrackToggleProps<T>) {
|
|
37
|
+
const roomFromContext = useMaybeRoomContext();
|
|
38
|
+
const roomFallback = React.useMemo(() => room ?? roomFromContext, [room, roomFromContext]);
|
|
39
|
+
const track = roomFallback?.localParticipant?.getTrackPublication(source);
|
|
40
|
+
/** `true` if a user interaction such as a click on the TrackToggle button has occurred. */
|
|
41
|
+
const userInteractionRef = React.useRef(false);
|
|
42
|
+
|
|
43
|
+
const { toggle, className, pendingObserver, enabledObserver } = React.useMemo(
|
|
44
|
+
() =>
|
|
45
|
+
roomFallback
|
|
46
|
+
? setupMediaToggle<T>(source, roomFallback, captureOptions, publishOptions, onDeviceError)
|
|
47
|
+
: setupManualToggle(),
|
|
48
|
+
[roomFallback, source, JSON.stringify(captureOptions), publishOptions],
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const pending = useObservableState(pendingObserver, false);
|
|
52
|
+
const enabled = useObservableState(enabledObserver, initialState ?? !!track?.isEnabled);
|
|
53
|
+
|
|
54
|
+
React.useEffect(() => {
|
|
55
|
+
onChange?.(enabled, userInteractionRef.current);
|
|
56
|
+
userInteractionRef.current = false;
|
|
57
|
+
}, [enabled, onChange]);
|
|
58
|
+
|
|
59
|
+
React.useEffect(() => {
|
|
60
|
+
if (initialState !== undefined) {
|
|
61
|
+
log.debug('forcing initial toggle state', source, initialState);
|
|
62
|
+
toggle(initialState);
|
|
63
|
+
}
|
|
64
|
+
// only execute once at the beginning
|
|
65
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
66
|
+
}, []);
|
|
67
|
+
|
|
68
|
+
const newProps = React.useMemo(() => mergeProps(rest, { className }), [rest, className]);
|
|
69
|
+
|
|
70
|
+
const clickHandler: React.MouseEventHandler<HTMLButtonElement> = React.useCallback(
|
|
71
|
+
(evt) => {
|
|
72
|
+
userInteractionRef.current = true;
|
|
73
|
+
toggle().catch(() => (userInteractionRef.current = false));
|
|
74
|
+
rest.onClick?.(evt);
|
|
75
|
+
},
|
|
76
|
+
[rest, toggle],
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
toggle,
|
|
81
|
+
enabled,
|
|
82
|
+
pending,
|
|
83
|
+
track,
|
|
84
|
+
buttonProps: {
|
|
85
|
+
...newProps,
|
|
86
|
+
'aria-pressed': enabled,
|
|
87
|
+
'data-lk-source': source,
|
|
88
|
+
'data-lk-enabled': enabled,
|
|
89
|
+
disabled: pending,
|
|
90
|
+
onClick: clickHandler,
|
|
91
|
+
} as React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ReceivedTranscriptionSegment,
|
|
3
|
+
addMediaTimestampToTranscription as addTimestampsToTranscription,
|
|
4
|
+
dedupeSegments,
|
|
5
|
+
// getActiveTranscriptionSegments,
|
|
6
|
+
getTrackReferenceId,
|
|
7
|
+
trackTranscriptionObserver,
|
|
8
|
+
type TrackReferenceOrPlaceholder,
|
|
9
|
+
// didActiveSegmentsChange,
|
|
10
|
+
} from '@livekit/components-core';
|
|
11
|
+
import type { TranscriptionSegment } from 'livekit-client';
|
|
12
|
+
import * as React from 'react';
|
|
13
|
+
import { useTrackSyncTime } from './useTrackSyncTime';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @alpha
|
|
17
|
+
* @deprecated Use useTranscription instead
|
|
18
|
+
*/
|
|
19
|
+
export interface TrackTranscriptionOptions {
|
|
20
|
+
/**
|
|
21
|
+
* how many transcription segments should be buffered in state
|
|
22
|
+
* @defaultValue 100
|
|
23
|
+
*/
|
|
24
|
+
bufferSize?: number;
|
|
25
|
+
/**
|
|
26
|
+
* optional callback for retrieving newly incoming transcriptions only
|
|
27
|
+
*/
|
|
28
|
+
onTranscription?: (newSegments: TranscriptionSegment[]) => void;
|
|
29
|
+
/** amount of time (in ms) that the segment is considered `active` past its original segment duration, defaults to 2_000 */
|
|
30
|
+
// maxAge?: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const TRACK_TRANSCRIPTION_DEFAULTS = {
|
|
34
|
+
bufferSize: 100,
|
|
35
|
+
// maxAge: 2_000,
|
|
36
|
+
} as const satisfies TrackTranscriptionOptions;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @returns An object consisting of `segments` with maximum length of opts.bufferSize
|
|
40
|
+
* @alpha
|
|
41
|
+
* @deprecated Use useTranscription instead
|
|
42
|
+
*/
|
|
43
|
+
export function useTrackTranscription(
|
|
44
|
+
trackRef: TrackReferenceOrPlaceholder | undefined,
|
|
45
|
+
options?: TrackTranscriptionOptions,
|
|
46
|
+
) {
|
|
47
|
+
const opts = { ...TRACK_TRANSCRIPTION_DEFAULTS, ...options };
|
|
48
|
+
const [segments, setSegments] = React.useState<Array<ReceivedTranscriptionSegment>>([]);
|
|
49
|
+
|
|
50
|
+
const syncTimestamps = useTrackSyncTime(trackRef);
|
|
51
|
+
const handleSegmentMessage = (newSegments: TranscriptionSegment[]) => {
|
|
52
|
+
opts.onTranscription?.(newSegments);
|
|
53
|
+
setSegments((prevSegments) =>
|
|
54
|
+
dedupeSegments(
|
|
55
|
+
prevSegments,
|
|
56
|
+
// when first receiving a segment, add the current media timestamp to it
|
|
57
|
+
newSegments.map((s) => addTimestampsToTranscription(s, syncTimestamps)),
|
|
58
|
+
opts.bufferSize,
|
|
59
|
+
),
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
React.useEffect(() => {
|
|
63
|
+
if (!trackRef?.publication) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const subscription = trackTranscriptionObserver(trackRef.publication).subscribe((evt) => {
|
|
67
|
+
handleSegmentMessage(...evt);
|
|
68
|
+
});
|
|
69
|
+
return () => {
|
|
70
|
+
subscription.unsubscribe();
|
|
71
|
+
};
|
|
72
|
+
}, [trackRef && getTrackReferenceId(trackRef), handleSegmentMessage]);
|
|
73
|
+
|
|
74
|
+
return { segments };
|
|
75
|
+
}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { LocalAudioTrack, RemoteAudioTrack, AudioAnalyserOptions } from 'livekit-client';
|
|
3
|
+
import { Track, createAudioAnalyser } from 'livekit-client';
|
|
4
|
+
import {
|
|
5
|
+
type TrackReference,
|
|
6
|
+
isTrackReference,
|
|
7
|
+
type TrackReferenceOrPlaceholder,
|
|
8
|
+
} from '@livekit/components-core';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @alpha
|
|
12
|
+
* Hook for tracking the volume of an audio track using the Web Audio API.
|
|
13
|
+
*/
|
|
14
|
+
export function useTrackVolume(
|
|
15
|
+
trackOrTrackReference?: LocalAudioTrack | RemoteAudioTrack | TrackReference,
|
|
16
|
+
options: AudioAnalyserOptions = { fftSize: 32, smoothingTimeConstant: 0 },
|
|
17
|
+
) {
|
|
18
|
+
const track = isTrackReference(trackOrTrackReference)
|
|
19
|
+
? <LocalAudioTrack | RemoteAudioTrack | undefined>trackOrTrackReference.publication.track
|
|
20
|
+
: trackOrTrackReference;
|
|
21
|
+
const [volume, setVolume] = React.useState(0);
|
|
22
|
+
React.useEffect(() => {
|
|
23
|
+
if (!track || !track.mediaStream) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const { cleanup, analyser } = createAudioAnalyser(track, options);
|
|
28
|
+
|
|
29
|
+
const bufferLength = analyser.frequencyBinCount;
|
|
30
|
+
const dataArray = new Uint8Array(bufferLength);
|
|
31
|
+
|
|
32
|
+
const updateVolume = () => {
|
|
33
|
+
analyser.getByteFrequencyData(dataArray);
|
|
34
|
+
let sum = 0;
|
|
35
|
+
for (let i = 0; i < dataArray.length; i++) {
|
|
36
|
+
const a = dataArray[i];
|
|
37
|
+
sum += a * a;
|
|
38
|
+
}
|
|
39
|
+
setVolume(Math.sqrt(sum / dataArray.length) / 255);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const interval = setInterval(updateVolume, 1000 / 30);
|
|
43
|
+
|
|
44
|
+
return () => {
|
|
45
|
+
cleanup();
|
|
46
|
+
clearInterval(interval);
|
|
47
|
+
};
|
|
48
|
+
}, [track, track?.mediaStream, JSON.stringify(options)]);
|
|
49
|
+
|
|
50
|
+
return volume;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const normalizeFrequencies = (frequencies: Float32Array) => {
|
|
54
|
+
const normalizeDb = (value: number) => {
|
|
55
|
+
const minDb = -100;
|
|
56
|
+
const maxDb = -10;
|
|
57
|
+
let db = 1 - (Math.max(minDb, Math.min(maxDb, value)) * -1) / 100;
|
|
58
|
+
db = Math.sqrt(db);
|
|
59
|
+
|
|
60
|
+
return db;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Normalize all frequency values
|
|
64
|
+
return frequencies.map((value) => {
|
|
65
|
+
if (value === -Infinity) {
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
return normalizeDb(value);
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Interface for configuring options for the useMultibandTrackVolume hook.
|
|
74
|
+
* @alpha
|
|
75
|
+
*/
|
|
76
|
+
export interface MultiBandTrackVolumeOptions {
|
|
77
|
+
bands?: number;
|
|
78
|
+
/**
|
|
79
|
+
* cut off of frequency bins on the lower end
|
|
80
|
+
* Note: this is not a frequency measure, but in relation to analyserOptions.fftSize,
|
|
81
|
+
*/
|
|
82
|
+
loPass?: number;
|
|
83
|
+
/**
|
|
84
|
+
* cut off of frequency bins on the higher end
|
|
85
|
+
* Note: this is not a frequency measure, but in relation to analyserOptions.fftSize,
|
|
86
|
+
*/
|
|
87
|
+
hiPass?: number;
|
|
88
|
+
/**
|
|
89
|
+
* update should run every x ms
|
|
90
|
+
*/
|
|
91
|
+
updateInterval?: number;
|
|
92
|
+
analyserOptions?: AnalyserOptions;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const multibandDefaults = {
|
|
96
|
+
bands: 5,
|
|
97
|
+
loPass: 100,
|
|
98
|
+
hiPass: 600,
|
|
99
|
+
updateInterval: 32,
|
|
100
|
+
analyserOptions: { fftSize: 2048 },
|
|
101
|
+
} as const satisfies MultiBandTrackVolumeOptions;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Hook for tracking the volume of an audio track across multiple frequency bands using the Web Audio API.
|
|
105
|
+
* @alpha
|
|
106
|
+
*/
|
|
107
|
+
export function useMultibandTrackVolume(
|
|
108
|
+
trackOrTrackReference?: LocalAudioTrack | RemoteAudioTrack | TrackReferenceOrPlaceholder,
|
|
109
|
+
options: MultiBandTrackVolumeOptions = {},
|
|
110
|
+
) {
|
|
111
|
+
const track =
|
|
112
|
+
trackOrTrackReference instanceof Track
|
|
113
|
+
? trackOrTrackReference
|
|
114
|
+
: <LocalAudioTrack | RemoteAudioTrack | undefined>trackOrTrackReference?.publication?.track;
|
|
115
|
+
const opts = { ...multibandDefaults, ...options };
|
|
116
|
+
const [frequencyBands, setFrequencyBands] = React.useState<Array<number>>(
|
|
117
|
+
new Array(opts.bands).fill(0),
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
React.useEffect(() => {
|
|
121
|
+
if (!track || !track?.mediaStream) {
|
|
122
|
+
setFrequencyBands((val) => val.slice().fill(0));
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const { analyser, cleanup } = createAudioAnalyser(track, opts.analyserOptions);
|
|
126
|
+
|
|
127
|
+
const bufferLength = analyser.frequencyBinCount;
|
|
128
|
+
const dataArray = new Float32Array(bufferLength);
|
|
129
|
+
|
|
130
|
+
const updateVolume = () => {
|
|
131
|
+
analyser.getFloatFrequencyData(dataArray);
|
|
132
|
+
let frequencies: Float32Array = new Float32Array(dataArray.length);
|
|
133
|
+
for (let i = 0; i < dataArray.length; i++) {
|
|
134
|
+
frequencies[i] = dataArray[i];
|
|
135
|
+
}
|
|
136
|
+
frequencies = frequencies.slice(opts.loPass, opts.hiPass);
|
|
137
|
+
|
|
138
|
+
const normalizedFrequencies = normalizeFrequencies(frequencies); // is this needed ?
|
|
139
|
+
const totalBins = normalizedFrequencies.length;
|
|
140
|
+
const chunks: Array<number> = [];
|
|
141
|
+
for (let i = 0; i < opts.bands; i++) {
|
|
142
|
+
// Use proportional distribution to evenly divide bins across bands
|
|
143
|
+
const startIndex = Math.floor((i * totalBins) / opts.bands);
|
|
144
|
+
const endIndex = Math.floor(((i + 1) * totalBins) / opts.bands);
|
|
145
|
+
const chunk = normalizedFrequencies.slice(startIndex, endIndex);
|
|
146
|
+
const chunkLength = chunk.length;
|
|
147
|
+
if (chunkLength === 0) {
|
|
148
|
+
chunks.push(0);
|
|
149
|
+
} else {
|
|
150
|
+
const summedVolumes = chunk.reduce((acc, val) => (acc += val), 0);
|
|
151
|
+
chunks.push(summedVolumes / chunkLength);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
setFrequencyBands(chunks);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const interval = setInterval(updateVolume, opts.updateInterval);
|
|
159
|
+
|
|
160
|
+
return () => {
|
|
161
|
+
cleanup();
|
|
162
|
+
clearInterval(interval);
|
|
163
|
+
};
|
|
164
|
+
}, [track, track?.mediaStream, JSON.stringify(options)]);
|
|
165
|
+
|
|
166
|
+
return frequencyBands;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* @alpha
|
|
171
|
+
*/
|
|
172
|
+
export interface AudioWaveformOptions {
|
|
173
|
+
barCount?: number;
|
|
174
|
+
volMultiplier?: number;
|
|
175
|
+
updateInterval?: number;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const waveformDefaults = {
|
|
179
|
+
barCount: 120,
|
|
180
|
+
volMultiplier: 5,
|
|
181
|
+
updateInterval: 20,
|
|
182
|
+
} as const satisfies AudioWaveformOptions;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @alpha
|
|
186
|
+
*/
|
|
187
|
+
export function useAudioWaveform(
|
|
188
|
+
trackOrTrackReference?: LocalAudioTrack | RemoteAudioTrack | TrackReferenceOrPlaceholder,
|
|
189
|
+
options: AudioWaveformOptions = {},
|
|
190
|
+
) {
|
|
191
|
+
const track =
|
|
192
|
+
trackOrTrackReference instanceof Track
|
|
193
|
+
? trackOrTrackReference
|
|
194
|
+
: <LocalAudioTrack | RemoteAudioTrack | undefined>trackOrTrackReference?.publication?.track;
|
|
195
|
+
const opts = { ...waveformDefaults, ...options };
|
|
196
|
+
|
|
197
|
+
const aggregateWave = React.useRef(new Float32Array());
|
|
198
|
+
const timeRef = React.useRef(performance.now());
|
|
199
|
+
const updates = React.useRef(0);
|
|
200
|
+
const [bars, setBars] = React.useState<number[]>([]);
|
|
201
|
+
|
|
202
|
+
const onUpdate = React.useCallback((wave: Float32Array) => {
|
|
203
|
+
setBars(
|
|
204
|
+
Array.from(
|
|
205
|
+
filterData(wave, opts.barCount).map((v) => Math.sqrt(v) * opts.volMultiplier),
|
|
206
|
+
// wave.slice(0, opts.barCount).map((v) => sigmoid(v * opts.volMultiplier, 0.08, 0.2)),
|
|
207
|
+
),
|
|
208
|
+
);
|
|
209
|
+
}, []);
|
|
210
|
+
|
|
211
|
+
React.useEffect(() => {
|
|
212
|
+
if (!track || !track?.mediaStream) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const { analyser, cleanup } = createAudioAnalyser(track, {
|
|
216
|
+
fftSize: getFFTSizeValue(opts.barCount),
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const bufferLength = getFFTSizeValue(opts.barCount);
|
|
220
|
+
const dataArray = new Float32Array(bufferLength);
|
|
221
|
+
|
|
222
|
+
const update = () => {
|
|
223
|
+
updateWaveform = requestAnimationFrame(update);
|
|
224
|
+
analyser.getFloatTimeDomainData(dataArray);
|
|
225
|
+
aggregateWave.current.map((v, i) => v + dataArray[i]);
|
|
226
|
+
updates.current += 1;
|
|
227
|
+
|
|
228
|
+
if (performance.now() - timeRef.current >= opts.updateInterval) {
|
|
229
|
+
const newData = dataArray.map((v) => v / updates.current);
|
|
230
|
+
onUpdate(newData);
|
|
231
|
+
timeRef.current = performance.now();
|
|
232
|
+
updates.current = 0;
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
let updateWaveform = requestAnimationFrame(update);
|
|
237
|
+
|
|
238
|
+
return () => {
|
|
239
|
+
cleanup();
|
|
240
|
+
cancelAnimationFrame(updateWaveform);
|
|
241
|
+
};
|
|
242
|
+
}, [track, track?.mediaStream, JSON.stringify(options), onUpdate]);
|
|
243
|
+
|
|
244
|
+
return {
|
|
245
|
+
bars,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function getFFTSizeValue(x: number) {
|
|
250
|
+
if (x < 32) return 32;
|
|
251
|
+
else return pow2ceil(x);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// function sigmoid(x: number, k = 2, s = 0) {
|
|
255
|
+
// return 1 / (1 + Math.exp(-(x - s) / k));
|
|
256
|
+
// }
|
|
257
|
+
|
|
258
|
+
function pow2ceil(v: number) {
|
|
259
|
+
let p = 2;
|
|
260
|
+
while ((v >>= 1)) {
|
|
261
|
+
p <<= 1;
|
|
262
|
+
}
|
|
263
|
+
return p;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function filterData(audioData: Float32Array, numSamples: number) {
|
|
267
|
+
const blockSize = Math.floor(audioData.length / numSamples); // the number of samples in each subdivision
|
|
268
|
+
const filteredData = new Float32Array(numSamples);
|
|
269
|
+
for (let i = 0; i < numSamples; i++) {
|
|
270
|
+
const blockStart = blockSize * i; // the location of the first sample in the block
|
|
271
|
+
let sum = 0;
|
|
272
|
+
for (let j = 0; j < blockSize; j++) {
|
|
273
|
+
sum = sum + Math.abs(audioData[blockStart + j]); // find the sum of all the samples in the block
|
|
274
|
+
}
|
|
275
|
+
filteredData[i] = sum / blockSize; // divide the sum by the block size to get the average
|
|
276
|
+
}
|
|
277
|
+
return filteredData;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// function normalizeData(audioData: Float32Array) {
|
|
281
|
+
// const multiplier = Math.pow(Math.max(...audioData), -1);
|
|
282
|
+
// return audioData.map((n) => n * multiplier);
|
|
283
|
+
// }
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Participant, Track } from 'livekit-client';
|
|
2
|
+
import { describe, test, expect } from 'vitest';
|
|
3
|
+
import { requiredPlaceholders } from './useTracks';
|
|
4
|
+
|
|
5
|
+
describe('Test requiredPlaceholders functions indicates that placeholders are required.', () => {
|
|
6
|
+
test('Participants without tracks should be included in the map.', () => {
|
|
7
|
+
const sources = [{ source: Track.Source.Camera, withPlaceholder: true }];
|
|
8
|
+
const participants = [new Participant('sid_A', 'identity_A')];
|
|
9
|
+
const results = requiredPlaceholders(sources, participants);
|
|
10
|
+
expect(results.get('identity_A')).toStrictEqual([Track.Source.Camera]);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test("Multiple participants should be included in the map if they don't have a subscribed tracks.", () => {
|
|
14
|
+
const sources = [
|
|
15
|
+
{ source: Track.Source.Camera, withPlaceholder: true },
|
|
16
|
+
{ source: Track.Source.ScreenShare, withPlaceholder: true },
|
|
17
|
+
];
|
|
18
|
+
const participants = [
|
|
19
|
+
new Participant('sid_A', 'identity_A'),
|
|
20
|
+
new Participant('sid_B', 'identity_B'),
|
|
21
|
+
];
|
|
22
|
+
const results = requiredPlaceholders(sources, participants);
|
|
23
|
+
expect(results.get('identity_A')).toStrictEqual([
|
|
24
|
+
Track.Source.Camera,
|
|
25
|
+
Track.Source.ScreenShare,
|
|
26
|
+
]);
|
|
27
|
+
expect(results.get('identity_B')).toStrictEqual([
|
|
28
|
+
Track.Source.Camera,
|
|
29
|
+
Track.Source.ScreenShare,
|
|
30
|
+
]);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('The map should only include placeholders for if `withPlaceholder: true`', () => {
|
|
34
|
+
const sources = [
|
|
35
|
+
{ source: Track.Source.Camera, withPlaceholder: true },
|
|
36
|
+
{ source: Track.Source.ScreenShare, withPlaceholder: false },
|
|
37
|
+
];
|
|
38
|
+
const participants = [
|
|
39
|
+
new Participant('sid_A', 'identity_A'),
|
|
40
|
+
new Participant('sid_B', 'identity_B'),
|
|
41
|
+
];
|
|
42
|
+
const results = requiredPlaceholders(sources, participants);
|
|
43
|
+
expect(results.get('identity_A')).toStrictEqual([Track.Source.Camera]);
|
|
44
|
+
expect(results.get('identity_B')).toStrictEqual([Track.Source.Camera]);
|
|
45
|
+
});
|
|
46
|
+
test('If no placeholders are wanted the map should be empty', () => {
|
|
47
|
+
const sources = [
|
|
48
|
+
{ source: Track.Source.Camera, withPlaceholder: false },
|
|
49
|
+
{ source: Track.Source.ScreenShare, withPlaceholder: false },
|
|
50
|
+
];
|
|
51
|
+
const participants = [
|
|
52
|
+
new Participant('sid_A', 'identity_A'),
|
|
53
|
+
new Participant('sid_B', 'identity_B'),
|
|
54
|
+
];
|
|
55
|
+
const results = requiredPlaceholders(sources, participants);
|
|
56
|
+
expect(results.size).toBe(0);
|
|
57
|
+
expect(results.has('identity_A')).toBeFalsy();
|
|
58
|
+
expect(results.has('identity_B')).toBeFalsy();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
SourcesArray,
|
|
3
|
+
TrackReference,
|
|
4
|
+
TrackReferenceOrPlaceholder,
|
|
5
|
+
TrackSourceWithOptions,
|
|
6
|
+
TrackReferencePlaceholder,
|
|
7
|
+
} from '@livekit/components-core';
|
|
8
|
+
import {
|
|
9
|
+
isSourcesWithOptions,
|
|
10
|
+
isSourceWitOptions,
|
|
11
|
+
log,
|
|
12
|
+
trackReferencesObservable,
|
|
13
|
+
} from '@livekit/components-core';
|
|
14
|
+
import type { Participant, Room, RoomEvent } from 'livekit-client';
|
|
15
|
+
import { Track } from 'livekit-client';
|
|
16
|
+
import * as React from 'react';
|
|
17
|
+
import { useEnsureRoom } from '../context';
|
|
18
|
+
|
|
19
|
+
/** @public */
|
|
20
|
+
export type UseTracksOptions = {
|
|
21
|
+
updateOnlyOn?: RoomEvent[];
|
|
22
|
+
onlySubscribed?: boolean;
|
|
23
|
+
room?: Room;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/** @public */
|
|
27
|
+
export type UseTracksHookReturnType<T> = T extends Track.Source[]
|
|
28
|
+
? TrackReference[]
|
|
29
|
+
: T extends TrackSourceWithOptions[]
|
|
30
|
+
? TrackReferenceOrPlaceholder[]
|
|
31
|
+
: never;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The `useTracks` hook returns an array of `TrackReference` or `TrackReferenceOrPlaceholder` depending on the provided `sources` property.
|
|
35
|
+
* If only subscribed tracks are desired, set the `onlySubscribed` property to `true`.
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* // Return all camera track publications.
|
|
39
|
+
* const trackReferences: TrackReference[] = useTracks([Track.Source.Camera])
|
|
40
|
+
* ```
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* // Return all subscribed camera tracks as well as placeholders for
|
|
44
|
+
* // participants without a camera subscription.
|
|
45
|
+
* const trackReferencesWithPlaceholders: TrackReferenceOrPlaceholder[] = useTracks([{source: Track.Source.Camera, withPlaceholder: true}])
|
|
46
|
+
* ```
|
|
47
|
+
* @public
|
|
48
|
+
*/
|
|
49
|
+
export function useTracks<T extends SourcesArray = Track.Source[]>(
|
|
50
|
+
sources: T = [
|
|
51
|
+
Track.Source.Camera,
|
|
52
|
+
Track.Source.Microphone,
|
|
53
|
+
Track.Source.ScreenShare,
|
|
54
|
+
Track.Source.ScreenShareAudio,
|
|
55
|
+
Track.Source.Unknown,
|
|
56
|
+
] as T,
|
|
57
|
+
options: UseTracksOptions = {},
|
|
58
|
+
): UseTracksHookReturnType<T> {
|
|
59
|
+
const room = useEnsureRoom(options.room);
|
|
60
|
+
const [trackReferences, setTrackReferences] = React.useState<TrackReference[]>([]);
|
|
61
|
+
const [participants, setParticipants] = React.useState<Participant[]>([]);
|
|
62
|
+
|
|
63
|
+
const sources_ = React.useMemo(() => {
|
|
64
|
+
return sources.map((s) => (isSourceWitOptions(s) ? s.source : s));
|
|
65
|
+
}, [JSON.stringify(sources)]);
|
|
66
|
+
|
|
67
|
+
React.useEffect(() => {
|
|
68
|
+
const subscription = trackReferencesObservable(room, sources_, {
|
|
69
|
+
additionalRoomEvents: options.updateOnlyOn,
|
|
70
|
+
onlySubscribed: options.onlySubscribed,
|
|
71
|
+
}).subscribe(({ trackReferences, participants }) => {
|
|
72
|
+
log.debug('setting track bundles', trackReferences, participants);
|
|
73
|
+
setTrackReferences(trackReferences);
|
|
74
|
+
setParticipants(participants);
|
|
75
|
+
});
|
|
76
|
+
return () => subscription.unsubscribe();
|
|
77
|
+
}, [
|
|
78
|
+
room,
|
|
79
|
+
JSON.stringify(options.onlySubscribed),
|
|
80
|
+
JSON.stringify(options.updateOnlyOn),
|
|
81
|
+
JSON.stringify(sources),
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
const maybeTrackReferences = React.useMemo(() => {
|
|
85
|
+
if (isSourcesWithOptions(sources)) {
|
|
86
|
+
const requirePlaceholder = requiredPlaceholders(sources, participants);
|
|
87
|
+
const trackReferencesWithPlaceholders: TrackReferenceOrPlaceholder[] =
|
|
88
|
+
Array.from(trackReferences);
|
|
89
|
+
participants.forEach((participant) => {
|
|
90
|
+
if (requirePlaceholder.has(participant.identity)) {
|
|
91
|
+
const sourcesToAddPlaceholder = requirePlaceholder.get(participant.identity) ?? [];
|
|
92
|
+
sourcesToAddPlaceholder.forEach((placeholderSource) => {
|
|
93
|
+
if (
|
|
94
|
+
trackReferences.find(
|
|
95
|
+
({ participant: p, publication }) =>
|
|
96
|
+
participant.identity === p.identity && publication.source === placeholderSource,
|
|
97
|
+
)
|
|
98
|
+
) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
log.debug(
|
|
102
|
+
`Add ${placeholderSource} placeholder for participant ${participant.identity}.`,
|
|
103
|
+
);
|
|
104
|
+
const placeholder: TrackReferencePlaceholder = {
|
|
105
|
+
participant,
|
|
106
|
+
source: placeholderSource,
|
|
107
|
+
};
|
|
108
|
+
trackReferencesWithPlaceholders.push(placeholder);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
return trackReferencesWithPlaceholders;
|
|
113
|
+
} else {
|
|
114
|
+
return trackReferences;
|
|
115
|
+
}
|
|
116
|
+
}, [trackReferences, participants, sources]);
|
|
117
|
+
|
|
118
|
+
return maybeTrackReferences as UseTracksHookReturnType<T>;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function difference<T>(setA: Set<T>, setB: Set<T>): Set<T> {
|
|
122
|
+
const _difference = new Set(setA);
|
|
123
|
+
for (const elem of setB) {
|
|
124
|
+
_difference.delete(elem);
|
|
125
|
+
}
|
|
126
|
+
return _difference;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function requiredPlaceholders<T extends SourcesArray>(
|
|
130
|
+
sources: T,
|
|
131
|
+
participants: Participant[],
|
|
132
|
+
): Map<Participant['identity'], Track.Source[]> {
|
|
133
|
+
const placeholderMap = new Map<Participant['identity'], Track.Source[]>();
|
|
134
|
+
if (isSourcesWithOptions(sources)) {
|
|
135
|
+
const sourcesThatNeedPlaceholder = sources
|
|
136
|
+
.filter((sourceWithOption) => sourceWithOption.withPlaceholder)
|
|
137
|
+
.map((sourceWithOption) => sourceWithOption.source);
|
|
138
|
+
|
|
139
|
+
participants.forEach((participant) => {
|
|
140
|
+
const sourcesOfSubscribedTracks = participant
|
|
141
|
+
.getTrackPublications()
|
|
142
|
+
.map((pub) => pub.track?.source)
|
|
143
|
+
.filter((trackSource): trackSource is Track.Source => trackSource !== undefined);
|
|
144
|
+
const placeholderNeededForThisParticipant = Array.from(
|
|
145
|
+
difference(new Set(sourcesThatNeedPlaceholder), new Set(sourcesOfSubscribedTracks)),
|
|
146
|
+
);
|
|
147
|
+
// If the participant needs placeholder add it to the placeholder map.
|
|
148
|
+
if (placeholderNeededForThisParticipant.length > 0) {
|
|
149
|
+
placeholderMap.set(participant.identity, placeholderNeededForThisParticipant);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
return placeholderMap;
|
|
154
|
+
}
|