mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-23 10:05:15 +00:00
Merge branch 'dev' into fix/video-call-rotation-and-avatars
This commit is contained in:
commit
2d98da10ee
@ -0,0 +1,46 @@
|
||||
package org.thoughtcrime.securesms.service
|
||||
|
||||
import android.os.Build
|
||||
import android.telephony.PhoneStateListener
|
||||
import android.telephony.PhoneStateListener.LISTEN_NONE
|
||||
import android.telephony.TelephonyManager
|
||||
import androidx.annotation.RequiresApi
|
||||
import org.thoughtcrime.securesms.webrtc.HangUpRtcOnPstnCallAnsweredListener
|
||||
import org.thoughtcrime.securesms.webrtc.HangUpRtcTelephonyCallback
|
||||
import java.util.concurrent.ExecutorService
|
||||
|
||||
internal interface TelephonyHandler {
|
||||
fun register(telephonyManager: TelephonyManager)
|
||||
fun unregister(telephonyManager: TelephonyManager)
|
||||
}
|
||||
|
||||
internal fun TelephonyHandler(serviceExecutor: ExecutorService, callback: () -> Unit) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
TelephonyHandlerV31(serviceExecutor, callback)
|
||||
} else {
|
||||
TelephonyHandlerV23(callback)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.S)
|
||||
private class TelephonyHandlerV31(val serviceExecutor: ExecutorService, callback: () -> Unit): TelephonyHandler {
|
||||
private val callback = HangUpRtcTelephonyCallback(callback)
|
||||
|
||||
override fun register(telephonyManager: TelephonyManager) {
|
||||
telephonyManager.registerTelephonyCallback(serviceExecutor, callback)
|
||||
}
|
||||
|
||||
override fun unregister(telephonyManager: TelephonyManager) {
|
||||
telephonyManager.unregisterTelephonyCallback(callback)
|
||||
}
|
||||
}
|
||||
|
||||
private class TelephonyHandlerV23(callback: () -> Unit): TelephonyHandler {
|
||||
val callback = HangUpRtcOnPstnCallAnsweredListener(callback)
|
||||
|
||||
override fun register(telephonyManager: TelephonyManager) {
|
||||
telephonyManager.listen(callback, PhoneStateListener.LISTEN_CALL_STATE)
|
||||
}
|
||||
|
||||
override fun unregister(telephonyManager: TelephonyManager) {
|
||||
telephonyManager.listen(callback, LISTEN_NONE)
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package org.thoughtcrime.securesms.service
|
||||
|
||||
import android.app.ForegroundServiceStartNotAllowedException
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@ -10,11 +9,11 @@ import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.media.AudioManager
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.ResultReceiver
|
||||
import android.telephony.PhoneStateListener
|
||||
import android.telephony.PhoneStateListener.LISTEN_NONE
|
||||
import android.telephony.TelephonyManager
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.LifecycleService
|
||||
@ -34,14 +33,33 @@ import org.thoughtcrime.securesms.util.CallNotificationBuilder.Companion.TYPE_IN
|
||||
import org.thoughtcrime.securesms.util.CallNotificationBuilder.Companion.TYPE_INCOMING_PRE_OFFER
|
||||
import org.thoughtcrime.securesms.util.CallNotificationBuilder.Companion.TYPE_INCOMING_RINGING
|
||||
import org.thoughtcrime.securesms.util.CallNotificationBuilder.Companion.TYPE_OUTGOING_RINGING
|
||||
import org.thoughtcrime.securesms.webrtc.*
|
||||
import org.thoughtcrime.securesms.webrtc.AudioManagerCommand
|
||||
import org.thoughtcrime.securesms.webrtc.CallManager
|
||||
import org.thoughtcrime.securesms.webrtc.CallViewModel
|
||||
import org.thoughtcrime.securesms.webrtc.HangUpRtcOnPstnCallAnsweredListener
|
||||
import org.thoughtcrime.securesms.webrtc.HangUpRtcTelephonyCallback
|
||||
import org.thoughtcrime.securesms.webrtc.IncomingPstnCallReceiver
|
||||
import org.thoughtcrime.securesms.webrtc.NetworkChangeReceiver
|
||||
import org.thoughtcrime.securesms.webrtc.PeerConnectionException
|
||||
import org.thoughtcrime.securesms.webrtc.PowerButtonReceiver
|
||||
import org.thoughtcrime.securesms.webrtc.ProximityLockRelease
|
||||
import org.thoughtcrime.securesms.webrtc.UncaughtExceptionHandlerManager
|
||||
import org.thoughtcrime.securesms.webrtc.WiredHeadsetStateReceiver
|
||||
import org.thoughtcrime.securesms.webrtc.audio.OutgoingRinger
|
||||
import org.thoughtcrime.securesms.webrtc.data.Event
|
||||
import org.thoughtcrime.securesms.webrtc.locks.LockManager
|
||||
import org.webrtc.*
|
||||
import org.webrtc.PeerConnection.IceConnectionState.*
|
||||
import java.util.*
|
||||
import org.webrtc.DataChannel
|
||||
import org.webrtc.IceCandidate
|
||||
import org.webrtc.MediaStream
|
||||
import org.webrtc.PeerConnection
|
||||
import org.webrtc.PeerConnection.IceConnectionState.CONNECTED
|
||||
import org.webrtc.PeerConnection.IceConnectionState.DISCONNECTED
|
||||
import org.webrtc.PeerConnection.IceConnectionState.FAILED
|
||||
import org.webrtc.RtpReceiver
|
||||
import org.webrtc.SessionDescription
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ExecutionException
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.ScheduledFuture
|
||||
import java.util.concurrent.TimeUnit
|
||||
@ -209,16 +227,11 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener {
|
||||
private val serviceExecutor = Executors.newSingleThreadExecutor()
|
||||
private val timeoutExecutor = Executors.newScheduledThreadPool(1)
|
||||
|
||||
private val hangupOnCallAnswered by lazy {
|
||||
HangUpRtcOnPstnCallAnsweredListener {
|
||||
ContextCompat.startForegroundService(this, hangupIntent(this))
|
||||
}
|
||||
}
|
||||
|
||||
private val hangupTelephonyCallback by lazy {
|
||||
HangUpRtcTelephonyCallback {
|
||||
ContextCompat.startForegroundService(this, hangupIntent(this))
|
||||
}
|
||||
private val telephonyHandler = TelephonyHandler(serviceExecutor) {
|
||||
ContextCompat.startForegroundService(
|
||||
this@WebRtcCallService,
|
||||
hangupIntent(this@WebRtcCallService)
|
||||
)
|
||||
}
|
||||
|
||||
private var networkChangedReceiver: NetworkChangeReceiver? = null
|
||||
@ -251,17 +264,12 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener {
|
||||
return callManager.callId == expectedCallId
|
||||
}
|
||||
|
||||
|
||||
private fun isPreOffer() = callManager.isPreOffer()
|
||||
|
||||
private fun isBusy(intent: Intent) = callManager.isBusy(this, getCallId(intent))
|
||||
|
||||
private fun isIdle() = callManager.isIdle()
|
||||
|
||||
override fun onBind(intent: Intent): IBinder? {
|
||||
return super.onBind(intent)
|
||||
}
|
||||
|
||||
override fun onHangup() {
|
||||
serviceExecutor.execute {
|
||||
callManager.handleRemoteHangup()
|
||||
@ -276,38 +284,41 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener {
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
super.onStartCommand(intent, flags, startId)
|
||||
if (intent == null || intent.action == null) return START_NOT_STICKY
|
||||
serviceExecutor.execute {
|
||||
val action = intent.action
|
||||
val callId = ((intent.getSerializableExtra(EXTRA_CALL_ID) as? UUID)?.toString() ?: "No callId")
|
||||
Log.i("Loki", "Handling ${intent.action} for call: ${callId}")
|
||||
when {
|
||||
action == ACTION_INCOMING_RING && isSameCall(intent) && callManager.currentConnectionState == CallState.Reconnecting -> handleNewOffer(
|
||||
intent
|
||||
)
|
||||
action == ACTION_PRE_OFFER && isIdle() -> handlePreOffer(intent)
|
||||
action == ACTION_INCOMING_RING && isBusy(intent) -> handleBusyCall(intent)
|
||||
action == ACTION_INCOMING_RING && isPreOffer() -> handleIncomingRing(intent)
|
||||
action == ACTION_OUTGOING_CALL && isIdle() -> handleOutgoingCall(intent)
|
||||
action == ACTION_ANSWER_CALL -> handleAnswerCall(intent)
|
||||
action == ACTION_DENY_CALL -> handleDenyCall(intent)
|
||||
action == ACTION_LOCAL_HANGUP -> handleLocalHangup(intent)
|
||||
action == ACTION_REMOTE_HANGUP -> handleRemoteHangup(intent)
|
||||
action == ACTION_SET_MUTE_AUDIO -> handleSetMuteAudio(intent)
|
||||
action == ACTION_SET_MUTE_VIDEO -> handleSetMuteVideo(intent)
|
||||
action == ACTION_FLIP_CAMERA -> handleSetCameraFlip(intent)
|
||||
action == ACTION_WIRED_HEADSET_CHANGE -> handleWiredHeadsetChanged(intent)
|
||||
action == ACTION_SCREEN_OFF -> handleScreenOffChange(intent)
|
||||
action == ACTION_RESPONSE_MESSAGE && isSameCall(intent) && callManager.currentConnectionState == CallState.Reconnecting -> handleResponseMessage(
|
||||
intent
|
||||
)
|
||||
action == ACTION_RESPONSE_MESSAGE -> handleResponseMessage(intent)
|
||||
action == ACTION_ICE_MESSAGE -> handleRemoteIceCandidate(intent)
|
||||
action == ACTION_ICE_CONNECTED -> handleIceConnected(intent)
|
||||
action == ACTION_CHECK_TIMEOUT -> handleCheckTimeout(intent)
|
||||
action == ACTION_CHECK_RECONNECT -> handleCheckReconnect(intent)
|
||||
action == ACTION_IS_IN_CALL_QUERY -> handleIsInCallQuery(intent)
|
||||
action == ACTION_UPDATE_AUDIO -> handleUpdateAudio(intent)
|
||||
when (action) {
|
||||
ACTION_INCOMING_RING -> if (isSameCall(intent) && callManager.currentConnectionState == CallState.Reconnecting) {
|
||||
handleNewOffer(intent)
|
||||
}
|
||||
ACTION_PRE_OFFER -> if (isIdle()) handlePreOffer(intent)
|
||||
ACTION_INCOMING_RING -> when {
|
||||
isBusy(intent) -> handleBusyCall(intent)
|
||||
isPreOffer() -> handleIncomingRing(intent)
|
||||
}
|
||||
ACTION_OUTGOING_CALL -> if (isIdle()) handleOutgoingCall(intent)
|
||||
ACTION_ANSWER_CALL -> handleAnswerCall(intent)
|
||||
ACTION_DENY_CALL -> handleDenyCall(intent)
|
||||
ACTION_LOCAL_HANGUP -> handleLocalHangup(intent)
|
||||
ACTION_REMOTE_HANGUP -> handleRemoteHangup(intent)
|
||||
ACTION_SET_MUTE_AUDIO -> handleSetMuteAudio(intent)
|
||||
ACTION_SET_MUTE_VIDEO -> handleSetMuteVideo(intent)
|
||||
ACTION_FLIP_CAMERA -> handleSetCameraFlip(intent)
|
||||
ACTION_WIRED_HEADSET_CHANGE -> handleWiredHeadsetChanged(intent)
|
||||
ACTION_SCREEN_OFF -> handleScreenOffChange(intent)
|
||||
ACTION_RESPONSE_MESSAGE -> if (isSameCall(intent) && callManager.currentConnectionState == CallState.Reconnecting) {
|
||||
handleResponseMessage(intent)
|
||||
}
|
||||
ACTION_RESPONSE_MESSAGE -> handleResponseMessage(intent)
|
||||
ACTION_ICE_MESSAGE -> handleRemoteIceCandidate(intent)
|
||||
ACTION_ICE_CONNECTED -> handleIceConnected(intent)
|
||||
ACTION_CHECK_TIMEOUT -> handleCheckTimeout(intent)
|
||||
ACTION_CHECK_RECONNECT -> handleCheckReconnect(intent)
|
||||
ACTION_IS_IN_CALL_QUERY -> handleIsInCallQuery(intent)
|
||||
ACTION_UPDATE_AUDIO -> handleUpdateAudio(intent)
|
||||
}
|
||||
}
|
||||
return START_NOT_STICKY
|
||||
@ -322,13 +333,7 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener {
|
||||
registerWiredHeadsetStateReceiver()
|
||||
registerWantsToAnswerReceiver()
|
||||
if (checkSelfPermission(android.Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
||||
getSystemService(TelephonyManager::class.java)
|
||||
.listen(hangupOnCallAnswered, PhoneStateListener.LISTEN_CALL_STATE)
|
||||
} else {
|
||||
getSystemService(TelephonyManager::class.java)
|
||||
.registerTelephonyCallback(serviceExecutor, hangupTelephonyCallback)
|
||||
}
|
||||
telephonyHandler.register(getSystemService(TelephonyManager::class.java))
|
||||
}
|
||||
registerUncaughtExceptionHandler()
|
||||
networkChangedReceiver = NetworkChangeReceiver(::networkChange)
|
||||
@ -735,9 +740,8 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener {
|
||||
CallNotificationBuilder.WEBRTC_NOTIFICATION,
|
||||
CallNotificationBuilder.getCallInProgressNotification(this, type, recipient)
|
||||
)
|
||||
}
|
||||
catch(e: ForegroundServiceStartNotAllowedException) {
|
||||
Log.e(TAG, "Failed to setCallInProgressNotification as a foreground service for type: ${type}, trying to update instead")
|
||||
} catch (e: IllegalStateException) {
|
||||
Log.e(TAG, "Failed to setCallInProgressNotification as a foreground service for type: ${type}, trying to update instead", e)
|
||||
}
|
||||
|
||||
if (!CallNotificationBuilder.areNotificationsEnabled(this) && type == TYPE_INCOMING_PRE_OFFER) {
|
||||
@ -750,11 +754,7 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener {
|
||||
}
|
||||
|
||||
private fun getOptionalRemoteRecipient(intent: Intent): Recipient? =
|
||||
if (intent.hasExtra(EXTRA_RECIPIENT_ADDRESS)) {
|
||||
getRemoteRecipient(intent)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
intent.takeIf { it.hasExtra(EXTRA_RECIPIENT_ADDRESS) }?.let(::getRemoteRecipient)
|
||||
|
||||
private fun getRemoteRecipient(intent: Intent): Recipient {
|
||||
val remoteAddress = intent.getParcelableExtra<Address>(EXTRA_RECIPIENT_ADDRESS)
|
||||
@ -763,10 +763,9 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener {
|
||||
return Recipient.from(this, remoteAddress, true)
|
||||
}
|
||||
|
||||
private fun getCallId(intent: Intent): UUID {
|
||||
return intent.getSerializableExtra(EXTRA_CALL_ID) as? UUID
|
||||
private fun getCallId(intent: Intent): UUID =
|
||||
intent.getSerializableExtra(EXTRA_CALL_ID) as? UUID
|
||||
?: throw AssertionError("No callId in intent!")
|
||||
}
|
||||
|
||||
private fun insertMissedCall(recipient: Recipient, signal: Boolean) {
|
||||
callManager.insertCallMessage(
|
||||
@ -788,8 +787,8 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener {
|
||||
callReceiver?.let { receiver ->
|
||||
unregisterReceiver(receiver)
|
||||
}
|
||||
wiredHeadsetStateReceiver?.let { unregisterReceiver(it) }
|
||||
powerButtonReceiver?.let { unregisterReceiver(it) }
|
||||
wiredHeadsetStateReceiver?.let(::unregisterReceiver)
|
||||
powerButtonReceiver?.let(::unregisterReceiver)
|
||||
networkChangedReceiver?.unregister(this)
|
||||
wantsToAnswerReceiver?.let { receiver ->
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver)
|
||||
@ -804,14 +803,7 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener {
|
||||
currentTimeouts = 0
|
||||
isNetworkAvailable = false
|
||||
if (checkSelfPermission(android.Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
|
||||
val telephonyManager = getSystemService(TelephonyManager::class.java)
|
||||
with(telephonyManager) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
||||
this.listen(hangupOnCallAnswered, LISTEN_NONE)
|
||||
} else {
|
||||
this.unregisterTelephonyCallback(hangupTelephonyCallback)
|
||||
}
|
||||
}
|
||||
telephonyHandler.unregister(getSystemService(TelephonyManager::class.java))
|
||||
}
|
||||
super.onDestroy()
|
||||
}
|
||||
@ -819,13 +811,12 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener {
|
||||
private fun networkChange(networkAvailable: Boolean) {
|
||||
Log.d("Loki", "flipping network available to $networkAvailable")
|
||||
isNetworkAvailable = networkAvailable
|
||||
if (networkAvailable && !callManager.isReestablishing && callManager.currentConnectionState == CallState.Connected) {
|
||||
if (networkAvailable && callManager.currentConnectionState == CallState.Connected) {
|
||||
Log.d("Loki", "Should reconnected")
|
||||
}
|
||||
}
|
||||
|
||||
private class CheckReconnectedRunnable(private val callId: UUID, private val context: Context) :
|
||||
Runnable {
|
||||
private class CheckReconnectedRunnable(private val callId: UUID, private val context: Context) : Runnable {
|
||||
override fun run() {
|
||||
val intent = Intent(context, WebRtcCallService::class.java)
|
||||
.setAction(ACTION_CHECK_RECONNECT)
|
||||
@ -834,18 +825,7 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener {
|
||||
}
|
||||
}
|
||||
|
||||
private class ReconnectTimeoutRunnable(private val callId: UUID, private val context: Context) :
|
||||
Runnable {
|
||||
override fun run() {
|
||||
val intent = Intent(context, WebRtcCallService::class.java)
|
||||
.setAction(ACTION_CHECK_RECONNECT_TIMEOUT)
|
||||
.putExtra(EXTRA_CALL_ID, callId)
|
||||
context.startService(intent)
|
||||
}
|
||||
}
|
||||
|
||||
private class TimeoutRunnable(private val callId: UUID, private val context: Context) :
|
||||
Runnable {
|
||||
private class TimeoutRunnable(private val callId: UUID, private val context: Context) : Runnable {
|
||||
override fun run() {
|
||||
val intent = Intent(context, WebRtcCallService::class.java)
|
||||
.setAction(ACTION_CHECK_TIMEOUT)
|
||||
|
@ -118,7 +118,7 @@ class CallManager(
|
||||
remoteVideoEnabled = false
|
||||
)
|
||||
)
|
||||
val videoState = _videoState
|
||||
val videoState = _videoState.asStateFlow()
|
||||
|
||||
private val stateProcessor = StateProcessor(CallState.Idle)
|
||||
|
||||
@ -137,7 +137,7 @@ class CallManager(
|
||||
val currentCallState
|
||||
get() = _callStateEvents.value
|
||||
|
||||
var iceState = IceConnectionState.CLOSED
|
||||
private var iceState = IceConnectionState.CLOSED
|
||||
|
||||
private var eglBase: EglBase? = null
|
||||
|
||||
@ -151,7 +151,6 @@ class CallManager(
|
||||
_recipientEvents.value = RecipientUpdate(value)
|
||||
}
|
||||
var callStartTime: Long = -1
|
||||
var isReestablishing: Boolean = false
|
||||
|
||||
private var peerConnection: PeerConnectionWrapper? = null
|
||||
private var dataChannel: DataChannel? = null
|
||||
@ -630,9 +629,7 @@ class CallManager(
|
||||
peerConnection?.rotationVideoSink?.setSink(fullscreenRenderer)
|
||||
floatingRenderer?.let { remoteRotationSink?.setSink(it) }
|
||||
} else {
|
||||
peerConnection?.rotationVideoSink?.apply {
|
||||
setSink(floatingRenderer)
|
||||
}
|
||||
peerConnection?.rotationVideoSink?.setSink(floatingRenderer)
|
||||
fullscreenRenderer?.let { remoteRotationSink?.setSink(it) }
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.webrtc
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -37,24 +36,20 @@ class CallViewModel @Inject constructor(private val callManager: CallManager): V
|
||||
val fullscreenRenderer: SurfaceViewRenderer?
|
||||
get() = callManager.fullscreenRenderer
|
||||
|
||||
private var _microphoneEnabled: Boolean = true
|
||||
var microphoneEnabled: Boolean = true
|
||||
private set
|
||||
|
||||
val microphoneEnabled: Boolean
|
||||
get() = _microphoneEnabled
|
||||
|
||||
private var _isSpeaker: Boolean = false
|
||||
val isSpeaker: Boolean
|
||||
get() = _isSpeaker
|
||||
var isSpeaker: Boolean = false
|
||||
private set
|
||||
|
||||
val audioDeviceState
|
||||
get() = callManager.audioDeviceEvents
|
||||
.onEach {
|
||||
_isSpeaker = it.selectedDevice == SignalAudioManager.AudioDevice.SPEAKER_PHONE
|
||||
get() = callManager.audioDeviceEvents.onEach {
|
||||
isSpeaker = it.selectedDevice == SignalAudioManager.AudioDevice.SPEAKER_PHONE
|
||||
}
|
||||
|
||||
val localAudioEnabledState
|
||||
get() = callManager.audioEvents.map { it.isEnabled }
|
||||
.onEach { _microphoneEnabled = it }
|
||||
.onEach { microphoneEnabled = it }
|
||||
|
||||
val videoState: StateFlow<VideoState>
|
||||
get() = callManager.videoState
|
||||
@ -65,17 +60,10 @@ class CallViewModel @Inject constructor(private val callManager: CallManager): V
|
||||
callManager.setDeviceOrientation(value)
|
||||
}
|
||||
|
||||
val currentCallState
|
||||
get() = callManager.currentCallState
|
||||
|
||||
val callState
|
||||
get() = callManager.callStateEvents
|
||||
|
||||
val recipient
|
||||
get() = callManager.recipientEvents
|
||||
|
||||
val callStartTime: Long
|
||||
get() = callManager.callStartTime
|
||||
val currentCallState get() = callManager.currentCallState
|
||||
val callState get() = callManager.callStateEvents
|
||||
val recipient get() = callManager.recipientEvents
|
||||
val callStartTime: Long get() = callManager.callStartTime
|
||||
|
||||
fun swapVideos() {
|
||||
callManager.swapVideos()
|
||||
|
Loading…
Reference in New Issue
Block a user