expo-nodemediaclient 0.2.3 → 0.2.4
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 +78 -78
- package/README_CN.md +293 -0
- package/android/build.gradle +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
# expo-nodemediaclient
|
|
2
2
|
|
|
3
|
-
##
|
|
4
|
-
-
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
##
|
|
12
|
-
|
|
13
|
-
|
|
3
|
+
## Features
|
|
4
|
+
- Support for iOS and Android
|
|
5
|
+
- Support for RTMP, HLS, HTTP-FLV, RTSP playback
|
|
6
|
+
- Support for H.264, H.265 video encoding
|
|
7
|
+
- Support for AAC, PCM audio encoding
|
|
8
|
+
- Hardware acceleration support
|
|
9
|
+
- Low-latency playback with cumulative latency elimination
|
|
10
|
+
|
|
11
|
+
## Prerequisites
|
|
12
|
+
Your Expo project should use Continuous Native Generation [(CNG)](https://docs.expo.dev/workflow/continuous-native-generation/)
|
|
13
|
+
If not, please run first:
|
|
14
14
|
```bash
|
|
15
15
|
npx expo prebuild
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## Installation
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
21
|
npm install expo-nodemediaclient
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
##
|
|
25
|
-
###
|
|
26
|
-
|
|
24
|
+
## Usage
|
|
25
|
+
### Register SDK
|
|
26
|
+
Android and iOS require different license codes, which need to be registered separately. Please contact [https://www.nodemedia.cn](https://www.nodemedia.cn) to obtain license codes.
|
|
27
27
|
|
|
28
28
|
```js
|
|
29
29
|
import { NodeMediaClient } from 'expo-nodemediaclient';
|
|
@@ -38,7 +38,7 @@ if (Platform.OS === 'ios') {
|
|
|
38
38
|
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
###
|
|
41
|
+
### Playback
|
|
42
42
|
|
|
43
43
|
```js
|
|
44
44
|
import { NodePlayer, NodePlayerRef } from 'expo-nodemediaclient';
|
|
@@ -74,44 +74,44 @@ export default function App() {
|
|
|
74
74
|
}
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
###
|
|
77
|
+
### Component Props
|
|
78
78
|
|
|
79
|
-
|
|
|
79
|
+
| Prop | Type | Description |
|
|
80
80
|
|------|------|------|
|
|
81
|
-
| `url` | `string` |
|
|
82
|
-
| `bufferTime` | `number` |
|
|
83
|
-
| `scaleMode` | `number` |
|
|
84
|
-
| `volume` | `number` |
|
|
85
|
-
| `onEventCallback` | `(event) => void` |
|
|
81
|
+
| `url` | `string` | Playback URL (supports RTMP, RTSP, HLS, HTTP-FLV) |
|
|
82
|
+
| `bufferTime` | `number` | Buffer time in milliseconds, default 1000 |
|
|
83
|
+
| `scaleMode` | `number` | Scale mode, `0`=fill, `1`=fit, `2`=stretch |
|
|
84
|
+
| `volume` | `number` | Volume (0.0 - 1.0), default 1.0 |
|
|
85
|
+
| `onEventCallback` | `(event) => void` | Event callback |
|
|
86
86
|
|
|
87
|
-
###
|
|
87
|
+
### Common Methods
|
|
88
88
|
|
|
89
89
|
```js
|
|
90
|
-
//
|
|
90
|
+
// Start playback
|
|
91
91
|
playerRef.current?.start(url);
|
|
92
92
|
|
|
93
|
-
//
|
|
93
|
+
// Stop playback
|
|
94
94
|
playerRef.current?.stop();
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
###
|
|
97
|
+
### Event Callback
|
|
98
98
|
|
|
99
99
|
```js
|
|
100
100
|
const handleEvent = (event: { nativeEvent: NodePlayerEventCallback }) => {
|
|
101
|
-
console.log('
|
|
102
|
-
console.log('
|
|
101
|
+
console.log('Event code:', event.nativeEvent.event);
|
|
102
|
+
console.log('Message:', event.nativeEvent.msg);
|
|
103
103
|
};
|
|
104
104
|
|
|
105
105
|
<NodePlayer
|
|
106
106
|
onEventCallback={handleEvent}
|
|
107
|
-
//
|
|
107
|
+
// ...other props
|
|
108
108
|
/>
|
|
109
109
|
```
|
|
110
110
|
|
|
111
111
|
|
|
112
|
-
##
|
|
112
|
+
## Streaming
|
|
113
113
|
|
|
114
|
-
###
|
|
114
|
+
### Basic Usage
|
|
115
115
|
|
|
116
116
|
```js
|
|
117
117
|
import { NodePublisher, NodePublisherRef } from 'expo-nodemediaclient';
|
|
@@ -155,7 +155,7 @@ export default function PublisherScreen() {
|
|
|
155
155
|
}}
|
|
156
156
|
/>
|
|
157
157
|
<Button
|
|
158
|
-
title={isPublishing ? "
|
|
158
|
+
title={isPublishing ? "Stop" : "Start Streaming"}
|
|
159
159
|
onPress={handleTogglePublish}
|
|
160
160
|
/>
|
|
161
161
|
</SafeAreaView>
|
|
@@ -163,83 +163,83 @@ export default function PublisherScreen() {
|
|
|
163
163
|
}
|
|
164
164
|
```
|
|
165
165
|
|
|
166
|
-
###
|
|
166
|
+
### Component Props
|
|
167
167
|
|
|
168
|
-
|
|
|
168
|
+
| Prop | Type | Description |
|
|
169
169
|
|------|------|------|
|
|
170
|
-
| `url` | `string` |
|
|
171
|
-
| `audioParam` | `AudioParam` |
|
|
172
|
-
| `videoParam` | `VideoParam` |
|
|
173
|
-
| `videoOrientation` | `number` |
|
|
174
|
-
| `keyFrameInterval` | `number` |
|
|
175
|
-
| `frontCamera` | `boolean` |
|
|
176
|
-
| `cameraFrontMirror` | `boolean` |
|
|
177
|
-
| `volume` | `number` |
|
|
178
|
-
| `zoomRatio` | `number` |
|
|
179
|
-
| `torchEnable` | `boolean` |
|
|
180
|
-
| `HWAccelEnable` | `boolean` |
|
|
181
|
-
| `denoiseEnable` | `boolean` |
|
|
182
|
-
| `colorStyleId` | `number` |
|
|
183
|
-
| `colorStyleIntensity` | `number` |
|
|
184
|
-
| `smoothskinIntensity` | `number` |
|
|
185
|
-
| `onEventCallback` | `(event) => void` |
|
|
170
|
+
| `url` | `string` | Streaming URL (RTMP) |
|
|
171
|
+
| `audioParam` | `AudioParam` | Audio encoding parameters |
|
|
172
|
+
| `videoParam` | `VideoParam` | Video encoding parameters |
|
|
173
|
+
| `videoOrientation` | `number` | Video orientation, e.g., `NodePublisher.VIDEO_ORIENTATION_PORTRAIT` |
|
|
174
|
+
| `keyFrameInterval` | `number` | Key frame interval in seconds, default 2 |
|
|
175
|
+
| `frontCamera` | `boolean` | Whether to use front camera, default false |
|
|
176
|
+
| `cameraFrontMirror` | `boolean` | Whether to mirror front camera, default true |
|
|
177
|
+
| `volume` | `number` | Volume (0.0 - 1.0) |
|
|
178
|
+
| `zoomRatio` | `number` | Camera zoom ratio (0.0 - 1.0)|
|
|
179
|
+
| `torchEnable` | `boolean` | Whether to enable torch/flashlight |
|
|
180
|
+
| `HWAccelEnable` | `boolean` | Whether to enable hardware acceleration, default true |
|
|
181
|
+
| `denoiseEnable` | `boolean` | Whether to enable noise reduction, default true |
|
|
182
|
+
| `colorStyleId` | `number` | Color style ID, e.g., `NodePublisher.EFFECTOR_STYLE_ID_FAIRSKIN` |
|
|
183
|
+
| `colorStyleIntensity` | `number` | Color intensity (0.0 - 1.0) |
|
|
184
|
+
| `smoothskinIntensity` | `number` | Skin smoothing intensity (0.0 - 1.0) |
|
|
185
|
+
| `onEventCallback` | `(event) => void` | Event callback |
|
|
186
186
|
|
|
187
187
|
### AudioParam
|
|
188
188
|
|
|
189
|
-
|
|
|
189
|
+
| Prop | Type | Description |
|
|
190
190
|
|------|------|------|
|
|
191
|
-
| `codecid` | `number` |
|
|
192
|
-
| `profile` | `number` |
|
|
193
|
-
| `channels` | `number` |
|
|
194
|
-
| `samplingRate` | `number` |
|
|
195
|
-
| `bitrate` | `number` |
|
|
191
|
+
| `codecid` | `number` | Codec ID, `NodePublisher.NMC_CODEC_ID_AAC` |
|
|
192
|
+
| `profile` | `number` | Codec profile, `NodePublisher.NMC_PROFILE_AUTO` |
|
|
193
|
+
| `channels` | `number` | Number of channels, 1 or 2 |
|
|
194
|
+
| `samplingRate` | `number` | Sampling rate, e.g., 44100 |
|
|
195
|
+
| `bitrate` | `number` | Bitrate, e.g., 64000 |
|
|
196
196
|
|
|
197
197
|
### VideoParam
|
|
198
198
|
|
|
199
|
-
|
|
|
199
|
+
| Prop | Type | Description |
|
|
200
200
|
|------|------|------|
|
|
201
|
-
| `codecid` | `number` |
|
|
202
|
-
| `profile` | `number` |
|
|
203
|
-
| `width` | `number` |
|
|
204
|
-
| `height` | `number` |
|
|
205
|
-
| `fps` | `number` |
|
|
206
|
-
| `bitrate` | `number` |
|
|
201
|
+
| `codecid` | `number` | Codec ID, `NodePublisher.NMC_CODEC_ID_H264` or `NodePublisher.NMC_CODEC_ID_H265` |
|
|
202
|
+
| `profile` | `number` | Codec profile, `NodePublisher.NMC_PROFILE_AUTO` |
|
|
203
|
+
| `width` | `number` | Video width |
|
|
204
|
+
| `height` | `number` | Video height |
|
|
205
|
+
| `fps` | `number` | Frame rate |
|
|
206
|
+
| `bitrate` | `number` | Bitrate, e.g., 2000000 |
|
|
207
207
|
|
|
208
|
-
###
|
|
208
|
+
### Common Methods
|
|
209
209
|
|
|
210
210
|
```js
|
|
211
|
-
//
|
|
211
|
+
// Start streaming
|
|
212
212
|
publisherRef.current?.start(url);
|
|
213
213
|
|
|
214
|
-
//
|
|
214
|
+
// Stop streaming
|
|
215
215
|
publisherRef.current?.stop();
|
|
216
216
|
```
|
|
217
217
|
|
|
218
|
-
###
|
|
218
|
+
### Event Callback
|
|
219
219
|
|
|
220
220
|
```js
|
|
221
221
|
const handleEvent = (event: { nativeEvent: NodePlayerEventCallback }) => {
|
|
222
|
-
console.log('
|
|
223
|
-
console.log('
|
|
222
|
+
console.log('Event code:', event.nativeEvent.event);
|
|
223
|
+
console.log('Message:', event.nativeEvent.msg);
|
|
224
224
|
};
|
|
225
225
|
|
|
226
226
|
<NodePublisher
|
|
227
227
|
onEventCallback={handleEvent}
|
|
228
|
-
//
|
|
228
|
+
// ...other props
|
|
229
229
|
/>
|
|
230
230
|
```
|
|
231
231
|
|
|
232
|
-
###
|
|
232
|
+
### Permissions
|
|
233
233
|
|
|
234
|
-
|
|
234
|
+
Streaming functionality requires camera and microphone permissions. We recommend using `expo-camera` to request permissions.
|
|
235
235
|
|
|
236
|
-
|
|
236
|
+
First install the dependency:
|
|
237
237
|
|
|
238
238
|
```bash
|
|
239
239
|
npm install expo-camera
|
|
240
240
|
```
|
|
241
241
|
|
|
242
|
-
|
|
242
|
+
Configure the `expo-camera` plugin in `app.json`:
|
|
243
243
|
|
|
244
244
|
```json
|
|
245
245
|
{
|
|
@@ -256,8 +256,8 @@ npm install expo-camera
|
|
|
256
256
|
],
|
|
257
257
|
"ios": {
|
|
258
258
|
"infoPlist": {
|
|
259
|
-
"NSCameraUsageDescription": "
|
|
260
|
-
"NSMicrophoneUsageDescription": "
|
|
259
|
+
"NSCameraUsageDescription": "Camera access is required for live streaming",
|
|
260
|
+
"NSMicrophoneUsageDescription": "Microphone access is required for live streaming"
|
|
261
261
|
}
|
|
262
262
|
},
|
|
263
263
|
"android": {
|
|
@@ -271,7 +271,7 @@ npm install expo-camera
|
|
|
271
271
|
}
|
|
272
272
|
```
|
|
273
273
|
|
|
274
|
-
|
|
274
|
+
Request permissions in code:
|
|
275
275
|
|
|
276
276
|
```js
|
|
277
277
|
import { useCameraPermissions, useMicrophonePermissions } from 'expo-camera';
|
package/README_CN.md
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# expo-nodemediaclient
|
|
2
|
+
|
|
3
|
+
## 特性
|
|
4
|
+
- 支持iOS与Android
|
|
5
|
+
- 支持RTMP、HLS、HTTP-FLV、RTSP播放
|
|
6
|
+
- 支持H.264、H.265视频编码
|
|
7
|
+
- 支持AAC、PCM音频编码
|
|
8
|
+
- 支持硬件加速
|
|
9
|
+
- 支持低延迟播放,累积延迟消除
|
|
10
|
+
|
|
11
|
+
## 前提
|
|
12
|
+
你的Expo项目应该是使用持续的原生生成 [(CNG)](https://docs.expo.dev/workflow/continuous-native-generation/)
|
|
13
|
+
如果不是请先执行
|
|
14
|
+
```bash
|
|
15
|
+
npx expo prebuild
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## 安装
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install expo-nodemediaclient
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 使用
|
|
25
|
+
### 注册SDK
|
|
26
|
+
android与iOS注册码不同,需要分别注册,注册码请联系[https://www.nodemedia.cn](https://www.nodemedia.cn)获取
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
import { NodeMediaClient } from 'expo-nodemediaclient';
|
|
30
|
+
import { Platform } from 'react-native';
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
if (Platform.OS === 'ios') {
|
|
34
|
+
NodeMediaClient.setLicense('');
|
|
35
|
+
} else if (Platform.OS === 'android') {
|
|
36
|
+
NodeMediaClient.setLicense('');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 播放
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
import { NodePlayer, NodePlayerRef } from 'expo-nodemediaclient';
|
|
45
|
+
import { useRef, useState } from 'react';
|
|
46
|
+
|
|
47
|
+
export default function App() {
|
|
48
|
+
const [url, setUrl] = useState('rtmp://192.168.0.2/live/bbb');
|
|
49
|
+
const playerRef = useRef<NodePlayerRef>(null);
|
|
50
|
+
return (
|
|
51
|
+
<SafeAreaView style={{ flex: 1 }}>
|
|
52
|
+
<NodePlayer
|
|
53
|
+
ref={playerRef}
|
|
54
|
+
url={url}
|
|
55
|
+
bufferTime={1000}
|
|
56
|
+
scaleMode={1}
|
|
57
|
+
style={{ backgroundColor: '#000000', height: 300 }}
|
|
58
|
+
/>
|
|
59
|
+
<TextInput value={url} onChangeText={setUrl} />
|
|
60
|
+
<Button
|
|
61
|
+
title="Play"
|
|
62
|
+
onPress={() => {
|
|
63
|
+
playerRef.current?.start(url);
|
|
64
|
+
}}
|
|
65
|
+
/>
|
|
66
|
+
<Button
|
|
67
|
+
title="Stop"
|
|
68
|
+
onPress={() => {
|
|
69
|
+
playerRef.current?.stop();
|
|
70
|
+
}}
|
|
71
|
+
/>
|
|
72
|
+
</SafeAreaView>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 组件属性
|
|
78
|
+
|
|
79
|
+
| 属性 | 类型 | 说明 |
|
|
80
|
+
|------|------|------|
|
|
81
|
+
| `url` | `string` | 播放地址 (支持 RTMP、RTSP、HLS、HTTP-FLV) |
|
|
82
|
+
| `bufferTime` | `number` | 缓冲时间 (毫秒),默认 1000 |
|
|
83
|
+
| `scaleMode` | `number` | 缩放模式,`0`=填充,`1`=适应,`2`=拉伸 |
|
|
84
|
+
| `volume` | `number` | 音量 (0.0 - 1.0),默认 1.0 |
|
|
85
|
+
| `onEventCallback` | `(event) => void` | 事件回调 |
|
|
86
|
+
|
|
87
|
+
### 常用方法
|
|
88
|
+
|
|
89
|
+
```js
|
|
90
|
+
// 开始播放
|
|
91
|
+
playerRef.current?.start(url);
|
|
92
|
+
|
|
93
|
+
// 停止播放
|
|
94
|
+
playerRef.current?.stop();
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 事件回调
|
|
98
|
+
|
|
99
|
+
```js
|
|
100
|
+
const handleEvent = (event: { nativeEvent: NodePlayerEventCallback }) => {
|
|
101
|
+
console.log('事件码:', event.nativeEvent.event);
|
|
102
|
+
console.log('消息:', event.nativeEvent.msg);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
<NodePlayer
|
|
106
|
+
onEventCallback={handleEvent}
|
|
107
|
+
// ...其他属性
|
|
108
|
+
/>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
## 推流
|
|
113
|
+
|
|
114
|
+
### 基本用法
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
import { NodePublisher, NodePublisherRef } from 'expo-nodemediaclient';
|
|
118
|
+
import { useRef, useState } from 'react';
|
|
119
|
+
|
|
120
|
+
export default function PublisherScreen() {
|
|
121
|
+
const [url, setUrl] = useState('rtmp://192.168.0.2/live/stream');
|
|
122
|
+
const [isPublishing, setIsPublishing] = useState(false);
|
|
123
|
+
const publisherRef = useRef<NodePublisherRef>(null);
|
|
124
|
+
|
|
125
|
+
const handleTogglePublish = () => {
|
|
126
|
+
if (!isPublishing) {
|
|
127
|
+
setIsPublishing(true);
|
|
128
|
+
publisherRef.current?.start(url);
|
|
129
|
+
} else {
|
|
130
|
+
setIsPublishing(false);
|
|
131
|
+
publisherRef.current?.stop();
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
return (
|
|
136
|
+
<SafeAreaView style={{ flex: 1 }}>
|
|
137
|
+
<NodePublisher
|
|
138
|
+
ref={publisherRef}
|
|
139
|
+
style={{ flex: 1, backgroundColor: '#000' }}
|
|
140
|
+
url={url}
|
|
141
|
+
audioParam={{
|
|
142
|
+
codecid: NodePublisher.NMC_CODEC_ID_AAC,
|
|
143
|
+
profile: NodePublisher.NMC_PROFILE_AUTO,
|
|
144
|
+
channels: 2,
|
|
145
|
+
samplingRate: 44100,
|
|
146
|
+
bitrate: 64_000,
|
|
147
|
+
}}
|
|
148
|
+
videoParam={{
|
|
149
|
+
codecid: NodePublisher.NMC_CODEC_ID_H264,
|
|
150
|
+
profile: NodePublisher.NMC_PROFILE_AUTO,
|
|
151
|
+
width: 720,
|
|
152
|
+
height: 1280,
|
|
153
|
+
fps: 30,
|
|
154
|
+
bitrate: 2000_000,
|
|
155
|
+
}}
|
|
156
|
+
/>
|
|
157
|
+
<Button
|
|
158
|
+
title={isPublishing ? "停止" : "推流"}
|
|
159
|
+
onPress={handleTogglePublish}
|
|
160
|
+
/>
|
|
161
|
+
</SafeAreaView>
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 组件属性
|
|
167
|
+
|
|
168
|
+
| 属性 | 类型 | 说明 |
|
|
169
|
+
|------|------|------|
|
|
170
|
+
| `url` | `string` | 推流地址 (RTMP) |
|
|
171
|
+
| `audioParam` | `AudioParam` | 音频编码参数 |
|
|
172
|
+
| `videoParam` | `VideoParam` | 视频编码参数 |
|
|
173
|
+
| `videoOrientation` | `number` | 视频方向,如 `NodePublisher.VIDEO_ORIENTATION_PORTRAIT` |
|
|
174
|
+
| `keyFrameInterval` | `number` | 关键帧间隔 (秒),默认 2 |
|
|
175
|
+
| `frontCamera` | `boolean` | 是否使用前置摄像头,默认 false |
|
|
176
|
+
| `cameraFrontMirror` | `boolean` | 前置摄像头是否镜像,默认 true |
|
|
177
|
+
| `volume` | `number` | 音量 (0.0 - 1.0) |
|
|
178
|
+
| `zoomRatio` | `number` | 摄像头缩放比例 (0.0 - 1.0)|
|
|
179
|
+
| `torchEnable` | `boolean` | 是否开启补光灯 |
|
|
180
|
+
| `HWAccelEnable` | `boolean` | 是否启用硬件加速,默认 true |
|
|
181
|
+
| `denoiseEnable` | `boolean` | 是否启用降噪,默认 true |
|
|
182
|
+
| `colorStyleId` | `number` | 色彩风格ID,如 `NodePublisher.EFFECTOR_STYLE_ID_FAIRSKIN` |
|
|
183
|
+
| `colorStyleIntensity` | `number` | 色彩强度 (0.0 - 1.0) |
|
|
184
|
+
| `smoothskinIntensity` | `number` | 磨皮强度 (0.0 - 1.0) |
|
|
185
|
+
| `onEventCallback` | `(event) => void` | 事件回调 |
|
|
186
|
+
|
|
187
|
+
### AudioParam
|
|
188
|
+
|
|
189
|
+
| 属性 | 类型 | 说明 |
|
|
190
|
+
|------|------|------|
|
|
191
|
+
| `codecid` | `number` | 编码ID,`NodePublisher.NMC_CODEC_ID_AAC` |
|
|
192
|
+
| `profile` | `number` | 编码profile,`NodePublisher.NMC_PROFILE_AUTO` |
|
|
193
|
+
| `channels` | `number` | 声道数,1 或 2 |
|
|
194
|
+
| `samplingRate` | `number` | 采样率,如 44100 |
|
|
195
|
+
| `bitrate` | `number` | 比特率,如 64000 |
|
|
196
|
+
|
|
197
|
+
### VideoParam
|
|
198
|
+
|
|
199
|
+
| 属性 | 类型 | 说明 |
|
|
200
|
+
|------|------|------|
|
|
201
|
+
| `codecid` | `number` | 编码ID,`NodePublisher.NMC_CODEC_ID_H264` 或 `NodePublisher.NMC_CODEC_ID_H265` |
|
|
202
|
+
| `profile` | `number` | 编码profile,`NodePublisher.NMC_PROFILE_AUTO` |
|
|
203
|
+
| `width` | `number` | 视频宽度 |
|
|
204
|
+
| `height` | `number` | 视频高度 |
|
|
205
|
+
| `fps` | `number` | 帧率 |
|
|
206
|
+
| `bitrate` | `number` | 比特率,如 2000000 |
|
|
207
|
+
|
|
208
|
+
### 常用方法
|
|
209
|
+
|
|
210
|
+
```js
|
|
211
|
+
// 开始推流
|
|
212
|
+
publisherRef.current?.start(url);
|
|
213
|
+
|
|
214
|
+
// 停止推流
|
|
215
|
+
publisherRef.current?.stop();
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### 事件回调
|
|
219
|
+
|
|
220
|
+
```js
|
|
221
|
+
const handleEvent = (event: { nativeEvent: NodePlayerEventCallback }) => {
|
|
222
|
+
console.log('事件码:', event.nativeEvent.event);
|
|
223
|
+
console.log('消息:', event.nativeEvent.msg);
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
<NodePublisher
|
|
227
|
+
onEventCallback={handleEvent}
|
|
228
|
+
// ...其他属性
|
|
229
|
+
/>
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### 权限说明
|
|
233
|
+
|
|
234
|
+
使用推流功能需要摄像头和麦克风权限,建议使用 `expo-camera` 来申请权限。
|
|
235
|
+
|
|
236
|
+
首先安装依赖:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
npm install expo-camera
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
在 `app.json` 中配置 `expo-camera` 插件:
|
|
243
|
+
|
|
244
|
+
```json
|
|
245
|
+
{
|
|
246
|
+
"expo": {
|
|
247
|
+
"plugins": [
|
|
248
|
+
[
|
|
249
|
+
"expo-camera",
|
|
250
|
+
{
|
|
251
|
+
"cameraPermission": "Allow $(PRODUCT_NAME) to access your camera",
|
|
252
|
+
"microphonePermission": "Allow $(PRODUCT_NAME) to access your microphone",
|
|
253
|
+
"recordAudioAndroid": true
|
|
254
|
+
}
|
|
255
|
+
]
|
|
256
|
+
],
|
|
257
|
+
"ios": {
|
|
258
|
+
"infoPlist": {
|
|
259
|
+
"NSCameraUsageDescription": "需要访问摄像头以进行直播推流",
|
|
260
|
+
"NSMicrophoneUsageDescription": "需要访问麦克风以进行直播推流"
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
"android": {
|
|
264
|
+
"permissions": [
|
|
265
|
+
"android.permission.CAMERA",
|
|
266
|
+
"android.permission.RECORD_AUDIO",
|
|
267
|
+
"android.permission.INTERNET"
|
|
268
|
+
]
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
在代码中申请权限:
|
|
275
|
+
|
|
276
|
+
```js
|
|
277
|
+
import { useCameraPermissions, useMicrophonePermissions } from 'expo-camera';
|
|
278
|
+
import { useEffect } from 'react';
|
|
279
|
+
|
|
280
|
+
export default function App() {
|
|
281
|
+
const [cameraPermission, requestCameraPermission] = useCameraPermissions();
|
|
282
|
+
const [microphonePermission, requestMicrophonePermission] = useMicrophonePermissions();
|
|
283
|
+
|
|
284
|
+
useEffect(() => {
|
|
285
|
+
requestCameraPermission();
|
|
286
|
+
requestMicrophonePermission();
|
|
287
|
+
}, []);
|
|
288
|
+
|
|
289
|
+
const hasPermission = cameraPermission?.granted && microphonePermission?.granted;
|
|
290
|
+
|
|
291
|
+
// ...
|
|
292
|
+
}
|
|
293
|
+
```
|
package/android/build.gradle
CHANGED
|
@@ -33,13 +33,13 @@ if (useManagedAndroidSdkVersions) {
|
|
|
33
33
|
android {
|
|
34
34
|
namespace "expo.modules.nodemediaclient"
|
|
35
35
|
defaultConfig {
|
|
36
|
-
versionCode
|
|
37
|
-
versionName "0.2.
|
|
36
|
+
versionCode 204
|
|
37
|
+
versionName "0.2.4"
|
|
38
38
|
}
|
|
39
39
|
lintOptions {
|
|
40
40
|
abortOnError false
|
|
41
41
|
}
|
|
42
42
|
dependencies {
|
|
43
|
-
implementation 'com.github.NodeMedia:NodeMediaClient-Android:4.1.
|
|
43
|
+
implementation 'com.github.NodeMedia:NodeMediaClient-Android:4.1.2'
|
|
44
44
|
}
|
|
45
45
|
}
|