[English](./README.md) | 简体中文

# @ray-js/ipc-player-integration

[![latest](https://img.shields.io/npm/v/@ray-js/ipc-player-integration/latest.svg)](https://www.npmjs.com/package/@ray-js/ipc-player-integration) [![download](https://img.shields.io/npm/dt/@ray-js/ipc-player-integration.svg)](https://www.npmjs.com/package/@ray-js/ipc-player-integration)

> IPC 融合播放器 —— 面向涂鸦 Ray 框架的 IPC（摄像机）播放器功能集成组件。

在 [`@ray-js/ray-ipc-player`](https://www.npmjs.com/package/@ray-js/ray-ipc-player) 之上封装了一整套播放器上层能力：清晰度切换、截图、录制、静音、对讲、PTZ 云台、变焦、电量/温湿度/信号等状态显示、横竖屏切换、多目布局等，开箱即用，同时支持高度自定义控件与样式。

## 目录

- [特性](#特性)
- [安装](#安装)
- [快速开始](#快速开始)
- [核心概念](#核心概念)
- [API](#api)
  - [`<IPCPlayerIntegration />`](#ipcplayerintegration-)
  - [`useCtx(options)`](#usectxoptions)
  - [`useStore(atoms)`](#usestoreatoms)
  - [`Features`](#features)
  - [`Widgets`](#widgets)
  - [`Hooks`](#hooks)
  - [`Utils` 与设备工具](#utils-与设备工具)
- [自定义样式](#自定义样式)
- [事件](#事件)
- [多目（Multi-Camera）](#多目multi-camera)
- [本地开发](#本地开发)

## 特性

- 🎥 **融合播放器**：封装预览、连接、播放状态管理，对接 `@ray-js/ray-ipc-player`。
- 🧩 **声明式控件编排**：通过 `Features.initPlayerWidgets` 一键初始化默认控件，或按需向四角 / 绝对定位区域增删控件。
- 🛠 **丰富的内置控件**：清晰度、截图、录制、静音、对讲、PTZ、变焦、电量、温湿度、4G 信号、补光灯、警笛、试看等。
- 🎨 **可定制**：通过 `brandColor` 与 `CSSVariable` 自定义品牌色、图标、字体等样式。
- 📱 **横竖屏 / 多目**：支持竖屏、全屏、横屏及画中画 / 平铺 / 宫格等多目布局。
- 🪝 **Hooks 工具集**：`useBattery`、`usePtz`、`useTemperature` 等便捷读取设备状态。

## 安装

```sh
$ npm install @ray-js/ipc-player-integration
# 或者
$ yarn add @ray-js/ipc-player-integration
```

> 该组件依赖 `ahooks`（peerDependency），请确保宿主工程已安装。

## 快速开始

```tsx
import React, { useEffect, useRef } from 'react';
import { View } from '@ray-js/components';
import {
  IPCPlayerIntegration,
  useCtx,
  useStore,
  Features,
  EventInstance,
} from '@ray-js/ipc-player-integration';

export default function Home(props) {
  const devId = props.location.query?.deviceId;
  // 1. 创建播放器上下文实例
  const instance = useCtx({ devId });
  // 2. 订阅需要响应式渲染的状态
  const { screenType } = useStore({ screenType: instance.screenType });
  const eventRef = useRef<EventInstance>();

  // 3. 初始化默认控件（清晰度 / 截图 / 录制 / 全屏 等）
  useEffect(() => {
    Features.initPlayerWidgets(instance, {
      hideRecordVideoMenu: false,
      hideScreenShotMenu: false,
      hideResolutionMenu: false,
      showToggleVerticalFull: true,
    });
  }, []);

  return (
    <View>
      <IPCPlayerIntegration
        instance={instance}
        devId={instance.devId}
        eventRef={eventRef}
        deviceOnline
        brandColor="#FF592A"
        landscapeMode="fill"
        playerFit="contain"
        style={{ height: screenType === 'vertical' ? 'calc(100vw * 0.56)' : '100vh' }}
      />
    </View>
  );
}
```

## 核心概念

| 概念                       | 说明                                                                                                                                                                            |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **instance（上下文实例）** | 由 `useCtx({ devId })` 创建，贯穿整个播放器，管理状态原子、播放器实例、控件内容与事件总线。需将其传入 `<IPCPlayerIntegration instance={instance} />`。                          |
| **atom（状态原子）**       | 基于 [jotai](https://jotai.org/)。`instance` 上的状态(如 `screenType`、`mute`、`resolution`)均为原子，需通过 `useStore` 订阅才能触发响应式渲染。                                |
| **content 区域**           | 播放器画面上的控件分布在 5 个区域：`topLeft`、`topRight`、`bottomLeft`、`bottomRight`、`absolute`(绝对定位)。通过 `addContent` / `deleteContent` / `updateContent` 等方法管理。 |
| **event（事件总线）**      | `instance.event` 提供 `on/off/emit`，可通过 `eventRef` 暴露给页面，用于监听点击、清晰度切换等事件。                                                                             |

## API

### `<IPCPlayerIntegration />`

播放器主组件。

| 属性                     | 类型                             | 默认值               | 说明                                              |
| ------------------------ | -------------------------------- | -------------------- | ------------------------------------------------- |
| `devId`                  | `string`                         | —                    | 设备 ID（必填）                                   |
| `instance`               | `ReturnType<useCtx>`             | —                    | `useCtx` 创建的上下文实例；不传则组件内部自动创建 |
| `eventRef`               | `React.RefObject<EventInstance>` | —                    | 事件总线 ref，用于页面侧监听事件                  |
| `playerFit`              | `'contain' \| 'cover'`           | `'contain'`          | 画面填充模式                                      |
| `landscapeMode`          | `'fill' \| 'standard'`           | `'standard'`         | 横屏展示模式                                      |
| `brandColor`             | `string`                         | `'#FF592A'`          | 品牌色                                            |
| `CSSVariable`            | `Partial<CSSVariable>`           | —                    | 自定义 CSS 变量，详见[自定义样式](#自定义样式)    |
| `deviceOnline`           | `boolean`                        | `true`               | 设备是否在线                                      |
| `privateState`           | `boolean`                        | `false`              | 是否处于隐私模式（遮罩）                          |
| `verticalMic`            | `boolean`                        | `true`               | 竖屏是否展示麦克风对讲                            |
| `isShare`                | `boolean`                        | `false`              | 是否为分享设备                                    |
| `ignoreHideStopPreview`  | `boolean`                        | `false`              | 控件隐藏时是否忽略停止预览                        |
| `awakeStatus`            | `boolean`                        | `undefined`          | 低功耗设备唤醒状态                                |
| `autoWakeUp`             | `boolean`                        | `false`              | 是否自动唤醒设备                                  |
| `limitFlow`              | `boolean`                        | `false`              | 是否限流                                          |
| `showFlowLowTip`         | `boolean`                        | `false`              | 是否展示低流量提示                                |
| `previewEnabled`         | `boolean`                        | `undefined`          | 受控的预览开关                                    |
| `refreshElement`         | `boolean`                        | `false`              | 触发 CoverView 高度刷新                           |
| `playerRoute`            | `string`                         | `'pages/home/index'` | 播放器所在路由                                    |
| `style` / `className`    | `CSSProperties` / `string`       | —                    | 容器样式 / 类名                                   |
| `onPlayStatus`           | `(data: PlayStatusData) => void` | —                    | 播放状态变化回调                                  |
| `onPlayerTap`            | `(data) => void`                 | —                    | 点击播放器画面回调                                |
| `onPreviewEnabledChange` | `(enabled: boolean) => void`     | —                    | 预览开关变化回调                                  |

### `useCtx(options)`

创建播放器上下文实例。

```ts
const instance = useCtx({
  devId: string,                       // 设备 ID（必填）
  saveToAlbum?: 0 | 1,                 // 0：系统相册；1：IPC 相册
  showPtzControlTip?: boolean,         // 是否展示 PTZ 操作引导
  videoSplitProtocol?: VideoSplitProtocol, // 多目分割协议
  initTopLeftContent?: ComponentConfig[],     // 初始各区域控件
  initTopRightContent?: ComponentConfig[],
  initBottomLeftContent?: ComponentConfig[],
  initBottomRightContent?: ComponentConfig[],
  initAbsoluteContent?: ComponentConfig[],
});
```

返回的 `instance` 提供：

- **状态原子**：`screenType`、`mute`、`intercom`、`recording`、`resolution`、`resolutionList`、`playState`、`brandColor`、`verticalMic`、`isVerticalFullLayout` 等（配合 `useStore` 订阅）。
- **状态操作**：`setMute`、`setIntercom`、`setRecording`、`setResolution`、`setScreenType`、`setBrandColor`、`setPlayState`、`changeStreamStatus`、`getStreamStatus` 等。
- **控件内容管理**：`addContent(type, config, position?)`、`deleteContent(type, id)`、`updateContent(type, data)`、`getContent()`、`hasContent`、`hideContent`、`showContent`。
- **其他**：`IPCPlayerInstance`(底层播放器实例)、`event`(事件总线)、`toast`、`multiCameraCtx`(多目上下文)。

### `useStore(atoms)`

订阅 `instance` 上的状态原子,返回响应式的值对象。

```tsx
const { screenType, mute, resolution } = useStore({
  screenType: instance.screenType,
  mute: instance.mute,
  resolution: instance.resolution,
});
```

### `Features`

控件编排能力,通过 `import { Features } from '@ray-js/ipc-player-integration'` 引入。

#### `Features.initPlayerWidgets(instance, options)`

根据设备 DP 信息一键初始化默认控件。常用 `options`：

| 选项                                                                                                  | 类型                | 说明                     |
| ----------------------------------------------------------------------------------------------------- | ------------------- | ------------------------ |
| `hideScreenShotMenu`                                                                                  | `boolean`           | 隐藏截图按钮             |
| `hideRecordVideoMenu`                                                                                 | `boolean`           | 隐藏录制按钮             |
| `hideResolutionMenu`                                                                                  | `boolean`           | 隐藏清晰度按钮           |
| `hideKbsMenu`                                                                                         | `boolean`           | 隐藏码率显示             |
| `hideSignalMenu`                                                                                      | `boolean`           | 隐藏信号强度按钮         |
| `hideHorizontalMenu`                                                                                  | `boolean`           | 隐藏进入横屏按钮         |
| `verticalResolutionCustomClick`                                                                       | `boolean`           | 竖屏清晰度自定义点击     |
| `showToggleVerticalFull`                                                                              | `boolean`           | 展示单目竖屏全屏切换按钮 |
| `showRealTimeMagnification`                                                                           | `boolean`           | 展示实时倍数按钮         |
| `hideSmartImageQualityState`                                                                          | `boolean`           | 隐藏智能画质状态         |
| `directionControlProps`                                                                               | `object`            | PTZ 方向盘控件透传属性   |
| `topLeftContent` / `topRightContent` / `bottomLeftContent` / `bottomRightContent` / `absoluteContent` | `ComponentConfig[]` | 覆盖默认控件配置         |

#### `Features.updatePlayerWidgetProps(ctx, area, widgetId, newProps)`

动态更新指定区域中某个控件的属性。

```ts
Features.updatePlayerWidgetProps(instance, 'topRight', 'VideoBitKBP', {
  hideKbsMenu: true,
});
```

> `area`：`'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight' | 'absolute'`；`widgetId` 见下方控件清单。

### `Widgets`

通过 `import { Widgets } from '@ray-js/ipc-player-integration'` 引入,可独立使用各控件。常用控件：

| 控件                            | WidgetId                                      | 说明             |
| ------------------------------- | --------------------------------------------- | ---------------- |
| `Widgets.VoiceIntercom`         | `FullSmallIntercom` / `VerticalSmallIntercom` | 语音对讲按钮     |
| `Widgets.Screenshot`            | `Screenshot`                                  | 截图             |
| `Widgets.RecordVideo`           | `RecordVideo`                                 | 录制             |
| `Widgets.Muted`                 | `Muted`                                       | 静音             |
| `Widgets.Resolution`            | `Resolution`                                  | 清晰度切换       |
| `Widgets.FullScreen`            | `FullScreen`                                  | 全屏 / 横屏      |
| `Widgets.Ptz`                   | `Ptz`                                         | PTZ 云台控制     |
| `Widgets.VideoBitKBP`           | `VideoBitKBP`                                 | 码率 / 信号      |
| `Widgets.BatteryFull`           | `BatteryFull`                                 | 电量             |
| `Widgets.TempHumidity`          | `TempHumidity`                                | 温湿度           |
| `Widgets.Floodlight`            | `Floodlight`                                  | 补光灯           |
| `Widgets.Siren`                 | `Siren`                                       | 警笛             |
| `Widgets.TryExperience`         | `TryExperience`                               | 试看             |
| `Widgets.PtzControlTip`         | —                                             | PTZ 操作引导弹窗 |
| `Widgets.RealTimeMagnification` | —                                             | 实时倍数         |
| `Widgets.ToggleVerticalFull`    | —                                             | 竖屏全屏切换     |
| `Widgets.FlowLowTip`            | —                                             | 低流量提示       |

独立使用 `VoiceIntercom` 示例：

```tsx
<Widgets.VoiceIntercom
  ref={intercomRef}
  IPCPlayerContext={instance?.IPCPlayerInstance}
  {...instance}
  mode="circle" // 'verticalSmall' | 'fullSmall' | 'circle'
  disabled={false}
  icon={intercomLightSvg}
  talkingColor="#440F7C"
/>
```

向 `absolute` 区域插入 PTZ 引导弹窗：

```tsx
instance.addContent('absolute', {
  id: 'ptzControlTipId',
  content: props => <Widgets.PtzControlTip {...props} />,
  absoluteContentClassName: 'ipc-player-plugin-ptz-control-tip-wrap',
  initProps: { ...props },
});
```

### `Hooks`

便捷读取设备状态(均从包根导出)：

| Hook             | 签名                                           | 说明                |
| ---------------- | ---------------------------------------------- | ------------------- |
| `useBattery`     | `(devId) => { batteryValue, batteryCharging }` | 电池电量 / 充电状态 |
| `usePtz`         | `(devId) => boolean`                           | 是否支持 PTZ        |
| `useTemperature` | `(devId) => number`                            | 温度                |
| `useHumidity`    | `() => number`                                 | 湿度                |
| `useSignal4G`    | `(devId) => { dpValue, signalKey }`            | 4G 信号强度         |
| `useDpState`     | —                                              | DP 状态读写         |
| `useDpSupport`   | —                                              | DP 支持性判断       |
| `useSchemaInfo`  | —                                              | 设备 schema 信息    |
| `useMemoizedFn`  | —                                              | 稳定函数引用        |

### `Utils` 与设备工具

```ts
import { Utils } from '@ray-js/ipc-player-integration';
// 设备相关工具单独从子路径引入
import {
  getDpValue,
  getDeviceInfo,
  getDpSchemaByCodes,
  getDpSchemaByCodesSync,
  hasDpCode,
} from '@ray-js/ipc-player-integration/utils/device';
```

- `getDpSchemaByCodes(devId, codes)`：按 DP code 批量获取 schema。
- `hasDpCode(devId, code)`：判断设备是否包含某 DP。
- `Utils.radialGradient(color)` / `Utils.adjustBrightness(hex, factor)`：颜色处理工具。

## 自定义样式

### 品牌色

通过 `brandColor` 属性或 `instance.setBrandColor(color)` 设置。

### CSS 变量

通过 `CSSVariable` 属性覆盖：

```tsx
<IPCPlayerIntegration
  CSSVariable={{
    '--iconColor': '#fff',
    '--iconActiveColor': '#ec653c',
    '--iconFontSize': '20px',
    '--bg-color': '#000',
    '--fontColor': '#fff',
    '--fontSize': '12px',
  }}
/>
```

可用变量：`--iconColor`、`--iconActiveColor`、`--iconFontSize`、`--iconPlayerSize`、`--iconBoxSize`、`--bg-color`、`--shot-card-bg-color`、`--fontColor`、`--fontSize`。

## 事件

通过 `eventRef` 拿到事件总线后,可监听播放器内部事件：

```tsx
const eventRef = useRef<EventInstance>();

useEffect(() => {
  const onResolutionClick = () => console.log('清晰度按钮点击');
  const onWidgetClick = data => console.log('控件点击', data);
  eventRef.current.on('resolutionBtnControlClick', onResolutionClick);
  eventRef.current.on('widgetClick', onWidgetClick);
  return () => {
    eventRef.current.off('resolutionBtnControlClick', onResolutionClick);
    eventRef.current.off('widgetClick', onWidgetClick);
  };
}, []);
```

## 多目（Multi-Camera）

支持画中画、平铺、宫格、缩略图等多目布局,相关类型从包根导出：

- `MultiCameraScreenMode`：屏幕模式（`short` / `full` / `landscape`）。
- `MultiCameraLayoutStyle`：布局样式（`pip` 画中画 / `tile` 平铺 / `grid` 宫格 / `thumbnail` 缩略图）。
- `VideoSplitProtocol`：多目分割协议,通过 `useCtx({ videoSplitProtocol })` 传入。
- `MultiCameraLenInfo`：镜头信息（索引、名称、是否支持 PTZ / Zoom / Localizer）。

多目上下文可通过 `instance.multiCameraCtx` 访问。

## 本地开发

```sh
# 安装依赖
yarn

# 实时编译并预览示例（涂鸦端）
yarn start:tuya

# 构建组件
yarn build
```

其他可用脚本：`start:wechat`、`start:web`、`start:native`、`build:tuya`、`build:wechat`、`build:web`、`build:native`。