feat: starting the screen rotation processing
This commit is contained in:
parent
9119ea2d5e
commit
eb2e3d075e
|
@ -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">
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue