@ray-js/ipc-player-integration 0.0.53-beta.6 → 0.0.53-beta.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/lib/ctx/ctx.autoClarity.test.d.ts +1 -0
- package/lib/ctx/ctx.autoClarity.test.js +150 -0
- package/lib/ctx/ctx.js +52 -5
- package/lib/ui/ui.js +41 -2
- package/lib/utils/ttt.autoClarity.test.d.ts +1 -0
- package/lib/utils/ttt.autoClarity.test.js +75 -0
- package/lib/utils/ttt.d.ts +2 -0
- package/lib/utils/ttt.js +26 -2
- package/lib/widgets/captureResult/captureResult.js +1 -4
- package/lib/widgets/captureResult/captureResult.less +37 -22
- package/lib/widgets/captureResult/captureResult.test.js +3 -2
- package/lib/widgets/videoBitKBP/videoBitKBP.js +12 -9
- package/lib/widgets/videoBitKBP/videoBitKBP.less +3 -0
- package/lib/widgets/videoBitKBP/videoBitKBP.test.d.ts +1 -0
- package/lib/widgets/videoBitKBP/videoBitKBP.test.js +81 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
|
+
import { act, renderHook } from '@testing-library/react-hooks';
|
|
3
|
+
import { ClarityType } from '@ray-js/ray-ipc-utils/lib/interface';
|
|
4
|
+
import { createUseCtx } from './ctx';
|
|
5
|
+
import { useStore } from './store';
|
|
6
|
+
import { PlayState } from '../interface';
|
|
7
|
+
import { getCachedAutoClarity, setCachedAutoClarity, subscribeClarityChanged } from '../utils/ttt';
|
|
8
|
+
jest.mock('@ray-js/ray', () => ({}));
|
|
9
|
+
jest.mock('@ray-js/ray-ipc-utils/lib/interface', () => ({
|
|
10
|
+
ClarityType: {
|
|
11
|
+
SS: 'SS',
|
|
12
|
+
SD: 'SD',
|
|
13
|
+
HD: 'HD',
|
|
14
|
+
UD: 'UD',
|
|
15
|
+
SSP: 'SSP',
|
|
16
|
+
AUTO: 'AUTO',
|
|
17
|
+
AUDIO: 'AUDIO'
|
|
18
|
+
},
|
|
19
|
+
IntercomMode: {
|
|
20
|
+
OneWay: 'OneWay',
|
|
21
|
+
TwoWay: 'TwoWay'
|
|
22
|
+
}
|
|
23
|
+
}));
|
|
24
|
+
jest.mock('../i18n', () => ({
|
|
25
|
+
__esModule: true,
|
|
26
|
+
default: {
|
|
27
|
+
getLang: key => key
|
|
28
|
+
}
|
|
29
|
+
}));
|
|
30
|
+
jest.mock('./multiCameraCtx', () => ({
|
|
31
|
+
isMultiCameraTileSupported: () => false,
|
|
32
|
+
useMultiCameraCtx: () => ({})
|
|
33
|
+
}));
|
|
34
|
+
jest.mock('../utils/ttt', () => ({
|
|
35
|
+
getCachedAutoClarity: jest.fn(),
|
|
36
|
+
isClarityChangedSupported: () => true,
|
|
37
|
+
setCachedAutoClarity: jest.fn(),
|
|
38
|
+
subscribeClarityChanged: jest.fn(() => () => undefined)
|
|
39
|
+
}));
|
|
40
|
+
const cameraState = resolution => ({
|
|
41
|
+
resolution,
|
|
42
|
+
resolutionList: [ClarityType.HD, ClarityType.SD],
|
|
43
|
+
mute: true,
|
|
44
|
+
intercomMode: 'TwoWay',
|
|
45
|
+
isIntercomSupported: false,
|
|
46
|
+
maxZoomSettings: 6
|
|
47
|
+
});
|
|
48
|
+
describe('cached auto clarity restoration', () => {
|
|
49
|
+
beforeEach(() => {
|
|
50
|
+
jest.clearAllMocks();
|
|
51
|
+
});
|
|
52
|
+
const mountContext = resolution => {
|
|
53
|
+
const setClarity = jest.fn();
|
|
54
|
+
const getMemoryState = jest.fn().mockResolvedValue(cameraState(resolution));
|
|
55
|
+
const useCtx = createUseCtx({
|
|
56
|
+
createPlayContext: () => ({
|
|
57
|
+
setClarity
|
|
58
|
+
}),
|
|
59
|
+
getMemoryState,
|
|
60
|
+
setResolutionMemoryState: jest.fn(),
|
|
61
|
+
setMuteMemoryState: jest.fn(),
|
|
62
|
+
authorizeStatus: jest.fn(),
|
|
63
|
+
toast: jest.fn()
|
|
64
|
+
});
|
|
65
|
+
const hook = renderHook(() => {
|
|
66
|
+
const ctx = useCtx({
|
|
67
|
+
devId: 'camera-1'
|
|
68
|
+
});
|
|
69
|
+
const state = useStore({
|
|
70
|
+
resolution: ctx.resolution,
|
|
71
|
+
autoClarity: ctx.autoClarity
|
|
72
|
+
});
|
|
73
|
+
return _objectSpread(_objectSpread({}, ctx), {}, {
|
|
74
|
+
state
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
return _objectSpread(_objectSpread({}, hook), {}, {
|
|
78
|
+
setClarity
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
it('shows last listener value on reopening AUTO and refreshes it after preview', async () => {
|
|
82
|
+
getCachedAutoClarity.mockReturnValue(ClarityType.HD);
|
|
83
|
+
const {
|
|
84
|
+
result,
|
|
85
|
+
setClarity,
|
|
86
|
+
unmount
|
|
87
|
+
} = mountContext(ClarityType.AUTO);
|
|
88
|
+
await act(async () => Promise.resolve());
|
|
89
|
+
expect(result.current.state).toEqual({
|
|
90
|
+
resolution: ClarityType.AUTO,
|
|
91
|
+
autoClarity: ClarityType.HD
|
|
92
|
+
});
|
|
93
|
+
act(() => result.current.setPlayState(PlayState.PLAYING));
|
|
94
|
+
await act(async () => Promise.resolve());
|
|
95
|
+
expect(setClarity).toHaveBeenCalledTimes(1);
|
|
96
|
+
expect(setClarity).toHaveBeenCalledWith(expect.objectContaining({
|
|
97
|
+
clarity: 'auto'
|
|
98
|
+
}));
|
|
99
|
+
const onReport = subscribeClarityChanged.mock.calls[0][1];
|
|
100
|
+
act(() => onReport({
|
|
101
|
+
deviceId: 'camera-1',
|
|
102
|
+
clarity: ClarityType.SD
|
|
103
|
+
}));
|
|
104
|
+
expect(result.current.state.autoClarity).toBe(ClarityType.SD);
|
|
105
|
+
expect(setCachedAutoClarity).toHaveBeenCalledWith('camera-1', ClarityType.SD);
|
|
106
|
+
unmount();
|
|
107
|
+
});
|
|
108
|
+
it('does not restore cached actual clarity in manual mode', async () => {
|
|
109
|
+
getCachedAutoClarity.mockReturnValue(ClarityType.HD);
|
|
110
|
+
const {
|
|
111
|
+
result,
|
|
112
|
+
unmount
|
|
113
|
+
} = mountContext(ClarityType.SD);
|
|
114
|
+
await act(async () => Promise.resolve());
|
|
115
|
+
expect(result.current.state).toEqual({
|
|
116
|
+
resolution: ClarityType.SD,
|
|
117
|
+
autoClarity: null
|
|
118
|
+
});
|
|
119
|
+
expect(getCachedAutoClarity).not.toHaveBeenCalled();
|
|
120
|
+
const onReport = subscribeClarityChanged.mock.calls[0][1];
|
|
121
|
+
act(() => onReport({
|
|
122
|
+
deviceId: 'camera-1',
|
|
123
|
+
clarity: ClarityType.HD
|
|
124
|
+
}));
|
|
125
|
+
expect(result.current.state.autoClarity).toBeNull();
|
|
126
|
+
expect(setCachedAutoClarity).not.toHaveBeenCalled();
|
|
127
|
+
unmount();
|
|
128
|
+
});
|
|
129
|
+
it('requests a fresh report when reopening AUTO without an actual clarity cache', async () => {
|
|
130
|
+
getCachedAutoClarity.mockReturnValue(null);
|
|
131
|
+
const {
|
|
132
|
+
result,
|
|
133
|
+
setClarity,
|
|
134
|
+
unmount
|
|
135
|
+
} = mountContext(ClarityType.AUTO);
|
|
136
|
+
await act(async () => Promise.resolve());
|
|
137
|
+
expect(result.current.state.autoClarity).toBeNull();
|
|
138
|
+
act(() => result.current.setPlayState(PlayState.PLAYING));
|
|
139
|
+
expect(setClarity).toHaveBeenCalledWith(expect.objectContaining({
|
|
140
|
+
clarity: 'auto'
|
|
141
|
+
}));
|
|
142
|
+
const onReport = subscribeClarityChanged.mock.calls[0][1];
|
|
143
|
+
act(() => onReport({
|
|
144
|
+
deviceId: 'camera-1',
|
|
145
|
+
clarity: ClarityType.HD
|
|
146
|
+
}));
|
|
147
|
+
expect(result.current.state.autoClarity).toBe(ClarityType.HD);
|
|
148
|
+
unmount();
|
|
149
|
+
});
|
|
150
|
+
});
|
package/lib/ctx/ctx.js
CHANGED
|
@@ -12,7 +12,7 @@ import { changeIgnoreHideStopPreview } from '../ui/constant';
|
|
|
12
12
|
import { ClarityType } from '@ray-js/ray-ipc-utils/lib/interface';
|
|
13
13
|
import { getEventInstance } from './event';
|
|
14
14
|
import { isMultiCameraTileSupported, useMultiCameraCtx } from './multiCameraCtx';
|
|
15
|
-
import { isClarityChangedSupported, subscribeClarityChanged } from '../utils/ttt';
|
|
15
|
+
import { getCachedAutoClarity, isClarityChangedSupported, setCachedAutoClarity, subscribeClarityChanged } from '../utils/ttt';
|
|
16
16
|
const SAVE_TO_ALBUM = 1;
|
|
17
17
|
export const createUseCtx = _ref => {
|
|
18
18
|
let {
|
|
@@ -110,13 +110,27 @@ export const createUseCtx = _ref => {
|
|
|
110
110
|
_playState: playState,
|
|
111
111
|
currentResolution: resolution
|
|
112
112
|
});
|
|
113
|
+
const restoredAutoRef = useRef(false);
|
|
114
|
+
const refreshedAutoRef = useRef(false);
|
|
115
|
+
const freshAutoClarityRef = useRef(false);
|
|
116
|
+
const pendingAutoSelectionRef = useRef(false);
|
|
117
|
+
const userSelectedResolutionRef = useRef(false);
|
|
113
118
|
useEffect(() => {
|
|
114
119
|
updateAtom(autoClarity, null);
|
|
115
|
-
|
|
120
|
+
restoredAutoRef.current = false;
|
|
121
|
+
refreshedAutoRef.current = false;
|
|
122
|
+
freshAutoClarityRef.current = false;
|
|
123
|
+
userSelectedResolutionRef.current = false;
|
|
124
|
+
if (!devId) return undefined;
|
|
116
125
|
return subscribeClarityChanged(devId, res => {
|
|
126
|
+
if (getDefaultStore().get(resolution) !== ClarityType.AUTO && !pendingAutoSelectionRef.current) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
freshAutoClarityRef.current = true;
|
|
117
130
|
updateAtom(autoClarity, res.clarity);
|
|
131
|
+
setCachedAutoClarity(devId, res.clarity);
|
|
118
132
|
});
|
|
119
|
-
}, [autoClarity,
|
|
133
|
+
}, [autoClarity, devId, resolution]);
|
|
120
134
|
const eventRef = useRef();
|
|
121
135
|
if (!eventRef.current) {
|
|
122
136
|
eventRef.current = getEventInstance();
|
|
@@ -139,6 +153,18 @@ export const createUseCtx = _ref => {
|
|
|
139
153
|
if (resolution !== ClarityType.AUTO || canShowAutoClarity(list)) return resolution;
|
|
140
154
|
return list.find(clarity => clarity !== ClarityType.AUTO) || ClarityType.HD;
|
|
141
155
|
};
|
|
156
|
+
const restoreResolution = (cachedResolution, list) => {
|
|
157
|
+
if (userSelectedResolutionRef.current) return;
|
|
158
|
+
const target = normalizeResolution(cachedResolution, list);
|
|
159
|
+
if (target === ClarityType.AUTO) {
|
|
160
|
+
restoredAutoRef.current = true;
|
|
161
|
+
const cachedClarity = getCachedAutoClarity(devId);
|
|
162
|
+
if (cachedClarity && list.includes(cachedClarity) && !getDefaultStore().get(autoClarity)) {
|
|
163
|
+
updateAtom(autoClarity, cachedClarity);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
_setResolution(target, true);
|
|
167
|
+
};
|
|
142
168
|
useEffect(() => {
|
|
143
169
|
// 初始化获取缓存值
|
|
144
170
|
|
|
@@ -148,7 +174,7 @@ export const createUseCtx = _ref => {
|
|
|
148
174
|
var _res$maxZoomSettings;
|
|
149
175
|
const res = await getMemoryState(devId);
|
|
150
176
|
setResolutionList(withAutoClarity(res.resolutionList));
|
|
151
|
-
|
|
177
|
+
restoreResolution(res.resolution, res.resolutionList);
|
|
152
178
|
_setMute(res.mute, true);
|
|
153
179
|
setIntercomMode(res.intercomMode);
|
|
154
180
|
setIntercomSupported(res.isIntercomSupported);
|
|
@@ -165,7 +191,7 @@ export const createUseCtx = _ref => {
|
|
|
165
191
|
var _res$maxZoomSettings2;
|
|
166
192
|
setResolutionList(withAutoClarity(res.resolutionList));
|
|
167
193
|
// 传true表示值即可,会取播放器的值
|
|
168
|
-
|
|
194
|
+
restoreResolution(res.resolution, res.resolutionList);
|
|
169
195
|
_setMute(res.mute, true);
|
|
170
196
|
setIntercomMode(res.intercomMode);
|
|
171
197
|
setIntercomSupported(res.isIntercomSupported);
|
|
@@ -173,6 +199,18 @@ export const createUseCtx = _ref => {
|
|
|
173
199
|
});
|
|
174
200
|
}
|
|
175
201
|
}, [devId, _playState]);
|
|
202
|
+
useEffect(() => {
|
|
203
|
+
var _IPCPlayerInstance$cu;
|
|
204
|
+
if (!devId || _playState !== PlayState.PLAYING || currentResolution !== ClarityType.AUTO || !restoredAutoRef.current || freshAutoClarityRef.current || refreshedAutoRef.current) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
refreshedAutoRef.current = true;
|
|
208
|
+
// 缓存只保证首屏有上次档位;出流后重申自动,让宿主回报本次实际档位。
|
|
209
|
+
(_IPCPlayerInstance$cu = IPCPlayerInstance.current) === null || _IPCPlayerInstance$cu === void 0 || _IPCPlayerInstance$cu.setClarity({
|
|
210
|
+
clarity: 'auto',
|
|
211
|
+
fail: error => console.warn('res===restore auto clarity fail', error)
|
|
212
|
+
});
|
|
213
|
+
}, [devId, _playState, currentResolution]);
|
|
176
214
|
// 获取content数据
|
|
177
215
|
const getContent = () => {
|
|
178
216
|
const store = getDefaultStore();
|
|
@@ -267,6 +305,13 @@ export const createUseCtx = _ref => {
|
|
|
267
305
|
updateAtom(resolution, target);
|
|
268
306
|
return false;
|
|
269
307
|
}
|
|
308
|
+
userSelectedResolutionRef.current = true;
|
|
309
|
+
// 清晰度事件可能在 setClarity 的 success 回调前到达,进入自动前先清掉上次的值。
|
|
310
|
+
restoredAutoRef.current = false;
|
|
311
|
+
if (target === ClarityType.AUTO) {
|
|
312
|
+
pendingAutoSelectionRef.current = true;
|
|
313
|
+
updateAtom(autoClarity, null);
|
|
314
|
+
}
|
|
270
315
|
return new Promise((resolve, reject) => {
|
|
271
316
|
const clarityMap = {
|
|
272
317
|
[ClarityType.SS]: 'ss',
|
|
@@ -280,11 +325,13 @@ export const createUseCtx = _ref => {
|
|
|
280
325
|
IPCPlayerInstance.current.setClarity({
|
|
281
326
|
clarity: clarityMap[target] || 'normal',
|
|
282
327
|
success: () => {
|
|
328
|
+
pendingAutoSelectionRef.current = false;
|
|
283
329
|
setResolutionMemoryState(devId, target);
|
|
284
330
|
updateAtom(resolution, target);
|
|
285
331
|
resolve(true);
|
|
286
332
|
},
|
|
287
333
|
fail: err => {
|
|
334
|
+
pendingAutoSelectionRef.current = false;
|
|
288
335
|
console.log(err, 'setClarity err');
|
|
289
336
|
// updateAtom(mute, !target);
|
|
290
337
|
reject(err);
|
package/lib/ui/ui.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
|
+
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
3
|
import "core-js/modules/esnext.iterator.constructor.js";
|
|
3
4
|
import "core-js/modules/esnext.iterator.filter.js";
|
|
4
5
|
import "core-js/modules/esnext.iterator.find.js";
|
|
5
6
|
import "core-js/modules/esnext.iterator.map.js";
|
|
7
|
+
import "core-js/modules/esnext.iterator.some.js";
|
|
6
8
|
import React, { useContext, useState, useRef, useMemo, useEffect, useImperativeHandle } from 'react';
|
|
7
9
|
import { View, CoverView, getSystemInfoSync, usePageEvent, setNavigationBarBack, setPageOrientation, getCurrentPages } from '@ray-js/ray';
|
|
8
10
|
import { unstable_batchedUpdates as batchedUpdates } from '@ray-core/ray';
|
|
9
11
|
import clsx from 'clsx';
|
|
10
12
|
import IPCPlayer from '@ray-js/ray-ipc-player';
|
|
11
13
|
import { ipcTTTOperatorLog } from '@ray-js/ray-ipc-utils';
|
|
14
|
+
import { ClarityType } from '@ray-js/ray-ipc-utils/lib/interface';
|
|
12
15
|
import { PlayState, PlayerStreamStatus, MultiCameraScreenMode } from '../interface';
|
|
13
16
|
import { useCtx } from '../ctx/ctx.composition';
|
|
14
17
|
import { useStore, updateAtom, getDefaultStore } from '../ctx/store';
|
|
@@ -18,7 +21,7 @@ import BottomLeftContent from './bottomLeftContent';
|
|
|
18
21
|
import BottomRightContent from './bottomRightContent';
|
|
19
22
|
import TopLeftContent from './topLeftContent';
|
|
20
23
|
import TopRightContent from './topRightContent';
|
|
21
|
-
import { FlowLowTip } from '../widgets';
|
|
24
|
+
import { FlowLowTip, VideoBitKBP } from '../widgets';
|
|
22
25
|
import { useMemoizedFn } from '../hooks';
|
|
23
26
|
import { Storage } from '../utils/storage';
|
|
24
27
|
import './ui.less';
|
|
@@ -27,6 +30,36 @@ import { getNgRawData, getSmartImageQualityState, isLowPhone, notifyOfflineShown
|
|
|
27
30
|
import { getCaptureResultSummary } from '../utils/captureResult';
|
|
28
31
|
import { lensCount } from '../widgets/zoomTurntable/lensSkill';
|
|
29
32
|
import { shouldRenderContent } from './absoluteContent';
|
|
33
|
+
const AutoClarityOnly = _ref => {
|
|
34
|
+
let {
|
|
35
|
+
instance
|
|
36
|
+
} = _ref;
|
|
37
|
+
return /*#__PURE__*/React.createElement(VideoBitKBP, _extends({}, instance, {
|
|
38
|
+
IPCPlayerContext: instance.IPCPlayerInstance,
|
|
39
|
+
className: "top-right-item-container",
|
|
40
|
+
hideKbsMenu: true,
|
|
41
|
+
hideSignalMenu: true
|
|
42
|
+
}));
|
|
43
|
+
};
|
|
44
|
+
const StandaloneAutoClarity = _ref2 => {
|
|
45
|
+
let {
|
|
46
|
+
instance,
|
|
47
|
+
show
|
|
48
|
+
} = _ref2;
|
|
49
|
+
const {
|
|
50
|
+
resolution,
|
|
51
|
+
autoClarity
|
|
52
|
+
} = useStore({
|
|
53
|
+
resolution: instance.resolution,
|
|
54
|
+
autoClarity: instance.autoClarity
|
|
55
|
+
});
|
|
56
|
+
if (!show || resolution !== ClarityType.AUTO || !autoClarity) return null;
|
|
57
|
+
return /*#__PURE__*/React.createElement(TopRightContent, {
|
|
58
|
+
ctx: instance
|
|
59
|
+
}, /*#__PURE__*/React.createElement(AutoClarityOnly, {
|
|
60
|
+
instance: instance
|
|
61
|
+
}));
|
|
62
|
+
};
|
|
30
63
|
function getCtxInstance(instance, devId) {
|
|
31
64
|
if (instance) return instance;
|
|
32
65
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
@@ -1013,6 +1046,7 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
|
|
|
1013
1046
|
};
|
|
1014
1047
|
}, []);
|
|
1015
1048
|
const playerReady = playState === PlayState.PLAYING;
|
|
1049
|
+
const hasVisibleBitrateWidget = topRightContent === null || topRightContent === void 0 ? void 0 : topRightContent.some(item => item.id === 'VideoBitKBP' && !item.hidden);
|
|
1016
1050
|
/**
|
|
1017
1051
|
* 监听当前的zoom比例状态
|
|
1018
1052
|
*/
|
|
@@ -1206,7 +1240,12 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
|
|
|
1206
1240
|
ctx: instance
|
|
1207
1241
|
}, renderTopLeftContent), /*#__PURE__*/React.createElement(TopRightContent, {
|
|
1208
1242
|
ctx: instance
|
|
1209
|
-
}, renderTopRightContent
|
|
1243
|
+
}, renderTopRightContent, !hasVisibleBitrateWidget && /*#__PURE__*/React.createElement(AutoClarityOnly, {
|
|
1244
|
+
instance: instance
|
|
1245
|
+
})))), /*#__PURE__*/React.createElement(StandaloneAutoClarity, {
|
|
1246
|
+
instance: instance,
|
|
1247
|
+
show: !showTopContent || componentHideState || !playerReady
|
|
1248
|
+
}), /*#__PURE__*/React.createElement(View, {
|
|
1210
1249
|
className: clsx('ipc-player-bottom-content', {
|
|
1211
1250
|
'ipc-player-bottom-content-hide': componentHideState,
|
|
1212
1251
|
'ipc-player-bottom-content-show': !componentHideState,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { ClarityType } from '@ray-js/ray-ipc-utils/lib/interface';
|
|
2
|
+
import { getCachedAutoClarity, setCachedAutoClarity, subscribeClarityChanged } from './ttt';
|
|
3
|
+
jest.mock('@ray-js/ray-ipc-utils/lib/interface', () => ({
|
|
4
|
+
ClarityType: {
|
|
5
|
+
SS: 'SS',
|
|
6
|
+
SD: 'SD',
|
|
7
|
+
HD: 'HD',
|
|
8
|
+
UD: 'UD',
|
|
9
|
+
SSP: 'SSP',
|
|
10
|
+
AUTO: 'AUTO',
|
|
11
|
+
AUDIO: 'AUDIO'
|
|
12
|
+
}
|
|
13
|
+
}));
|
|
14
|
+
describe('auto clarity cache and listener', () => {
|
|
15
|
+
const storage = new Map();
|
|
16
|
+
let listener;
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
storage.clear();
|
|
19
|
+
globalThis.ty = {
|
|
20
|
+
getStorageSync: jest.fn(_ref => {
|
|
21
|
+
let {
|
|
22
|
+
key
|
|
23
|
+
} = _ref;
|
|
24
|
+
return storage.get(key);
|
|
25
|
+
}),
|
|
26
|
+
setStorageSync: jest.fn(_ref2 => {
|
|
27
|
+
let {
|
|
28
|
+
key,
|
|
29
|
+
data
|
|
30
|
+
} = _ref2;
|
|
31
|
+
return storage.set(key, data);
|
|
32
|
+
}),
|
|
33
|
+
ipc: {
|
|
34
|
+
onClarityChanged: jest.fn(callback => {
|
|
35
|
+
listener = callback;
|
|
36
|
+
}),
|
|
37
|
+
offClarityChanged: jest.fn()
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
it('restores the last reported actual clarity only for its device', () => {
|
|
42
|
+
setCachedAutoClarity('camera-1', ClarityType.HD);
|
|
43
|
+
expect(getCachedAutoClarity('camera-1')).toBe(ClarityType.HD);
|
|
44
|
+
expect(getCachedAutoClarity('camera-2')).toBeNull();
|
|
45
|
+
setCachedAutoClarity('camera-1', ClarityType.AUTO);
|
|
46
|
+
expect(getCachedAutoClarity('camera-1')).toBe(ClarityType.HD);
|
|
47
|
+
globalThis.ty.getStorageSync = jest.fn(() => ({
|
|
48
|
+
data: ClarityType.SD
|
|
49
|
+
}));
|
|
50
|
+
expect(getCachedAutoClarity('camera-1')).toBe(ClarityType.SD);
|
|
51
|
+
});
|
|
52
|
+
it('accepts a new actual clarity report for the same device', () => {
|
|
53
|
+
const handler = jest.fn();
|
|
54
|
+
const unsubscribe = subscribeClarityChanged('camera-1', handler);
|
|
55
|
+
listener({
|
|
56
|
+
deviceId: 'camera-2',
|
|
57
|
+
clarity: ClarityType.SD
|
|
58
|
+
});
|
|
59
|
+
listener({
|
|
60
|
+
deviceId: 'camera-1',
|
|
61
|
+
clarity: ClarityType.AUTO
|
|
62
|
+
});
|
|
63
|
+
listener({
|
|
64
|
+
deviceId: 'camera-1',
|
|
65
|
+
clarity: ClarityType.SD
|
|
66
|
+
});
|
|
67
|
+
expect(handler).toHaveBeenCalledTimes(1);
|
|
68
|
+
expect(handler).toHaveBeenCalledWith({
|
|
69
|
+
deviceId: 'camera-1',
|
|
70
|
+
clarity: ClarityType.SD
|
|
71
|
+
});
|
|
72
|
+
unsubscribe();
|
|
73
|
+
expect(globalThis.ty.ipc.offClarityChanged).toHaveBeenCalledWith(listener);
|
|
74
|
+
});
|
|
75
|
+
});
|
package/lib/utils/ttt.d.ts
CHANGED
|
@@ -54,6 +54,8 @@ export type ClarityChangedResult = {
|
|
|
54
54
|
};
|
|
55
55
|
export type ClarityChangedHandler = (result: ClarityChangedResult) => void;
|
|
56
56
|
type ClarityChangedListener = (payload: ClarityChangedResult) => void;
|
|
57
|
+
export declare function getCachedAutoClarity(devId: string): ClarityType | null;
|
|
58
|
+
export declare function setCachedAutoClarity(devId: string, clarity: ClarityType): void;
|
|
57
59
|
export declare function offClarityChanged(listener: ClarityChangedListener): void;
|
|
58
60
|
/**
|
|
59
61
|
* 监听自动清晰度变化,返回取消监听函数。
|
package/lib/utils/ttt.js
CHANGED
|
@@ -171,6 +171,30 @@ export function isClarityChangedSupported() {
|
|
|
171
171
|
var _ty5;
|
|
172
172
|
return typeof ty !== 'undefined' && typeof ((_ty5 = ty) === null || _ty5 === void 0 || (_ty5 = _ty5.ipc) === null || _ty5 === void 0 ? void 0 : _ty5.onClarityChanged) === 'function';
|
|
173
173
|
}
|
|
174
|
+
const actualClarityTypes = [ClarityType.SS, ClarityType.SD, ClarityType.HD, ClarityType.UD, ClarityType.SSP];
|
|
175
|
+
const autoClarityStorageKey = devId => `${devId}_auto_clarity`;
|
|
176
|
+
export function getCachedAutoClarity(devId) {
|
|
177
|
+
try {
|
|
178
|
+
const stored = ty.getStorageSync({
|
|
179
|
+
key: autoClarityStorageKey(devId)
|
|
180
|
+
});
|
|
181
|
+
const clarity = typeof stored === 'string' ? stored : stored === null || stored === void 0 ? void 0 : stored.data;
|
|
182
|
+
return actualClarityTypes.includes(clarity) ? clarity : null;
|
|
183
|
+
} catch (error) {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
export function setCachedAutoClarity(devId, clarity) {
|
|
188
|
+
if (!actualClarityTypes.includes(clarity)) return;
|
|
189
|
+
try {
|
|
190
|
+
ty.setStorageSync({
|
|
191
|
+
key: autoClarityStorageKey(devId),
|
|
192
|
+
data: clarity
|
|
193
|
+
});
|
|
194
|
+
} catch (error) {
|
|
195
|
+
console.warn('res===setCachedAutoClarity fail', error);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
174
198
|
export function offClarityChanged(listener) {
|
|
175
199
|
var _ty6;
|
|
176
200
|
const ipc = typeof ty !== 'undefined' ? (_ty6 = ty) === null || _ty6 === void 0 ? void 0 : _ty6.ipc : undefined;
|
|
@@ -202,8 +226,8 @@ export function subscribeClarityChanged(devId, handler) {
|
|
|
202
226
|
deviceId,
|
|
203
227
|
clarity
|
|
204
228
|
} = payload || {};
|
|
205
|
-
if (!
|
|
206
|
-
console.warn('[resolution] onClarityChanged
|
|
229
|
+
if (!actualClarityTypes.includes(clarity)) {
|
|
230
|
+
console.warn('[resolution] onClarityChanged 未返回实际清晰度');
|
|
207
231
|
return;
|
|
208
232
|
}
|
|
209
233
|
// 一页多设备时只认自己的;宿主没带 deviceId 就不过滤
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import "core-js/modules/esnext.iterator.constructor.js";
|
|
2
|
-
import "core-js/modules/esnext.iterator.map.js";
|
|
3
1
|
import React from 'react';
|
|
4
2
|
import { Image, Text, View } from '@ray-js/ray';
|
|
5
3
|
import clsx from 'clsx';
|
|
@@ -55,12 +53,11 @@ export function CaptureResultToast(_ref) {
|
|
|
55
53
|
const textKeys = TEXT_KEYS[kind];
|
|
56
54
|
const legacyCls = LEGACY_CLASS_MAP[kind];
|
|
57
55
|
const imageClassName = clsx('ipc-player-plugin-capture-result-image', legacyCls.image);
|
|
58
|
-
const backdropLayers = BACKDROP_LAYERS.slice(-Math.min(count - 1, BACKDROP_LAYERS.length));
|
|
59
56
|
return /*#__PURE__*/React.createElement(View, {
|
|
60
57
|
className: clsx('ipc-player-plugin-capture-result-toast', legacyCls.toast, className)
|
|
61
58
|
}, /*#__PURE__*/React.createElement(View, {
|
|
62
59
|
className: clsx('ipc-player-plugin-capture-result-image-box', legacyCls.imageBox, isMultiLens && ['ipc-player-plugin-capture-result-image-box-multi', legacyCls.imageBoxMulti])
|
|
63
|
-
}, isMultiLens ? /*#__PURE__*/React.createElement(React.Fragment, null,
|
|
60
|
+
}, isMultiLens ? /*#__PURE__*/React.createElement(React.Fragment, null, BACKDROP_LAYERS.map(layer => /*#__PURE__*/React.createElement(View, {
|
|
64
61
|
key: layer,
|
|
65
62
|
className: clsx('ipc-player-plugin-capture-result-backdrop', `ipc-player-plugin-capture-result-image-${layer}`)
|
|
66
63
|
})), /*#__PURE__*/React.createElement(Image, {
|
|
@@ -1,22 +1,36 @@
|
|
|
1
1
|
.ipc-player-plugin-capture-result-toast,
|
|
2
2
|
.ipc-player-plugin-record-success-toast,
|
|
3
3
|
.ipc-player-plugin-screenshot-toast {
|
|
4
|
+
--capture-result-text-color: var(--fontColor, #fff);
|
|
5
|
+
--capture-result-near-backdrop-color: rgba(255, 255, 255, 0.2);
|
|
6
|
+
--capture-result-far-backdrop-color: rgba(255, 255, 255, 0.1);
|
|
7
|
+
|
|
4
8
|
z-index: 100;
|
|
5
9
|
display: flex;
|
|
6
10
|
flex: 1;
|
|
7
11
|
align-items: center;
|
|
8
|
-
padding: calc(
|
|
12
|
+
padding: calc(7px * var(--ipc-player-size-scale, 1))
|
|
13
|
+
calc(16px * var(--ipc-player-size-scale, 1))
|
|
14
|
+
calc(7px * var(--ipc-player-size-scale, 1))
|
|
9
15
|
calc(12px * var(--ipc-player-size-scale, 1));
|
|
10
16
|
background-color: var(--shot-card-bg-color);
|
|
11
17
|
border-radius: calc(8px * var(--ipc-player-size-scale, 1));
|
|
12
18
|
}
|
|
13
19
|
|
|
20
|
+
:root[theme='light'] .ipc-player-plugin-capture-result-toast {
|
|
21
|
+
--capture-result-text-color: #1a1a1a;
|
|
22
|
+
--capture-result-near-backdrop-color: rgba(0, 0, 0, 0.1);
|
|
23
|
+
--capture-result-far-backdrop-color: rgba(0, 0, 0, 0.05);
|
|
24
|
+
|
|
25
|
+
background-color: #fff;
|
|
26
|
+
}
|
|
27
|
+
|
|
14
28
|
.ipc-player-plugin-capture-result-image-box,
|
|
15
29
|
.ipc-player-plugin-record-success-toast-image-box,
|
|
16
30
|
.ipc-player-plugin-screenshot-toast-image-box {
|
|
17
31
|
position: relative;
|
|
18
32
|
width: calc(66px * var(--ipc-player-size-scale, 1));
|
|
19
|
-
height: calc(
|
|
33
|
+
height: calc(39px * var(--ipc-player-size-scale, 1));
|
|
20
34
|
overflow: hidden;
|
|
21
35
|
border-radius: calc(4px * var(--ipc-player-size-scale, 1));
|
|
22
36
|
}
|
|
@@ -29,12 +43,6 @@
|
|
|
29
43
|
object-fit: cover;
|
|
30
44
|
}
|
|
31
45
|
|
|
32
|
-
.ipc-player-plugin-capture-result-image-box-multi,
|
|
33
|
-
.ipc-player-plugin-record-success-toast-image-box-multi,
|
|
34
|
-
.ipc-player-plugin-screenshot-toast-image-box-multi {
|
|
35
|
-
height: calc(39px * var(--ipc-player-size-scale, 1));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
46
|
.ipc-player-plugin-capture-result-backdrop,
|
|
39
47
|
.ipc-player-plugin-capture-result-image-front {
|
|
40
48
|
position: absolute;
|
|
@@ -42,16 +50,13 @@
|
|
|
42
50
|
border-radius: calc(4px * var(--ipc-player-size-scale, 1));
|
|
43
51
|
}
|
|
44
52
|
|
|
45
|
-
.ipc-player-plugin-capture-result-backdrop {
|
|
46
|
-
background: rgba(255, 255, 255, 0.2);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
53
|
.ipc-player-plugin-capture-result-image-back {
|
|
50
|
-
top:
|
|
51
|
-
left: calc(
|
|
54
|
+
top: calc(1px * var(--ipc-player-size-scale, 1));
|
|
55
|
+
left: calc(5px * var(--ipc-player-size-scale, 1));
|
|
52
56
|
z-index: 1;
|
|
53
|
-
width: calc(
|
|
57
|
+
width: calc(56px * var(--ipc-player-size-scale, 1));
|
|
54
58
|
height: calc(28px * var(--ipc-player-size-scale, 1));
|
|
59
|
+
background: var(--capture-result-far-backdrop-color);
|
|
55
60
|
}
|
|
56
61
|
|
|
57
62
|
.ipc-player-plugin-capture-result-image-middle {
|
|
@@ -60,10 +65,11 @@
|
|
|
60
65
|
z-index: 2;
|
|
61
66
|
width: calc(61px * var(--ipc-player-size-scale, 1));
|
|
62
67
|
height: calc(30.5px * var(--ipc-player-size-scale, 1));
|
|
68
|
+
background: var(--capture-result-near-backdrop-color);
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
.ipc-player-plugin-capture-result-image-front {
|
|
66
|
-
top: calc(
|
|
72
|
+
top: calc(5px * var(--ipc-player-size-scale, 1));
|
|
67
73
|
left: 0;
|
|
68
74
|
z-index: 3;
|
|
69
75
|
width: calc(66px * var(--ipc-player-size-scale, 1));
|
|
@@ -79,18 +85,23 @@
|
|
|
79
85
|
display: flex;
|
|
80
86
|
align-items: center;
|
|
81
87
|
justify-content: center;
|
|
82
|
-
width:
|
|
83
|
-
height:
|
|
88
|
+
width: calc(16px * var(--ipc-player-size-scale, 1));
|
|
89
|
+
height: calc(16px * var(--ipc-player-size-scale, 1));
|
|
84
90
|
overflow: hidden;
|
|
85
91
|
background-color: rgba(0, 0, 0, 0.2);
|
|
86
92
|
border-radius: 50%;
|
|
87
93
|
transform: translate(-50%, -50%);
|
|
88
94
|
}
|
|
89
95
|
|
|
96
|
+
.ipc-player-plugin-capture-result-image-box-multi
|
|
97
|
+
.ipc-player-plugin-capture-result-play-icon-box {
|
|
98
|
+
top: calc(50% + 2px * var(--ipc-player-size-scale, 1));
|
|
99
|
+
}
|
|
100
|
+
|
|
90
101
|
.ipc-player-plugin-capture-result-play-icon,
|
|
91
102
|
.ipc-player-plugin-record-success-play-icon {
|
|
92
103
|
color: #ffffff;
|
|
93
|
-
font-size: calc(
|
|
104
|
+
font-size: calc(9px * var(--ipc-player-size-scale, 1)) !important;
|
|
94
105
|
}
|
|
95
106
|
|
|
96
107
|
.ipc-player-plugin-capture-result-title,
|
|
@@ -99,17 +110,20 @@
|
|
|
99
110
|
display: flex;
|
|
100
111
|
flex: 1;
|
|
101
112
|
flex-direction: column;
|
|
113
|
+
min-width: 0;
|
|
102
114
|
margin-right: calc(12px * var(--ipc-player-size-scale, 1));
|
|
103
|
-
margin-left: calc(
|
|
104
|
-
color: var(--fontColor);
|
|
115
|
+
margin-left: calc(8px * var(--ipc-player-size-scale, 1));
|
|
116
|
+
color: var(--capture-result-text-color, var(--fontColor));
|
|
105
117
|
font-size: calc(14px * var(--ipc-player-size-scale, 1));
|
|
118
|
+
line-height: calc(20px * var(--ipc-player-size-scale, 1));
|
|
106
119
|
word-break: break-word;
|
|
107
120
|
}
|
|
108
121
|
|
|
109
122
|
.ipc-player-plugin-capture-result-count {
|
|
110
123
|
margin-top: calc(2px * var(--ipc-player-size-scale, 1));
|
|
111
|
-
color: var(--fontColor);
|
|
124
|
+
color: var(--capture-result-text-color, var(--fontColor));
|
|
112
125
|
font-size: calc(12px * var(--ipc-player-size-scale, 1));
|
|
126
|
+
line-height: calc(17px * var(--ipc-player-size-scale, 1));
|
|
113
127
|
opacity: 0.5;
|
|
114
128
|
}
|
|
115
129
|
|
|
@@ -118,6 +132,7 @@
|
|
|
118
132
|
.ipc-player-plugin-screenshot-toast-bottom {
|
|
119
133
|
min-width: calc(52px * var(--ipc-player-size-scale, 1));
|
|
120
134
|
max-width: calc(100px * var(--ipc-player-size-scale, 1));
|
|
135
|
+
flex-shrink: 0;
|
|
121
136
|
padding: calc(5px * var(--ipc-player-size-scale, 1))
|
|
122
137
|
calc(11px * var(--ipc-player-size-scale, 1));
|
|
123
138
|
overflow: hidden;
|
|
@@ -63,9 +63,10 @@ describe('CaptureResultToast', () => {
|
|
|
63
63
|
expect(countClass(markup, 'ipc-player-plugin-capture-result-image-front')).toBe(0);
|
|
64
64
|
expect(countClass(markup, 'ipc-player-plugin-capture-result-image')).toBe(1);
|
|
65
65
|
});
|
|
66
|
-
it('renders
|
|
66
|
+
it('renders both backdrops for two captured items', () => {
|
|
67
67
|
const markup = renderToast(2);
|
|
68
|
-
expect(countClass(markup, 'ipc-player-plugin-capture-result-backdrop')).toBe(
|
|
68
|
+
expect(countClass(markup, 'ipc-player-plugin-capture-result-backdrop')).toBe(2);
|
|
69
|
+
expect(countClass(markup, 'ipc-player-plugin-capture-result-image-back')).toBe(1);
|
|
69
70
|
expect(countClass(markup, 'ipc-player-plugin-capture-result-image-middle')).toBe(1);
|
|
70
71
|
expect(countClass(markup, 'ipc-player-plugin-capture-result-image-front')).toBe(1);
|
|
71
72
|
});
|
|
@@ -56,13 +56,14 @@ export const VideoBitKBP = props => {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
};
|
|
59
|
-
const
|
|
60
|
-
const
|
|
59
|
+
const isPlaying = store.playState === PlayState.PLAYING;
|
|
60
|
+
const hasKbps = isPlaying && !hideKbsMenu && bitKBP !== '' && bitKBP !== '0';
|
|
61
|
+
const hasSignal = isPlaying && !hideSignalMenu && signalStrength !== null;
|
|
61
62
|
const activeClarity = store.resolution === ClarityType.AUTO ? store.autoClarity : null;
|
|
62
|
-
|
|
63
|
+
const hasClarity = Boolean(activeClarity);
|
|
64
|
+
if (!hasKbps && !hasSignal && !hasClarity) {
|
|
63
65
|
return null;
|
|
64
66
|
}
|
|
65
|
-
if (hideKbsMenu && hideSignalMenu) return null;
|
|
66
67
|
return /*#__PURE__*/React.createElement(View, {
|
|
67
68
|
className: clsx({
|
|
68
69
|
'ipc-player-plugin-videoBitKBP-container': true,
|
|
@@ -76,12 +77,14 @@ export const VideoBitKBP = props => {
|
|
|
76
77
|
className: clsx('icon-panel', 'icon-panel-wi-Fi', 'ipc-player-plugin-videoBitKBP-signal-icon')
|
|
77
78
|
}), /*#__PURE__*/React.createElement(Text, null, signalStrength), /*#__PURE__*/React.createElement(Text, {
|
|
78
79
|
className: "ipc-player-plugin-videoBitKBP-unit-percent"
|
|
79
|
-
}, signalStrength > 0 ? '%' : 'dBm')), hasSignal && hasKbps && /*#__PURE__*/React.createElement(View, {
|
|
80
|
+
}, signalStrength > 0 ? '%' : 'dBm')), hasSignal && (hasKbps || hasClarity) && /*#__PURE__*/React.createElement(View, {
|
|
80
81
|
className: "ipc-player-plugin-videoBitKBP-divider"
|
|
81
|
-
}), hasKbps && /*#__PURE__*/React.createElement(View, {
|
|
82
|
+
}), (hasKbps || hasClarity) && /*#__PURE__*/React.createElement(View, {
|
|
82
83
|
className: "ipc-player-plugin-videoBitKBP-kbps"
|
|
83
84
|
}, activeClarity && /*#__PURE__*/React.createElement(Text, {
|
|
84
|
-
className:
|
|
85
|
+
className: clsx('ipc-player-plugin-videoBitKBP-clarity', {
|
|
86
|
+
'ipc-player-plugin-videoBitKBP-clarity-only': !hasKbps
|
|
87
|
+
})
|
|
85
88
|
}, (clarity => {
|
|
86
89
|
switch (clarity) {
|
|
87
90
|
case ClarityType.SS:
|
|
@@ -101,7 +104,7 @@ export const VideoBitKBP = props => {
|
|
|
101
104
|
default:
|
|
102
105
|
return clarity;
|
|
103
106
|
}
|
|
104
|
-
})(activeClarity)), /*#__PURE__*/React.createElement(Text, null, bitKBP), /*#__PURE__*/React.createElement(Text, {
|
|
107
|
+
})(activeClarity)), hasKbps && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, null, bitKBP), /*#__PURE__*/React.createElement(Text, {
|
|
105
108
|
className: "ipc-player-plugin-videoBitKBP-unit-kbs"
|
|
106
|
-
}, "KB/S"))));
|
|
109
|
+
}, "KB/S")))));
|
|
107
110
|
};
|
|
@@ -39,6 +39,9 @@
|
|
|
39
39
|
.ipc-player-plugin-videoBitKBP-clarity {
|
|
40
40
|
margin-right: calc(4px * var(--ipc-player-size-scale, 1));
|
|
41
41
|
}
|
|
42
|
+
.ipc-player-plugin-videoBitKBP-clarity-only {
|
|
43
|
+
margin-right: 0;
|
|
44
|
+
}
|
|
42
45
|
.ipc-player-plugin-videoBitKBP-unit-kbs {
|
|
43
46
|
margin-left: calc(4px * var(--ipc-player-size-scale, 1));
|
|
44
47
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { renderToStaticMarkup } from 'react-dom/server';
|
|
3
|
+
let mockStoreState;
|
|
4
|
+
jest.mock('@ray-js/ray', () => ({
|
|
5
|
+
View: _ref => {
|
|
6
|
+
let {
|
|
7
|
+
children,
|
|
8
|
+
className
|
|
9
|
+
} = _ref;
|
|
10
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
11
|
+
className: className
|
|
12
|
+
}, children);
|
|
13
|
+
},
|
|
14
|
+
Text: _ref2 => {
|
|
15
|
+
let {
|
|
16
|
+
children,
|
|
17
|
+
className
|
|
18
|
+
} = _ref2;
|
|
19
|
+
return /*#__PURE__*/React.createElement("span", {
|
|
20
|
+
className: className
|
|
21
|
+
}, children);
|
|
22
|
+
},
|
|
23
|
+
usePageEvent: () => undefined
|
|
24
|
+
}));
|
|
25
|
+
jest.mock('@ray-js/ray-ipc-utils', () => ({
|
|
26
|
+
getVideoBitrateKbps: jest.fn(),
|
|
27
|
+
requestWifiSignal: jest.fn()
|
|
28
|
+
}));
|
|
29
|
+
jest.mock('@ray-js/ray-ipc-utils/lib/interface', () => ({
|
|
30
|
+
ClarityType: {
|
|
31
|
+
SS: 'SS',
|
|
32
|
+
SD: 'SD',
|
|
33
|
+
HD: 'HD',
|
|
34
|
+
UD: 'UD',
|
|
35
|
+
SSP: 'SSP',
|
|
36
|
+
AUTO: 'AUTO',
|
|
37
|
+
AUDIO: 'AUDIO'
|
|
38
|
+
}
|
|
39
|
+
}));
|
|
40
|
+
jest.mock('../../ctx/store', () => ({
|
|
41
|
+
useStore: () => mockStoreState
|
|
42
|
+
}));
|
|
43
|
+
jest.mock('../../i18n', () => ({
|
|
44
|
+
__esModule: true,
|
|
45
|
+
default: {
|
|
46
|
+
getLang: key => key
|
|
47
|
+
}
|
|
48
|
+
}));
|
|
49
|
+
jest.mock('./videoBitKBP.less', () => ({}));
|
|
50
|
+
const {
|
|
51
|
+
VideoBitKBP
|
|
52
|
+
} = require('./videoBitKBP');
|
|
53
|
+
const renderWidget = function (resolution, autoClarity) {
|
|
54
|
+
let playState = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
|
|
55
|
+
mockStoreState = {
|
|
56
|
+
resolution,
|
|
57
|
+
autoClarity,
|
|
58
|
+
playState
|
|
59
|
+
};
|
|
60
|
+
return renderToStaticMarkup(/*#__PURE__*/React.createElement(VideoBitKBP, {
|
|
61
|
+
devId: 'device',
|
|
62
|
+
playState: {},
|
|
63
|
+
resolution: {},
|
|
64
|
+
autoClarity: {},
|
|
65
|
+
hideKbsMenu: true,
|
|
66
|
+
hideSignalMenu: true
|
|
67
|
+
}));
|
|
68
|
+
};
|
|
69
|
+
describe('VideoBitKBP auto clarity', () => {
|
|
70
|
+
it('shows actual clarity independently of bitrate, signal and play state', () => {
|
|
71
|
+
const markup = renderWidget('AUTO', 'HD', 2);
|
|
72
|
+
expect(markup).toContain('ipc_player_resolution_HD');
|
|
73
|
+
expect(markup).not.toContain('KB/S');
|
|
74
|
+
});
|
|
75
|
+
it('does not show clarity outside auto mode', () => {
|
|
76
|
+
expect(renderWidget('SD', 'HD')).toBe('');
|
|
77
|
+
});
|
|
78
|
+
it('waits for the native clarity report in auto mode', () => {
|
|
79
|
+
expect(renderWidget('AUTO', null)).toBe('');
|
|
80
|
+
});
|
|
81
|
+
});
|