tirtc-react-native 2.3.1 → 2.4.0-alpha.3
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 +585 -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 +35 -8
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeEventSink.kt +20 -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/TiRtcReactNativeStoreSupport.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+Store.mm +496 -0
- package/ios/TiRtcReactNative.h +2 -1
- package/ios/TiRtcReactNative.mm +109 -1
- package/ios/TiRtcReactNativeEventBinder.h +8 -0
- package/ios/TiRtcReactNativeEventBinder.mm +104 -0
- package/ios/TiRtcReactNativeEventSink.h +4 -0
- package/ios/TiRtcReactNativeEventSink.mm +20 -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/store.js +698 -0
- package/lib/module/store.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/store.d.ts +202 -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/store.ts +760 -0
- package/src/video_input.ts +97 -62
- package/src/video_output.ts +54 -16
|
@@ -1,6 +1,39 @@
|
|
|
1
1
|
#import "TiRtcReactNative+Private.h"
|
|
2
2
|
#import "TiRtcReactNativeErrors.h"
|
|
3
3
|
#import "TiRtcReactNativeMaps.h"
|
|
4
|
+
#import <Photos/Photos.h>
|
|
5
|
+
|
|
6
|
+
static NSString* TiRtcReactNativeGalleryFileName(NSString* fileName, BOOL video) {
|
|
7
|
+
NSString* extension = video ? @".mp4" : @".jpg";
|
|
8
|
+
if (fileName == nil) {
|
|
9
|
+
return [NSString stringWithFormat:@"%lld%@",
|
|
10
|
+
(long long)(NSDate.date.timeIntervalSince1970 * 1000),
|
|
11
|
+
extension];
|
|
12
|
+
}
|
|
13
|
+
unichar nul = 0;
|
|
14
|
+
NSString* nulString = [NSString stringWithCharacters:&nul length:1];
|
|
15
|
+
if (fileName.length == 0 ||
|
|
16
|
+
[[fileName stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet]
|
|
17
|
+
length] == 0 ||
|
|
18
|
+
[fileName isEqualToString:@"."] || [fileName isEqualToString:@".."] ||
|
|
19
|
+
[fileName containsString:@"/"] || [fileName containsString:@"\\"] ||
|
|
20
|
+
[fileName containsString:nulString]) {
|
|
21
|
+
return nil;
|
|
22
|
+
}
|
|
23
|
+
NSString* stem = nil;
|
|
24
|
+
NSString* normalized = nil;
|
|
25
|
+
if ([fileName.lowercaseString hasSuffix:extension]) {
|
|
26
|
+
stem = [fileName substringToIndex:fileName.length - extension.length];
|
|
27
|
+
normalized = fileName;
|
|
28
|
+
} else if ([fileName containsString:@"."]) {
|
|
29
|
+
return nil;
|
|
30
|
+
} else {
|
|
31
|
+
stem = fileName;
|
|
32
|
+
normalized = [fileName stringByAppendingString:extension];
|
|
33
|
+
}
|
|
34
|
+
NSUInteger stemBytes = [stem lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
|
35
|
+
return stemBytes >= 1 && stemBytes <= 200 ? normalized : nil;
|
|
36
|
+
}
|
|
4
37
|
|
|
5
38
|
#pragma clang diagnostic push
|
|
6
39
|
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
|
|
@@ -96,6 +129,138 @@
|
|
|
96
129
|
}];
|
|
97
130
|
}
|
|
98
131
|
|
|
132
|
+
- (NSDictionary*)connStartRecording:(double)objectId
|
|
133
|
+
options:(JS::NativeTiRtc::NativeRecordingOptions&)options {
|
|
134
|
+
TiRtcConn* conn = [self conn:objectId];
|
|
135
|
+
if (conn == nil) {
|
|
136
|
+
return @{@"code" : @(TiRtcReactNativeErrorObjectReleased), @"taskId" : (id)kCFNull};
|
|
137
|
+
}
|
|
138
|
+
NSNumber* audioStreamId =
|
|
139
|
+
options.audioStreamId().has_value() ? @(options.audioStreamId().value()) : nil;
|
|
140
|
+
TiRtcRecordingTaskStartResult* result =
|
|
141
|
+
[conn startRecordingWithVideoStreamId:(int32_t)options.videoStreamId()
|
|
142
|
+
audioStreamId:audioStreamId];
|
|
143
|
+
if (result.code != 0 || result.task == nil) {
|
|
144
|
+
return @{@"code" : @(TiRtcReactNativeNormalizeDarwin(result.code)), @"taskId" : (id)kCFNull};
|
|
145
|
+
}
|
|
146
|
+
NSInteger taskId = [[self registry] addObject:result.task];
|
|
147
|
+
return @{@"code" : @(TiRtcReactNativeErrorOK), @"taskId" : @(taskId)};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
- (void)recordingTaskStop:(double)objectId
|
|
151
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
152
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
153
|
+
TiRtcRecordingTask* task = [[self registry] objectForId:(NSInteger)objectId];
|
|
154
|
+
if (![task isKindOfClass:[TiRtcRecordingTask class]]) {
|
|
155
|
+
resolve(@{
|
|
156
|
+
@"code" : @(TiRtcReactNativeErrorObjectReleased),
|
|
157
|
+
@"fileId" : (id)kCFNull,
|
|
158
|
+
@"filePath" : (id)kCFNull,
|
|
159
|
+
@"durationMs" : (id)kCFNull
|
|
160
|
+
});
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
[task stopWithCompletion:^(TiRtcRecordingResult* result) {
|
|
164
|
+
[[self registry] releaseObject:(NSInteger)objectId];
|
|
165
|
+
NSInteger fileId = result.file == nil ? 0 : [[self registry] addTransientObject:result.file];
|
|
166
|
+
resolve(@{
|
|
167
|
+
@"code" : @(TiRtcReactNativeNormalizeDarwin(result.code)),
|
|
168
|
+
@"fileId" : fileId == 0 ? (id)kCFNull : @(fileId),
|
|
169
|
+
@"filePath" : result.file.path ?: (id)kCFNull,
|
|
170
|
+
@"durationMs" : result.file != nil ? @(result.file.durationMs) : (id)kCFNull
|
|
171
|
+
});
|
|
172
|
+
}];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
- (void)mediaFileMoveToGallery:(double)objectId
|
|
176
|
+
fileName:(NSString*)fileName
|
|
177
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
178
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
179
|
+
id file = [[self registry] transientObjectForId:(NSInteger)objectId];
|
|
180
|
+
if (![file isKindOfClass:[TiRtcRecordingFile class]] &&
|
|
181
|
+
![file isKindOfClass:[TiRtcSnapshotFile class]] &&
|
|
182
|
+
![file isKindOfClass:[TiStoreRecordingFile class]] &&
|
|
183
|
+
![file isKindOfClass:[TiStoreSnapshotFile class]]) {
|
|
184
|
+
resolve(@{@"code" : @(TiRtcReactNativeErrorObjectReleased), @"uri" : (id)kCFNull});
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
NSString* path = [file path];
|
|
188
|
+
BOOL video = [file isKindOfClass:[TiRtcRecordingFile class]] ||
|
|
189
|
+
[file isKindOfClass:[TiStoreRecordingFile class]];
|
|
190
|
+
NSString* normalizedName = TiRtcReactNativeGalleryFileName(fileName, video);
|
|
191
|
+
if (normalizedName == nil) {
|
|
192
|
+
resolve(@{@"code" : @6000, @"uri" : (id)kCFNull});
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (![[NSFileManager defaultManager] isReadableFileAtPath:path]) {
|
|
196
|
+
resolve(@{@"code" : @6045, @"uri" : (id)kCFNull});
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
PHAuthorizationStatus status =
|
|
200
|
+
[PHPhotoLibrary authorizationStatusForAccessLevel:PHAccessLevelAddOnly];
|
|
201
|
+
if (status != PHAuthorizationStatusAuthorized && status != PHAuthorizationStatusLimited) {
|
|
202
|
+
resolve(@{@"code" : @6024, @"uri" : (id)kCFNull});
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
__block NSString* localIdentifier = nil;
|
|
206
|
+
[[PHPhotoLibrary sharedPhotoLibrary]
|
|
207
|
+
performChanges:^{
|
|
208
|
+
PHAssetCreationRequest* request = [PHAssetCreationRequest creationRequestForAsset];
|
|
209
|
+
PHAssetResourceCreationOptions* options = [[PHAssetResourceCreationOptions alloc] init];
|
|
210
|
+
options.originalFilename = normalizedName;
|
|
211
|
+
[request addResourceWithType:video ? PHAssetResourceTypeVideo : PHAssetResourceTypePhoto
|
|
212
|
+
fileURL:[NSURL fileURLWithPath:path]
|
|
213
|
+
options:options];
|
|
214
|
+
localIdentifier = request.placeholderForCreatedAsset.localIdentifier;
|
|
215
|
+
}
|
|
216
|
+
completionHandler:^(BOOL success, __unused NSError* error) {
|
|
217
|
+
if (!success || localIdentifier.length == 0) {
|
|
218
|
+
resolve(@{@"code" : @6046, @"uri" : (id)kCFNull});
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
void (^deleted)(int32_t) = ^(int32_t code) {
|
|
222
|
+
if (code == 0) {
|
|
223
|
+
[[self registry] releaseTransientObject:(NSInteger)objectId];
|
|
224
|
+
resolve(@{@"code" : @0,
|
|
225
|
+
@"uri" : [@"ph://" stringByAppendingString:localIdentifier]});
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
PHFetchResult<PHAsset*>* assets =
|
|
229
|
+
[PHAsset fetchAssetsWithLocalIdentifiers:@[ localIdentifier ] options:nil];
|
|
230
|
+
[[PHPhotoLibrary sharedPhotoLibrary]
|
|
231
|
+
performChanges:^{ [PHAssetChangeRequest deleteAssets:assets]; }
|
|
232
|
+
completionHandler:^(__unused BOOL rolledBack, __unused NSError* rollbackError) {
|
|
233
|
+
resolve(@{@"code" : @(TiRtcReactNativeNormalizeDarwin(code)),
|
|
234
|
+
@"uri" : (id)kCFNull});
|
|
235
|
+
}];
|
|
236
|
+
};
|
|
237
|
+
[file deleteWithCompletion:deleted];
|
|
238
|
+
}];
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
- (void)mediaFileDelete:(double)objectId
|
|
242
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
243
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
244
|
+
id file = [[self registry] transientObjectForId:(NSInteger)objectId];
|
|
245
|
+
if (![file isKindOfClass:[TiRtcRecordingFile class]] &&
|
|
246
|
+
![file isKindOfClass:[TiRtcSnapshotFile class]] &&
|
|
247
|
+
![file isKindOfClass:[TiStoreRecordingFile class]] &&
|
|
248
|
+
![file isKindOfClass:[TiStoreSnapshotFile class]]) {
|
|
249
|
+
resolve(@(TiRtcReactNativeErrorObjectReleased));
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
[file deleteWithCompletion:^(int32_t code) {
|
|
253
|
+
if (code == 0) {
|
|
254
|
+
[[self registry] releaseTransientObject:(NSInteger)objectId];
|
|
255
|
+
}
|
|
256
|
+
resolve(@(TiRtcReactNativeNormalizeDarwin(code)));
|
|
257
|
+
}];
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
- (void)mediaFileRelease:(double)objectId {
|
|
261
|
+
[[self registry] releaseTransientObject:(NSInteger)objectId];
|
|
262
|
+
}
|
|
263
|
+
|
|
99
264
|
- (NSDictionary*)connGetMetricsSnapshot:(double)objectId {
|
|
100
265
|
TiRtcConn* conn = [self conn:objectId];
|
|
101
266
|
return conn == nil ? TiRtcReactNativeReleasedSnapshotResult()
|
|
@@ -104,8 +269,14 @@
|
|
|
104
269
|
|
|
105
270
|
- (NSNumber*)connDispose:(double)objectId {
|
|
106
271
|
TiRtcConn* conn = [self conn:objectId];
|
|
107
|
-
|
|
108
|
-
|
|
272
|
+
if (conn == nil) {
|
|
273
|
+
return @(TiRtcReactNativeErrorObjectReleased);
|
|
274
|
+
}
|
|
275
|
+
NSInteger code = TiRtcReactNativeNormalizeDarwin([conn dispose]);
|
|
276
|
+
if (code == TiRtcReactNativeErrorOK) {
|
|
277
|
+
[self releaseRegisteredObject:(NSInteger)objectId object:conn];
|
|
278
|
+
}
|
|
279
|
+
return @(code);
|
|
109
280
|
}
|
|
110
281
|
|
|
111
282
|
@end
|
|
@@ -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;
|