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
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
package com.tange.ai.tirtc.reactnative
|
|
2
|
+
|
|
3
|
+
import android.os.Handler
|
|
4
|
+
import android.os.Looper
|
|
5
|
+
import com.tange.ai.tirtc.TiRtc
|
|
6
|
+
import com.tange.ai.tirtc.TiRtcAudioInput
|
|
7
|
+
import com.tange.ai.tirtc.TiRtcAudioOutput
|
|
8
|
+
import com.tange.ai.tirtc.TiRtcConn
|
|
9
|
+
import com.tange.ai.tirtc.TiRtcLogging
|
|
10
|
+
import com.tange.ai.tirtc.TiRtcRecordingFile
|
|
11
|
+
import com.tange.ai.tirtc.TiRtcRecordingTask
|
|
12
|
+
import com.tange.ai.tirtc.TiRtcSnapshotFile
|
|
13
|
+
import com.tange.ai.tirtc.TiRtcVideoInput
|
|
14
|
+
import com.tange.ai.tirtc.TiRtcVideoOutput
|
|
15
|
+
import com.tange.ai.tirtc.TiStore
|
|
16
|
+
import com.tange.ai.tirtc.TiStoreAudioOutput
|
|
17
|
+
import com.tange.ai.tirtc.TiStoreRecordingFile
|
|
18
|
+
import com.tange.ai.tirtc.TiStoreRecordingTask
|
|
19
|
+
import com.tange.ai.tirtc.TiStoreReplay
|
|
20
|
+
import com.tange.ai.tirtc.TiStoreSnapshotFile
|
|
21
|
+
import com.tange.ai.tirtc.TiStoreVideoOutput
|
|
22
|
+
import java.util.concurrent.atomic.AtomicInteger
|
|
23
|
+
|
|
24
|
+
internal object TiRtcReactNativeCleanup {
|
|
25
|
+
private const val TAG = "TIRTC_REACT_NATIVE"
|
|
26
|
+
|
|
27
|
+
fun release(objects: List<Any>, files: List<Any>) {
|
|
28
|
+
val pending = AtomicInteger(1)
|
|
29
|
+
fun retain() {
|
|
30
|
+
pending.incrementAndGet()
|
|
31
|
+
}
|
|
32
|
+
fun finish() {
|
|
33
|
+
if (pending.decrementAndGet() == 0) {
|
|
34
|
+
Handler(Looper.getMainLooper()).post { releaseOwners(objects) }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
fun delete(file: Any?) {
|
|
38
|
+
if (file == null) return
|
|
39
|
+
retain()
|
|
40
|
+
val completed: (Int) -> Unit = { code ->
|
|
41
|
+
if (code != 0) logFailure("media_delete", code)
|
|
42
|
+
finish()
|
|
43
|
+
}
|
|
44
|
+
when (file) {
|
|
45
|
+
is TiRtcRecordingFile -> file.delete(completed)
|
|
46
|
+
is TiRtcSnapshotFile -> file.delete(completed)
|
|
47
|
+
is TiStoreRecordingFile -> file.delete(completed)
|
|
48
|
+
is TiStoreSnapshotFile -> file.delete(completed)
|
|
49
|
+
else -> finish()
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
files.forEach(::delete)
|
|
54
|
+
objects.forEach { value ->
|
|
55
|
+
when (value) {
|
|
56
|
+
is TiRtcRecordingTask -> {
|
|
57
|
+
retain()
|
|
58
|
+
value.stop { result ->
|
|
59
|
+
delete(result.file)
|
|
60
|
+
finish()
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
is TiStoreRecordingTask -> {
|
|
64
|
+
retain()
|
|
65
|
+
value.stop { result ->
|
|
66
|
+
delete(result.file)
|
|
67
|
+
finish()
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
is StoreExportBridge -> {
|
|
71
|
+
retain()
|
|
72
|
+
value.invalidate { result ->
|
|
73
|
+
delete(result?.file)
|
|
74
|
+
finish()
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
finish()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private fun releaseOwners(objects: List<Any>) {
|
|
83
|
+
objects.filterIsInstance<TiStoreAudioOutput>().forEach { output ->
|
|
84
|
+
logFailure("store_audio_detach", output.detach())
|
|
85
|
+
logFailure("store_audio_dispose", output.dispose())
|
|
86
|
+
}
|
|
87
|
+
objects.filterIsInstance<TiStoreVideoOutput>().forEach { output ->
|
|
88
|
+
logFailure("store_video_detach", output.detach())
|
|
89
|
+
logFailure("store_video_view_detach", output.detachView())
|
|
90
|
+
logFailure("store_video_dispose", output.dispose())
|
|
91
|
+
}
|
|
92
|
+
objects.filterIsInstance<TiRtcAudioOutput>().forEach { logFailure("audio_output_dispose", it.dispose()) }
|
|
93
|
+
objects.filterIsInstance<TiRtcVideoOutput>().forEach { logFailure("video_output_dispose", it.dispose()) }
|
|
94
|
+
objects.filterIsInstance<TiRtcAudioInput>().forEach { logFailure("audio_input_dispose", it.dispose()) }
|
|
95
|
+
objects.filterIsInstance<TiRtcVideoInput>().forEach { logFailure("video_input_dispose", it.dispose()) }
|
|
96
|
+
objects.filterIsInstance<TiStoreReplay>().forEach { replay ->
|
|
97
|
+
logFailure("store_replay_stop", replay.stop())
|
|
98
|
+
logFailure("store_replay_dispose", replay.dispose())
|
|
99
|
+
}
|
|
100
|
+
objects.filterIsInstance<TiRtcConn>().forEach { conn ->
|
|
101
|
+
logFailure("conn_disconnect", conn.disconnect())
|
|
102
|
+
logFailure("conn_dispose", conn.dispose())
|
|
103
|
+
}
|
|
104
|
+
objects.filterIsInstance<TiStore>().forEach { logFailure("store_dispose", it.dispose()) }
|
|
105
|
+
logFailure("store_shutdown", TiStore.shutdown())
|
|
106
|
+
logFailure("runtime_shutdown", TiRtc.shutdown())
|
|
107
|
+
TiRtcLogging.i(TAG, "[module_invalidate] native owners released")
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private fun logFailure(operation: String, code: Int) {
|
|
111
|
+
if (code != 0 && code != TiRtcReactNativeErrors.OBJECT_RELEASED) {
|
|
112
|
+
TiRtcLogging.w(TAG, "[module_invalidate] operation=$operation error_code=$code")
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
package com.tange.ai.tirtc.reactnative
|
|
2
2
|
|
|
3
|
-
import android.util.Log
|
|
4
3
|
import com.tange.ai.tirtc.TiRtcAudioInput
|
|
5
4
|
import com.tange.ai.tirtc.TiRtcAudioOutput
|
|
6
5
|
import com.tange.ai.tirtc.TiRtcAudioOutputErrorListener
|
|
@@ -17,16 +16,50 @@ import com.tange.ai.tirtc.TiRtcVideoOutput
|
|
|
17
16
|
import com.tange.ai.tirtc.TiRtcVideoOutputErrorListener
|
|
18
17
|
import com.tange.ai.tirtc.TiRtcVideoOutputRenderSizeListener
|
|
19
18
|
import com.tange.ai.tirtc.TiRtcVideoOutputStateListener
|
|
19
|
+
import com.tange.ai.tirtc.TiStore
|
|
20
|
+
import com.tange.ai.tirtc.TiStoreAudioOutput
|
|
21
|
+
import com.tange.ai.tirtc.TiStoreAudioOutputStateListener
|
|
22
|
+
import com.tange.ai.tirtc.TiStoreOutputErrorListener
|
|
23
|
+
import com.tange.ai.tirtc.TiStoreReplay
|
|
24
|
+
import com.tange.ai.tirtc.TiStoreReplayCompletedListener
|
|
25
|
+
import com.tange.ai.tirtc.TiStoreReplayErrorListener
|
|
26
|
+
import com.tange.ai.tirtc.TiStoreTimeChangedListener
|
|
27
|
+
import com.tange.ai.tirtc.TiStoreTokenExpiredListener
|
|
28
|
+
import com.tange.ai.tirtc.TiStoreVideoOutput
|
|
29
|
+
import com.tange.ai.tirtc.TiStoreVideoOutputStateListener
|
|
20
30
|
|
|
21
31
|
internal class TiRtcReactNativeEventBinder(
|
|
22
32
|
private val events: TiRtcReactNativeEventSink,
|
|
23
33
|
) {
|
|
34
|
+
fun wireStore(id: Int, store: TiStore) {
|
|
35
|
+
store.onTokenExpired = TiStoreTokenExpiredListener { events.storeTokenExpired(id) }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
fun wireStoreReplay(id: Int, replay: TiStoreReplay) {
|
|
39
|
+
replay.onTimeChanged = TiStoreTimeChangedListener { events.storeReplayTimeChanged(id, it) }
|
|
40
|
+
replay.onCompleted = TiStoreReplayCompletedListener { events.storeReplayCompleted(id) }
|
|
41
|
+
replay.onError = TiStoreReplayErrorListener { events.storeReplayError(id, it) }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
fun wireStoreAudioOutput(id: Int, output: TiStoreAudioOutput) {
|
|
45
|
+
output.onStateChanged = TiStoreAudioOutputStateListener {
|
|
46
|
+
events.audioOutputStateChanged(id, it.name.lowercase())
|
|
47
|
+
}
|
|
48
|
+
output.onError = TiStoreOutputErrorListener { events.audioOutputError(id, it) }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
fun wireStoreVideoOutput(id: Int, output: TiStoreVideoOutput) {
|
|
52
|
+
output.onStateChanged = TiStoreVideoOutputStateListener {
|
|
53
|
+
events.videoOutputStateChanged(id, it.name.lowercase())
|
|
54
|
+
}
|
|
55
|
+
output.onError = TiStoreOutputErrorListener { events.videoOutputError(id, it) }
|
|
56
|
+
}
|
|
57
|
+
|
|
24
58
|
fun wireConn(
|
|
25
59
|
id: Int,
|
|
26
60
|
conn: TiRtcConn,
|
|
27
61
|
) {
|
|
28
62
|
conn.onStateChanged = TiRtcConnStateListener { state, errorCode ->
|
|
29
|
-
Log.i(TAG, "connStateChanged objectId=$id state=${state.name.lowercase()} code=$errorCode")
|
|
30
63
|
events.connStateChanged(id, state.name.lowercase(), errorCode)
|
|
31
64
|
}
|
|
32
65
|
conn.onCommand = TiRtcConnCommandListener { command, data ->
|
|
@@ -69,7 +102,6 @@ internal class TiRtcReactNativeEventBinder(
|
|
|
69
102
|
input: TiRtcAudioInput,
|
|
70
103
|
) {
|
|
71
104
|
input.onStateChanged = TiRtcInputStateListener { state ->
|
|
72
|
-
Log.i(TAG, "audioInputStateChanged objectId=$id state=${state.name.lowercase()}")
|
|
73
105
|
events.audioInputStateChanged(id, state.name.lowercase())
|
|
74
106
|
}
|
|
75
107
|
input.onError = TiRtcInputErrorListener { code, message ->
|
|
@@ -82,7 +114,6 @@ internal class TiRtcReactNativeEventBinder(
|
|
|
82
114
|
input: TiRtcVideoInput,
|
|
83
115
|
) {
|
|
84
116
|
input.onStateChanged = TiRtcInputStateListener { state ->
|
|
85
|
-
Log.i(TAG, "videoInputStateChanged objectId=$id state=${state.name.lowercase()}")
|
|
86
117
|
events.videoInputStateChanged(id, state.name.lowercase())
|
|
87
118
|
}
|
|
88
119
|
input.onActualConfigChanged = TiRtcVideoInputActualConfigListener { size, fps ->
|
|
@@ -92,8 +123,4 @@ internal class TiRtcReactNativeEventBinder(
|
|
|
92
123
|
events.videoInputError(id, code, message)
|
|
93
124
|
}
|
|
94
125
|
}
|
|
95
|
-
|
|
96
|
-
private companion object {
|
|
97
|
-
const val TAG = "TiRtcReactNative"
|
|
98
|
-
}
|
|
99
126
|
}
|
|
@@ -44,6 +44,26 @@ internal class TiRtcReactNativeEventSink(
|
|
|
44
44
|
})
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
fun storeTokenExpired(objectId: Int) {
|
|
48
|
+
emit(base("storeTokenExpired", objectId))
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
fun storeReplayTimeChanged(objectId: Int, timestampMs: Long) {
|
|
52
|
+
emit(base("storeReplayTimeChanged", objectId).apply {
|
|
53
|
+
putDouble("timestampMs", timestampMs.toDouble())
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
fun storeReplayCompleted(objectId: Int) {
|
|
58
|
+
emit(base("storeReplayCompleted", objectId))
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
fun storeReplayError(objectId: Int, code: Int) {
|
|
62
|
+
emit(base("storeReplayError", objectId).apply {
|
|
63
|
+
putInt("code", TiRtcReactNativeErrors.normalizeAndroid(code))
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
47
67
|
fun audioOutputStateChanged(
|
|
48
68
|
objectId: Int,
|
|
49
69
|
state: String,
|
|
@@ -2,6 +2,68 @@ package com.tange.ai.tirtc.reactnative
|
|
|
2
2
|
|
|
3
3
|
import com.facebook.react.bridge.Arguments
|
|
4
4
|
import com.facebook.react.bridge.WritableMap
|
|
5
|
+
import com.tange.ai.tirtc.TiStoreRecordingRange
|
|
6
|
+
import com.tange.ai.tirtc.TiStoreRecordingDay
|
|
7
|
+
|
|
8
|
+
internal fun recordingStartResult(code: Int, taskId: Int?): WritableMap =
|
|
9
|
+
Arguments.createMap().apply {
|
|
10
|
+
putInt("code", TiRtcReactNativeErrors.normalizeAndroid(code))
|
|
11
|
+
if (taskId == null) putNull("taskId") else putInt("taskId", taskId)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
internal fun storeRecordingsResult(code: Int, ranges: List<TiStoreRecordingRange>): WritableMap =
|
|
15
|
+
Arguments.createMap().apply {
|
|
16
|
+
putInt("code", code)
|
|
17
|
+
putArray("recordings", Arguments.createArray().apply {
|
|
18
|
+
ranges.forEach { range ->
|
|
19
|
+
pushMap(Arguments.createMap().apply {
|
|
20
|
+
putDouble("startTimeMs", range.startTimeMs.toDouble())
|
|
21
|
+
putDouble("endTimeMs", range.endTimeMs.toDouble())
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
internal fun storeRecordingDaysResult(code: Int, days: List<TiStoreRecordingDay>): WritableMap =
|
|
28
|
+
Arguments.createMap().apply {
|
|
29
|
+
putInt("code", code)
|
|
30
|
+
putArray("days", Arguments.createArray().apply {
|
|
31
|
+
days.forEach { day ->
|
|
32
|
+
pushMap(Arguments.createMap().apply {
|
|
33
|
+
putString("date", day.date)
|
|
34
|
+
putBoolean("hasRecording", day.hasRecording)
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
internal fun storeReplayInfoResult(code: Int, speed: Int, currentTimeMs: Long?): WritableMap =
|
|
41
|
+
Arguments.createMap().apply {
|
|
42
|
+
putInt("code", code)
|
|
43
|
+
putInt("speed", speed)
|
|
44
|
+
if (currentTimeMs == null) putNull("currentTimeMs") else putDouble("currentTimeMs", currentTimeMs.toDouble())
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
internal fun mp4Result(code: Int, fileId: Int?, filePath: String?, durationMs: Long?): WritableMap =
|
|
48
|
+
Arguments.createMap().apply {
|
|
49
|
+
putInt("code", TiRtcReactNativeErrors.normalizeAndroid(code))
|
|
50
|
+
if (fileId == null) putNull("fileId") else putInt("fileId", fileId)
|
|
51
|
+
if (filePath == null) putNull("filePath") else putString("filePath", filePath)
|
|
52
|
+
if (durationMs == null) putNull("durationMs") else putDouble("durationMs", durationMs.toDouble())
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
internal fun mediaSnapshotResult(code: Int, fileId: Int?, filePath: String?): WritableMap =
|
|
56
|
+
Arguments.createMap().apply {
|
|
57
|
+
putInt("code", TiRtcReactNativeErrors.normalizeAndroid(code))
|
|
58
|
+
if (fileId == null) putNull("fileId") else putInt("fileId", fileId)
|
|
59
|
+
if (filePath == null) putNull("filePath") else putString("filePath", filePath)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
internal fun galleryResult(code: Int, uri: String?): WritableMap =
|
|
63
|
+
Arguments.createMap().apply {
|
|
64
|
+
putInt("code", TiRtcReactNativeErrors.normalizeAndroid(code))
|
|
65
|
+
if (uri == null) putNull("uri") else putString("uri", uri)
|
|
66
|
+
}
|
|
5
67
|
|
|
6
68
|
internal fun createResult(
|
|
7
69
|
code: Int,
|
package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeModuleSupport.kt
CHANGED
|
@@ -2,7 +2,6 @@ package com.tange.ai.tirtc.reactnative
|
|
|
2
2
|
|
|
3
3
|
import android.os.Handler
|
|
4
4
|
import android.os.Looper
|
|
5
|
-
import android.util.Log
|
|
6
5
|
import com.facebook.react.bridge.Arguments
|
|
7
6
|
import com.facebook.react.bridge.Promise
|
|
8
7
|
import com.facebook.react.bridge.ReadableArray
|
|
@@ -11,18 +10,21 @@ import com.tange.ai.tirtc.TiRtcLogging
|
|
|
11
10
|
import java.util.concurrent.atomic.AtomicBoolean
|
|
12
11
|
|
|
13
12
|
private const val LOG_UPLOAD_TIMEOUT_MS = 30_000L
|
|
13
|
+
private const val TAG = "TiRtcReactNative"
|
|
14
14
|
|
|
15
15
|
internal fun uploadLogsToPromise(
|
|
16
16
|
promise: Promise,
|
|
17
|
-
tag: String,
|
|
18
17
|
) {
|
|
19
|
-
Log.i(tag, "uploadLogs start")
|
|
20
18
|
val settled = AtomicBoolean(false)
|
|
21
19
|
val timeoutHandler = Handler(Looper.getMainLooper())
|
|
22
20
|
val timeout =
|
|
23
21
|
Runnable {
|
|
24
22
|
if (settled.compareAndSet(false, true)) {
|
|
25
|
-
|
|
23
|
+
TiRtcLogging.e(
|
|
24
|
+
TAG,
|
|
25
|
+
"[react_native_log_upload] failed: native upload did not settle the Promise before timeout; " +
|
|
26
|
+
"error_code=1001 reason=promise_timeout",
|
|
27
|
+
)
|
|
26
28
|
promise.resolve(
|
|
27
29
|
Arguments.createMap().apply {
|
|
28
30
|
putInt("code", TiRtcReactNativeErrors.PLATFORM_INTERNAL)
|
|
@@ -37,7 +39,6 @@ internal fun uploadLogsToPromise(
|
|
|
37
39
|
return@upload
|
|
38
40
|
}
|
|
39
41
|
timeoutHandler.removeCallbacks(timeout)
|
|
40
|
-
Log.i(tag, "uploadLogs completed code=$code logIdPresent=${!logId.isNullOrEmpty()}")
|
|
41
42
|
promise.resolve(
|
|
42
43
|
Arguments.createMap().apply {
|
|
43
44
|
putInt("code", TiRtcReactNativeErrors.normalizeAndroid(code))
|
|
@@ -50,7 +51,6 @@ internal fun uploadLogsToPromise(
|
|
|
50
51
|
return
|
|
51
52
|
}
|
|
52
53
|
timeoutHandler.removeCallbacks(timeout)
|
|
53
|
-
Log.w(tag, "uploadLogs failed_to_start code=$startCode")
|
|
54
54
|
promise.resolve(
|
|
55
55
|
Arguments.createMap().apply {
|
|
56
56
|
putInt("code", TiRtcReactNativeErrors.normalizeAndroid(startCode))
|
|
@@ -5,6 +5,12 @@ import com.tange.ai.tirtc.TiRtcAudioOutput
|
|
|
5
5
|
import com.tange.ai.tirtc.TiRtcConn
|
|
6
6
|
import com.tange.ai.tirtc.TiRtcVideoInput
|
|
7
7
|
import com.tange.ai.tirtc.TiRtcVideoOutput
|
|
8
|
+
import com.tange.ai.tirtc.TiRtcRecordingTask
|
|
9
|
+
import com.tange.ai.tirtc.TiStore
|
|
10
|
+
import com.tange.ai.tirtc.TiStoreAudioOutput
|
|
11
|
+
import com.tange.ai.tirtc.TiStoreRecordingTask
|
|
12
|
+
import com.tange.ai.tirtc.TiStoreReplay
|
|
13
|
+
import com.tange.ai.tirtc.TiStoreVideoOutput
|
|
8
14
|
import java.util.concurrent.ConcurrentHashMap
|
|
9
15
|
import java.util.concurrent.atomic.AtomicInteger
|
|
10
16
|
|
|
@@ -32,6 +38,13 @@ internal object TiRtcReactNativeRegistry {
|
|
|
32
38
|
events = eventSink
|
|
33
39
|
}
|
|
34
40
|
|
|
41
|
+
fun drain(eventSink: TiRtcReactNativeEventSink): List<Any> {
|
|
42
|
+
val values = entries.values.map(Entry::value)
|
|
43
|
+
entries.clear()
|
|
44
|
+
if (events === eventSink) events = null
|
|
45
|
+
return values
|
|
46
|
+
}
|
|
47
|
+
|
|
35
48
|
fun release(id: Int) {
|
|
36
49
|
entries.remove(id)
|
|
37
50
|
}
|
|
@@ -48,6 +61,20 @@ internal object TiRtcReactNativeRegistry {
|
|
|
48
61
|
|
|
49
62
|
fun videoInput(id: Int): TiRtcVideoInput? = entries[id]?.value as? TiRtcVideoInput
|
|
50
63
|
|
|
64
|
+
fun recordingTask(id: Int): TiRtcRecordingTask? = entries[id]?.value as? TiRtcRecordingTask
|
|
65
|
+
|
|
66
|
+
fun store(id: Int): TiStore? = entries[id]?.value as? TiStore
|
|
67
|
+
|
|
68
|
+
fun storeReplay(id: Int): TiStoreReplay? = entries[id]?.value as? TiStoreReplay
|
|
69
|
+
|
|
70
|
+
fun storeRecordingTask(id: Int): TiStoreRecordingTask? = entries[id]?.value as? TiStoreRecordingTask
|
|
71
|
+
|
|
72
|
+
fun storeExportTask(id: Int): StoreExportBridge? = entries[id]?.value as? StoreExportBridge
|
|
73
|
+
|
|
74
|
+
fun storeAudioOutput(id: Int): TiStoreAudioOutput? = entries[id]?.value as? TiStoreAudioOutput
|
|
75
|
+
|
|
76
|
+
fun storeVideoOutput(id: Int): TiStoreVideoOutput? = entries[id]?.value as? TiStoreVideoOutput
|
|
77
|
+
|
|
51
78
|
fun reportVideoOutputError(
|
|
52
79
|
id: Int,
|
|
53
80
|
code: Int,
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
package com.tange.ai.tirtc.reactnative
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Promise
|
|
4
|
+
import com.tange.ai.tirtc.TiStoreExportTask
|
|
5
|
+
import com.tange.ai.tirtc.TiStoreRecordingResult
|
|
6
|
+
|
|
7
|
+
internal class StoreExportBridge(
|
|
8
|
+
private val resolve: (Promise, TiStoreRecordingResult) -> Unit,
|
|
9
|
+
) {
|
|
10
|
+
@Volatile var task: TiStoreExportTask? = null
|
|
11
|
+
@Volatile var onDrained: (() -> Unit)? = null
|
|
12
|
+
private var result: TiStoreRecordingResult? = null
|
|
13
|
+
private val waiters = mutableListOf<Promise>()
|
|
14
|
+
private var invalidated = false
|
|
15
|
+
private var invalidationCompletion: ((TiStoreRecordingResult?) -> Unit)? = null
|
|
16
|
+
|
|
17
|
+
fun complete(value: TiStoreRecordingResult) {
|
|
18
|
+
val completed = synchronized(this) {
|
|
19
|
+
if (result != null) return
|
|
20
|
+
result = value
|
|
21
|
+
val pending = if (invalidated) emptyList() else waiters.toList()
|
|
22
|
+
waiters.clear()
|
|
23
|
+
pending to invalidationCompletion.also { invalidationCompletion = null }
|
|
24
|
+
}
|
|
25
|
+
completed.first.forEach { resolve(it, value) }
|
|
26
|
+
if (completed.first.isNotEmpty()) onDrained?.invoke()
|
|
27
|
+
completed.second?.invoke(value)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
fun await(promise: Promise) {
|
|
31
|
+
val completed = synchronized(this) {
|
|
32
|
+
result?.also { return@synchronized it } ?: run {
|
|
33
|
+
waiters += promise
|
|
34
|
+
null
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (completed != null) {
|
|
38
|
+
resolve(promise, completed)
|
|
39
|
+
onDrained?.invoke()
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
fun invalidate(onTerminal: (TiStoreRecordingResult?) -> Unit) {
|
|
44
|
+
val completed = synchronized(this) {
|
|
45
|
+
invalidated = true
|
|
46
|
+
waiters.clear()
|
|
47
|
+
result?.also { return@synchronized it } ?: run {
|
|
48
|
+
invalidationCompletion = onTerminal
|
|
49
|
+
null
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (completed != null) {
|
|
53
|
+
onTerminal(completed)
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
val code = task?.stop() ?: TiRtcReactNativeErrors.OBJECT_RELEASED
|
|
57
|
+
if (code != 0) {
|
|
58
|
+
synchronized(this) {
|
|
59
|
+
invalidationCompletion = null
|
|
60
|
+
}
|
|
61
|
+
onTerminal(null)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -22,7 +22,7 @@ class TiRtcVideoOutputViewManager :
|
|
|
22
22
|
|
|
23
23
|
override fun onDropViewInstance(view: FrameLayout) {
|
|
24
24
|
(view.getTag(ATTACHED_ID_TAG) as? Int)?.let { id ->
|
|
25
|
-
|
|
25
|
+
detachView(id)
|
|
26
26
|
}
|
|
27
27
|
super.onDropViewInstance(view)
|
|
28
28
|
}
|
|
@@ -63,7 +63,7 @@ class TiRtcVideoOutputViewManager :
|
|
|
63
63
|
val attachedId = view.getTag(ATTACHED_ID_TAG) as? Int
|
|
64
64
|
val attachedGeneration = view.getTag(ATTACHED_GENERATION_TAG) as? Int
|
|
65
65
|
if (attachedId != null && (attachedId != nativeObjectId || attachedGeneration != generation)) {
|
|
66
|
-
|
|
66
|
+
detachView(attachedId)
|
|
67
67
|
view.setTag(ATTACHED_ID_TAG, null)
|
|
68
68
|
view.setTag(ATTACHED_GENERATION_TAG, null)
|
|
69
69
|
}
|
|
@@ -86,7 +86,22 @@ class TiRtcVideoOutputViewManager :
|
|
|
86
86
|
}
|
|
87
87
|
view.setTag(ATTACHED_ID_TAG, nativeObjectId)
|
|
88
88
|
view.setTag(ATTACHED_GENERATION_TAG, generation)
|
|
89
|
+
return
|
|
89
90
|
}
|
|
91
|
+
TiRtcReactNativeRegistry.storeVideoOutput(nativeObjectId)?.let { output ->
|
|
92
|
+
val code = output.attachView(view)
|
|
93
|
+
if (TiRtcReactNativeErrors.normalizeAndroid(code) != TiRtcReactNativeErrors.OK) {
|
|
94
|
+
TiRtcReactNativeRegistry.reportVideoOutputError(nativeObjectId, code)
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
view.setTag(ATTACHED_ID_TAG, nativeObjectId)
|
|
98
|
+
view.setTag(ATTACHED_GENERATION_TAG, generation)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private fun detachView(id: Int) {
|
|
103
|
+
TiRtcReactNativeRegistry.videoOutput(id)?.detachView()
|
|
104
|
+
?: TiRtcReactNativeRegistry.storeVideoOutput(id)?.detachView()
|
|
90
105
|
}
|
|
91
106
|
|
|
92
107
|
private fun resizeModeForView(view: FrameLayout): TiRtcVideoViewResizeMode =
|