mirror of
https://github.com/oxen-io/session-android.git
synced 2023-12-14 02:53:01 +01:00
feat: adding base for rotation and picking random subset of turn servers
This commit is contained in:
parent
cf06390812
commit
9119ea2d5e
|
@ -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"
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue