@byteplus/react-native-live-push 1.1.3-rc.3 → 1.1.4-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.
- package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushModule.java +2 -13
- package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushPackage.java +13 -16
- package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushView.java +0 -16
- package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushViewManager.java +2 -7
- package/lib/commonjs/index.js +2126 -2925
- package/lib/module/index.js +2128 -2922
- package/lib/typescript/codegen/android/api.d.ts +121 -1
- package/lib/typescript/codegen/ios/api.d.ts +28 -1
- package/lib/typescript/codegen/pack/api.d.ts +133 -1
- package/lib/typescript/core/api.d.ts +2 -17
- package/lib/typescript/core/keytype.d.ts +0 -15
- package/lib/typescript/index.d.ts +0 -1
- package/package.json +1 -1
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerManager.java +0 -397
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerView.java +0 -423
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerViewManager.java +0 -79
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/TextureMgr.java +0 -168
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/YuvHelper.java +0 -165
- package/ios/VeLiveMixerHelper.h +0 -44
- package/ios/VeLiveMixerHelper.m +0 -591
- package/ios/VeLiveMixerView.h +0 -69
- package/ios/VeLiveMixerView.m +0 -592
- package/ios/VeLiveMixerViewManager.m +0 -92
- package/lib/commonjs/typescript/android/index.d.ts +0 -47
- package/lib/commonjs/typescript/codegen/android/api.d.ts +0 -1527
- package/lib/commonjs/typescript/codegen/android/callback.d.ts +0 -91
- package/lib/commonjs/typescript/codegen/android/errorcode.d.ts +0 -26
- package/lib/commonjs/typescript/codegen/android/index.d.ts +0 -5
- package/lib/commonjs/typescript/codegen/android/keytype.d.ts +0 -846
- package/lib/commonjs/typescript/codegen/android/types.d.ts +0 -33
- package/lib/commonjs/typescript/codegen/ios/api.d.ts +0 -222
- package/lib/commonjs/typescript/codegen/ios/callback.d.ts +0 -80
- package/lib/commonjs/typescript/codegen/ios/errorcode.d.ts +0 -54
- package/lib/commonjs/typescript/codegen/ios/external.d.ts +0 -1
- package/lib/commonjs/typescript/codegen/ios/index.d.ts +0 -6
- package/lib/commonjs/typescript/codegen/ios/keytype.d.ts +0 -460
- package/lib/commonjs/typescript/codegen/ios/types.d.ts +0 -46
- package/lib/commonjs/typescript/codegen/pack/api.d.ts +0 -1835
- package/lib/commonjs/typescript/codegen/pack/callback.d.ts +0 -400
- package/lib/commonjs/typescript/codegen/pack/errorcode.d.ts +0 -35
- package/lib/commonjs/typescript/codegen/pack/index.d.ts +0 -5
- package/lib/commonjs/typescript/codegen/pack/keytype.d.ts +0 -1392
- package/lib/commonjs/typescript/codegen/pack/types.d.ts +0 -68
- package/lib/commonjs/typescript/codegen/type-shim.d.ts +0 -6
- package/lib/commonjs/typescript/component.d.ts +0 -15
- package/lib/commonjs/typescript/core/api.d.ts +0 -17
- package/lib/commonjs/typescript/core/callback.d.ts +0 -2
- package/lib/commonjs/typescript/core/env.d.ts +0 -29
- package/lib/commonjs/typescript/core/errorcode.d.ts +0 -2
- package/lib/commonjs/typescript/core/index.d.ts +0 -6
- package/lib/commonjs/typescript/core/keytype.d.ts +0 -17
- package/lib/commonjs/typescript/core/mixer.d.ts +0 -26
- package/lib/commonjs/typescript/core/pusher.d.ts +0 -16
- package/lib/commonjs/typescript/index.d.ts +0 -3
- package/lib/commonjs/typescript/ios/extends.d.ts +0 -41
- package/lib/commonjs/typescript/platforms/android/extends.d.ts +0 -8
- package/lib/commonjs/typescript/platforms/android/helper.d.ts +0 -8
- package/lib/commonjs/typescript/platforms/android/mixer.d.ts +0 -8
- package/lib/commonjs/typescript/platforms/ios/extends.d.ts +0 -17
- package/lib/commonjs/typescript/platforms/ios/helper.d.ts +0 -8
- package/lib/commonjs/typescript/platforms/ios/mixer.d.ts +0 -9
- package/lib/commonjs/typescript/runtime.d.ts +0 -1
- package/lib/commonjs/typescript/view/MixView.d.ts +0 -52
- package/lib/commonjs/typescript/view/VeImageView.d.ts +0 -19
- package/lib/commonjs/typescript/view/VeTextView.d.ts +0 -7
- package/lib/commonjs/typescript/view/VeView.d.ts +0 -7
- package/lib/commonjs/typescript/view/VeWebView.d.ts +0 -7
- package/lib/commonjs/typescript/view/index.d.ts +0 -5
- package/lib/module/typescript/android/index.d.ts +0 -47
- package/lib/module/typescript/codegen/android/api.d.ts +0 -1527
- package/lib/module/typescript/codegen/android/callback.d.ts +0 -91
- package/lib/module/typescript/codegen/android/errorcode.d.ts +0 -26
- package/lib/module/typescript/codegen/android/index.d.ts +0 -5
- package/lib/module/typescript/codegen/android/keytype.d.ts +0 -846
- package/lib/module/typescript/codegen/android/types.d.ts +0 -33
- package/lib/module/typescript/codegen/ios/api.d.ts +0 -222
- package/lib/module/typescript/codegen/ios/callback.d.ts +0 -80
- package/lib/module/typescript/codegen/ios/errorcode.d.ts +0 -54
- package/lib/module/typescript/codegen/ios/external.d.ts +0 -1
- package/lib/module/typescript/codegen/ios/index.d.ts +0 -6
- package/lib/module/typescript/codegen/ios/keytype.d.ts +0 -460
- package/lib/module/typescript/codegen/ios/types.d.ts +0 -46
- package/lib/module/typescript/codegen/pack/api.d.ts +0 -1835
- package/lib/module/typescript/codegen/pack/callback.d.ts +0 -400
- package/lib/module/typescript/codegen/pack/errorcode.d.ts +0 -35
- package/lib/module/typescript/codegen/pack/index.d.ts +0 -5
- package/lib/module/typescript/codegen/pack/keytype.d.ts +0 -1392
- package/lib/module/typescript/codegen/pack/types.d.ts +0 -68
- package/lib/module/typescript/codegen/type-shim.d.ts +0 -6
- package/lib/module/typescript/component.d.ts +0 -15
- package/lib/module/typescript/core/api.d.ts +0 -17
- package/lib/module/typescript/core/callback.d.ts +0 -2
- package/lib/module/typescript/core/env.d.ts +0 -29
- package/lib/module/typescript/core/errorcode.d.ts +0 -2
- package/lib/module/typescript/core/index.d.ts +0 -6
- package/lib/module/typescript/core/keytype.d.ts +0 -17
- package/lib/module/typescript/core/mixer.d.ts +0 -26
- package/lib/module/typescript/core/pusher.d.ts +0 -16
- package/lib/module/typescript/index.d.ts +0 -3
- package/lib/module/typescript/ios/extends.d.ts +0 -41
- package/lib/module/typescript/platforms/android/extends.d.ts +0 -8
- package/lib/module/typescript/platforms/android/helper.d.ts +0 -8
- package/lib/module/typescript/platforms/android/mixer.d.ts +0 -8
- package/lib/module/typescript/platforms/ios/extends.d.ts +0 -17
- package/lib/module/typescript/platforms/ios/helper.d.ts +0 -8
- package/lib/module/typescript/platforms/ios/mixer.d.ts +0 -9
- package/lib/module/typescript/runtime.d.ts +0 -1
- package/lib/module/typescript/view/MixView.d.ts +0 -52
- package/lib/module/typescript/view/VeImageView.d.ts +0 -19
- package/lib/module/typescript/view/VeTextView.d.ts +0 -7
- package/lib/module/typescript/view/VeView.d.ts +0 -7
- package/lib/module/typescript/view/VeWebView.d.ts +0 -7
- package/lib/module/typescript/view/index.d.ts +0 -5
- package/lib/typescript/core/mixer.d.ts +0 -26
- package/lib/typescript/platforms/android/extends.d.ts +0 -8
- package/lib/typescript/platforms/android/mixer.d.ts +0 -8
- package/lib/typescript/platforms/ios/mixer.d.ts +0 -9
- package/lib/typescript/view/MixView.d.ts +0 -52
- package/lib/typescript/view/VeImageView.d.ts +0 -19
- package/lib/typescript/view/VeTextView.d.ts +0 -7
- package/lib/typescript/view/VeView.d.ts +0 -7
- package/lib/typescript/view/VeWebView.d.ts +0 -7
- package/lib/typescript/view/index.d.ts +0 -5
package/ios/VeLiveMixerView.m
DELETED
|
@@ -1,592 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// VeLiveMixerView.m
|
|
3
|
-
// react-native-live-push
|
|
4
|
-
//
|
|
5
|
-
// Created by ByteDance on 2024/12/09.
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
#import "VeLiveMixerView.h"
|
|
9
|
-
#import "VeLiveMixerHelper.h"
|
|
10
|
-
#import <UIKit/UIKit.h>
|
|
11
|
-
#import <AVFoundation/AVFoundation.h>
|
|
12
|
-
#import <CoreMedia/CoreMedia.h>
|
|
13
|
-
#import <CoreVideo/CoreVideo.h>
|
|
14
|
-
|
|
15
|
-
@interface VeLiveMixerUIView ()
|
|
16
|
-
|
|
17
|
-
// Mix configuration - Align with Android
|
|
18
|
-
@property(nonatomic, assign) float mixX;
|
|
19
|
-
@property(nonatomic, assign) float mixY;
|
|
20
|
-
@property(nonatomic, assign) float mixWidth;
|
|
21
|
-
@property(nonatomic, assign) float mixHeight;
|
|
22
|
-
@property(nonatomic, assign) int mixZOrder;
|
|
23
|
-
@property(nonatomic, assign) int mixRenderMode;
|
|
24
|
-
|
|
25
|
-
// Capture configuration - Internal properties
|
|
26
|
-
@property(nonatomic, strong) NSString *internalCaptureMode;
|
|
27
|
-
@property(nonatomic, assign) float internalCaptureFramerate;
|
|
28
|
-
@property(nonatomic, assign) float internalAutoSensitivity;
|
|
29
|
-
|
|
30
|
-
// Capture state - Align with Android
|
|
31
|
-
@property(nonatomic, strong) NSTimer *captureTimer;
|
|
32
|
-
@property(nonatomic, assign) BOOL isCapturing;
|
|
33
|
-
@property(nonatomic, assign) BOOL isDestroyed;
|
|
34
|
-
@property(nonatomic, assign) CFTimeInterval lastCaptureTime;
|
|
35
|
-
|
|
36
|
-
// Performance optimization - Align with Android
|
|
37
|
-
@property(nonatomic, strong) UIImage *lastBitmap;
|
|
38
|
-
|
|
39
|
-
// Auto mode state - Align with Android
|
|
40
|
-
@property(nonatomic, assign) int changeCount;
|
|
41
|
-
@property(nonatomic, assign) CFTimeInterval windowStartTime;
|
|
42
|
-
@property(nonatomic, assign) BOOL isInRealtimeMode;
|
|
43
|
-
|
|
44
|
-
@end
|
|
45
|
-
|
|
46
|
-
@implementation VeLiveMixerUIView
|
|
47
|
-
|
|
48
|
-
static const CFTimeInterval AUTO_WINDOW_SECONDS = 2.0; // 2 second window
|
|
49
|
-
static const int HIGH_CHANGE_THRESHOLD = 10;
|
|
50
|
-
static const int LOW_CHANGE_THRESHOLD = 2;
|
|
51
|
-
|
|
52
|
-
- (instancetype)initWithFrame:(CGRect)frame {
|
|
53
|
-
self = [super initWithFrame:frame];
|
|
54
|
-
if (self) {
|
|
55
|
-
[self initializeCapture];
|
|
56
|
-
[self setupUIView];
|
|
57
|
-
}
|
|
58
|
-
return self;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
- (void)setupUIView {
|
|
62
|
-
// Reference VeLivePushView.m settings, but keep our mixed view features
|
|
63
|
-
self.clipsToBounds = YES; // Changed to YES, consistent with VeLivePushView
|
|
64
|
-
self.userInteractionEnabled = YES;
|
|
65
|
-
|
|
66
|
-
// Set default background color to transparent, allowing subviews to display
|
|
67
|
-
self.backgroundColor = [UIColor clearColor];
|
|
68
|
-
|
|
69
|
-
NSLog(@"[VeLiveMixerView] 🎨 setupUIView completed (clipsToBounds=YES, like VeLivePushView)");
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
- (void)initializeCapture {
|
|
73
|
-
// Initialize defaults - Completely align with Android
|
|
74
|
-
_mixX = 0.0f;
|
|
75
|
-
_mixY = 0.0f;
|
|
76
|
-
_mixWidth = 0.0f;
|
|
77
|
-
_mixHeight = 0.0f;
|
|
78
|
-
_mixZOrder = 0;
|
|
79
|
-
_mixRenderMode = 0;
|
|
80
|
-
|
|
81
|
-
_internalCaptureMode = @"onchange";
|
|
82
|
-
_internalCaptureFramerate = 30.0f;
|
|
83
|
-
_internalAutoSensitivity = 5.0f;
|
|
84
|
-
|
|
85
|
-
_isCapturing = NO;
|
|
86
|
-
_isDestroyed = NO;
|
|
87
|
-
_lastCaptureTime = 0;
|
|
88
|
-
|
|
89
|
-
// Auto mode state
|
|
90
|
-
_changeCount = 0;
|
|
91
|
-
_windowStartTime = 0;
|
|
92
|
-
_isInRealtimeMode = NO;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
#pragma mark - Property Getters/Setters - Align with React Native props
|
|
96
|
-
|
|
97
|
-
- (NSString *)captureMode {
|
|
98
|
-
return self.internalCaptureMode;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
- (void)setCaptureMode:(NSString *)mode {
|
|
102
|
-
if ([mode isEqualToString:self.internalCaptureMode]) return;
|
|
103
|
-
|
|
104
|
-
[self stopCapture];
|
|
105
|
-
_internalCaptureMode = mode;
|
|
106
|
-
[self startCapture];
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
- (NSNumber *)captureFramerate {
|
|
110
|
-
return @(self.internalCaptureFramerate);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
- (void)setCaptureFramerate:(NSNumber *)framerate {
|
|
114
|
-
_internalCaptureFramerate = MAX(1.0f, MIN(60.0f, [framerate floatValue]));
|
|
115
|
-
if ([self.internalCaptureMode isEqualToString:@"realtime"]) {
|
|
116
|
-
[self restartRealtimeCapture];
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
- (NSNumber *)autoSensitivity {
|
|
121
|
-
return @(self.internalAutoSensitivity);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
- (void)setAutoSensitivity:(NSNumber *)sensitivity {
|
|
125
|
-
_internalAutoSensitivity = MAX(1.0f, MIN(10.0f, [sensitivity floatValue]));
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
- (void)setViewId:(NSString *)viewId {
|
|
129
|
-
if (!viewId) {
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
NSLog(@"[VeLiveMixerView] 📝 setViewId: %@", viewId);
|
|
134
|
-
|
|
135
|
-
// Set viewId
|
|
136
|
-
_viewId = [viewId copy];
|
|
137
|
-
|
|
138
|
-
// Register to global cache - Align with Android's onAttachedToWindow
|
|
139
|
-
NSMutableDictionary *cachedViews = [VeLiveMixerHelper cachedMixedViews];
|
|
140
|
-
if (cachedViews) {
|
|
141
|
-
[cachedViews setObject:self forKey:viewId];
|
|
142
|
-
NSLog(@"[VeLiveMixerView] ✅ Registered to cachedMixedViews: %@", viewId);
|
|
143
|
-
|
|
144
|
-
// Notify MixerHelper view is ready, check for pending callbacks
|
|
145
|
-
[VeLiveMixerHelper onViewReady:viewId mixerView:self];
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
#pragma mark - Property setters for React Native props - Align with Android
|
|
150
|
-
|
|
151
|
-
// React Native property setter - Corresponds to VeLiveMixerViewManager.m properties
|
|
152
|
-
- (void)setX:(NSNumber *)x {
|
|
153
|
-
_x = x;
|
|
154
|
-
_mixX = [x floatValue];
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
- (void)setY:(NSNumber *)y {
|
|
158
|
-
_y = y;
|
|
159
|
-
_mixY = [y floatValue];
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
- (void)setWidth:(NSNumber *)width {
|
|
163
|
-
_width = width;
|
|
164
|
-
_mixWidth = [width floatValue];
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
- (void)setHeight:(NSNumber *)height {
|
|
168
|
-
_height = height;
|
|
169
|
-
_mixHeight = [height floatValue];
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
- (void)setZOrder:(NSNumber *)zOrder {
|
|
173
|
-
_zOrder = zOrder;
|
|
174
|
-
_mixZOrder = [zOrder intValue];
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
- (void)setRenderMode:(NSNumber *)renderMode {
|
|
178
|
-
_renderMode = renderMode;
|
|
179
|
-
_mixRenderMode = [renderMode intValue];
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
#pragma mark - Internal setters for mix configuration - Internal use
|
|
183
|
-
|
|
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; }
|
|
190
|
-
|
|
191
|
-
#pragma mark - Capture Methods - Completely align with Android
|
|
192
|
-
|
|
193
|
-
- (void)startCapture {
|
|
194
|
-
if (self.isDestroyed) return;
|
|
195
|
-
|
|
196
|
-
if ([self.internalCaptureMode isEqualToString:@"onchange"]) {
|
|
197
|
-
[self startOnChangeCapture];
|
|
198
|
-
} else if ([self.internalCaptureMode isEqualToString:@"realtime"]) {
|
|
199
|
-
[self startRealtimeCapture];
|
|
200
|
-
} else if ([self.internalCaptureMode isEqualToString:@"auto"]) {
|
|
201
|
-
[self startAutoCapture];
|
|
202
|
-
}
|
|
203
|
-
// manual mode doesn't auto-start
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
- (void)stopCapture {
|
|
207
|
-
[self.captureTimer invalidate];
|
|
208
|
-
self.captureTimer = nil;
|
|
209
|
-
self.isCapturing = NO;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
- (void)startOnChangeCapture {
|
|
213
|
-
// onchange mode triggers in layoutSubviews
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
- (void)startRealtimeCapture {
|
|
217
|
-
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];
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
- (void)realtimeCapture {
|
|
226
|
-
if (!self.isDestroyed && [self.internalCaptureMode isEqualToString:@"realtime"]) {
|
|
227
|
-
@autoreleasepool {
|
|
228
|
-
[self performCapture:@"realtime"];
|
|
229
|
-
|
|
230
|
-
// Every 5 realtime captures, perform background memory cleanup
|
|
231
|
-
static int captureCount = 0;
|
|
232
|
-
captureCount++;
|
|
233
|
-
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
|
-
});
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
- (void)restartRealtimeCapture {
|
|
246
|
-
if ([self.internalCaptureMode isEqualToString:@"realtime"]) {
|
|
247
|
-
[self stopCapture];
|
|
248
|
-
[self startRealtimeCapture];
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
- (void)startAutoCapture {
|
|
253
|
-
// Start with onchange mode
|
|
254
|
-
self.isInRealtimeMode = NO;
|
|
255
|
-
self.windowStartTime = CACurrentMediaTime();
|
|
256
|
-
self.changeCount = 0;
|
|
257
|
-
[self startOnChangeCapture];
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
#pragma mark - Layout Change Detection - Align with Android's onViewChanged
|
|
261
|
-
|
|
262
|
-
- (void)handleAutoModeChange {
|
|
263
|
-
if (!self.isInRealtimeMode) {
|
|
264
|
-
[self performCapture:@"auto_onchange"];
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Count changes for auto mode
|
|
268
|
-
self.changeCount++;
|
|
269
|
-
|
|
270
|
-
CFTimeInterval currentTime = CACurrentMediaTime();
|
|
271
|
-
if (currentTime - self.windowStartTime >= AUTO_WINDOW_SECONDS) {
|
|
272
|
-
[self evaluateAutoMode];
|
|
273
|
-
// Reset window
|
|
274
|
-
self.windowStartTime = currentTime;
|
|
275
|
-
self.changeCount = 0;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
- (void)evaluateAutoMode {
|
|
280
|
-
float changesPerSecond = self.changeCount / AUTO_WINDOW_SECONDS;
|
|
281
|
-
float threshold = self.internalAutoSensitivity;
|
|
282
|
-
|
|
283
|
-
BOOL shouldBeRealtime = changesPerSecond > (HIGH_CHANGE_THRESHOLD / threshold);
|
|
284
|
-
BOOL shouldBeOnChange = changesPerSecond < (LOW_CHANGE_THRESHOLD / threshold);
|
|
285
|
-
|
|
286
|
-
if (shouldBeRealtime && !self.isInRealtimeMode) {
|
|
287
|
-
[self switchToRealtimeMode];
|
|
288
|
-
} else if (shouldBeOnChange && self.isInRealtimeMode) {
|
|
289
|
-
[self switchToOnChangeMode];
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
- (void)switchToRealtimeMode {
|
|
294
|
-
self.isInRealtimeMode = YES;
|
|
295
|
-
[self startRealtimeCapture];
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
- (void)switchToOnChangeMode {
|
|
299
|
-
self.isInRealtimeMode = NO;
|
|
300
|
-
[self.captureTimer invalidate];
|
|
301
|
-
self.captureTimer = nil;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
#pragma mark - Core Capture Logic - Align with Android's performCapture
|
|
305
|
-
|
|
306
|
-
- (void)performCapture:(NSString *)trigger {
|
|
307
|
-
if (self.isCapturing || self.isDestroyed) return;
|
|
308
|
-
|
|
309
|
-
// Throttle captures to prevent excessive calls
|
|
310
|
-
CFTimeInterval currentTime = CACurrentMediaTime();
|
|
311
|
-
if (currentTime - self.lastCaptureTime < 1.0/60.0) { // Max 60fps
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
self.lastCaptureTime = currentTime;
|
|
315
|
-
|
|
316
|
-
self.isCapturing = YES;
|
|
317
|
-
|
|
318
|
-
@try {
|
|
319
|
-
UIImage *bitmap = [self createBitmap];
|
|
320
|
-
if (bitmap) {
|
|
321
|
-
[self processBitmap:bitmap trigger:trigger];
|
|
322
|
-
}
|
|
323
|
-
} @finally {
|
|
324
|
-
self.isCapturing = NO;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
- (UIImage *)createBitmap {
|
|
329
|
-
CGSize viewSize = self.bounds.size;
|
|
330
|
-
|
|
331
|
-
// Check for valid bounds
|
|
332
|
-
if (viewSize.width <= 0 || viewSize.height <= 0) {
|
|
333
|
-
return nil;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// Limit maximum image dimensions to prevent memory issues
|
|
337
|
-
CGFloat maxDimension = 1920.0; // Max 1920px on either side
|
|
338
|
-
CGFloat scale = [UIScreen mainScreen].scale;
|
|
339
|
-
|
|
340
|
-
// Calculate actual pixel dimensions
|
|
341
|
-
CGFloat pixelWidth = viewSize.width * scale;
|
|
342
|
-
CGFloat pixelHeight = viewSize.height * scale;
|
|
343
|
-
|
|
344
|
-
// Scale down if too large
|
|
345
|
-
if (pixelWidth > maxDimension || pixelHeight > maxDimension) {
|
|
346
|
-
CGFloat scaleDown = MIN(maxDimension / pixelWidth, maxDimension / pixelHeight);
|
|
347
|
-
scale = scale * scaleDown;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// Further limit scale on very large views
|
|
351
|
-
if (viewSize.width * viewSize.height > 1000000) { // > 1M points
|
|
352
|
-
scale = MIN(scale, 1.0);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
@autoreleasepool {
|
|
356
|
-
UIGraphicsBeginImageContextWithOptions(viewSize, NO, scale);
|
|
357
|
-
|
|
358
|
-
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
359
|
-
if (!context) {
|
|
360
|
-
UIGraphicsEndImageContext();
|
|
361
|
-
return nil;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:NO];
|
|
365
|
-
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
|
366
|
-
UIGraphicsEndImageContext();
|
|
367
|
-
|
|
368
|
-
return image;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
- (void)processBitmap:(UIImage *)bitmap trigger:(NSString *)trigger {
|
|
373
|
-
@autoreleasepool {
|
|
374
|
-
if (!bitmap || bitmap.size.width <= 0 || bitmap.size.height <= 0) {
|
|
375
|
-
return;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// Check bitmap memory size and skip if too large
|
|
379
|
-
CGFloat bitmapMemoryMB = (bitmap.size.width * bitmap.size.height * 4.0) / (1024.0 * 1024.0);
|
|
380
|
-
if (bitmapMemoryMB > 50.0) { // Skip bitmaps larger than 50MB
|
|
381
|
-
return;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
if (self.bitmapCaptureCallback) {
|
|
385
|
-
@try {
|
|
386
|
-
[self.bitmapCaptureCallback onBitmapCaptured:bitmap];
|
|
387
|
-
} @catch (NSException *exception) {
|
|
388
|
-
if (self.bitmapCaptureCallback) {
|
|
389
|
-
[self.bitmapCaptureCallback onCaptureError:[NSString stringWithFormat:@"Callback error: %@", exception.reason]];
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
if (self.onBitmapCapture) {
|
|
395
|
-
@autoreleasepool {
|
|
396
|
-
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)
|
|
407
|
-
};
|
|
408
|
-
self.onBitmapCapture(event);
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
// Clean up old bitmap immediately
|
|
413
|
-
if (self.lastBitmap) {
|
|
414
|
-
self.lastBitmap = nil;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
// For realtime mode, don't keep bitmap reference to reduce memory usage
|
|
418
|
-
if ([trigger isEqualToString:@"realtime"]) {
|
|
419
|
-
// Bitmap will be auto-released at autoreleasepool end
|
|
420
|
-
|
|
421
|
-
// Force memory cleanup every 10 realtime captures
|
|
422
|
-
static int realtimeCount = 0;
|
|
423
|
-
realtimeCount++;
|
|
424
|
-
if (realtimeCount % 10 == 0) {
|
|
425
|
-
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
|
|
426
|
-
@autoreleasepool {
|
|
427
|
-
[[NSURLCache sharedURLCache] removeAllCachedResponses];
|
|
428
|
-
}
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
} else {
|
|
432
|
-
self.lastBitmap = bitmap;
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
#pragma mark - Public Methods - Align with Android interface
|
|
438
|
-
|
|
439
|
-
// Align with Android's performManualCapture
|
|
440
|
-
- (void)performCaptureWithTrigger:(NSString *)trigger {
|
|
441
|
-
[self performCapture:trigger];
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
// Align with Android's setBitmapCaptureCallback
|
|
445
|
-
- (void)setBitmapCaptureCallback:(id<VeLiveBitmapCaptureCallback>)callback {
|
|
446
|
-
_bitmapCaptureCallback = callback;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
#pragma mark - Cleanup - Align with Android
|
|
450
|
-
|
|
451
|
-
- (void)cleanup {
|
|
452
|
-
NSLog(@"[VeLiveMixerView] 🧹 Starting cleanup for viewId: %@", self.viewId);
|
|
453
|
-
|
|
454
|
-
self.isDestroyed = YES;
|
|
455
|
-
[self stopCapture];
|
|
456
|
-
|
|
457
|
-
// Clean up bitmap cache
|
|
458
|
-
self.lastBitmap = nil;
|
|
459
|
-
|
|
460
|
-
// Clean up callback references, avoid circular references
|
|
461
|
-
self.bitmapCaptureCallback = nil;
|
|
462
|
-
|
|
463
|
-
NSLog(@"[VeLiveMixerView] ✅ Cleanup completed for viewId: %@", self.viewId);
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
- (void)dealloc {
|
|
467
|
-
// Remove from global cache
|
|
468
|
-
if (self.viewId) {
|
|
469
|
-
NSMutableDictionary *cachedViews = [VeLiveMixerHelper cachedMixedViews];
|
|
470
|
-
if (cachedViews) {
|
|
471
|
-
[cachedViews removeObjectForKey:self.viewId];
|
|
472
|
-
NSLog(@"[VeLiveMixerView] ♻️ Removed from cachedMixedViews: %@", self.viewId);
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
NSLog(@"[VeLiveMixerView] 🗑️ Deallocated: %@", self.viewId);
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
#pragma mark - View Conversion Methods
|
|
480
|
-
|
|
481
|
-
- (UIImage *)snapshotIncludeSubviews {
|
|
482
|
-
CGSize viewSize = self.bounds.size;
|
|
483
|
-
|
|
484
|
-
// Check for valid bounds
|
|
485
|
-
if (viewSize.width <= 0 || viewSize.height <= 0) {
|
|
486
|
-
return nil;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
// Limit maximum image dimensions to prevent memory issues
|
|
490
|
-
CGFloat maxDimension = 1920.0; // Max 1920px on either side
|
|
491
|
-
CGFloat scale = [UIScreen mainScreen].scale;
|
|
492
|
-
|
|
493
|
-
// Calculate actual pixel dimensions
|
|
494
|
-
CGFloat pixelWidth = viewSize.width * scale;
|
|
495
|
-
CGFloat pixelHeight = viewSize.height * scale;
|
|
496
|
-
|
|
497
|
-
// Scale down if too large
|
|
498
|
-
if (pixelWidth > maxDimension || pixelHeight > maxDimension) {
|
|
499
|
-
CGFloat scaleDown = MIN(maxDimension / pixelWidth, maxDimension / pixelHeight);
|
|
500
|
-
scale = scale * scaleDown;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
// Further limit scale on very large views
|
|
504
|
-
if (viewSize.width * viewSize.height > 1000000) { // > 1M points
|
|
505
|
-
scale = MIN(scale, 1.0);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
@autoreleasepool {
|
|
509
|
-
UIGraphicsBeginImageContextWithOptions(viewSize, NO, scale);
|
|
510
|
-
|
|
511
|
-
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
512
|
-
if (!context) {
|
|
513
|
-
UIGraphicsEndImageContext();
|
|
514
|
-
return nil;
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:NO];
|
|
518
|
-
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
|
519
|
-
UIGraphicsEndImageContext();
|
|
520
|
-
|
|
521
|
-
return image;
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
- (CVPixelBufferRef)createPixelBuffer {
|
|
526
|
-
// Implement pixel buffer creation (corresponds to Android's ByteBuffer)
|
|
527
|
-
return NULL; // Temporary return NULL, implementation based on needs
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
- (CMSampleBufferRef)createSampleBuffer {
|
|
531
|
-
// Implement sample buffer creation (corresponds to Android's VideoFrame)
|
|
532
|
-
return NULL; // Temporary return NULL, implementation based on needs
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
#pragma mark - React Native Child View Support - Focus on RN subview management
|
|
536
|
-
|
|
537
|
-
// React Native subview insertion - This is the main method called by RN framework
|
|
538
|
-
- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex {
|
|
539
|
-
NSLog(@"[VeLiveMixerView] 📱 insertReactSubview: %@ at index: %ld", subview.class, (long)atIndex);
|
|
540
|
-
|
|
541
|
-
// Process directly on main thread because React Native ensures thread safety
|
|
542
|
-
[super insertSubview:subview atIndex:atIndex];
|
|
543
|
-
[self setSubViewAutoLayout:subview];
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
- (void)removeReactSubview:(UIView *)subview {
|
|
547
|
-
NSLog(@"[VeLiveMixerView] 🗑️ removeReactSubview: %@", subview.class);
|
|
548
|
-
[subview removeFromSuperview];
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
- (NSArray<UIView *> *)reactSubviews {
|
|
552
|
-
return [self subviews];
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
// Set Auto Layout constraints - Ensure subview fills parent view
|
|
556
|
-
- (void)setSubViewAutoLayout:(UIView *)subview {
|
|
557
|
-
NSLog(@"[VeLiveMixerView] 📐 setSubViewAutoLayout for: %@", subview.class);
|
|
558
|
-
|
|
559
|
-
// Disable automatic conversion, use constraints layout
|
|
560
|
-
subview.translatesAutoresizingMaskIntoConstraints = NO;
|
|
561
|
-
|
|
562
|
-
// Set four-side constraints, let subview fill parent view
|
|
563
|
-
[NSLayoutConstraint activateConstraints:@[
|
|
564
|
-
[subview.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
|
|
565
|
-
[subview.trailingAnchor constraintEqualToAnchor:self.trailingAnchor],
|
|
566
|
-
[subview.topAnchor constraintEqualToAnchor:self.topAnchor],
|
|
567
|
-
[subview.bottomAnchor constraintEqualToAnchor:self.bottomAnchor]
|
|
568
|
-
]];
|
|
569
|
-
|
|
570
|
-
NSLog(@"[VeLiveMixerView] ✅ Auto Layout constraints applied for subview");
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
// Override layoutSubviews to ensure correct subview layout
|
|
574
|
-
- (void)layoutSubviews {
|
|
575
|
-
[super layoutSubviews];
|
|
576
|
-
if (self.isDestroyed) return;
|
|
577
|
-
|
|
578
|
-
// Original capture logic
|
|
579
|
-
if ([self.internalCaptureMode isEqualToString:@"onchange"]) {
|
|
580
|
-
[self performCapture:@"onchange"];
|
|
581
|
-
} else if ([self.internalCaptureMode isEqualToString:@"auto"]) {
|
|
582
|
-
[self handleAutoModeChange];
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
// Ensure UIView can correctly display background color and subviews
|
|
587
|
-
- (void)setBackgroundColor:(UIColor *)backgroundColor {
|
|
588
|
-
NSLog(@"[VeLiveMixerView] 🎨 setBackgroundColor: %@", backgroundColor);
|
|
589
|
-
[super setBackgroundColor:backgroundColor];
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
@end
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// VeLiveMixerViewManager.m
|
|
3
|
-
// react-native-live-push
|
|
4
|
-
//
|
|
5
|
-
// Created to manage VeLiveMixerView React Native component
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
#import "VeLiveMixerView.h"
|
|
9
|
-
#import <Foundation/Foundation.h>
|
|
10
|
-
#import <React/RCTComponent.h>
|
|
11
|
-
#import <React/RCTViewManager.h>
|
|
12
|
-
#import <UIKit/UIKit.h>
|
|
13
|
-
|
|
14
|
-
@interface VeLiveMixerViewManager : RCTViewManager
|
|
15
|
-
@end
|
|
16
|
-
|
|
17
|
-
@implementation VeLiveMixerViewManager
|
|
18
|
-
|
|
19
|
-
+ (BOOL)requiresMainQueueSetup {
|
|
20
|
-
return YES;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
RCT_EXPORT_MODULE(VeLiveMixView)
|
|
24
|
-
|
|
25
|
-
- (VeLiveMixerUIView *)view {
|
|
26
|
-
VeLiveMixerUIView *view = [[VeLiveMixerUIView alloc] init];
|
|
27
|
-
view.accessibilityLabel = @"VeLiveMixerUIView";
|
|
28
|
-
return view;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// 导出视图ID属性 - 使用自定义属性处理
|
|
32
|
-
RCT_CUSTOM_VIEW_PROPERTY(viewId, NSString, VeLiveMixerUIView) {
|
|
33
|
-
if (json == nil) {
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
NSString *viewId = [RCTConvert NSString:json];
|
|
38
|
-
[view setViewId:viewId];
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// 导出混合配置属性 - 与Android保持一致的属性名
|
|
42
|
-
RCT_CUSTOM_VIEW_PROPERTY(x, NSNumber, VeLiveMixerUIView) {
|
|
43
|
-
NSNumber *x = [RCTConvert NSNumber:json];
|
|
44
|
-
[view setX:x];
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
RCT_CUSTOM_VIEW_PROPERTY(y, NSNumber, VeLiveMixerUIView) {
|
|
48
|
-
NSNumber *y = [RCTConvert NSNumber:json];
|
|
49
|
-
[view setY:y];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
RCT_CUSTOM_VIEW_PROPERTY(width, NSNumber, VeLiveMixerUIView) {
|
|
53
|
-
NSNumber *width = [RCTConvert NSNumber:json];
|
|
54
|
-
[view setWidth:width];
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
RCT_CUSTOM_VIEW_PROPERTY(height, NSNumber, VeLiveMixerUIView) {
|
|
58
|
-
NSNumber *height = [RCTConvert NSNumber:json];
|
|
59
|
-
[view setHeight:height];
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
RCT_CUSTOM_VIEW_PROPERTY(zOrder, NSNumber, VeLiveMixerUIView) {
|
|
63
|
-
NSNumber *zOrder = [RCTConvert NSNumber:json];
|
|
64
|
-
[view setZOrder:zOrder];
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
RCT_CUSTOM_VIEW_PROPERTY(renderMode, NSNumber, VeLiveMixerUIView) {
|
|
68
|
-
NSNumber *renderMode = [RCTConvert NSNumber:json];
|
|
69
|
-
[view setRenderMode:renderMode];
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// 导出捕获配置属性
|
|
73
|
-
RCT_CUSTOM_VIEW_PROPERTY(captureMode, NSString, VeLiveMixerUIView) {
|
|
74
|
-
NSString *captureMode = [RCTConvert NSString:json];
|
|
75
|
-
if (captureMode != nil) {
|
|
76
|
-
[view setCaptureMode:captureMode];
|
|
77
|
-
} else {
|
|
78
|
-
[view setCaptureMode:@"onchange"];
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
RCT_CUSTOM_VIEW_PROPERTY(captureFramerate, NSNumber, VeLiveMixerUIView) {
|
|
83
|
-
NSNumber *framerate = [RCTConvert NSNumber:json];
|
|
84
|
-
[view setCaptureFramerate:framerate];
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
RCT_CUSTOM_VIEW_PROPERTY(autoSensitivity, NSNumber, VeLiveMixerUIView) {
|
|
88
|
-
NSNumber *sensitivity = [RCTConvert NSNumber:json];
|
|
89
|
-
[view setAutoSensitivity:sensitivity];
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
@end
|