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.
Files changed (77) hide show
  1. package/README.md +23 -7
  2. package/TiRtcReactNative.podspec +1 -1
  3. package/android/build.gradle +1 -1
  4. package/android/src/main/AndroidManifest.xml +2 -1
  5. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcModule.kt +585 -28
  6. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeCleanup.kt +115 -0
  7. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeEventBinder.kt +35 -8
  8. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeEventSink.kt +20 -0
  9. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeMaps.kt +62 -0
  10. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeModuleSupport.kt +6 -6
  11. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeRegistry.kt +27 -0
  12. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeStoreSupport.kt +64 -0
  13. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcVideoOutputViewManager.kt +17 -2
  14. package/ios/TiRtcReactNative+Conn.mm +173 -2
  15. package/ios/TiRtcReactNative+Input.mm +18 -4
  16. package/ios/TiRtcReactNative+Output.mm +41 -4
  17. package/ios/TiRtcReactNative+Private.h +4 -0
  18. package/ios/TiRtcReactNative+Store.mm +496 -0
  19. package/ios/TiRtcReactNative.h +2 -1
  20. package/ios/TiRtcReactNative.mm +109 -1
  21. package/ios/TiRtcReactNativeEventBinder.h +8 -0
  22. package/ios/TiRtcReactNativeEventBinder.mm +104 -0
  23. package/ios/TiRtcReactNativeEventSink.h +4 -0
  24. package/ios/TiRtcReactNativeEventSink.mm +20 -0
  25. package/ios/TiRtcReactNativeRegistry.h +5 -0
  26. package/ios/TiRtcReactNativeRegistry.mm +43 -0
  27. package/ios/TiRtcVideoOutputView.mm +11 -0
  28. package/lib/module/audio_input.js +33 -17
  29. package/lib/module/audio_input.js.map +1 -1
  30. package/lib/module/audio_output.js +27 -10
  31. package/lib/module/audio_output.js.map +1 -1
  32. package/lib/module/conn.js +31 -7
  33. package/lib/module/conn.js.map +1 -1
  34. package/lib/module/errors.js +4 -3
  35. package/lib/module/errors.js.map +1 -1
  36. package/lib/module/index.js +2 -0
  37. package/lib/module/index.js.map +1 -1
  38. package/lib/module/logging.js +9 -1
  39. package/lib/module/logging.js.map +1 -1
  40. package/lib/module/logging_internal.js +27 -0
  41. package/lib/module/logging_internal.js.map +1 -0
  42. package/lib/module/recording.js +210 -0
  43. package/lib/module/recording.js.map +1 -0
  44. package/lib/module/runtime.js +13 -5
  45. package/lib/module/runtime.js.map +1 -1
  46. package/lib/module/specs/NativeTiRtc.js.map +1 -1
  47. package/lib/module/store.js +698 -0
  48. package/lib/module/store.js.map +1 -0
  49. package/lib/module/video_input.js +40 -22
  50. package/lib/module/video_input.js.map +1 -1
  51. package/lib/module/video_output.js +51 -10
  52. package/lib/module/video_output.js.map +1 -1
  53. package/lib/typescript/audio_input.d.ts +1 -0
  54. package/lib/typescript/conn.d.ts +2 -0
  55. package/lib/typescript/errors.d.ts +3 -2
  56. package/lib/typescript/index.d.ts +4 -0
  57. package/lib/typescript/logging_internal.d.ts +2 -0
  58. package/lib/typescript/recording.d.ts +53 -0
  59. package/lib/typescript/runtime.d.ts +2 -0
  60. package/lib/typescript/specs/NativeTiRtc.d.ts +88 -0
  61. package/lib/typescript/store.d.ts +202 -0
  62. package/lib/typescript/video_input.d.ts +1 -0
  63. package/lib/typescript/video_output.d.ts +3 -0
  64. package/package.json +1 -1
  65. package/src/audio_input.ts +85 -59
  66. package/src/audio_output.ts +30 -17
  67. package/src/conn.ts +46 -28
  68. package/src/errors.ts +4 -3
  69. package/src/index.ts +54 -0
  70. package/src/logging.ts +7 -1
  71. package/src/logging_internal.ts +23 -0
  72. package/src/recording.ts +271 -0
  73. package/src/runtime.ts +14 -5
  74. package/src/specs/NativeTiRtc.ts +123 -0
  75. package/src/store.ts +760 -0
  76. package/src/video_input.ts +97 -62
  77. 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
- [conn dispose];
108
- return [self releaseRegisteredObject:(NSInteger)objectId object:conn];
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
- [input dispose];
95
- resolve([self releaseRegisteredObject:(NSInteger)objectId object:input]);
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
- [input dispose];
192
- resolve([self releaseRegisteredObject:(NSInteger)objectId object:input]);
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
- [output dispose];
89
- return [self releaseRegisteredObject:(NSInteger)objectId object:output];
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
- [output dispose];
168
- return [self releaseRegisteredObject:(NSInteger)objectId object:output];
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;