@ray-js/ipc-player-integration 0.0.38 → 0.0.39
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/README.md +337 -8
- package/lib/ctx/ctx.js +10 -7
- package/lib/ctx/multiCameraCtx.d.ts +4 -0
- package/lib/ctx/multiCameraCtx.js +8 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -4,7 +4,37 @@ English | [简体中文](./README-zh_CN.md)
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@ray-js/ipc-player-integration) [](https://www.npmjs.com/package/@ray-js/ipc-player-integration)
|
|
6
6
|
|
|
7
|
-
> IPC
|
|
7
|
+
> IPC integrated player — an all-in-one IPC (camera) player feature integration component for the Tuya Ray framework.
|
|
8
|
+
|
|
9
|
+
Built on top of [`@ray-js/ray-ipc-player`](https://www.npmjs.com/package/@ray-js/ray-ipc-player), it wraps a complete set of upper-layer player capabilities: resolution switching, screenshot, recording, mute, two-way talk, PTZ control, zoom, battery / temperature & humidity / signal status display, portrait–landscape switching, multi-camera layouts and more — ready to use out of the box, while remaining highly customizable for both widgets and styles.
|
|
10
|
+
|
|
11
|
+
## Table of Contents
|
|
12
|
+
|
|
13
|
+
- [Features](#features)
|
|
14
|
+
- [Installation](#installation)
|
|
15
|
+
- [Quick Start](#quick-start)
|
|
16
|
+
- [Core Concepts](#core-concepts)
|
|
17
|
+
- [API](#api)
|
|
18
|
+
- [`<IPCPlayerIntegration />`](#ipcplayerintegration-)
|
|
19
|
+
- [`useCtx(options)`](#usectxoptions)
|
|
20
|
+
- [`useStore(atoms)`](#usestoreatoms)
|
|
21
|
+
- [`Features`](#features-1)
|
|
22
|
+
- [`Widgets`](#widgets)
|
|
23
|
+
- [`Hooks`](#hooks)
|
|
24
|
+
- [`Utils` & device helpers](#utils--device-helpers)
|
|
25
|
+
- [Custom Styling](#custom-styling)
|
|
26
|
+
- [Events](#events)
|
|
27
|
+
- [Multi-Camera](#multi-camera)
|
|
28
|
+
- [Develop](#develop)
|
|
29
|
+
|
|
30
|
+
## Features
|
|
31
|
+
|
|
32
|
+
- 🎥 **Integrated player**: encapsulates preview, connection and play-state management on top of `@ray-js/ray-ipc-player`.
|
|
33
|
+
- 🧩 **Declarative widget orchestration**: initialize default widgets with one call to `Features.initPlayerWidgets`, or add/remove widgets in the four corners and the absolute-positioned area on demand.
|
|
34
|
+
- 🛠 **Rich built-in widgets**: resolution, screenshot, recording, mute, intercom, PTZ, zoom, battery, temperature & humidity, 4G signal, floodlight, siren, trial, and more.
|
|
35
|
+
- 🎨 **Customizable**: tailor brand color, icons and fonts via `brandColor` and `CSSVariable`.
|
|
36
|
+
- 📱 **Portrait / landscape / multi-camera**: supports portrait, fullscreen, landscape, and PiP / tile / grid multi-camera layouts.
|
|
37
|
+
- 🪝 **Hook toolkit**: `useBattery`, `usePtz`, `useTemperature` and others for convenient device-state access.
|
|
8
38
|
|
|
9
39
|
## Installation
|
|
10
40
|
|
|
@@ -14,19 +44,318 @@ $ npm install @ray-js/ipc-player-integration
|
|
|
14
44
|
$ yarn add @ray-js/ipc-player-integration
|
|
15
45
|
```
|
|
16
46
|
|
|
47
|
+
> This component requires `ahooks` (a peerDependency); make sure it is installed in the host project.
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import React, { useEffect, useRef } from 'react';
|
|
53
|
+
import { View } from '@ray-js/components';
|
|
54
|
+
import {
|
|
55
|
+
IPCPlayerIntegration,
|
|
56
|
+
useCtx,
|
|
57
|
+
useStore,
|
|
58
|
+
Features,
|
|
59
|
+
EventInstance,
|
|
60
|
+
} from '@ray-js/ipc-player-integration';
|
|
61
|
+
|
|
62
|
+
export default function Home(props) {
|
|
63
|
+
const devId = props.location.query?.deviceId;
|
|
64
|
+
// 1. Create the player context instance
|
|
65
|
+
const instance = useCtx({ devId });
|
|
66
|
+
// 2. Subscribe to the state you want to render reactively
|
|
67
|
+
const { screenType } = useStore({ screenType: instance.screenType });
|
|
68
|
+
const eventRef = useRef<EventInstance>();
|
|
69
|
+
|
|
70
|
+
// 3. Initialize default widgets (resolution / screenshot / record / fullscreen ...)
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
Features.initPlayerWidgets(instance, {
|
|
73
|
+
hideRecordVideoMenu: false,
|
|
74
|
+
hideScreenShotMenu: false,
|
|
75
|
+
hideResolutionMenu: false,
|
|
76
|
+
showToggleVerticalFull: true,
|
|
77
|
+
});
|
|
78
|
+
}, []);
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<View>
|
|
82
|
+
<IPCPlayerIntegration
|
|
83
|
+
instance={instance}
|
|
84
|
+
devId={instance.devId}
|
|
85
|
+
eventRef={eventRef}
|
|
86
|
+
deviceOnline
|
|
87
|
+
brandColor="#FF592A"
|
|
88
|
+
landscapeMode="fill"
|
|
89
|
+
playerFit="contain"
|
|
90
|
+
style={{ height: screenType === 'vertical' ? 'calc(100vw * 0.56)' : '100vh' }}
|
|
91
|
+
/>
|
|
92
|
+
</View>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Core Concepts
|
|
98
|
+
|
|
99
|
+
| Concept | Description |
|
|
100
|
+
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
101
|
+
| **instance** | Created by `useCtx({ devId })`, it spans the whole player and manages state atoms, the player instance, widget content and the event bus. Pass it to `<IPCPlayerIntegration instance={instance} />`. |
|
|
102
|
+
| **atom** | Based on [jotai](https://jotai.org/). State on the `instance` (e.g. `screenType`, `mute`, `resolution`) are atoms; subscribe via `useStore` to render reactively. |
|
|
103
|
+
| **content areas** | Widgets on the player are distributed across 5 areas: `topLeft`, `topRight`, `bottomLeft`, `bottomRight`, `absolute`. Managed via `addContent` / `deleteContent` / `updateContent`, etc. |
|
|
104
|
+
| **event** | `instance.event` provides `on/off/emit`. Expose it to the page through `eventRef` to listen for clicks, resolution switches and other events. |
|
|
105
|
+
|
|
106
|
+
## API
|
|
107
|
+
|
|
108
|
+
### `<IPCPlayerIntegration />`
|
|
109
|
+
|
|
110
|
+
The main player component.
|
|
111
|
+
|
|
112
|
+
| Prop | Type | Default | Description |
|
|
113
|
+
| ------------------------ | -------------------------------- | -------------------- | ----------------------------------------------------------------- |
|
|
114
|
+
| `devId` | `string` | — | Device ID (required) |
|
|
115
|
+
| `instance` | `ReturnType<useCtx>` | — | The context instance from `useCtx`; created internally if omitted |
|
|
116
|
+
| `eventRef` | `React.RefObject<EventInstance>` | — | Event-bus ref for listening on the page side |
|
|
117
|
+
| `playerFit` | `'contain' \| 'cover'` | `'contain'` | Video fit mode |
|
|
118
|
+
| `landscapeMode` | `'fill' \| 'standard'` | `'standard'` | Landscape display mode |
|
|
119
|
+
| `brandColor` | `string` | `'#FF592A'` | Brand color |
|
|
120
|
+
| `CSSVariable` | `Partial<CSSVariable>` | — | Custom CSS variables, see [Custom Styling](#custom-styling) |
|
|
121
|
+
| `deviceOnline` | `boolean` | `true` | Whether the device is online |
|
|
122
|
+
| `privateState` | `boolean` | `false` | Whether privacy mode (mask) is on |
|
|
123
|
+
| `verticalMic` | `boolean` | `true` | Whether to show the mic intercom in portrait |
|
|
124
|
+
| `isShare` | `boolean` | `false` | Whether it is a shared device |
|
|
125
|
+
| `ignoreHideStopPreview` | `boolean` | `false` | Ignore stop-preview when widgets hide |
|
|
126
|
+
| `awakeStatus` | `boolean` | `undefined` | Wake-up status for low-power devices |
|
|
127
|
+
| `autoWakeUp` | `boolean` | `false` | Auto wake up the device |
|
|
128
|
+
| `limitFlow` | `boolean` | `false` | Whether flow is limited |
|
|
129
|
+
| `showFlowLowTip` | `boolean` | `false` | Show the low-flow tip |
|
|
130
|
+
| `previewEnabled` | `boolean` | `undefined` | Controlled preview switch |
|
|
131
|
+
| `refreshElement` | `boolean` | `false` | Trigger a CoverView height refresh |
|
|
132
|
+
| `playerRoute` | `string` | `'pages/home/index'` | Route the player lives on |
|
|
133
|
+
| `style` / `className` | `CSSProperties` / `string` | — | Container style / className |
|
|
134
|
+
| `onPlayStatus` | `(data: PlayStatusData) => void` | — | Play-state change callback |
|
|
135
|
+
| `onPlayerTap` | `(data) => void` | — | Tap-on-video callback |
|
|
136
|
+
| `onPreviewEnabledChange` | `(enabled: boolean) => void` | — | Preview-switch change callback |
|
|
137
|
+
|
|
138
|
+
### `useCtx(options)`
|
|
139
|
+
|
|
140
|
+
Creates the player context instance.
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
const instance = useCtx({
|
|
144
|
+
devId: string, // Device ID (required)
|
|
145
|
+
saveToAlbum?: 0 | 1, // 0: system album; 1: IPC album
|
|
146
|
+
showPtzControlTip?: boolean, // Show the PTZ control guide
|
|
147
|
+
videoSplitProtocol?: VideoSplitProtocol, // Multi-camera split protocol
|
|
148
|
+
initTopLeftContent?: ComponentConfig[], // Initial widgets per area
|
|
149
|
+
initTopRightContent?: ComponentConfig[],
|
|
150
|
+
initBottomLeftContent?: ComponentConfig[],
|
|
151
|
+
initBottomRightContent?: ComponentConfig[],
|
|
152
|
+
initAbsoluteContent?: ComponentConfig[],
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The returned `instance` provides:
|
|
157
|
+
|
|
158
|
+
- **State atoms**: `screenType`, `mute`, `intercom`, `recording`, `resolution`, `resolutionList`, `playState`, `brandColor`, `verticalMic`, `isVerticalFullLayout`, etc. (subscribe via `useStore`).
|
|
159
|
+
- **State setters**: `setMute`, `setIntercom`, `setRecording`, `setResolution`, `setScreenType`, `setBrandColor`, `setPlayState`, `changeStreamStatus`, `getStreamStatus`, etc.
|
|
160
|
+
- **Content management**: `addContent(type, config, position?)`, `deleteContent(type, id)`, `updateContent(type, data)`, `getContent()`, `hasContent`, `hideContent`, `showContent`.
|
|
161
|
+
- **Misc**: `IPCPlayerInstance` (the underlying player instance), `event` (event bus), `toast`, `multiCameraCtx` (multi-camera context).
|
|
162
|
+
|
|
163
|
+
### `useStore(atoms)`
|
|
164
|
+
|
|
165
|
+
Subscribes to state atoms on the `instance` and returns a reactive value object.
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
const { screenType, mute, resolution } = useStore({
|
|
169
|
+
screenType: instance.screenType,
|
|
170
|
+
mute: instance.mute,
|
|
171
|
+
resolution: instance.resolution,
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### `Features`
|
|
176
|
+
|
|
177
|
+
Widget-orchestration capabilities, imported via `import { Features } from '@ray-js/ipc-player-integration'`.
|
|
178
|
+
|
|
179
|
+
#### `Features.initPlayerWidgets(instance, options)`
|
|
180
|
+
|
|
181
|
+
Initializes the default widgets based on the device's DP info. Common `options`:
|
|
182
|
+
|
|
183
|
+
| Option | Type | Description |
|
|
184
|
+
| ----------------------------------------------------------------------------------------------------- | ------------------- | ------------------------------------------------ |
|
|
185
|
+
| `hideScreenShotMenu` | `boolean` | Hide the screenshot button |
|
|
186
|
+
| `hideRecordVideoMenu` | `boolean` | Hide the record button |
|
|
187
|
+
| `hideResolutionMenu` | `boolean` | Hide the resolution button |
|
|
188
|
+
| `hideKbsMenu` | `boolean` | Hide the bitrate display |
|
|
189
|
+
| `hideSignalMenu` | `boolean` | Hide the signal-strength button |
|
|
190
|
+
| `hideHorizontalMenu` | `boolean` | Hide the enter-landscape button |
|
|
191
|
+
| `verticalResolutionCustomClick` | `boolean` | Custom click for portrait resolution |
|
|
192
|
+
| `showToggleVerticalFull` | `boolean` | Show the single-cam portrait-fullscreen toggle |
|
|
193
|
+
| `showRealTimeMagnification` | `boolean` | Show the real-time magnification button |
|
|
194
|
+
| `hideSmartImageQualityState` | `boolean` | Hide the smart image-quality state |
|
|
195
|
+
| `directionControlProps` | `object` | Pass-through props for the PTZ direction control |
|
|
196
|
+
| `topLeftContent` / `topRightContent` / `bottomLeftContent` / `bottomRightContent` / `absoluteContent` | `ComponentConfig[]` | Override default widget config |
|
|
197
|
+
|
|
198
|
+
#### `Features.updatePlayerWidgetProps(ctx, area, widgetId, newProps)`
|
|
199
|
+
|
|
200
|
+
Dynamically updates props of a widget in a given area.
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
Features.updatePlayerWidgetProps(instance, 'topRight', 'VideoBitKBP', {
|
|
204
|
+
hideKbsMenu: true,
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
> `area`: `'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight' | 'absolute'`; for `widgetId` see the widget list below.
|
|
209
|
+
|
|
210
|
+
### `Widgets`
|
|
211
|
+
|
|
212
|
+
Imported via `import { Widgets } from '@ray-js/ipc-player-integration'`; each widget can be used standalone. Common widgets:
|
|
213
|
+
|
|
214
|
+
| Widget | WidgetId | Description |
|
|
215
|
+
| ------------------------------- | --------------------------------------------- | -------------------------- |
|
|
216
|
+
| `Widgets.VoiceIntercom` | `FullSmallIntercom` / `VerticalSmallIntercom` | Two-way talk button |
|
|
217
|
+
| `Widgets.Screenshot` | `Screenshot` | Screenshot |
|
|
218
|
+
| `Widgets.RecordVideo` | `RecordVideo` | Recording |
|
|
219
|
+
| `Widgets.Muted` | `Muted` | Mute |
|
|
220
|
+
| `Widgets.Resolution` | `Resolution` | Resolution switch |
|
|
221
|
+
| `Widgets.FullScreen` | `FullScreen` | Fullscreen / landscape |
|
|
222
|
+
| `Widgets.Ptz` | `Ptz` | PTZ control |
|
|
223
|
+
| `Widgets.VideoBitKBP` | `VideoBitKBP` | Bitrate / signal |
|
|
224
|
+
| `Widgets.BatteryFull` | `BatteryFull` | Battery |
|
|
225
|
+
| `Widgets.TempHumidity` | `TempHumidity` | Temperature & humidity |
|
|
226
|
+
| `Widgets.Floodlight` | `Floodlight` | Floodlight |
|
|
227
|
+
| `Widgets.Siren` | `Siren` | Siren |
|
|
228
|
+
| `Widgets.TryExperience` | `TryExperience` | Trial |
|
|
229
|
+
| `Widgets.PtzControlTip` | — | PTZ control guide dialog |
|
|
230
|
+
| `Widgets.RealTimeMagnification` | — | Real-time magnification |
|
|
231
|
+
| `Widgets.ToggleVerticalFull` | — | Portrait-fullscreen toggle |
|
|
232
|
+
| `Widgets.FlowLowTip` | — | Low-flow tip |
|
|
233
|
+
|
|
234
|
+
Standalone `VoiceIntercom` example:
|
|
235
|
+
|
|
236
|
+
```tsx
|
|
237
|
+
<Widgets.VoiceIntercom
|
|
238
|
+
ref={intercomRef}
|
|
239
|
+
IPCPlayerContext={instance?.IPCPlayerInstance}
|
|
240
|
+
{...instance}
|
|
241
|
+
mode="circle" // 'verticalSmall' | 'fullSmall' | 'circle'
|
|
242
|
+
disabled={false}
|
|
243
|
+
icon={intercomLightSvg}
|
|
244
|
+
talkingColor="#440F7C"
|
|
245
|
+
/>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Insert the PTZ guide dialog into the `absolute` area:
|
|
249
|
+
|
|
250
|
+
```tsx
|
|
251
|
+
instance.addContent('absolute', {
|
|
252
|
+
id: 'ptzControlTipId',
|
|
253
|
+
content: props => <Widgets.PtzControlTip {...props} />,
|
|
254
|
+
absoluteContentClassName: 'ipc-player-plugin-ptz-control-tip-wrap',
|
|
255
|
+
initProps: { ...props },
|
|
256
|
+
});
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### `Hooks`
|
|
260
|
+
|
|
261
|
+
Convenient device-state access (all exported from the package root):
|
|
262
|
+
|
|
263
|
+
| Hook | Signature | Description |
|
|
264
|
+
| ---------------- | ---------------------------------------------- | ------------------------------ |
|
|
265
|
+
| `useBattery` | `(devId) => { batteryValue, batteryCharging }` | Battery level / charging state |
|
|
266
|
+
| `usePtz` | `(devId) => boolean` | Whether PTZ is supported |
|
|
267
|
+
| `useTemperature` | `(devId) => number` | Temperature |
|
|
268
|
+
| `useHumidity` | `() => number` | Humidity |
|
|
269
|
+
| `useSignal4G` | `(devId) => { dpValue, signalKey }` | 4G signal strength |
|
|
270
|
+
| `useDpState` | — | Read/write DP state |
|
|
271
|
+
| `useDpSupport` | — | DP support check |
|
|
272
|
+
| `useSchemaInfo` | — | Device schema info |
|
|
273
|
+
| `useMemoizedFn` | — | Stable function reference |
|
|
274
|
+
|
|
275
|
+
### `Utils` & device helpers
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
import { Utils } from '@ray-js/ipc-player-integration';
|
|
279
|
+
// Device helpers are imported from a sub-path
|
|
280
|
+
import {
|
|
281
|
+
getDpValue,
|
|
282
|
+
getDeviceInfo,
|
|
283
|
+
getDpSchemaByCodes,
|
|
284
|
+
getDpSchemaByCodesSync,
|
|
285
|
+
hasDpCode,
|
|
286
|
+
} from '@ray-js/ipc-player-integration/utils/device';
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
- `getDpSchemaByCodes(devId, codes)`: batch-fetch schema by DP code.
|
|
290
|
+
- `hasDpCode(devId, code)`: check whether the device has a given DP.
|
|
291
|
+
- `Utils.radialGradient(color)` / `Utils.adjustBrightness(hex, factor)`: color helpers.
|
|
292
|
+
|
|
293
|
+
## Custom Styling
|
|
294
|
+
|
|
295
|
+
### Brand color
|
|
296
|
+
|
|
297
|
+
Set via the `brandColor` prop or `instance.setBrandColor(color)`.
|
|
298
|
+
|
|
299
|
+
### CSS variables
|
|
300
|
+
|
|
301
|
+
Override via the `CSSVariable` prop:
|
|
302
|
+
|
|
303
|
+
```tsx
|
|
304
|
+
<IPCPlayerIntegration
|
|
305
|
+
CSSVariable={{
|
|
306
|
+
'--iconColor': '#fff',
|
|
307
|
+
'--iconActiveColor': '#ec653c',
|
|
308
|
+
'--iconFontSize': '20px',
|
|
309
|
+
'--bg-color': '#000',
|
|
310
|
+
'--fontColor': '#fff',
|
|
311
|
+
'--fontSize': '12px',
|
|
312
|
+
}}
|
|
313
|
+
/>
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Available variables: `--iconColor`, `--iconActiveColor`, `--iconFontSize`, `--iconPlayerSize`, `--iconBoxSize`, `--bg-color`, `--shot-card-bg-color`, `--fontColor`, `--fontSize`.
|
|
317
|
+
|
|
318
|
+
## Events
|
|
319
|
+
|
|
320
|
+
Once you have the event bus through `eventRef`, you can listen to internal player events:
|
|
321
|
+
|
|
322
|
+
```tsx
|
|
323
|
+
const eventRef = useRef<EventInstance>();
|
|
324
|
+
|
|
325
|
+
useEffect(() => {
|
|
326
|
+
const onResolutionClick = () => console.log('resolution button clicked');
|
|
327
|
+
const onWidgetClick = data => console.log('widget clicked', data);
|
|
328
|
+
eventRef.current.on('resolutionBtnControlClick', onResolutionClick);
|
|
329
|
+
eventRef.current.on('widgetClick', onWidgetClick);
|
|
330
|
+
return () => {
|
|
331
|
+
eventRef.current.off('resolutionBtnControlClick', onResolutionClick);
|
|
332
|
+
eventRef.current.off('widgetClick', onWidgetClick);
|
|
333
|
+
};
|
|
334
|
+
}, []);
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## Multi-Camera
|
|
338
|
+
|
|
339
|
+
Supports PiP, tile, grid and thumbnail multi-camera layouts. Related types are exported from the package root:
|
|
340
|
+
|
|
341
|
+
- `MultiCameraScreenMode`: screen mode (`short` / `full` / `landscape`).
|
|
342
|
+
- `MultiCameraLayoutStyle`: layout style (`pip` / `tile` / `grid` / `thumbnail`).
|
|
343
|
+
- `VideoSplitProtocol`: the multi-camera split protocol, passed via `useCtx({ videoSplitProtocol })`.
|
|
344
|
+
- `MultiCameraLenInfo`: lens info (index, name, whether PTZ / Zoom / Localizer is supported).
|
|
345
|
+
|
|
346
|
+
The multi-camera context is accessible via `instance.multiCameraCtx`.
|
|
347
|
+
|
|
17
348
|
## Develop
|
|
18
349
|
|
|
19
350
|
```sh
|
|
20
351
|
# install deps
|
|
21
352
|
yarn
|
|
22
353
|
|
|
23
|
-
# watch
|
|
354
|
+
# watch & preview the demo (Tuya target)
|
|
24
355
|
yarn start:tuya
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Usage
|
|
28
356
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
export default () => <Foo />;
|
|
357
|
+
# build the component
|
|
358
|
+
yarn build
|
|
32
359
|
```
|
|
360
|
+
|
|
361
|
+
Other available scripts: `start:wechat`, `start:web`, `start:native`, `build:tuya`, `build:wechat`, `build:web`, `build:native`.
|
package/lib/ctx/ctx.js
CHANGED
|
@@ -11,7 +11,7 @@ import { PlayState, IntercomMode } from '../interface';
|
|
|
11
11
|
import { changeIgnoreHideStopPreview } from '../ui/constant';
|
|
12
12
|
import { ClarityType } from '@ray-js/ray-ipc-utils/lib/interface';
|
|
13
13
|
import { getEventInstance } from './event';
|
|
14
|
-
import { useMultiCameraCtx } from './multiCameraCtx';
|
|
14
|
+
import { isMultiCameraTileSupported, useMultiCameraCtx } from './multiCameraCtx';
|
|
15
15
|
const SAVE_TO_ALBUM = 1;
|
|
16
16
|
export const createUseCtx = _ref => {
|
|
17
17
|
let {
|
|
@@ -42,9 +42,16 @@ export const createUseCtx = _ref => {
|
|
|
42
42
|
const streamStatus = useRef();
|
|
43
43
|
// 全屏、竖屏
|
|
44
44
|
const [screenType, setScreenType] = useAtom('vertical');
|
|
45
|
+
const IPCPlayerInstance = useRef();
|
|
46
|
+
if (!IPCPlayerInstance.current) {
|
|
47
|
+
IPCPlayerInstance.current = createPlayContext(devId);
|
|
48
|
+
}
|
|
45
49
|
|
|
46
|
-
//
|
|
47
|
-
|
|
50
|
+
// 是否处于竖屏填充布局。
|
|
51
|
+
// 多目平铺设备首帧即按竖屏填充渲染:screenMode 初始就是 full(multiCameraCtx),
|
|
52
|
+
// 若此处初始为 false,首帧会以 16:9 短屏渲染、effect 后才切全高,
|
|
53
|
+
// 原生层在该尺寸跳变窗口内可能丢失 viewPos 更新,残留短屏尺寸。
|
|
54
|
+
const [isVerticalFullLayout, setIsVerticalFullLayout] = useAtom(isMultiCameraTileSupported(videoSplitProtocol, IPCPlayerInstance.current));
|
|
48
55
|
|
|
49
56
|
// 录像中
|
|
50
57
|
const [recording] = useAtom(false);
|
|
@@ -184,10 +191,6 @@ export const createUseCtx = _ref => {
|
|
|
184
191
|
|
|
185
192
|
// 判断是否已经有了对应id的content
|
|
186
193
|
|
|
187
|
-
const IPCPlayerInstance = useRef();
|
|
188
|
-
if (!IPCPlayerInstance.current) {
|
|
189
|
-
IPCPlayerInstance.current = createPlayContext(devId);
|
|
190
|
-
}
|
|
191
194
|
const _setMute = async function (target) {
|
|
192
195
|
let onlyUpdateAtom = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
193
196
|
if (onlyUpdateAtom) {
|
|
@@ -16,6 +16,10 @@ interface Props {
|
|
|
16
16
|
IPCPlayerInstance: IpcContext;
|
|
17
17
|
videoSplitProtocol?: VideoSplitProtocol;
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* 是否支持多目平铺布局(协议 + 基础库能力),首次渲染即可同步判定
|
|
21
|
+
*/
|
|
22
|
+
export declare const isMultiCameraTileSupported: (videoSplitProtocol?: VideoSplitProtocol, IPCPlayerInstance?: IpcContext) => boolean;
|
|
19
23
|
/**
|
|
20
24
|
* 多目摄像头相关状态、方法维护
|
|
21
25
|
*/
|
|
@@ -25,6 +25,13 @@ const DEFAULT_SELECTED_LEN_INFO = {
|
|
|
25
25
|
supportLocalizer: false,
|
|
26
26
|
supportZoom: false
|
|
27
27
|
};
|
|
28
|
+
/**
|
|
29
|
+
* 是否支持多目平铺布局(协议 + 基础库能力),首次渲染即可同步判定
|
|
30
|
+
*/
|
|
31
|
+
export const isMultiCameraTileSupported = (videoSplitProtocol, IPCPlayerInstance) => {
|
|
32
|
+
return (videoSplitProtocol === null || videoSplitProtocol === void 0 ? void 0 : videoSplitProtocol.total_split_num) > 1 && (videoSplitProtocol === null || videoSplitProtocol === void 0 ? void 0 : videoSplitProtocol.p_v) >= 3 && typeof (IPCPlayerInstance === null || IPCPlayerInstance === void 0 ? void 0 : IPCPlayerInstance.switchLayoutStyle) === 'function';
|
|
33
|
+
};
|
|
34
|
+
|
|
28
35
|
/**
|
|
29
36
|
* 多目摄像头相关状态、方法维护
|
|
30
37
|
*/
|
|
@@ -35,7 +42,7 @@ export const useMultiCameraCtx = props => {
|
|
|
35
42
|
videoSplitProtocol = DEFAULT_VIDEO_SPLIT_PROTOCOL
|
|
36
43
|
} = props;
|
|
37
44
|
const isSupport = useMemo(() => {
|
|
38
|
-
return (videoSplitProtocol
|
|
45
|
+
return isMultiCameraTileSupported(videoSplitProtocol, IPCPlayerInstance);
|
|
39
46
|
}, [IPCPlayerInstance, videoSplitProtocol]);
|
|
40
47
|
const dpSupportMap = useDpSupport({
|
|
41
48
|
devId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ray-js/ipc-player-integration",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.39",
|
|
4
4
|
"description": "IPC 融合播放器",
|
|
5
5
|
"main": "lib/index",
|
|
6
6
|
"files": [
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@ray-js/direction-control": "^0.0.8",
|
|
39
39
|
"@ray-js/ipc-ptz-zoom": "^0.0.3",
|
|
40
|
-
"@ray-js/ray-ipc-player": "^2.1.
|
|
40
|
+
"@ray-js/ray-ipc-player": "^2.1.3",
|
|
41
41
|
"@ray-js/ray-ipc-utils": "^1.1.15",
|
|
42
42
|
"@ray-js/svg": "0.2.0",
|
|
43
43
|
"clsx": "^1.2.1",
|