@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.
@@ -7,10 +7,10 @@
7
7
 
8
8
  #import "VeLiveMixerView.h"
9
9
  #import "VeLiveMixerHelper.h"
10
- #import <UIKit/UIKit.h>
11
10
  #import <AVFoundation/AVFoundation.h>
12
11
  #import <CoreMedia/CoreMedia.h>
13
12
  #import <CoreVideo/CoreVideo.h>
13
+ #import <UIKit/UIKit.h>
14
14
 
15
15
  @interface VeLiveMixerUIView ()
16
16
 
@@ -60,13 +60,11 @@ static const int LOW_CHANGE_THRESHOLD = 2;
60
60
 
61
61
  - (void)setupUIView {
62
62
  // Reference VeLivePushView.m settings, but keep our mixed view features
63
- self.clipsToBounds = YES; // Changed to YES, consistent with VeLivePushView
63
+ self.clipsToBounds = YES; // Changed to YES, consistent with VeLivePushView
64
64
  self.userInteractionEnabled = YES;
65
-
65
+
66
66
  // Set default background color to transparent, allowing subviews to display
67
67
  self.backgroundColor = [UIColor clearColor];
68
-
69
- NSLog(@"[VeLiveMixerView] ๐ŸŽจ setupUIView completed (clipsToBounds=YES, like VeLivePushView)");
70
68
  }
71
69
 
72
70
  - (void)initializeCapture {
@@ -77,15 +75,15 @@ static const int LOW_CHANGE_THRESHOLD = 2;
77
75
  _mixHeight = 0.0f;
78
76
  _mixZOrder = 0;
79
77
  _mixRenderMode = 0;
80
-
78
+
81
79
  _internalCaptureMode = @"onchange";
82
80
  _internalCaptureFramerate = 30.0f;
83
81
  _internalAutoSensitivity = 5.0f;
84
-
82
+
85
83
  _isCapturing = NO;
86
84
  _isDestroyed = NO;
87
85
  _lastCaptureTime = 0;
88
-
86
+
89
87
  // Auto mode state
90
88
  _changeCount = 0;
91
89
  _windowStartTime = 0;
@@ -99,8 +97,9 @@ static const int LOW_CHANGE_THRESHOLD = 2;
99
97
  }
100
98
 
101
99
  - (void)setCaptureMode:(NSString *)mode {
102
- if ([mode isEqualToString:self.internalCaptureMode]) return;
103
-
100
+ if ([mode isEqualToString:self.internalCaptureMode])
101
+ return;
102
+
104
103
  [self stopCapture];
105
104
  _internalCaptureMode = mode;
106
105
  [self startCapture];
@@ -129,18 +128,15 @@ static const int LOW_CHANGE_THRESHOLD = 2;
129
128
  if (!viewId) {
130
129
  return;
131
130
  }
132
-
133
- NSLog(@"[VeLiveMixerView] ๐Ÿ“ setViewId: %@", viewId);
134
-
131
+
135
132
  // Set viewId
136
133
  _viewId = [viewId copy];
137
-
134
+
138
135
  // Register to global cache - Align with Android's onAttachedToWindow
139
136
  NSMutableDictionary *cachedViews = [VeLiveMixerHelper cachedMixedViews];
140
137
  if (cachedViews) {
141
138
  [cachedViews setObject:self forKey:viewId];
142
- NSLog(@"[VeLiveMixerView] โœ… Registered to cachedMixedViews: %@", viewId);
143
-
139
+
144
140
  // Notify MixerHelper view is ready, check for pending callbacks
145
141
  [VeLiveMixerHelper onViewReady:viewId mixerView:self];
146
142
  }
@@ -148,7 +144,8 @@ static const int LOW_CHANGE_THRESHOLD = 2;
148
144
 
149
145
  #pragma mark - Property setters for React Native props - Align with Android
150
146
 
151
- // React Native property setter - Corresponds to VeLiveMixerViewManager.m properties
147
+ // React Native property setter - Corresponds to VeLiveMixerViewManager.m
148
+ // properties
152
149
  - (void)setX:(NSNumber *)x {
153
150
  _x = x;
154
151
  _mixX = [x floatValue];
@@ -181,18 +178,31 @@ static const int LOW_CHANGE_THRESHOLD = 2;
181
178
 
182
179
  #pragma mark - Internal setters for mix configuration - Internal use
183
180
 
184
- - (void)setMixX:(float)x { _mixX = x; }
185
- - (void)setMixY:(float)y { _mixY = y; }
186
- - (void)setMixWidth:(float)width { _mixWidth = width; }
187
- - (void)setMixHeight:(float)height { _mixHeight = height; }
188
- - (void)setMixZOrder:(int)zOrder { _mixZOrder = zOrder; }
189
- - (void)setMixRenderMode:(int)renderMode { _mixRenderMode = renderMode; }
181
+ - (void)setMixX:(float)x {
182
+ _mixX = x;
183
+ }
184
+ - (void)setMixY:(float)y {
185
+ _mixY = y;
186
+ }
187
+ - (void)setMixWidth:(float)width {
188
+ _mixWidth = width;
189
+ }
190
+ - (void)setMixHeight:(float)height {
191
+ _mixHeight = height;
192
+ }
193
+ - (void)setMixZOrder:(int)zOrder {
194
+ _mixZOrder = zOrder;
195
+ }
196
+ - (void)setMixRenderMode:(int)renderMode {
197
+ _mixRenderMode = renderMode;
198
+ }
190
199
 
191
200
  #pragma mark - Capture Methods - Completely align with Android
192
201
 
193
202
  - (void)startCapture {
194
- if (self.isDestroyed) return;
195
-
203
+ if (self.isDestroyed)
204
+ return;
205
+
196
206
  if ([self.internalCaptureMode isEqualToString:@"onchange"]) {
197
207
  [self startOnChangeCapture];
198
208
  } else if ([self.internalCaptureMode isEqualToString:@"realtime"]) {
@@ -215,28 +225,31 @@ static const int LOW_CHANGE_THRESHOLD = 2;
215
225
 
216
226
  - (void)startRealtimeCapture {
217
227
  long interval = (long)(1000.0f / self.internalCaptureFramerate);
218
- self.captureTimer = [NSTimer scheduledTimerWithTimeInterval:interval/1000.0
219
- target:self
220
- selector:@selector(realtimeCapture)
221
- userInfo:nil
222
- repeats:YES];
228
+ self.captureTimer =
229
+ [NSTimer scheduledTimerWithTimeInterval:interval / 1000.0
230
+ target:self
231
+ selector:@selector(realtimeCapture)
232
+ userInfo:nil
233
+ repeats:YES];
223
234
  }
224
235
 
225
236
  - (void)realtimeCapture {
226
- if (!self.isDestroyed && [self.internalCaptureMode isEqualToString:@"realtime"]) {
237
+ if (!self.isDestroyed &&
238
+ [self.internalCaptureMode isEqualToString:@"realtime"]) {
227
239
  @autoreleasepool {
228
240
  [self performCapture:@"realtime"];
229
-
241
+
230
242
  // Every 5 realtime captures, perform background memory cleanup
231
243
  static int captureCount = 0;
232
244
  captureCount++;
233
245
  if (captureCount % 5 == 0) {
234
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
235
- NSLog(@"[VeLiveMixerView] ๐Ÿงน Performing background memory cleanup after %d captures", captureCount);
236
- [[NSURLCache sharedURLCache] removeAllCachedResponses];
237
- [[NSURLCache sharedURLCache] setMemoryCapacity:0];
238
- [[NSURLCache sharedURLCache] setMemoryCapacity:10 * 1024 * 1024]; // 10MB
239
- });
246
+ dispatch_async(
247
+ dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
248
+ [[NSURLCache sharedURLCache] removeAllCachedResponses];
249
+ [[NSURLCache sharedURLCache] setMemoryCapacity:0];
250
+ [[NSURLCache sharedURLCache]
251
+ setMemoryCapacity:10 * 1024 * 1024]; // 10MB
252
+ });
240
253
  }
241
254
  }
242
255
  }
@@ -263,10 +276,10 @@ static const int LOW_CHANGE_THRESHOLD = 2;
263
276
  if (!self.isInRealtimeMode) {
264
277
  [self performCapture:@"auto_onchange"];
265
278
  }
266
-
279
+
267
280
  // Count changes for auto mode
268
281
  self.changeCount++;
269
-
282
+
270
283
  CFTimeInterval currentTime = CACurrentMediaTime();
271
284
  if (currentTime - self.windowStartTime >= AUTO_WINDOW_SECONDS) {
272
285
  [self evaluateAutoMode];
@@ -279,10 +292,11 @@ static const int LOW_CHANGE_THRESHOLD = 2;
279
292
  - (void)evaluateAutoMode {
280
293
  float changesPerSecond = self.changeCount / AUTO_WINDOW_SECONDS;
281
294
  float threshold = self.internalAutoSensitivity;
282
-
283
- BOOL shouldBeRealtime = changesPerSecond > (HIGH_CHANGE_THRESHOLD / threshold);
295
+
296
+ BOOL shouldBeRealtime =
297
+ changesPerSecond > (HIGH_CHANGE_THRESHOLD / threshold);
284
298
  BOOL shouldBeOnChange = changesPerSecond < (LOW_CHANGE_THRESHOLD / threshold);
285
-
299
+
286
300
  if (shouldBeRealtime && !self.isInRealtimeMode) {
287
301
  [self switchToRealtimeMode];
288
302
  } else if (shouldBeOnChange && self.isInRealtimeMode) {
@@ -304,17 +318,18 @@ static const int LOW_CHANGE_THRESHOLD = 2;
304
318
  #pragma mark - Core Capture Logic - Align with Android's performCapture
305
319
 
306
320
  - (void)performCapture:(NSString *)trigger {
307
- if (self.isCapturing || self.isDestroyed) return;
308
-
321
+ if (self.isCapturing || self.isDestroyed)
322
+ return;
323
+
309
324
  // Throttle captures to prevent excessive calls
310
325
  CFTimeInterval currentTime = CACurrentMediaTime();
311
- if (currentTime - self.lastCaptureTime < 1.0/60.0) { // Max 60fps
326
+ if (currentTime - self.lastCaptureTime < 1.0 / 60.0) { // Max 60fps
312
327
  return;
313
328
  }
314
329
  self.lastCaptureTime = currentTime;
315
-
330
+
316
331
  self.isCapturing = YES;
317
-
332
+
318
333
  @try {
319
334
  UIImage *bitmap = [self createBitmap];
320
335
  if (bitmap) {
@@ -327,44 +342,45 @@ static const int LOW_CHANGE_THRESHOLD = 2;
327
342
 
328
343
  - (UIImage *)createBitmap {
329
344
  CGSize viewSize = self.bounds.size;
330
-
345
+
331
346
  // Check for valid bounds
332
347
  if (viewSize.width <= 0 || viewSize.height <= 0) {
333
348
  return nil;
334
349
  }
335
-
350
+
336
351
  // Limit maximum image dimensions to prevent memory issues
337
352
  CGFloat maxDimension = 1920.0; // Max 1920px on either side
338
353
  CGFloat scale = [UIScreen mainScreen].scale;
339
-
354
+
340
355
  // Calculate actual pixel dimensions
341
356
  CGFloat pixelWidth = viewSize.width * scale;
342
357
  CGFloat pixelHeight = viewSize.height * scale;
343
-
358
+
344
359
  // Scale down if too large
345
360
  if (pixelWidth > maxDimension || pixelHeight > maxDimension) {
346
- CGFloat scaleDown = MIN(maxDimension / pixelWidth, maxDimension / pixelHeight);
361
+ CGFloat scaleDown =
362
+ MIN(maxDimension / pixelWidth, maxDimension / pixelHeight);
347
363
  scale = scale * scaleDown;
348
364
  }
349
-
365
+
350
366
  // Further limit scale on very large views
351
367
  if (viewSize.width * viewSize.height > 1000000) { // > 1M points
352
368
  scale = MIN(scale, 1.0);
353
369
  }
354
-
370
+
355
371
  @autoreleasepool {
356
372
  UIGraphicsBeginImageContextWithOptions(viewSize, NO, scale);
357
-
373
+
358
374
  CGContextRef context = UIGraphicsGetCurrentContext();
359
375
  if (!context) {
360
376
  UIGraphicsEndImageContext();
361
377
  return nil;
362
378
  }
363
-
379
+
364
380
  [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:NO];
365
381
  UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
366
382
  UIGraphicsEndImageContext();
367
-
383
+
368
384
  return image;
369
385
  }
370
386
  }
@@ -374,59 +390,63 @@ static const int LOW_CHANGE_THRESHOLD = 2;
374
390
  if (!bitmap || bitmap.size.width <= 0 || bitmap.size.height <= 0) {
375
391
  return;
376
392
  }
377
-
393
+
378
394
  // Check bitmap memory size and skip if too large
379
- CGFloat bitmapMemoryMB = (bitmap.size.width * bitmap.size.height * 4.0) / (1024.0 * 1024.0);
395
+ CGFloat bitmapMemoryMB =
396
+ (bitmap.size.width * bitmap.size.height * 4.0) / (1024.0 * 1024.0);
380
397
  if (bitmapMemoryMB > 50.0) { // Skip bitmaps larger than 50MB
381
398
  return;
382
399
  }
383
-
400
+
384
401
  if (self.bitmapCaptureCallback) {
385
402
  @try {
386
403
  [self.bitmapCaptureCallback onBitmapCaptured:bitmap];
387
404
  } @catch (NSException *exception) {
388
405
  if (self.bitmapCaptureCallback) {
389
- [self.bitmapCaptureCallback onCaptureError:[NSString stringWithFormat:@"Callback error: %@", exception.reason]];
406
+ [self.bitmapCaptureCallback
407
+ onCaptureError:[NSString stringWithFormat:@"Callback error: %@",
408
+ exception.reason]];
390
409
  }
391
410
  }
392
411
  }
393
-
412
+
394
413
  if (self.onBitmapCapture) {
395
414
  @autoreleasepool {
396
415
  NSDictionary *event = @{
397
- @"trigger": trigger ?: @"unknown",
398
- @"success": @(YES),
399
- @"x": @(self.mixX),
400
- @"y": @(self.mixY),
401
- @"width": @(self.mixWidth),
402
- @"height": @(self.mixHeight),
403
- @"zOrder": @(self.mixZOrder),
404
- @"renderMode": @(self.mixRenderMode),
405
- @"bitmapWidth": @(bitmap.size.width),
406
- @"bitmapHeight": @(bitmap.size.height)
416
+ @"trigger" : trigger ?: @"unknown",
417
+ @"success" : @(YES),
418
+ @"x" : @(self.mixX),
419
+ @"y" : @(self.mixY),
420
+ @"width" : @(self.mixWidth),
421
+ @"height" : @(self.mixHeight),
422
+ @"zOrder" : @(self.mixZOrder),
423
+ @"renderMode" : @(self.mixRenderMode),
424
+ @"bitmapWidth" : @(bitmap.size.width),
425
+ @"bitmapHeight" : @(bitmap.size.height)
407
426
  };
408
427
  self.onBitmapCapture(event);
409
428
  }
410
429
  }
411
-
430
+
412
431
  // Clean up old bitmap immediately
413
432
  if (self.lastBitmap) {
414
433
  self.lastBitmap = nil;
415
434
  }
416
-
435
+
417
436
  // For realtime mode, don't keep bitmap reference to reduce memory usage
418
437
  if ([trigger isEqualToString:@"realtime"]) {
419
438
  // Bitmap will be auto-released at autoreleasepool end
420
-
439
+
421
440
  // Force memory cleanup every 10 realtime captures
422
441
  static int realtimeCount = 0;
423
442
  realtimeCount++;
424
443
  if (realtimeCount % 10 == 0) {
425
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
426
- @autoreleasepool {
427
- [[NSURLCache sharedURLCache] removeAllCachedResponses];
428
- }
429
- });
444
+ dispatch_async(
445
+ dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
446
+ @autoreleasepool {
447
+ [[NSURLCache sharedURLCache] removeAllCachedResponses];
448
+ }
449
+ });
430
450
  }
431
451
  } else {
432
452
  self.lastBitmap = bitmap;
@@ -449,18 +469,14 @@ static const int LOW_CHANGE_THRESHOLD = 2;
449
469
  #pragma mark - Cleanup - Align with Android
450
470
 
451
471
  - (void)cleanup {
452
- NSLog(@"[VeLiveMixerView] ๐Ÿงน Starting cleanup for viewId: %@", self.viewId);
453
-
454
472
  self.isDestroyed = YES;
455
473
  [self stopCapture];
456
-
474
+
457
475
  // Clean up bitmap cache
458
476
  self.lastBitmap = nil;
459
-
477
+
460
478
  // Clean up callback references, avoid circular references
461
479
  self.bitmapCaptureCallback = nil;
462
-
463
- NSLog(@"[VeLiveMixerView] โœ… Cleanup completed for viewId: %@", self.viewId);
464
480
  }
465
481
 
466
482
  - (void)dealloc {
@@ -469,55 +485,53 @@ static const int LOW_CHANGE_THRESHOLD = 2;
469
485
  NSMutableDictionary *cachedViews = [VeLiveMixerHelper cachedMixedViews];
470
486
  if (cachedViews) {
471
487
  [cachedViews removeObjectForKey:self.viewId];
472
- NSLog(@"[VeLiveMixerView] โ™ป๏ธ Removed from cachedMixedViews: %@", self.viewId);
473
488
  }
474
489
  }
475
-
476
- NSLog(@"[VeLiveMixerView] ๐Ÿ—‘๏ธ Deallocated: %@", self.viewId);
477
490
  }
478
491
 
479
492
  #pragma mark - View Conversion Methods
480
493
 
481
494
  - (UIImage *)snapshotIncludeSubviews {
482
495
  CGSize viewSize = self.bounds.size;
483
-
496
+
484
497
  // Check for valid bounds
485
498
  if (viewSize.width <= 0 || viewSize.height <= 0) {
486
499
  return nil;
487
500
  }
488
-
501
+
489
502
  // Limit maximum image dimensions to prevent memory issues
490
503
  CGFloat maxDimension = 1920.0; // Max 1920px on either side
491
504
  CGFloat scale = [UIScreen mainScreen].scale;
492
-
505
+
493
506
  // Calculate actual pixel dimensions
494
507
  CGFloat pixelWidth = viewSize.width * scale;
495
508
  CGFloat pixelHeight = viewSize.height * scale;
496
-
509
+
497
510
  // Scale down if too large
498
511
  if (pixelWidth > maxDimension || pixelHeight > maxDimension) {
499
- CGFloat scaleDown = MIN(maxDimension / pixelWidth, maxDimension / pixelHeight);
512
+ CGFloat scaleDown =
513
+ MIN(maxDimension / pixelWidth, maxDimension / pixelHeight);
500
514
  scale = scale * scaleDown;
501
515
  }
502
-
516
+
503
517
  // Further limit scale on very large views
504
518
  if (viewSize.width * viewSize.height > 1000000) { // > 1M points
505
519
  scale = MIN(scale, 1.0);
506
520
  }
507
-
521
+
508
522
  @autoreleasepool {
509
523
  UIGraphicsBeginImageContextWithOptions(viewSize, NO, scale);
510
-
524
+
511
525
  CGContextRef context = UIGraphicsGetCurrentContext();
512
526
  if (!context) {
513
527
  UIGraphicsEndImageContext();
514
528
  return nil;
515
529
  }
516
-
530
+
517
531
  [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:NO];
518
532
  UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
519
533
  UIGraphicsEndImageContext();
520
-
534
+
521
535
  return image;
522
536
  }
523
537
  }
@@ -534,17 +548,15 @@ static const int LOW_CHANGE_THRESHOLD = 2;
534
548
 
535
549
  #pragma mark - React Native Child View Support - Focus on RN subview management
536
550
 
537
- // React Native subview insertion - This is the main method called by RN framework
551
+ // React Native subview insertion - This is the main method called by RN
552
+ // framework
538
553
  - (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex {
539
- NSLog(@"[VeLiveMixerView] ๐Ÿ“ฑ insertReactSubview: %@ at index: %ld", subview.class, (long)atIndex);
540
-
541
554
  // Process directly on main thread because React Native ensures thread safety
542
555
  [super insertSubview:subview atIndex:atIndex];
543
556
  [self setSubViewAutoLayout:subview];
544
557
  }
545
558
 
546
559
  - (void)removeReactSubview:(UIView *)subview {
547
- NSLog(@"[VeLiveMixerView] ๐Ÿ—‘๏ธ removeReactSubview: %@", subview.class);
548
560
  [subview removeFromSuperview];
549
561
  }
550
562
 
@@ -554,11 +566,9 @@ static const int LOW_CHANGE_THRESHOLD = 2;
554
566
 
555
567
  // Set Auto Layout constraints - Ensure subview fills parent view
556
568
  - (void)setSubViewAutoLayout:(UIView *)subview {
557
- NSLog(@"[VeLiveMixerView] ๐Ÿ“ setSubViewAutoLayout for: %@", subview.class);
558
-
559
569
  // Disable automatic conversion, use constraints layout
560
570
  subview.translatesAutoresizingMaskIntoConstraints = NO;
561
-
571
+
562
572
  // Set four-side constraints, let subview fill parent view
563
573
  [NSLayoutConstraint activateConstraints:@[
564
574
  [subview.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
@@ -566,15 +576,14 @@ static const int LOW_CHANGE_THRESHOLD = 2;
566
576
  [subview.topAnchor constraintEqualToAnchor:self.topAnchor],
567
577
  [subview.bottomAnchor constraintEqualToAnchor:self.bottomAnchor]
568
578
  ]];
569
-
570
- NSLog(@"[VeLiveMixerView] โœ… Auto Layout constraints applied for subview");
571
579
  }
572
580
 
573
581
  // Override layoutSubviews to ensure correct subview layout
574
582
  - (void)layoutSubviews {
575
583
  [super layoutSubviews];
576
- if (self.isDestroyed) return;
577
-
584
+ if (self.isDestroyed)
585
+ return;
586
+
578
587
  // Original capture logic
579
588
  if ([self.internalCaptureMode isEqualToString:@"onchange"]) {
580
589
  [self performCapture:@"onchange"];
@@ -585,7 +594,6 @@ static const int LOW_CHANGE_THRESHOLD = 2;
585
594
 
586
595
  // Ensure UIView can correctly display background color and subviews
587
596
  - (void)setBackgroundColor:(UIColor *)backgroundColor {
588
- NSLog(@"[VeLiveMixerView] ๐ŸŽจ setBackgroundColor: %@", backgroundColor);
589
597
  [super setBackgroundColor:backgroundColor];
590
598
  }
591
599