@byteplus/react-native-rtc 1.0.6 → 1.1.0
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 +0 -316
- package/android/build.gradle +58 -43
- package/android/src/live/java/com/volcengine/reactnative/vertc/live/VertcLive.java +143 -0
- package/android/src/main/java/com/volcengine/reactnative/vertc/VertcHelper.java +10 -0
- package/android/src/main/java/com/volcengine/reactnative/vertc/VertcModule.java +2 -0
- package/android/src/main/java/com/volcengine/reactnative/vertc/VertcView.java +1 -1
- package/android/src/main/java/com/volcengine/reactnative/vertc/VertcViewManager.java +1 -1
- package/ios/core/VertcHelper.h +21 -0
- package/ios/core/VertcHelper.m +42 -0
- package/ios/live/VertcLive.h +24 -0
- package/ios/live/VertcLive.m +124 -0
- package/lib/commonjs/index.js +206 -11
- package/lib/module/index.js +206 -11
- package/lib/typescript/core/callback.d.ts +1 -1
- package/lib/typescript/core/rtc-video.d.ts +33 -1
- package/lib/typescript/core.d.ts +0 -4
- package/lib/typescript/interface.d.ts +53 -1
- package/lib/typescript/platforms/android/live.d.ts +8 -0
- package/lib/typescript/platforms/android/vertc.d.ts +2 -0
- package/lib/typescript/platforms/ios/live.d.ts +9 -0
- package/lib/typescript/platforms/ios/vertc.d.ts +10 -0
- package/package.json +1 -1
- package/react-native-rtc.podspec +44 -27
- /package/android/src/{main → vod}/java/com/volcengine/reactnative/vertc/vod/OESTextureProcessor.java +0 -0
- /package/android/src/{main → vod}/java/com/volcengine/reactnative/vertc/vod/VertcVod.java +0 -0
- /package/android/src/{main → vod}/java/com/volcengine/reactnative/vertc/vod/VideoAudioProcessor.java +0 -0
- /package/android/src/{main → vod}/java/com/volcengine/reactnative/vertc/vod/VodAudioProcessor.java +0 -0
- /package/android/src/{main → vod}/java/com/volcengine/reactnative/vertc/vod/VodMock.java +0 -0
- /package/android/src/{main → vod}/java/com/volcengine/reactnative/vertc/vod/VodVideoEngineCallbackProxy.java +0 -0
- /package/ios/{RTCHeader.h → core/RTCHeader.h} +0 -0
- /package/ios/{RTCHeader.m → core/RTCHeader.m} +0 -0
- /package/ios/{VertcApiEngine.h → core/VertcApiEngine.h} +0 -0
- /package/ios/{VertcApiEngine.m → core/VertcApiEngine.m} +0 -0
- /package/ios/{VertcModule.h → core/VertcModule.h} +0 -0
- /package/ios/{VertcModule.m → core/VertcModule.m} +0 -0
- /package/ios/{VertcView.h → core/VertcView.h} +0 -0
- /package/ios/{VertcView.m → core/VertcView.m} +0 -0
- /package/ios/{VertcViewManager.m → core/VertcViewManager.m} +0 -0
package/README.md
CHANGED
|
@@ -138,12 +138,6 @@ const Login = () => {
|
|
|
138
138
|
extras: {
|
|
139
139
|
source_language: room.language,
|
|
140
140
|
},
|
|
141
|
-
roomConfigs: {
|
|
142
|
-
profile: room.roomMode,
|
|
143
|
-
isAutoPublish: room.autoPublish,
|
|
144
|
-
isAutoSubscribeAudio: room.autoSubscribeAudio,
|
|
145
|
-
isAutoSubscribeVideo: room.autoSubscribeVideo,
|
|
146
|
-
},
|
|
147
141
|
});
|
|
148
142
|
|
|
149
143
|
/** Capture local streams */
|
|
@@ -171,316 +165,6 @@ const Login = () => {
|
|
|
171
165
|
|
|
172
166
|
export default Login;
|
|
173
167
|
```
|
|
174
|
-
|
|
175
|
-
## On-Demand Video with Real-Time Guest Interaction Example
|
|
176
|
-
|
|
177
|
-
**We recommend using the latest RTC React Native SDK version in combination with react-native-vod-player SDK v1.2.4.**
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
### RTC Core Definition
|
|
181
|
-
`@/core/index.ts`
|
|
182
|
-
|
|
183
|
-
Based on the rtc core definition in `Basic Example`, add some apis:
|
|
184
|
-
```typescript
|
|
185
|
-
...
|
|
186
|
-
import type { TTVideoEngine } from '@byteplus/react-native-vod-player';
|
|
187
|
-
|
|
188
|
-
class RTCClient {
|
|
189
|
-
|
|
190
|
-
...
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* @brief Start to observe vod player, capture frames from vod player and set stream for external screen stream.
|
|
194
|
-
*/
|
|
195
|
-
startVodPlayerCapture(player: TTVideoEngine) {
|
|
196
|
-
return this.engine?.startVodPlayerCapture(player);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* @brief Stop all vod player observer in rtc.
|
|
201
|
-
* @note Once you invoke this api, you should invoke `startVodPlayerCapture` to observe vod player.
|
|
202
|
-
*/
|
|
203
|
-
stopVodPlayerCapture(player: TTVideoEngine) {
|
|
204
|
-
return this.engine?.stopVodPlayerCapture(player);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
```
|
|
208
|
-
### Main logic page in react-native
|
|
209
|
-
`@/page/vodRtc.ts`
|
|
210
|
-
|
|
211
|
-
```typescript
|
|
212
|
-
import React, {useEffect, useRef, useState} from 'react';
|
|
213
|
-
import fs from 'react-native-fs';
|
|
214
|
-
import {Platform, SafeAreaView, ScrollView} from 'react-native';
|
|
215
|
-
import {Button, Input, Text, Toast, View} from '@ant-design/react-native';
|
|
216
|
-
import {
|
|
217
|
-
NativeViewComponent,
|
|
218
|
-
StreamIndex,
|
|
219
|
-
RenderMode,
|
|
220
|
-
MediaStreamType,
|
|
221
|
-
LocalLogLevel,
|
|
222
|
-
} from '@byteplus/react-native-rtc';
|
|
223
|
-
import {
|
|
224
|
-
createDirectUrlSource,
|
|
225
|
-
type TTVideoEngine,
|
|
226
|
-
} from '@byteplus/react-native-vod-player';
|
|
227
|
-
import {
|
|
228
|
-
launchImageLibrary,
|
|
229
|
-
type ImagePickerResponse,
|
|
230
|
-
} from 'react-native-image-picker';
|
|
231
|
-
import RTCClient from '@/core';
|
|
232
|
-
import { createVeplayer } from '@/core/veplayer';
|
|
233
|
-
import RowItem from '@/components/RowItem';
|
|
234
|
-
import {GlobalStyles} from '@/style';
|
|
235
|
-
|
|
236
|
-
const viewId = 'my-view';
|
|
237
|
-
|
|
238
|
-
const auth = {
|
|
239
|
-
appId: 'Your RTC AppID',
|
|
240
|
-
roomId: 'Your Room ID',
|
|
241
|
-
userId: 'Your User ID',
|
|
242
|
-
token: 'Your RTC Token',
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
const Page = () => {
|
|
246
|
-
const [isViewLoaded, setViewLoaded] = useState<boolean>(false);
|
|
247
|
-
const [filepath, setFilepath] = useState('');
|
|
248
|
-
const hasCaptureRef = useRef(false);
|
|
249
|
-
const playerRef = useRef<TTVideoEngine>();
|
|
250
|
-
|
|
251
|
-
const handleViewLoad = () => {
|
|
252
|
-
setViewLoaded(true);
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
const handleSelectVideoFile = async () => {
|
|
256
|
-
try {
|
|
257
|
-
const callback = (response: ImagePickerResponse) => {
|
|
258
|
-
if (!response.didCancel && !response.errorCode) {
|
|
259
|
-
const filePath = response.assets?.[0]?.uri;
|
|
260
|
-
if (filePath) {
|
|
261
|
-
setFilepath(filePath);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
|
-
launchImageLibrary(
|
|
266
|
-
{
|
|
267
|
-
mediaType: 'video',
|
|
268
|
-
},
|
|
269
|
-
callback,
|
|
270
|
-
);
|
|
271
|
-
} catch {
|
|
272
|
-
Toast.fail('Select media file failed.');
|
|
273
|
-
}
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
const handlePublish = () => {
|
|
277
|
-
RTCClient.publishScreen(MediaStreamType.RTC_MEDIA_STREAM_TYPE_BOTH);
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
const setVideoSource = () => {
|
|
281
|
-
const source = filepath
|
|
282
|
-
? createDirectUrlSource({
|
|
283
|
-
url: filepath,
|
|
284
|
-
cacheKey: filepath,
|
|
285
|
-
})
|
|
286
|
-
: createDirectUrlSource({
|
|
287
|
-
url: 'Your media url, like https://xxxx.mp4',
|
|
288
|
-
cacheKey: 'remote',
|
|
289
|
-
vid: 'remote',
|
|
290
|
-
});
|
|
291
|
-
playerRef.current!.setVideoSource(source);
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
const handlePlay = async () => {
|
|
295
|
-
if (hasCaptureRef.current) {
|
|
296
|
-
playerRef.current!.play();
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
if (!playerRef.current) {
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
setVideoSource();
|
|
303
|
-
await RTCClient.startVodPlayerCapture(playerRef.current);
|
|
304
|
-
await playerRef.current!.play();
|
|
305
|
-
|
|
306
|
-
RTCClient.publishScreen(MediaStreamType.RTC_MEDIA_STREAM_TYPE_BOTH);
|
|
307
|
-
|
|
308
|
-
hasCaptureRef.current = true;
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
const handleStop = async () => {
|
|
312
|
-
if (hasCaptureRef.current) {
|
|
313
|
-
playerRef.current!.pause();
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
const handleDestroy = async () => {
|
|
318
|
-
if (!playerRef.current) {
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
321
|
-
await RTCClient.stopVodPlayerCapture(playerRef.current);
|
|
322
|
-
hasCaptureRef.current = false;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
const initializePlayer = async () => {
|
|
326
|
-
/**
|
|
327
|
-
* @brief It's not necessary to set viewId for vod player.
|
|
328
|
-
* @note You should realize veplayer for youself, refer to @byteplus/react-native-vod-player SDK.
|
|
329
|
-
*/
|
|
330
|
-
playerRef.current = await createVeplayer({ viewId: '' });
|
|
331
|
-
playerRef.current.setListener({
|
|
332
|
-
onLoadStateChanged(engine, loadState) {
|
|
333
|
-
console.log('onLoadStateChanged: ', loadState);
|
|
334
|
-
},
|
|
335
|
-
onError(message, code) {
|
|
336
|
-
console.error('onError: ', message, code);
|
|
337
|
-
},
|
|
338
|
-
onPlaybackStateChanged(engine, playbackState) {
|
|
339
|
-
console.log('onPlaybackStateChanged: ', playbackState);
|
|
340
|
-
},
|
|
341
|
-
});
|
|
342
|
-
};
|
|
343
|
-
|
|
344
|
-
const initializeRTC = async () => {
|
|
345
|
-
/** Init your engine */
|
|
346
|
-
let DefaultPath = fs.ExternalDirectoryPath;
|
|
347
|
-
if (Platform.OS === 'ios') {
|
|
348
|
-
DefaultPath = fs.DocumentDirectoryPath;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/** Set log */
|
|
352
|
-
RTCClient.setLogConfig({
|
|
353
|
-
logLevel: LocalLogLevel.INFO,
|
|
354
|
-
logPath: DefaultPath,
|
|
355
|
-
logFileSize: 10,
|
|
356
|
-
logFilenamePrefix: '',
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
/** Create RTC Engine */
|
|
360
|
-
await RTCClient.createEngine({
|
|
361
|
-
appID: auth.appId,
|
|
362
|
-
parameters: {},
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
/** Set Local video canvas for player */
|
|
366
|
-
RTCClient.setLocalVideoCanvas(StreamIndex.STREAM_INDEX_SCREEN, {
|
|
367
|
-
viewId,
|
|
368
|
-
renderMode: RenderMode.ByteRTCRenderModeFit,
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
/** Join room */
|
|
372
|
-
RTCClient.createRoom(auth.roomId);
|
|
373
|
-
RTCClient.setRTCRoomEventHandler({
|
|
374
|
-
onUserJoined(userInfo, elapsed) {
|
|
375
|
-
console.log('onUserJoined: ', userInfo, elapsed);
|
|
376
|
-
},
|
|
377
|
-
});
|
|
378
|
-
RTCClient.joinRoom({
|
|
379
|
-
token: auth.token,
|
|
380
|
-
userId: auth.userId,
|
|
381
|
-
roomConfigs: {
|
|
382
|
-
profile: 0,
|
|
383
|
-
isAutoPublish: true,
|
|
384
|
-
isAutoSubscribeAudio: false,
|
|
385
|
-
isAutoSubscribeVideo: false,
|
|
386
|
-
},
|
|
387
|
-
});
|
|
388
|
-
};
|
|
389
|
-
|
|
390
|
-
useEffect(() => {
|
|
391
|
-
if (isViewLoaded) {
|
|
392
|
-
initializeRTC();
|
|
393
|
-
initializePlayer();
|
|
394
|
-
console.log('init success');
|
|
395
|
-
}
|
|
396
|
-
}, [isViewLoaded]);
|
|
397
|
-
|
|
398
|
-
useEffect(() => {
|
|
399
|
-
return () => {
|
|
400
|
-
RTCClient.engine?.stopVodPlayerCapture(playerRef.current);
|
|
401
|
-
}
|
|
402
|
-
}, []);
|
|
403
|
-
|
|
404
|
-
return (
|
|
405
|
-
<SafeAreaView>
|
|
406
|
-
<ScrollView
|
|
407
|
-
style={{
|
|
408
|
-
display: 'flex',
|
|
409
|
-
flexDirection: 'column',
|
|
410
|
-
width: '100%',
|
|
411
|
-
height: '100%',
|
|
412
|
-
backgroundColor: 'gray',
|
|
413
|
-
}}>
|
|
414
|
-
<RowItem
|
|
415
|
-
theme="dark"
|
|
416
|
-
leftItem="File path"
|
|
417
|
-
leftItemStyle={{width: '25%'}}
|
|
418
|
-
rightItem={
|
|
419
|
-
<Input disabled placeholder="Select media file" value={filepath} />
|
|
420
|
-
}
|
|
421
|
-
/>
|
|
422
|
-
<Button
|
|
423
|
-
style={{...GlobalStyles.rowBtn, marginBottom: 6}}
|
|
424
|
-
onPress={handleSelectVideoFile}>
|
|
425
|
-
<Text style={{color: 'gray'}}>Select media file</Text>
|
|
426
|
-
</Button>
|
|
427
|
-
<Button
|
|
428
|
-
style={{...GlobalStyles.rowBtn, marginBottom: 6}}
|
|
429
|
-
onPress={() => setFilepath('')}>
|
|
430
|
-
<Text style={{color: 'gray'}}>Clear media file</Text>
|
|
431
|
-
</Button>
|
|
432
|
-
<Button
|
|
433
|
-
style={{...GlobalStyles.rowBtn, marginBottom: 6}}
|
|
434
|
-
onPress={handlePublish}>
|
|
435
|
-
<Text style={{color: 'gray'}}>Push Stream</Text>
|
|
436
|
-
</Button>
|
|
437
|
-
<Button
|
|
438
|
-
style={{...GlobalStyles.rowBtn, marginBottom: 6}}
|
|
439
|
-
onPress={handlePlay}>
|
|
440
|
-
<Text style={{color: 'gray'}}>Play</Text>
|
|
441
|
-
</Button>
|
|
442
|
-
<Button
|
|
443
|
-
style={{...GlobalStyles.rowBtn, marginBottom: 6}}
|
|
444
|
-
onPress={handleStop}>
|
|
445
|
-
<Text style={{color: 'gray'}}>Pause</Text>
|
|
446
|
-
</Button>
|
|
447
|
-
<Button
|
|
448
|
-
style={{...GlobalStyles.rowBtn, marginBottom: 6}}
|
|
449
|
-
onPress={handleDestroy}>
|
|
450
|
-
<Text style={{color: 'gray'}}>Destroy</Text>
|
|
451
|
-
</Button>
|
|
452
|
-
<View
|
|
453
|
-
style={{
|
|
454
|
-
flex: 1,
|
|
455
|
-
width: '100%',
|
|
456
|
-
minHeight: 300,
|
|
457
|
-
backgroundColor: '#000',
|
|
458
|
-
}}>
|
|
459
|
-
<Text>{`${viewId}`}</Text>
|
|
460
|
-
<NativeViewComponent
|
|
461
|
-
viewId={viewId}
|
|
462
|
-
style={{
|
|
463
|
-
width: '100%',
|
|
464
|
-
height: '100%',
|
|
465
|
-
}}
|
|
466
|
-
onLoad={handleViewLoad}
|
|
467
|
-
kind={
|
|
468
|
-
Platform.select({
|
|
469
|
-
android: 'SurfaceView',
|
|
470
|
-
ios: 'UIView',
|
|
471
|
-
})!
|
|
472
|
-
}
|
|
473
|
-
/>
|
|
474
|
-
</View>
|
|
475
|
-
</ScrollView>
|
|
476
|
-
</SafeAreaView>
|
|
477
|
-
);
|
|
478
|
-
};
|
|
479
|
-
|
|
480
|
-
export default Page;
|
|
481
|
-
```
|
|
482
|
-
|
|
483
|
-
|
|
484
168
|
## Attention
|
|
485
169
|
- In Android/iOS scenarios, the screen sharing method is slightly different. For details, please refer to [Android screen sharing](https://docs.byteplus.com/en/docs/byteplus-rtc/docs-124176) and [iOS screen sharing](https://docs.byteplus.com/en/docs/byteplus-rtc/docs-124177).
|
|
486
170
|
- Not support debug in iOS simulator, using real device instead.
|
package/android/build.gradle
CHANGED
|
@@ -9,6 +9,35 @@ buildscript {
|
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
def getLicenseType() {
|
|
13
|
+
try {
|
|
14
|
+
def packageJson = file("../../../../package.json")
|
|
15
|
+
def parsedJson = new groovy.json.JsonSlurper().parseText(packageJson.text)
|
|
16
|
+
return parsedJson.TTVideoEngine.licenseType
|
|
17
|
+
} catch (e) {
|
|
18
|
+
return "premium"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
def enableUnionForRTCWithLive = project.findProperty('enableUnionForRTCWithLive') == null ? false : project.findProperty('enableUnionForRTCWithLive').toString().toBoolean()
|
|
23
|
+
def enableUnionForRTCWithVod = project.findProperty('enableUnionForRTCWithVod') == null ? false : project.findProperty('enableUnionForRTCWithVod').toString().toBoolean()
|
|
24
|
+
|
|
25
|
+
def packageJson = file("../package.json")
|
|
26
|
+
def parsedJson = new groovy.json.JsonSlurper().parseText(packageJson.text)
|
|
27
|
+
def isBp = parsedJson.name.startsWith("@byteplus")
|
|
28
|
+
|
|
29
|
+
def license_type = getLicenseType()
|
|
30
|
+
|
|
31
|
+
def rtcVersionToUse
|
|
32
|
+
if (isBp) {
|
|
33
|
+
rtcVersionToUse = enableUnionForRTCWithLive ? "3.58.1.20600" : "3.58.1.15100"
|
|
34
|
+
println "Using BytePlusRTC SDK version : $rtcVersionToUse (union live enabled: $enableUnionForRTCWithLive / union vod enabled: $enableUnionForRTCWithVod)"
|
|
35
|
+
} else {
|
|
36
|
+
rtcVersionToUse = enableUnionForRTCWithLive ? "3.58.1.20700" : "3.58.1.2700"
|
|
37
|
+
println "Using VolcEngineRTC SDK version : $rtcVersionToUse (union build enabled: $enableUnionForRTCWithLive / union vod enabled: $enableUnionForRTCWithVod)"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
12
41
|
def isNewArchitectureEnabled() {
|
|
13
42
|
return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
|
|
14
43
|
}
|
|
@@ -36,42 +65,16 @@ def supportsNamespace() {
|
|
|
36
65
|
return (major == 7 && minor >= 3) || major >= 8
|
|
37
66
|
}
|
|
38
67
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return "premium"
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
def getNativeDep() {
|
|
50
|
-
def packageJson = file("../package.json")
|
|
51
|
-
def parsedJson = new groovy.json.JsonSlurper().parseText(packageJson.text)
|
|
52
|
-
def isBp = parsedJson.name.startsWith("@byteplus")
|
|
53
|
-
|
|
54
|
-
def enableUnionForRTCWithLive = rootProject.ext.has('enableUnionForRTCWithLive') ? rootProject.ext.get('enableUnionForRTCWithLive') : false
|
|
55
|
-
def rtcVersionToUse
|
|
56
|
-
if (isBp) {
|
|
57
|
-
rtcVersionToUse = enableUnionForRTCWithLive ? "3.58.1.20600" : "3.58.1.15100"
|
|
58
|
-
println "Using BytePlusRTC SDK version : $rtcVersionToUse (union build enabled: $enableUnionForRTCWithLive)"
|
|
59
|
-
return "com.byteplus:BytePlusRTC:$rtcVersionToUse"
|
|
68
|
+
android {
|
|
69
|
+
sourceSets {
|
|
70
|
+
main {
|
|
71
|
+
java.srcDirs = ['src/main/java']
|
|
72
|
+
manifest.srcFile "src/main/AndroidManifestNew.xml"
|
|
73
|
+
}
|
|
60
74
|
}
|
|
61
|
-
rtcVersionToUse = enableUnionForRTCWithLive ? "3.58.1.20700" : "3.58.1.2700"
|
|
62
|
-
println "Using VolcEngineRTC SDK version : $rtcVersionToUse (union build enabled: $enableUnionForRTCWithLive)"
|
|
63
|
-
return "com.volcengine:VolcEngineRTC:$rtcVersionToUse"
|
|
64
|
-
}
|
|
65
75
|
|
|
66
|
-
android {
|
|
67
76
|
if (supportsNamespace()) {
|
|
68
77
|
namespace "com.volcengine.reactnative.vertc"
|
|
69
|
-
|
|
70
|
-
sourceSets {
|
|
71
|
-
main {
|
|
72
|
-
manifest.srcFile "src/main/AndroidManifestNew.xml"
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
|
|
@@ -99,23 +102,35 @@ android {
|
|
|
99
102
|
}
|
|
100
103
|
}
|
|
101
104
|
|
|
105
|
+
def apiVolcEngineVersion = "1.6.2";
|
|
106
|
+
|
|
107
|
+
if (enableUnionForRTCWithLive) {
|
|
108
|
+
android.sourceSets.main.java.srcDirs += 'src/live/java'
|
|
109
|
+
dependencies {
|
|
110
|
+
implementation project(':byteplus_react-native-live-push')
|
|
111
|
+
implementation "com.bytedanceapi:ttsdk-player_$license_type:1.46.300.2"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (enableUnionForRTCWithVod) {
|
|
116
|
+
android.sourceSets.main.java.srcDirs += 'src/vod/java'
|
|
117
|
+
//
|
|
118
|
+
// Might cause rtc api some error, just alpha version.
|
|
119
|
+
//
|
|
120
|
+
apiVolcEngineVersion = '1.5.0'
|
|
121
|
+
dependencies {
|
|
122
|
+
implementation "com.bytedanceapi:ttsdk-player_$license_type:1.46.300.2"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
102
126
|
dependencies {
|
|
103
127
|
// For < 0.71, this will be from the local maven repo
|
|
104
128
|
// For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
|
|
105
129
|
// noinspection GradleDynamicVersion
|
|
106
130
|
implementation "com.facebook.react:react-native:+"
|
|
107
131
|
|
|
108
|
-
implementation "com.volcengine:VolcApiEngine
|
|
109
|
-
// implementation project(":hybrid-runtime");
|
|
132
|
+
implementation "com.volcengine:VolcApiEngine:$apiVolcEngineVersion"
|
|
110
133
|
|
|
111
134
|
// Use the RTC SDK dependency determined by getNativeDep() which can be overridden by customer's app build.gradle.
|
|
112
|
-
|
|
113
|
-
implementation rtcDep
|
|
114
|
-
|
|
115
|
-
// TTVideoEngine
|
|
116
|
-
// byteplus and volcengine use different name, different version
|
|
117
|
-
// volcengine com.bytedanceapi:ttsdk-player_premium:1.43.1.5 com.bytedanceapi:ttsdk-player_standard:1.43.1.5
|
|
118
|
-
// byteplus com.bytedanceapi:ttsdk-player_premium:1.42.300.101 com.bytedanceapi:ttsdk-player_standard:1.42.300.101
|
|
119
|
-
def license_type = getLicenseType()
|
|
120
|
-
implementation "com.bytedanceapi:ttsdk-player_$license_type:1.+"
|
|
135
|
+
implementation isBp ? "com.byteplus:BytePlusRTC:$rtcVersionToUse" : "com.volcengine:VolcEngineRTC:$rtcVersionToUse"
|
|
121
136
|
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// Copyright © 2022 BytePlusRTC All rights reserved.
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
package com.volcengine.reactnative.vertc.live;
|
|
5
|
+
|
|
6
|
+
import android.util.Log;
|
|
7
|
+
|
|
8
|
+
import com.ss.avframework.live.VeLivePusherDef;
|
|
9
|
+
import com.ss.avframework.live.VeLiveVideoFrame;
|
|
10
|
+
import com.ss.avframework.opengl.RendererCommon;
|
|
11
|
+
import com.ss.bytertc.engine.RTCVideo;
|
|
12
|
+
import com.ss.avframework.live.VeLivePusher;
|
|
13
|
+
import com.ss.bytertc.engine.data.ReturnStatus;
|
|
14
|
+
import com.ss.bytertc.engine.data.StreamIndex;
|
|
15
|
+
import com.ss.bytertc.engine.data.VideoPixelFormat;
|
|
16
|
+
import com.ss.bytertc.engine.data.VideoRotation;
|
|
17
|
+
import com.ss.bytertc.engine.data.VideoSourceType;
|
|
18
|
+
import java.util.concurrent.TimeUnit;
|
|
19
|
+
import com.ss.bytertc.engine.video.builder.GLTextureVideoFrameBuilder;
|
|
20
|
+
import com.volcengine.velive.rn.push.VeLivePushHelper;
|
|
21
|
+
|
|
22
|
+
import javax.annotation.Nonnull;
|
|
23
|
+
|
|
24
|
+
public class VertcLive {
|
|
25
|
+
private String TAG = "VertcLive";
|
|
26
|
+
|
|
27
|
+
private VeLivePusher mLivePusher;
|
|
28
|
+
private VeLivePusherDef.VeLiveVideoFrameListener mListener;
|
|
29
|
+
private org.json.JSONObject mOptions;
|
|
30
|
+
private RTCVideo mEngine;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @brief Start to capture live stream.
|
|
34
|
+
*/
|
|
35
|
+
public int startLiveVideoCapture(RTCVideo engine, String pusherViewId, org.json.JSONObject options) {
|
|
36
|
+
try {
|
|
37
|
+
stopLiveVideoCapture();
|
|
38
|
+
|
|
39
|
+
mEngine = engine;
|
|
40
|
+
mOptions = options;
|
|
41
|
+
|
|
42
|
+
mLivePusher = getVeLivePusher(pusherViewId);
|
|
43
|
+
if (mLivePusher == null) {
|
|
44
|
+
throw new RuntimeException("[Unknown LivePusher] can't find pusher instance by view id.");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// set video source as external
|
|
48
|
+
engine.setVideoSourceType(getStreamIndex(), VideoSourceType.VIDEO_SOURCE_TYPE_EXTERNAL);
|
|
49
|
+
// set video frame listener
|
|
50
|
+
mListener = new VeLivePusherDef.VeLiveVideoFrameListener() {
|
|
51
|
+
@Nonnull
|
|
52
|
+
@Override
|
|
53
|
+
public VeLivePusherDef.VeLiveVideoFrameSource getObservedVideoFrameSource() {
|
|
54
|
+
return new VeLivePusherDef.VeLiveVideoFrameSource(VeLivePusherDef.VeLiveVideoFrameSource.VeLiveVideoFrameSourcePreEncode);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@Override
|
|
58
|
+
public void onPreEncodeVideoFrame(VeLiveVideoFrame frame) {
|
|
59
|
+
int ret_status = -1;
|
|
60
|
+
StreamIndex streamIndex = getStreamIndex();
|
|
61
|
+
|
|
62
|
+
float[] mMVPMatrix = RendererCommon.convertMatrixFromAndroidGraphicsMatrix(frame.getTextureMatrix());
|
|
63
|
+
GLTextureVideoFrameBuilder builder = new GLTextureVideoFrameBuilder(
|
|
64
|
+
frame.isOesTextureFrame() ? VideoPixelFormat.TEXTURE_OES : VideoPixelFormat.TEXTURE_2D
|
|
65
|
+
)
|
|
66
|
+
.setTextureID(frame.getTextureId())
|
|
67
|
+
.setWidth(frame.getWidth())
|
|
68
|
+
.setHeight(frame.getHeight())
|
|
69
|
+
.setRotation(VideoRotation.VIDEO_ROTATION_0)
|
|
70
|
+
.setTextureMatrix(mMVPMatrix)
|
|
71
|
+
.setEGLContext(VeLivePusher.getEGLContext())
|
|
72
|
+
.setTimeStampUs(System.currentTimeMillis() * TimeUnit.MILLISECONDS.toNanos(1));
|
|
73
|
+
|
|
74
|
+
if (streamIndex == StreamIndex.STREAM_INDEX_MAIN) {
|
|
75
|
+
ret_status = engine.pushExternalVideoFrame(builder.build());
|
|
76
|
+
}
|
|
77
|
+
if (streamIndex == StreamIndex.STREAM_INDEX_SCREEN) {
|
|
78
|
+
ret_status = engine.pushScreenVideoFrame(builder.build());
|
|
79
|
+
}
|
|
80
|
+
boolean result = ret_status == ReturnStatus.RETURN_STATUS_SUCCESS.value()
|
|
81
|
+
|| ret_status == ReturnStatus.RETURN_STATUS_VIDEO_TIMESTAMP_WARNING.value();
|
|
82
|
+
if (!result) {
|
|
83
|
+
Log.d(TAG, "Push external frame fail: " + ret_status);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
mLivePusher.addVideoFrameListener(mListener);
|
|
88
|
+
|
|
89
|
+
return 0;
|
|
90
|
+
} catch (Exception err) {
|
|
91
|
+
Log.d(TAG, "startLiveVideoCapture failed:" + err.getMessage());
|
|
92
|
+
throw new RuntimeException(err);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @brief Stop to capture live stream.
|
|
98
|
+
*/
|
|
99
|
+
public int stopLiveVideoCapture() {
|
|
100
|
+
try {
|
|
101
|
+
if (
|
|
102
|
+
mOptions == null ||
|
|
103
|
+
mEngine == null
|
|
104
|
+
) {
|
|
105
|
+
return 0;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// reset sourceType to Internal
|
|
109
|
+
mEngine.setVideoSourceType(getStreamIndex(), VideoSourceType.VIDEO_SOURCE_TYPE_INTERNAL);
|
|
110
|
+
|
|
111
|
+
// release listener
|
|
112
|
+
mLivePusher.removeVideoFrameListener(mListener);
|
|
113
|
+
mListener = null;
|
|
114
|
+
mOptions = null;
|
|
115
|
+
mLivePusher = null;
|
|
116
|
+
mEngine = null;
|
|
117
|
+
|
|
118
|
+
return 0;
|
|
119
|
+
} catch (Exception err) {
|
|
120
|
+
Log.d(TAG, "stopLiveVideoCapture failed:" + err.getMessage());
|
|
121
|
+
throw new RuntimeException(err);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
// Get VeLivePusher from Object
|
|
127
|
+
private VeLivePusher getVeLivePusher(String pusherViewId) {
|
|
128
|
+
|
|
129
|
+
if (VeLivePushHelper.getPusher(pusherViewId) != null) {
|
|
130
|
+
return VeLivePushHelper.getPusher(pusherViewId);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Get StreamIndex from options
|
|
137
|
+
private StreamIndex getStreamIndex() {
|
|
138
|
+
Number index = mOptions.optInt("streamIndex", StreamIndex.STREAM_INDEX_MAIN.value());
|
|
139
|
+
StreamIndex streamIndex = StreamIndex.fromId(index.intValue());
|
|
140
|
+
Log.d(TAG, "getStreamIndex:" + streamIndex);
|
|
141
|
+
return streamIndex;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -8,9 +8,12 @@ import android.util.Log;
|
|
|
8
8
|
import com.ss.bytertc.engine.RTCVideo;
|
|
9
9
|
import com.ss.bytertc.engine.VideoEncoderConfig;
|
|
10
10
|
import com.ss.bytertc.engine.data.MirrorType;
|
|
11
|
+
import com.ss.bytertc.engine.live.IPushSingleStreamToCDNObserver;
|
|
12
|
+
import com.ss.bytertc.engine.live.PushSingleStreamParam;
|
|
11
13
|
|
|
12
14
|
public class VertcHelper {
|
|
13
15
|
|
|
16
|
+
final public String TAG = "VertcHelper";
|
|
14
17
|
static public VertcHelper sInstance = new VertcHelper();
|
|
15
18
|
|
|
16
19
|
public static VertcHelper getInstance() {
|
|
@@ -24,4 +27,11 @@ public class VertcHelper {
|
|
|
24
27
|
public int invokeSetLocalVideoMirrorType(RTCVideo engine, int mirrorType) {
|
|
25
28
|
return engine.setLocalVideoMirrorType(MirrorType.fromId(mirrorType));
|
|
26
29
|
}
|
|
30
|
+
|
|
31
|
+
public int invokeStartPushSingleStreamToCDN(RTCVideo engine, String taskId, PushSingleStreamParam param) {
|
|
32
|
+
IPushSingleStreamToCDNObserver observer = (eventType, taskId1, error) -> {
|
|
33
|
+
Log.d(TAG, "StartPushSingleStreamToCDN: " + eventType + " " + taskId1 + " " + error);
|
|
34
|
+
};
|
|
35
|
+
return engine.startPushSingleStreamToCDN(taskId, param, observer);
|
|
36
|
+
}
|
|
27
37
|
}
|
|
@@ -72,7 +72,7 @@ public class VertcViewManager extends SimpleViewManager<VertcView> implements Vo
|
|
|
72
72
|
|
|
73
73
|
public Map getExportedCustomBubblingEventTypeConstants() {
|
|
74
74
|
return MapBuilder.builder().put(
|
|
75
|
-
"
|
|
75
|
+
"vertcLoad",
|
|
76
76
|
MapBuilder.of(
|
|
77
77
|
"phasedRegistrationNames",
|
|
78
78
|
MapBuilder.of("bubbled", "onViewLoad")
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Copyright © 2022 BytePlusRTC All rights reserved.
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
//
|
|
5
|
+
// Pods
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#import "RTCHeader.h"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@interface VertcHelper : NSObject
|
|
12
|
+
|
|
13
|
+
+ (instancetype) getInstance;
|
|
14
|
+
|
|
15
|
+
- (void)onStreamPushEvent:(ByteRTCSingleStreamPushEvent)event
|
|
16
|
+
taskId:(NSString *_Nonnull)taskID
|
|
17
|
+
error:(NSInteger)errorCode;
|
|
18
|
+
|
|
19
|
+
- (int) invokeStartPushSingleStreamToCDN:(ByteRTCVideo *)rtc taskId:(NSString *_Nonnull)taskID singleStream:(ByteRTCPushSingleStreamParam *_Nonnull)singleStream;
|
|
20
|
+
|
|
21
|
+
@end
|