@stream-io/video-react-sdk 0.4.7 → 0.4.8
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/CHANGELOG.md +12 -0
- package/dist/css/styles.css +16 -69
- package/dist/css/styles.css.map +1 -1
- package/dist/index.cjs.js +15 -131
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.es.js +14 -133
- package/dist/index.es.js.map +1 -1
- package/dist/src/components/index.d.ts +1 -0
- package/dist/src/hooks/useFloatingUIPreset.d.ts +11 -5
- package/dist/src/translations/index.d.ts +2 -0
- package/index.ts +0 -1
- package/package.json +5 -5
- package/src/components/Permissions/PermissionRequests.tsx +3 -3
- package/src/components/index.ts +1 -0
- package/src/core/components/ParticipantView/DefaultParticipantViewUI.tsx +5 -25
- package/src/hooks/useFloatingUIPreset.ts +5 -5
- package/src/translations/en.json +3 -0
- package/dist/src/components/Debug/DebugParticipantPublishQuality.d.ts +0 -5
- package/dist/src/components/Debug/DebugStatsView.d.ts +0 -7
- package/dist/src/components/Debug/useIsDebugMode.d.ts +0 -5
- package/dist/src/types/components.d.ts +0 -7
- package/dist/src/types/index.d.ts +0 -1
- package/src/components/Debug/DebugParticipantPublishQuality.tsx +0 -62
- package/src/components/Debug/DebugStatsView.tsx +0 -126
- package/src/components/Debug/useIsDebugMode.ts +0 -24
- package/src/types/components.ts +0 -7
- package/src/types/index.ts +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,5 @@ export * from '@stream-io/video-client';
|
|
|
2
2
|
export * from '@stream-io/video-react-bindings';
|
|
3
3
|
export * from './src/core';
|
|
4
4
|
export * from './src/components';
|
|
5
|
-
export * from './src/types';
|
|
6
5
|
export * from './src/translations';
|
|
7
6
|
export { useHorizontalScrollPosition, useVerticalScrollPosition, useRequestPermission, usePersistedDevicePreferences, } from './src/hooks';
|
package/dist/index.es.js
CHANGED
|
@@ -3,7 +3,7 @@ export * from '@stream-io/video-client';
|
|
|
3
3
|
import { useCall, useCallStateHooks, useHasPermissions, useI18n, Restricted, useConnectedUser, StreamCallProvider, StreamVideoProvider } from '@stream-io/video-react-bindings';
|
|
4
4
|
export * from '@stream-io/video-react-bindings';
|
|
5
5
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
6
|
-
import { useState, useEffect, Fragment as Fragment$1, isValidElement, forwardRef, useLayoutEffect, useCallback, useRef,
|
|
6
|
+
import { useState, useEffect, Fragment as Fragment$1, isValidElement, forwardRef, useLayoutEffect, useCallback, useRef, createContext, useContext, useMemo } from 'react';
|
|
7
7
|
import clsx from 'clsx';
|
|
8
8
|
import { useFloating, offset, shift, flip, size, autoUpdate } from '@floating-ui/react';
|
|
9
9
|
import { ResponsiveLine } from '@nivo/line';
|
|
@@ -1417,20 +1417,21 @@ const PermissionRequests = () => {
|
|
|
1417
1417
|
const [expanded, setExpanded] = useState(false);
|
|
1418
1418
|
const [permissionRequests, setPermissionRequests] = useState([]);
|
|
1419
1419
|
const canUpdateCallPermissions = useHasPermissions(OwnCapability.UPDATE_CALL_PERMISSIONS);
|
|
1420
|
+
const localUserId = localParticipant?.userId;
|
|
1420
1421
|
useEffect(() => {
|
|
1421
1422
|
if (!call || !canUpdateCallPermissions)
|
|
1422
1423
|
return;
|
|
1423
1424
|
const unsubscribe = call.on('call.permission_request', (event) => {
|
|
1424
1425
|
if (event.type !== 'call.permission_request')
|
|
1425
1426
|
return;
|
|
1426
|
-
if (event.user.id !==
|
|
1427
|
+
if (event.user.id !== localUserId) {
|
|
1427
1428
|
setPermissionRequests((requests) => [...requests, event].sort((a, b) => byNameOrId(a.user, b.user)));
|
|
1428
1429
|
}
|
|
1429
1430
|
});
|
|
1430
1431
|
return () => {
|
|
1431
1432
|
unsubscribe();
|
|
1432
1433
|
};
|
|
1433
|
-
}, [call, canUpdateCallPermissions,
|
|
1434
|
+
}, [call, canUpdateCallPermissions, localUserId]);
|
|
1434
1435
|
const handleUpdatePermission = (request, type) => {
|
|
1435
1436
|
return async () => {
|
|
1436
1437
|
const { user, permissions } = request;
|
|
@@ -1525,128 +1526,6 @@ const VideoPreview = ({ className, mirror = true, DisabledVideoPreview = Default
|
|
|
1525
1526
|
return (jsx("div", { className: clsx('str-video__video-preview-container', className), children: contents }));
|
|
1526
1527
|
};
|
|
1527
1528
|
|
|
1528
|
-
const DebugParticipantPublishQuality = (props) => {
|
|
1529
|
-
const { call, participant } = props;
|
|
1530
|
-
const [quality, setQuality] = useState();
|
|
1531
|
-
const [publishStats, setPublishStats] = useState(() => ({
|
|
1532
|
-
f: true,
|
|
1533
|
-
h: true,
|
|
1534
|
-
q: true,
|
|
1535
|
-
}));
|
|
1536
|
-
useEffect(() => {
|
|
1537
|
-
return call.on('changePublishQuality', (event) => {
|
|
1538
|
-
if (event.eventPayload.oneofKind !== 'changePublishQuality')
|
|
1539
|
-
return;
|
|
1540
|
-
const { videoSenders } = event.eventPayload.changePublishQuality;
|
|
1541
|
-
// FIXME OL: support additional layers (like screenshare)
|
|
1542
|
-
const [videoLayer] = videoSenders.map(({ layers }) => {
|
|
1543
|
-
return layers.map((l) => ({ [l.name]: l.active }));
|
|
1544
|
-
});
|
|
1545
|
-
setPublishStats((s) => ({
|
|
1546
|
-
...s,
|
|
1547
|
-
...videoLayer,
|
|
1548
|
-
}));
|
|
1549
|
-
});
|
|
1550
|
-
}, [call]);
|
|
1551
|
-
return (jsxs("select", { title: `Published tracks: ${JSON.stringify(publishStats)}`, value: quality, onChange: (e) => {
|
|
1552
|
-
const value = e.target.value;
|
|
1553
|
-
setQuality(value);
|
|
1554
|
-
let w = 960;
|
|
1555
|
-
let h = 540;
|
|
1556
|
-
if (value === 'h') {
|
|
1557
|
-
w = w / 2; // 480
|
|
1558
|
-
h = h / 2; // 270
|
|
1559
|
-
}
|
|
1560
|
-
else if (value === 'q') {
|
|
1561
|
-
w = w / 4; // 240
|
|
1562
|
-
h = h / 4; // 135
|
|
1563
|
-
}
|
|
1564
|
-
call.updateSubscriptionsPartial('video', {
|
|
1565
|
-
[participant.sessionId]: {
|
|
1566
|
-
dimension: {
|
|
1567
|
-
width: w,
|
|
1568
|
-
height: h,
|
|
1569
|
-
},
|
|
1570
|
-
},
|
|
1571
|
-
});
|
|
1572
|
-
}, children: [jsx("option", { value: "f", children: "High (f)" }), jsx("option", { value: "h", children: "Medium (h)" }), jsx("option", { value: "q", children: "Low (q)" })] }));
|
|
1573
|
-
};
|
|
1574
|
-
|
|
1575
|
-
const DebugStatsView = (props) => {
|
|
1576
|
-
const { call, mediaStream, sessionId, userId } = props;
|
|
1577
|
-
const { useCallStatsReport } = useCallStateHooks();
|
|
1578
|
-
const callStatsReport = useCallStatsReport();
|
|
1579
|
-
useEffect(() => {
|
|
1580
|
-
call.startReportingStatsFor(sessionId);
|
|
1581
|
-
return () => {
|
|
1582
|
-
call.stopReportingStatsFor(sessionId);
|
|
1583
|
-
};
|
|
1584
|
-
}, [call, sessionId]);
|
|
1585
|
-
const reportForTracks = callStatsReport?.participants[sessionId];
|
|
1586
|
-
const trackStats = reportForTracks?.flatMap((report) => report.streams);
|
|
1587
|
-
const previousWidth = useRef({ f: 0, h: 0, q: 0 });
|
|
1588
|
-
const previousHeight = useRef({ f: 0, h: 0, q: 0 });
|
|
1589
|
-
trackStats?.forEach((track) => {
|
|
1590
|
-
if (track.kind !== 'video')
|
|
1591
|
-
return;
|
|
1592
|
-
const { frameWidth = 0, frameHeight = 0, rid = '' } = track;
|
|
1593
|
-
if (frameWidth !== previousWidth.current[rid] ||
|
|
1594
|
-
frameHeight !== previousHeight.current[rid]) {
|
|
1595
|
-
const trackSize = `${frameWidth}x${frameHeight}`;
|
|
1596
|
-
console.log(`Track stats (${userId}/${sessionId}): ${rid}(${trackSize})`);
|
|
1597
|
-
previousWidth.current[rid] = frameWidth;
|
|
1598
|
-
previousHeight.current[rid] = frameHeight;
|
|
1599
|
-
}
|
|
1600
|
-
});
|
|
1601
|
-
const { refs, strategy, y, x } = useFloatingUIPreset({
|
|
1602
|
-
placement: 'top',
|
|
1603
|
-
strategy: 'absolute',
|
|
1604
|
-
});
|
|
1605
|
-
const [isPopperOpen, setIsPopperOpen] = useState(false);
|
|
1606
|
-
const [videoTrack] = mediaStream?.getVideoTracks() ?? [];
|
|
1607
|
-
const settings = videoTrack?.getSettings();
|
|
1608
|
-
return (jsxs(Fragment, { children: [jsx("span", { className: "str-video__debug__track-stats-icon", tabIndex: 0, ref: refs.setReference, title: settings &&
|
|
1609
|
-
`${settings.width}x${settings.height}@${Math.round(settings.frameRate || 0)}`, onClick: () => {
|
|
1610
|
-
setIsPopperOpen((v) => !v);
|
|
1611
|
-
} }), isPopperOpen && (jsxs("div", { className: "str-video__debug__track-stats str-video__call-stats", ref: refs.setFloating, style: {
|
|
1612
|
-
position: strategy,
|
|
1613
|
-
top: y ?? 0,
|
|
1614
|
-
left: x ?? 0,
|
|
1615
|
-
overflowY: 'auto',
|
|
1616
|
-
}, children: [jsx("h3", { children: "Participant stats" }), jsx("div", { className: "str-video__call-stats__card-container", children: trackStats
|
|
1617
|
-
?.map((track) => {
|
|
1618
|
-
if (track.kind === 'video') {
|
|
1619
|
-
return (jsx(StatCard, { label: `${track.kind}: ${track.codec} ` +
|
|
1620
|
-
(track.rid ? ` (${track.rid})` : ''), value: `${track.frameWidth || 0}x${track.frameHeight || 0}@${track.framesPerSecond || 0}fps` }, `${track.rid}/${track.ssrc}/${track.codec}/${track.kind}`));
|
|
1621
|
-
}
|
|
1622
|
-
else if (track.kind === 'audio') {
|
|
1623
|
-
return (jsx(StatCard, { label: track.codec || 'N/A', value: `Jitter: ${track.jitter || 0}ms` }, `${track.ssrc}/${track.codec}/${track.kind}`));
|
|
1624
|
-
}
|
|
1625
|
-
return null;
|
|
1626
|
-
})
|
|
1627
|
-
.filter(Boolean) }), reportForTracks?.map((report, index) => (jsx("pre", { children: JSON.stringify(unwrapStats(report.rawStats), null, 2) }, index)))] }))] }));
|
|
1628
|
-
};
|
|
1629
|
-
const unwrapStats = (rawStats) => {
|
|
1630
|
-
const decodedStats = {};
|
|
1631
|
-
rawStats?.forEach((s) => {
|
|
1632
|
-
decodedStats[s.id] = s;
|
|
1633
|
-
});
|
|
1634
|
-
return decodedStats;
|
|
1635
|
-
};
|
|
1636
|
-
|
|
1637
|
-
const useQueryParams = () => {
|
|
1638
|
-
return useMemo(() => typeof window === 'undefined'
|
|
1639
|
-
? null
|
|
1640
|
-
: new URLSearchParams(window.location.search), []);
|
|
1641
|
-
};
|
|
1642
|
-
/**
|
|
1643
|
-
* Internal purpose hook. Enables certain development mode tools.
|
|
1644
|
-
*/
|
|
1645
|
-
const useIsDebugMode = () => {
|
|
1646
|
-
const params = useQueryParams();
|
|
1647
|
-
return !!params?.get('debug');
|
|
1648
|
-
};
|
|
1649
|
-
|
|
1650
1529
|
const ParticipantViewContext = createContext(undefined);
|
|
1651
1530
|
const useParticipantViewContext = () => useContext(ParticipantViewContext);
|
|
1652
1531
|
|
|
@@ -1674,18 +1553,18 @@ const DefaultParticipantViewUI = ({ indicatorsVisible = true, menuPlacement = 'b
|
|
|
1674
1553
|
};
|
|
1675
1554
|
const ParticipantDetails = ({ indicatorsVisible = true, }) => {
|
|
1676
1555
|
const { participant } = useParticipantViewContext();
|
|
1677
|
-
const { isDominantSpeaker, isLocalParticipant, connectionQuality, publishedTracks, pin, sessionId, name, userId,
|
|
1556
|
+
const { isDominantSpeaker, isLocalParticipant, connectionQuality, publishedTracks, pin, sessionId, name, userId, } = participant;
|
|
1678
1557
|
const call = useCall();
|
|
1558
|
+
const { t } = useI18n();
|
|
1679
1559
|
const connectionQualityAsString = !!connectionQuality &&
|
|
1680
1560
|
SfuModels.ConnectionQuality[connectionQuality].toLowerCase();
|
|
1681
1561
|
const hasAudio = publishedTracks.includes(SfuModels.TrackType.AUDIO);
|
|
1682
1562
|
const hasVideo = publishedTracks.includes(SfuModels.TrackType.VIDEO);
|
|
1683
1563
|
const canUnpin = !!pin && pin.isLocalPin;
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
jsx("span", { title: "Unpin", onClick: () => call?.unpin(sessionId), style: { cursor: 'pointer' }, className: "str-video__participant-details__name--pinned" }))] }), isDebugMode && (jsxs(Fragment, { children: [jsx(DebugParticipantPublishQuality, { participant: participant, call: call }), jsx(DebugStatsView, { call: call, sessionId: sessionId, userId: userId, mediaStream: videoStream })] }))] }));
|
|
1564
|
+
return (jsx("div", { className: "str-video__participant-details", children: jsxs("span", { className: "str-video__participant-details__name", children: [name || userId, indicatorsVisible && isDominantSpeaker && (jsx("span", { className: "str-video__participant-details__name--dominant_speaker", title: t('Dominant speaker') })), indicatorsVisible && (jsx(Notification, { isVisible: isLocalParticipant &&
|
|
1565
|
+
connectionQuality === SfuModels.ConnectionQuality.POOR, message: t('Poor connection quality'), children: connectionQualityAsString && (jsx("span", { className: clsx('str-video__participant-details__connection-quality', `str-video__participant-details__connection-quality--${connectionQualityAsString}`), title: connectionQualityAsString })) })), indicatorsVisible && !hasAudio && (jsx("span", { className: "str-video__participant-details__name--audio-muted" })), indicatorsVisible && !hasVideo && (jsx("span", { className: "str-video__participant-details__name--video-muted" })), indicatorsVisible && canUnpin && (
|
|
1566
|
+
// TODO: remove this monstrosity once we have a proper design
|
|
1567
|
+
jsx("span", { title: t('Unpin'), onClick: () => call?.unpin(sessionId), style: { cursor: 'pointer' }, className: "str-video__participant-details__name--pinned" }))] }) }));
|
|
1689
1568
|
};
|
|
1690
1569
|
|
|
1691
1570
|
const ParticipantView = forwardRef(({ participant, trackType = 'videoTrack', muteAudio, refs: { setVideoElement, setVideoPlaceholderElement } = {}, className, VideoPlaceholder, ParticipantViewUI = DefaultParticipantViewUI, }, ref) => {
|
|
@@ -1825,6 +1704,8 @@ var en = {
|
|
|
1825
1704
|
Leave: Leave,
|
|
1826
1705
|
"{{ direction }} fullscreen": "{{ direction }} fullscreen",
|
|
1827
1706
|
"{{ direction }} picture-in-picture": "{{ direction }} picture-in-picture",
|
|
1707
|
+
"Dominant Speaker": "Dominant Speaker",
|
|
1708
|
+
"Poor connection quality": "Poor connection quality. Please check your internet connection.",
|
|
1828
1709
|
Participants: Participants,
|
|
1829
1710
|
Anonymous: Anonymous,
|
|
1830
1711
|
"No participants found": "No participants found",
|
|
@@ -2114,7 +1995,7 @@ const VerticalScrollButtons = ({ scrollWrapper, }) => {
|
|
|
2114
1995
|
};
|
|
2115
1996
|
const hasScreenShare = (p) => !!p?.publishedTracks.includes(SfuModels.TrackType.SCREEN_SHARE);
|
|
2116
1997
|
|
|
2117
|
-
const [major, minor, patch] = ("0.4.
|
|
1998
|
+
const [major, minor, patch] = ("0.4.8" ).split('.');
|
|
2118
1999
|
setSdkInfo({
|
|
2119
2000
|
type: SfuModels.SdkType.REACT,
|
|
2120
2001
|
major,
|
|
@@ -2122,5 +2003,5 @@ setSdkInfo({
|
|
|
2122
2003
|
patch,
|
|
2123
2004
|
});
|
|
2124
2005
|
|
|
2125
|
-
export { AcceptCallButton, Audio, Avatar, AvatarFallback, BaseVideo, CallControls, CallParticipantListing, CallParticipantListingItem, CallParticipantsList, CallPreview, CallRecordingList, CallRecordingListHeader, CallRecordingListItem, CallStatsButton, CancelCallButton, CompositeButton, CopyToClipboardButton, CopyToClipboardButtonWithPopup, DefaultParticipantViewUI, DefaultReactionsMenu, DefaultScreenShareOverlay, DefaultVideoPlaceholder, DeviceSelector, DeviceSelectorAudioInput, DeviceSelectorAudioOutput, DeviceSelectorVideo, DeviceSettings, EmptyCallRecordingListing, GenericMenu, GenericMenuButtonItem, Icon, IconButton, LivestreamLayout, LoadingCallRecordingListing, LoadingIndicator, MenuToggle, Notification, PaginatedGridLayout, ParticipantActionsContextMenu, ParticipantDetails, ParticipantView, ParticipantViewContext, ParticipantsAudio, PermissionNotification, PermissionRequestList, PermissionRequests, ReactionsButton, RecordCallButton, RingingCall, RingingCallControls, ScreenShareButton, SearchInput, SearchResults, SpeakerLayout, SpeakingWhileMutedNotification, StreamCall, StreamTheme, StreamVideo, TextButton, ToggleAudioOutputButton, ToggleAudioPreviewButton, ToggleAudioPublishingButton, ToggleVideoPreviewButton, ToggleVideoPublishingButton, Tooltip, Video$1 as Video, VideoPreview, WithTooltip, defaultReactions, translations, useHasBrowserPermissions, useHorizontalScrollPosition, useParticipantViewContext, usePersistedDevicePreferences, useRequestPermission, useTrackElementVisibility, useVerticalScrollPosition };
|
|
2006
|
+
export { AcceptCallButton, Audio, Avatar, AvatarFallback, BaseVideo, CallControls, CallParticipantListing, CallParticipantListingItem, CallParticipantsList, CallPreview, CallRecordingList, CallRecordingListHeader, CallRecordingListItem, CallStats, CallStatsButton, CallStatsLatencyChart, CancelCallButton, CompositeButton, CopyToClipboardButton, CopyToClipboardButtonWithPopup, DefaultParticipantViewUI, DefaultReactionsMenu, DefaultScreenShareOverlay, DefaultVideoPlaceholder, DeviceSelector, DeviceSelectorAudioInput, DeviceSelectorAudioOutput, DeviceSelectorVideo, DeviceSettings, EmptyCallRecordingListing, GenericMenu, GenericMenuButtonItem, Icon, IconButton, LivestreamLayout, LoadingCallRecordingListing, LoadingIndicator, MenuToggle, Notification, PaginatedGridLayout, ParticipantActionsContextMenu, ParticipantDetails, ParticipantView, ParticipantViewContext, ParticipantsAudio, PermissionNotification, PermissionRequestList, PermissionRequests, ReactionsButton, RecordCallButton, RingingCall, RingingCallControls, ScreenShareButton, SearchInput, SearchResults, SpeakerLayout, SpeakingWhileMutedNotification, StatCard, StreamCall, StreamTheme, StreamVideo, TextButton, ToggleAudioOutputButton, ToggleAudioPreviewButton, ToggleAudioPublishingButton, ToggleVideoPreviewButton, ToggleVideoPublishingButton, Tooltip, Video$1 as Video, VideoPreview, WithTooltip, defaultReactions, translations, useHasBrowserPermissions, useHorizontalScrollPosition, useParticipantViewContext, usePersistedDevicePreferences, useRequestPermission, useTrackElementVisibility, useVerticalScrollPosition };
|
|
2126
2007
|
//# sourceMappingURL=index.es.js.map
|