Toggle HD/SD

This commit is contained in:
Valere 2020-06-19 10:11:45 +02:00
parent f3e2a55869
commit 374790176f
9 changed files with 97 additions and 16 deletions

View file

@ -19,11 +19,14 @@ package im.vector.riotx.features.call
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import com.airbnb.mvrx.activityViewModel
import im.vector.riotx.R
import im.vector.riotx.core.platform.VectorBaseBottomSheetDialogFragment
import kotlinx.android.synthetic.main.activity_call.*
import kotlinx.android.synthetic.main.bottom_sheet_call_controls.*
import kotlinx.android.synthetic.main.vector_preference_push_rule.view.*
import me.gujun.android.span.span
class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment() {
@ -47,6 +50,11 @@ class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment() {
dismiss()
}
callControlsToggleSDHD.clickableView.debouncedClicks {
callViewModel.handle(VectorCallViewActions.ToggleHDSD)
dismiss()
}
callViewModel.observeViewEvents {
when (it) {
is VectorCallViewEvents.ShowSoundDeviceChooser -> {
@ -112,5 +120,20 @@ class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment() {
callControlsSwitchCamera.isVisible = state.canSwitchCamera
callControlsSwitchCamera.subTitle = getString(if (state.isFrontCamera) R.string.call_camera_front else R.string.call_camera_back)
if (state.isVideoCall) {
callControlsToggleSDHD.isVisible = true
if (state.isHD) {
callControlsToggleSDHD.title = getString(R.string.call_format_turn_hd_off)
callControlsToggleSDHD.subTitle = null
callControlsToggleSDHD.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_hd)
} else {
callControlsToggleSDHD.title = getString(R.string.call_format_turn_hd_on)
callControlsToggleSDHD.subTitle = null
callControlsToggleSDHD.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_hd_disabled)
}
} else {
callControlsToggleSDHD.isVisible = false
}
}
}

View file

@ -25,3 +25,8 @@ data class CameraProxy(
val name: String,
val type: CameraType
)
sealed class CaptureFormat(val width: Int, val height: Int, val fps: Int) {
object HD : CaptureFormat(1280, 720, 30)
object SD : CaptureFormat(640, 480, 30)
}

View file

@ -33,12 +33,12 @@ class SharedActiveCallViewModel @Inject constructor(
val activeCall: MutableLiveData<MxCall?> = MutableLiveData()
val callStateListener = object: MxCall.StateListener {
val callStateListener = object : MxCall.StateListener {
override fun onStateUpdate(call: MxCall) {
if (activeCall.value?.callId == call.callId) {
activeCall.postValue(call)
}
if (activeCall.value?.callId == call.callId) {
activeCall.postValue(call)
}
}
}
@ -48,10 +48,6 @@ class SharedActiveCallViewModel @Inject constructor(
activeCall.postValue(call)
call?.addListener(callStateListener)
}
override fun onCaptureStateChanged(captureInError: Boolean) {
// nop
}
}
init {

View file

@ -48,6 +48,7 @@ data class VectorCallViewState(
val isAudioMuted: Boolean = false,
val isVideoEnabled: Boolean = true,
val isVideoCaptureInError: Boolean = false,
val isHD: Boolean = false,
val isFrontCamera: Boolean = true,
val canSwitchCamera: Boolean = true,
val soundDevice: CallAudioManager.SoundDevice = CallAudioManager.SoundDevice.PHONE,
@ -66,6 +67,7 @@ sealed class VectorCallViewActions : VectorViewModelAction {
object SwitchSoundDevice : VectorCallViewActions()
object HeadSetButtonPressed : VectorCallViewActions()
object ToggleCamera : VectorCallViewActions()
object ToggleHDSD : VectorCallViewActions()
}
sealed class VectorCallViewEvents : VectorViewEvents {
@ -129,9 +131,12 @@ class VectorCallViewModel @AssistedInject constructor(
override fun onCurrentCallChange(call: MxCall?) {
}
override fun onCaptureStateChanged(captureInError: Boolean) {
override fun onCaptureStateChanged(mgr: WebRtcPeerConnectionManager) {
setState {
copy(isVideoCaptureInError = captureInError)
copy(
isVideoCaptureInError = mgr.capturerIsInError,
isHD = mgr.currentCaptureFormat() is CaptureFormat.HD
)
}
}
@ -174,7 +179,8 @@ class VectorCallViewModel @AssistedInject constructor(
soundDevice = webRtcPeerConnectionManager.audioManager.getCurrentSoundDevice(),
availableSoundDevices = webRtcPeerConnectionManager.audioManager.getAvailableSoundDevices(),
isFrontCamera = webRtcPeerConnectionManager.currentCameraType() == CameraType.FRONT,
canSwitchCamera = webRtcPeerConnectionManager.canSwitchCamera()
canSwitchCamera = webRtcPeerConnectionManager.canSwitchCamera(),
isHD = mxCall.isVideoCall && webRtcPeerConnectionManager.currentCaptureFormat() is CaptureFormat.HD
)
}
} ?: run {
@ -253,6 +259,10 @@ class VectorCallViewModel @AssistedInject constructor(
VectorCallViewActions.ToggleCamera -> {
webRtcPeerConnectionManager.switchCamera()
}
VectorCallViewActions.ToggleHDSD -> {
if (!state.isVideoCall) return@withState
webRtcPeerConnectionManager.setCaptureFormat(if (state.isHD) CaptureFormat.SD else CaptureFormat.HD)
}
}.exhaustive
}

View file

@ -76,7 +76,7 @@ class WebRtcPeerConnectionManager @Inject constructor(
interface CurrentCallListener {
fun onCurrentCallChange(call: MxCall?)
fun onCaptureStateChanged(captureInError: Boolean)
fun onCaptureStateChanged(mgr: WebRtcPeerConnectionManager) {}
fun onAudioDevicesChange(mgr: WebRtcPeerConnectionManager) {}
fun onCameraChange(mgr: WebRtcPeerConnectionManager) {}
}
@ -165,11 +165,13 @@ class WebRtcPeerConnectionManager @Inject constructor(
private val availableCamera = ArrayList<CameraProxy>()
private var cameraInUse: CameraProxy? = null
private var currentCaptureMode: CaptureFormat = CaptureFormat.HD
var capturerIsInError = false
set(value) {
field = value
currentCallsListeners.forEach {
tryThis { it.onCaptureStateChanged(value) }
tryThis { it.onCaptureStateChanged(this) }
}
}
@ -336,7 +338,7 @@ class WebRtcPeerConnectionManager @Inject constructor(
// Fallback for old android, try to restart capture when attached
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && capturerIsInError && call.mxCall.isVideoCall) {
// try to restart capture?
videoCapturer?.startCapture(1280, 720, 30)
videoCapturer?.startCapture(currentCaptureMode.width, currentCaptureMode.height, currentCaptureMode.fps)
}
// sink existing tracks (configuration change, e.g screen rotation)
attachViewRenderersInternal()
@ -463,7 +465,7 @@ class WebRtcPeerConnectionManager @Inject constructor(
videoCapturer.initialize(surfaceTextureHelper, context.applicationContext, videoSource!!.capturerObserver)
// HD
videoCapturer.startCapture(1280, 720, 30)
videoCapturer.startCapture(currentCaptureMode.width, currentCaptureMode.height, currentCaptureMode.fps)
this.videoCapturer = videoCapturer
val localVideoTrack = peerConnectionFactory!!.createVideoTrack("ARDAMSv0", videoSource)
@ -706,6 +708,21 @@ class WebRtcPeerConnectionManager @Inject constructor(
return cameraInUse?.type
}
fun setCaptureFormat(format: CaptureFormat) {
Timber.v("## VOIP setCaptureFormat $format")
currentCall ?: return
executor.execute {
// videoCapturer?.stopCapture()
videoCapturer?.changeCaptureFormat(format.width, format.height, format.fps)
currentCaptureMode = format
currentCallsListeners.forEach { tryThis { it.onCaptureStateChanged(this) } }
}
}
fun currentCaptureFormat(): CaptureFormat {
return currentCaptureMode
}
fun endCall() {
// Update service state
CallService.onNoActiveCall(context)
@ -971,7 +988,7 @@ class WebRtcPeerConnectionManager @Inject constructor(
if (this.cameraId == cameraId && currentCall?.mxCall?.callId == callId) {
// re-start the capture
// TODO notify that video is enabled
videoCapturer?.startCapture(1280, 720, 30)
videoCapturer?.startCapture(currentCaptureMode.width, currentCaptureMode.height, currentCaptureMode.fps)
(context.getSystemService(Context.CAMERA_SERVICE) as? CameraManager)
?.unregisterAvailabilityCallback(this)
}

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M19,3H5C3.89,3 3,3.9 3,5V19C3,20.1 3.89,21 5,21H19C20.1,21 21,20.1 21,19V5C21,3.9 20.1,3 19,3ZM11,15H9.5V13H7.5V15H6V9H7.5V11.5H9.5V9H11V15ZM13,9H17C17.55,9 18,9.45 18,10V14C18,14.55 17.55,15 17,15H13V9ZM14.5,13.5H16.5V10.5H14.5V13.5Z"
android:fillColor="#000000"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M17.5,15V13H18.6L19.5,15H21L20.1,12.9C20.6,12.7 21,12.1 21,11.5V10.5C21,9.7 20.3,9 19.5,9H16V13.9L17.1,15H17.5ZM17.5,10.5H19.5V11.5H17.5V10.5ZM13,10.5V10.9L14.5,12.4V10.5C14.5,9.7 13.8,9 13,9H11.1L12.6,10.5H13ZM9.5,9.5L2.5,2.5L1.4,3.5L6.9,9H6.5V11H4.5V9H3V15H4.5V12.5H6.5V15H8V10.1L9.5,11.6V15H12.9L20.5,22.6L21.6,21.5L9.5,9.5Z"
android:fillColor="#000000"/>
</vector>

View file

@ -25,4 +25,13 @@
app:leftIcon="@drawable/ic_video_flip"
app:tint="?attr/riotx_text_primary" />
<im.vector.riotx.core.ui.views.BottomSheetActionButton
android:id="@+id/callControlsToggleSDHD"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:actionTitle="@string/call_switch_camera"
tools:actionDescription="Front"
app:leftIcon="@drawable/ic_hd"
app:tint="?attr/riotx_text_primary" />
</LinearLayout>

View file

@ -222,6 +222,9 @@
<string name="call_switch_camera">Switch Camera</string>
<string name="call_camera_front">Front</string>
<string name="call_camera_back">Back</string>
<string name="call_format_turn_hd_off">Turn HD off</string>
<string name="call_format_turn_hd_on">Turn HD on</string>
<string name="option_send_files">Send files</string>