mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-24 15:58:22 +00:00
feat: adding more lifecycle vm and callmanager / call service functionality
This commit is contained in:
@@ -297,7 +297,7 @@
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.Session.DayNight.NoActionBar" />
|
||||
<activity android:name="org.thoughtcrime.securesms.calls.WebRtcTestsActivity"
|
||||
<activity android:name="org.thoughtcrime.securesms.calls.WebRtcCallActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:launchMode="singleTop"
|
||||
android:parentActivityName="org.thoughtcrime.securesms.home.HomeActivity"
|
||||
|
@@ -11,7 +11,6 @@ import android.view.MenuItem
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import androidx.activity.viewModels
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
@@ -25,7 +24,6 @@ import org.session.libsession.messaging.messages.control.CallMessage
|
||||
import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||
import org.session.libsession.messaging.utilities.WebRtcUtils
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.Debouncer
|
||||
import org.session.libsignal.protos.SignalServiceProtos
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
@@ -35,7 +33,7 @@ import org.webrtc.*
|
||||
import java.util.*
|
||||
|
||||
@AndroidEntryPoint
|
||||
class WebRtcTestsActivity: PassphraseRequiredActionBarActivity() {
|
||||
class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
|
||||
|
||||
companion object {
|
||||
const val CALL_ID = "call_id_session"
|
||||
@@ -48,6 +46,8 @@ class WebRtcTestsActivity: PassphraseRequiredActionBarActivity() {
|
||||
const val EXTRA_SDP = "WebRtcTestsActivity_EXTRA_SDP"
|
||||
const val EXTRA_ADDRESS = "WebRtcTestsActivity_EXTRA_ADDRESS"
|
||||
const val EXTRA_CALL_ID = "WebRtcTestsActivity_EXTRA_CALL_ID"
|
||||
|
||||
const val BUSY_SIGNAL_DELAY_FINISH = 5500L
|
||||
}
|
||||
|
||||
private val viewModel by viewModels<CallViewModel>()
|
||||
@@ -135,7 +135,7 @@ class WebRtcTestsActivity: PassphraseRequiredActionBarActivity() {
|
||||
}
|
||||
if (answer != null) {
|
||||
peerConnection.setRemoteDescription(
|
||||
this@WebRtcTestsActivity,
|
||||
this@WebRtcCallActivity,
|
||||
SessionDescription(SessionDescription.Type.ANSWER, answer.sdps[0])
|
||||
)
|
||||
break
|
||||
@@ -153,7 +153,7 @@ class WebRtcTestsActivity: PassphraseRequiredActionBarActivity() {
|
||||
lifecycleScope.launchWhenResumed {
|
||||
while (this.isActive) {
|
||||
delay(2_000L)
|
||||
peerConnection.getStats(this@WebRtcTestsActivity)
|
||||
peerConnection.getStats(this@WebRtcCallActivity)
|
||||
synchronized(WebRtcUtils.callCache) {
|
||||
val set = WebRtcUtils.callCache[callId] ?: mutableSetOf()
|
||||
set.filter { it.hashCode() !in acceptedCallMessageHashes
|
@@ -36,7 +36,7 @@ import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsignal.utilities.guava.Optional
|
||||
import org.session.libsignal.utilities.toHexString
|
||||
import org.thoughtcrime.securesms.*
|
||||
import org.thoughtcrime.securesms.calls.WebRtcTestsActivity
|
||||
import org.thoughtcrime.securesms.calls.WebRtcCallActivity
|
||||
import org.thoughtcrime.securesms.contacts.SelectContactsActivity
|
||||
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
|
||||
import org.thoughtcrime.securesms.conversation.v2.utilities.NotificationUtils
|
||||
@@ -187,15 +187,15 @@ object ConversationMenuHelper {
|
||||
.setTitle("Call")
|
||||
.setMessage("Use relay?")
|
||||
.setPositiveButton("Use Relay") { d, w ->
|
||||
val intent = Intent(context, WebRtcTestsActivity::class.java)
|
||||
intent.putExtra(WebRtcTestsActivity.EXTRA_CALL_ID, UUID.randomUUID().toString())
|
||||
intent.putExtra(WebRtcTestsActivity.EXTRA_ADDRESS, thread.address)
|
||||
val intent = Intent(context, WebRtcCallActivity::class.java)
|
||||
intent.putExtra(WebRtcCallActivity.EXTRA_CALL_ID, UUID.randomUUID().toString())
|
||||
intent.putExtra(WebRtcCallActivity.EXTRA_ADDRESS, thread.address)
|
||||
val activity = context as AppCompatActivity
|
||||
activity.startActivity(intent)
|
||||
}
|
||||
.setNeutralButton("P2P only") { d, w ->
|
||||
val intent = Intent(context, WebRtcTestsActivity::class.java)
|
||||
intent.putExtra(WebRtcTestsActivity.EXTRA_ADDRESS, thread.address)
|
||||
val intent = Intent(context, WebRtcCallActivity::class.java)
|
||||
intent.putExtra(WebRtcCallActivity.EXTRA_ADDRESS, thread.address)
|
||||
val activity = context as AppCompatActivity
|
||||
activity.startActivity(intent)
|
||||
}
|
||||
|
@@ -45,7 +45,7 @@ import org.session.libsignal.utilities.toHexString
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.MuteDialog
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.calls.WebRtcTestsActivity
|
||||
import org.thoughtcrime.securesms.calls.WebRtcCallActivity
|
||||
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
|
||||
import org.thoughtcrime.securesms.conversation.v2.utilities.NotificationUtils
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
|
||||
@@ -185,7 +185,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
|
||||
synchronized(WebRtcUtils.callCache) {
|
||||
WebRtcUtils.callCache[callId] = mutableSetOf()
|
||||
}
|
||||
sendBroadcast(Intent(WebRtcTestsActivity.ACTION_END))
|
||||
sendBroadcast(Intent(WebRtcCallActivity.ACTION_END))
|
||||
}
|
||||
else -> { /* do nothing */ }
|
||||
}
|
||||
|
@@ -6,18 +6,32 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.media.AudioManager
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.ResultReceiver
|
||||
import android.telephony.PhoneStateListener
|
||||
import android.telephony.TelephonyManager
|
||||
import androidx.core.content.ContextCompat
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.FutureTaskListener
|
||||
import org.session.libsession.utilities.Util
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.thoughtcrime.securesms.calls.WebRtcCallActivity
|
||||
import org.thoughtcrime.securesms.util.CallNotificationBuilder
|
||||
import org.thoughtcrime.securesms.util.CallNotificationBuilder.Companion.TYPE_ESTABLISHED
|
||||
import org.thoughtcrime.securesms.util.CallNotificationBuilder.Companion.TYPE_INCOMING_CONNECTING
|
||||
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.CallManager.CallState.*
|
||||
import org.thoughtcrime.securesms.webrtc.audio.OutgoingRinger
|
||||
import java.lang.AssertionError
|
||||
import java.util.*
|
||||
import java.util.concurrent.ExecutionException
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
@@ -26,6 +40,9 @@ class WebRtcCallService: Service() {
|
||||
@Inject lateinit var callManager: CallManager
|
||||
|
||||
companion object {
|
||||
|
||||
private val TAG = Log.tag(WebRtcCallService::class.java)
|
||||
|
||||
const val ACTION_INCOMING_CALL = "CALL_INCOMING"
|
||||
const val ACTION_OUTGOING_CALL = "CALL_OUTGOING"
|
||||
const val ACTION_ANSWER_CALL = "ANSWER_CALL"
|
||||
@@ -168,6 +185,100 @@ class WebRtcCallService: Service() {
|
||||
registerReceiver(wiredHeadsetStateReceiver, IntentFilter(AudioManager.ACTION_HEADSET_PLUG))
|
||||
}
|
||||
|
||||
private fun handleBusyCall(intent: Intent) {
|
||||
val recipient = getRemoteRecipient(intent)
|
||||
val callId = getCallId(intent)
|
||||
val callState = callManager.currentConnectionState
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
when (callState) {
|
||||
STATE_DIALING,
|
||||
STATE_REMOTE_RINGING -> setCallInProgressNotification(TYPE_OUTGOING_RINGING, callManager.recipient)
|
||||
STATE_IDLE -> setCallInProgressNotification(TYPE_INCOMING_CONNECTING, recipient)
|
||||
STATE_ANSWERING -> setCallInProgressNotification(TYPE_INCOMING_CONNECTING, callManager.recipient)
|
||||
STATE_LOCAL_RINGING -> setCallInProgressNotification(TYPE_INCOMING_RINGING, callManager.recipient)
|
||||
STATE_CONNECTED -> setCallInProgressNotification(TYPE_ESTABLISHED, callManager.recipient)
|
||||
else -> throw AssertionError()
|
||||
}
|
||||
}
|
||||
|
||||
if (callState == STATE_IDLE) {
|
||||
stopForeground(true)
|
||||
}
|
||||
|
||||
// TODO: send hangup via messageSender
|
||||
insertMissedCall(getRemoteRecipient(intent), false)
|
||||
}
|
||||
|
||||
private fun handleBusyMessage(intent: Intent) {
|
||||
val recipient = getRemoteRecipient(intent)
|
||||
val callId = getCallId(intent)
|
||||
if (callManager.currentConnectionState != STATE_DIALING || callManager.callId != callManager.callId || callManager.recipient != callManager.recipient) {
|
||||
Log.w(TAG,"Got busy message for inactive session...")
|
||||
return
|
||||
}
|
||||
callManager.postViewModelState(CallViewModel.State.CALL_BUSY)
|
||||
callManager.startOutgoingRinger(OutgoingRinger.Type.BUSY)
|
||||
Util.runOnMainDelayed({
|
||||
startService(
|
||||
Intent(this, WebRtcCallService::class.java)
|
||||
.setAction(ACTION_LOCAL_HANGUP)
|
||||
)
|
||||
}, WebRtcCallActivity.BUSY_SIGNAL_DELAY_FINISH)
|
||||
}
|
||||
|
||||
private fun handleIncomingCall(intent: Intent) {
|
||||
if (callManager.currentConnectionState != STATE_IDLE) throw IllegalStateException("Incoming on non-idle")
|
||||
|
||||
val offer = intent.getStringExtra(EXTRA_REMOTE_DESCRIPTION)
|
||||
callManager.postConnectionEvent(STATE_ANSWERING)
|
||||
callManager.callId = getCallId(intent)
|
||||
callManager.clearPendingIceUpdates()
|
||||
val recipient = getRemoteRecipient(intent)
|
||||
callManager.recipient = recipient
|
||||
if (isIncomingMessageExpired(intent)) {
|
||||
insertMissedCall(recipient, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleCheckTimeout(intent: Intent) {
|
||||
val callId = callManager.callId ?: return
|
||||
val callState = callManager.currentConnectionState
|
||||
|
||||
if (callId == getCallId(intent) && callState != STATE_CONNECTED) {
|
||||
Log.w(TAG, "Timing out call: $callId")
|
||||
callManager.postViewModelState(CallViewModel.State.CALL_DISCONNECTED)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setCallInProgressNotification(type: Int, recipient: Recipient?) {
|
||||
startForeground(
|
||||
CallNotificationBuilder.WEBRTC_NOTIFICATION,
|
||||
CallNotificationBuilder.getCallInProgressNotification(this, type, recipient)
|
||||
)
|
||||
}
|
||||
|
||||
private fun getRemoteRecipient(intent: Intent): Recipient {
|
||||
val remoteAddress = intent.getParcelableExtra<Address>(EXTRA_RECIPIENT_ADDRESS)
|
||||
?: throw AssertionError("No recipient in intent!")
|
||||
|
||||
return Recipient.from(this, remoteAddress, true)
|
||||
}
|
||||
|
||||
private fun getCallId(intent: Intent) : UUID {
|
||||
return intent.getSerializableExtra(EXTRA_CALL_ID) as? UUID
|
||||
?: throw AssertionError("No callId in intent!")
|
||||
}
|
||||
|
||||
private fun insertMissedCall(recipient: Recipient, signal: Boolean) {
|
||||
// TODO
|
||||
// val messageAndThreadId = DatabaseComponent.get(this).smsDatabase().insertReceivedCall(recipient.address)
|
||||
// MessageNotifier.updateNotification(this, messageAndThreadId.second, signal)
|
||||
}
|
||||
|
||||
private fun isIncomingMessageExpired(intent: Intent) =
|
||||
System.currentTimeMillis() - intent.getLongExtra(EXTRA_TIMESTAMP, -1) > TimeUnit.MINUTES.toMillis(2)
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
callReceiver?.let { receiver ->
|
||||
|
@@ -0,0 +1,107 @@
|
||||
package org.thoughtcrime.securesms.util
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.app.NotificationCompat
|
||||
import network.loki.messenger.R
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.calls.WebRtcCallActivity
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels
|
||||
import org.thoughtcrime.securesms.service.WebRtcCallService
|
||||
|
||||
class CallNotificationBuilder {
|
||||
|
||||
companion object {
|
||||
const val WEBRTC_NOTIFICATION = 313388
|
||||
|
||||
const val TYPE_INCOMING_RINGING = 1
|
||||
const val TYPE_OUTGOING_RINGING = 2
|
||||
const val TYPE_ESTABLISHED = 3
|
||||
const val TYPE_INCOMING_CONNECTING = 4
|
||||
|
||||
@JvmStatic
|
||||
fun getCallInProgressNotification(context: Context, type: Int, recipient: Recipient?): Notification {
|
||||
val contentIntent = Intent(context, WebRtcCallActivity::class.java)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
|
||||
val pendingIntent = PendingIntent.getActivity(context, 0, contentIntent, 0)
|
||||
|
||||
val builder = NotificationCompat.Builder(context, NotificationChannels.CALLS)
|
||||
.setSmallIcon(R.drawable.ic_baseline_call_24)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setOngoing(true)
|
||||
|
||||
recipient?.name?.let { name ->
|
||||
builder.setContentTitle(name)
|
||||
}
|
||||
|
||||
when (type) {
|
||||
TYPE_INCOMING_CONNECTING -> {
|
||||
builder.setContentText(context.getString(R.string.CallNotificationBuilder_connecting))
|
||||
builder.priority = NotificationCompat.PRIORITY_MIN
|
||||
}
|
||||
TYPE_INCOMING_RINGING -> {
|
||||
builder.setContentText(context.getString(R.string.NotificationBarManager__incoming_signal_call))
|
||||
builder.addAction(getServiceNotificationAction(
|
||||
context,
|
||||
WebRtcCallService.ACTION_DENY_CALL,
|
||||
R.drawable.ic_close_grey600_32dp,
|
||||
R.string.NotificationBarManager__deny_call
|
||||
))
|
||||
builder.addAction(getActivityNotificationAction(
|
||||
context,
|
||||
WebRtcCallActivity.ACTION_ANSWER,
|
||||
R.drawable.ic_phone_grey600_32dp,
|
||||
R.string.NotificationBarManager__answer_call
|
||||
))
|
||||
}
|
||||
TYPE_OUTGOING_RINGING -> {
|
||||
builder.setContentText(context.getString(R.string.NotificationBarManager__establishing_signal_call))
|
||||
builder.addAction(getServiceNotificationAction(
|
||||
context,
|
||||
WebRtcCallService.ACTION_LOCAL_HANGUP,
|
||||
R.drawable.ic_call_end_grey600_32dp,
|
||||
R.string.NotificationBarManager__cancel_call
|
||||
))
|
||||
}
|
||||
else -> {
|
||||
builder.setContentText(context.getString(R.string.NotificationBarManager_call_in_progress))
|
||||
builder.addAction(getServiceNotificationAction(
|
||||
context,
|
||||
WebRtcCallService.ACTION_LOCAL_HANGUP,
|
||||
R.drawable.ic_call_end_grey600_32dp,
|
||||
R.string.NotificationBarManager__end_call
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private fun getServiceNotificationAction(context: Context, action: String, iconResId: Int, titleResId: Int): NotificationCompat.Action {
|
||||
val intent = Intent(context, WebRtcCallService::class.java)
|
||||
.setAction(action)
|
||||
|
||||
val pendingIntent = PendingIntent.getService(context, 0, intent, 0)
|
||||
|
||||
return NotificationCompat.Action(iconResId, context.getString(titleResId), pendingIntent)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private fun getActivityNotificationAction(context: Context, action: String,
|
||||
@DrawableRes iconResId: Int, @StringRes titleResId: Int): NotificationCompat.Action {
|
||||
val intent = Intent(context, WebRtcCallActivity::class.java)
|
||||
.setAction(action)
|
||||
|
||||
val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
|
||||
|
||||
return NotificationCompat.Action(iconResId, context.getString(titleResId), pendingIntent)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -15,7 +15,7 @@ import org.session.libsession.messaging.messages.control.CallMessage
|
||||
import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.calls.WebRtcTestsActivity
|
||||
import org.thoughtcrime.securesms.calls.WebRtcCallActivity
|
||||
import org.thoughtcrime.securesms.mms.GlideApp
|
||||
import java.util.*
|
||||
|
||||
@@ -54,13 +54,13 @@ class CallBottomSheet: BottomSheetDialogFragment() {
|
||||
nameTextView.text = recipient.name ?: address.serialize()
|
||||
|
||||
acceptButton.setOnClickListener {
|
||||
val intent = Intent(requireContext(), WebRtcTestsActivity::class.java)
|
||||
val intent = Intent(requireContext(), WebRtcCallActivity::class.java)
|
||||
val bundle = bundleOf(
|
||||
WebRtcTestsActivity.EXTRA_ADDRESS to address,
|
||||
WebRtcTestsActivity.EXTRA_CALL_ID to callId
|
||||
WebRtcCallActivity.EXTRA_ADDRESS to address,
|
||||
WebRtcCallActivity.EXTRA_CALL_ID to callId
|
||||
)
|
||||
intent.action = WebRtcTestsActivity.ACTION_ANSWER
|
||||
bundle.putStringArray(WebRtcTestsActivity.EXTRA_SDP, sdp)
|
||||
intent.action = WebRtcCallActivity.ACTION_ANSWER
|
||||
bundle.putStringArray(WebRtcCallActivity.EXTRA_SDP, sdp)
|
||||
|
||||
intent.putExtras(bundle)
|
||||
startActivity(intent)
|
||||
|
@@ -11,6 +11,7 @@ import org.session.libsignal.protos.SignalServiceProtos
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.thoughtcrime.securesms.service.WebRtcCallService
|
||||
import org.thoughtcrime.securesms.webrtc.audio.AudioManagerCompat
|
||||
import org.thoughtcrime.securesms.webrtc.audio.OutgoingRinger
|
||||
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager
|
||||
import org.thoughtcrime.securesms.webrtc.video.CameraState
|
||||
import org.webrtc.*
|
||||
@@ -59,19 +60,21 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne
|
||||
val remoteVideoEvents = _remoteVideoEvents.asSharedFlow()
|
||||
private val _connectionEvents = MutableStateFlow<StateEvent>(StateEvent.CallStateUpdate(CallState.STATE_IDLE))
|
||||
val connectionEvents = _connectionEvents.asSharedFlow()
|
||||
private val _callStateEvents = MutableStateFlow(CallViewModel.State.CALL_PENDING)
|
||||
val callStateEvents = _callStateEvents.asSharedFlow()
|
||||
private var localCameraState: CameraState = CameraState.UNKNOWN
|
||||
private var microphoneEnabled = true
|
||||
private var remoteVideoEnabled = false
|
||||
private var bluetoothAvailable = false
|
||||
|
||||
private val currentCallState = (_connectionEvents.value as StateEvent.CallStateUpdate).state
|
||||
val currentConnectionState = (_connectionEvents.value as StateEvent.CallStateUpdate).state
|
||||
|
||||
private val networkExecutor = Executors.newSingleThreadExecutor()
|
||||
|
||||
private var eglBase: EglBase? = null
|
||||
|
||||
private var callId: UUID? = null
|
||||
private var recipient: Recipient? = null
|
||||
var callId: UUID? = null
|
||||
var recipient: Recipient? = null
|
||||
private var peerConnectionWrapper: PeerConnectionWrapper? = null
|
||||
private var dataChannel: DataChannel? = null
|
||||
|
||||
@@ -82,6 +85,23 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne
|
||||
private var remoteRenderer: SurfaceViewRenderer? = null
|
||||
private var peerConnectionFactory: PeerConnectionFactory? = null
|
||||
|
||||
fun clearPendingIceUpdates() {
|
||||
pendingOutgoingIceUpdates.clear()
|
||||
pendingIncomingIceUpdates.clear()
|
||||
}
|
||||
|
||||
fun startOutgoingRinger(ringerType: OutgoingRinger.Type) {
|
||||
signalAudioManager.startOutgoingRinger(ringerType)
|
||||
}
|
||||
|
||||
fun postConnectionEvent(newState: CallState) {
|
||||
_connectionEvents.value = StateEvent.CallStateUpdate(newState)
|
||||
}
|
||||
|
||||
fun postViewModelState(newState: CallViewModel.State) {
|
||||
_callStateEvents.value = newState
|
||||
}
|
||||
|
||||
private fun createCameraCapturer(enumerator: CameraEnumerator): CameraVideoCapturer? {
|
||||
val deviceNames = enumerator.deviceNames
|
||||
|
||||
@@ -128,7 +148,7 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne
|
||||
|
||||
}
|
||||
|
||||
fun isBusy(context: Context) = currentCallState != CallState.STATE_IDLE
|
||||
fun isBusy(context: Context) = currentConnectionState != CallState.STATE_IDLE
|
||||
|| context.getSystemService(TelephonyManager::class.java).callState != TelephonyManager.CALL_STATE_IDLE
|
||||
|
||||
fun initializeVideo(context: Context) {
|
||||
@@ -162,14 +182,14 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne
|
||||
}
|
||||
|
||||
fun setAudioEnabled(isEnabled: Boolean) {
|
||||
currentCallState.withState(*(CONNECTED_STATES + PENDING_CONNECTION_STATES)) {
|
||||
currentConnectionState.withState(*(CONNECTED_STATES + PENDING_CONNECTION_STATES)) {
|
||||
peerConnectionWrapper?.setAudioEnabled(isEnabled)
|
||||
_audioEvents.value = StateEvent.AudioEnabled(true)
|
||||
}
|
||||
}
|
||||
|
||||
fun setVideoEnabled(isEnabled: Boolean) {
|
||||
currentCallState.withState(*(CONNECTED_STATES + PENDING_CONNECTION_STATES)) {
|
||||
currentConnectionState.withState(*(CONNECTED_STATES + PENDING_CONNECTION_STATES)) {
|
||||
peerConnectionWrapper?.setVideoEnabled(isEnabled)
|
||||
_audioEvents.value = StateEvent.AudioEnabled(true)
|
||||
}
|
||||
@@ -236,7 +256,7 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
signalAudioManager.stop(currentCallState in OUTGOING_STATES)
|
||||
signalAudioManager.stop(currentConnectionState in OUTGOING_STATES)
|
||||
peerConnectionWrapper?.dispose()
|
||||
peerConnectionWrapper = null
|
||||
|
||||
|
@@ -14,15 +14,30 @@ import javax.inject.Inject
|
||||
@HiltViewModel
|
||||
class CallViewModel @Inject constructor(private val callManager: CallManager): ViewModel() {
|
||||
|
||||
enum class State {
|
||||
CALL_PENDING,
|
||||
|
||||
CALL_INCOMING,
|
||||
CALL_OUTGOING,
|
||||
CALL_CONNECTED,
|
||||
CALL_RINGING,
|
||||
CALL_BUSY,
|
||||
CALL_DISCONNECTED,
|
||||
|
||||
NETWORK_FAILURE,
|
||||
RECIPIENT_UNAVAILABLE,
|
||||
NO_SUCH_USER,
|
||||
UNTRUSTED_IDENTITY,
|
||||
}
|
||||
|
||||
val localAudioEnabledState = callManager.audioEvents.map { it.isEnabled }
|
||||
val localVideoEnabledState = callManager.videoEvents.map { it.isEnabled }
|
||||
val remoteVideoEnabledState = callManager.remoteVideoEvents.map { it.isEnabled }
|
||||
val callState = callManager.callStateEvents
|
||||
|
||||
// set up listeners for establishing connection toggling video / audio
|
||||
init {
|
||||
callManager.audioEvents.onEach { (enabled) -> callManager.setAudioEnabled(enabled) }
|
||||
.launchIn(viewModelScope)
|
||||
callManager.videoEvents.onEach { (enabled) -> callManager.setVideoEnabled(enabled) }
|
||||
.launchIn(viewModelScope)
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -58,8 +58,8 @@ class SignalAudioManager(private val context: Context,
|
||||
private val connectedSoundId = soundPool.load(context, R.raw.webrtc_completed, 1)
|
||||
private val disconnectedSoundId = soundPool.load(context, R.raw.webrtc_disconnected, 1)
|
||||
|
||||
private val incomingRinger = IncomingRinger(context)
|
||||
private val outgoingRinger = OutgoingRinger(context)
|
||||
val incomingRinger = IncomingRinger(context)
|
||||
val outgoingRinger = OutgoingRinger(context)
|
||||
|
||||
private var wiredHeadsetReceiver: WiredHeadsetReceiver? = null
|
||||
|
||||
@@ -340,7 +340,7 @@ class SignalAudioManager(private val context: Context,
|
||||
incomingRinger.stop()
|
||||
}
|
||||
|
||||
private fun startOutgoingRinger() {
|
||||
fun startOutgoingRinger(type: OutgoingRinger.Type) {
|
||||
Log.i(TAG, "startOutgoingRinger(): currentDevice: $selectedAudioDevice")
|
||||
|
||||
androidAudioManager.mode = AudioManager.MODE_IN_COMMUNICATION
|
||||
|
@@ -903,5 +903,13 @@
|
||||
<string name="activity_settings_support">Debug Log</string>
|
||||
<string name="dialog_share_logs_title">Share Logs</string>
|
||||
<string name="dialog_share_logs_explanation">Would you like to export your application logs to be able to share for troubleshooting?</string>
|
||||
<string name="CallNotificationBuilder_connecting">Connecting…</string>
|
||||
<string name="NotificationBarManager__incoming_signal_call">Incoming call</string>
|
||||
<string name="NotificationBarManager__deny_call">Deny call</string>
|
||||
<string name="NotificationBarManager__answer_call">Answer call</string>
|
||||
<string name="NotificationBarManager_call_in_progress">Call in progress</string>
|
||||
<string name="NotificationBarManager__cancel_call">Cancel call</string>
|
||||
<string name="NotificationBarManager__establishing_signal_call">Establishing call</string>
|
||||
<string name="NotificationBarManager__end_call">End call</string>
|
||||
|
||||
</resources>
|
||||
|
Reference in New Issue
Block a user