tirtc-react-native 2.2.0

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 (104) hide show
  1. package/LICENSE +11 -0
  2. package/README.md +140 -0
  3. package/TiRtcReactNative.podspec +35 -0
  4. package/android/build.gradle +37 -0
  5. package/android/src/main/AndroidManifest.xml +1 -0
  6. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcModule.kt +482 -0
  7. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcPackage.kt +43 -0
  8. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeErrors.kt +32 -0
  9. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeEventBinder.kt +99 -0
  10. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeEventSink.kt +168 -0
  11. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeMaps.kt +49 -0
  12. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeMetricsMaps.kt +173 -0
  13. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeModuleSupport.kt +91 -0
  14. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeOptions.kt +127 -0
  15. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeRegistry.kt +71 -0
  16. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcVideoInputPreviewManager.kt +109 -0
  17. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcVideoOutputViewManager.kt +109 -0
  18. package/ios/TiRtcReactNative+Conn.mm +112 -0
  19. package/ios/TiRtcReactNative+Input.mm +196 -0
  20. package/ios/TiRtcReactNative+Output.mm +172 -0
  21. package/ios/TiRtcReactNative+Private.h +28 -0
  22. package/ios/TiRtcReactNative.h +6 -0
  23. package/ios/TiRtcReactNative.mm +189 -0
  24. package/ios/TiRtcReactNativeErrors.h +18 -0
  25. package/ios/TiRtcReactNativeErrors.mm +105 -0
  26. package/ios/TiRtcReactNativeEventBinder.h +19 -0
  27. package/ios/TiRtcReactNativeEventBinder.mm +226 -0
  28. package/ios/TiRtcReactNativeEventSink.h +29 -0
  29. package/ios/TiRtcReactNativeEventSink.mm +125 -0
  30. package/ios/TiRtcReactNativeMaps.h +21 -0
  31. package/ios/TiRtcReactNativeMaps.mm +249 -0
  32. package/ios/TiRtcReactNativeNative.h +8 -0
  33. package/ios/TiRtcReactNativeOptions.h +11 -0
  34. package/ios/TiRtcReactNativeOptions.mm +123 -0
  35. package/ios/TiRtcReactNativeRegistry.h +20 -0
  36. package/ios/TiRtcReactNativeRegistry.mm +119 -0
  37. package/ios/TiRtcVideoInputPreview.h +5 -0
  38. package/ios/TiRtcVideoInputPreview.mm +149 -0
  39. package/ios/TiRtcVideoOutputView.h +5 -0
  40. package/ios/TiRtcVideoOutputView.mm +149 -0
  41. package/lib/module/audio_input.js +177 -0
  42. package/lib/module/audio_input.js.map +1 -0
  43. package/lib/module/audio_output.js +168 -0
  44. package/lib/module/audio_output.js.map +1 -0
  45. package/lib/module/conn.js +174 -0
  46. package/lib/module/conn.js.map +1 -0
  47. package/lib/module/errors.js +63 -0
  48. package/lib/module/errors.js.map +1 -0
  49. package/lib/module/events.js +37 -0
  50. package/lib/module/events.js.map +1 -0
  51. package/lib/module/index.js +9 -0
  52. package/lib/module/index.js.map +1 -0
  53. package/lib/module/logging.js +26 -0
  54. package/lib/module/logging.js.map +1 -0
  55. package/lib/module/native.js +5 -0
  56. package/lib/module/native.js.map +1 -0
  57. package/lib/module/native_object_id.js +47 -0
  58. package/lib/module/native_object_id.js.map +1 -0
  59. package/lib/module/runtime.js +27 -0
  60. package/lib/module/runtime.js.map +1 -0
  61. package/lib/module/specs/NativeTiRtc.js +3 -0
  62. package/lib/module/specs/NativeTiRtc.js.map +1 -0
  63. package/lib/module/specs/TiRtcVideoInputPreviewNativeComponent.js +24 -0
  64. package/lib/module/specs/TiRtcVideoOutputViewNativeComponent.js +24 -0
  65. package/lib/module/types.js +93 -0
  66. package/lib/module/types.js.map +1 -0
  67. package/lib/module/video_input.js +266 -0
  68. package/lib/module/video_input.js.map +1 -0
  69. package/lib/module/video_output.js +224 -0
  70. package/lib/module/video_output.js.map +1 -0
  71. package/lib/typescript/audio_input.d.ts +25 -0
  72. package/lib/typescript/audio_output.d.ts +25 -0
  73. package/lib/typescript/conn.d.ts +28 -0
  74. package/lib/typescript/errors.d.ts +19 -0
  75. package/lib/typescript/events.d.ts +6 -0
  76. package/lib/typescript/index.d.ts +9 -0
  77. package/lib/typescript/logging.d.ts +9 -0
  78. package/lib/typescript/native.d.ts +5 -0
  79. package/lib/typescript/native_object_id.d.ts +12 -0
  80. package/lib/typescript/runtime.d.ts +8 -0
  81. package/lib/typescript/specs/NativeTiRtc.d.ts +223 -0
  82. package/lib/typescript/specs/TiRtcVideoInputPreviewNativeComponent.d.ts +8 -0
  83. package/lib/typescript/specs/TiRtcVideoOutputViewNativeComponent.d.ts +8 -0
  84. package/lib/typescript/types.d.ts +281 -0
  85. package/lib/typescript/video_input.d.ts +50 -0
  86. package/lib/typescript/video_output.d.ts +46 -0
  87. package/package.json +80 -0
  88. package/react-native.config.js +10 -0
  89. package/src/audio_input.ts +205 -0
  90. package/src/audio_output.ts +202 -0
  91. package/src/conn.ts +222 -0
  92. package/src/errors.ts +81 -0
  93. package/src/events.ts +44 -0
  94. package/src/index.ts +61 -0
  95. package/src/logging.ts +33 -0
  96. package/src/native.ts +6 -0
  97. package/src/native_object_id.ts +63 -0
  98. package/src/runtime.ts +32 -0
  99. package/src/specs/NativeTiRtc.ts +256 -0
  100. package/src/specs/TiRtcVideoInputPreviewNativeComponent.ts +14 -0
  101. package/src/specs/TiRtcVideoOutputViewNativeComponent.ts +12 -0
  102. package/src/types.ts +340 -0
  103. package/src/video_input.ts +314 -0
  104. package/src/video_output.ts +273 -0
@@ -0,0 +1,273 @@
1
+ import * as React from 'react';
2
+ import {View} from 'react-native';
3
+
4
+ import {
5
+ isPositiveInt32,
6
+ isUInt8,
7
+ normalizeCreateResult,
8
+ returnReleasedIfDisposed,
9
+ TIRTC_ERROR_INVALID_ARGUMENT,
10
+ TIRTC_ERROR_OK,
11
+ } from './errors';
12
+ import {registerNativeEventHandler, unregisterNativeEventHandler} from './events';
13
+ import {
14
+ clearNativeIdentity,
15
+ readNativeIdentity,
16
+ setNativeIdentity,
17
+ subscribeNativeIdentity,
18
+ type NativeIdentity,
19
+ } from './native_object_id';
20
+ import {NativeTiRtc, NativeTiRtcVideoOutputView, type NativeTiRtcEvent} from './native';
21
+ import {TiRtcConn} from './conn';
22
+ import type {
23
+ TiRtcOnVideoOutputError,
24
+ TiRtcOnVideoOutputRenderSizeChanged,
25
+ TiRtcOnVideoOutputStateChanged,
26
+ TiRtcSize,
27
+ TiRtcVideoOutputDebugSnapshotResult,
28
+ TiRtcVideoOutputMetricsResult,
29
+ TiRtcVideoOutputOptions,
30
+ TiRtcVideoOutputState,
31
+ TiRtcVideoOutputViewProps,
32
+ } from './types';
33
+
34
+ type VideoOutputViewPropsWithoutOwner = Omit<TiRtcVideoOutputViewProps, 'output'>;
35
+
36
+ export class TiRtcVideoOutput {
37
+ private identity: NativeIdentity | null = null;
38
+ private disposed = false;
39
+ private createCode: number = TIRTC_ERROR_OK;
40
+ private currentState: TiRtcVideoOutputState = 'idle';
41
+ private currentRenderSize: TiRtcSize | null = null;
42
+ private options: Required<Omit<TiRtcVideoOutputOptions, 'maxBufferWatermarkMs'>> &
43
+ Pick<TiRtcVideoOutputOptions, 'maxBufferWatermarkMs'> = {
44
+ decoderPreference: 'auto',
45
+ bufferStrategy: 'automatic',
46
+ maxBufferWatermarkMs: undefined,
47
+ };
48
+
49
+ onStateChanged: TiRtcOnVideoOutputStateChanged | null = null;
50
+ onRenderSizeChanged: TiRtcOnVideoOutputRenderSizeChanged | null = null;
51
+ onError: TiRtcOnVideoOutputError | null = null;
52
+
53
+ constructor() {
54
+ const result = normalizeCreateResult(NativeTiRtc.createVideoOutput());
55
+ this.createCode = result.code;
56
+ if (result.code === TIRTC_ERROR_OK) {
57
+ this.adoptIdentity({objectId: result.objectId, generation: result.generation});
58
+ }
59
+ }
60
+
61
+ get state(): TiRtcVideoOutputState {
62
+ if (this.identity !== null && !this.disposed) {
63
+ const result = NativeTiRtc.videoOutputGetState(this.identity.objectId);
64
+ if (result.state !== null) {
65
+ this.currentState = result.state as TiRtcVideoOutputState;
66
+ }
67
+ }
68
+ return this.currentState;
69
+ }
70
+
71
+ get renderSize(): TiRtcSize | null {
72
+ if (this.identity !== null && !this.disposed) {
73
+ this.currentRenderSize = NativeTiRtc.videoOutputGetRenderSize(this.identity.objectId).size;
74
+ }
75
+ return this.currentRenderSize;
76
+ }
77
+
78
+ setOptions(options: TiRtcVideoOutputOptions): number {
79
+ const normalized = {
80
+ decoderPreference: options.decoderPreference ?? 'auto',
81
+ bufferStrategy: options.bufferStrategy ?? 'automatic',
82
+ maxBufferWatermarkMs: options.maxBufferWatermarkMs,
83
+ };
84
+ if (
85
+ normalized.maxBufferWatermarkMs !== undefined
86
+ && !isPositiveInt32(normalized.maxBufferWatermarkMs)
87
+ ) {
88
+ return TIRTC_ERROR_INVALID_ARGUMENT;
89
+ }
90
+ const identity = this.ensureIdentity();
91
+ if (typeof identity === 'number') {
92
+ return identity;
93
+ }
94
+ const code = NativeTiRtc.videoOutputSetOptions(identity.objectId, {
95
+ ...normalized,
96
+ maxBufferWatermarkMs: normalized.maxBufferWatermarkMs ?? null,
97
+ });
98
+ if (code === TIRTC_ERROR_OK) {
99
+ this.options = normalized;
100
+ }
101
+ return code;
102
+ }
103
+
104
+ attach(connection: TiRtcConn, streamId: number): number {
105
+ const connIdentity = readNativeIdentity(connection);
106
+ if (!isUInt8(streamId)) {
107
+ return TIRTC_ERROR_INVALID_ARGUMENT;
108
+ }
109
+ if (connIdentity === null) {
110
+ return TIRTC_ERROR_INVALID_ARGUMENT;
111
+ }
112
+ const identity = this.ensureIdentity();
113
+ if (typeof identity === 'number') {
114
+ return identity;
115
+ }
116
+ return NativeTiRtc.videoOutputAttach(identity.objectId, connIdentity.objectId, streamId);
117
+ }
118
+
119
+ detach(): number {
120
+ const released = returnReleasedIfDisposed(this.disposed);
121
+ if (released !== null) {
122
+ return released;
123
+ }
124
+ return this.identity === null ? TIRTC_ERROR_OK : NativeTiRtc.videoOutputDetach(this.identity.objectId);
125
+ }
126
+
127
+ /**
128
+ * Creates a React element bound to this output owner.
129
+ *
130
+ * The returned element renders a placeholder until this output has a live
131
+ * native identity. Attach the output to a connection before expecting remote
132
+ * frames, and dispose the output when the render surface is no longer needed.
133
+ */
134
+ view(props: VideoOutputViewPropsWithoutOwner = {}): React.ReactElement {
135
+ return React.createElement(TiRtcVideoOutputView, {
136
+ ...props,
137
+ output: this,
138
+ });
139
+ }
140
+
141
+ getMetricsSnapshot(): TiRtcVideoOutputMetricsResult {
142
+ const identity = this.ensureIdentity();
143
+ if (typeof identity === 'number') {
144
+ return {code: identity, snapshot: null};
145
+ }
146
+ return NativeTiRtc.videoOutputGetMetricsSnapshot(identity.objectId);
147
+ }
148
+
149
+ resetMetricsSession(): number {
150
+ const identity = this.ensureIdentity();
151
+ if (typeof identity === 'number') {
152
+ return identity;
153
+ }
154
+ return NativeTiRtc.videoOutputResetMetricsSession(identity.objectId);
155
+ }
156
+
157
+ getDebugSnapshot(): TiRtcVideoOutputDebugSnapshotResult {
158
+ const identity = this.ensureIdentity();
159
+ if (typeof identity === 'number') {
160
+ return {code: identity, snapshot: null};
161
+ }
162
+ return NativeTiRtc.videoOutputGetDebugSnapshot(identity.objectId);
163
+ }
164
+
165
+ dispose(): number {
166
+ if (this.disposed) {
167
+ return TIRTC_ERROR_OK;
168
+ }
169
+ if (this.identity === null) {
170
+ this.disposed = true;
171
+ this.clearCallbacks();
172
+ this.currentState = 'idle';
173
+ this.currentRenderSize = null;
174
+ return TIRTC_ERROR_OK;
175
+ }
176
+ const identity = this.identity;
177
+ const code = NativeTiRtc.videoOutputDispose(identity.objectId);
178
+ if (code === TIRTC_ERROR_OK) {
179
+ this.disposed = true;
180
+ this.identity = null;
181
+ unregisterNativeEventHandler(identity);
182
+ clearNativeIdentity(this);
183
+ this.clearCallbacks();
184
+ this.currentState = 'idle';
185
+ this.currentRenderSize = null;
186
+ }
187
+ return code;
188
+ }
189
+
190
+ private ensureIdentity(): NativeIdentity | number {
191
+ const released = returnReleasedIfDisposed(this.disposed);
192
+ if (released !== null) {
193
+ return released;
194
+ }
195
+ if (this.identity !== null) {
196
+ return this.identity;
197
+ }
198
+ return this.createCode;
199
+ }
200
+
201
+ private adoptIdentity(identity: NativeIdentity): void {
202
+ this.identity = identity;
203
+ setNativeIdentity(this, identity);
204
+ registerNativeEventHandler(identity, (event) => this.handleEvent(event));
205
+ NativeTiRtc.videoOutputSetOptions(identity.objectId, {
206
+ ...this.options,
207
+ maxBufferWatermarkMs: this.options.maxBufferWatermarkMs ?? null,
208
+ });
209
+ }
210
+
211
+ private clearCallbacks(): void {
212
+ this.onStateChanged = null;
213
+ this.onRenderSizeChanged = null;
214
+ this.onError = null;
215
+ }
216
+
217
+ private handleEvent(event: NativeTiRtcEvent): void {
218
+ if (this.disposed) {
219
+ return;
220
+ }
221
+ switch (event.type) {
222
+ case 'videoOutputStateChanged':
223
+ if (event.state !== undefined) {
224
+ this.currentState = event.state as TiRtcVideoOutputState;
225
+ this.onStateChanged?.(this.currentState);
226
+ }
227
+ break;
228
+ case 'videoOutputRenderSizeChanged':
229
+ if (event.size !== undefined) {
230
+ this.currentRenderSize = event.size;
231
+ this.onRenderSizeChanged?.(event.size);
232
+ }
233
+ break;
234
+ case 'videoOutputError':
235
+ this.onError?.(event.code ?? TIRTC_ERROR_INVALID_ARGUMENT);
236
+ break;
237
+ default:
238
+ break;
239
+ }
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Renders the remote video stream attached to a `TiRtcVideoOutput`.
245
+ *
246
+ * The component observes the owner identity and never accepts raw native ids.
247
+ * If the owner is not created, has been disposed, or is not a `TiRtcVideoOutput`,
248
+ * it renders a regular `View` with the remaining props.
249
+ */
250
+ export function TiRtcVideoOutputView(props: TiRtcVideoOutputViewProps): React.ReactElement {
251
+ const {output, resizeMode = 'contain', ...viewProps} = props as TiRtcVideoOutputViewProps;
252
+ const identity = useOwnerIdentity(output instanceof TiRtcVideoOutput ? output : null);
253
+ if (identity === null) {
254
+ return React.createElement(View, viewProps);
255
+ }
256
+ return React.createElement(NativeTiRtcVideoOutputView, {
257
+ ...viewProps,
258
+ nativeObjectId: identity.objectId,
259
+ generation: identity.generation,
260
+ resizeMode,
261
+ });
262
+ }
263
+
264
+ function useOwnerIdentity(owner: object | null): NativeIdentity | null {
265
+ const [, forceUpdate] = React.useReducer((value: number) => value + 1, 0);
266
+ React.useEffect(() => {
267
+ if (owner === null) {
268
+ return undefined;
269
+ }
270
+ return subscribeNativeIdentity(owner, forceUpdate);
271
+ }, [owner]);
272
+ return owner === null ? null : readNativeIdentity(owner);
273
+ }