Skip to content

Commit a69f3bf

Browse files
author
Daily Autobot
committed
Merge branch 'main' into daily-js-releases
2 parents 6461e5e + c173c06 commit a69f3bf

File tree

6 files changed

+129
-3
lines changed

6 files changed

+129
-3
lines changed

src/DailyNetwork.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,19 @@ import React, { useCallback, useEffect } from 'react';
55

66
import { useDaily } from './hooks/useDaily';
77
import { useDailyEvent } from './hooks/useDailyEvent';
8+
import { arraysDeepEqual } from './lib/customDeepEqual';
89
import { jotaiDebugLabel } from './lib/jotai-custom';
910

1011
export const topologyState = atom<DailyNetworkTopology | 'none'>('none');
1112
topologyState.debugLabel = jotaiDebugLabel('topology');
13+
export const networkState = atom<DailyNetworkStats['networkState']>('unknown');
14+
export const networkStateReasons = atom<
15+
DailyNetworkStats['networkStateReasons']
16+
>([]);
17+
// @deprecated
1218
export const networkQualityState = atom<DailyNetworkStats['quality']>(100);
1319
networkQualityState.debugLabel = jotaiDebugLabel('network-quality');
20+
// @deprecated
1421
export const networkThresholdState =
1522
atom<DailyNetworkStats['threshold']>('good');
1623
networkThresholdState.debugLabel = jotaiDebugLabel('network-threshold');
@@ -52,6 +59,22 @@ export const DailyNetwork: React.FC<React.PropsWithChildren<{}>> = ({
5259
'network-quality-change',
5360
useAtomCallback(
5461
useCallback((_get, set, ev) => {
62+
set(
63+
networkState,
64+
(prevNetworkState: DailyNetworkStats['networkState']) =>
65+
prevNetworkState !== ev.networkState
66+
? ev.networkState
67+
: prevNetworkState
68+
);
69+
set(
70+
networkStateReasons,
71+
(prevReasons: DailyNetworkStats['networkStateReasons']) => {
72+
const curReasons = ev.networkStateReasons ?? [];
73+
return !arraysDeepEqual(prevReasons, curReasons)
74+
? curReasons
75+
: prevReasons;
76+
}
77+
);
5578
set(networkQualityState, (prevQuality: DailyNetworkStats['quality']) =>
5679
prevQuality !== ev.quality ? ev.quality : prevQuality
5780
);
@@ -69,6 +92,8 @@ export const DailyNetwork: React.FC<React.PropsWithChildren<{}>> = ({
6992
useAtomCallback(
7093
useCallback((_get, set) => {
7194
set(topologyState, 'none');
95+
set(networkState, 'unknown');
96+
set(networkStateReasons, []);
7297
set(networkQualityState, 100);
7398
set(networkThresholdState, 'good');
7499
}, [])

src/hooks/useNetwork.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { useCallback, useDebugValue } from 'react';
44

55
import {
66
networkQualityState,
7+
networkState as netState,
8+
networkStateReasons as netReasons,
79
networkThresholdState,
810
topologyState,
911
} from '../DailyNetwork';
@@ -26,6 +28,8 @@ export const useNetwork = ({
2628
const daily = useDaily();
2729

2830
const topology = useAtomValue(topologyState);
31+
const networkState = useAtomValue(netState);
32+
const networkStateReasons = useAtomValue(netReasons);
2933
const quality = useAtomValue(networkQualityState);
3034
const threshold = useAtomValue(networkThresholdState);
3135

@@ -55,6 +59,8 @@ export const useNetwork = ({
5559

5660
const result = {
5761
getStats,
62+
networkState,
63+
networkStateReasons,
5864
quality,
5965
threshold,
6066
topology,

test/.test-utils/mocks.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const mockParticipant = (p: Partial<DailyParticipant> = {}): DailyPartici
1616
local: false,
1717
owner: false,
1818
permissions: {
19+
canReceive: { base: true },
1920
canSend: true,
2021
hasPresence: true,
2122
canAdmin: false

test/hooks/useMediaTrack.test.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,12 @@ const participantBase: DailyParticipant = {
5252
joined_at: faker.date.recent(),
5353
local: false,
5454
owner: false,
55-
permissions: { canSend: true, hasPresence: true, canAdmin: false },
55+
permissions: {
56+
canReceive: { base: true },
57+
canSend: true,
58+
hasPresence: true,
59+
canAdmin: false,
60+
},
5661
record: false,
5762
screen: false,
5863
screen_info: {},

test/hooks/useNetwork.test.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,22 +54,29 @@ const createWrapper =
5454
<DailyProvider callObject={callObject}>{children}</DailyProvider>;
5555

5656
describe('useNetwork', () => {
57-
it('returns getStats method, quality, threshold & topology with perfect defaults', () => {
57+
it('returns getStats method with perfect defaults', () => {
5858
const { result } = renderHook(() => useNetwork(), {
5959
wrapper: createWrapper(),
6060
});
6161
expect(result.current).toHaveProperty('getStats');
6262
expect(typeof result.current.getStats).toBe('function');
6363
expect(result.current).toHaveProperty('quality');
6464
expect(result.current.quality).toBe(100);
65+
expect(result.current).toHaveProperty('networkState');
66+
expect(result.current.networkState).toBe('unknown');
67+
expect(result.current).toHaveProperty('networkStateReasons');
68+
expect(result.current.networkStateReasons).toStrictEqual([]);
6569
expect(result.current).toHaveProperty('threshold');
6670
expect(result.current.threshold).toBe('good');
6771
expect(result.current).toHaveProperty('topology');
6872
expect(result.current.topology).toBe('none');
6973
});
7074
it('getStats calls getNetworkStats internally', async () => {
7175
const mockStats: DailyNetworkStats = {
76+
networkState: 'good',
77+
networkStateReasons: [],
7278
quality: 99,
79+
threshold: 'good',
7380
stats: {
7481
latest: {
7582
recvBitsPerSecond: 1000000,
@@ -102,7 +109,6 @@ describe('useNetwork', () => {
102109
worstAudioSendJitter: 0,
103110
averageNetworkRoundTripTime: 0.07171428571428572,
104111
},
105-
threshold: 'good',
106112
};
107113
const daily = Daily.createCallObject();
108114
(
@@ -184,14 +190,19 @@ describe('useNetwork', () => {
184190
const event: DailyEvent = 'network-quality-change';
185191
const payload: DailyEventObjectNetworkQualityEvent = mockEvent({
186192
action: 'network-quality-change',
193+
networkState: 'bad',
194+
networkStateReasons: ['sendPacketLoss'],
187195
quality: 80,
188196
threshold: 'low',
197+
stats: {},
189198
});
190199
act(() => {
191200
// @ts-ignore
192201
daily.emit(event, payload);
193202
});
194203
await waitFor(() => {
204+
expect(result.current.networkState).toBe('bad');
205+
expect(result.current.networkStateReasons).toEqual(['sendPacketLoss']);
195206
expect(result.current.quality).toBe(80);
196207
expect(result.current.threshold).toBe('low');
197208
expect(onNetworkQualityChange).toHaveBeenCalledWith(payload);

test/hooks/usePermissions.test.tsx

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,24 @@ const createWrapper =
4040
({ children }) =>
4141
<DailyProvider callObject={callObject}>{children}</DailyProvider>;
4242

43+
const canReceivePermissions = {
44+
base: {
45+
video: false,
46+
audio: true,
47+
screenVideo: false,
48+
screenAudio: true,
49+
customVideo: { '*': false },
50+
customAudio: { '*': true },
51+
},
52+
};
53+
4354
describe('usePermissions', () => {
4455
beforeEach(() => {
4556
jest.clearAllMocks();
4657
});
4758
it('returns permissions, as is', async () => {
4859
const permissions = {
60+
canReceive: canReceivePermissions,
4961
canSend: false,
5062
hasPresence: true,
5163
canAdmin: false,
@@ -71,6 +83,7 @@ describe('usePermissions', () => {
7183
local: mockParticipant({
7284
local: true,
7385
permissions: {
86+
canReceive: canReceivePermissions,
7487
canSend: true,
7588
hasPresence: true,
7689
canAdmin: false,
@@ -95,6 +108,7 @@ describe('usePermissions', () => {
95108
local: mockParticipant({
96109
local: true,
97110
permissions: {
111+
canReceive: canReceivePermissions,
98112
canSend: false,
99113
hasPresence: true,
100114
canAdmin: false,
@@ -119,6 +133,7 @@ describe('usePermissions', () => {
119133
local: mockParticipant({
120134
local: true,
121135
permissions: {
136+
canReceive: canReceivePermissions,
122137
canSend: new Set(['audio', 'customAudio', 'screenAudio']),
123138
hasPresence: true,
124139
canAdmin: false,
@@ -145,6 +160,7 @@ describe('usePermissions', () => {
145160
local: mockParticipant({
146161
local: true,
147162
permissions: {
163+
canReceive: canReceivePermissions,
148164
canSend: true,
149165
hasPresence: true,
150166
canAdmin: false,
@@ -164,6 +180,7 @@ describe('usePermissions', () => {
164180
local: mockParticipant({
165181
local: true,
166182
permissions: {
183+
canReceive: canReceivePermissions,
167184
canSend: true,
168185
hasPresence: false,
169186
canAdmin: false,
@@ -185,6 +202,7 @@ describe('usePermissions', () => {
185202
local: mockParticipant({
186203
local: true,
187204
permissions: {
205+
canReceive: canReceivePermissions,
188206
canSend: true,
189207
hasPresence: true,
190208
canAdmin: true,
@@ -206,6 +224,7 @@ describe('usePermissions', () => {
206224
local: mockParticipant({
207225
local: true,
208226
permissions: {
227+
canReceive: canReceivePermissions,
209228
canSend: true,
210229
hasPresence: true,
211230
canAdmin: false,
@@ -227,6 +246,7 @@ describe('usePermissions', () => {
227246
local: mockParticipant({
228247
local: true,
229248
permissions: {
249+
canReceive: canReceivePermissions,
230250
canSend: true,
231251
hasPresence: true,
232252
canAdmin: new Set(['streaming', 'transcription']),
@@ -249,6 +269,7 @@ describe('usePermissions', () => {
249269
const mockRemoteParticipant = mockParticipant({
250270
local: false,
251271
permissions: {
272+
canReceive: canReceivePermissions,
252273
canSend: true,
253274
hasPresence: true,
254275
canAdmin: false,
@@ -258,6 +279,7 @@ describe('usePermissions', () => {
258279
local: mockParticipant({
259280
local: true,
260281
permissions: {
282+
canReceive: canReceivePermissions,
261283
canSend: true,
262284
hasPresence: false,
263285
canAdmin: false,
@@ -280,6 +302,7 @@ describe('usePermissions', () => {
280302
const mockRemoteParticipant = mockParticipant({
281303
local: false,
282304
permissions: {
305+
canReceive: canReceivePermissions,
283306
canSend: true,
284307
hasPresence: false,
285308
canAdmin: false,
@@ -289,6 +312,7 @@ describe('usePermissions', () => {
289312
local: mockParticipant({
290313
local: true,
291314
permissions: {
315+
canReceive: canReceivePermissions,
292316
canSend: true,
293317
hasPresence: false,
294318
canAdmin: false,
@@ -311,6 +335,7 @@ describe('usePermissions', () => {
311335
const mockRemoteParticipant = mockParticipant({
312336
local: false,
313337
permissions: {
338+
canReceive: canReceivePermissions,
314339
canSend: new Set(['audio', 'customAudio', 'screenAudio']),
315340
hasPresence: true,
316341
canAdmin: false,
@@ -320,6 +345,7 @@ describe('usePermissions', () => {
320345
local: mockParticipant({
321346
local: true,
322347
permissions: {
348+
canReceive: canReceivePermissions,
323349
canSend: true,
324350
hasPresence: true,
325351
canAdmin: false,
@@ -347,6 +373,7 @@ describe('usePermissions', () => {
347373
const mockRemoteParticipant = mockParticipant({
348374
local: false,
349375
permissions: {
376+
canReceive: canReceivePermissions,
350377
canSend: true,
351378
hasPresence: true,
352379
canAdmin: new Set(['streaming', 'transcription']),
@@ -356,6 +383,7 @@ describe('usePermissions', () => {
356383
local: mockParticipant({
357384
local: true,
358385
permissions: {
386+
canReceive: canReceivePermissions,
359387
canSend: true,
360388
hasPresence: true,
361389
canAdmin: false,
@@ -375,5 +403,55 @@ describe('usePermissions', () => {
375403
expect(result.current.canAdminTranscription).toEqual(true);
376404
});
377405
});
406+
it('returns canReceive permissions', async () => {
407+
const daily = Daily.createCallObject();
408+
const mockRemoteParticipant = mockParticipant({
409+
local: false,
410+
permissions: {
411+
canReceive: canReceivePermissions,
412+
canSend: true,
413+
hasPresence: true,
414+
canAdmin: new Set(['streaming', 'transcription']),
415+
},
416+
});
417+
(daily.participants as jest.Mock).mockImplementation(() => ({
418+
local: mockParticipant({
419+
local: true,
420+
permissions: {
421+
canReceive: canReceivePermissions,
422+
canSend: true,
423+
hasPresence: true,
424+
canAdmin: false,
425+
},
426+
}),
427+
[mockRemoteParticipant.session_id]: mockRemoteParticipant,
428+
}));
429+
const { result } = renderHook(
430+
() => usePermissions(mockRemoteParticipant.session_id),
431+
{
432+
wrapper: createWrapper(daily),
433+
}
434+
);
435+
await waitFor(() => {
436+
const canReceive = result.current.permissions.canReceive;
437+
expect(canReceive).toBeDefined();
438+
expect(typeof canReceive.base).toEqual('object');
439+
if (typeof canReceive.base !== 'object') {
440+
return;
441+
}
442+
expect(canReceive.base?.video).toEqual(false);
443+
expect(canReceive.base?.audio).toEqual(true);
444+
expect(canReceive.base?.screenVideo).toEqual(false);
445+
expect(canReceive.base?.screenAudio).toEqual(true);
446+
expect(canReceive.base?.customVideo).toBeDefined();
447+
if (typeof canReceive.base.customVideo !== 'object') {
448+
expect(canReceive.base.customVideo['*']).toEqual(false);
449+
}
450+
expect(canReceive.base?.customAudio).toBeDefined();
451+
if (typeof canReceive.base.customAudio !== 'object') {
452+
expect(canReceive.base.customAudio['*']).toEqual(false);
453+
}
454+
});
455+
});
378456
});
379457
});

0 commit comments

Comments
 (0)