@byteplus/react-native-live-push 1.1.3-rc.1 → 1.1.3-rc.3

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 (123) hide show
  1. package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushModule.java +13 -2
  2. package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushPackage.java +16 -13
  3. package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushView.java +16 -0
  4. package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushViewManager.java +7 -2
  5. package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerManager.java +397 -0
  6. package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerView.java +423 -0
  7. package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerViewManager.java +79 -0
  8. package/android/src/main/java/com/volcengine/velive/rn/push/mixer/TextureMgr.java +168 -0
  9. package/android/src/main/java/com/volcengine/velive/rn/push/mixer/YuvHelper.java +165 -0
  10. package/ios/VeLiveMixerHelper.h +44 -0
  11. package/ios/VeLiveMixerHelper.m +591 -0
  12. package/ios/VeLiveMixerView.h +69 -0
  13. package/ios/VeLiveMixerView.m +592 -0
  14. package/ios/VeLiveMixerViewManager.m +92 -0
  15. package/lib/commonjs/index.js +1779 -980
  16. package/lib/commonjs/typescript/android/index.d.ts +47 -0
  17. package/lib/commonjs/typescript/codegen/android/api.d.ts +1527 -0
  18. package/lib/commonjs/typescript/codegen/android/callback.d.ts +91 -0
  19. package/lib/commonjs/typescript/codegen/android/errorcode.d.ts +26 -0
  20. package/lib/commonjs/typescript/codegen/android/index.d.ts +5 -0
  21. package/lib/commonjs/typescript/codegen/android/keytype.d.ts +846 -0
  22. package/lib/commonjs/typescript/codegen/android/types.d.ts +33 -0
  23. package/lib/commonjs/typescript/codegen/ios/api.d.ts +222 -0
  24. package/lib/commonjs/typescript/codegen/ios/callback.d.ts +80 -0
  25. package/lib/commonjs/typescript/codegen/ios/errorcode.d.ts +54 -0
  26. package/lib/commonjs/typescript/codegen/ios/external.d.ts +1 -0
  27. package/lib/commonjs/typescript/codegen/ios/index.d.ts +6 -0
  28. package/lib/commonjs/typescript/codegen/ios/keytype.d.ts +460 -0
  29. package/lib/commonjs/typescript/codegen/ios/types.d.ts +46 -0
  30. package/lib/commonjs/typescript/codegen/pack/api.d.ts +1835 -0
  31. package/lib/commonjs/typescript/codegen/pack/callback.d.ts +400 -0
  32. package/lib/commonjs/typescript/codegen/pack/errorcode.d.ts +35 -0
  33. package/lib/commonjs/typescript/codegen/pack/index.d.ts +5 -0
  34. package/lib/commonjs/typescript/codegen/pack/keytype.d.ts +1392 -0
  35. package/lib/commonjs/typescript/codegen/pack/types.d.ts +68 -0
  36. package/lib/commonjs/typescript/codegen/type-shim.d.ts +6 -0
  37. package/lib/commonjs/typescript/component.d.ts +15 -0
  38. package/lib/commonjs/typescript/core/api.d.ts +17 -0
  39. package/lib/commonjs/typescript/core/callback.d.ts +2 -0
  40. package/lib/commonjs/typescript/core/env.d.ts +29 -0
  41. package/lib/commonjs/typescript/core/errorcode.d.ts +2 -0
  42. package/lib/commonjs/typescript/core/index.d.ts +6 -0
  43. package/lib/commonjs/typescript/core/keytype.d.ts +17 -0
  44. package/lib/commonjs/typescript/core/mixer.d.ts +26 -0
  45. package/lib/commonjs/typescript/core/pusher.d.ts +16 -0
  46. package/lib/commonjs/typescript/index.d.ts +3 -0
  47. package/lib/commonjs/typescript/ios/extends.d.ts +41 -0
  48. package/lib/commonjs/typescript/platforms/android/extends.d.ts +8 -0
  49. package/lib/commonjs/typescript/platforms/android/helper.d.ts +8 -0
  50. package/lib/commonjs/typescript/platforms/android/mixer.d.ts +8 -0
  51. package/lib/commonjs/typescript/platforms/ios/extends.d.ts +17 -0
  52. package/lib/commonjs/typescript/platforms/ios/helper.d.ts +8 -0
  53. package/lib/commonjs/typescript/platforms/ios/mixer.d.ts +9 -0
  54. package/lib/commonjs/typescript/runtime.d.ts +1 -0
  55. package/lib/commonjs/typescript/view/MixView.d.ts +52 -0
  56. package/lib/commonjs/typescript/view/VeImageView.d.ts +19 -0
  57. package/lib/commonjs/typescript/view/VeTextView.d.ts +7 -0
  58. package/lib/commonjs/typescript/view/VeView.d.ts +7 -0
  59. package/lib/commonjs/typescript/view/VeWebView.d.ts +7 -0
  60. package/lib/commonjs/typescript/view/index.d.ts +5 -0
  61. package/lib/module/index.js +1776 -982
  62. package/lib/module/typescript/android/index.d.ts +47 -0
  63. package/lib/module/typescript/codegen/android/api.d.ts +1527 -0
  64. package/lib/module/typescript/codegen/android/callback.d.ts +91 -0
  65. package/lib/module/typescript/codegen/android/errorcode.d.ts +26 -0
  66. package/lib/module/typescript/codegen/android/index.d.ts +5 -0
  67. package/lib/module/typescript/codegen/android/keytype.d.ts +846 -0
  68. package/lib/module/typescript/codegen/android/types.d.ts +33 -0
  69. package/lib/module/typescript/codegen/ios/api.d.ts +222 -0
  70. package/lib/module/typescript/codegen/ios/callback.d.ts +80 -0
  71. package/lib/module/typescript/codegen/ios/errorcode.d.ts +54 -0
  72. package/lib/module/typescript/codegen/ios/external.d.ts +1 -0
  73. package/lib/module/typescript/codegen/ios/index.d.ts +6 -0
  74. package/lib/module/typescript/codegen/ios/keytype.d.ts +460 -0
  75. package/lib/module/typescript/codegen/ios/types.d.ts +46 -0
  76. package/lib/module/typescript/codegen/pack/api.d.ts +1835 -0
  77. package/lib/module/typescript/codegen/pack/callback.d.ts +400 -0
  78. package/lib/module/typescript/codegen/pack/errorcode.d.ts +35 -0
  79. package/lib/module/typescript/codegen/pack/index.d.ts +5 -0
  80. package/lib/module/typescript/codegen/pack/keytype.d.ts +1392 -0
  81. package/lib/module/typescript/codegen/pack/types.d.ts +68 -0
  82. package/lib/module/typescript/codegen/type-shim.d.ts +6 -0
  83. package/lib/module/typescript/component.d.ts +15 -0
  84. package/lib/module/typescript/core/api.d.ts +17 -0
  85. package/lib/module/typescript/core/callback.d.ts +2 -0
  86. package/lib/module/typescript/core/env.d.ts +29 -0
  87. package/lib/module/typescript/core/errorcode.d.ts +2 -0
  88. package/lib/module/typescript/core/index.d.ts +6 -0
  89. package/lib/module/typescript/core/keytype.d.ts +17 -0
  90. package/lib/module/typescript/core/mixer.d.ts +26 -0
  91. package/lib/module/typescript/core/pusher.d.ts +16 -0
  92. package/lib/module/typescript/index.d.ts +3 -0
  93. package/lib/module/typescript/ios/extends.d.ts +41 -0
  94. package/lib/module/typescript/platforms/android/extends.d.ts +8 -0
  95. package/lib/module/typescript/platforms/android/helper.d.ts +8 -0
  96. package/lib/module/typescript/platforms/android/mixer.d.ts +8 -0
  97. package/lib/module/typescript/platforms/ios/extends.d.ts +17 -0
  98. package/lib/module/typescript/platforms/ios/helper.d.ts +8 -0
  99. package/lib/module/typescript/platforms/ios/mixer.d.ts +9 -0
  100. package/lib/module/typescript/runtime.d.ts +1 -0
  101. package/lib/module/typescript/view/MixView.d.ts +52 -0
  102. package/lib/module/typescript/view/VeImageView.d.ts +19 -0
  103. package/lib/module/typescript/view/VeTextView.d.ts +7 -0
  104. package/lib/module/typescript/view/VeView.d.ts +7 -0
  105. package/lib/module/typescript/view/VeWebView.d.ts +7 -0
  106. package/lib/module/typescript/view/index.d.ts +5 -0
  107. package/lib/typescript/codegen/android/api.d.ts +1 -121
  108. package/lib/typescript/codegen/ios/api.d.ts +1 -28
  109. package/lib/typescript/codegen/pack/api.d.ts +1 -133
  110. package/lib/typescript/core/api.d.ts +17 -2
  111. package/lib/typescript/core/keytype.d.ts +15 -0
  112. package/lib/typescript/core/mixer.d.ts +26 -0
  113. package/lib/typescript/index.d.ts +1 -0
  114. package/lib/typescript/platforms/android/extends.d.ts +8 -0
  115. package/lib/typescript/platforms/android/mixer.d.ts +8 -0
  116. package/lib/typescript/platforms/ios/mixer.d.ts +9 -0
  117. package/lib/typescript/view/MixView.d.ts +52 -0
  118. package/lib/typescript/view/VeImageView.d.ts +19 -0
  119. package/lib/typescript/view/VeTextView.d.ts +7 -0
  120. package/lib/typescript/view/VeView.d.ts +7 -0
  121. package/lib/typescript/view/VeWebView.d.ts +7 -0
  122. package/lib/typescript/view/index.d.ts +5 -0
  123. package/package.json +1 -1
@@ -82,8 +82,19 @@ public class VeLivePushModule extends VeLivePushModuleSpec implements IEventRece
82
82
  try {
83
83
  newApiEngine();
84
84
  String params = arg.getString("params");
85
- this.apiEngine.callApi(params, (res) -> {
86
- callback.invoke(res.toJsonString());
85
+
86
+ // 获取主线程处理器
87
+ android.os.Handler mainHandler =
88
+ new android.os.Handler(android.os.Looper.getMainLooper());
89
+
90
+ // 在主线程上执行 API 调用
91
+ mainHandler.post(() -> {
92
+ try {
93
+ this.apiEngine.callApi(
94
+ params, (res) -> { callback.invoke(res.toJsonString()); });
95
+ } catch (Exception e) {
96
+ e.printStackTrace();
97
+ }
87
98
  });
88
99
  } catch (Exception e) {
89
100
  e.printStackTrace();
@@ -4,24 +4,27 @@ import com.facebook.react.ReactPackage;
4
4
  import com.facebook.react.bridge.NativeModule;
5
5
  import com.facebook.react.bridge.ReactApplicationContext;
6
6
  import com.facebook.react.uimanager.ViewManager;
7
-
7
+ import com.volcengine.velive.rn.push.mixer.MixerViewManager;
8
8
  import java.util.ArrayList;
9
9
  import java.util.List;
10
10
 
11
11
  public class VeLivePushPackage implements ReactPackage {
12
- @Override
13
- public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
14
- List<ViewManager> viewManagers = new ArrayList<>();
15
- viewManagers.add(new VeLivePushViewManager());
16
- return viewManagers;
17
- }
12
+ @Override
13
+ public List<ViewManager>
14
+ createViewManagers(ReactApplicationContext reactContext) {
15
+ List<ViewManager> viewManagers = new ArrayList<>();
16
+ viewManagers.add(new VeLivePushViewManager());
17
+ viewManagers.add(new MixerViewManager());
18
+ return viewManagers;
19
+ }
18
20
 
19
- @Override
20
- public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
21
- List<NativeModule> modules = new ArrayList<>();
21
+ @Override
22
+ public List<NativeModule>
23
+ createNativeModules(ReactApplicationContext reactContext) {
24
+ List<NativeModule> modules = new ArrayList<>();
22
25
 
23
- modules.add(new VeLivePushModule(reactContext));
26
+ modules.add(new VeLivePushModule(reactContext));
24
27
 
25
- return modules;
26
- }
28
+ return modules;
29
+ }
27
30
  }
@@ -123,4 +123,20 @@ public class VeLivePushView extends FrameLayout {
123
123
  reactContext.getJSModule(RCTEventEmitter.class)
124
124
  .receiveEvent(getId(), "load", event);
125
125
  }
126
+
127
+ @Override
128
+ protected void onAttachedToWindow() {
129
+ super.onAttachedToWindow();
130
+ if (viewId != null && hasRegister) {
131
+ VolcViewManager.putViewById(viewId, this);
132
+ }
133
+ }
134
+
135
+ @Override
136
+ protected void onDetachedFromWindow() {
137
+ super.onDetachedFromWindow();
138
+ if (viewId != null) {
139
+ // VolcViewManager.removeViewById(viewId);
140
+ }
141
+ }
126
142
  }
@@ -3,6 +3,8 @@ package com.volcengine.velive.rn.push;
3
3
  import android.os.Looper;
4
4
  import androidx.annotation.NonNull;
5
5
  import androidx.annotation.Nullable;
6
+
7
+ import com.facebook.react.bridge.ReactApplicationContext;
6
8
  import com.facebook.react.bridge.ReadableArray;
7
9
  import com.facebook.react.common.MapBuilder;
8
10
  import com.facebook.react.uimanager.SimpleViewManager;
@@ -12,8 +14,10 @@ import java.util.Map;
12
14
 
13
15
  public class VeLivePushViewManager extends SimpleViewManager<VeLivePushView> {
14
16
  public static final String NAME = "VeLivePushView";
15
-
16
- private ThemedReactContext context;
17
+
18
+ public static ReactApplicationContext ctx;
19
+
20
+ public ThemedReactContext context;
17
21
 
18
22
  @NonNull
19
23
  @Override
@@ -31,6 +35,7 @@ public class VeLivePushViewManager extends SimpleViewManager<VeLivePushView> {
31
35
  "View must be created on the main thread");
32
36
  }
33
37
  context = reactContext;
38
+ ctx = context.getReactApplicationContext();
34
39
  return new VeLivePushView(reactContext);
35
40
  }
36
41
 
@@ -0,0 +1,397 @@
1
+ package com.volcengine.velive.rn.push.mixer;
2
+
3
+ import android.graphics.Bitmap;
4
+ import android.util.Log;
5
+ import android.view.View;
6
+ import android.view.ViewTreeObserver;
7
+
8
+ import com.ss.avframework.live.VeLivePusher;
9
+ import com.ss.avframework.live.VeLivePusherDef.VeLiveMixVideoLayout;
10
+ import com.ss.avframework.live.VeLivePusherDef.VeLiveStreamMixDescription;
11
+ import com.ss.avframework.live.VeLivePusherDef.VeLivePusherRenderMode;
12
+ import com.ss.avframework.live.VeLiveVideoFrame;
13
+
14
+ import org.json.JSONObject;
15
+
16
+ import java.util.HashMap;
17
+ import java.util.Map;
18
+ import java.util.concurrent.ConcurrentHashMap;
19
+
20
+ import javax.annotation.Nullable;
21
+
22
+ public class MixerManager {
23
+ public static Map<String, View> cachedMixedViews = new HashMap<>();
24
+
25
+ private static final String TAG = "MixerManager";
26
+
27
+ 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
+ }
35
+
36
+ /**
37
+ * Add a view to the mixer
38
+ * @param viewId Unique identifier for the view
39
+ * @param viewInfo Configuration for the view
40
+ * @return streamId for this view
41
+ */
42
+ 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
+ }
104
+ }
105
+
106
+ /**
107
+ * Update view configuration
108
+ */
109
+ public boolean updateView(String viewId, JSONObject viewInfo) {
110
+ try {
111
+ VeLiveMixVideoLayout layout = mixedViewLayout.get(viewId);
112
+ if(layout == null) {
113
+ return false;
114
+ }
115
+ 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");
120
+ Integer streamId = viewIdToStreamId.get(viewId);
121
+ if(streamId != null) {
122
+ layout.streamId = streamId;
123
+ }
124
+ if (viewInfo.has("zOrder")) {
125
+ layout.zOrder = viewInfo.getInt("zOrder");
126
+ }
127
+ if (viewInfo.has("renderMode")) {
128
+ int renderModeValue = viewInfo.getInt("renderMode");
129
+ VeLivePusherRenderMode[] renderModes = VeLivePusherRenderMode.values();
130
+ if (renderModeValue >= 0 && renderModeValue < renderModes.length) {
131
+ layout.renderMode = renderModes[renderModeValue];
132
+ }
133
+ }
134
+ mixedViewLayout.put(viewId, layout);
135
+ description.mixVideoStreams.add(layout);
136
+ pusher.getMixerManager().updateStreamMixDescription(description);
137
+ View view = cachedMixedViews.get(viewId);
138
+ if (view instanceof MixerView) {
139
+ MixerView mixerView = (MixerView) view;
140
+ mixerView.performManualCapture();
141
+ }
142
+ return true;
143
+ } catch (Exception e) {
144
+ return false;
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Remove view from mixer
150
+ */
151
+ public boolean removeView(String viewId) {
152
+ try {
153
+ VeLiveMixVideoLayout layout = mixedViewLayout.remove(viewId);
154
+ if (layout == null) {
155
+ return false;
156
+ }
157
+
158
+ viewIdToStreamId.remove(viewId);
159
+
160
+ View view = cachedMixedViews.get(viewId);
161
+ if (view instanceof MixerView) {
162
+ MixerView mixerView = (MixerView) view;
163
+ mixerView.setBitmapCaptureCallback(null);
164
+ }
165
+
166
+ pusher.getMixerManager().removeVideoStream(layout.streamId);
167
+ return true;
168
+
169
+ } catch (Exception e) {
170
+ return false;
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Manually trigger bitmap capture for a view
176
+ */
177
+ public void captureView(String viewId) {
178
+ View view = cachedMixedViews.get(viewId);
179
+ if (view instanceof MixerView) {
180
+ MixerView mixerView = (MixerView) view;
181
+ mixerView.performManualCapture();
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Called when MixerView is ready - check for pending callbacks
187
+ */
188
+ public static void onViewReady(String viewId, MixerView mixerView) {
189
+ try {
190
+ MixerManager instance = findActiveMixerManager();
191
+ if (instance != null) {
192
+ Integer streamId = instance.pendingCallbacks.remove(viewId);
193
+ if (streamId != null) {
194
+ setupCallbackForMixerView(mixerView, streamId);
195
+
196
+ android.os.Handler mainHandler = new android.os.Handler(android.os.Looper.getMainLooper());
197
+ mainHandler.postDelayed(new Runnable() {
198
+ @Override
199
+ public void run() {
200
+ try {
201
+ VeLiveMixVideoLayout layout = instance.mixedViewLayout.get(viewId);
202
+ if (layout != null && instance.pusher != null && instance.pusher.getMixerManager() != null) {
203
+ VeLiveStreamMixDescription description = new VeLiveStreamMixDescription();
204
+ description.mixVideoStreams.add(layout);
205
+ instance.pusher.getMixerManager().updateStreamMixDescription(description);
206
+ }
207
+ mixerView.performManualCapture();
208
+ } catch (Exception e) {
209
+ // Ignore
210
+ }
211
+ }
212
+ }, 1000);
213
+ }
214
+ }
215
+ } catch (Exception e) {
216
+ // Ignore
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Send captured bitmap to mixer as video frame
222
+ */
223
+ private void sendBitmapToMixer(int streamId, Bitmap bitmap) {
224
+ try {
225
+ if (bitmap == null || bitmap.isRecycled()) {
226
+ return;
227
+ }
228
+
229
+ if (pusher == null || pusher.getMixerManager() == null) {
230
+ return;
231
+ }
232
+
233
+ int width = bitmap.getWidth();
234
+ int height = bitmap.getHeight();
235
+
236
+ if (width <= 0 || height <= 0) {
237
+ return;
238
+ }
239
+
240
+ TextureMgr textureMgr = new TextureMgr(width, height);
241
+ textureMgr.dealWithTexture(bitmap, new TextureMgr.RenderListener() {
242
+ @Override
243
+ public void doBusiness(int texture) {
244
+ try {
245
+ if (texture <= 0) {
246
+ return;
247
+ }
248
+
249
+ long pts = System.currentTimeMillis() * 1000;
250
+ VeLiveVideoFrame videoFrame = new VeLiveVideoFrame(width, height, pts, texture, false, null);
251
+
252
+ if (pusher != null && pusher.getMixerManager() != null) {
253
+ pusher.getMixerManager().sendCustomVideoFrame(videoFrame, streamId);
254
+ }
255
+ } catch (Exception e) {
256
+ // Ignore
257
+ } finally {
258
+ if (bitmap != null && !bitmap.isRecycled()) {
259
+ bitmap.recycle();
260
+ }
261
+ textureMgr.cleanup();
262
+ }
263
+ }
264
+ });
265
+ } catch (Exception e) {
266
+ // Ignore
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Static method to set up callback for MixerView
272
+ * Now with intelligent layout waiting logic
273
+ */
274
+ private static void setupCallbackForMixerView(MixerView mixerView, int streamId) {
275
+ if (mixerView == null) {
276
+ return;
277
+ }
278
+
279
+ mixerView.setBitmapCaptureCallback(new BitmapCaptureCallback() {
280
+ @Override
281
+ public void onBitmapCaptured(Bitmap bitmap) {
282
+ try {
283
+ if (bitmap != null && !bitmap.isRecycled()) {
284
+ sendBitmapToMixerStatic(streamId, bitmap);
285
+ }
286
+ } catch (OutOfMemoryError e) {
287
+ System.gc();
288
+ } catch (Exception e) {
289
+ // Ignore
290
+ }
291
+ }
292
+
293
+ @Override
294
+ public void onCaptureError(String error) {
295
+ // Ignore
296
+ }
297
+ });
298
+
299
+ if (mixerView.getWidth() > 0 && mixerView.getHeight() > 0) {
300
+ try {
301
+ mixerView.performManualCapture();
302
+ } catch (Exception e) {
303
+ // Ignore
304
+ }
305
+ } 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();
314
+ }
315
+ }
316
+ } catch (Exception e) {
317
+ // Ignore
318
+ }
319
+ }
320
+ };
321
+
322
+ try {
323
+ mixerView.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
324
+ } catch (Exception e) {
325
+ // Ignore
326
+ }
327
+ }
328
+ }
329
+
330
+ /**
331
+ * Static version of sendBitmapToMixer - finds the active MixerManager instance
332
+ */
333
+ private static void sendBitmapToMixerStatic(int streamId, Bitmap bitmap) {
334
+ try {
335
+ MixerManager instance = findActiveMixerManager();
336
+ if (instance != null && instance.pusher != null) {
337
+ instance.sendBitmapToMixer(streamId, bitmap);
338
+ }
339
+ } catch (Exception e) {
340
+ // Ignore
341
+ }
342
+ }
343
+
344
+ /**
345
+ * Find the active MixerManager instance
346
+ */
347
+ private static MixerManager findActiveMixerManager() {
348
+ MixerManager instance = currentInstance;
349
+ if (instance != null && instance.pusher != null) {
350
+ return instance;
351
+ }
352
+ return null;
353
+ }
354
+
355
+ private static volatile MixerManager currentInstance;
356
+
357
+ public MixerManager() {
358
+ synchronized (MixerManager.class) {
359
+ currentInstance = this;
360
+ }
361
+ }
362
+
363
+ /**
364
+ * 清理资源,防止内存泄漏
365
+ */
366
+ public void cleanup() {
367
+ try {
368
+ for (String viewId : cachedMixedViews.keySet()) {
369
+ View view = cachedMixedViews.get(viewId);
370
+ if (view instanceof MixerView) {
371
+ MixerView mixerView = (MixerView) view;
372
+ mixerView.setBitmapCaptureCallback(null);
373
+ }
374
+ }
375
+
376
+ mixedViewLayout.clear();
377
+ viewIdToStreamId.clear();
378
+ pendingCallbacks.clear();
379
+
380
+ synchronized (MixerManager.class) {
381
+ if (currentInstance == this) {
382
+ currentInstance = null;
383
+ }
384
+ }
385
+
386
+ pusher = null;
387
+ } catch (Exception e) {
388
+ // Ignore
389
+ }
390
+ }
391
+
392
+ // Callback interface for bitmap capture
393
+ public interface BitmapCaptureCallback {
394
+ void onBitmapCaptured(Bitmap bitmap);
395
+ void onCaptureError(String error);
396
+ }
397
+ }