@byteplus/react-native-live-push 1.1.3-rc.3 → 1.2.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 (63) 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 +157 -144
  6. package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerView.java +33 -22
  7. package/ios/VeLiveMixerHelper.h +7 -5
  8. package/ios/VeLiveMixerHelper.m +32 -3
  9. package/ios/VeLiveMixerView.m +120 -112
  10. package/ios/VeLiveMixerViewManager.m +2 -2
  11. package/lib/commonjs/index.js +25072 -23532
  12. package/lib/commonjs/typescript/android/index.d.ts +0 -3
  13. package/lib/commonjs/typescript/codegen/android/api.d.ts +190 -644
  14. package/lib/commonjs/typescript/codegen/android/callback.d.ts +234 -2
  15. package/lib/commonjs/typescript/codegen/android/errorcode.d.ts +66 -0
  16. package/lib/commonjs/typescript/codegen/android/keytype.d.ts +1014 -181
  17. package/lib/commonjs/typescript/codegen/ios/api.d.ts +890 -0
  18. package/lib/commonjs/typescript/codegen/ios/callback.d.ts +162 -0
  19. package/lib/commonjs/typescript/codegen/ios/errorcode.d.ts +101 -1
  20. package/lib/commonjs/typescript/codegen/ios/keytype.d.ts +694 -0
  21. package/lib/commonjs/typescript/codegen/pack/api.d.ts +303 -686
  22. package/lib/commonjs/typescript/codegen/pack/callback.d.ts +37 -38
  23. package/lib/commonjs/typescript/codegen/pack/errorcode.d.ts +75 -5
  24. package/lib/commonjs/typescript/codegen/pack/keytype.d.ts +1002 -298
  25. package/lib/commonjs/typescript/core/api.d.ts +2 -1
  26. package/lib/commonjs/typescript/core/keytype.d.ts +1 -0
  27. package/lib/commonjs/typescript/core/pusher.d.ts +0 -3
  28. package/lib/module/index.js +25074 -23533
  29. package/lib/module/typescript/android/index.d.ts +0 -3
  30. package/lib/module/typescript/codegen/android/api.d.ts +190 -644
  31. package/lib/module/typescript/codegen/android/callback.d.ts +234 -2
  32. package/lib/module/typescript/codegen/android/errorcode.d.ts +66 -0
  33. package/lib/module/typescript/codegen/android/keytype.d.ts +1014 -181
  34. package/lib/module/typescript/codegen/ios/api.d.ts +890 -0
  35. package/lib/module/typescript/codegen/ios/callback.d.ts +162 -0
  36. package/lib/module/typescript/codegen/ios/errorcode.d.ts +101 -1
  37. package/lib/module/typescript/codegen/ios/keytype.d.ts +694 -0
  38. package/lib/module/typescript/codegen/pack/api.d.ts +303 -686
  39. package/lib/module/typescript/codegen/pack/callback.d.ts +37 -38
  40. package/lib/module/typescript/codegen/pack/errorcode.d.ts +75 -5
  41. package/lib/module/typescript/codegen/pack/keytype.d.ts +1002 -298
  42. package/lib/module/typescript/core/api.d.ts +2 -1
  43. package/lib/module/typescript/core/keytype.d.ts +1 -0
  44. package/lib/module/typescript/core/pusher.d.ts +0 -3
  45. package/lib/typescript/android/index.d.ts +0 -3
  46. package/lib/typescript/codegen/android/api.d.ts +190 -644
  47. package/lib/typescript/codegen/android/callback.d.ts +234 -2
  48. package/lib/typescript/codegen/android/errorcode.d.ts +66 -0
  49. package/lib/typescript/codegen/android/keytype.d.ts +1014 -181
  50. package/lib/typescript/codegen/ios/api.d.ts +890 -0
  51. package/lib/typescript/codegen/ios/callback.d.ts +162 -0
  52. package/lib/typescript/codegen/ios/errorcode.d.ts +101 -1
  53. package/lib/typescript/codegen/ios/keytype.d.ts +694 -0
  54. package/lib/typescript/codegen/pack/api.d.ts +303 -686
  55. package/lib/typescript/codegen/pack/callback.d.ts +37 -38
  56. package/lib/typescript/codegen/pack/errorcode.d.ts +75 -5
  57. package/lib/typescript/codegen/pack/keytype.d.ts +1002 -298
  58. package/lib/typescript/core/api.d.ts +2 -1
  59. package/lib/typescript/core/keytype.d.ts +1 -0
  60. package/lib/typescript/core/pusher.d.ts +0 -3
  61. package/package.json +1 -1
  62. package/react-native-velive-push.podspec +3 -3
  63. 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
 
@@ -4,34 +4,31 @@ import android.graphics.Bitmap;
4
4
  import android.util.Log;
5
5
  import android.view.View;
6
6
  import android.view.ViewTreeObserver;
7
-
8
7
  import com.ss.avframework.live.VeLivePusher;
9
8
  import com.ss.avframework.live.VeLivePusherDef.VeLiveMixVideoLayout;
10
- import com.ss.avframework.live.VeLivePusherDef.VeLiveStreamMixDescription;
11
9
  import com.ss.avframework.live.VeLivePusherDef.VeLivePusherRenderMode;
10
+ import com.ss.avframework.live.VeLivePusherDef.VeLiveStreamMixDescription;
12
11
  import com.ss.avframework.live.VeLiveVideoFrame;
13
-
14
- import org.json.JSONObject;
15
-
16
12
  import java.util.HashMap;
17
13
  import java.util.Map;
18
14
  import java.util.concurrent.ConcurrentHashMap;
19
-
20
15
  import javax.annotation.Nullable;
16
+ import org.json.JSONObject;
21
17
 
22
18
  public class MixerManager {
23
- public static Map<String, View> cachedMixedViews = new HashMap<>();
19
+ public static Map<String, View> cachedMixedViews = new HashMap<>();
24
20
 
25
21
  private static final String TAG = "MixerManager";
26
22
 
27
23
  private VeLivePusher pusher;
28
- private final Map<String, VeLiveMixVideoLayout> mixedViewLayout = new ConcurrentHashMap<>();
29
- private final Map<String, Integer> viewIdToStreamId = new ConcurrentHashMap<>();
30
- private final Map<String, Integer> pendingCallbacks = new ConcurrentHashMap<>();
31
-
32
- public void setPusher(VeLivePusher pusher) {
33
- this.pusher = pusher;
34
- }
24
+ private final Map<String, VeLiveMixVideoLayout> mixedViewLayout =
25
+ new ConcurrentHashMap<>();
26
+ private final Map<String, Integer> viewIdToStreamId =
27
+ new ConcurrentHashMap<>();
28
+ private final Map<String, Integer> pendingCallbacks =
29
+ new ConcurrentHashMap<>();
30
+
31
+ public void setPusher(VeLivePusher pusher) { this.pusher = pusher; }
35
32
 
36
33
  /**
37
34
  * Add a view to the mixer
@@ -40,85 +37,81 @@ public class MixerManager {
40
37
  * @return streamId for this view
41
38
  */
42
39
  public int addView(String viewId, JSONObject viewInfo) {
43
- try {
44
- if (pusher == null || pusher.getMixerManager() == null) {
45
- return -1;
46
- }
47
-
48
- if (viewIdToStreamId.containsKey(viewId)) {
49
- return viewIdToStreamId.get(viewId);
50
- }
51
-
52
- int videoStreamId = pusher.getMixerManager().addVideoStream();
53
- VeLiveStreamMixDescription description = new VeLiveStreamMixDescription();
54
- VeLiveMixVideoLayout layout = new VeLiveMixVideoLayout();
55
- layout.x = (float) viewInfo.getDouble("x");
56
- layout.y = (float) viewInfo.getDouble("y");
57
- layout.width = (float) viewInfo.getDouble("width");
58
- layout.height = (float) viewInfo.getDouble("height");
59
- layout.zOrder = viewInfo.optInt("zOrder", 0);
60
- int renderModeValue = viewInfo.optInt("renderMode", 0);
61
- VeLivePusherRenderMode[] renderModes = VeLivePusherRenderMode.values();
62
- if (renderModeValue >= 0 && renderModeValue < renderModes.length) {
63
- layout.renderMode = renderModes[renderModeValue];
64
- } else {
65
- layout.renderMode = VeLivePusherRenderMode.values()[0];
66
- }
67
- layout.streamId = videoStreamId;
68
- description.mixVideoStreams.add(layout);
69
- mixedViewLayout.put(viewId, layout);
70
- viewIdToStreamId.put(viewId, videoStreamId);
71
- pusher.getMixerManager().updateStreamMixDescription(description);
72
-
73
- View view = cachedMixedViews.get(viewId);
74
- if (view instanceof MixerView) {
75
- MixerView mixerView = (MixerView) view;
76
- setupCallbackForMixerView(mixerView, videoStreamId);
77
-
78
- android.os.Handler mainHandler = new android.os.Handler(android.os.Looper.getMainLooper());
79
- mainHandler.postDelayed(new Runnable() {
80
- @Override
81
- public void run() {
82
- try {
83
- VeLiveMixVideoLayout layout = mixedViewLayout.get(viewId);
84
- if (layout != null && pusher != null && pusher.getMixerManager() != null) {
85
- VeLiveStreamMixDescription description = new VeLiveStreamMixDescription();
86
- description.mixVideoStreams.add(layout);
87
- pusher.getMixerManager().updateStreamMixDescription(description);
88
- }
89
- mixerView.performManualCapture();
90
- } catch (Exception e) {
91
- // Ignore
92
- }
93
- }
94
- }, 300);
95
-
96
- } else {
97
- pendingCallbacks.put(viewId, videoStreamId);
98
- }
99
-
100
- return videoStreamId;
101
- } catch (Exception e) {
102
- return -1;
103
- }
40
+ try {
41
+ if (pusher == null || pusher.getMixerManager() == null) {
42
+ return -1;
43
+ }
44
+
45
+ if (viewIdToStreamId.containsKey(viewId)) {
46
+ return viewIdToStreamId.get(viewId);
47
+ }
48
+
49
+ int videoStreamId = pusher.getMixerManager().addVideoStream();
50
+ VeLiveStreamMixDescription description = new VeLiveStreamMixDescription();
51
+ VeLiveMixVideoLayout layout = new VeLiveMixVideoLayout();
52
+ layout.x = (float)viewInfo.getDouble("x");
53
+ layout.y = (float)viewInfo.getDouble("y");
54
+ layout.width = (float)viewInfo.getDouble("width");
55
+ layout.height = (float)viewInfo.getDouble("height");
56
+ layout.alpha = (float)viewInfo.optDouble("alpha", 1.0);
57
+ layout.zOrder = viewInfo.optInt("zOrder", 0);
58
+ int renderModeValue = viewInfo.optInt("renderMode", 0);
59
+ VeLivePusherRenderMode[] renderModes = VeLivePusherRenderMode.values();
60
+ if (renderModeValue >= 0 && renderModeValue < renderModes.length) {
61
+ layout.renderMode = renderModes[renderModeValue];
62
+ } else {
63
+ layout.renderMode = VeLivePusherRenderMode.values()[0];
64
+ }
65
+ layout.streamId = videoStreamId;
66
+ description.mixVideoStreams.add(layout);
67
+ mixedViewLayout.put(viewId, layout);
68
+ viewIdToStreamId.put(viewId, videoStreamId);
69
+ pusher.getMixerManager().updateStreamMixDescription(description);
70
+
71
+ View view = cachedMixedViews.get(viewId);
72
+ if (view instanceof MixerView) {
73
+ MixerView mixerView = (MixerView)view;
74
+ setupCallbackForMixerView(mixerView, videoStreamId);
75
+
76
+ android.os.Handler mainHandler =
77
+ new android.os.Handler(android.os.Looper.getMainLooper());
78
+ mainHandler.postDelayed(new Runnable() {
79
+ @Override
80
+ public void run() {
81
+ try {
82
+ mixerView.performManualCapture();
83
+ } catch (Exception e) {
84
+ Log.w(TAG, "Failed to perform manual capture after addView", e);
85
+ }
86
+ }
87
+ }, 300);
88
+ } else {
89
+ pendingCallbacks.put(viewId, videoStreamId);
90
+ }
91
+
92
+ return videoStreamId;
93
+ } catch (Exception e) {
94
+ return -1;
95
+ }
104
96
  }
105
-
97
+
106
98
  /**
107
99
  * Update view configuration
108
100
  */
109
101
  public boolean updateView(String viewId, JSONObject viewInfo) {
110
102
  try {
111
103
  VeLiveMixVideoLayout layout = mixedViewLayout.get(viewId);
112
- if(layout == null) {
104
+ if (layout == null) {
113
105
  return false;
114
106
  }
115
107
  VeLiveStreamMixDescription description = new VeLiveStreamMixDescription();
116
- layout.x = (float) viewInfo.getDouble("x");
117
- layout.y = (float) viewInfo.getDouble("y");
118
- layout.width = (float) viewInfo.getDouble("width");
119
- layout.height = (float) viewInfo.getDouble("height");
108
+ layout.x = (float)viewInfo.getDouble("x");
109
+ layout.y = (float)viewInfo.getDouble("y");
110
+ layout.width = (float)viewInfo.getDouble("width");
111
+ layout.height = (float)viewInfo.getDouble("height");
112
+ layout.alpha = (float)viewInfo.optDouble("alpha", 1.0);
120
113
  Integer streamId = viewIdToStreamId.get(viewId);
121
- if(streamId != null) {
114
+ if (streamId != null) {
122
115
  layout.streamId = streamId;
123
116
  }
124
117
  if (viewInfo.has("zOrder")) {
@@ -134,10 +127,22 @@ public class MixerManager {
134
127
  mixedViewLayout.put(viewId, layout);
135
128
  description.mixVideoStreams.add(layout);
136
129
  pusher.getMixerManager().updateStreamMixDescription(description);
130
+
137
131
  View view = cachedMixedViews.get(viewId);
138
132
  if (view instanceof MixerView) {
139
- MixerView mixerView = (MixerView) view;
140
- mixerView.performManualCapture();
133
+ MixerView mixerView = (MixerView)view;
134
+ android.os.Handler mainHandler =
135
+ new android.os.Handler(android.os.Looper.getMainLooper());
136
+ mainHandler.postDelayed(new Runnable() {
137
+ @Override
138
+ public void run() {
139
+ try {
140
+ mixerView.performManualCapture();
141
+ } catch (Exception e) {
142
+ Log.w(TAG, "Failed to perform manual capture after update", e);
143
+ }
144
+ }
145
+ }, 300);
141
146
  }
142
147
  return true;
143
148
  } catch (Exception e) {
@@ -154,15 +159,16 @@ public class MixerManager {
154
159
  if (layout == null) {
155
160
  return false;
156
161
  }
157
-
162
+
158
163
  viewIdToStreamId.remove(viewId);
159
-
164
+
160
165
  View view = cachedMixedViews.get(viewId);
161
166
  if (view instanceof MixerView) {
162
- MixerView mixerView = (MixerView) view;
167
+ MixerView mixerView = (MixerView)view;
163
168
  mixerView.setBitmapCaptureCallback(null);
164
169
  }
165
-
170
+ cachedMixedViews.remove(viewId);
171
+
166
172
  pusher.getMixerManager().removeVideoStream(layout.streamId);
167
173
  return true;
168
174
 
@@ -177,7 +183,7 @@ public class MixerManager {
177
183
  public void captureView(String viewId) {
178
184
  View view = cachedMixedViews.get(viewId);
179
185
  if (view instanceof MixerView) {
180
- MixerView mixerView = (MixerView) view;
186
+ MixerView mixerView = (MixerView)view;
181
187
  mixerView.performManualCapture();
182
188
  }
183
189
  }
@@ -192,28 +198,33 @@ public class MixerManager {
192
198
  Integer streamId = instance.pendingCallbacks.remove(viewId);
193
199
  if (streamId != null) {
194
200
  setupCallbackForMixerView(mixerView, streamId);
195
-
196
- android.os.Handler mainHandler = new android.os.Handler(android.os.Looper.getMainLooper());
201
+
202
+ android.os.Handler mainHandler =
203
+ new android.os.Handler(android.os.Looper.getMainLooper());
197
204
  mainHandler.postDelayed(new Runnable() {
198
205
  @Override
199
206
  public void run() {
200
207
  try {
201
- VeLiveMixVideoLayout layout = instance.mixedViewLayout.get(viewId);
202
- if (layout != null && instance.pusher != null && instance.pusher.getMixerManager() != null) {
203
- VeLiveStreamMixDescription description = new VeLiveStreamMixDescription();
208
+ VeLiveMixVideoLayout layout =
209
+ instance.mixedViewLayout.get(viewId);
210
+ if (layout != null && instance.pusher != null &&
211
+ instance.pusher.getMixerManager() != null) {
212
+ VeLiveStreamMixDescription description =
213
+ new VeLiveStreamMixDescription();
204
214
  description.mixVideoStreams.add(layout);
205
- instance.pusher.getMixerManager().updateStreamMixDescription(description);
215
+ instance.pusher.getMixerManager().updateStreamMixDescription(
216
+ description);
206
217
  }
207
218
  mixerView.performManualCapture();
208
219
  } catch (Exception e) {
209
- // Ignore
220
+ Log.w(TAG, "Failed to perform operations in onViewReady", e);
210
221
  }
211
222
  }
212
- }, 1000);
223
+ }, 300);
213
224
  }
214
225
  }
215
226
  } catch (Exception e) {
216
- // Ignore
227
+ Log.w(TAG, "Error in onViewReady", e);
217
228
  }
218
229
  }
219
230
 
@@ -225,18 +236,18 @@ public class MixerManager {
225
236
  if (bitmap == null || bitmap.isRecycled()) {
226
237
  return;
227
238
  }
228
-
239
+
229
240
  if (pusher == null || pusher.getMixerManager() == null) {
230
241
  return;
231
242
  }
232
-
243
+
233
244
  int width = bitmap.getWidth();
234
245
  int height = bitmap.getHeight();
235
-
246
+
236
247
  if (width <= 0 || height <= 0) {
237
248
  return;
238
249
  }
239
-
250
+
240
251
  TextureMgr textureMgr = new TextureMgr(width, height);
241
252
  textureMgr.dealWithTexture(bitmap, new TextureMgr.RenderListener() {
242
253
  @Override
@@ -245,19 +256,18 @@ public class MixerManager {
245
256
  if (texture <= 0) {
246
257
  return;
247
258
  }
248
-
259
+
249
260
  long pts = System.currentTimeMillis() * 1000;
250
- VeLiveVideoFrame videoFrame = new VeLiveVideoFrame(width, height, pts, texture, false, null);
251
-
261
+ VeLiveVideoFrame videoFrame =
262
+ new VeLiveVideoFrame(width, height, pts, texture, false, null);
263
+
252
264
  if (pusher != null && pusher.getMixerManager() != null) {
253
- pusher.getMixerManager().sendCustomVideoFrame(videoFrame, streamId);
265
+ pusher.getMixerManager().sendCustomVideoFrame(videoFrame,
266
+ streamId);
254
267
  }
255
268
  } catch (Exception e) {
256
269
  // Ignore
257
270
  } finally {
258
- if (bitmap != null && !bitmap.isRecycled()) {
259
- bitmap.recycle();
260
- }
261
271
  textureMgr.cleanup();
262
272
  }
263
273
  }
@@ -266,16 +276,17 @@ public class MixerManager {
266
276
  // Ignore
267
277
  }
268
278
  }
269
-
279
+
270
280
  /**
271
281
  * Static method to set up callback for MixerView
272
282
  * Now with intelligent layout waiting logic
273
283
  */
274
- private static void setupCallbackForMixerView(MixerView mixerView, int streamId) {
284
+ private static void setupCallbackForMixerView(MixerView mixerView,
285
+ int streamId) {
275
286
  if (mixerView == null) {
276
287
  return;
277
288
  }
278
-
289
+
279
290
  mixerView.setBitmapCaptureCallback(new BitmapCaptureCallback() {
280
291
  @Override
281
292
  public void onBitmapCaptured(Bitmap bitmap) {
@@ -289,13 +300,13 @@ public class MixerManager {
289
300
  // Ignore
290
301
  }
291
302
  }
292
-
303
+
293
304
  @Override
294
305
  public void onCaptureError(String error) {
295
306
  // Ignore
296
307
  }
297
308
  });
298
-
309
+
299
310
  if (mixerView.getWidth() > 0 && mixerView.getHeight() > 0) {
300
311
  try {
301
312
  mixerView.performManualCapture();
@@ -303,32 +314,36 @@ public class MixerManager {
303
314
  // Ignore
304
315
  }
305
316
  } else {
306
- ViewTreeObserver.OnGlobalLayoutListener layoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
307
- @Override
308
- public void onGlobalLayout() {
309
- try {
310
- if (mixerView.getViewTreeObserver().isAlive()) {
311
- if (mixerView.getWidth() > 0 && mixerView.getHeight() > 0) {
312
- mixerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
313
- mixerView.performManualCapture();
317
+ ViewTreeObserver.OnGlobalLayoutListener layoutListener =
318
+ new ViewTreeObserver.OnGlobalLayoutListener() {
319
+ @Override
320
+ public void onGlobalLayout() {
321
+ try {
322
+ if (mixerView.getViewTreeObserver().isAlive()) {
323
+ if (mixerView.getWidth() > 0 && mixerView.getHeight() > 0) {
324
+ mixerView.getViewTreeObserver()
325
+ .removeOnGlobalLayoutListener(this);
326
+ mixerView.performManualCapture();
327
+ }
328
+ }
329
+ } catch (Exception e) {
330
+ // Ignore
314
331
  }
315
332
  }
316
- } catch (Exception e) {
317
- // Ignore
318
- }
319
- }
320
- };
321
-
333
+ };
334
+
322
335
  try {
323
- mixerView.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
336
+ mixerView.getViewTreeObserver().addOnGlobalLayoutListener(
337
+ layoutListener);
324
338
  } catch (Exception e) {
325
339
  // Ignore
326
340
  }
327
341
  }
328
342
  }
329
-
343
+
330
344
  /**
331
- * Static version of sendBitmapToMixer - finds the active MixerManager instance
345
+ * Static version of sendBitmapToMixer - finds the active MixerManager
346
+ * instance
332
347
  */
333
348
  private static void sendBitmapToMixerStatic(int streamId, Bitmap bitmap) {
334
349
  try {
@@ -340,7 +355,7 @@ public class MixerManager {
340
355
  // Ignore
341
356
  }
342
357
  }
343
-
358
+
344
359
  /**
345
360
  * Find the active MixerManager instance
346
361
  */
@@ -351,44 +366,42 @@ public class MixerManager {
351
366
  }
352
367
  return null;
353
368
  }
354
-
369
+
355
370
  private static volatile MixerManager currentInstance;
356
-
371
+
357
372
  public MixerManager() {
358
- synchronized (MixerManager.class) {
359
- currentInstance = this;
360
- }
373
+ synchronized (MixerManager.class) { currentInstance = this; }
361
374
  }
362
-
375
+
363
376
  /**
364
- * 清理资源,防止内存泄漏
377
+ * cleanup method to release resources
365
378
  */
366
379
  public void cleanup() {
367
380
  try {
368
381
  for (String viewId : cachedMixedViews.keySet()) {
369
382
  View view = cachedMixedViews.get(viewId);
370
383
  if (view instanceof MixerView) {
371
- MixerView mixerView = (MixerView) view;
384
+ MixerView mixerView = (MixerView)view;
372
385
  mixerView.setBitmapCaptureCallback(null);
373
386
  }
374
387
  }
375
-
388
+
376
389
  mixedViewLayout.clear();
377
390
  viewIdToStreamId.clear();
378
391
  pendingCallbacks.clear();
379
-
392
+
380
393
  synchronized (MixerManager.class) {
381
394
  if (currentInstance == this) {
382
395
  currentInstance = null;
383
396
  }
384
397
  }
385
-
398
+
386
399
  pusher = null;
387
400
  } catch (Exception e) {
388
401
  // Ignore
389
402
  }
390
403
  }
391
-
404
+
392
405
  // Callback interface for bitmap capture
393
406
  public interface BitmapCaptureCallback {
394
407
  void onBitmapCaptured(Bitmap bitmap);
@@ -150,7 +150,7 @@ public class MixerView extends FrameLayout {
150
150
 
151
151
  private void startRealtimeCapture() {
152
152
  long interval = (long)(1000f / captureFramerate);
153
-
153
+
154
154
  captureRunnable = new Runnable() {
155
155
  @Override
156
156
  public void run() {
@@ -260,7 +260,7 @@ public class MixerView extends FrameLayout {
260
260
  return;
261
261
  }
262
262
  lastCaptureTime = currentTime;
263
-
263
+
264
264
  synchronized (captureLock) {
265
265
  if (isCapturing.compareAndSet(false, true)) {
266
266
  Bitmap bitmap = null;
@@ -271,9 +271,16 @@ public class MixerView extends FrameLayout {
271
271
  }
272
272
  } catch (OutOfMemoryError e) {
273
273
  System.gc();
274
+ // If an OOM occurs and the bitmap has not been passed to
275
+ // processBitmap, recycle it
276
+ if (bitmap != null && !bitmap.isRecycled()) {
277
+ bitmap.recycle();
278
+ }
279
+ } catch (Exception e) {
280
+ // If any other exception occurs and the bitmap has not been passed to
281
+ // processBitmap, recycle it
274
282
  if (bitmap != null && !bitmap.isRecycled()) {
275
283
  bitmap.recycle();
276
- bitmap = null;
277
284
  }
278
285
  } finally {
279
286
  isCapturing.set(false);
@@ -313,7 +320,7 @@ public class MixerView extends FrameLayout {
313
320
  }
314
321
  return;
315
322
  }
316
-
323
+
317
324
  // Call callback first if set (for MixerManager)
318
325
  if (bitmapCaptureCallback != null) {
319
326
  try {
@@ -321,7 +328,8 @@ public class MixerView extends FrameLayout {
321
328
  bitmapCaptureCallback.onBitmapCaptured(bitmap);
322
329
  } catch (Exception e) {
323
330
  if (bitmapCaptureCallback != null) {
324
- bitmapCaptureCallback.onCaptureError("Callback error: " + e.getMessage());
331
+ bitmapCaptureCallback.onCaptureError("Callback error: " +
332
+ e.getMessage());
325
333
  }
326
334
  }
327
335
  } else {
@@ -341,19 +349,23 @@ public class MixerView extends FrameLayout {
341
349
  } catch (IllegalStateException e) {
342
350
  // Ignore
343
351
  }
344
-
345
- // if no callback, recycle immediately to avoid accumulation
346
- if (bitmap != null && !bitmap.isRecycled()) {
347
- bitmap.recycle();
348
- return;
349
- }
350
352
  }
351
353
 
352
354
  // Clean up old bitmap
353
355
  if (lastBitmap != null && !lastBitmap.isRecycled()) {
354
356
  lastBitmap.recycle();
355
357
  }
356
- lastBitmap = bitmap;
358
+
359
+ // 如果没有设置回调,立即释放当前 bitmap 以避免内存累积
360
+ // 如果设置了回调,bitmap 将由回调的接收方负责管理
361
+ if (bitmapCaptureCallback == null) {
362
+ if (bitmap != null && !bitmap.isRecycled()) {
363
+ bitmap.recycle();
364
+ }
365
+ lastBitmap = null;
366
+ } else {
367
+ lastBitmap = bitmap;
368
+ }
357
369
  }
358
370
 
359
371
  public void handleCommand(String command, @Nullable ReadableArray args) {
@@ -384,7 +396,7 @@ public class MixerView extends FrameLayout {
384
396
  MixerManager.onViewReady(viewId, this);
385
397
  }
386
398
  }
387
-
399
+
388
400
  @Override
389
401
  protected void onDetachedFromWindow() {
390
402
  super.onDetachedFromWindow();
@@ -393,24 +405,23 @@ public class MixerView extends FrameLayout {
393
405
  }
394
406
  cleanup();
395
407
  }
396
-
397
- public void setViewId(String viewId) {
398
- this.viewId = viewId;
408
+
409
+ public void setViewId(String viewId) {
410
+ this.viewId = viewId;
399
411
  MixerManager.cachedMixedViews.put(viewId, this);
400
412
  // 通知MixerManager视图已准备好,检查是否有待处理的回调
401
413
  MixerManager.onViewReady(viewId, this);
402
414
  }
403
415
 
404
416
  // Add callback support for MixerManager integration
405
- public void setBitmapCaptureCallback(MixerManager.BitmapCaptureCallback callback) {
417
+ public void
418
+ setBitmapCaptureCallback(MixerManager.BitmapCaptureCallback callback) {
406
419
  this.bitmapCaptureCallback = callback;
407
420
  }
408
421
 
409
422
  // Public method for manual capture (called by MixerManager)
410
- public void performManualCapture() {
411
- performCapture("manual");
412
- }
413
-
423
+ public void performManualCapture() { performCapture("manual"); }
424
+
414
425
  private void cleanup() {
415
426
  isDestroyed.set(true);
416
427
  stopCapture();
@@ -420,4 +431,4 @@ public class MixerView extends FrameLayout {
420
431
  lastBitmap = null;
421
432
  }
422
433
  }
423
- }
434
+ }