feat: adding base for rotation and picking random subset of turn servers

This commit is contained in:
jubb 2022-02-11 16:55:45 +11:00
parent cf06390812
commit 9119ea2d5e
6 changed files with 71 additions and 11 deletions

View file

@ -297,7 +297,6 @@
android:exported="true" android:exported="true"
android:theme="@style/Theme.Session.DayNight.NoActionBar" /> android:theme="@style/Theme.Session.DayNight.NoActionBar" />
<activity android:name="org.thoughtcrime.securesms.calls.WebRtcCallActivity" <activity android:name="org.thoughtcrime.securesms.calls.WebRtcCallActivity"
android:screenOrientation="portrait"
android:launchMode="singleTop" android:launchMode="singleTop"
android:showForAllUsers="true" android:showForAllUsers="true"
android:parentActivityName="org.thoughtcrime.securesms.home.HomeActivity" android:parentActivityName="org.thoughtcrime.securesms.home.HomeActivity"

View file

@ -25,6 +25,7 @@ import network.loki.messenger.databinding.ActivityWebrtcBinding
import org.apache.commons.lang3.time.DurationFormatUtils import org.apache.commons.lang3.time.DurationFormatUtils
import org.session.libsession.avatars.ProfileContactPhoto import org.session.libsession.avatars.ProfileContactPhoto
import org.session.libsession.messaging.contacts.Contact import org.session.libsession.messaging.contacts.Contact
import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.dependencies.DatabaseComponent import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import org.thoughtcrime.securesms.mms.GlideApp import org.thoughtcrime.securesms.mms.GlideApp
@ -181,7 +182,6 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
incomingControlGroup.isVisible = false incomingControlGroup.isVisible = false
} }
} else { } else {
controlGroup.isVisible = state in listOf( controlGroup.isVisible = state in listOf(
CALL_CONNECTED, CALL_CONNECTED,
CALL_OUTGOING, CALL_OUTGOING,
@ -210,6 +210,7 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
launch { launch {
viewModel.callState.collect { state -> viewModel.callState.collect { state ->
Log.d("Loki", "Consuming view model state $state")
when (state) { when (state) {
CALL_RINGING -> { CALL_RINGING -> {
if (wantsToAnswer) { if (wantsToAnswer) {
@ -308,6 +309,13 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
} }
} }
launch {
viewModel.cameraRotations.collect { (localRotation, remoteRotation) ->
val screenRotation = getDeviceRotation()
Log.d("Loki", "local rotation: $localRotation, remote rotation: $remoteRotation, screen rotation: $screenRotation")
}
}
launch { launch {
viewModel.remoteVideoEnabledState.collect { isEnabled -> viewModel.remoteVideoEnabledState.collect { isEnabled ->
binding.remoteRenderer.removeAllViews() binding.remoteRenderer.removeAllViews()
@ -323,6 +331,21 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
} }
} }
private fun getDeviceRotation(): Int {
val rotation = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
display?.rotation
} else {
windowManager.defaultDisplay.rotation
}
return when (rotation) {
Surface.ROTATION_0 -> 0
Surface.ROTATION_180 -> 180
Surface.ROTATION_270 -> 270
Surface.ROTATION_90 -> 90
else -> throw NullPointerException("Unrecognized rotation $rotation")
}
}
private fun getUserDisplayName(publicKey: String): String { private fun getUserDisplayName(publicKey: String): String {
val contact = val contact =
DatabaseComponent.get(this).sessionContactDatabase().getContactWithSessionID(publicKey) DatabaseComponent.get(this).sessionContactDatabase().getContactWithSessionID(publicKey)

View file

@ -85,7 +85,7 @@ class WebRtcCallService: Service(), CallManager.WebRtcListener {
const val EXTRA_WANTS_TO_ANSWER = "wants_to_answer" const val EXTRA_WANTS_TO_ANSWER = "wants_to_answer"
const val INVALID_NOTIFICATION_ID = -1 const val INVALID_NOTIFICATION_ID = -1
private const val TIMEOUT_SECONDS = 30L private const val TIMEOUT_SECONDS = 60L
fun cameraEnabled(context: Context, enabled: Boolean) = Intent(context, WebRtcCallService::class.java) fun cameraEnabled(context: Context, enabled: Boolean) = Intent(context, WebRtcCallService::class.java)
.setAction(ACTION_SET_MUTE_VIDEO) .setAction(ACTION_SET_MUTE_VIDEO)
@ -485,7 +485,6 @@ class WebRtcCallService: Service(), CallManager.WebRtcListener {
Log.e(TAG,e) Log.e(TAG,e)
terminate() terminate()
} }
// DatabaseComponent.get(this).smsDatabase().insertReceivedCall(recipient)
} }
private fun handleDenyCall(intent: Intent) { private fun handleDenyCall(intent: Intent) {

View file

@ -28,6 +28,7 @@ import org.thoughtcrime.securesms.webrtc.video.CameraEventListener
import org.thoughtcrime.securesms.webrtc.video.CameraState import org.thoughtcrime.securesms.webrtc.video.CameraState
import org.webrtc.* import org.webrtc.*
import org.webrtc.PeerConnection.IceConnectionState import org.webrtc.PeerConnection.IceConnectionState
import org.webrtc.RendererCommon.ScalingType.SCALE_ASPECT_FIT
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.util.* import java.util.*
import java.util.concurrent.Executors import java.util.concurrent.Executors
@ -99,6 +100,9 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va
val recipientEvents = _recipientEvents.asSharedFlow() val recipientEvents = _recipientEvents.asSharedFlow()
private var localCameraState: CameraState = CameraState.UNKNOWN private var localCameraState: CameraState = CameraState.UNKNOWN
private val _cameraRotations = MutableStateFlow(0 to 0)
val cameraRotations = _cameraRotations.asSharedFlow()
private val _audioDeviceEvents = MutableStateFlow(AudioDeviceUpdate(AudioDevice.NONE, setOf())) private val _audioDeviceEvents = MutableStateFlow(AudioDeviceUpdate(AudioDevice.NONE, setOf()))
val audioDeviceEvents = _audioDeviceEvents.asSharedFlow() val audioDeviceEvents = _audioDeviceEvents.asSharedFlow()
@ -161,6 +165,7 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va
} }
fun postViewModelState(newState: CallViewModel.State) { fun postViewModelState(newState: CallViewModel.State) {
Log.d("Loki", "Posting view model state $newState")
_callStateEvents.value = newState _callStateEvents.value = newState
} }
@ -177,12 +182,35 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va
Util.runOnMainSync { Util.runOnMainSync {
val base = EglBase.create() val base = EglBase.create()
eglBase = base eglBase = base
localRenderer = SurfaceViewRenderer(context) _cameraRotations.value = 0 to 0
remoteRenderer = SurfaceViewRenderer(context) localRenderer = SurfaceViewRenderer(context).apply {
setEnableHardwareScaler(true)
}
localRenderer?.init(base.eglBaseContext, null) remoteRenderer = SurfaceViewRenderer(context).apply {
localRenderer?.setMirror(true) setEnableHardwareScaler(true)
remoteRenderer?.init(base.eglBaseContext, null) setScalingType(SCALE_ASPECT_FIT, SCALE_ASPECT_FIT)
}
localRenderer?.init(base.eglBaseContext, object : RendererCommon.RendererEvents {
override fun onFirstFrameRendered() {
localCameraState
}
override fun onFrameResolutionChanged(p0: Int, p1: Int, rotation: Int) {
_cameraRotations.value = _cameraRotations.value.copy(first = rotation)
}
})
localRenderer?.setMirror(localCameraState.activeDirection == CameraState.Direction.FRONT)
remoteRenderer?.init(base.eglBaseContext, object : RendererCommon.RendererEvents {
override fun onFirstFrameRendered() {
localCameraState
}
override fun onFrameResolutionChanged(p0: Int, p1: Int, rotation: Int) {
_cameraRotations.value = _cameraRotations.value.copy(second = rotation)
}
})
val encoderFactory = DefaultVideoEncoderFactory(base.eglBaseContext, true, true) val encoderFactory = DefaultVideoEncoderFactory(base.eglBaseContext, true, true)
val decoderFactory = DefaultVideoDecoderFactory(base.eglBaseContext) val decoderFactory = DefaultVideoDecoderFactory(base.eglBaseContext)
@ -216,6 +244,7 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va
} }
override fun onIceConnectionChange(newState: IceConnectionState) { override fun onIceConnectionChange(newState: IceConnectionState) {
Log.d("Loki", "New ice connection state = $newState")
iceState = newState iceState = newState
peerConnectionObservers.forEach { listener -> listener.onIceConnectionChange(newState) } peerConnectionObservers.forEach { listener -> listener.onIceConnectionChange(newState) }
if (newState == IceConnectionState.CONNECTED) { if (newState == IceConnectionState.CONNECTED) {
@ -558,6 +587,7 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va
peerConnection?.let { connection -> peerConnection?.let { connection ->
connection.flipCamera() connection.flipCamera()
localCameraState = connection.getCameraState() localCameraState = connection.getCameraState()
localRenderer?.setMirror(localCameraState.activeDirection == CameraState.Direction.FRONT)
} }
} }

View file

@ -66,6 +66,9 @@ class CallViewModel @Inject constructor(private val callManager: CallManager): V
val remoteVideoEnabledState val remoteVideoEnabledState
get() = callManager.remoteVideoEvents.map { it.isEnabled } get() = callManager.remoteVideoEvents.map { it.isEnabled }
val cameraRotations
get() = callManager.cameraRotations
val currentCallState val currentCallState
get() = callManager.currentCallState get() = callManager.currentCallState

View file

@ -6,7 +6,9 @@ import org.thoughtcrime.securesms.webrtc.video.Camera
import org.thoughtcrime.securesms.webrtc.video.CameraEventListener import org.thoughtcrime.securesms.webrtc.video.CameraEventListener
import org.thoughtcrime.securesms.webrtc.video.CameraState import org.thoughtcrime.securesms.webrtc.video.CameraState
import org.webrtc.* import org.webrtc.*
import java.security.SecureRandom
import java.util.concurrent.ExecutionException import java.util.concurrent.ExecutionException
import kotlin.random.asKotlinRandom
class PeerConnectionWrapper(context: Context, class PeerConnectionWrapper(context: Context,
factory: PeerConnectionFactory, factory: PeerConnectionFactory,
@ -27,8 +29,12 @@ class PeerConnectionWrapper(context: Context,
get() = peerConnection.localDescription != null && peerConnection.remoteDescription != null get() = peerConnection.localDescription != null && peerConnection.remoteDescription != null
init { init {
val iceServers = listOf("freyr","fenrir","frigg","angus","hereford","holstein","brahman").map { sub -> val random = SecureRandom().asKotlinRandom()
PeerConnection.IceServer.builder("turn:$sub.getsession.org").setUsername("session202111").setPassword("053c268164bc7bd7").createIceServer() val iceServers = listOf("freyr","fenrir","frigg","angus","hereford","holstein", "brahman").shuffled(random).take(2).map { sub ->
PeerConnection.IceServer.builder("turn:$sub.getsession.org")
.setUsername("session202111")
.setPassword("053c268164bc7bd7")
.createIceServer()
} }
val constraints = MediaConstraints().apply { val constraints = MediaConstraints().apply {