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.
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 +622 -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 +32 -8
  8. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeEventSink.kt +16 -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/TiRtcReactNativeStorageSupport.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+Storage.mm +513 -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 +102 -0
  23. package/ios/TiRtcReactNativeEventSink.h +3 -0
  24. package/ios/TiRtcReactNativeEventSink.mm +16 -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/storage.js +706 -0
  48. package/lib/module/storage.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/storage.d.ts +204 -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/storage.ts +769 -0
  76. package/src/video_input.ts +97 -62
  77. 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
- [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;
@@ -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
@@ -1,6 +1,7 @@
1
1
  #import <Foundation/Foundation.h>
2
+ #import <React/RCTInvalidating.h>
2
3
 
3
4
  #import "TiRtcSpec.h"
4
5
 
5
- @interface TiRtcReactNative : NativeTiRtcSpecBase <NativeTiRtcSpec>
6
+ @interface TiRtcReactNative : NativeTiRtcSpecBase <NativeTiRtcSpec, RCTInvalidating>
6
7
  @end