tirtc-react-native 2.3.1 → 2.4.0-alpha.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/README.md +23 -7
- package/TiRtcReactNative.podspec +1 -1
- package/android/build.gradle +1 -1
- package/android/src/main/AndroidManifest.xml +2 -1
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcModule.kt +622 -28
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeCleanup.kt +115 -0
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeEventBinder.kt +32 -8
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeEventSink.kt +16 -0
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeMaps.kt +62 -0
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeModuleSupport.kt +6 -6
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeRegistry.kt +27 -0
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeStorageSupport.kt +64 -0
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcVideoOutputViewManager.kt +17 -2
- package/ios/TiRtcReactNative+Conn.mm +173 -2
- package/ios/TiRtcReactNative+Input.mm +18 -4
- package/ios/TiRtcReactNative+Output.mm +41 -4
- package/ios/TiRtcReactNative+Private.h +4 -0
- package/ios/TiRtcReactNative+Storage.mm +513 -0
- package/ios/TiRtcReactNative.h +2 -1
- package/ios/TiRtcReactNative.mm +109 -1
- package/ios/TiRtcReactNativeEventBinder.h +8 -0
- package/ios/TiRtcReactNativeEventBinder.mm +102 -0
- package/ios/TiRtcReactNativeEventSink.h +3 -0
- package/ios/TiRtcReactNativeEventSink.mm +16 -0
- package/ios/TiRtcReactNativeRegistry.h +5 -0
- package/ios/TiRtcReactNativeRegistry.mm +43 -0
- package/ios/TiRtcVideoOutputView.mm +11 -0
- package/lib/module/audio_input.js +33 -17
- package/lib/module/audio_input.js.map +1 -1
- package/lib/module/audio_output.js +27 -10
- package/lib/module/audio_output.js.map +1 -1
- package/lib/module/conn.js +31 -7
- package/lib/module/conn.js.map +1 -1
- package/lib/module/errors.js +4 -3
- package/lib/module/errors.js.map +1 -1
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/logging.js +9 -1
- package/lib/module/logging.js.map +1 -1
- package/lib/module/logging_internal.js +27 -0
- package/lib/module/logging_internal.js.map +1 -0
- package/lib/module/recording.js +210 -0
- package/lib/module/recording.js.map +1 -0
- package/lib/module/runtime.js +13 -5
- package/lib/module/runtime.js.map +1 -1
- package/lib/module/specs/NativeTiRtc.js.map +1 -1
- package/lib/module/storage.js +706 -0
- package/lib/module/storage.js.map +1 -0
- package/lib/module/video_input.js +40 -22
- package/lib/module/video_input.js.map +1 -1
- package/lib/module/video_output.js +51 -10
- package/lib/module/video_output.js.map +1 -1
- package/lib/typescript/audio_input.d.ts +1 -0
- package/lib/typescript/conn.d.ts +2 -0
- package/lib/typescript/errors.d.ts +3 -2
- package/lib/typescript/index.d.ts +4 -0
- package/lib/typescript/logging_internal.d.ts +2 -0
- package/lib/typescript/recording.d.ts +53 -0
- package/lib/typescript/runtime.d.ts +2 -0
- package/lib/typescript/specs/NativeTiRtc.d.ts +88 -0
- package/lib/typescript/storage.d.ts +204 -0
- package/lib/typescript/video_input.d.ts +1 -0
- package/lib/typescript/video_output.d.ts +3 -0
- package/package.json +1 -1
- package/src/audio_input.ts +85 -59
- package/src/audio_output.ts +30 -17
- package/src/conn.ts +46 -28
- package/src/errors.ts +4 -3
- package/src/index.ts +54 -0
- package/src/logging.ts +7 -1
- package/src/logging_internal.ts +23 -0
- package/src/recording.ts +271 -0
- package/src/runtime.ts +14 -5
- package/src/specs/NativeTiRtc.ts +123 -0
- package/src/storage.ts +769 -0
- package/src/video_input.ts +97 -62
- package/src/video_output.ts +54 -16
|
@@ -91,8 +91,15 @@
|
|
|
91
91
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
92
92
|
reject:(RCTPromiseRejectBlock)reject {
|
|
93
93
|
TiRtcAudioInput* input = [self audioInput:objectId];
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
if (input == nil) {
|
|
95
|
+
resolve(@(TiRtcReactNativeErrorObjectReleased));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
NSInteger code = TiRtcReactNativeNormalizeDarwin([input dispose]);
|
|
99
|
+
if (code == TiRtcReactNativeErrorOK) {
|
|
100
|
+
[self releaseRegisteredObject:(NSInteger)objectId object:input];
|
|
101
|
+
}
|
|
102
|
+
resolve(@(code));
|
|
96
103
|
}
|
|
97
104
|
|
|
98
105
|
- (NSDictionary*)createVideoInput {
|
|
@@ -188,8 +195,15 @@
|
|
|
188
195
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
189
196
|
reject:(RCTPromiseRejectBlock)reject {
|
|
190
197
|
TiRtcVideoInput* input = [self videoInput:objectId];
|
|
191
|
-
|
|
192
|
-
|
|
198
|
+
if (input == nil) {
|
|
199
|
+
resolve(@(TiRtcReactNativeErrorObjectReleased));
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
NSInteger code = TiRtcReactNativeNormalizeDarwin([input dispose]);
|
|
203
|
+
if (code == TiRtcReactNativeErrorOK) {
|
|
204
|
+
[self releaseRegisteredObject:(NSInteger)objectId object:input];
|
|
205
|
+
}
|
|
206
|
+
resolve(@(code));
|
|
193
207
|
}
|
|
194
208
|
|
|
195
209
|
@end
|
|
@@ -85,8 +85,14 @@
|
|
|
85
85
|
|
|
86
86
|
- (NSNumber*)audioOutputDispose:(double)objectId {
|
|
87
87
|
TiRtcAudioOutput* output = [self audioOutput:objectId];
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
if (output == nil) {
|
|
89
|
+
return @(TiRtcReactNativeErrorObjectReleased);
|
|
90
|
+
}
|
|
91
|
+
NSInteger code = TiRtcReactNativeNormalizeDarwin([output dispose]);
|
|
92
|
+
if (code == TiRtcReactNativeErrorOK) {
|
|
93
|
+
[self releaseRegisteredObject:(NSInteger)objectId object:output];
|
|
94
|
+
}
|
|
95
|
+
return @(code);
|
|
90
96
|
}
|
|
91
97
|
|
|
92
98
|
- (NSDictionary*)createVideoOutput {
|
|
@@ -162,10 +168,41 @@
|
|
|
162
168
|
: TiRtcReactNativeVideoDebugResult([output getDebugSnapshot]);
|
|
163
169
|
}
|
|
164
170
|
|
|
171
|
+
- (void)videoOutputTakeSnapshot:(double)objectId
|
|
172
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
173
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
174
|
+
TiRtcVideoOutput* output = [self videoOutput:objectId];
|
|
175
|
+
if (output == nil) {
|
|
176
|
+
resolve(@{
|
|
177
|
+
@"code" : @(TiRtcReactNativeErrorObjectReleased),
|
|
178
|
+
@"fileId" : (id)kCFNull,
|
|
179
|
+
@"filePath" : (id)kCFNull
|
|
180
|
+
});
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
184
|
+
[output takeSnapshotWithCompletion:^(TiRtcSnapshotResult* snapshotResult) {
|
|
185
|
+
NSInteger fileId =
|
|
186
|
+
snapshotResult.file == nil ? 0 : [[self registry] addTransientObject:snapshotResult.file];
|
|
187
|
+
resolve(@{
|
|
188
|
+
@"code" : @(TiRtcReactNativeNormalizeDarwin(snapshotResult.code)),
|
|
189
|
+
@"fileId" : fileId == 0 ? (id)kCFNull : @(fileId),
|
|
190
|
+
@"filePath" : snapshotResult.file.path ?: (id)kCFNull
|
|
191
|
+
});
|
|
192
|
+
}];
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
165
196
|
- (NSNumber*)videoOutputDispose:(double)objectId {
|
|
166
197
|
TiRtcVideoOutput* output = [self videoOutput:objectId];
|
|
167
|
-
|
|
168
|
-
|
|
198
|
+
if (output == nil) {
|
|
199
|
+
return @(TiRtcReactNativeErrorObjectReleased);
|
|
200
|
+
}
|
|
201
|
+
NSInteger code = TiRtcReactNativeNormalizeDarwin([output dispose]);
|
|
202
|
+
if (code == TiRtcReactNativeErrorOK) {
|
|
203
|
+
[self releaseRegisteredObject:(NSInteger)objectId object:output];
|
|
204
|
+
}
|
|
205
|
+
return @(code);
|
|
169
206
|
}
|
|
170
207
|
|
|
171
208
|
@end
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
#import "TiRtcReactNativeNative.h"
|
|
4
4
|
#import "TiRtcReactNativeRegistry.h"
|
|
5
5
|
|
|
6
|
+
@protocol TiRtcReactNativeReloadTask <NSObject>
|
|
7
|
+
- (void)stopForReactNativeInvalidation:(void (^)(id file))completion;
|
|
8
|
+
@end
|
|
9
|
+
|
|
6
10
|
@interface TiRtcReactNative (Private)
|
|
7
11
|
|
|
8
12
|
- (TiRtcReactNativeRegistry*)registry;
|
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
#import "TiRtcReactNative+Private.h"
|
|
2
|
+
|
|
3
|
+
#import "TiRtcReactNativeErrors.h"
|
|
4
|
+
#import "TiRtcReactNativeMaps.h"
|
|
5
|
+
|
|
6
|
+
#pragma clang diagnostic push
|
|
7
|
+
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
|
|
8
|
+
|
|
9
|
+
static NSInteger TiRtcReactNativeCloudStorageReplaySpeedValue(TiCloudStorageReplaySpeed speed) {
|
|
10
|
+
switch (speed) {
|
|
11
|
+
case TiCloudStorageReplaySpeedX0_125: return 6;
|
|
12
|
+
case TiCloudStorageReplaySpeedX0_25: return 5;
|
|
13
|
+
case TiCloudStorageReplaySpeedX0_5: return 4;
|
|
14
|
+
case TiCloudStorageReplaySpeedX1: return 0;
|
|
15
|
+
case TiCloudStorageReplaySpeedX2: return 1;
|
|
16
|
+
case TiCloudStorageReplaySpeedX4: return 2;
|
|
17
|
+
case TiCloudStorageReplaySpeedX8: return 3;
|
|
18
|
+
}
|
|
19
|
+
return 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static int32_t TiRtcReactNativeDetachCloudStorageVideoView(TiCloudStorageVideoOutput* output) {
|
|
23
|
+
if ([NSThread isMainThread]) return [output detachView];
|
|
24
|
+
__block int32_t code = TiRtcReactNativeErrorPlatformInternal;
|
|
25
|
+
dispatch_sync(dispatch_get_main_queue(), ^{
|
|
26
|
+
code = [output detachView];
|
|
27
|
+
});
|
|
28
|
+
return code;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static BOOL TiRtcReactNativeCloudStorageReplaySpeedFromValue(NSInteger value, TiCloudStorageReplaySpeed* speed) {
|
|
32
|
+
switch (value) {
|
|
33
|
+
case 6: *speed = TiCloudStorageReplaySpeedX0_125; return YES;
|
|
34
|
+
case 5: *speed = TiCloudStorageReplaySpeedX0_25; return YES;
|
|
35
|
+
case 4: *speed = TiCloudStorageReplaySpeedX0_5; return YES;
|
|
36
|
+
case 0: *speed = TiCloudStorageReplaySpeedX1; return YES;
|
|
37
|
+
case 1: *speed = TiCloudStorageReplaySpeedX2; return YES;
|
|
38
|
+
case 2: *speed = TiCloudStorageReplaySpeedX4; return YES;
|
|
39
|
+
case 3: *speed = TiCloudStorageReplaySpeedX8; return YES;
|
|
40
|
+
default: return NO;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static NSString* TiRtcReactNativeCloudStorageAudioState(TiCloudStorageAudioOutputState state) {
|
|
45
|
+
switch (state) {
|
|
46
|
+
case TiCloudStorageAudioOutputStateIdle: return @"idle";
|
|
47
|
+
case TiCloudStorageAudioOutputStateBuffering: return @"buffering";
|
|
48
|
+
case TiCloudStorageAudioOutputStatePlaying: return @"playing";
|
|
49
|
+
case TiCloudStorageAudioOutputStateFailed: return @"failed";
|
|
50
|
+
case TiCloudStorageAudioOutputStatePaused: return @"paused";
|
|
51
|
+
case TiCloudStorageAudioOutputStateCompleted: return @"completed";
|
|
52
|
+
}
|
|
53
|
+
return @"failed";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static NSString* TiRtcReactNativeCloudStorageVideoState(TiCloudStorageVideoOutputState state) {
|
|
57
|
+
switch (state) {
|
|
58
|
+
case TiCloudStorageVideoOutputStateIdle: return @"idle";
|
|
59
|
+
case TiCloudStorageVideoOutputStateBuffering: return @"buffering";
|
|
60
|
+
case TiCloudStorageVideoOutputStateRendering: return @"rendering";
|
|
61
|
+
case TiCloudStorageVideoOutputStateFailed: return @"failed";
|
|
62
|
+
case TiCloudStorageVideoOutputStatePaused: return @"paused";
|
|
63
|
+
case TiCloudStorageVideoOutputStateCompleted: return @"completed";
|
|
64
|
+
}
|
|
65
|
+
return @"failed";
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static NSDictionary* TiRtcReactNativeCloudStorageMp4Result(
|
|
69
|
+
TiRtcReactNativeRegistry* registry, TiCloudStorageRecordingResult* result) {
|
|
70
|
+
NSInteger fileId = result.file == nil ? 0 : [registry addTransientObject:result.file];
|
|
71
|
+
return @{
|
|
72
|
+
@"code" : @(TiRtcReactNativeNormalizeDarwin(result.code)),
|
|
73
|
+
@"fileId" : fileId == 0 ? (id)kCFNull : @(fileId),
|
|
74
|
+
@"filePath" : result.file.path ?: (id)kCFNull,
|
|
75
|
+
@"durationMs" : result.file == nil ? (id)kCFNull : @(result.file.durationMs),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@interface TiRtcReactNativeCloudStorageExportBridge : NSObject <TiRtcReactNativeReloadTask>
|
|
80
|
+
@property(nonatomic, strong) TiCloudStorageExportTask* task;
|
|
81
|
+
@property(nonatomic, assign) NSInteger objectId;
|
|
82
|
+
- (instancetype)initWithRegistry:(TiRtcReactNativeRegistry*)registry;
|
|
83
|
+
- (void)complete:(TiCloudStorageRecordingResult*)result;
|
|
84
|
+
- (void)await:(RCTPromiseResolveBlock)resolve;
|
|
85
|
+
@end
|
|
86
|
+
|
|
87
|
+
@implementation TiRtcReactNativeCloudStorageExportBridge {
|
|
88
|
+
TiRtcReactNativeRegistry* _registry;
|
|
89
|
+
TiCloudStorageRecordingResult* _result;
|
|
90
|
+
NSMutableArray<RCTPromiseResolveBlock>* _waiters;
|
|
91
|
+
BOOL _invalidated;
|
|
92
|
+
void (^_invalidationCompletion)(id file);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
- (instancetype)initWithRegistry:(TiRtcReactNativeRegistry*)registry {
|
|
96
|
+
if (self = [super init]) {
|
|
97
|
+
_registry = registry;
|
|
98
|
+
_waiters = [NSMutableArray new];
|
|
99
|
+
}
|
|
100
|
+
return self;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
- (void)complete:(TiCloudStorageRecordingResult*)result {
|
|
104
|
+
NSArray<RCTPromiseResolveBlock>* waiters;
|
|
105
|
+
void (^invalidationCompletion)(id file);
|
|
106
|
+
@synchronized(self) {
|
|
107
|
+
if (_result != nil) return;
|
|
108
|
+
_result = result;
|
|
109
|
+
waiters = _invalidated ? @[] : [_waiters copy];
|
|
110
|
+
[_waiters removeAllObjects];
|
|
111
|
+
invalidationCompletion = _invalidationCompletion;
|
|
112
|
+
_invalidationCompletion = nil;
|
|
113
|
+
}
|
|
114
|
+
for (RCTPromiseResolveBlock resolve in waiters) {
|
|
115
|
+
resolve(TiRtcReactNativeCloudStorageMp4Result(_registry, result));
|
|
116
|
+
}
|
|
117
|
+
if (waiters.count > 0 && self.objectId > 0) [_registry releaseObject:self.objectId];
|
|
118
|
+
if (invalidationCompletion != nil) invalidationCompletion(result.file);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
- (void)await:(RCTPromiseResolveBlock)resolve {
|
|
122
|
+
TiCloudStorageRecordingResult* result;
|
|
123
|
+
@synchronized(self) {
|
|
124
|
+
result = _result;
|
|
125
|
+
if (result == nil) {
|
|
126
|
+
[_waiters addObject:[resolve copy]];
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
resolve(TiRtcReactNativeCloudStorageMp4Result(_registry, result));
|
|
131
|
+
if (self.objectId > 0) [_registry releaseObject:self.objectId];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
- (void)stopForReactNativeInvalidation:(void (^)(id file))completion {
|
|
135
|
+
TiCloudStorageRecordingResult* result;
|
|
136
|
+
@synchronized(self) {
|
|
137
|
+
_invalidated = YES;
|
|
138
|
+
[_waiters removeAllObjects];
|
|
139
|
+
result = _result;
|
|
140
|
+
if (result == nil) _invalidationCompletion = [completion copy];
|
|
141
|
+
}
|
|
142
|
+
if (result != nil) {
|
|
143
|
+
completion(result.file);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
int32_t code = [self.task stop];
|
|
147
|
+
if (code != 0) {
|
|
148
|
+
@synchronized(self) {
|
|
149
|
+
_invalidationCompletion = nil;
|
|
150
|
+
}
|
|
151
|
+
completion(nil);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@end
|
|
156
|
+
|
|
157
|
+
@implementation TiRtcReactNative (Storage)
|
|
158
|
+
|
|
159
|
+
- (void)tiCloudStorageInitialize:(JS::NativeTiRtc::NativeInitOptions&)options
|
|
160
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
161
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
162
|
+
int32_t code = [TiCloudStorage initializeWithAppId:options.appId() ?: @""
|
|
163
|
+
endpoint:options.endpoint() ?: @""
|
|
164
|
+
consoleLogEnabled:options.consoleLogEnabled()];
|
|
165
|
+
resolve(@(TiRtcReactNativeNormalizeDarwin(code)));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
- (NSNumber*)tiCloudStorageShutdown {
|
|
169
|
+
return @(TiRtcReactNativeNormalizeDarwin([TiCloudStorage shutdown]));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
- (NSDictionary*)tiCloudStorageCreate:(NSString*)token {
|
|
173
|
+
return [self
|
|
174
|
+
registerObject:^id { return [[TiCloudStorage alloc] initWithToken:token]; }
|
|
175
|
+
wire:^id(NSInteger objectId, id object) {
|
|
176
|
+
return [[self eventBinder] wireCloudStorage:(TiCloudStorage*)object objectId:objectId];
|
|
177
|
+
}];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
- (NSNumber*)tiCloudStorageUpdateToken:(double)objectId token:(NSString*)token {
|
|
181
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
182
|
+
return [object isKindOfClass:[TiCloudStorage class]]
|
|
183
|
+
? @(TiRtcReactNativeNormalizeDarwin([(TiCloudStorage*)object updateToken:token]))
|
|
184
|
+
: @(TiRtcReactNativeErrorObjectReleased);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
- (void)tiCloudStorageListRecordings:(double)objectId
|
|
188
|
+
startTimeMs:(double)startTimeMs
|
|
189
|
+
endTimeMs:(double)endTimeMs
|
|
190
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
191
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
192
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
193
|
+
if (![object isKindOfClass:[TiCloudStorage class]]) {
|
|
194
|
+
resolve(@{@"code" : @(TiRtcReactNativeErrorObjectReleased), @"recordings" : @[]});
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
TiCloudStorage* cloudStorage = (TiCloudStorage*)object;
|
|
198
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
199
|
+
[cloudStorage listRecordingsWithStartTimeMs:(int64_t)startTimeMs
|
|
200
|
+
endTimeMs:(int64_t)endTimeMs
|
|
201
|
+
completion:^(TiCloudStorageRecordingRangesResult* result) {
|
|
202
|
+
NSMutableArray* ranges = [NSMutableArray arrayWithCapacity:result.recordings.count];
|
|
203
|
+
for (TiCloudStorageRecordingRange* range in result.recordings) {
|
|
204
|
+
[ranges addObject:@{@"startTimeMs" : @(range.startTimeMs), @"endTimeMs" : @(range.endTimeMs)}];
|
|
205
|
+
}
|
|
206
|
+
resolve(@{@"code" : @(TiRtcReactNativeNormalizeDarwin(result.code)), @"recordings" : ranges});
|
|
207
|
+
}];
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
- (void)tiCloudStorageListRecordingDays:(double)objectId
|
|
212
|
+
startDate:(NSString*)startDate
|
|
213
|
+
endDate:(NSString*)endDate
|
|
214
|
+
timeZoneId:(NSString*)timeZoneId
|
|
215
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
216
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
217
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
218
|
+
if (![object isKindOfClass:[TiCloudStorage class]]) {
|
|
219
|
+
resolve(@{@"code" : @(TiRtcReactNativeErrorObjectReleased), @"days" : @[]});
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
TiCloudStorage* cloudStorage = (TiCloudStorage*)object;
|
|
223
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
224
|
+
[cloudStorage listRecordingDaysWithStartDate:startDate
|
|
225
|
+
endDate:endDate
|
|
226
|
+
timeZoneId:timeZoneId
|
|
227
|
+
completion:^(TiCloudStorageRecordingDaysResult* result) {
|
|
228
|
+
NSMutableArray* days = [NSMutableArray arrayWithCapacity:result.days.count];
|
|
229
|
+
for (TiCloudStorageRecordingDay* day in result.days) {
|
|
230
|
+
[days addObject:@{@"date" : day.date, @"hasRecording" : @(day.hasRecording)}];
|
|
231
|
+
}
|
|
232
|
+
resolve(@{@"code" : @(TiRtcReactNativeNormalizeDarwin(result.code)), @"days" : days});
|
|
233
|
+
}];
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
- (NSDictionary*)tiCloudStorageCreateReplay:(double)objectId {
|
|
238
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
239
|
+
if (![object isKindOfClass:[TiCloudStorage class]]) {
|
|
240
|
+
return TiRtcReactNativeCreateResult(TiRtcReactNativeErrorObjectReleased, 0, 0, nil);
|
|
241
|
+
}
|
|
242
|
+
return [self
|
|
243
|
+
registerObject:^id { return [(TiCloudStorage*)object createReplay]; }
|
|
244
|
+
wire:^id(NSInteger replayId, id replay) {
|
|
245
|
+
return [[self eventBinder] wireCloudStorageReplay:(TiCloudStorageReplay*)replay objectId:replayId];
|
|
246
|
+
}];
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
- (NSDictionary*)tiCloudStorageExportRecording:(double)objectId
|
|
250
|
+
startTimeMs:(double)startTimeMs
|
|
251
|
+
endTimeMs:(double)endTimeMs
|
|
252
|
+
videoChannelId:(double)videoChannelId
|
|
253
|
+
audioChannelId:(NSNumber*)audioChannelId {
|
|
254
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
255
|
+
if (![object isKindOfClass:[TiCloudStorage class]]) {
|
|
256
|
+
return @{@"code" : @(TiRtcReactNativeErrorObjectReleased), @"taskId" : (id)kCFNull};
|
|
257
|
+
}
|
|
258
|
+
TiRtcReactNativeCloudStorageExportBridge* bridge =
|
|
259
|
+
[[TiRtcReactNativeCloudStorageExportBridge alloc] initWithRegistry:[self registry]];
|
|
260
|
+
TiCloudStorageExportRequest* request = [[TiCloudStorageExportRequest alloc]
|
|
261
|
+
initWithStartTimeMs:(int64_t)startTimeMs
|
|
262
|
+
endTimeMs:(int64_t)endTimeMs
|
|
263
|
+
videoChannelId:(NSInteger)videoChannelId
|
|
264
|
+
audioChannelId:audioChannelId];
|
|
265
|
+
TiCloudStorageExportTaskStartResult* started = [(TiCloudStorage*)object
|
|
266
|
+
exportRecording:request
|
|
267
|
+
progress:nil
|
|
268
|
+
completion:^(TiCloudStorageRecordingResult* result) { [bridge complete:result]; }];
|
|
269
|
+
if (started.code != 0 || started.task == nil) {
|
|
270
|
+
return @{@"code" : @(TiRtcReactNativeNormalizeDarwin(started.code)), @"taskId" : (id)kCFNull};
|
|
271
|
+
}
|
|
272
|
+
bridge.task = started.task;
|
|
273
|
+
bridge.objectId = [[self registry] addObject:bridge];
|
|
274
|
+
return @{@"code" : @0, @"taskId" : @(bridge.objectId)};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
- (NSNumber*)tiCloudStorageExportProgress:(double)objectId {
|
|
278
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
279
|
+
return [object isKindOfClass:[TiRtcReactNativeCloudStorageExportBridge class]]
|
|
280
|
+
? @(((TiRtcReactNativeCloudStorageExportBridge*)object).task.progress)
|
|
281
|
+
: @0;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
- (void)tiCloudStorageExportResult:(double)objectId
|
|
285
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
286
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
287
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
288
|
+
if (![object isKindOfClass:[TiRtcReactNativeCloudStorageExportBridge class]]) {
|
|
289
|
+
resolve(@{@"code" : @(TiRtcReactNativeErrorObjectReleased), @"fileId" : (id)kCFNull,
|
|
290
|
+
@"filePath" : (id)kCFNull, @"durationMs" : (id)kCFNull});
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
[(TiRtcReactNativeCloudStorageExportBridge*)object await:resolve];
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
- (NSNumber*)tiCloudStorageExportStop:(double)objectId {
|
|
297
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
298
|
+
if (![object isKindOfClass:[TiRtcReactNativeCloudStorageExportBridge class]]) {
|
|
299
|
+
return @(TiRtcReactNativeErrorObjectReleased);
|
|
300
|
+
}
|
|
301
|
+
TiCloudStorageExportTask* task = ((TiRtcReactNativeCloudStorageExportBridge*)object).task;
|
|
302
|
+
return @(TiRtcReactNativeNormalizeDarwin([task stop]));
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
- (NSNumber*)tiCloudStorageDispose:(double)objectId {
|
|
306
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
307
|
+
if (![object isKindOfClass:[TiCloudStorage class]]) return @(TiRtcReactNativeErrorObjectReleased);
|
|
308
|
+
int32_t code = [(TiCloudStorage*)object dispose];
|
|
309
|
+
if (code == 0) [[self registry] releaseObject:(NSInteger)objectId];
|
|
310
|
+
return @(TiRtcReactNativeNormalizeDarwin(code));
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
- (NSDictionary*)tiCloudStorageReplayGetInfo:(double)objectId {
|
|
314
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
315
|
+
if (![object isKindOfClass:[TiCloudStorageReplay class]]) {
|
|
316
|
+
return @{@"code" : @(TiRtcReactNativeErrorObjectReleased), @"speed" : @0,
|
|
317
|
+
@"currentTimeMs" : (id)kCFNull};
|
|
318
|
+
}
|
|
319
|
+
TiCloudStorageReplay* replay = (TiCloudStorageReplay*)object;
|
|
320
|
+
return @{@"code" : @0, @"speed" : @(TiRtcReactNativeCloudStorageReplaySpeedValue(replay.speed)),
|
|
321
|
+
@"currentTimeMs" : replay.currentTimeMs ?: (id)kCFNull};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
- (NSNumber*)tiCloudStorageReplayPlay:(double)objectId
|
|
325
|
+
startTimeMs:(double)startTimeMs
|
|
326
|
+
endTimeMs:(double)endTimeMs
|
|
327
|
+
initialTimeMs:(NSNumber*)initialTimeMs {
|
|
328
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
329
|
+
return [object isKindOfClass:[TiCloudStorageReplay class]]
|
|
330
|
+
? @(TiRtcReactNativeNormalizeDarwin([(TiCloudStorageReplay*)object
|
|
331
|
+
playWithStartTimeMs:(int64_t)startTimeMs
|
|
332
|
+
endTimeMs:(int64_t)endTimeMs
|
|
333
|
+
initialTimeMs:initialTimeMs]))
|
|
334
|
+
: @(TiRtcReactNativeErrorObjectReleased);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
- (NSNumber*)tiCloudStorageReplayPause:(double)objectId { return [self tiCloudStorageReplayCode:objectId selector:@selector(pause)]; }
|
|
338
|
+
- (NSNumber*)tiCloudStorageReplayResume:(double)objectId { return [self tiCloudStorageReplayCode:objectId selector:@selector(resume)]; }
|
|
339
|
+
- (NSNumber*)tiCloudStorageReplayStop:(double)objectId { return [self tiCloudStorageReplayCode:objectId selector:@selector(stop)]; }
|
|
340
|
+
|
|
341
|
+
- (NSNumber*)tiCloudStorageReplaySeek:(double)objectId timeMs:(double)timeMs {
|
|
342
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
343
|
+
return [object isKindOfClass:[TiCloudStorageReplay class]]
|
|
344
|
+
? @(TiRtcReactNativeNormalizeDarwin([(TiCloudStorageReplay*)object seekToTimeMs:(int64_t)timeMs]))
|
|
345
|
+
: @(TiRtcReactNativeErrorObjectReleased);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
- (NSNumber*)tiCloudStorageReplaySetSpeed:(double)objectId speed:(double)speed {
|
|
349
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
350
|
+
if (![object isKindOfClass:[TiCloudStorageReplay class]]) return @(TiRtcReactNativeErrorObjectReleased);
|
|
351
|
+
TiCloudStorageReplaySpeed mapped;
|
|
352
|
+
if (!TiRtcReactNativeCloudStorageReplaySpeedFromValue((NSInteger)speed, &mapped)) return @(6000);
|
|
353
|
+
return @(TiRtcReactNativeNormalizeDarwin([(TiCloudStorageReplay*)object setSpeed:mapped]));
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
- (NSDictionary*)tiCloudStorageReplayStartRecording:(double)objectId
|
|
357
|
+
videoChannelId:(double)videoChannelId
|
|
358
|
+
audioChannelId:(NSNumber*)audioChannelId {
|
|
359
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
360
|
+
if (![object isKindOfClass:[TiCloudStorageReplay class]]) {
|
|
361
|
+
return @{@"code" : @(TiRtcReactNativeErrorObjectReleased), @"taskId" : (id)kCFNull};
|
|
362
|
+
}
|
|
363
|
+
TiCloudStorageRecordingTaskStartResult* started = [(TiCloudStorageReplay*)object
|
|
364
|
+
startRecordingWithVideoChannelId:(NSInteger)videoChannelId audioChannelId:audioChannelId];
|
|
365
|
+
if (started.code != 0 || started.task == nil) {
|
|
366
|
+
return @{@"code" : @(TiRtcReactNativeNormalizeDarwin(started.code)), @"taskId" : (id)kCFNull};
|
|
367
|
+
}
|
|
368
|
+
NSInteger taskId = [[self registry] addObject:started.task];
|
|
369
|
+
return @{@"code" : @0, @"taskId" : @(taskId)};
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
- (void)tiCloudStorageRecordingTaskStop:(double)objectId
|
|
373
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
374
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
375
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
376
|
+
if (![object isKindOfClass:[TiCloudStorageRecordingTask class]]) {
|
|
377
|
+
resolve(@{@"code" : @(TiRtcReactNativeErrorObjectReleased), @"fileId" : (id)kCFNull,
|
|
378
|
+
@"filePath" : (id)kCFNull, @"durationMs" : (id)kCFNull});
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
[(TiCloudStorageRecordingTask*)object stopWithCompletion:^(TiCloudStorageRecordingResult* result) {
|
|
382
|
+
[[self registry] releaseObject:(NSInteger)objectId];
|
|
383
|
+
resolve(TiRtcReactNativeCloudStorageMp4Result([self registry], result));
|
|
384
|
+
}];
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
- (NSNumber*)tiCloudStorageReplayDispose:(double)objectId {
|
|
388
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
389
|
+
if (![object isKindOfClass:[TiCloudStorageReplay class]]) return @(TiRtcReactNativeErrorObjectReleased);
|
|
390
|
+
int32_t code = [(TiCloudStorageReplay*)object dispose];
|
|
391
|
+
if (code == 0) [[self registry] releaseObject:(NSInteger)objectId];
|
|
392
|
+
return @(TiRtcReactNativeNormalizeDarwin(code));
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
- (NSNumber*)tiCloudStorageReplayCode:(double)objectId selector:(SEL)selector {
|
|
396
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
397
|
+
if (![object isKindOfClass:[TiCloudStorageReplay class]]) return @(TiRtcReactNativeErrorObjectReleased);
|
|
398
|
+
IMP implementation = [object methodForSelector:selector];
|
|
399
|
+
int32_t (*call)(id, SEL) = (int32_t (*)(id, SEL))implementation;
|
|
400
|
+
return @(TiRtcReactNativeNormalizeDarwin(call(object, selector)));
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
- (NSDictionary*)tiCloudStorageCreateAudioOutput {
|
|
404
|
+
return [self
|
|
405
|
+
registerObject:^id { return [TiCloudStorageAudioOutput new]; }
|
|
406
|
+
wire:^id(NSInteger objectId, id object) {
|
|
407
|
+
return [[self eventBinder] wireCloudStorageAudioOutput:(TiCloudStorageAudioOutput*)object objectId:objectId];
|
|
408
|
+
}];
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
- (NSDictionary*)tiCloudStorageAudioOutputGetState:(double)objectId {
|
|
412
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
413
|
+
if (![object isKindOfClass:[TiCloudStorageAudioOutput class]]) {
|
|
414
|
+
return TiRtcReactNativeStateResult(TiRtcReactNativeErrorObjectReleased, nil);
|
|
415
|
+
}
|
|
416
|
+
return TiRtcReactNativeStateResult(0, TiRtcReactNativeCloudStorageAudioState(((TiCloudStorageAudioOutput*)object).state));
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
- (NSNumber*)tiCloudStorageAudioOutputSetVolume:(double)objectId volumePercent:(double)volumePercent {
|
|
420
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
421
|
+
return [object isKindOfClass:[TiCloudStorageAudioOutput class]]
|
|
422
|
+
? @(TiRtcReactNativeNormalizeDarwin([(TiCloudStorageAudioOutput*)object setVolume:(uint32_t)volumePercent]))
|
|
423
|
+
: @(TiRtcReactNativeErrorObjectReleased);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
- (NSNumber*)tiCloudStorageAudioOutputAttach:(double)outputId replayId:(double)replayId channelId:(double)channelId {
|
|
427
|
+
id output = [[self registry] objectForId:(NSInteger)outputId];
|
|
428
|
+
id replay = [[self registry] objectForId:(NSInteger)replayId];
|
|
429
|
+
return [output isKindOfClass:[TiCloudStorageAudioOutput class]] && [replay isKindOfClass:[TiCloudStorageReplay class]]
|
|
430
|
+
? @(TiRtcReactNativeNormalizeDarwin([(TiCloudStorageAudioOutput*)output
|
|
431
|
+
attachWithReplay:(TiCloudStorageReplay*)replay channelId:(uint8_t)channelId]))
|
|
432
|
+
: @(TiRtcReactNativeErrorObjectReleased);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
- (NSNumber*)tiCloudStorageAudioOutputDetach:(double)objectId {
|
|
436
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
437
|
+
return [object isKindOfClass:[TiCloudStorageAudioOutput class]]
|
|
438
|
+
? @(TiRtcReactNativeNormalizeDarwin([(TiCloudStorageAudioOutput*)object detach]))
|
|
439
|
+
: @(TiRtcReactNativeErrorObjectReleased);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
- (NSNumber*)tiCloudStorageAudioOutputDispose:(double)objectId {
|
|
443
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
444
|
+
if (![object isKindOfClass:[TiCloudStorageAudioOutput class]]) return @(TiRtcReactNativeErrorObjectReleased);
|
|
445
|
+
int32_t code = [(TiCloudStorageAudioOutput*)object dispose];
|
|
446
|
+
if (code == 0) [[self registry] releaseObject:(NSInteger)objectId];
|
|
447
|
+
return @(TiRtcReactNativeNormalizeDarwin(code));
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
- (NSDictionary*)tiCloudStorageCreateVideoOutput {
|
|
451
|
+
return [self
|
|
452
|
+
registerObject:^id { return [TiCloudStorageVideoOutput new]; }
|
|
453
|
+
wire:^id(NSInteger objectId, id object) {
|
|
454
|
+
return [[self eventBinder] wireCloudStorageVideoOutput:(TiCloudStorageVideoOutput*)object objectId:objectId];
|
|
455
|
+
}];
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
- (NSDictionary*)tiCloudStorageVideoOutputGetState:(double)objectId {
|
|
459
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
460
|
+
if (![object isKindOfClass:[TiCloudStorageVideoOutput class]]) {
|
|
461
|
+
return TiRtcReactNativeStateResult(TiRtcReactNativeErrorObjectReleased, nil);
|
|
462
|
+
}
|
|
463
|
+
return TiRtcReactNativeStateResult(0, TiRtcReactNativeCloudStorageVideoState(((TiCloudStorageVideoOutput*)object).state));
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
- (NSNumber*)tiCloudStorageVideoOutputAttach:(double)outputId replayId:(double)replayId channelId:(double)channelId {
|
|
467
|
+
id output = [[self registry] objectForId:(NSInteger)outputId];
|
|
468
|
+
id replay = [[self registry] objectForId:(NSInteger)replayId];
|
|
469
|
+
return [output isKindOfClass:[TiCloudStorageVideoOutput class]] && [replay isKindOfClass:[TiCloudStorageReplay class]]
|
|
470
|
+
? @(TiRtcReactNativeNormalizeDarwin([(TiCloudStorageVideoOutput*)output
|
|
471
|
+
attachWithReplay:(TiCloudStorageReplay*)replay channelId:(uint8_t)channelId]))
|
|
472
|
+
: @(TiRtcReactNativeErrorObjectReleased);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
- (NSNumber*)tiCloudStorageVideoOutputDetach:(double)objectId {
|
|
476
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
477
|
+
return [object isKindOfClass:[TiCloudStorageVideoOutput class]]
|
|
478
|
+
? @(TiRtcReactNativeNormalizeDarwin([(TiCloudStorageVideoOutput*)object detach]))
|
|
479
|
+
: @(TiRtcReactNativeErrorObjectReleased);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
- (void)tiCloudStorageVideoOutputTakeSnapshot:(double)objectId
|
|
483
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
484
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
485
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
486
|
+
if (![object isKindOfClass:[TiCloudStorageVideoOutput class]]) {
|
|
487
|
+
resolve(@{@"code" : @(TiRtcReactNativeErrorObjectReleased), @"fileId" : (id)kCFNull,
|
|
488
|
+
@"filePath" : (id)kCFNull});
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
TiCloudStorageVideoOutput* output = (TiCloudStorageVideoOutput*)object;
|
|
492
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
493
|
+
[output takeSnapshotWithCompletion:^(TiCloudStorageSnapshotResult* result) {
|
|
494
|
+
NSInteger fileId = result.file == nil ? 0 : [[self registry] addTransientObject:result.file];
|
|
495
|
+
resolve(@{@"code" : @(TiRtcReactNativeNormalizeDarwin(result.code)),
|
|
496
|
+
@"fileId" : fileId == 0 ? (id)kCFNull : @(fileId),
|
|
497
|
+
@"filePath" : result.file.path ?: (id)kCFNull});
|
|
498
|
+
}];
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
- (NSNumber*)tiCloudStorageVideoOutputDispose:(double)objectId {
|
|
503
|
+
id object = [[self registry] objectForId:(NSInteger)objectId];
|
|
504
|
+
if (![object isKindOfClass:[TiCloudStorageVideoOutput class]]) return @(TiRtcReactNativeErrorObjectReleased);
|
|
505
|
+
TiCloudStorageVideoOutput* output = (TiCloudStorageVideoOutput*)object;
|
|
506
|
+
int32_t code = TiRtcReactNativeDetachCloudStorageVideoView(output);
|
|
507
|
+
if (code == 0) code = [output dispose];
|
|
508
|
+
if (code == 0) [[self registry] releaseObject:(NSInteger)objectId];
|
|
509
|
+
return @(TiRtcReactNativeNormalizeDarwin(code));
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
@end
|
|
513
|
+
#pragma clang diagnostic pop
|
package/ios/TiRtcReactNative.h
CHANGED