@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.
Files changed (68) hide show
  1. package/android/build.gradle +2 -2
  2. package/android/src/main/java/com/volcengine/velive/rn/push/ClassHelper.java +9 -0
  3. package/android/src/main/java/com/volcengine/velive/rn/push/NativeVariableManager.java +5 -8
  4. package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushModule.java +1 -0
  5. package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerManager.java +2 -4
  6. package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerView.java +50 -145
  7. package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerViewManager.java +1 -37
  8. package/ios/VeLiveMixerHelper.h +16 -11
  9. package/ios/VeLiveMixerHelper.m +39 -13
  10. package/ios/VeLiveMixerView.h +1 -8
  11. package/ios/VeLiveMixerView.m +178 -231
  12. package/ios/VeLiveMixerViewManager.m +2 -38
  13. package/lib/commonjs/index.js +23205 -20306
  14. package/lib/commonjs/typescript/android/index.d.ts +0 -3
  15. package/lib/commonjs/typescript/codegen/android/api.d.ts +190 -644
  16. package/lib/commonjs/typescript/codegen/android/callback.d.ts +234 -2
  17. package/lib/commonjs/typescript/codegen/android/errorcode.d.ts +66 -0
  18. package/lib/commonjs/typescript/codegen/android/keytype.d.ts +1014 -181
  19. package/lib/commonjs/typescript/codegen/ios/api.d.ts +890 -0
  20. package/lib/commonjs/typescript/codegen/ios/callback.d.ts +162 -0
  21. package/lib/commonjs/typescript/codegen/ios/errorcode.d.ts +101 -1
  22. package/lib/commonjs/typescript/codegen/ios/keytype.d.ts +694 -0
  23. package/lib/commonjs/typescript/codegen/pack/api.d.ts +303 -686
  24. package/lib/commonjs/typescript/codegen/pack/callback.d.ts +37 -38
  25. package/lib/commonjs/typescript/codegen/pack/errorcode.d.ts +75 -5
  26. package/lib/commonjs/typescript/codegen/pack/keytype.d.ts +1002 -298
  27. package/lib/commonjs/typescript/core/api.d.ts +2 -1
  28. package/lib/commonjs/typescript/core/keytype.d.ts +2 -3
  29. package/lib/commonjs/typescript/core/pusher.d.ts +0 -3
  30. package/lib/commonjs/typescript/view/MixView.d.ts +1 -9
  31. package/lib/module/index.js +23206 -20306
  32. package/lib/module/typescript/android/index.d.ts +0 -3
  33. package/lib/module/typescript/codegen/android/api.d.ts +190 -644
  34. package/lib/module/typescript/codegen/android/callback.d.ts +234 -2
  35. package/lib/module/typescript/codegen/android/errorcode.d.ts +66 -0
  36. package/lib/module/typescript/codegen/android/keytype.d.ts +1014 -181
  37. package/lib/module/typescript/codegen/ios/api.d.ts +890 -0
  38. package/lib/module/typescript/codegen/ios/callback.d.ts +162 -0
  39. package/lib/module/typescript/codegen/ios/errorcode.d.ts +101 -1
  40. package/lib/module/typescript/codegen/ios/keytype.d.ts +694 -0
  41. package/lib/module/typescript/codegen/pack/api.d.ts +303 -686
  42. package/lib/module/typescript/codegen/pack/callback.d.ts +37 -38
  43. package/lib/module/typescript/codegen/pack/errorcode.d.ts +75 -5
  44. package/lib/module/typescript/codegen/pack/keytype.d.ts +1002 -298
  45. package/lib/module/typescript/core/api.d.ts +2 -1
  46. package/lib/module/typescript/core/keytype.d.ts +2 -3
  47. package/lib/module/typescript/core/pusher.d.ts +0 -3
  48. package/lib/module/typescript/view/MixView.d.ts +1 -9
  49. package/lib/typescript/android/index.d.ts +0 -3
  50. package/lib/typescript/codegen/android/api.d.ts +190 -644
  51. package/lib/typescript/codegen/android/callback.d.ts +234 -2
  52. package/lib/typescript/codegen/android/errorcode.d.ts +66 -0
  53. package/lib/typescript/codegen/android/keytype.d.ts +1014 -181
  54. package/lib/typescript/codegen/ios/api.d.ts +890 -0
  55. package/lib/typescript/codegen/ios/callback.d.ts +162 -0
  56. package/lib/typescript/codegen/ios/errorcode.d.ts +101 -1
  57. package/lib/typescript/codegen/ios/keytype.d.ts +694 -0
  58. package/lib/typescript/codegen/pack/api.d.ts +303 -686
  59. package/lib/typescript/codegen/pack/callback.d.ts +37 -38
  60. package/lib/typescript/codegen/pack/errorcode.d.ts +75 -5
  61. package/lib/typescript/codegen/pack/keytype.d.ts +1002 -298
  62. package/lib/typescript/core/api.d.ts +2 -1
  63. package/lib/typescript/core/keytype.d.ts +2 -3
  64. package/lib/typescript/core/pusher.d.ts +0 -3
  65. package/lib/typescript/view/MixView.d.ts +1 -9
  66. package/package.json +1 -1
  67. package/react-native-velive-push.podspec +3 -3
  68. package/android/src/main/java/com/volcengine/velive/rn/push/ScreenCaptureHelper.java +0 -73
@@ -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.3"
91
- api 'com.bytedanceapi:ttsdk-ttlivepush_rtc:1.41.300.103'
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, ReactApplicationContext reactContext) {
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
- var helper = new ScreenCaptureHelper(reactContext);
16
- m.registerVar("screenIntent", helper::getScreenIntent);
17
- helper.setup();
12
+ m.registerVar("ApplicationContext",
13
+ (Object[] args) -> reactContext.getApplicationContext());
14
+ m.registerVar("ReactApplicationContext", (Object[] args) -> reactContext);
18
15
  }
19
16
  }
@@ -50,6 +50,7 @@ public class VeLivePushModule extends VeLivePushModuleSpec implements IEventRece
50
50
  apiEngine = new VolcApiEngine(getReactApplicationContext(), this);
51
51
 
52
52
  NativeVariableManager.init(apiEngine, super.context);
53
+ ClassHelper.init();
53
54
  return true;
54
55
  }
55
56
 
@@ -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
- }, 300);
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 = 30f;
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
- if (getViewTreeObserver().isAlive()) {
147
- getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
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
- switch (captureMode) {
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: " + e.getMessage());
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
- lastBitmap = bitmap;
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
- // 通知MixerManager视图已准备好,检查是否有待处理的回调
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
- // 通知MixerManager视图已准备好,检查是否有待处理的回调
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 setBitmapCaptureCallback(MixerManager.BitmapCaptureCallback callback) {
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
- performCapture("manual");
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 = 30f)
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) {
@@ -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
- // 混流管理器助手类 - 完全对齐Android MixerManager.java
17
+ // Mixer helper class - fully aligned with Android MixerManager.java
17
18
  @interface VeLiveMixerHelper : NSObject <VeLiveBitmapCaptureCallback>
18
19
 
19
- // 对齐Androidstatic cachedMixedViews
20
- @property (class, nonatomic, strong) NSMutableDictionary<NSString *, VeLiveMixerUIView *> *cachedMixedViews;
20
+ // Aligned with Android's static cachedMixedViews
21
+ @property(class, nonatomic, strong)
22
+ NSMutableDictionary<NSString *, VeLiveMixerUIView *> *cachedMixedViews;
21
23
 
22
- @property (nonatomic, weak) VeLivePusher *pusher;
24
+ @property(nonatomic, weak) VeLivePusher *pusher;
23
25
 
24
26
  - (instancetype)initWithPusher:(VeLivePusher *)pusher;
25
27
 
26
- // Public方法 - 完全对齐Android MixerManagerpublic接口
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方法 - 只保留Android中实际存在的
34
- + (void)setupCallbackForMixerView:(VeLiveMixerUIView *)mixerView streamId:(int)streamId;
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
@@ -6,7 +6,7 @@
6
6
  //
7
7
 
8
8
  #import "VeLiveMixerHelper.h"
9
- #import <TTSDKLivePushRTS/TTSDKLivePushRTS.h>
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
- // 对齐Androidstatic cachedMixedViews
46
+ // Aligned with Android's static cachedMixedViews
47
47
  static NSMutableDictionary<NSString *, VeLiveMixerUIView *> *_cachedMixedViews =
48
48
  nil;
49
- static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释放
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
- if (pixelBuffer) {
533
- CVPixelBufferRelease(pixelBuffer);
534
- pixelBuffer = NULL;
535
- }
561
+ // Handle exception silently
536
562
  }
537
563
  }
538
564
  }
@@ -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;