omikit-plugin 3.3.10 → 3.3.14
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/android/build.gradle
CHANGED
|
@@ -122,7 +122,7 @@ dependencies {
|
|
|
122
122
|
implementation("androidx.work:work-runtime:2.8.1")
|
|
123
123
|
implementation "androidx.security:security-crypto:1.1.0-alpha06"
|
|
124
124
|
// api 'vn.vihat.omicall:omi-sdk:2.3.23'
|
|
125
|
-
api "io.omicrm.vihat:omi-sdk:2.3.
|
|
125
|
+
api "io.omicrm.vihat:omi-sdk:2.3.94"
|
|
126
126
|
|
|
127
127
|
implementation "com.facebook.react:react-native:+" // From node_modules
|
|
128
128
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
@@ -79,7 +79,7 @@ object OmiRegistrationStatus {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
|
-
* Helper functions for parameter validation
|
|
82
|
+
* Helper functions for parameter validation and safe OmiClient access
|
|
83
83
|
*/
|
|
84
84
|
object ValidationHelper {
|
|
85
85
|
fun validateRequired(params: Map<String, String?>, promise: Promise): Boolean {
|
|
@@ -93,6 +93,24 @@ object ValidationHelper {
|
|
|
93
93
|
}
|
|
94
94
|
return true
|
|
95
95
|
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Safe OmiClient access to prevent crashes during service shutdown
|
|
99
|
+
*/
|
|
100
|
+
fun safeOmiClientAccess(context: ReactApplicationContext, action: (OmiClient) -> Unit): Boolean {
|
|
101
|
+
return try {
|
|
102
|
+
val omiClient = OmiClient.getInstance(context)
|
|
103
|
+
if (omiClient != null) {
|
|
104
|
+
action(omiClient)
|
|
105
|
+
true
|
|
106
|
+
} else {
|
|
107
|
+
false
|
|
108
|
+
}
|
|
109
|
+
} catch (e: Exception) {
|
|
110
|
+
Log.e("OMISDK", "Error accessing OmiClient: ${e.message}")
|
|
111
|
+
false
|
|
112
|
+
}
|
|
113
|
+
}
|
|
96
114
|
}
|
|
97
115
|
|
|
98
116
|
class OmikitPluginModule(reactContext: ReactApplicationContext?) :
|
|
@@ -101,10 +119,60 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
|
|
|
101
119
|
private var isIncoming: Boolean = false
|
|
102
120
|
private var isAnswerCall: Boolean = false
|
|
103
121
|
private var permissionPromise: Promise? = null
|
|
122
|
+
|
|
123
|
+
// Call state management to prevent concurrent calls
|
|
124
|
+
private var isCallInProgress: Boolean = false
|
|
125
|
+
private var lastCallTime: Long = 0
|
|
126
|
+
private val callCooldownMs: Long = 2000 // 2 seconds cooldown between calls
|
|
127
|
+
private val callStateLock = Any()
|
|
104
128
|
|
|
105
129
|
override fun getName(): String {
|
|
106
130
|
return NAME
|
|
107
131
|
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Check if we can start a new call (no concurrent calls, cooldown passed)
|
|
135
|
+
*/
|
|
136
|
+
private fun canStartNewCall(): Boolean {
|
|
137
|
+
synchronized(callStateLock) {
|
|
138
|
+
val currentTime = System.currentTimeMillis()
|
|
139
|
+
val timeSinceLastCall = currentTime - lastCallTime
|
|
140
|
+
|
|
141
|
+
// Check if call is in progress or cooldown not passed
|
|
142
|
+
if (isCallInProgress) {
|
|
143
|
+
Log.d("OMISDK", "🚫 Call blocked: Call already in progress")
|
|
144
|
+
return false
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (timeSinceLastCall < callCooldownMs) {
|
|
148
|
+
Log.d("OMISDK", "🚫 Call blocked: Cooldown period (${callCooldownMs - timeSinceLastCall}ms remaining)")
|
|
149
|
+
return false
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return true
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Mark call as started
|
|
158
|
+
*/
|
|
159
|
+
private fun markCallStarted() {
|
|
160
|
+
synchronized(callStateLock) {
|
|
161
|
+
isCallInProgress = true
|
|
162
|
+
lastCallTime = System.currentTimeMillis()
|
|
163
|
+
Log.d("OMISDK", "📞 Call started, marking in progress")
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Mark call as ended
|
|
169
|
+
*/
|
|
170
|
+
private fun markCallEnded() {
|
|
171
|
+
synchronized(callStateLock) {
|
|
172
|
+
isCallInProgress = false
|
|
173
|
+
Log.d("OMISDK", "📴 Call ended, clearing in progress flag")
|
|
174
|
+
}
|
|
175
|
+
}
|
|
108
176
|
|
|
109
177
|
|
|
110
178
|
private val handler = Handler(Looper.getMainLooper())
|
|
@@ -166,6 +234,8 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
|
|
|
166
234
|
// Reset call state variables
|
|
167
235
|
isIncoming = false
|
|
168
236
|
isAnswerCall = false
|
|
237
|
+
// Clear call progress state when remote party ends call
|
|
238
|
+
markCallEnded()
|
|
169
239
|
Log.d("OMISDK", "=>> onCallEnd AFTER RESET - isIncoming: $isIncoming, isAnswerCall: $isAnswerCall")
|
|
170
240
|
|
|
171
241
|
// Kiểm tra kiểu dữ liệu trước khi ép kiểu để tránh lỗi
|
|
@@ -851,35 +921,55 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
|
|
|
851
921
|
Manifest.permission.RECORD_AUDIO
|
|
852
922
|
)
|
|
853
923
|
val map: WritableMap = WritableNativeMap()
|
|
924
|
+
|
|
925
|
+
// Check if we can start a new call first
|
|
926
|
+
if (!canStartNewCall()) {
|
|
927
|
+
map.putInt("status", 8) // HAVE_ANOTHER_CALL
|
|
928
|
+
map.putString("_id", "")
|
|
929
|
+
map.putString("message", messageCall(8) as String)
|
|
930
|
+
promise.resolve(map)
|
|
931
|
+
return
|
|
932
|
+
}
|
|
933
|
+
|
|
854
934
|
if (audio == PackageManager.PERMISSION_GRANTED) {
|
|
855
935
|
mainScope.launch {
|
|
856
936
|
var callResult: OmiStartCallStatus? = null
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
937
|
+
try {
|
|
938
|
+
val uuid = data.getString("usrUuid") as String
|
|
939
|
+
val isVideo = data.getBoolean("isVideo")
|
|
940
|
+
|
|
941
|
+
// Mark call as started before making the actual call
|
|
942
|
+
markCallStarted()
|
|
943
|
+
|
|
944
|
+
// Check if OmiClient instance and service are ready before making call
|
|
945
|
+
val omiClient = OmiClient.getInstance(reactApplicationContext!!)
|
|
946
|
+
if (omiClient == null) {
|
|
947
|
+
callResult = null
|
|
948
|
+
markCallEnded() // Clean up state
|
|
949
|
+
} else {
|
|
869
950
|
// Add small delay to ensure service is fully initialized
|
|
870
|
-
kotlinx.coroutines.delay(
|
|
951
|
+
kotlinx.coroutines.delay(200) // Increased delay for better stability
|
|
871
952
|
|
|
953
|
+
// Call on main thread to avoid PJSIP thread registration issues
|
|
872
954
|
callResult = omiClient.startCallWithUuid(uuid = uuid, isVideo = isVideo)
|
|
873
|
-
|
|
874
|
-
//
|
|
875
|
-
callResult
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
callResult = null
|
|
879
|
-
} catch (e: Throwable) {
|
|
880
|
-
// Handle any other exceptions
|
|
881
|
-
callResult = null
|
|
955
|
+
|
|
956
|
+
// If call failed, mark as ended
|
|
957
|
+
if (callResult == null || callResult.ordinal <= 7) { // 0-7 are failure statuses
|
|
958
|
+
markCallEnded()
|
|
959
|
+
}
|
|
882
960
|
}
|
|
961
|
+
} catch (e: IllegalStateException) {
|
|
962
|
+
// Handle service not ready state
|
|
963
|
+
callResult = null
|
|
964
|
+
markCallEnded()
|
|
965
|
+
} catch (e: NullPointerException) {
|
|
966
|
+
// Handle null pointer exceptions
|
|
967
|
+
callResult = null
|
|
968
|
+
markCallEnded()
|
|
969
|
+
} catch (e: Throwable) {
|
|
970
|
+
// Handle any other exceptions including PJSIP thread issues
|
|
971
|
+
callResult = null
|
|
972
|
+
markCallEnded()
|
|
883
973
|
}
|
|
884
974
|
var statusCalltemp = callResult?.ordinal ?: 8
|
|
885
975
|
map.putInt("status", statusCalltemp)
|
|
@@ -922,11 +1012,15 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
|
|
|
922
1012
|
|
|
923
1013
|
@ReactMethod
|
|
924
1014
|
fun endCall(promise: Promise) {
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
1015
|
+
ValidationHelper.safeOmiClientAccess(reactApplicationContext!!) { omiClient ->
|
|
1016
|
+
if (isIncoming && !isAnswerCall) {
|
|
1017
|
+
omiClient.decline()
|
|
1018
|
+
} else {
|
|
1019
|
+
omiClient.hangUp()
|
|
1020
|
+
}
|
|
929
1021
|
}
|
|
1022
|
+
// Clear call state when ending call
|
|
1023
|
+
markCallEnded()
|
|
930
1024
|
promise.resolve(true)
|
|
931
1025
|
}
|
|
932
1026
|
|
|
@@ -935,15 +1029,17 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
|
|
|
935
1029
|
Log.d("OMISDK", "➡️ rejectCall called - isIncoming: $isIncoming, isAnswerCall: $isAnswerCall")
|
|
936
1030
|
if (isIncoming) {
|
|
937
1031
|
Log.d("OMISDK", "📞 Incoming call")
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1032
|
+
ValidationHelper.safeOmiClientAccess(reactApplicationContext!!) { omiClient ->
|
|
1033
|
+
if (!isAnswerCall) {
|
|
1034
|
+
Log.d("OMISDK", "🚫 Declining call with declineWithCode(true)")
|
|
1035
|
+
omiClient.declineWithCode(true) // 486 Busy Here
|
|
1036
|
+
} else {
|
|
1037
|
+
Log.d("OMISDK", "📴 Call already answered, hanging up")
|
|
1038
|
+
omiClient.hangUp()
|
|
1039
|
+
}
|
|
945
1040
|
}
|
|
946
|
-
|
|
1041
|
+
// Clear call state when rejecting call
|
|
1042
|
+
markCallEnded()
|
|
947
1043
|
promise.resolve(true)
|
|
948
1044
|
} else {
|
|
949
1045
|
Log.d("OMISDK", "📤 Not incoming call, skipping reject")
|
|
@@ -953,11 +1049,15 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
|
|
|
953
1049
|
|
|
954
1050
|
@ReactMethod
|
|
955
1051
|
fun dropCall(promise: Promise) {
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
1052
|
+
ValidationHelper.safeOmiClientAccess(reactApplicationContext!!) { omiClient ->
|
|
1053
|
+
if (isIncoming && !isAnswerCall) {
|
|
1054
|
+
omiClient.declineWithCode(false) // 603
|
|
1055
|
+
} else {
|
|
1056
|
+
omiClient.hangUp()
|
|
1057
|
+
}
|
|
960
1058
|
}
|
|
1059
|
+
// Clear call state when dropping call
|
|
1060
|
+
markCallEnded()
|
|
961
1061
|
promise.resolve(true)
|
|
962
1062
|
}
|
|
963
1063
|
|