feat: setting up rotation for the remote render view

This commit is contained in:
jubb 2022-02-15 16:17:14 +11:00
parent eb2e3d075e
commit a11a5da7c2
8 changed files with 86 additions and 20 deletions

View File

@ -44,6 +44,8 @@ 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
import org.thoughtcrime.securesms.webrtc.data.quadrantRotation
import org.thoughtcrime.securesms.webrtc.video.RotationVideoProcessor
@AndroidEntryPoint
class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
@ -73,7 +75,7 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
private val rotationListener by lazy {
object : OrientationEventListener(this) {
override fun onOrientationChanged(orientation: Int) {
viewModel.setDeviceRotation(orientation)
viewModel.deviceRotation = orientation
}
}
}

View File

@ -2,6 +2,8 @@ package org.thoughtcrime.securesms.webrtc
import android.content.Context
import android.telephony.TelephonyManager
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.*
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.serialization.Serializable
@ -182,10 +184,12 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va
eglBase = base
localRenderer = SurfaceViewRenderer(context).apply {
setEnableHardwareScaler(true)
setScalingType(SCALE_ASPECT_FIT)
}
remoteRenderer = SurfaceViewRenderer(context).apply {
setEnableHardwareScaler(true)
setScalingType(SCALE_ASPECT_FIT)
}
localRenderer?.init(base.eglBaseContext, null)
@ -198,7 +202,6 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va
Log.d("Loki", "remote rotation: $p2")
}
})
remoteRenderer?.setScalingType(SCALE_ASPECT_FIT)
val encoderFactory = DefaultVideoEncoderFactory(base.eglBaseContext, true, true)
val decoderFactory = DefaultVideoDecoderFactory(base.eglBaseContext)

View File

@ -66,9 +66,11 @@ class CallViewModel @Inject constructor(private val callManager: CallManager): V
val remoteVideoEnabledState
get() = callManager.remoteVideoEvents.map { it.isEnabled }
fun setDeviceRotation(newRotation: Int) {
callManager.setDeviceRotation(newRotation)
}
var deviceRotation: Int = 0
set(value) {
field = value
callManager.setDeviceRotation(value)
}
val currentCallState
get() = callManager.currentCallState

View File

@ -1,10 +1,12 @@
package org.thoughtcrime.securesms.webrtc
import android.content.Context
import org.session.libsignal.utilities.Log
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.RotationVideoProcessor
import org.thoughtcrime.securesms.webrtc.video.RotationVideoSink
import org.webrtc.*
import java.security.SecureRandom
@ -74,7 +76,7 @@ class PeerConnectionWrapper(context: Context,
context,
rotationVideoSink
)
videoTrack.addSink(localRenderer)
rotationVideoSink.setSink(localRenderer)
videoTrack.setEnabled(false)
mediaStream.addTrack(videoTrack)
} else {
@ -278,6 +280,7 @@ class PeerConnectionWrapper(context: Context,
}
fun setDeviceRotation(rotation: Int) {
Log.d("Loki", "rotation: $rotation")
rotationVideoSink.rotation = rotation
}

View File

@ -0,0 +1,11 @@
package org.thoughtcrime.securesms.webrtc.data
// get the video rotation from a specific rotation, locked into 90 degree
// chunks offset by 45 degrees
fun Int.quadrantRotation() = when (this % 360) {
in 315 until 360,
in 0 until 45 -> 90
in 45 until 135 -> 180
in 135 until 225 -> 270
else -> 0
}

View File

@ -0,0 +1,35 @@
package org.thoughtcrime.securesms.webrtc.video
import kotlinx.coroutines.newSingleThreadContext
import org.webrtc.VideoFrame
import org.webrtc.VideoProcessor
import org.webrtc.VideoSink
class RotationVideoProcessor: VideoProcessor {
private var isCapturing: Boolean = true
private var sink: VideoSink? = null
var rotation: Int = 0
override fun onCapturerStarted(p0: Boolean) {
isCapturing = true
}
override fun onCapturerStopped() {
isCapturing = false
}
override fun onFrameCaptured(frame: VideoFrame?) {
val thisSink = sink ?: return
val thisFrame = frame ?: return
val newFrame = VideoFrame(thisFrame.buffer, rotation, thisFrame.timestampNs)
thisSink.onFrame(newFrame)
}
override fun setSink(newSink: VideoSink?) {
sink = newSink
}
}

View File

@ -1,17 +1,20 @@
package org.thoughtcrime.securesms.webrtc.video
import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.webrtc.data.quadrantRotation
import org.webrtc.CapturerObserver
import org.webrtc.VideoFrame
import org.webrtc.VideoProcessor
import org.webrtc.VideoSink
import java.lang.ref.SoftReference
import java.util.concurrent.atomic.AtomicBoolean
class RotationVideoSink: CapturerObserver {
class RotationVideoSink: CapturerObserver, VideoProcessor {
var rotation: Int = 0
private val capturing = AtomicBoolean(false)
private var capturerObserver = SoftReference<CapturerObserver>(null)
private var sink = SoftReference<VideoSink>(null)
override fun onCapturerStarted(ignored: Boolean) {
capturing.set(true)
@ -26,15 +29,19 @@ class RotationVideoSink: CapturerObserver {
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 quadrantRotation = rotation.quadrantRotation()
val localRotation = 90
val newFrame = VideoFrame(videoFrame.buffer, quadrantRotation, videoFrame.timestampNs)
val localFrame = VideoFrame(videoFrame.buffer, localRotation, videoFrame.timestampNs)
observer.onFrameCaptured(newFrame)
sink.get()?.onFrame(localFrame)
}
override fun setSink(sink: VideoSink?) {
this.sink = SoftReference(sink)
}
fun setObserver(videoSink: CapturerObserver?) {

View File

@ -9,15 +9,18 @@
<FrameLayout
android:id="@+id/remote_parent"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent">
<FrameLayout
android:id="@+id/remote_renderer"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
</FrameLayout>
<ImageView
android:id="@+id/remote_recipient"