omikit-plugin 1.0.1 → 2.0.1

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 (47) hide show
  1. package/README.md +99 -15
  2. package/android/build.gradle +1 -1
  3. package/android/src/main/java/com/omikitplugin/FLLocalCameraModule.kt +37 -0
  4. package/android/src/main/java/com/omikitplugin/FLLocalCameraView.kt +23 -0
  5. package/android/src/main/java/com/omikitplugin/FLRemoteCameraModule.kt +37 -0
  6. package/android/src/main/java/com/omikitplugin/FLRemoteCameraView.kt +23 -0
  7. package/android/src/main/java/com/omikitplugin/OmikitPluginModule.kt +249 -85
  8. package/android/src/main/java/com/omikitplugin/OmikitPluginPackage.kt +21 -2
  9. package/android/src/main/java/com/omikitplugin/constants/constant.kt +23 -12
  10. package/ios/CallProcess/CallManager.swift +109 -71
  11. package/ios/Constant/Constant.swift +15 -10
  12. package/ios/OmikitPlugin.m +34 -2
  13. package/ios/OmikitPlugin.swift +70 -32
  14. package/ios/VideoCall/FLLocalCameraView.m +17 -0
  15. package/ios/VideoCall/FLLocalCameraView.swift +41 -80
  16. package/ios/VideoCall/FLRemoteCameraView.m +18 -0
  17. package/ios/VideoCall/FLRemoteCameraView.swift +39 -1
  18. package/lib/commonjs/index.js +32 -64
  19. package/lib/commonjs/index.js.map +1 -1
  20. package/lib/commonjs/omi_local_camera.js +15 -0
  21. package/lib/commonjs/omi_local_camera.js.map +1 -0
  22. package/lib/commonjs/omi_remote_camera.js +15 -0
  23. package/lib/commonjs/omi_remote_camera.js.map +1 -0
  24. package/lib/commonjs/omikit.js +98 -0
  25. package/lib/commonjs/omikit.js.map +1 -0
  26. package/lib/module/index.js +3 -51
  27. package/lib/module/index.js.map +1 -1
  28. package/lib/module/omi_local_camera.js +7 -0
  29. package/lib/module/omi_local_camera.js.map +1 -0
  30. package/lib/module/omi_remote_camera.js +7 -0
  31. package/lib/module/omi_remote_camera.js.map +1 -0
  32. package/lib/module/omikit.js +73 -0
  33. package/lib/module/omikit.js.map +1 -0
  34. package/lib/typescript/index.d.ts +3 -19
  35. package/lib/typescript/index.d.ts.map +1 -1
  36. package/lib/typescript/omi_local_camera.d.ts +5 -0
  37. package/lib/typescript/omi_local_camera.d.ts.map +1 -0
  38. package/lib/typescript/omi_remote_camera.d.ts +5 -0
  39. package/lib/typescript/omi_remote_camera.d.ts.map +1 -0
  40. package/lib/typescript/omikit.d.ts +26 -0
  41. package/lib/typescript/omikit.d.ts.map +1 -0
  42. package/omikit-plugin.podspec +1 -1
  43. package/package.json +1 -1
  44. package/src/index.tsx +3 -71
  45. package/src/omi_local_camera.tsx +11 -0
  46. package/src/omi_remote_camera.tsx +11 -0
  47. package/src/omikit.tsx +98 -0
@@ -4,12 +4,18 @@ import android.Manifest
4
4
  import android.content.Context
5
5
  import android.hardware.camera2.CameraManager
6
6
  import android.os.Build
7
+ import android.os.Handler
7
8
  import android.util.Log
8
9
  import androidx.core.app.ActivityCompat
9
10
  import com.facebook.react.ReactActivity
10
11
  import com.facebook.react.bridge.*
11
12
  import com.facebook.react.modules.core.RCTNativeAppEventEmitter
12
13
  import com.omikitplugin.constants.*
14
+ import kotlinx.coroutines.CoroutineScope
15
+ import kotlinx.coroutines.Dispatchers
16
+ import kotlinx.coroutines.launch
17
+ import kotlinx.coroutines.withContext
18
+ import vn.vihat.omicall.omisdk.OmiAccountListener
13
19
  import vn.vihat.omicall.omisdk.OmiClient
14
20
  import vn.vihat.omicall.omisdk.OmiListener
15
21
  import vn.vihat.omicall.omisdk.utils.OmiSDKUtils
@@ -17,10 +23,11 @@ import vn.vihat.omicall.omisdk.utils.OmiSDKUtils
17
23
 
18
24
  class OmikitPluginModule(reactContext: ReactApplicationContext?) :
19
25
  ReactContextBaseJavaModule(reactContext) {
26
+ private val mainScope = CoroutineScope(Dispatchers.Main)
20
27
 
21
-
22
- private var icSpeaker = false
23
- private var isMute = false
28
+ override fun getName(): String {
29
+ return NAME
30
+ }
24
31
 
25
32
  private val callListener = object : OmiListener {
26
33
 
@@ -42,11 +49,13 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
42
49
  isVideo: Boolean?,
43
50
  startTime: Long,
44
51
  ) {
45
- val map: WritableMap = WritableNativeMap()
46
- val sipNumber = OmiClient.instance.callUUID
47
- map.putString("callerNumber", sipNumber)
48
- map.putBoolean("isVideo", isVideo ?: true)
49
- sendEvent(CALL_ESTABLISHED, map)
52
+ Handler().postDelayed({
53
+ Log.d("OmikitReactNative", "onCallEstablished")
54
+ val map: WritableMap = WritableNativeMap()
55
+ map.putString("callerNumber", phoneNumber)
56
+ map.putBoolean("isVideo", isVideo ?: true)
57
+ sendEvent(CALL_ESTABLISHED, map)
58
+ }, 500)
50
59
  }
51
60
 
52
61
  override fun onConnectionTimeout() {
@@ -54,9 +63,9 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
54
63
  }
55
64
 
56
65
  override fun onHold(isHold: Boolean) {
57
- val map: WritableMap = WritableNativeMap()
58
- map.putBoolean("isHold", isHold)
59
- sendEvent(HOLD, map)
66
+ // val map: WritableMap = WritableNativeMap()
67
+ // map.putBoolean("isHold", isHold)
68
+ // sendEvent(HOLD, map)
60
69
  }
61
70
 
62
71
  override fun onMuted(isMuted: Boolean) {
@@ -78,18 +87,61 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
78
87
  }
79
88
  }
80
89
 
81
- override fun getName(): String {
82
- return NAME
90
+ private val accountListener = object : OmiAccountListener {
91
+ override fun onAccountStatus(online: Boolean) {
92
+ Log.d("aaa", "Account status $online")
93
+ // initResult?.success(online)
94
+ // initResult = null
95
+ }
83
96
  }
84
97
 
85
98
  override fun initialize() {
86
99
  super.initialize()
87
- OmiClient(reactApplicationContext!!)
100
+ }
101
+
102
+ @ReactMethod
103
+ fun startServices(promise: Promise) {
104
+ OmiClient(context = reactApplicationContext!!)
88
105
  OmiClient.instance.setListener(callListener)
106
+ OmiClient.instance.addAccountListener(accountListener)
107
+ val needSetupVideo = OmiClient.instance.needSetupCamera()
108
+ if (needSetupVideo) {
109
+ setCamera()
110
+ }
111
+ promise.resolve(true)
89
112
  }
90
113
 
91
114
  @ReactMethod
92
- fun initCall(data: ReadableMap, promise: Promise) {
115
+ fun configPushNotification(data: ReadableMap, promise: Promise) {
116
+ currentActivity?.runOnUiThread {
117
+ val prefix = data.getString("prefix")
118
+ val declineTitle = data.getString("declineTitle")
119
+ val acceptTitle = data.getString("acceptTitle")
120
+ val acceptBackgroundColor = data.getString("acceptBackgroundColor")
121
+ val declineBackgroundColor = data.getString("declineBackgroundColor")
122
+ val incomingBackgroundColor = data.getString("incomingBackgroundColor")
123
+ val incomingAcceptButtonImage = data.getString("incomingAcceptButtonImage")
124
+ val incomingDeclineButtonImage = data.getString("incomingDeclineButtonImage")
125
+ val backImage = data.getString("backImage")
126
+ val userImage = data.getString("userImage")
127
+ OmiClient.instance.configPushNotification(
128
+ prefix = prefix ?: "Cuộc gọi tới từ: ",
129
+ declineTitle = declineTitle ?: "Từ chối",
130
+ acceptTitle = acceptTitle ?: "Chấp nhận",
131
+ acceptBackgroundColor = acceptBackgroundColor ?: "#FF3700B3",
132
+ declineBackgroundColor = declineBackgroundColor ?: "#FF000000",
133
+ incomingBackgroundColor = incomingBackgroundColor ?: "#FFFFFFFF",
134
+ incomingAcceptButtonImage = incomingAcceptButtonImage ?: "join_call",
135
+ incomingDeclineButtonImage = incomingDeclineButtonImage ?: "hangup",
136
+ backImage = backImage ?: "ic_back",
137
+ userImage = userImage ?: "calling_face",
138
+ )
139
+ promise.resolve(true)
140
+ }
141
+ }
142
+
143
+ @ReactMethod
144
+ fun initCallWithUserPassword(data: ReadableMap, promise: Promise) {
93
145
  currentActivity?.runOnUiThread {
94
146
  val userName = data.getString("userName")
95
147
  val password = data.getString("password")
@@ -98,123 +150,209 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
98
150
  val isVideo = data.getBoolean("isVideo")
99
151
  if (userName != null && password != null && realm != null && host != null) {
100
152
  OmiClient.register(
101
- reactApplicationContext!!,
102
153
  userName,
103
154
  password,
104
155
  isVideo,
105
156
  realm,
106
- host = host,
107
- customUI = true,
108
- isTcp = true
109
- )
110
- }
111
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
112
- ActivityCompat.requestPermissions(
113
- currentActivity!!,
114
- arrayOf(
115
- Manifest.permission.USE_SIP,
116
- Manifest.permission.CALL_PHONE,
117
- Manifest.permission.CAMERA,
118
- Manifest.permission.MODIFY_AUDIO_SETTINGS,
119
- Manifest.permission.RECORD_AUDIO,
120
- Manifest.permission.POST_NOTIFICATIONS,
121
- ),
122
- 0,
123
- )
124
- } else {
125
- ActivityCompat.requestPermissions(
126
- currentActivity!!,
127
- arrayOf(
128
- Manifest.permission.USE_SIP,
129
- Manifest.permission.CALL_PHONE,
130
- Manifest.permission.CAMERA,
131
- Manifest.permission.MODIFY_AUDIO_SETTINGS,
132
- Manifest.permission.RECORD_AUDIO,
133
- ),
134
- 0,
157
+ host,
135
158
  )
136
159
  }
160
+ requestPermission(isVideo)
137
161
  if (isVideo) {
138
- val cm = currentActivity!!.getSystemService(Context.CAMERA_SERVICE) as CameraManager
139
- OmiClient.instance.setCameraManager(cm)
162
+ setCamera()
140
163
  }
141
164
  promise.resolve(true)
142
165
  }
143
166
  }
144
167
 
145
168
  @ReactMethod
146
- fun getInitialCall(promise: Promise) {
147
- currentActivity?.runOnUiThread {
148
- promise.resolve(false)
169
+ fun initCallWithApiKey(data: ReadableMap, promise: Promise) {
170
+ mainScope.launch {
171
+ var loginResult = false
172
+ val usrName = data.getString("fullName")
173
+ val usrUuid = data.getString("usrUuid")
174
+ val apiKey = data.getString("apiKey")
175
+ val isVideo = data.getBoolean("isVideo")
176
+ withContext(Dispatchers.Default) {
177
+ try {
178
+ if (usrName != null && usrUuid != null && apiKey != null) {
179
+ loginResult = OmiClient.registerWithApiKey(
180
+ apiKey = apiKey,
181
+ userName = usrName,
182
+ uuid = usrUuid,
183
+ isVideo,
184
+ )
185
+ }
186
+ } catch (_ : Throwable) {
187
+
188
+ }
189
+ }
190
+ requestPermission(isVideo)
191
+ if (isVideo) {
192
+ setCamera()
193
+ }
194
+ promise.resolve(loginResult)
149
195
  }
150
196
  }
151
197
 
198
+
152
199
  @ReactMethod
153
- fun joinCall(promise: Promise) {
154
- OmiClient.instance.pickUp(true)
155
- promise.resolve(true)
200
+ fun getInitialCall(promise: Promise) {
201
+ currentActivity?.runOnUiThread {
202
+ promise.resolve(false)
203
+ }
156
204
  }
157
205
 
158
206
  @ReactMethod
159
207
  fun updateToken(data: ReadableMap, promise: Promise) {
160
- currentActivity?.runOnUiThread {
208
+ mainScope.launch {
161
209
  val deviceTokenAndroid = data.getString("fcmToken") as String
162
210
  val appId = data.getString("appId") as String
163
211
  val deviceId = data.getString("deviceId") as String
164
- OmiClient.instance.updatePushToken(
165
- "",
166
- deviceTokenAndroid,
167
- deviceId,
168
- appId,
169
- )
212
+ withContext(Dispatchers.Default) {
213
+ try {
214
+ OmiClient.instance.updatePushToken(
215
+ "",
216
+ deviceTokenAndroid,
217
+ deviceId,
218
+ appId,
219
+ )
220
+ } catch (_ : Throwable) {
221
+
222
+ }
223
+ }
170
224
  promise.resolve(true)
171
225
  }
172
226
  }
173
227
 
174
228
  @ReactMethod
175
229
  fun startCall(data: ReadableMap, promise: Promise) {
176
- val phoneNumber = data.getString("phoneNumber") as String
177
- val isVideo = data.getBoolean("isVideo")
178
- OmiClient.instance.startCall(phoneNumber, isVideo)
179
- promise.resolve(true)
230
+ currentActivity?.runOnUiThread {
231
+ val phoneNumber = data.getString("phoneNumber") as String
232
+ val isVideo = data.getBoolean("isVideo")
233
+ val result = OmiClient.instance.startCall(phoneNumber, isVideo)
234
+ promise.resolve(result)
235
+ }
236
+ }
237
+
238
+ @ReactMethod
239
+ fun startCallWithUuid(data: ReadableMap, promise: Promise) {
240
+ mainScope.launch {
241
+ var callResult = false
242
+ withContext(Dispatchers.Default) {
243
+ try {
244
+ val uuid = data.getString("usrUuid") as String
245
+ val isVideo = data.getBoolean("isVideo")
246
+ callResult = OmiClient.instance.startCallWithUuid(uuid = uuid, isVideo = isVideo)
247
+ } catch (_ : Throwable) {
248
+
249
+ }
250
+ }
251
+ promise.resolve(callResult)
252
+ }
253
+ }
254
+
255
+ @ReactMethod
256
+ fun joinCall(promise: Promise) {
257
+ currentActivity?.runOnUiThread {
258
+ OmiClient.instance.pickUp()
259
+ promise.resolve(true)
260
+ }
180
261
  }
181
262
 
182
263
  @ReactMethod
183
264
  fun endCall(promise: Promise) {
184
- OmiClient.instance.hangUp()
185
- promise.resolve(true)
265
+ currentActivity?.runOnUiThread {
266
+ OmiClient.instance.hangUp()
267
+ promise.resolve(true)
268
+ }
186
269
  }
187
270
 
188
271
  @ReactMethod
189
272
  fun toggleMute(promise: Promise) {
190
- OmiClient.instance.toggleMute()
191
- promise.resolve(true)
192
- isMute = !isMute
193
- sendEvent(MUTED, isMute)
273
+ mainScope.launch {
274
+ var newStatus : Boolean? = null
275
+ withContext(Dispatchers.Default) {
276
+ try {
277
+ newStatus = OmiClient.instance.toggleMute()
278
+ } catch (_ : Throwable) {
279
+
280
+ }
281
+ }
282
+ promise.resolve(newStatus)
283
+ sendEvent(MUTED, newStatus)
284
+ }
194
285
  }
195
286
 
196
287
  @ReactMethod
197
- fun toggleSpeak(promise: Promise) {
198
- icSpeaker = !icSpeaker
199
- OmiClient.instance.toggleSpeaker(icSpeaker)
200
- promise.resolve(true)
201
- sendEvent(SPEAKER, icSpeaker)
288
+ fun toggleSpeaker(promise: Promise) {
289
+ currentActivity?.runOnUiThread {
290
+ val newStatus = OmiClient.instance.toggleSpeaker()
291
+ promise.resolve(newStatus)
292
+ sendEvent(SPEAKER, newStatus)
293
+ }
202
294
  }
203
295
 
204
296
  @ReactMethod
205
297
  fun sendDTMF(data: ReadableMap, promise: Promise) {
206
- val character = data.getString("character")
207
- var characterCode: Int? = character?.toIntOrNull()
208
- if (character == "*") {
209
- characterCode = 10
298
+ currentActivity?.runOnUiThread {
299
+ val character = data.getString("character")
300
+ var characterCode: Int? = character?.toIntOrNull()
301
+ if (character == "*") {
302
+ characterCode = 10
303
+ }
304
+ if (character == "#") {
305
+ characterCode = 11
306
+ }
307
+ if (characterCode != null) {
308
+ OmiClient.instance.sendDtmf(characterCode)
309
+ }
310
+ promise.resolve(true)
311
+ }
312
+ }
313
+
314
+ @ReactMethod
315
+ fun switchOmiCamera(promise: Promise) {
316
+ currentActivity?.runOnUiThread {
317
+ OmiClient.instance.switchCamera()
318
+ promise.resolve(true)
210
319
  }
211
- if (character == "#") {
212
- characterCode = 11
320
+ }
321
+
322
+ @ReactMethod
323
+ fun toggleOmiVideo(promise: Promise) {
324
+ currentActivity?.runOnUiThread {
325
+ OmiClient.instance.toggleCamera()
326
+ promise.resolve(true)
213
327
  }
214
- if (characterCode != null) {
215
- OmiClient.instance.sendDtmf(characterCode)
328
+ }
329
+
330
+ @ReactMethod
331
+ fun omiInputs(promise: Promise) {
332
+ currentActivity?.runOnUiThread {
333
+ val inputs = OmiClient.instance.getAudioInputs()
334
+ val allAudios = inputs.map {
335
+ mapOf(
336
+ "name" to it.first,
337
+ "id" to it.second,
338
+ )
339
+ }.toTypedArray()
340
+ promise.resolve(allAudios)
341
+ }
342
+ }
343
+
344
+ @ReactMethod
345
+ fun omiOutputs(promise: Promise) {
346
+ currentActivity?.runOnUiThread {
347
+ val inputs = OmiClient.instance.getAudioOutputs()
348
+ val allAudios = inputs.map {
349
+ mapOf(
350
+ "name" to it.first,
351
+ "id" to it.second,
352
+ )
353
+ }.toTypedArray()
354
+ promise.resolve(allAudios)
216
355
  }
217
- promise.resolve(true)
218
356
  }
219
357
 
220
358
  companion object {
@@ -236,9 +374,35 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
236
374
  }
237
375
 
238
376
  private fun sendEvent(eventName: String?, params: Any?) {
239
- currentActivity?.runOnUiThread {
377
+ currentActivity!!.runOnUiThread {
240
378
  reactApplicationContext.getJSModule(RCTNativeAppEventEmitter::class.java)
241
379
  .emit(eventName, params)
242
380
  }
243
381
  }
382
+
383
+ private fun requestPermission(isVideo : Boolean) {
384
+ var permissions = arrayOf(
385
+ Manifest.permission.USE_SIP,
386
+ Manifest.permission.CALL_PHONE,
387
+ Manifest.permission.MODIFY_AUDIO_SETTINGS,
388
+ Manifest.permission.RECORD_AUDIO,
389
+ )
390
+ if (isVideo) {
391
+ permissions = permissions.plus(Manifest.permission.CAMERA)
392
+ }
393
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
394
+ permissions = permissions.plus(Manifest.permission.POST_NOTIFICATIONS)
395
+ }
396
+ ActivityCompat.requestPermissions(
397
+ reactApplicationContext.currentActivity!!,
398
+ permissions,
399
+ 0,
400
+ )
401
+ }
402
+
403
+ private fun setCamera() {
404
+ val cm =
405
+ reactApplicationContext!!.getSystemService(Context.CAMERA_SERVICE) as CameraManager
406
+ OmiClient.instance.setCameraManager(cm)
407
+ }
244
408
  }
@@ -7,11 +7,30 @@ import com.facebook.react.uimanager.ViewManager
7
7
 
8
8
 
9
9
  class OmikitPluginPackage : ReactPackage {
10
+
11
+ private var localView: FLLocalCameraView? = null
12
+ private var remoteView: FLRemoteCameraView? = null
10
13
  override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
11
- return listOf(OmikitPluginModule(reactContext))
14
+ if (localView == null) {
15
+ localView = FLLocalCameraView(reactContext)
16
+ }
17
+ if (remoteView == null) {
18
+ remoteView = FLRemoteCameraView(reactContext)
19
+ }
20
+ return listOf(
21
+ OmikitPluginModule(reactContext),
22
+ FLLocalCameraModule(reactContext, localView!!),
23
+ FLRemoteCameraModule(reactContext, remoteView!!),
24
+ )
12
25
  }
13
26
 
14
27
  override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
15
- return emptyList()
28
+ if (localView == null) {
29
+ localView = FLLocalCameraView(reactContext)
30
+ }
31
+ if (remoteView == null) {
32
+ remoteView = FLRemoteCameraView(reactContext)
33
+ }
34
+ return listOf(localView!!, remoteView!!)
16
35
  }
17
36
  }
@@ -1,20 +1,31 @@
1
1
  package com.omikitplugin.constants
2
2
 
3
- //EVENT
4
- const val INIT_CALL = "INIT_CALL";
5
- const val UPDATE_TOKEN = "UPDATE_TOKEN";
6
- const val START_CALL = "START_CALL";
7
- const val END_CALL = "END_CALL";
8
- const val TOGGLE_MUTE = "TOGGLE_MUTE";
9
- const val TOGGLE_SPEAK = "TOGGLE_SPEAK";
10
- const val REGISTER = "REGISTER";
11
- const val SEND_DTMF = "SEND_DTMF";
3
+ const val START_SERVICES = "START_SERVICES"
4
+ const val CONFIG_NOTIFICATION = "CONFIG_NOTIFICATION"
5
+ const val INIT_CALL_API_KEY = "INIT_CALL_API_KEY"
6
+ const val INIT_CALL_USER_PASSWORD = "INIT_CALL_USER_PASSWORD"
7
+ const val UPDATE_TOKEN = "UPDATE_TOKEN"
8
+ const val START_CALL = "START_CALL"
9
+ const val END_CALL = "END_CALL"
10
+ const val TOGGLE_MUTE = "TOGGLE_MUTE"
11
+ const val TOGGLE_SPEAK = "TOGGLE_SPEAK"
12
+ const val REGISTER = "REGISTER"
13
+ const val SEND_DTMF = "SEND_DTMF"
14
+ const val SWITCH_CAMERA = "SWITCH_CAMERA"
15
+ const val CAMERA_STATUS = "CAMERA_STATUS"
16
+ const val TOGGLE_VIDEO = "TOGGLE_VIDEO"
17
+ const val INPUTS = "INPUTS"
18
+ const val OUTPUTS = "OUTOUTS"
19
+ const val SET_INPUT = "SET_INPUT"
20
+ const val SET_OUTPUT = "SET_OUTPUT"
21
+ const val JOIN_CALL = "JOIN_CALL"
22
+ const val START_CALL_WITH_UUID = "START_CALL_WITH_UUID"
23
+ const val LOG_OUT = "LOG_OUT"
12
24
 
13
25
  //LISTENER
14
26
  const val CALL_ESTABLISHED = "CALL_ESTABLISHED"
15
27
  const val CALL_END = "CALL_END"
16
28
  const val INCOMING_RECEIVED = "INCOMING_RECEIVED"
17
- //const val CONNECTION_TIMEOUT = "CONNECTION_TIMEOUT"
18
- const val HOLD = "HOLD"
19
- const val MUTED = "MUTED"
29
+ const val VIDEO = "VIDEO"
20
30
  const val SPEAKER = "SPEAKER"
31
+ const val MUTED = "MUTED"