mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-24 22:17:25 +00:00
refactor: moving call code around to service and viewmodel interactions
This commit is contained in:
@@ -37,11 +37,11 @@ dependencies {
|
||||
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
||||
implementation 'androidx.exifinterface:exifinterface:1.2.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-common-java8:2.3.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.4.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-common-java8:2.4.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.0'
|
||||
implementation 'androidx.activity:activity-ktx:1.2.2'
|
||||
implementation 'androidx.fragment:fragment-ktx:1.3.2'
|
||||
implementation "androidx.core:core-ktx:1.3.2"
|
||||
|
@@ -7,8 +7,10 @@ import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import androidx.activity.viewModels
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.android.synthetic.main.activity_webrtc_tests.*
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
@@ -22,10 +24,11 @@ import org.session.libsignal.protos.SignalServiceProtos
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.permissions.Permissions
|
||||
import org.thoughtcrime.securesms.webrtc.CallViewModel
|
||||
import org.webrtc.*
|
||||
import java.util.*
|
||||
|
||||
|
||||
@AndroidEntryPoint
|
||||
class WebRtcTestsActivity: PassphraseRequiredActionBarActivity(), PeerConnection.Observer,
|
||||
SdpObserver, RTCStatsCollectorCallback {
|
||||
|
||||
@@ -45,25 +48,14 @@ class WebRtcTestsActivity: PassphraseRequiredActionBarActivity(), PeerConnection
|
||||
|
||||
}
|
||||
|
||||
private val eglBase by lazy { EglBase.create() }
|
||||
private val surfaceHelper by lazy { SurfaceTextureHelper.create(Thread.currentThread().name, eglBase.eglBaseContext) }
|
||||
private val viewModel by viewModels<CallViewModel>()
|
||||
|
||||
private val surfaceHelper by lazy { SurfaceTextureHelper.create(Thread.currentThread().name, viewModel.eglBaseContext) }
|
||||
private val audioSource by lazy { connectionFactory.createAudioSource(MediaConstraints()) }
|
||||
private val videoCapturer by lazy { createCameraCapturer(Camera2Enumerator(this)) }
|
||||
|
||||
private val acceptedCallMessageHashes = mutableSetOf<Int>()
|
||||
|
||||
private val connectionFactory by lazy {
|
||||
|
||||
val decoderFactory = DefaultVideoDecoderFactory(eglBase.eglBaseContext)
|
||||
val encoderFactory = DefaultVideoEncoderFactory(eglBase.eglBaseContext, true, true)
|
||||
|
||||
PeerConnectionFactory.builder()
|
||||
.setVideoDecoderFactory(decoderFactory)
|
||||
.setVideoEncoderFactory(encoderFactory)
|
||||
.setOptions(PeerConnectionFactory.Options())
|
||||
.createPeerConnectionFactory()
|
||||
}
|
||||
|
||||
private val candidates: MutableList<IceCandidate> = mutableListOf()
|
||||
private val iceDebouncer = Debouncer(2_000)
|
||||
|
||||
@@ -90,20 +82,6 @@ class WebRtcTestsActivity: PassphraseRequiredActionBarActivity(), PeerConnection
|
||||
private lateinit var callAddress: Address
|
||||
private lateinit var callId: UUID
|
||||
|
||||
private val peerConnection by lazy {
|
||||
// TODO: in a lokinet world, ice servers shouldn't be needed as .loki addresses should suffice to p2p
|
||||
val stun = PeerConnection.IceServer.builder("stun:freyr.getsession.org:5349").setTlsCertPolicy(PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK).createIceServer()
|
||||
val turn = PeerConnection.IceServer.builder("turn:freyr.getsession.org:5349").setUsername("webrtc").setPassword("webrtc").setTlsCertPolicy(PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK).createIceServer()
|
||||
val iceServers = mutableListOf(turn, stun)
|
||||
val rtcConfig = PeerConnection.RTCConfiguration(iceServers).apply {
|
||||
this.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.ENABLED
|
||||
this.candidateNetworkPolicy = PeerConnection.CandidateNetworkPolicy.ALL
|
||||
// this.iceTransportsType = PeerConnection.IceTransportsType.RELAY
|
||||
}
|
||||
rtcConfig.keyType = PeerConnection.KeyType.ECDSA
|
||||
connectionFactory.createPeerConnection(rtcConfig, this)!!
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
endCall()
|
||||
}
|
||||
|
@@ -11,8 +11,11 @@ import org.thoughtcrime.securesms.dependencies.CallComponent
|
||||
import org.thoughtcrime.securesms.webrtc.AudioManagerCommand
|
||||
import org.thoughtcrime.securesms.webrtc.CallManager
|
||||
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager
|
||||
import java.sql.CallableStatement
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.properties.Delegates
|
||||
import kotlin.properties.Delegates.observable
|
||||
|
||||
@AndroidEntryPoint
|
||||
class WebRtcCallService: Service(), SignalAudioManager.EventListener {
|
||||
@@ -22,6 +25,10 @@ class WebRtcCallService: Service(), SignalAudioManager.EventListener {
|
||||
SignalAudioManager(this, this, CallComponent.get(this).callManagerCompat())
|
||||
}
|
||||
|
||||
private enum class CallState {
|
||||
STATE_IDLE, STATE_DIALING, STATE_ANSWERING, STATE_REMOTE_RINGING, STATE_LOCAL_RINGING, STATE_CONNECTED
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ACTION_UPDATE = "UPDATE"
|
||||
private const val ACTION_STOP = "STOP"
|
||||
@@ -74,6 +81,10 @@ class WebRtcCallService: Service(), SignalAudioManager.EventListener {
|
||||
}
|
||||
}
|
||||
|
||||
private var state: CallState by observable(CallState.STATE_IDLE) { _, previousValue, newValue ->
|
||||
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? = null
|
||||
|
||||
override fun onCreate() {
|
||||
|
@@ -3,16 +3,44 @@ package org.thoughtcrime.securesms.webrtc
|
||||
import android.content.Context
|
||||
import com.android.mms.transaction.MessageSender
|
||||
import org.thoughtcrime.securesms.database.Storage
|
||||
import org.webrtc.*
|
||||
import java.util.concurrent.Executors
|
||||
import javax.inject.Inject
|
||||
|
||||
class CallManager(private val context: Context,
|
||||
private val storage: Storage) {
|
||||
private val storage: Storage): PeerConnection.Observer {
|
||||
|
||||
private val serviceExecutor = Executors.newSingleThreadExecutor()
|
||||
private val networkExecutor = Executors.newSingleThreadExecutor()
|
||||
|
||||
private val eglBase: EglBase = EglBase.create()
|
||||
|
||||
private val connectionFactory by lazy {
|
||||
|
||||
val decoderFactory = DefaultVideoDecoderFactory(eglBase.eglBaseContext)
|
||||
val encoderFactory = DefaultVideoEncoderFactory(eglBase.eglBaseContext, true, true)
|
||||
|
||||
PeerConnectionFactory.builder()
|
||||
.setVideoDecoderFactory(decoderFactory)
|
||||
.setVideoEncoderFactory(encoderFactory)
|
||||
.setOptions(PeerConnectionFactory.Options())
|
||||
.createPeerConnectionFactory()!!
|
||||
}
|
||||
|
||||
private var peerConnection: PeerConnection? = null
|
||||
|
||||
private fun getPeerConnection(): PeerConnection {
|
||||
val stun = PeerConnection.IceServer.builder("stun:freyr.getsession.org:5349").setTlsCertPolicy(PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK).createIceServer()
|
||||
val turn = PeerConnection.IceServer.builder("turn:freyr.getsession.org:5349").setUsername("webrtc").setPassword("webrtc").setTlsCertPolicy(PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK).createIceServer()
|
||||
val iceServers = mutableListOf(turn, stun)
|
||||
val rtcConfig = PeerConnection.RTCConfiguration(iceServers).apply {
|
||||
this.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.ENABLED
|
||||
this.candidateNetworkPolicy = PeerConnection.CandidateNetworkPolicy.ALL
|
||||
// this.iceTransportsType = PeerConnection.IceTransportsType.RELAY
|
||||
}
|
||||
rtcConfig.keyType = PeerConnection.KeyType.ECDSA
|
||||
return connectionFactory.createPeerConnection(rtcConfig, this)!!
|
||||
}
|
||||
|
||||
fun networkChange(networkAvailable: Boolean) {
|
||||
|
||||
@@ -26,6 +54,11 @@ class CallManager(private val context: Context,
|
||||
|
||||
}
|
||||
|
||||
fun callEnded() {
|
||||
peerConnection?.close()
|
||||
peerConnection = null
|
||||
}
|
||||
|
||||
fun setAudioEnabled(isEnabled: Boolean) {
|
||||
|
||||
}
|
||||
@@ -34,4 +67,47 @@ class CallManager(private val context: Context,
|
||||
|
||||
}
|
||||
|
||||
override fun onSignalingChange(p0: PeerConnection.SignalingState?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun onIceConnectionChange(p0: PeerConnection.IceConnectionState?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun onIceConnectionReceivingChange(p0: Boolean) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun onIceGatheringChange(p0: PeerConnection.IceGatheringState?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun onIceCandidate(p0: IceCandidate?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun onIceCandidatesRemoved(p0: Array<out IceCandidate>?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun onAddStream(p0: MediaStream?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun onRemoveStream(p0: MediaStream?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun onDataChannel(p0: DataChannel?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun onRenegotiationNeeded() {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun onAddTrack(p0: RtpReceiver?, p1: Array<out MediaStream>?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
@@ -6,12 +6,13 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import org.webrtc.*
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class CallViewModel @Inject constructor(
|
||||
private val callManager: CallManager
|
||||
): ViewModel() {
|
||||
): ViewModel(), PeerConnection.Observer {
|
||||
|
||||
sealed class StateEvent {
|
||||
data class AudioEnabled(val isEnabled: Boolean): StateEvent()
|
||||
@@ -21,6 +22,8 @@ class CallViewModel @Inject constructor(
|
||||
private val audioEnabledState = MutableStateFlow(StateEvent.AudioEnabled(true))
|
||||
private val videoEnabledState = MutableStateFlow(StateEvent.VideoEnabled(false))
|
||||
|
||||
private val peerConnection = callManager.getPeerConnection(this)
|
||||
|
||||
// set up listeners for establishing connection toggling video / audio
|
||||
init {
|
||||
audioEnabledState.onEach { (enabled) -> callManager.setAudioEnabled(enabled) }
|
||||
@@ -29,4 +32,48 @@ class CallViewModel @Inject constructor(
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
override fun onSignalingChange(p0: PeerConnection.SignalingState?) {
|
||||
|
||||
}
|
||||
|
||||
override fun onIceConnectionChange(p0: PeerConnection.IceConnectionState?) {
|
||||
|
||||
}
|
||||
|
||||
override fun onIceConnectionReceivingChange(p0: Boolean) {
|
||||
|
||||
}
|
||||
|
||||
override fun onIceGatheringChange(p0: PeerConnection.IceGatheringState?) {
|
||||
|
||||
}
|
||||
|
||||
override fun onIceCandidate(p0: IceCandidate?) {
|
||||
|
||||
}
|
||||
|
||||
override fun onIceCandidatesRemoved(p0: Array<out IceCandidate>?) {
|
||||
|
||||
}
|
||||
|
||||
override fun onAddStream(p0: MediaStream?) {
|
||||
|
||||
}
|
||||
|
||||
override fun onRemoveStream(p0: MediaStream?) {
|
||||
|
||||
}
|
||||
|
||||
override fun onDataChannel(p0: DataChannel?) {
|
||||
|
||||
}
|
||||
|
||||
override fun onRenegotiationNeeded() {
|
||||
|
||||
}
|
||||
|
||||
override fun onAddTrack(p0: RtpReceiver?, p1: Array<out MediaStream>?) {
|
||||
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user