@ray-js/ipc-player-integration 0.0.50-beta.4 → 0.0.50-beta.5

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.
@@ -14,7 +14,8 @@ export type InitPlayerWidgetsOptions = {
14
14
  showRealTimeMagnification?: boolean;
15
15
  /**
16
16
  * 允许展示焦距转盘入口(长按图标弹出转盘)。
17
- * 仅为功能开关;实际渲染还要 ipc_multi_zoom 解析出 cnt > 1,单镜头设备传 true 也不出现。
17
+ * 仅为功能开关;实际渲染还要宿主提供 ty.ipc.switchChannel、且 ipc_multi_zoom 解析出 cnt > 1
18
+ * 单镜头设备与老宿主上传 true 也不出现。
18
19
  */
19
20
  showZoomTurntable?: boolean;
20
21
  directionControlProps?: Partial<React.ComponentProps<typeof FullScreen>['directionControlProps']>;
@@ -53,7 +53,8 @@ export async function initPlayerWidgets(ctx, options) {
53
53
  }
54
54
  }
55
55
  // 焦距转盘入口:这里只放开占位,真正是否渲染由 widget 内部按
56
- // ipc_multi_zoom 上报值解析出的 cnt > 1 决定(单镜头设备不出现)
56
+ // 「宿主有 ty.ipc.switchChannel」+「ipc_multi_zoom 解析出 cnt > 1」决定
57
+ // (单镜头设备、不支持切镜头的老宿主都不出现)
57
58
  if (options.showZoomTurntable) {
58
59
  const zoomTurntableIndex = newDefaultBottomLeftContent.findIndex(item => item.id === 'ZoomTurntableEntry');
59
60
  if (zoomTurntableIndex !== -1) {
@@ -56,6 +56,14 @@ export declare const isZoomSkillValid: (skill?: ZoomSkill | null) => boolean;
56
56
  * @param value DP 值;内部 mock 常量是对象、DP 上报是 string,两条来源共用同一校验链路
57
57
  */
58
58
  export declare const parseZoomSkill: (value?: unknown) => ZoomSkill | null;
59
+ /**
60
+ * 宿主是否支持切镜头下发。
61
+ *
62
+ * 转盘的每一种交互(点 tab 切镜头、拖转盘跨界、手势触底下切)最终都落到 switchChannel 上,
63
+ * 方法不存在时转盘画得出来却切不动,只会让用户以为坏了 —— 故整个入口不渲染
64
+ * (门控在 useLensZoom 的 multiLensReady 里,与 cnt > 1 同级)。
65
+ */
66
+ export declare const isSwitchChannelSupported: () => boolean;
59
67
  /**
60
68
  * 切换物理镜头。channel 取上报的子镜头 id 而非数组下标 —— 固件可上报非连续 id。
61
69
  * 返回 false(不支持 / 失败)时由 useLensZoom 回滚读数,无回调另有 SWITCH_LENS_TIMEOUT 兜底。
@@ -111,13 +111,34 @@ export const parseZoomSkill = value => {
111
111
 
112
112
  /** ty.ipc.switchChannel 的最小签名:ty 类型包尚未收录,本地声明避免调用点退化成 any */
113
113
 
114
+ /** 「宿主不支持 switchChannel」只提示一次:判定会被 render 反复调用,不去重会刷屏 */
115
+ let switchChannelMissingLogged = false;
116
+
117
+ /**
118
+ * 宿主是否支持切镜头下发。
119
+ *
120
+ * 转盘的每一种交互(点 tab 切镜头、拖转盘跨界、手势触底下切)最终都落到 switchChannel 上,
121
+ * 方法不存在时转盘画得出来却切不动,只会让用户以为坏了 —— 故整个入口不渲染
122
+ * (门控在 useLensZoom 的 multiLensReady 里,与 cnt > 1 同级)。
123
+ */
124
+ export const isSwitchChannelSupported = () => {
125
+ var _ty;
126
+ const supported = typeof ((_ty = ty) === null || _ty === void 0 || (_ty = _ty.ipc) === null || _ty === void 0 ? void 0 : _ty.switchChannel) === 'function';
127
+ if (!supported && !switchChannelMissingLogged) {
128
+ switchChannelMissingLogged = true;
129
+ console.warn('[zoomTurntable] 宿主不支持 ty.ipc.switchChannel,焦距转盘入口不展示');
130
+ dumpChannelApis();
131
+ }
132
+ return supported;
133
+ };
134
+
114
135
  /**
115
136
  * 切换物理镜头。channel 取上报的子镜头 id 而非数组下标 —— 固件可上报非连续 id。
116
137
  * 返回 false(不支持 / 失败)时由 useLensZoom 回滚读数,无回调另有 SWITCH_LENS_TIMEOUT 兜底。
117
138
  */
118
139
  export const switchLens = (devId, lens) => {
119
- var _ty;
120
- const switchChannel = (_ty = ty) === null || _ty === void 0 || (_ty = _ty.ipc) === null || _ty === void 0 ? void 0 : _ty.switchChannel;
140
+ var _ty2;
141
+ const switchChannel = (_ty2 = ty) === null || _ty2 === void 0 || (_ty2 = _ty2.ipc) === null || _ty2 === void 0 ? void 0 : _ty2.switchChannel;
121
142
  // 入参与回调结果都打出来:真机上「切没切成」只能靠这条链路判断
122
143
  const params = {
123
144
  deviceId: devId,
@@ -223,8 +244,8 @@ const pickChannel = payload => {
223
244
  * 返回 null(不支持 / 失败 / 超时)时调用方保持现状,不重置镜头。
224
245
  */
225
246
  export const queryCurrentLens = devId => {
226
- var _ty2;
227
- const queryCurrentChannel = (_ty2 = ty) === null || _ty2 === void 0 || (_ty2 = _ty2.ipc) === null || _ty2 === void 0 ? void 0 : _ty2.queryCurrentChannel;
247
+ var _ty3;
248
+ const queryCurrentChannel = (_ty3 = ty) === null || _ty3 === void 0 || (_ty3 = _ty3.ipc) === null || _ty3 === void 0 ? void 0 : _ty3.queryCurrentChannel;
228
249
  if (typeof queryCurrentChannel !== 'function') {
229
250
  console.warn('[zoomTurntable] 宿主不支持 ty.ipc.queryCurrentChannel');
230
251
  return Promise.resolve(null);
@@ -273,8 +294,8 @@ export const queryCurrentLens = devId => {
273
294
  * 切镜头的收尾(画面归 1 倍 + 刷读数)以该事件为准,不支持时只能退回「switchChannel 成功即收尾」。
274
295
  */
275
296
  export const isChannelChangeSupported = () => {
276
- var _ty3;
277
- return typeof ((_ty3 = ty) === null || _ty3 === void 0 || (_ty3 = _ty3.ipc) === null || _ty3 === void 0 ? void 0 : _ty3.onChannelChange) === 'function';
297
+ var _ty4;
298
+ return typeof ((_ty4 = ty) === null || _ty4 === void 0 || (_ty4 = _ty4.ipc) === null || _ty4 === void 0 ? void 0 : _ty4.onChannelChange) === 'function';
278
299
  };
279
300
 
280
301
  /**
@@ -282,8 +303,8 @@ export const isChannelChangeSupported = () => {
282
303
  * 真机上「事件为什么不来」第一步就是确认宿主到底提供了哪个名字。
283
304
  */
284
305
  export const dumpChannelApis = () => {
285
- var _ty4;
286
- const ipc = (_ty4 = ty) === null || _ty4 === void 0 ? void 0 : _ty4.ipc;
306
+ var _ty5;
307
+ const ipc = (_ty5 = ty) === null || _ty5 === void 0 ? void 0 : _ty5.ipc;
287
308
  if (!ipc) {
288
309
  console.warn('[zoomTurntable] ty.ipc 不存在', `typeof ty=${typeof ty}`);
289
310
  return;
@@ -321,9 +342,9 @@ export const subscribeChannelChange = (devId, handler) => {
321
342
  console.log('[zoomTurntable] 已订阅 ty.ipc.onChannelChange', devId);
322
343
  ty.ipc.onChannelChange(listener);
323
344
  return () => {
324
- var _ty5;
345
+ var _ty6;
325
346
  console.log('[zoomTurntable] 解绑 channelChange 监听', devId);
326
- if (typeof ((_ty5 = ty) === null || _ty5 === void 0 || (_ty5 = _ty5.ipc) === null || _ty5 === void 0 ? void 0 : _ty5.offChannelChange) === 'function') {
347
+ if (typeof ((_ty6 = ty) === null || _ty6 === void 0 || (_ty6 = _ty6.ipc) === null || _ty6 === void 0 ? void 0 : _ty6.offChannelChange) === 'function') {
327
348
  ty.ipc.offChannelChange(listener);
328
349
  } else {
329
350
  console.warn('[zoomTurntable] 宿主无 offChannelChange,监听无法解绑');
@@ -1,6 +1,6 @@
1
1
  import { ComponentConfigProps } from '../../interface';
2
2
  type Options = ComponentConfigProps & {
3
- /** 业务侧的功能开关;实际是否渲染仍由 ipc_multi_zoom 解析出的 cnt 决定 */
3
+ /** 业务侧的功能开关;实际是否渲染仍由宿主 switchChannel 能力 + ipc_multi_zoom cnt 决定 */
4
4
  showZoomTurntable?: boolean;
5
5
  /** 跳过能力加载:Entry 常驻负责加载,Dock 作为消费方传 true 避免重复解析 */
6
6
  skipLoad?: boolean;
@@ -1,10 +1,10 @@
1
- import { useEffect, useRef, useState } from 'react';
1
+ import { useEffect, useMemo, useRef, useState } from 'react';
2
2
  import { useMemoizedFn } from 'ahooks';
3
3
  import { useStore } from '../../ctx/store';
4
4
  import { PlayState } from '../../interface';
5
5
  import { useDpState } from '../../hooks/useDpState';
6
6
  import { setScaleMultipleEvent, zoomLevelChange } from '../../ui/constant';
7
- import { MOCK_ZOOM_SKILL, MULTI_ZOOM_DP_CODE, dumpChannelApis, isChannelChangeSupported, isZoomSkillValid, lensCount, parseZoomSkill, queryCurrentLens, showSmallMonitor, subscribeChannelChange, switchLens } from './lensSkill';
7
+ import { MOCK_ZOOM_SKILL, MULTI_ZOOM_DP_CODE, dumpChannelApis, isChannelChangeSupported, isSwitchChannelSupported, isZoomSkillValid, lensCount, parseZoomSkill, queryCurrentLens, showSmallMonitor, subscribeChannelChange, switchLens } from './lensSkill';
8
8
  import { DEFAULT_STEP, D_MIN, buildMarks, buildTickValues, indexOfLensId, lensRange, matchLens, maxScaleMultiple, toDisplayZoom, toScaleMultiple, zoomBounds } from './lensModel';
9
9
  import { CHANNEL_SETTLE_TIMEOUT, DOWN_SWITCH_COOLDOWN, DRAG_CROSS_SWITCH_DELAY, D_MATCH_EPS, FLOOR_HIT_COUNT, FLOOR_HIT_SETTLE_GUARD, FLOOR_HIT_WINDOW, GESTURE_SWITCH_DEBOUNCE, POST_SWITCH_APPLY_DELAY, SETTLE_APPLY_TIMEOUT, SWITCH_DEDUPE_WINDOW, SWITCH_LENS_TIMEOUT, ZOOM_PREVIEW_THROTTLE, zoomTurntableLensChange, zoomTurntableSwitching, zoomTurntableZoomChange } from './constants';
10
10
  /**
@@ -210,9 +210,18 @@ export const useLensZoom = options => {
210
210
  };
211
211
  }, [event]);
212
212
 
213
+ // ---------------- 宿主能力 ----------------
214
+ /**
215
+ * 宿主是否支持 ty.ipc.switchChannel。宿主能力在运行期不会变,求一次即可 ——
216
+ * 放 useMemo 而不是 render 期直接调,免得 typeof 判定与首次告警日志跟着每次渲染跑。
217
+ *
218
+ * 转盘的每一种交互最终都落到这个方法上,它不存在时转盘切不动,故整个入口不展示。
219
+ */
220
+ const switchChannelSupported = useMemo(() => isSwitchChannelSupported(), []);
221
+
213
222
  // ---------------- 能力加载 ----------------
214
223
  useEffect(() => {
215
- if (skipLoad || !devId || !showZoomTurntable) return undefined;
224
+ if (skipLoad || !devId || !showZoomTurntable || !switchChannelSupported) return undefined;
216
225
  const raw = multiZoomDpValue;
217
226
  console.log('[zoomTurntable] ipc_multi_zoom 上报值', JSON.stringify(raw !== null && raw !== void 0 ? raw : null));
218
227
  const skill = parseZoomSkill(raw);
@@ -223,10 +232,14 @@ export const useLensZoom = options => {
223
232
  }
224
233
  setZoomSkill(skill);
225
234
  return undefined;
226
- }, [devId, showZoomTurntable, multiZoomDpValue, skipLoad]);
235
+ }, [devId, showZoomTurntable, switchChannelSupported, multiZoomDpValue, skipLoad]);
227
236
 
228
- /** 多镜头能力就绪:ipc_multi_zoom 解析出的 cnt > 1(单镜头设备不出现) */
229
- const multiLensReady = showZoomTurntable && lensCount(zoomSkill) > 1;
237
+ /**
238
+ * 多镜头能力就绪:宿主提供 ty.ipc.switchChannel,且 ipc_multi_zoom 解析出的 cnt > 1
239
+ * 两条缺一个入口都不出现 —— 单镜头设备没有可切的镜头,
240
+ * 老宿主则是切不动(见 isSwitchChannelSupported)。
241
+ */
242
+ const multiLensReady = showZoomTurntable && switchChannelSupported && lensCount(zoomSkill) > 1;
230
243
 
231
244
  // 手势缩放上限按当前镜头换算后下发给播放器:maxScaleMultiple 是 d 口径,
232
245
  // 直接用画面绝对上限(如 6.0)会让画面放到该镜头区间之外。切镜头后跟着更新。
@@ -3,7 +3,7 @@ import { ComponentConfigProps } from '../../interface';
3
3
  import './zoomTurntableEntry.less';
4
4
  type Props = ComponentConfigProps & {
5
5
  className?: string;
6
- /** 业务侧的功能开关;实际是否渲染仍由 ipc_multi_zoom 解析出的 cnt 决定 */
6
+ /** 业务侧的功能开关;实际是否渲染仍由宿主 switchChannel 能力 + ipc_multi_zoom cnt 决定 */
7
7
  showZoomTurntable?: boolean;
8
8
  /** 长按判定时长,默认 500ms */
9
9
  longPressDuration?: number;
@@ -12,7 +12,8 @@ type Props = ComponentConfigProps & {
12
12
  };
13
13
  /**
14
14
  * 焦距转盘入口:左下角工具条中的图标,长按弹出转盘。
15
- * cnt > 1 的多镜头设备渲染;单镜头设备倍率交互仍由 RealTimeMagnification 承担。
15
+ * 仅「宿主支持 ty.ipc.switchChannel」且 cnt > 1 的多镜头设备渲染;
16
+ * 单镜头设备倍率交互仍由 RealTimeMagnification 承担。
16
17
  */
17
18
  export declare const ZoomTurntableEntry: (props: Props) => React.JSX.Element | null;
18
19
  export {};
@@ -19,7 +19,8 @@ import { FORCE_SHOW_ZOOM_TIP, LONG_PRESS_MS, MOVE_TOLERANCE, TIP_RESHOW_DELAY, g
19
19
  import './zoomTurntableEntry.less';
20
20
  /**
21
21
  * 焦距转盘入口:左下角工具条中的图标,长按弹出转盘。
22
- * cnt > 1 的多镜头设备渲染;单镜头设备倍率交互仍由 RealTimeMagnification 承担。
22
+ * 仅「宿主支持 ty.ipc.switchChannel」且 cnt > 1 的多镜头设备渲染;
23
+ * 单镜头设备倍率交互仍由 RealTimeMagnification 承担。
23
24
  */
24
25
  export const ZoomTurntableEntry = props => {
25
26
  var _props$event;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ray-js/ipc-player-integration",
3
- "version": "0.0.50-beta.4",
3
+ "version": "0.0.50-beta.5",
4
4
  "description": "IPC 融合播放器",
5
5
  "main": "lib/index",
6
6
  "files": [