feat: starting the screen rotation processing

This commit is contained in:
jubb 2022-02-14 17:24:28 +11:00
parent 9119ea2d5e
commit eb2e3d075e
6 changed files with 87 additions and 35 deletions

View File

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

View File

@ -8,7 +8,10 @@ import android.content.IntentFilter
import android.media.AudioManager
import android.os.Build
import android.os.Bundle
import android.view.*
import android.view.MenuItem
import android.view.OrientationEventListener
import android.view.Surface
import android.view.WindowManager
import androidx.activity.viewModels
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
@ -34,9 +37,13 @@ import org.thoughtcrime.securesms.service.WebRtcCallService
import org.thoughtcrime.securesms.util.AvatarPlaceholderGenerator
import org.thoughtcrime.securesms.webrtc.AudioManagerCommand
import org.thoughtcrime.securesms.webrtc.CallViewModel
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.*
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager.AudioDevice.*
import java.util.*
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_CONNECTED
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_INCOMING
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_OUTGOING
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_PRE_INIT
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_RINGING
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager.AudioDevice.EARPIECE
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager.AudioDevice.SPEAKER_PHONE
@AndroidEntryPoint
class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
@ -63,6 +70,14 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
}
private var hangupReceiver: BroadcastReceiver? = null
private val rotationListener by lazy {
object : OrientationEventListener(this) {
override fun onOrientationChanged(orientation: Int) {
viewModel.setDeviceRotation(orientation)
}
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
finish()
@ -81,6 +96,7 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
super.onCreate(savedInstanceState, ready)
rotationListener.enable()
binding = ActivityWebrtcBinding.inflate(layoutInflater)
setContentView(binding.root)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
@ -166,6 +182,7 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
hangupReceiver?.let { receiver ->
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver)
}
rotationListener.disable()
}
private fun answerCall() {
@ -174,7 +191,7 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
}
private fun updateControls(state: CallViewModel.State? = null) {
with (binding) {
with(binding) {
if (state == null) {
if (wantsToAnswer) {
controlGroup.isVisible = true
@ -309,13 +326,6 @@ 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 {
viewModel.remoteVideoEnabledState.collect { isEnabled ->
binding.remoteRenderer.removeAllViews()

View File

@ -28,6 +28,7 @@ import org.thoughtcrime.securesms.webrtc.video.CameraEventListener
import org.thoughtcrime.securesms.webrtc.video.CameraState
import org.webrtc.*
import org.webrtc.PeerConnection.IceConnectionState
import org.webrtc.RendererCommon.ScalingType.SCALE_ASPECT_FILL
import org.webrtc.RendererCommon.ScalingType.SCALE_ASPECT_FIT
import java.nio.ByteBuffer
import java.util.*
@ -100,9 +101,6 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va
val recipientEvents = _recipientEvents.asSharedFlow()
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()))
val audioDeviceEvents = _audioDeviceEvents.asSharedFlow()
@ -182,35 +180,25 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va
Util.runOnMainSync {
val base = EglBase.create()
eglBase = base
_cameraRotations.value = 0 to 0
localRenderer = SurfaceViewRenderer(context).apply {
setEnableHardwareScaler(true)
}
remoteRenderer = SurfaceViewRenderer(context).apply {
setEnableHardwareScaler(true)
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?.init(base.eglBaseContext, null)
localRenderer?.setMirror(localCameraState.activeDirection == CameraState.Direction.FRONT)
remoteRenderer?.init(base.eglBaseContext, object : RendererCommon.RendererEvents {
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)
override fun onFrameResolutionChanged(p0: Int, p1: Int, p2: Int) {
Log.d("Loki", "remote rotation: $p2")
}
})
remoteRenderer?.setScalingType(SCALE_ASPECT_FIT)
val encoderFactory = DefaultVideoEncoderFactory(base.eglBaseContext, true, true)
val decoderFactory = DefaultVideoDecoderFactory(base.eglBaseContext)
@ -591,6 +579,10 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va
}
}
fun setDeviceRotation(newRotation: Int) {
peerConnection?.setDeviceRotation(newRotation)
}
fun handleWiredHeadsetChanged(present: Boolean) {
if (currentConnectionState in arrayOf(CallState.STATE_CONNECTED,
CallState.STATE_DIALING,

View File

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

View File

@ -5,6 +5,7 @@ import org.session.libsignal.utilities.SettableFuture
import org.thoughtcrime.securesms.webrtc.video.Camera
import org.thoughtcrime.securesms.webrtc.video.CameraEventListener
import org.thoughtcrime.securesms.webrtc.video.CameraState
import org.thoughtcrime.securesms.webrtc.video.RotationVideoSink
import org.webrtc.*
import java.security.SecureRandom
import java.util.concurrent.ExecutionException
@ -24,6 +25,7 @@ class PeerConnectionWrapper(context: Context,
private val camera: Camera
private val videoSource: VideoSource?
private val videoTrack: VideoTrack?
private val rotationVideoSink = RotationVideoSink()
val readyForIce
get() = peerConnection.localDescription != null && peerConnection.remoteDescription != null
@ -66,13 +68,12 @@ class PeerConnectionWrapper(context: Context,
if (camera.capturer != null) {
videoSource = factory.createVideoSource(false)
videoTrack = factory.createVideoTrack("ARDAMSv0", videoSource)
rotationVideoSink.setObserver(videoSource.capturerObserver)
camera.capturer.initialize(
SurfaceTextureHelper.create("WebRTC-SurfaceTextureHelper", eglBase.eglBaseContext),
context,
videoSource.capturerObserver
rotationVideoSink
)
videoTrack.addSink(localRenderer)
videoTrack.setEnabled(false)
mediaStream.addTrack(videoTrack)
@ -276,6 +277,10 @@ class PeerConnectionWrapper(context: Context,
audioTrack.setEnabled(isEnabled)
}
fun setDeviceRotation(rotation: Int) {
rotationVideoSink.rotation = rotation
}
fun setVideoEnabled(isEnabled: Boolean) {
videoTrack?.let { track ->
track.setEnabled(isEnabled)

View File

@ -0,0 +1,43 @@
package org.thoughtcrime.securesms.webrtc.video
import org.session.libsignal.utilities.Log
import org.webrtc.CapturerObserver
import org.webrtc.VideoFrame
import java.lang.ref.SoftReference
import java.util.concurrent.atomic.AtomicBoolean
class RotationVideoSink: CapturerObserver {
var rotation: Int = 0
private val capturing = AtomicBoolean(false)
private var capturerObserver = SoftReference<CapturerObserver>(null)
override fun onCapturerStarted(ignored: Boolean) {
capturing.set(true)
}
override fun onCapturerStopped() {
capturing.set(false)
}
override fun onFrameCaptured(videoFrame: VideoFrame?) {
// rotate if need
val observer = capturerObserver.get()
if (videoFrame == null || observer == null || !capturing.get()) return
val quadrantRotation = when (rotation % 360) {
in 0 until 90 -> 90
in 90 until 180 -> 180
in 180 until 270 -> 270
else -> 0
}
val newFrame = VideoFrame(videoFrame.buffer, quadrantRotation, videoFrame.timestampNs)
observer.onFrameCaptured(newFrame)
}
fun setObserver(videoSink: CapturerObserver?) {
capturerObserver = SoftReference(videoSink)
}
}