@byteplus/react-native-live-push 1.1.3-rc.0 → 1.1.3-rc.2
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 +13 -2
- package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushPackage.java +16 -13
- package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushView.java +16 -0
- package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushViewManager.java +7 -2
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerManager.java +392 -0
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerView.java +415 -0
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerViewManager.java +79 -0
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/TextureMgr.java +168 -0
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/YuvHelper.java +154 -0
- package/ios/VeLiveMixerHelper.h +44 -0
- package/ios/VeLiveMixerHelper.m +562 -0
- package/ios/VeLiveMixerView.h +69 -0
- package/ios/VeLiveMixerView.m +592 -0
- package/ios/VeLiveMixerViewManager.m +92 -0
- package/lib/commonjs/index.js +1779 -980
- package/lib/commonjs/typescript/android/index.d.ts +47 -0
- package/lib/commonjs/typescript/codegen/android/api.d.ts +1527 -0
- package/lib/commonjs/typescript/codegen/android/callback.d.ts +91 -0
- package/lib/commonjs/typescript/codegen/android/errorcode.d.ts +26 -0
- package/lib/commonjs/typescript/codegen/android/index.d.ts +5 -0
- package/lib/commonjs/typescript/codegen/android/keytype.d.ts +846 -0
- package/lib/commonjs/typescript/codegen/android/types.d.ts +33 -0
- package/lib/commonjs/typescript/codegen/ios/api.d.ts +222 -0
- package/lib/commonjs/typescript/codegen/ios/callback.d.ts +80 -0
- package/lib/commonjs/typescript/codegen/ios/errorcode.d.ts +54 -0
- package/lib/commonjs/typescript/codegen/ios/external.d.ts +1 -0
- package/lib/commonjs/typescript/codegen/ios/index.d.ts +6 -0
- package/lib/commonjs/typescript/codegen/ios/keytype.d.ts +460 -0
- package/lib/commonjs/typescript/codegen/ios/types.d.ts +46 -0
- package/lib/commonjs/typescript/codegen/pack/api.d.ts +1835 -0
- package/lib/commonjs/typescript/codegen/pack/callback.d.ts +400 -0
- package/lib/commonjs/typescript/codegen/pack/errorcode.d.ts +35 -0
- package/lib/commonjs/typescript/codegen/pack/index.d.ts +5 -0
- package/lib/commonjs/typescript/codegen/pack/keytype.d.ts +1392 -0
- package/lib/commonjs/typescript/codegen/pack/types.d.ts +68 -0
- package/lib/commonjs/typescript/codegen/type-shim.d.ts +6 -0
- package/lib/commonjs/typescript/component.d.ts +15 -0
- package/lib/commonjs/typescript/core/api.d.ts +17 -0
- package/lib/commonjs/typescript/core/callback.d.ts +2 -0
- package/lib/commonjs/typescript/core/env.d.ts +29 -0
- package/lib/commonjs/typescript/core/errorcode.d.ts +2 -0
- package/lib/commonjs/typescript/core/index.d.ts +6 -0
- package/lib/commonjs/typescript/core/keytype.d.ts +17 -0
- package/lib/commonjs/typescript/core/mixer.d.ts +26 -0
- package/lib/commonjs/typescript/core/pusher.d.ts +16 -0
- package/lib/commonjs/typescript/index.d.ts +3 -0
- package/lib/commonjs/typescript/ios/extends.d.ts +41 -0
- package/lib/commonjs/typescript/platforms/android/extends.d.ts +8 -0
- package/lib/commonjs/typescript/platforms/android/helper.d.ts +8 -0
- package/lib/commonjs/typescript/platforms/android/mixer.d.ts +8 -0
- package/lib/commonjs/typescript/platforms/ios/extends.d.ts +17 -0
- package/lib/commonjs/typescript/platforms/ios/helper.d.ts +8 -0
- package/lib/commonjs/typescript/platforms/ios/mixer.d.ts +9 -0
- package/lib/commonjs/typescript/runtime.d.ts +1 -0
- package/lib/commonjs/typescript/view/MixView.d.ts +52 -0
- package/lib/commonjs/typescript/view/VeImageView.d.ts +19 -0
- package/lib/commonjs/typescript/view/VeTextView.d.ts +7 -0
- package/lib/commonjs/typescript/view/VeView.d.ts +7 -0
- package/lib/commonjs/typescript/view/VeWebView.d.ts +7 -0
- package/lib/commonjs/typescript/view/index.d.ts +5 -0
- package/lib/module/index.js +1776 -982
- package/lib/module/typescript/android/index.d.ts +47 -0
- package/lib/module/typescript/codegen/android/api.d.ts +1527 -0
- package/lib/module/typescript/codegen/android/callback.d.ts +91 -0
- package/lib/module/typescript/codegen/android/errorcode.d.ts +26 -0
- package/lib/module/typescript/codegen/android/index.d.ts +5 -0
- package/lib/module/typescript/codegen/android/keytype.d.ts +846 -0
- package/lib/module/typescript/codegen/android/types.d.ts +33 -0
- package/lib/module/typescript/codegen/ios/api.d.ts +222 -0
- package/lib/module/typescript/codegen/ios/callback.d.ts +80 -0
- package/lib/module/typescript/codegen/ios/errorcode.d.ts +54 -0
- package/lib/module/typescript/codegen/ios/external.d.ts +1 -0
- package/lib/module/typescript/codegen/ios/index.d.ts +6 -0
- package/lib/module/typescript/codegen/ios/keytype.d.ts +460 -0
- package/lib/module/typescript/codegen/ios/types.d.ts +46 -0
- package/lib/module/typescript/codegen/pack/api.d.ts +1835 -0
- package/lib/module/typescript/codegen/pack/callback.d.ts +400 -0
- package/lib/module/typescript/codegen/pack/errorcode.d.ts +35 -0
- package/lib/module/typescript/codegen/pack/index.d.ts +5 -0
- package/lib/module/typescript/codegen/pack/keytype.d.ts +1392 -0
- package/lib/module/typescript/codegen/pack/types.d.ts +68 -0
- package/lib/module/typescript/codegen/type-shim.d.ts +6 -0
- package/lib/module/typescript/component.d.ts +15 -0
- package/lib/module/typescript/core/api.d.ts +17 -0
- package/lib/module/typescript/core/callback.d.ts +2 -0
- package/lib/module/typescript/core/env.d.ts +29 -0
- package/lib/module/typescript/core/errorcode.d.ts +2 -0
- package/lib/module/typescript/core/index.d.ts +6 -0
- package/lib/module/typescript/core/keytype.d.ts +17 -0
- package/lib/module/typescript/core/mixer.d.ts +26 -0
- package/lib/module/typescript/core/pusher.d.ts +16 -0
- package/lib/module/typescript/index.d.ts +3 -0
- package/lib/module/typescript/ios/extends.d.ts +41 -0
- package/lib/module/typescript/platforms/android/extends.d.ts +8 -0
- package/lib/module/typescript/platforms/android/helper.d.ts +8 -0
- package/lib/module/typescript/platforms/android/mixer.d.ts +8 -0
- package/lib/module/typescript/platforms/ios/extends.d.ts +17 -0
- package/lib/module/typescript/platforms/ios/helper.d.ts +8 -0
- package/lib/module/typescript/platforms/ios/mixer.d.ts +9 -0
- package/lib/module/typescript/runtime.d.ts +1 -0
- package/lib/module/typescript/view/MixView.d.ts +52 -0
- package/lib/module/typescript/view/VeImageView.d.ts +19 -0
- package/lib/module/typescript/view/VeTextView.d.ts +7 -0
- package/lib/module/typescript/view/VeView.d.ts +7 -0
- package/lib/module/typescript/view/VeWebView.d.ts +7 -0
- package/lib/module/typescript/view/index.d.ts +5 -0
- package/lib/typescript/codegen/android/api.d.ts +1 -121
- package/lib/typescript/codegen/ios/api.d.ts +1 -28
- package/lib/typescript/codegen/pack/api.d.ts +1 -133
- package/lib/typescript/core/api.d.ts +17 -2
- package/lib/typescript/core/keytype.d.ts +15 -0
- package/lib/typescript/core/mixer.d.ts +26 -0
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/platforms/android/extends.d.ts +8 -0
- package/lib/typescript/platforms/android/mixer.d.ts +8 -0
- package/lib/typescript/platforms/ios/mixer.d.ts +9 -0
- package/lib/typescript/view/MixView.d.ts +52 -0
- package/lib/typescript/view/VeImageView.d.ts +19 -0
- package/lib/typescript/view/VeTextView.d.ts +7 -0
- package/lib/typescript/view/VeView.d.ts +7 -0
- package/lib/typescript/view/VeWebView.d.ts +7 -0
- package/lib/typescript/view/index.d.ts +5 -0
- package/package.json +1 -1
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
//
|
|
2
|
+
// VeLiveMixerHelper.m
|
|
3
|
+
// react-native-live-push
|
|
4
|
+
//
|
|
5
|
+
// Created by ByteDance on 2024/12/09.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#import "VeLiveMixerHelper.h"
|
|
9
|
+
#include <objc/NSObjCRuntime.h>
|
|
10
|
+
#import <UIKit/UIKit.h>
|
|
11
|
+
#import <TTSDKLivePushRTS/TTSDKLivePushRTS.h>
|
|
12
|
+
#import <mach/mach.h>
|
|
13
|
+
#import <mach/task_info.h>
|
|
14
|
+
|
|
15
|
+
static NSString *TAG = @"VeLiveMixerHelper";
|
|
16
|
+
|
|
17
|
+
#pragma mark - Forward Declaration
|
|
18
|
+
|
|
19
|
+
@class VeLiveMixerBitmapCallback;
|
|
20
|
+
|
|
21
|
+
#pragma mark - VeLiveMixerHelper Implementation
|
|
22
|
+
|
|
23
|
+
@interface VeLiveMixerHelper ()
|
|
24
|
+
|
|
25
|
+
@property(nonatomic, strong) NSMutableDictionary<NSString *, NSDictionary *> *mixedViewLayout;
|
|
26
|
+
@property(nonatomic, strong) NSMutableDictionary<NSString *, NSNumber *> *viewIdToStreamId;
|
|
27
|
+
@property(nonatomic, strong) NSMutableDictionary<NSString *, NSNumber *> *pendingCallbacks;
|
|
28
|
+
@property(nonatomic, strong) NSMutableDictionary<NSString *, VeLiveMixerBitmapCallback *> *callbacks;
|
|
29
|
+
@property (nonatomic, strong) NSTimer *memoryMonitorTimer;
|
|
30
|
+
|
|
31
|
+
@end
|
|
32
|
+
|
|
33
|
+
#pragma mark - VeLiveMixerBitmapCallback Declaration
|
|
34
|
+
|
|
35
|
+
@interface VeLiveMixerBitmapCallback : NSObject <VeLiveBitmapCaptureCallback>
|
|
36
|
+
@property (nonatomic, assign) int streamId;
|
|
37
|
+
- (instancetype)initWithStreamId:(int)streamId;
|
|
38
|
+
@end
|
|
39
|
+
|
|
40
|
+
@implementation VeLiveMixerHelper
|
|
41
|
+
|
|
42
|
+
// 对齐Android的static cachedMixedViews
|
|
43
|
+
static NSMutableDictionary<NSString *, VeLiveMixerUIView *> *_cachedMixedViews = nil;
|
|
44
|
+
static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释放
|
|
45
|
+
|
|
46
|
+
+ (NSMutableDictionary<NSString *, VeLiveMixerUIView *> *)cachedMixedViews {
|
|
47
|
+
if (!_cachedMixedViews) {
|
|
48
|
+
_cachedMixedViews = [[NSMutableDictionary alloc] init];
|
|
49
|
+
}
|
|
50
|
+
return _cachedMixedViews;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
+ (void)setCachedMixedViews:(NSMutableDictionary<NSString *, VeLiveMixerUIView *> *)cachedMixedViews {
|
|
54
|
+
_cachedMixedViews = cachedMixedViews;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
- (instancetype)init {
|
|
58
|
+
self = [super init];
|
|
59
|
+
if (self) {
|
|
60
|
+
[self commonInit];
|
|
61
|
+
}
|
|
62
|
+
return self;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
- (instancetype)initWithPusher:(VeLivePusher *)pusher {
|
|
66
|
+
self = [super init];
|
|
67
|
+
if (self) {
|
|
68
|
+
_pusher = pusher;
|
|
69
|
+
[self commonInit];
|
|
70
|
+
[self startMemoryMonitoring];
|
|
71
|
+
}
|
|
72
|
+
return self;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
- (void)commonInit {
|
|
76
|
+
_mixedViewLayout = [[NSMutableDictionary alloc] init];
|
|
77
|
+
_viewIdToStreamId = [[NSMutableDictionary alloc] init];
|
|
78
|
+
_pendingCallbacks = [[NSMutableDictionary alloc] init];
|
|
79
|
+
_callbacks = [[NSMutableDictionary alloc] init];
|
|
80
|
+
|
|
81
|
+
currentInstance = self;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
#pragma mark - Lazy Loading Properties
|
|
85
|
+
|
|
86
|
+
- (NSMutableDictionary *)mixedViewLayout {
|
|
87
|
+
if (!_mixedViewLayout) {
|
|
88
|
+
_mixedViewLayout = [[NSMutableDictionary alloc] init];
|
|
89
|
+
}
|
|
90
|
+
return _mixedViewLayout;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
- (NSMutableDictionary *)viewIdToStreamId {
|
|
94
|
+
if (!_viewIdToStreamId) {
|
|
95
|
+
_viewIdToStreamId = [[NSMutableDictionary alloc] init];
|
|
96
|
+
}
|
|
97
|
+
return _viewIdToStreamId;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
- (NSMutableDictionary *)pendingCallbacks {
|
|
101
|
+
if (!_pendingCallbacks) {
|
|
102
|
+
_pendingCallbacks = [[NSMutableDictionary alloc] init];
|
|
103
|
+
}
|
|
104
|
+
return _pendingCallbacks;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
- (NSMutableDictionary *)callbacks {
|
|
108
|
+
if (!_callbacks) {
|
|
109
|
+
_callbacks = [[NSMutableDictionary alloc] init];
|
|
110
|
+
}
|
|
111
|
+
return _callbacks;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
#pragma mark - Public Methods
|
|
115
|
+
|
|
116
|
+
- (void)setPusher:(VeLivePusher *)pusher {
|
|
117
|
+
_pusher = pusher;
|
|
118
|
+
|
|
119
|
+
if (currentInstance != self) {
|
|
120
|
+
currentInstance = self;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
- (int)addView:(NSString *)viewId config:(NSDictionary *)viewInfo {
|
|
125
|
+
@try {
|
|
126
|
+
if (!self.pusher) {
|
|
127
|
+
return -1;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
VeLiveMixerUIView *view = [VeLiveMixerHelper cachedMixedViews][viewId];
|
|
131
|
+
if (![view isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
132
|
+
// View not ready, store pending callback
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
NSNumber *existingStreamId = [self.viewIdToStreamId objectForKey:viewId];
|
|
136
|
+
if(existingStreamId != nil) {
|
|
137
|
+
return [existingStreamId intValue];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
int videoStreamId = [[self.pusher getMixerManager] addVideoStream];
|
|
141
|
+
|
|
142
|
+
NSDictionary *layout = @{
|
|
143
|
+
@"x": viewInfo[@"x"] ?: @(0),
|
|
144
|
+
@"y": viewInfo[@"y"] ?: @(0),
|
|
145
|
+
@"width": viewInfo[@"width"] ?: @(0),
|
|
146
|
+
@"height": viewInfo[@"height"] ?: @(0),
|
|
147
|
+
@"zOrder": viewInfo[@"zOrder"] ?: @(1),
|
|
148
|
+
@"renderMode": viewInfo[@"renderMode"] ?: @(0),
|
|
149
|
+
@"streamId": @(videoStreamId)
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
VeLiveStreamMixDescription *description = [[VeLiveStreamMixDescription alloc] init];
|
|
153
|
+
VeLiveMixVideoLayout *videoLayout = [[VeLiveMixVideoLayout alloc] init];
|
|
154
|
+
videoLayout.streamId = videoStreamId;
|
|
155
|
+
videoLayout.x = [viewInfo[@"x"] floatValue];
|
|
156
|
+
videoLayout.y = [viewInfo[@"y"] floatValue];
|
|
157
|
+
videoLayout.width = [viewInfo[@"width"] floatValue];
|
|
158
|
+
videoLayout.height = [viewInfo[@"height"] floatValue];
|
|
159
|
+
videoLayout.zOrder = [viewInfo[@"zOrder"] intValue];
|
|
160
|
+
videoLayout.renderMode = [viewInfo[@"renderMode"] intValue];
|
|
161
|
+
description.mixVideoStreams = @[videoLayout];
|
|
162
|
+
[self.pusher.getMixerManager updateStreamMixDescription:description];
|
|
163
|
+
|
|
164
|
+
[self.mixedViewLayout setObject:layout forKey:viewId];
|
|
165
|
+
[self.viewIdToStreamId setObject:@(videoStreamId) forKey:viewId];
|
|
166
|
+
|
|
167
|
+
if ([view isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
168
|
+
[VeLiveMixerHelper setupCallbackForMixerView:view streamId:videoStreamId];
|
|
169
|
+
} else {
|
|
170
|
+
[self.pendingCallbacks setObject:@(videoStreamId) forKey:viewId];
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return videoStreamId;
|
|
174
|
+
} @catch (NSException *exception) {
|
|
175
|
+
return -1;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
- (BOOL)updateView:(NSString *)viewId config:(NSDictionary *)viewInfo {
|
|
180
|
+
@try {
|
|
181
|
+
NSDictionary *layout = [self.mixedViewLayout objectForKey:viewId];
|
|
182
|
+
if (!layout) {
|
|
183
|
+
return NO;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
NSNumber *streamIdNumber = [self.viewIdToStreamId objectForKey:viewId];
|
|
187
|
+
int videoStreamId = [streamIdNumber intValue];
|
|
188
|
+
|
|
189
|
+
NSMutableDictionary *updatedLayout = [layout mutableCopy];
|
|
190
|
+
[updatedLayout setObject:(viewInfo[@"x"] ?: layout[@"x"]) forKey:@"x"];
|
|
191
|
+
[updatedLayout setObject:(viewInfo[@"y"] ?: layout[@"y"]) forKey:@"y"];
|
|
192
|
+
[updatedLayout setObject:(viewInfo[@"width"] ?: layout[@"width"]) forKey:@"width"];
|
|
193
|
+
[updatedLayout setObject:(viewInfo[@"height"] ?: layout[@"height"]) forKey:@"height"];
|
|
194
|
+
[updatedLayout setObject:(viewInfo[@"zOrder"] ?: layout[@"zOrder"]) forKey:@"zOrder"];
|
|
195
|
+
[updatedLayout setObject:(viewInfo[@"renderMode"] ?: layout[@"renderMode"]) forKey:@"renderMode"];
|
|
196
|
+
|
|
197
|
+
VeLiveStreamMixDescription *description = [[VeLiveStreamMixDescription alloc] init];
|
|
198
|
+
VeLiveMixVideoLayout *videoLayout = [[VeLiveMixVideoLayout alloc] init];
|
|
199
|
+
videoLayout.streamId = videoStreamId;
|
|
200
|
+
videoLayout.x = [updatedLayout[@"x"] floatValue];
|
|
201
|
+
videoLayout.y = [updatedLayout[@"y"] floatValue];
|
|
202
|
+
videoLayout.width = [updatedLayout[@"width"] floatValue];
|
|
203
|
+
videoLayout.height = [updatedLayout[@"height"] floatValue];
|
|
204
|
+
videoLayout.zOrder = [updatedLayout[@"zOrder"] intValue];
|
|
205
|
+
videoLayout.renderMode = [updatedLayout[@"renderMode"] intValue];
|
|
206
|
+
description.mixVideoStreams = @[videoLayout];
|
|
207
|
+
[self.pusher.getMixerManager updateStreamMixDescription:description];
|
|
208
|
+
|
|
209
|
+
[self.mixedViewLayout setObject:updatedLayout forKey:viewId];
|
|
210
|
+
|
|
211
|
+
VeLiveMixerUIView *mixerView = [[VeLiveMixerHelper cachedMixedViews] objectForKey:viewId];
|
|
212
|
+
[mixerView performCaptureWithTrigger:@"update"];
|
|
213
|
+
|
|
214
|
+
return YES;
|
|
215
|
+
} @catch (NSException *exception) {
|
|
216
|
+
return NO;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
- (BOOL)removeView:(NSString *)viewId {
|
|
221
|
+
@try {
|
|
222
|
+
NSDictionary *layout = [self.mixedViewLayout objectForKey:viewId];
|
|
223
|
+
if (!layout) {
|
|
224
|
+
return NO;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
NSNumber *streamIdNumber = [self.viewIdToStreamId objectForKey:viewId];
|
|
228
|
+
if (streamIdNumber) {
|
|
229
|
+
int streamId = [streamIdNumber intValue];
|
|
230
|
+
[self.pusher.getMixerManager removeVideoStream:streamId];
|
|
231
|
+
|
|
232
|
+
NSString *callbackKey = [NSString stringWithFormat:@"%d", streamId];
|
|
233
|
+
[self.callbacks removeObjectForKey:callbackKey];
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
[self.viewIdToStreamId removeObjectForKey:viewId];
|
|
237
|
+
[self.pendingCallbacks removeObjectForKey:viewId];
|
|
238
|
+
|
|
239
|
+
VeLiveMixerUIView *view = [[VeLiveMixerHelper cachedMixedViews] objectForKey:viewId];
|
|
240
|
+
if ([view isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
241
|
+
view.bitmapCaptureCallback = nil;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
[self.mixedViewLayout removeObjectForKey:viewId];
|
|
245
|
+
|
|
246
|
+
return YES;
|
|
247
|
+
} @catch (NSException *exception) {
|
|
248
|
+
return NO;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
- (void)captureView:(NSString *)viewId {
|
|
253
|
+
VeLiveMixerUIView *view = [[VeLiveMixerHelper cachedMixedViews] objectForKey:viewId];
|
|
254
|
+
if ([view isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
255
|
+
[view performCaptureWithTrigger:@"manual"];
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
#pragma mark - Static Methods
|
|
260
|
+
|
|
261
|
+
+ (void)setupCallbackForMixerView:(VeLiveMixerUIView *)mixerView streamId:(int)streamId {
|
|
262
|
+
if (mixerView == nil) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
VeLiveMixerHelper *instance = [VeLiveMixerHelper findActiveMixerManager];
|
|
267
|
+
if (!instance) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
VeLiveMixerBitmapCallback *callback = [[VeLiveMixerBitmapCallback alloc] initWithStreamId:streamId];
|
|
272
|
+
|
|
273
|
+
NSString *callbackKey = [NSString stringWithFormat:@"%d", streamId];
|
|
274
|
+
[instance.callbacks setObject:callback forKey:callbackKey];
|
|
275
|
+
|
|
276
|
+
mixerView.bitmapCaptureCallback = callback;
|
|
277
|
+
|
|
278
|
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
279
|
+
@try {
|
|
280
|
+
if (mixerView && mixerView.bitmapCaptureCallback) {
|
|
281
|
+
VeLiveMixerHelper *instance = [VeLiveMixerHelper findActiveMixerManager];
|
|
282
|
+
if (instance && instance.pusher) {
|
|
283
|
+
@try {
|
|
284
|
+
NSString *viewId = mixerView.viewId;
|
|
285
|
+
NSDictionary *layout = [instance.mixedViewLayout objectForKey:viewId];
|
|
286
|
+
if (layout) {
|
|
287
|
+
VeLiveStreamMixDescription *description = [[VeLiveStreamMixDescription alloc] init];
|
|
288
|
+
VeLiveMixVideoLayout *videoLayout = [[VeLiveMixVideoLayout alloc] init];
|
|
289
|
+
videoLayout.streamId = streamId;
|
|
290
|
+
videoLayout.x = [layout[@"x"] floatValue];
|
|
291
|
+
videoLayout.y = [layout[@"y"] floatValue];
|
|
292
|
+
videoLayout.width = [layout[@"width"] floatValue];
|
|
293
|
+
videoLayout.height = [layout[@"height"] floatValue];
|
|
294
|
+
videoLayout.zOrder = [layout[@"zOrder"] intValue];
|
|
295
|
+
videoLayout.renderMode = [layout[@"renderMode"] intValue];
|
|
296
|
+
description.mixVideoStreams = @[videoLayout];
|
|
297
|
+
[instance.pusher.getMixerManager updateStreamMixDescription:description];
|
|
298
|
+
}
|
|
299
|
+
} @catch (NSException *e) {
|
|
300
|
+
// Ignore
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
[mixerView performCaptureWithTrigger:@"update"];
|
|
305
|
+
}
|
|
306
|
+
} @catch (NSException *exception) {
|
|
307
|
+
// Ignore
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
+ (void)sendBitmapToMixerStatic:(int)streamId bitmap:(UIImage *)bitmap {
|
|
313
|
+
VeLiveMixerHelper *instance = [VeLiveMixerHelper findActiveMixerManager];
|
|
314
|
+
if (instance && instance.pusher) {
|
|
315
|
+
[instance sendBitmapToMixer:streamId bitmap:bitmap];
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
+ (VeLiveMixerHelper *)findActiveMixerManager {
|
|
320
|
+
return currentInstance;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
+ (void)onViewReady:(NSString *)viewId mixerView:(VeLiveMixerUIView *)mixerView {
|
|
324
|
+
@try {
|
|
325
|
+
VeLiveMixerHelper *instance = [VeLiveMixerHelper findActiveMixerManager];
|
|
326
|
+
if (instance != nil) {
|
|
327
|
+
NSNumber *streamIdNumber = [instance.pendingCallbacks objectForKey:viewId];
|
|
328
|
+
if (streamIdNumber != nil) {
|
|
329
|
+
int streamId = [streamIdNumber intValue];
|
|
330
|
+
[instance.pendingCallbacks removeObjectForKey:viewId];
|
|
331
|
+
[VeLiveMixerHelper setupCallbackForMixerView:mixerView streamId:streamId];
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
} @catch (NSException *exception) {
|
|
335
|
+
// Ignore
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
- (void)cleanup {
|
|
340
|
+
[self stopMemoryMonitoring];
|
|
341
|
+
|
|
342
|
+
for (NSString *viewId in self.mixedViewLayout.allKeys) {
|
|
343
|
+
VeLiveMixerUIView *view = [[VeLiveMixerHelper cachedMixedViews] objectForKey:viewId];
|
|
344
|
+
if ([view isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
345
|
+
view.bitmapCaptureCallback = nil;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
[self.mixedViewLayout removeAllObjects];
|
|
350
|
+
[self.pendingCallbacks removeAllObjects];
|
|
351
|
+
[self.callbacks removeAllObjects];
|
|
352
|
+
|
|
353
|
+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
|
|
354
|
+
@autoreleasepool {
|
|
355
|
+
[[NSURLCache sharedURLCache] removeAllCachedResponses];
|
|
356
|
+
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
|
|
357
|
+
[[NSURLCache sharedURLCache] setMemoryCapacity:10 * 1024 * 1024];
|
|
358
|
+
|
|
359
|
+
[[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
|
360
|
+
|
|
361
|
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
362
|
+
// Final cleanup completed
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
- (void)dealloc {
|
|
369
|
+
[self cleanup];
|
|
370
|
+
|
|
371
|
+
if (currentInstance == self) {
|
|
372
|
+
currentInstance = nil;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
#pragma mark - Memory Monitoring
|
|
377
|
+
|
|
378
|
+
- (void)startMemoryMonitoring {
|
|
379
|
+
self.memoryMonitorTimer = [NSTimer scheduledTimerWithTimeInterval:30.0
|
|
380
|
+
target:self
|
|
381
|
+
selector:@selector(checkMemoryUsage)
|
|
382
|
+
userInfo:nil
|
|
383
|
+
repeats:YES];
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
- (void)stopMemoryMonitoring {
|
|
387
|
+
if (self.memoryMonitorTimer) {
|
|
388
|
+
[self.memoryMonitorTimer invalidate];
|
|
389
|
+
self.memoryMonitorTimer = nil;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
- (void)checkMemoryUsage {
|
|
394
|
+
@autoreleasepool {
|
|
395
|
+
struct task_basic_info info;
|
|
396
|
+
mach_msg_type_number_t size = TASK_BASIC_INFO_COUNT;
|
|
397
|
+
kern_return_t kerr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size);
|
|
398
|
+
|
|
399
|
+
if (kerr == KERN_SUCCESS) {
|
|
400
|
+
double memoryUsageMB = info.resident_size / 1024.0 / 1024.0;
|
|
401
|
+
|
|
402
|
+
if (memoryUsageMB > 200.0) {
|
|
403
|
+
[self performMemoryCleanup];
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
- (void)performMemoryCleanup {
|
|
410
|
+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
|
|
411
|
+
@autoreleasepool {
|
|
412
|
+
NSMutableDictionary *cachedViews = [VeLiveMixerHelper cachedMixedViews];
|
|
413
|
+
for (NSString *viewId in cachedViews.allKeys) {
|
|
414
|
+
VeLiveMixerUIView *view = [cachedViews objectForKey:viewId];
|
|
415
|
+
if ([view isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
416
|
+
if ([view.captureMode isEqualToString:@"realtime"]) {
|
|
417
|
+
[view stopCapture];
|
|
418
|
+
|
|
419
|
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
420
|
+
if (view && [cachedViews objectForKey:viewId] == view) {
|
|
421
|
+
[view startCapture];
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
[[NSURLCache sharedURLCache] removeAllCachedResponses];
|
|
429
|
+
[[NSURLCache sharedURLCache] setMemoryCapacity:5 * 1024 * 1024];
|
|
430
|
+
|
|
431
|
+
[[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
#pragma mark - Private Methods
|
|
437
|
+
|
|
438
|
+
- (void)sendBitmapToMixer:(int)streamId bitmap:(UIImage *)bitmap {
|
|
439
|
+
@autoreleasepool {
|
|
440
|
+
if (!self.pusher || !bitmap) {
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
CVPixelBufferRef pixelBuffer = NULL;
|
|
445
|
+
|
|
446
|
+
@try {
|
|
447
|
+
pixelBuffer = [self pixelBufferFromUIImage:bitmap];
|
|
448
|
+
if (!pixelBuffer) {
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
VeLiveVideoFrame *videoFrame = [[VeLiveVideoFrame alloc] init];
|
|
453
|
+
videoFrame.bufferType = VeLiveVideoBufferTypePixelBuffer;
|
|
454
|
+
videoFrame.pts = CMTimeMakeWithSeconds(CACurrentMediaTime(), 1000000000);
|
|
455
|
+
videoFrame.pixelBuffer = pixelBuffer;
|
|
456
|
+
|
|
457
|
+
__block CVPixelBufferRef bufferToRelease = pixelBuffer;
|
|
458
|
+
[videoFrame setReleaseCallback:^{
|
|
459
|
+
@autoreleasepool {
|
|
460
|
+
if (bufferToRelease) {
|
|
461
|
+
CVPixelBufferRelease(bufferToRelease);
|
|
462
|
+
bufferToRelease = NULL;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}];
|
|
466
|
+
|
|
467
|
+
[[self.pusher getMixerManager] sendCustomVideoFrame:videoFrame streamId:streamId];
|
|
468
|
+
|
|
469
|
+
pixelBuffer = NULL;
|
|
470
|
+
|
|
471
|
+
} @catch (NSException *exception) {
|
|
472
|
+
if (pixelBuffer) {
|
|
473
|
+
CVPixelBufferRelease(pixelBuffer);
|
|
474
|
+
pixelBuffer = NULL;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
#pragma mark - Helper Methods
|
|
481
|
+
|
|
482
|
+
- (CVPixelBufferRef)pixelBufferFromUIImage:(UIImage *)image {
|
|
483
|
+
if (!image) {
|
|
484
|
+
return NULL;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
CGImageRef cgImage = image.CGImage;
|
|
488
|
+
if (!cgImage) {
|
|
489
|
+
return NULL;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
CGFloat width = CGImageGetWidth(cgImage);
|
|
493
|
+
CGFloat height = CGImageGetHeight(cgImage);
|
|
494
|
+
|
|
495
|
+
NSDictionary *options = @{
|
|
496
|
+
(NSString *)kCVPixelBufferCGImageCompatibilityKey: @YES,
|
|
497
|
+
(NSString *)kCVPixelBufferCGBitmapContextCompatibilityKey: @YES,
|
|
498
|
+
(NSString *)kCVPixelBufferIOSurfacePropertiesKey: @{}
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
CVPixelBufferRef pixelBuffer = NULL;
|
|
502
|
+
CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault,
|
|
503
|
+
width, height,
|
|
504
|
+
kCVPixelFormatType_32BGRA,
|
|
505
|
+
(__bridge CFDictionaryRef)options,
|
|
506
|
+
&pixelBuffer);
|
|
507
|
+
|
|
508
|
+
if (status != kCVReturnSuccess || !pixelBuffer) {
|
|
509
|
+
return NULL;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
|
|
513
|
+
|
|
514
|
+
void *pixelData = CVPixelBufferGetBaseAddress(pixelBuffer);
|
|
515
|
+
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);
|
|
516
|
+
|
|
517
|
+
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
|
518
|
+
CGContextRef context = CGBitmapContextCreate(pixelData, width, height,
|
|
519
|
+
8, bytesPerRow, colorSpace,
|
|
520
|
+
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
|
|
521
|
+
|
|
522
|
+
if (!context) {
|
|
523
|
+
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
|
|
524
|
+
CVPixelBufferRelease(pixelBuffer);
|
|
525
|
+
CGColorSpaceRelease(colorSpace);
|
|
526
|
+
return NULL;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage);
|
|
530
|
+
|
|
531
|
+
CGContextRelease(context);
|
|
532
|
+
CGColorSpaceRelease(colorSpace);
|
|
533
|
+
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
|
|
534
|
+
|
|
535
|
+
return pixelBuffer;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
@end
|
|
539
|
+
|
|
540
|
+
#pragma mark - VeLiveMixerBitmapCallback Implementation
|
|
541
|
+
|
|
542
|
+
@implementation VeLiveMixerBitmapCallback
|
|
543
|
+
|
|
544
|
+
- (instancetype)initWithStreamId:(int)streamId {
|
|
545
|
+
self = [super init];
|
|
546
|
+
if (self) {
|
|
547
|
+
_streamId = streamId;
|
|
548
|
+
}
|
|
549
|
+
return self;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
- (void)onBitmapCaptured:(UIImage *)bitmap {
|
|
553
|
+
if (bitmap != nil) {
|
|
554
|
+
[VeLiveMixerHelper sendBitmapToMixerStatic:self.streamId bitmap:bitmap];
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
- (void)onCaptureError:(NSString *)error {
|
|
559
|
+
// Ignore
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
@end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//
|
|
2
|
+
// VeLiveMixerView.h
|
|
3
|
+
// react-native-live-push
|
|
4
|
+
//
|
|
5
|
+
// Created by ByteDance on 2025/06/09.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#import <Foundation/Foundation.h>
|
|
9
|
+
#import <UIKit/UIKit.h>
|
|
10
|
+
#import <React/RCTComponent.h>
|
|
11
|
+
#import <CoreVideo/CoreVideo.h>
|
|
12
|
+
#import <CoreMedia/CoreMedia.h>
|
|
13
|
+
|
|
14
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
15
|
+
|
|
16
|
+
// Bitmap捕获回调协议 - 对应Android的BitmapCaptureCallback
|
|
17
|
+
@protocol VeLiveBitmapCaptureCallback <NSObject>
|
|
18
|
+
- (void)onBitmapCaptured:(UIImage *)bitmap;
|
|
19
|
+
- (void)onCaptureError:(NSString *)error;
|
|
20
|
+
@end
|
|
21
|
+
|
|
22
|
+
// MixerView代理协议
|
|
23
|
+
@protocol VeLiveMixerViewDelegate <NSObject>
|
|
24
|
+
- (void)onBitmapCaptured:(UIImage *)image viewId:(NSString *)viewId;
|
|
25
|
+
- (void)onCaptureError:(NSString *)error viewId:(NSString *)viewId;
|
|
26
|
+
@end
|
|
27
|
+
|
|
28
|
+
@interface VeLiveMixerUIView : UIView
|
|
29
|
+
|
|
30
|
+
// 视图标识
|
|
31
|
+
@property (nonatomic, strong) NSString *viewId;
|
|
32
|
+
|
|
33
|
+
// 混流配置属性
|
|
34
|
+
@property (nonatomic, strong) NSNumber *x;
|
|
35
|
+
@property (nonatomic, strong) NSNumber *y;
|
|
36
|
+
@property (nonatomic, strong) NSNumber *width;
|
|
37
|
+
@property (nonatomic, strong) NSNumber *height;
|
|
38
|
+
@property (nonatomic, strong) NSNumber *zOrder;
|
|
39
|
+
@property (nonatomic, strong) NSNumber *renderMode;
|
|
40
|
+
@property (nonatomic, strong) NSString *captureMode;
|
|
41
|
+
@property (nonatomic, strong) NSNumber *captureFramerate;
|
|
42
|
+
@property (nonatomic, strong) NSNumber *autoSensitivity;
|
|
43
|
+
|
|
44
|
+
// React Native 事件回调
|
|
45
|
+
@property (nonatomic, copy) RCTBubblingEventBlock onBitmapCapture;
|
|
46
|
+
@property (nonatomic, copy) RCTBubblingEventBlock onCaptureError;
|
|
47
|
+
|
|
48
|
+
// 代理
|
|
49
|
+
@property (nonatomic, weak) id<VeLiveMixerViewDelegate> delegate;
|
|
50
|
+
|
|
51
|
+
// Bitmap捕获回调 - 用于与MixerManager集成
|
|
52
|
+
@property (nonatomic, weak) id<VeLiveBitmapCaptureCallback> bitmapCaptureCallback;
|
|
53
|
+
|
|
54
|
+
// 控制方法
|
|
55
|
+
- (void)startCapture;
|
|
56
|
+
- (void)stopCapture;
|
|
57
|
+
- (void)performCaptureWithTrigger:(NSString *)trigger;
|
|
58
|
+
|
|
59
|
+
// 设置bitmap捕获回调
|
|
60
|
+
- (void)setBitmapCaptureCallback:(id<VeLiveBitmapCaptureCallback>)callback;
|
|
61
|
+
|
|
62
|
+
// UIView转换方法
|
|
63
|
+
- (UIImage *)snapshotIncludeSubviews;
|
|
64
|
+
- (CVPixelBufferRef)createPixelBuffer;
|
|
65
|
+
- (CMSampleBufferRef)createSampleBuffer;
|
|
66
|
+
|
|
67
|
+
@end
|
|
68
|
+
|
|
69
|
+
NS_ASSUME_NONNULL_END
|