@byteplus/react-native-live-push 1.1.3-rc.2 โ 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.
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerManager.java +161 -141
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerView.java +9 -1
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/TextureMgr.java +3 -3
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/YuvHelper.java +16 -5
- package/ios/VeLiveMixerHelper.m +222 -164
- package/ios/VeLiveMixerView.m +120 -112
- package/lib/commonjs/index.js +14 -1374
- package/lib/commonjs/typescript/core/keytype.d.ts +1 -0
- package/lib/module/index.js +15 -1375
- package/lib/module/typescript/core/keytype.d.ts +1 -0
- package/lib/typescript/core/keytype.d.ts +1 -0
- package/package.json +1 -1
package/ios/VeLiveMixerView.m
CHANGED
|
@@ -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;
|
|
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])
|
|
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
|
-
|
|
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
|
|
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 {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
- (void)
|
|
188
|
-
|
|
189
|
-
|
|
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)
|
|
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 =
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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 &&
|
|
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(
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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 =
|
|
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)
|
|
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 =
|
|
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 =
|
|
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
|
|
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(
|
|
426
|
-
|
|
427
|
-
|
|
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 =
|
|
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
|
|
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)
|
|
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
|
|