@byteplus/react-native-live-push 1.1.3-rc.4 → 1.3.0-rc.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/android/build.gradle +2 -2
- package/android/src/main/java/com/volcengine/velive/rn/push/ClassHelper.java +9 -0
- package/android/src/main/java/com/volcengine/velive/rn/push/NativeVariableManager.java +5 -8
- package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushModule.java +1 -0
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerManager.java +2 -4
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerView.java +50 -145
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerViewManager.java +1 -37
- package/ios/VeLiveMixerHelper.h +16 -11
- package/ios/VeLiveMixerHelper.m +39 -13
- package/ios/VeLiveMixerView.h +1 -8
- package/ios/VeLiveMixerView.m +178 -231
- package/ios/VeLiveMixerViewManager.m +2 -38
- package/lib/commonjs/index.js +23205 -20306
- package/lib/commonjs/typescript/android/index.d.ts +0 -3
- package/lib/commonjs/typescript/codegen/android/api.d.ts +190 -644
- package/lib/commonjs/typescript/codegen/android/callback.d.ts +234 -2
- package/lib/commonjs/typescript/codegen/android/errorcode.d.ts +66 -0
- package/lib/commonjs/typescript/codegen/android/keytype.d.ts +1014 -181
- package/lib/commonjs/typescript/codegen/ios/api.d.ts +890 -0
- package/lib/commonjs/typescript/codegen/ios/callback.d.ts +162 -0
- package/lib/commonjs/typescript/codegen/ios/errorcode.d.ts +101 -1
- package/lib/commonjs/typescript/codegen/ios/keytype.d.ts +694 -0
- package/lib/commonjs/typescript/codegen/pack/api.d.ts +303 -686
- package/lib/commonjs/typescript/codegen/pack/callback.d.ts +37 -38
- package/lib/commonjs/typescript/codegen/pack/errorcode.d.ts +75 -5
- package/lib/commonjs/typescript/codegen/pack/keytype.d.ts +1002 -298
- package/lib/commonjs/typescript/core/api.d.ts +2 -1
- package/lib/commonjs/typescript/core/keytype.d.ts +2 -3
- package/lib/commonjs/typescript/core/pusher.d.ts +0 -3
- package/lib/commonjs/typescript/view/MixView.d.ts +1 -9
- package/lib/module/index.js +23206 -20306
- package/lib/module/typescript/android/index.d.ts +0 -3
- package/lib/module/typescript/codegen/android/api.d.ts +190 -644
- package/lib/module/typescript/codegen/android/callback.d.ts +234 -2
- package/lib/module/typescript/codegen/android/errorcode.d.ts +66 -0
- package/lib/module/typescript/codegen/android/keytype.d.ts +1014 -181
- package/lib/module/typescript/codegen/ios/api.d.ts +890 -0
- package/lib/module/typescript/codegen/ios/callback.d.ts +162 -0
- package/lib/module/typescript/codegen/ios/errorcode.d.ts +101 -1
- package/lib/module/typescript/codegen/ios/keytype.d.ts +694 -0
- package/lib/module/typescript/codegen/pack/api.d.ts +303 -686
- package/lib/module/typescript/codegen/pack/callback.d.ts +37 -38
- package/lib/module/typescript/codegen/pack/errorcode.d.ts +75 -5
- package/lib/module/typescript/codegen/pack/keytype.d.ts +1002 -298
- package/lib/module/typescript/core/api.d.ts +2 -1
- package/lib/module/typescript/core/keytype.d.ts +2 -3
- package/lib/module/typescript/core/pusher.d.ts +0 -3
- package/lib/module/typescript/view/MixView.d.ts +1 -9
- package/lib/typescript/android/index.d.ts +0 -3
- package/lib/typescript/codegen/android/api.d.ts +190 -644
- package/lib/typescript/codegen/android/callback.d.ts +234 -2
- package/lib/typescript/codegen/android/errorcode.d.ts +66 -0
- package/lib/typescript/codegen/android/keytype.d.ts +1014 -181
- package/lib/typescript/codegen/ios/api.d.ts +890 -0
- package/lib/typescript/codegen/ios/callback.d.ts +162 -0
- package/lib/typescript/codegen/ios/errorcode.d.ts +101 -1
- package/lib/typescript/codegen/ios/keytype.d.ts +694 -0
- package/lib/typescript/codegen/pack/api.d.ts +303 -686
- package/lib/typescript/codegen/pack/callback.d.ts +37 -38
- package/lib/typescript/codegen/pack/errorcode.d.ts +75 -5
- package/lib/typescript/codegen/pack/keytype.d.ts +1002 -298
- package/lib/typescript/core/api.d.ts +2 -1
- package/lib/typescript/core/keytype.d.ts +2 -3
- package/lib/typescript/core/pusher.d.ts +0 -3
- package/lib/typescript/view/MixView.d.ts +1 -9
- package/package.json +1 -1
- package/react-native-velive-push.podspec +3 -3
- package/android/src/main/java/com/volcengine/velive/rn/push/ScreenCaptureHelper.java +0 -73
package/android/build.gradle
CHANGED
|
@@ -87,6 +87,6 @@ dependencies {
|
|
|
87
87
|
// For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
|
|
88
88
|
//noinspection GradleDynamicVersion
|
|
89
89
|
implementation "com.facebook.react:react-native:+"
|
|
90
|
-
implementation "com.volcengine:VolcApiEngine:1.2
|
|
91
|
-
api 'com.bytedanceapi:ttsdk-ttlivepush_rtc:1.
|
|
90
|
+
implementation "com.volcengine:VolcApiEngine:1.6.2"
|
|
91
|
+
api 'com.bytedanceapi:ttsdk-ttlivepush_rtc:1.46.300.2'
|
|
92
92
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
package com.volcengine.velive.rn.push;
|
|
2
|
+
import com.ss.avframework.live.statistics.VeLivePusherStatisticsExt;
|
|
3
|
+
import com.volcengine.VolcApiEngine.runtime.Util;
|
|
4
|
+
|
|
5
|
+
public class ClassHelper {
|
|
6
|
+
public static void init() {
|
|
7
|
+
Util.JsonAbleClass.add(VeLivePusherStatisticsExt.class);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
package com.volcengine.velive.rn.push;
|
|
2
2
|
|
|
3
3
|
import androidx.annotation.NonNull;
|
|
4
|
-
|
|
5
4
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
6
5
|
import com.volcengine.VolcApiEngine.*;
|
|
7
6
|
|
|
8
7
|
public class NativeVariableManager {
|
|
9
|
-
static void init(@NonNull VolcApiEngine apiEngine,
|
|
8
|
+
static void init(@NonNull VolcApiEngine apiEngine,
|
|
9
|
+
ReactApplicationContext reactContext) {
|
|
10
10
|
var m = apiEngine.msgClient.proto.variableManager;
|
|
11
|
-
|
|
12
|
-
m.registerVar("ApplicationContext", (Object[] args) -> reactContext.getApplicationContext());
|
|
13
|
-
m.registerVar("ReactApplicationContext", (Object[] args) -> reactContext);
|
|
14
11
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
m.registerVar("ApplicationContext",
|
|
13
|
+
(Object[] args) -> reactContext.getApplicationContext());
|
|
14
|
+
m.registerVar("ReactApplicationContext", (Object[] args) -> reactContext);
|
|
18
15
|
}
|
|
19
16
|
}
|
|
@@ -84,7 +84,7 @@ public class MixerManager {
|
|
|
84
84
|
Log.w(TAG, "Failed to perform manual capture after addView", e);
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
|
-
},
|
|
87
|
+
}, 1000);
|
|
88
88
|
} else {
|
|
89
89
|
pendingCallbacks.put(viewId, videoStreamId);
|
|
90
90
|
}
|
|
@@ -167,6 +167,7 @@ public class MixerManager {
|
|
|
167
167
|
MixerView mixerView = (MixerView)view;
|
|
168
168
|
mixerView.setBitmapCaptureCallback(null);
|
|
169
169
|
}
|
|
170
|
+
cachedMixedViews.remove(viewId);
|
|
170
171
|
|
|
171
172
|
pusher.getMixerManager().removeVideoStream(layout.streamId);
|
|
172
173
|
return true;
|
|
@@ -267,9 +268,6 @@ public class MixerManager {
|
|
|
267
268
|
} catch (Exception e) {
|
|
268
269
|
// Ignore
|
|
269
270
|
} finally {
|
|
270
|
-
if (bitmap != null && !bitmap.isRecycled()) {
|
|
271
|
-
bitmap.recycle();
|
|
272
|
-
}
|
|
273
271
|
textureMgr.cleanup();
|
|
274
272
|
}
|
|
275
273
|
}
|
|
@@ -20,24 +20,14 @@ public class MixerView extends FrameLayout {
|
|
|
20
20
|
private ThemedReactContext context;
|
|
21
21
|
private String viewId;
|
|
22
22
|
|
|
23
|
-
// Mix configuration
|
|
24
|
-
private float mixX = 0f;
|
|
25
|
-
private float mixY = 0f;
|
|
26
|
-
private float mixWidth = 0f;
|
|
27
|
-
private float mixHeight = 0f;
|
|
28
|
-
private int mixZOrder = 0;
|
|
29
|
-
private int mixRenderMode = 0;
|
|
30
|
-
|
|
31
23
|
// Capture configuration
|
|
32
24
|
private String captureMode = "onchange";
|
|
33
|
-
private float captureFramerate =
|
|
34
|
-
private float autoSensitivity = 5f;
|
|
25
|
+
private float captureFramerate = 5f; // realTime mode default 5 fps
|
|
35
26
|
|
|
36
27
|
// Capture state
|
|
37
28
|
private Handler captureHandler;
|
|
38
29
|
private Runnable captureRunnable;
|
|
39
30
|
private ViewTreeObserver.OnGlobalLayoutListener layoutListener;
|
|
40
|
-
private ViewTreeObserver.OnDrawListener drawListener;
|
|
41
31
|
private AtomicBoolean isCapturing = new AtomicBoolean(false);
|
|
42
32
|
private AtomicBoolean isDestroyed = new AtomicBoolean(false);
|
|
43
33
|
|
|
@@ -46,14 +36,6 @@ public class MixerView extends FrameLayout {
|
|
|
46
36
|
private long lastCaptureTime = 0;
|
|
47
37
|
private final Object captureLock = new Object();
|
|
48
38
|
|
|
49
|
-
// Auto mode state
|
|
50
|
-
private int changeCount = 0;
|
|
51
|
-
private long windowStartTime = 0;
|
|
52
|
-
private boolean isInRealtimeMode = false;
|
|
53
|
-
private static final long AUTO_WINDOW_MS = 2000; // 2 second window
|
|
54
|
-
private static final int HIGH_CHANGE_THRESHOLD = 10;
|
|
55
|
-
private static final int LOW_CHANGE_THRESHOLD = 2;
|
|
56
|
-
|
|
57
39
|
// Add callback support for MixerManager integration
|
|
58
40
|
private MixerManager.BitmapCaptureCallback bitmapCaptureCallback;
|
|
59
41
|
|
|
@@ -67,19 +49,6 @@ public class MixerView extends FrameLayout {
|
|
|
67
49
|
private void initializeCapture() {
|
|
68
50
|
// Initialize layout change listener
|
|
69
51
|
layoutListener = this::onViewChanged;
|
|
70
|
-
|
|
71
|
-
// Initialize draw listener for auto mode
|
|
72
|
-
drawListener = this::onViewDraw;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Setters for mix configuration
|
|
76
|
-
public void setMixX(float x) { this.mixX = x; }
|
|
77
|
-
public void setMixY(float y) { this.mixY = y; }
|
|
78
|
-
public void setMixWidth(float width) { this.mixWidth = width; }
|
|
79
|
-
public void setMixHeight(float height) { this.mixHeight = height; }
|
|
80
|
-
public void setMixZOrder(int zOrder) { this.mixZOrder = zOrder; }
|
|
81
|
-
public void setMixRenderMode(int renderMode) {
|
|
82
|
-
this.mixRenderMode = renderMode;
|
|
83
52
|
}
|
|
84
53
|
|
|
85
54
|
public void setCaptureMode(String mode) {
|
|
@@ -98,10 +67,6 @@ public class MixerView extends FrameLayout {
|
|
|
98
67
|
}
|
|
99
68
|
}
|
|
100
69
|
|
|
101
|
-
public void setAutoSensitivity(float sensitivity) {
|
|
102
|
-
this.autoSensitivity = Math.max(1f, Math.min(10f, sensitivity));
|
|
103
|
-
}
|
|
104
|
-
|
|
105
70
|
private void startCapture() {
|
|
106
71
|
if (isDestroyed.get())
|
|
107
72
|
return;
|
|
@@ -113,9 +78,6 @@ public class MixerView extends FrameLayout {
|
|
|
113
78
|
case "realtime":
|
|
114
79
|
startRealtimeCapture();
|
|
115
80
|
break;
|
|
116
|
-
case "auto":
|
|
117
|
-
startAutoCapture();
|
|
118
|
-
break;
|
|
119
81
|
case "manual":
|
|
120
82
|
// Manual mode doesn't auto-start
|
|
121
83
|
break;
|
|
@@ -128,9 +90,6 @@ public class MixerView extends FrameLayout {
|
|
|
128
90
|
if (layoutListener != null) {
|
|
129
91
|
getViewTreeObserver().removeOnGlobalLayoutListener(layoutListener);
|
|
130
92
|
}
|
|
131
|
-
if (drawListener != null) {
|
|
132
|
-
getViewTreeObserver().removeOnDrawListener(drawListener);
|
|
133
|
-
}
|
|
134
93
|
}
|
|
135
94
|
|
|
136
95
|
// Stop realtime capture
|
|
@@ -143,14 +102,24 @@ public class MixerView extends FrameLayout {
|
|
|
143
102
|
}
|
|
144
103
|
|
|
145
104
|
private void startOnChangeCapture() {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
105
|
+
// onChange mode triggers every 2 seconds
|
|
106
|
+
long interval = 2000; // 2 seconds
|
|
107
|
+
|
|
108
|
+
captureRunnable = new Runnable() {
|
|
109
|
+
@Override
|
|
110
|
+
public void run() {
|
|
111
|
+
if (!isDestroyed.get() && "onchange".equals(captureMode)) {
|
|
112
|
+
performCapture("onchange");
|
|
113
|
+
captureHandler.postDelayed(this, interval);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
captureHandler.postDelayed(captureRunnable, interval);
|
|
149
118
|
}
|
|
150
119
|
|
|
151
120
|
private void startRealtimeCapture() {
|
|
152
121
|
long interval = (long)(1000f / captureFramerate);
|
|
153
|
-
|
|
122
|
+
|
|
154
123
|
captureRunnable = new Runnable() {
|
|
155
124
|
@Override
|
|
156
125
|
public void run() {
|
|
@@ -170,82 +139,13 @@ public class MixerView extends FrameLayout {
|
|
|
170
139
|
}
|
|
171
140
|
}
|
|
172
141
|
|
|
173
|
-
private void startAutoCapture() {
|
|
174
|
-
// Start with onchange mode
|
|
175
|
-
isInRealtimeMode = false;
|
|
176
|
-
windowStartTime = System.currentTimeMillis();
|
|
177
|
-
changeCount = 0;
|
|
178
|
-
|
|
179
|
-
if (getViewTreeObserver().isAlive()) {
|
|
180
|
-
getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
|
|
181
|
-
getViewTreeObserver().addOnDrawListener(drawListener);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
142
|
private void onViewChanged() {
|
|
186
143
|
if (isDestroyed.get()) {
|
|
187
144
|
return;
|
|
188
145
|
}
|
|
189
146
|
|
|
190
|
-
|
|
191
|
-
case "onchange":
|
|
147
|
+
if ("onchange".equals(captureMode)) {
|
|
192
148
|
performCapture("onchange");
|
|
193
|
-
break;
|
|
194
|
-
case "auto":
|
|
195
|
-
handleAutoModeChange();
|
|
196
|
-
break;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
private void onViewDraw() {
|
|
201
|
-
if (isDestroyed.get() || !"auto".equals(captureMode))
|
|
202
|
-
return;
|
|
203
|
-
|
|
204
|
-
// Count draws for auto mode sensitivity
|
|
205
|
-
changeCount++;
|
|
206
|
-
|
|
207
|
-
long currentTime = System.currentTimeMillis();
|
|
208
|
-
if (currentTime - windowStartTime >= AUTO_WINDOW_MS) {
|
|
209
|
-
evaluateAutoMode();
|
|
210
|
-
// Reset window
|
|
211
|
-
windowStartTime = currentTime;
|
|
212
|
-
changeCount = 0;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
private void handleAutoModeChange() {
|
|
217
|
-
if (!isInRealtimeMode) {
|
|
218
|
-
performCapture("auto_onchange");
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
private void evaluateAutoMode() {
|
|
223
|
-
float changesPerSecond = changeCount * 1000f / AUTO_WINDOW_MS;
|
|
224
|
-
float threshold = autoSensitivity;
|
|
225
|
-
|
|
226
|
-
boolean shouldBeRealtime =
|
|
227
|
-
changesPerSecond > (HIGH_CHANGE_THRESHOLD / threshold);
|
|
228
|
-
boolean shouldBeOnChange =
|
|
229
|
-
changesPerSecond < (LOW_CHANGE_THRESHOLD / threshold);
|
|
230
|
-
|
|
231
|
-
if (shouldBeRealtime && !isInRealtimeMode) {
|
|
232
|
-
switchToRealtimeMode();
|
|
233
|
-
} else if (shouldBeOnChange && isInRealtimeMode) {
|
|
234
|
-
switchToOnChangeMode();
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
private void switchToRealtimeMode() {
|
|
239
|
-
isInRealtimeMode = true;
|
|
240
|
-
startRealtimeCapture();
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
private void switchToOnChangeMode() {
|
|
244
|
-
isInRealtimeMode = false;
|
|
245
|
-
// Stop realtime capture but keep layout listener
|
|
246
|
-
if (captureRunnable != null) {
|
|
247
|
-
captureHandler.removeCallbacks(captureRunnable);
|
|
248
|
-
captureRunnable = null;
|
|
249
149
|
}
|
|
250
150
|
}
|
|
251
151
|
|
|
@@ -260,7 +160,7 @@ public class MixerView extends FrameLayout {
|
|
|
260
160
|
return;
|
|
261
161
|
}
|
|
262
162
|
lastCaptureTime = currentTime;
|
|
263
|
-
|
|
163
|
+
|
|
264
164
|
synchronized (captureLock) {
|
|
265
165
|
if (isCapturing.compareAndSet(false, true)) {
|
|
266
166
|
Bitmap bitmap = null;
|
|
@@ -271,9 +171,16 @@ public class MixerView extends FrameLayout {
|
|
|
271
171
|
}
|
|
272
172
|
} catch (OutOfMemoryError e) {
|
|
273
173
|
System.gc();
|
|
174
|
+
// If an OOM occurs and the bitmap has not been passed to
|
|
175
|
+
// processBitmap, recycle it
|
|
176
|
+
if (bitmap != null && !bitmap.isRecycled()) {
|
|
177
|
+
bitmap.recycle();
|
|
178
|
+
}
|
|
179
|
+
} catch (Exception e) {
|
|
180
|
+
// If any other exception occurs and the bitmap has not been passed to
|
|
181
|
+
// processBitmap, recycle it
|
|
274
182
|
if (bitmap != null && !bitmap.isRecycled()) {
|
|
275
183
|
bitmap.recycle();
|
|
276
|
-
bitmap = null;
|
|
277
184
|
}
|
|
278
185
|
} finally {
|
|
279
186
|
isCapturing.set(false);
|
|
@@ -313,7 +220,7 @@ public class MixerView extends FrameLayout {
|
|
|
313
220
|
}
|
|
314
221
|
return;
|
|
315
222
|
}
|
|
316
|
-
|
|
223
|
+
|
|
317
224
|
// Call callback first if set (for MixerManager)
|
|
318
225
|
if (bitmapCaptureCallback != null) {
|
|
319
226
|
try {
|
|
@@ -321,7 +228,8 @@ public class MixerView extends FrameLayout {
|
|
|
321
228
|
bitmapCaptureCallback.onBitmapCaptured(bitmap);
|
|
322
229
|
} catch (Exception e) {
|
|
323
230
|
if (bitmapCaptureCallback != null) {
|
|
324
|
-
bitmapCaptureCallback.onCaptureError("Callback error: " +
|
|
231
|
+
bitmapCaptureCallback.onCaptureError("Callback error: " +
|
|
232
|
+
e.getMessage());
|
|
325
233
|
}
|
|
326
234
|
}
|
|
327
235
|
} else {
|
|
@@ -330,30 +238,28 @@ public class MixerView extends FrameLayout {
|
|
|
330
238
|
WritableMap event = Arguments.createMap();
|
|
331
239
|
event.putString("trigger", trigger);
|
|
332
240
|
event.putBoolean("success", true);
|
|
333
|
-
event.putDouble("x", mixX);
|
|
334
|
-
event.putDouble("y", mixY);
|
|
335
|
-
event.putDouble("width", mixWidth);
|
|
336
|
-
event.putDouble("height", mixHeight);
|
|
337
|
-
event.putInt("zOrder", mixZOrder);
|
|
338
|
-
event.putInt("renderMode", mixRenderMode);
|
|
339
241
|
event.putInt("bitmapWidth", bitmap.getWidth());
|
|
340
242
|
event.putInt("bitmapHeight", bitmap.getHeight());
|
|
341
243
|
} catch (IllegalStateException e) {
|
|
342
244
|
// Ignore
|
|
343
245
|
}
|
|
344
|
-
|
|
345
|
-
// if no callback, recycle immediately to avoid accumulation
|
|
346
|
-
if (bitmap != null && !bitmap.isRecycled()) {
|
|
347
|
-
bitmap.recycle();
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
246
|
}
|
|
351
247
|
|
|
352
248
|
// Clean up old bitmap
|
|
353
249
|
if (lastBitmap != null && !lastBitmap.isRecycled()) {
|
|
354
250
|
lastBitmap.recycle();
|
|
355
251
|
}
|
|
356
|
-
|
|
252
|
+
|
|
253
|
+
// If no callback is set, immediately release current bitmap to avoid memory accumulation
|
|
254
|
+
// If callback is set, bitmap will be managed by the callback receiver
|
|
255
|
+
if (bitmapCaptureCallback == null) {
|
|
256
|
+
if (bitmap != null && !bitmap.isRecycled()) {
|
|
257
|
+
bitmap.recycle();
|
|
258
|
+
}
|
|
259
|
+
lastBitmap = null;
|
|
260
|
+
} else {
|
|
261
|
+
lastBitmap = bitmap;
|
|
262
|
+
}
|
|
357
263
|
}
|
|
358
264
|
|
|
359
265
|
public void handleCommand(String command, @Nullable ReadableArray args) {
|
|
@@ -380,11 +286,11 @@ public class MixerView extends FrameLayout {
|
|
|
380
286
|
super.onAttachedToWindow();
|
|
381
287
|
if (viewId != null) {
|
|
382
288
|
MixerManager.cachedMixedViews.put(viewId, this);
|
|
383
|
-
//
|
|
289
|
+
// Notify MixerManager that view is ready, check for pending callbacks
|
|
384
290
|
MixerManager.onViewReady(viewId, this);
|
|
385
291
|
}
|
|
386
292
|
}
|
|
387
|
-
|
|
293
|
+
|
|
388
294
|
@Override
|
|
389
295
|
protected void onDetachedFromWindow() {
|
|
390
296
|
super.onDetachedFromWindow();
|
|
@@ -393,24 +299,23 @@ public class MixerView extends FrameLayout {
|
|
|
393
299
|
}
|
|
394
300
|
cleanup();
|
|
395
301
|
}
|
|
396
|
-
|
|
397
|
-
public void setViewId(String viewId) {
|
|
398
|
-
this.viewId = viewId;
|
|
302
|
+
|
|
303
|
+
public void setViewId(String viewId) {
|
|
304
|
+
this.viewId = viewId;
|
|
399
305
|
MixerManager.cachedMixedViews.put(viewId, this);
|
|
400
|
-
//
|
|
306
|
+
// Notify MixerManager that view is ready, check for pending callbacks
|
|
401
307
|
MixerManager.onViewReady(viewId, this);
|
|
402
308
|
}
|
|
403
309
|
|
|
404
310
|
// Add callback support for MixerManager integration
|
|
405
|
-
public void
|
|
311
|
+
public void
|
|
312
|
+
setBitmapCaptureCallback(MixerManager.BitmapCaptureCallback callback) {
|
|
406
313
|
this.bitmapCaptureCallback = callback;
|
|
407
314
|
}
|
|
408
315
|
|
|
409
316
|
// Public method for manual capture (called by MixerManager)
|
|
410
|
-
public void performManualCapture() {
|
|
411
|
-
|
|
412
|
-
}
|
|
413
|
-
|
|
317
|
+
public void performManualCapture() { performCapture("manual"); }
|
|
318
|
+
|
|
414
319
|
private void cleanup() {
|
|
415
320
|
isDestroyed.set(true);
|
|
416
321
|
stopCapture();
|
|
@@ -420,4 +325,4 @@ public class MixerView extends FrameLayout {
|
|
|
420
325
|
lastBitmap = null;
|
|
421
326
|
}
|
|
422
327
|
}
|
|
423
|
-
}
|
|
328
|
+
}
|
|
@@ -22,52 +22,16 @@ public class MixerViewManager extends ViewGroupManager<MixerView> {
|
|
|
22
22
|
return new MixerView(reactContext);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
// Props for mixing configuration
|
|
26
|
-
@ReactProp(name = "x", defaultFloat = 0f)
|
|
27
|
-
public void setX(MixerView view, float x) {
|
|
28
|
-
view.setMixX(x);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
@ReactProp(name = "y", defaultFloat = 0f)
|
|
32
|
-
public void setY(MixerView view, float y) {
|
|
33
|
-
view.setMixY(y);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
@ReactProp(name = "width", defaultFloat = 0f)
|
|
37
|
-
public void setWidth(MixerView view, float width) {
|
|
38
|
-
view.setMixWidth(width);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
@ReactProp(name = "height", defaultFloat = 0f)
|
|
42
|
-
public void setHeight(MixerView view, float height) {
|
|
43
|
-
view.setMixHeight(height);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
@ReactProp(name = "zOrder", defaultInt = 0)
|
|
47
|
-
public void setZOrder(MixerView view, int zOrder) {
|
|
48
|
-
view.setMixZOrder(zOrder);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
@ReactProp(name = "renderMode", defaultInt = 0)
|
|
52
|
-
public void setRenderMode(MixerView view, int renderMode) {
|
|
53
|
-
view.setMixRenderMode(renderMode);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
25
|
@ReactProp(name = "captureMode")
|
|
57
26
|
public void setCaptureMode(MixerView view, @Nullable String captureMode) {
|
|
58
27
|
view.setCaptureMode(captureMode != null ? captureMode : "onchange");
|
|
59
28
|
}
|
|
60
29
|
|
|
61
|
-
@ReactProp(name = "captureFramerate", defaultFloat =
|
|
30
|
+
@ReactProp(name = "captureFramerate", defaultFloat = 5f)
|
|
62
31
|
public void setCaptureFramerate(MixerView view, float framerate) {
|
|
63
32
|
view.setCaptureFramerate(framerate);
|
|
64
33
|
}
|
|
65
34
|
|
|
66
|
-
@ReactProp(name = "autoSensitivity", defaultFloat = 5f)
|
|
67
|
-
public void setAutoSensitivity(MixerView view, float sensitivity) {
|
|
68
|
-
view.setAutoSensitivity(sensitivity);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
35
|
@ReactProp(name = "viewId")
|
|
72
36
|
public void setViewId(MixerView view, @Nullable String viewId) {
|
|
73
37
|
if (viewId != null) {
|
package/ios/VeLiveMixerHelper.h
CHANGED
|
@@ -5,40 +5,45 @@
|
|
|
5
5
|
// Created by ByteDance on 2024/12/09.
|
|
6
6
|
//
|
|
7
7
|
|
|
8
|
-
#import <Foundation/Foundation.h>
|
|
9
8
|
#import "VeLiveMixerView.h"
|
|
9
|
+
#import <CoreVideo/CoreVideo.h>
|
|
10
|
+
#import <Foundation/Foundation.h>
|
|
10
11
|
|
|
11
12
|
NS_ASSUME_NONNULL_BEGIN
|
|
12
13
|
|
|
13
|
-
//
|
|
14
|
+
// Forward declaration
|
|
14
15
|
@class VeLivePusher;
|
|
15
16
|
|
|
16
|
-
//
|
|
17
|
+
// Mixer helper class - fully aligned with Android MixerManager.java
|
|
17
18
|
@interface VeLiveMixerHelper : NSObject <VeLiveBitmapCaptureCallback>
|
|
18
19
|
|
|
19
|
-
//
|
|
20
|
-
@property
|
|
20
|
+
// Aligned with Android's static cachedMixedViews
|
|
21
|
+
@property(class, nonatomic, strong)
|
|
22
|
+
NSMutableDictionary<NSString *, VeLiveMixerUIView *> *cachedMixedViews;
|
|
21
23
|
|
|
22
|
-
@property
|
|
24
|
+
@property(nonatomic, weak) VeLivePusher *pusher;
|
|
23
25
|
|
|
24
26
|
- (instancetype)initWithPusher:(VeLivePusher *)pusher;
|
|
25
27
|
|
|
26
|
-
// Public
|
|
28
|
+
// Public methods - fully aligned with Android MixerManager's public interface
|
|
27
29
|
- (void)setPusher:(VeLivePusher *)pusher;
|
|
28
30
|
- (int)addView:(NSString *)viewId config:(NSDictionary *)viewInfo;
|
|
29
31
|
- (BOOL)updateView:(NSString *)viewId config:(NSDictionary *)viewInfo;
|
|
30
32
|
- (BOOL)removeView:(NSString *)viewId;
|
|
31
33
|
- (void)captureView:(NSString *)viewId;
|
|
32
34
|
|
|
33
|
-
// Static
|
|
34
|
-
+ (void)setupCallbackForMixerView:(VeLiveMixerUIView *)mixerView
|
|
35
|
+
// Static methods - for sending captured content to mixer
|
|
36
|
+
+ (void)setupCallbackForMixerView:(VeLiveMixerUIView *)mixerView
|
|
37
|
+
streamId:(int)streamId;
|
|
35
38
|
+ (void)sendBitmapToMixerStatic:(int)streamId bitmap:(UIImage *)bitmap;
|
|
39
|
+
+ (void)sendPixelBufferToMixerStatic:(int)streamId
|
|
40
|
+
pixelBuffer:(CVPixelBufferRef)pixelBuffer;
|
|
36
41
|
+ (VeLiveMixerHelper *)findActiveMixerManager;
|
|
37
42
|
+ (void)onViewReady:(NSString *)viewId mixerView:(VeLiveMixerUIView *)mixerView;
|
|
38
43
|
|
|
39
|
-
//
|
|
44
|
+
// Resource cleanup
|
|
40
45
|
- (void)cleanup;
|
|
41
46
|
|
|
42
47
|
@end
|
|
43
48
|
|
|
44
|
-
NS_ASSUME_NONNULL_END
|
|
49
|
+
NS_ASSUME_NONNULL_END
|
package/ios/VeLiveMixerHelper.m
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
//
|
|
7
7
|
|
|
8
8
|
#import "VeLiveMixerHelper.h"
|
|
9
|
-
#import <
|
|
9
|
+
#import <TTSDKFramework/VeLivePusher.h>
|
|
10
10
|
#import <UIKit/UIKit.h>
|
|
11
11
|
#import <mach/mach.h>
|
|
12
12
|
#import <mach/task_info.h>
|
|
@@ -43,10 +43,11 @@ static NSString *TAG = @"VeLiveMixerHelper";
|
|
|
43
43
|
|
|
44
44
|
@implementation VeLiveMixerHelper
|
|
45
45
|
|
|
46
|
-
//
|
|
46
|
+
// Aligned with Android's static cachedMixedViews
|
|
47
47
|
static NSMutableDictionary<NSString *, VeLiveMixerUIView *> *_cachedMixedViews =
|
|
48
48
|
nil;
|
|
49
|
-
static VeLiveMixerHelper *currentInstance =
|
|
49
|
+
static VeLiveMixerHelper *currentInstance =
|
|
50
|
+
nil; // Strong reference to prevent ARC deallocation
|
|
50
51
|
|
|
51
52
|
+ (NSMutableDictionary<NSString *, VeLiveMixerUIView *> *)cachedMixedViews {
|
|
52
53
|
if (!_cachedMixedViews) {
|
|
@@ -176,7 +177,7 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
176
177
|
if ([view isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
177
178
|
[VeLiveMixerHelper setupCallbackForMixerView:view streamId:videoStreamId];
|
|
178
179
|
|
|
179
|
-
//
|
|
180
|
+
// Delayed capture execution to ensure view layout completion
|
|
180
181
|
dispatch_after(
|
|
181
182
|
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)),
|
|
182
183
|
dispatch_get_main_queue(), ^{
|
|
@@ -238,7 +239,7 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
238
239
|
|
|
239
240
|
[self.mixedViewLayout setObject:updatedLayout forKey:viewId];
|
|
240
241
|
|
|
241
|
-
//
|
|
242
|
+
// Delayed capture execution to ensure property updates completion
|
|
242
243
|
VeLiveMixerUIView *mixerView =
|
|
243
244
|
[[VeLiveMixerHelper cachedMixedViews] objectForKey:viewId];
|
|
244
245
|
if ([mixerView isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
@@ -344,6 +345,7 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
344
345
|
videoLayout.width = [layout[@"width"] floatValue];
|
|
345
346
|
videoLayout.height = [layout[@"height"] floatValue];
|
|
346
347
|
videoLayout.zOrder = [layout[@"zOrder"] intValue];
|
|
348
|
+
videoLayout.alpha = [layout[@"alpha"] floatValue];
|
|
347
349
|
videoLayout.renderMode = [layout[@"renderMode"] intValue];
|
|
348
350
|
description.mixVideoStreams = @[ videoLayout ];
|
|
349
351
|
[instance.pusher.getMixerManager
|
|
@@ -369,6 +371,15 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
369
371
|
}
|
|
370
372
|
}
|
|
371
373
|
|
|
374
|
+
// New: Send pixelBuffer directly to mixer, avoiding UIImage conversion overhead
|
|
375
|
+
+ (void)sendPixelBufferToMixerStatic:(int)streamId
|
|
376
|
+
pixelBuffer:(CVPixelBufferRef)pixelBuffer {
|
|
377
|
+
VeLiveMixerHelper *instance = [VeLiveMixerHelper findActiveMixerManager];
|
|
378
|
+
if (instance && instance.pusher) {
|
|
379
|
+
[instance sendPixelBufferToMixer:streamId pixelBuffer:pixelBuffer];
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
372
383
|
+ (VeLiveMixerHelper *)findActiveMixerManager {
|
|
373
384
|
return currentInstance;
|
|
374
385
|
}
|
|
@@ -503,6 +514,7 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
503
514
|
|
|
504
515
|
#pragma mark - Private Methods
|
|
505
516
|
|
|
517
|
+
// Send UIImage to mixer (via pixelBuffer conversion)
|
|
506
518
|
- (void)sendBitmapToMixer:(int)streamId bitmap:(UIImage *)bitmap {
|
|
507
519
|
@autoreleasepool {
|
|
508
520
|
if (!self.pusher || !bitmap) {
|
|
@@ -517,6 +529,27 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
517
529
|
return;
|
|
518
530
|
}
|
|
519
531
|
|
|
532
|
+
// Use new pixelBuffer method
|
|
533
|
+
[self sendPixelBufferToMixer:streamId pixelBuffer:pixelBuffer];
|
|
534
|
+
|
|
535
|
+
} @finally {
|
|
536
|
+
if (pixelBuffer) {
|
|
537
|
+
CVPixelBufferRelease(pixelBuffer);
|
|
538
|
+
pixelBuffer = NULL;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Send pixelBuffer directly to mixer, better performance
|
|
545
|
+
- (void)sendPixelBufferToMixer:(int)streamId
|
|
546
|
+
pixelBuffer:(CVPixelBufferRef)pixelBuffer {
|
|
547
|
+
@autoreleasepool {
|
|
548
|
+
if (!self.pusher || !pixelBuffer) {
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
@try {
|
|
520
553
|
VeLiveVideoFrame *videoFrame = [[VeLiveVideoFrame alloc] init];
|
|
521
554
|
videoFrame.bufferType = VeLiveVideoBufferTypePixelBuffer;
|
|
522
555
|
videoFrame.pts = CMTimeMakeWithSeconds(CACurrentMediaTime(), 1000000000);
|
|
@@ -524,15 +557,8 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
524
557
|
|
|
525
558
|
[[self.pusher getMixerManager] sendCustomVideoFrame:videoFrame
|
|
526
559
|
streamId:streamId];
|
|
527
|
-
CVPixelBufferRelease(pixelBuffer);
|
|
528
|
-
|
|
529
|
-
pixelBuffer = NULL;
|
|
530
|
-
|
|
531
560
|
} @catch (NSException *exception) {
|
|
532
|
-
|
|
533
|
-
CVPixelBufferRelease(pixelBuffer);
|
|
534
|
-
pixelBuffer = NULL;
|
|
535
|
-
}
|
|
561
|
+
// Handle exception silently
|
|
536
562
|
}
|
|
537
563
|
}
|
|
538
564
|
}
|
package/ios/VeLiveMixerView.h
CHANGED
|
@@ -30,16 +30,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
30
30
|
// 视图标识
|
|
31
31
|
@property (nonatomic, strong) NSString *viewId;
|
|
32
32
|
|
|
33
|
-
//
|
|
34
|
-
@property (nonatomic, strong) NSNumber *x;
|
|
35
|
-
@property (nonatomic, strong) NSNumber *y;
|
|
36
|
-
@property (nonatomic, strong) NSNumber *width;
|
|
37
|
-
@property (nonatomic, strong) NSNumber *height;
|
|
38
|
-
@property (nonatomic, strong) NSNumber *zOrder;
|
|
39
|
-
@property (nonatomic, strong) NSNumber *renderMode;
|
|
33
|
+
// 捕获配置属性
|
|
40
34
|
@property (nonatomic, strong) NSString *captureMode;
|
|
41
35
|
@property (nonatomic, strong) NSNumber *captureFramerate;
|
|
42
|
-
@property (nonatomic, strong) NSNumber *autoSensitivity;
|
|
43
36
|
|
|
44
37
|
// React Native 事件回调
|
|
45
38
|
@property (nonatomic, copy) RCTBubblingEventBlock onBitmapCapture;
|