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

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.
@@ -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,15 @@ 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
+
166
171
  pusher.getMixerManager().removeVideoStream(layout.streamId);
167
172
  return true;
168
173
 
@@ -177,7 +182,7 @@ public class MixerManager {
177
182
  public void captureView(String viewId) {
178
183
  View view = cachedMixedViews.get(viewId);
179
184
  if (view instanceof MixerView) {
180
- MixerView mixerView = (MixerView) view;
185
+ MixerView mixerView = (MixerView)view;
181
186
  mixerView.performManualCapture();
182
187
  }
183
188
  }
@@ -192,28 +197,33 @@ public class MixerManager {
192
197
  Integer streamId = instance.pendingCallbacks.remove(viewId);
193
198
  if (streamId != null) {
194
199
  setupCallbackForMixerView(mixerView, streamId);
195
-
196
- android.os.Handler mainHandler = new android.os.Handler(android.os.Looper.getMainLooper());
200
+
201
+ android.os.Handler mainHandler =
202
+ new android.os.Handler(android.os.Looper.getMainLooper());
197
203
  mainHandler.postDelayed(new Runnable() {
198
204
  @Override
199
205
  public void run() {
200
206
  try {
201
- VeLiveMixVideoLayout layout = instance.mixedViewLayout.get(viewId);
202
- if (layout != null && instance.pusher != null && instance.pusher.getMixerManager() != null) {
203
- VeLiveStreamMixDescription description = new VeLiveStreamMixDescription();
207
+ VeLiveMixVideoLayout layout =
208
+ instance.mixedViewLayout.get(viewId);
209
+ if (layout != null && instance.pusher != null &&
210
+ instance.pusher.getMixerManager() != null) {
211
+ VeLiveStreamMixDescription description =
212
+ new VeLiveStreamMixDescription();
204
213
  description.mixVideoStreams.add(layout);
205
- instance.pusher.getMixerManager().updateStreamMixDescription(description);
214
+ instance.pusher.getMixerManager().updateStreamMixDescription(
215
+ description);
206
216
  }
207
217
  mixerView.performManualCapture();
208
218
  } catch (Exception e) {
209
- // Ignore
219
+ Log.w(TAG, "Failed to perform operations in onViewReady", e);
210
220
  }
211
221
  }
212
- }, 1000);
222
+ }, 300);
213
223
  }
214
224
  }
215
225
  } catch (Exception e) {
216
- // Ignore
226
+ Log.w(TAG, "Error in onViewReady", e);
217
227
  }
218
228
  }
219
229
 
@@ -225,18 +235,18 @@ public class MixerManager {
225
235
  if (bitmap == null || bitmap.isRecycled()) {
226
236
  return;
227
237
  }
228
-
238
+
229
239
  if (pusher == null || pusher.getMixerManager() == null) {
230
240
  return;
231
241
  }
232
-
242
+
233
243
  int width = bitmap.getWidth();
234
244
  int height = bitmap.getHeight();
235
-
245
+
236
246
  if (width <= 0 || height <= 0) {
237
247
  return;
238
248
  }
239
-
249
+
240
250
  TextureMgr textureMgr = new TextureMgr(width, height);
241
251
  textureMgr.dealWithTexture(bitmap, new TextureMgr.RenderListener() {
242
252
  @Override
@@ -245,12 +255,14 @@ public class MixerManager {
245
255
  if (texture <= 0) {
246
256
  return;
247
257
  }
248
-
258
+
249
259
  long pts = System.currentTimeMillis() * 1000;
250
- VeLiveVideoFrame videoFrame = new VeLiveVideoFrame(width, height, pts, texture, false, null);
251
-
260
+ VeLiveVideoFrame videoFrame =
261
+ new VeLiveVideoFrame(width, height, pts, texture, false, null);
262
+
252
263
  if (pusher != null && pusher.getMixerManager() != null) {
253
- pusher.getMixerManager().sendCustomVideoFrame(videoFrame, streamId);
264
+ pusher.getMixerManager().sendCustomVideoFrame(videoFrame,
265
+ streamId);
254
266
  }
255
267
  } catch (Exception e) {
256
268
  // Ignore
@@ -266,16 +278,17 @@ public class MixerManager {
266
278
  // Ignore
267
279
  }
268
280
  }
269
-
281
+
270
282
  /**
271
283
  * Static method to set up callback for MixerView
272
284
  * Now with intelligent layout waiting logic
273
285
  */
274
- private static void setupCallbackForMixerView(MixerView mixerView, int streamId) {
286
+ private static void setupCallbackForMixerView(MixerView mixerView,
287
+ int streamId) {
275
288
  if (mixerView == null) {
276
289
  return;
277
290
  }
278
-
291
+
279
292
  mixerView.setBitmapCaptureCallback(new BitmapCaptureCallback() {
280
293
  @Override
281
294
  public void onBitmapCaptured(Bitmap bitmap) {
@@ -289,13 +302,13 @@ public class MixerManager {
289
302
  // Ignore
290
303
  }
291
304
  }
292
-
305
+
293
306
  @Override
294
307
  public void onCaptureError(String error) {
295
308
  // Ignore
296
309
  }
297
310
  });
298
-
311
+
299
312
  if (mixerView.getWidth() > 0 && mixerView.getHeight() > 0) {
300
313
  try {
301
314
  mixerView.performManualCapture();
@@ -303,32 +316,36 @@ public class MixerManager {
303
316
  // Ignore
304
317
  }
305
318
  } 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();
319
+ ViewTreeObserver.OnGlobalLayoutListener layoutListener =
320
+ new ViewTreeObserver.OnGlobalLayoutListener() {
321
+ @Override
322
+ public void onGlobalLayout() {
323
+ try {
324
+ if (mixerView.getViewTreeObserver().isAlive()) {
325
+ if (mixerView.getWidth() > 0 && mixerView.getHeight() > 0) {
326
+ mixerView.getViewTreeObserver()
327
+ .removeOnGlobalLayoutListener(this);
328
+ mixerView.performManualCapture();
329
+ }
330
+ }
331
+ } catch (Exception e) {
332
+ // Ignore
314
333
  }
315
334
  }
316
- } catch (Exception e) {
317
- // Ignore
318
- }
319
- }
320
- };
321
-
335
+ };
336
+
322
337
  try {
323
- mixerView.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
338
+ mixerView.getViewTreeObserver().addOnGlobalLayoutListener(
339
+ layoutListener);
324
340
  } catch (Exception e) {
325
341
  // Ignore
326
342
  }
327
343
  }
328
344
  }
329
-
345
+
330
346
  /**
331
- * Static version of sendBitmapToMixer - finds the active MixerManager instance
347
+ * Static version of sendBitmapToMixer - finds the active MixerManager
348
+ * instance
332
349
  */
333
350
  private static void sendBitmapToMixerStatic(int streamId, Bitmap bitmap) {
334
351
  try {
@@ -340,7 +357,7 @@ public class MixerManager {
340
357
  // Ignore
341
358
  }
342
359
  }
343
-
360
+
344
361
  /**
345
362
  * Find the active MixerManager instance
346
363
  */
@@ -351,44 +368,42 @@ public class MixerManager {
351
368
  }
352
369
  return null;
353
370
  }
354
-
371
+
355
372
  private static volatile MixerManager currentInstance;
356
-
373
+
357
374
  public MixerManager() {
358
- synchronized (MixerManager.class) {
359
- currentInstance = this;
360
- }
375
+ synchronized (MixerManager.class) { currentInstance = this; }
361
376
  }
362
-
377
+
363
378
  /**
364
- * 清理资源,防止内存泄漏
379
+ * cleanup method to release resources
365
380
  */
366
381
  public void cleanup() {
367
382
  try {
368
383
  for (String viewId : cachedMixedViews.keySet()) {
369
384
  View view = cachedMixedViews.get(viewId);
370
385
  if (view instanceof MixerView) {
371
- MixerView mixerView = (MixerView) view;
386
+ MixerView mixerView = (MixerView)view;
372
387
  mixerView.setBitmapCaptureCallback(null);
373
388
  }
374
389
  }
375
-
390
+
376
391
  mixedViewLayout.clear();
377
392
  viewIdToStreamId.clear();
378
393
  pendingCallbacks.clear();
379
-
394
+
380
395
  synchronized (MixerManager.class) {
381
396
  if (currentInstance == this) {
382
397
  currentInstance = null;
383
398
  }
384
399
  }
385
-
400
+
386
401
  pusher = null;
387
402
  } catch (Exception e) {
388
403
  // Ignore
389
404
  }
390
405
  }
391
-
406
+
392
407
  // Callback interface for bitmap capture
393
408
  public interface BitmapCaptureCallback {
394
409
  void onBitmapCaptured(Bitmap bitmap);
@@ -150,6 +150,7 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
150
150
  @"y" : viewInfo[@"y"] ?: @(0),
151
151
  @"width" : viewInfo[@"width"] ?: @(0),
152
152
  @"height" : viewInfo[@"height"] ?: @(0),
153
+ @"alpha" : viewInfo[@"alpha"] ?: @(1.0),
153
154
  @"zOrder" : viewInfo[@"zOrder"] ?: @(1),
154
155
  @"renderMode" : viewInfo[@"renderMode"] ?: @(0),
155
156
  @"streamId" : @(videoStreamId)
@@ -164,6 +165,7 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
164
165
  videoLayout.width = [viewInfo[@"width"] floatValue];
165
166
  videoLayout.height = [viewInfo[@"height"] floatValue];
166
167
  videoLayout.zOrder = [viewInfo[@"zOrder"] intValue];
168
+ videoLayout.alpha = [viewInfo[@"alpha"] floatValue] ?: 1.0;
167
169
  videoLayout.renderMode = [viewInfo[@"renderMode"] intValue];
168
170
  description.mixVideoStreams = @[ videoLayout ];
169
171
  [self.pusher.getMixerManager updateStreamMixDescription:description];
@@ -173,6 +175,19 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
173
175
 
174
176
  if ([view isKindOfClass:[VeLiveMixerUIView class]]) {
175
177
  [VeLiveMixerHelper setupCallbackForMixerView:view streamId:videoStreamId];
178
+
179
+ // 延迟执行捕获,确保视图布局完成
180
+ dispatch_after(
181
+ dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)),
182
+ dispatch_get_main_queue(), ^{
183
+ @try {
184
+ if (view && view.bitmapCaptureCallback) {
185
+ [view performCaptureWithTrigger:@"addView"];
186
+ }
187
+ } @catch (NSException *exception) {
188
+ // Ignore
189
+ }
190
+ });
176
191
  } else {
177
192
  [self.pendingCallbacks setObject:@(videoStreamId) forKey:viewId];
178
193
  }
@@ -202,6 +217,8 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
202
217
  forKey:@"height"];
203
218
  [updatedLayout setObject:(viewInfo[@"zOrder"] ?: layout[@"zOrder"])
204
219
  forKey:@"zOrder"];
220
+ [updatedLayout setObject:(viewInfo[@"alpha"] ?: layout[@"alpha"])
221
+ forKey:@"alpha"];
205
222
  [updatedLayout setObject:(viewInfo[@"renderMode"] ?: layout[@"renderMode"])
206
223
  forKey:@"renderMode"];
207
224
 
@@ -213,6 +230,7 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
213
230
  videoLayout.y = [updatedLayout[@"y"] floatValue];
214
231
  videoLayout.width = [updatedLayout[@"width"] floatValue];
215
232
  videoLayout.height = [updatedLayout[@"height"] floatValue];
233
+ videoLayout.alpha = [updatedLayout[@"alpha"] floatValue];
216
234
  videoLayout.zOrder = [updatedLayout[@"zOrder"] intValue];
217
235
  videoLayout.renderMode = [updatedLayout[@"renderMode"] intValue];
218
236
  description.mixVideoStreams = @[ videoLayout ];
@@ -220,9 +238,20 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
220
238
 
221
239
  [self.mixedViewLayout setObject:updatedLayout forKey:viewId];
222
240
 
241
+ // 延迟执行捕获,确保属性更新完成
223
242
  VeLiveMixerUIView *mixerView =
224
243
  [[VeLiveMixerHelper cachedMixedViews] objectForKey:viewId];
225
- [mixerView performCaptureWithTrigger:@"update"];
244
+ if ([mixerView isKindOfClass:[VeLiveMixerUIView class]]) {
245
+ dispatch_after(
246
+ dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)),
247
+ dispatch_get_main_queue(), ^{
248
+ @try {
249
+ [mixerView performCaptureWithTrigger:@"update"];
250
+ } @catch (NSException *exception) {
251
+ // Ignore
252
+ }
253
+ });
254
+ }
226
255
 
227
256
  return YES;
228
257
  } @catch (NSException *exception) {
@@ -293,7 +322,7 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
293
322
  mixerView.bitmapCaptureCallback = callback;
294
323
 
295
324
  dispatch_after(
296
- dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)),
325
+ dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)),
297
326
  dispatch_get_main_queue(), ^{
298
327
  @try {
299
328
  if (mixerView && mixerView.bitmapCaptureCallback) {