Conference: disable video when using audio only layout + sort participants device depending on layout

This commit is contained in:
Sylvain Berfini 2022-02-25 13:42:42 +01:00
parent 26f06436f4
commit ab0cc34b24
4 changed files with 61 additions and 51 deletions

View file

@ -106,7 +106,7 @@ class ConferenceWaitingRoomViewModel : ViewModel() {
isAudioOnlyLayoutSelected.value = false
updateLayout()
isVideoAvailable.value = core.isVideoCaptureEnabled || core.isVideoPreviewEnabled
isVideoAvailable.value = isAudioOnlyLayoutSelected.value == false && (core.isVideoCaptureEnabled || core.isVideoPreviewEnabled)
callParams.isVideoEnabled = isVideoAvailable.value == true
callParams.videoDirection = if (core.videoActivationPolicy.automaticallyInitiate) MediaDirection.SendRecv else MediaDirection.RecvOnly
Log.i("[Conference Waiting Room] Video will be ${if (callParams.isVideoEnabled) "enabled" else "disabled"}")
@ -233,6 +233,7 @@ class ConferenceWaitingRoomViewModel : ViewModel() {
askPermissionEvent.value = Event(Manifest.permission.CAMERA)
return
}
callParams.isVideoEnabled = isVideoAvailable.value == true
callParams.videoDirection = if (callParams.videoDirection == MediaDirection.SendRecv) MediaDirection.RecvOnly else MediaDirection.SendRecv
Log.i("[Conference Waiting Room] Video will be ${if (callParams.isVideoEnabled) "enabled" else "disabled"}")
updateVideoState()
@ -240,6 +241,7 @@ class ConferenceWaitingRoomViewModel : ViewModel() {
fun enableVideo() {
Log.i("[Conference Waiting Room] Video will be enabled")
callParams.isVideoEnabled = isVideoAvailable.value == true
callParams.videoDirection = MediaDirection.SendRecv
updateVideoState()
}
@ -288,13 +290,19 @@ class ConferenceWaitingRoomViewModel : ViewModel() {
}
private fun updateLayout() {
val layout = coreContext.core.defaultConferenceLayout
val core = coreContext.core
val layout = core.defaultConferenceLayout
isActiveSpeakerLayoutSelected.value = layout == ConferenceLayout.ActiveSpeaker
isAudioOnlyLayoutSelected.value = layout == ConferenceLayout.Legacy // TODO: FIXME: Replace Legacy by AudioOnly
isVideoAvailable.value = isAudioOnlyLayoutSelected.value == false && (core.isVideoCaptureEnabled || core.isVideoPreviewEnabled)
callParams.isVideoEnabled = isVideoAvailable.value == true && isAudioOnlyLayoutSelected.value == false
if (isAudioOnlyLayoutSelected.value == true) callParams.videoDirection = MediaDirection.RecvOnly
updateVideoState()
}
private fun updateVideoState() {
isVideoEnabled.value = callParams.videoDirection == MediaDirection.SendRecv
isVideoEnabled.value = callParams.isVideoEnabled && callParams.videoDirection == MediaDirection.SendRecv
isSwitchCameraAvailable.value = callParams.isVideoEnabled && coreContext.showSwitchCameraButton()
coreContext.core.isVideoPreviewEnabled = callParams.isVideoEnabled
}

View file

@ -26,8 +26,6 @@ import androidx.navigation.navGraphViewModels
import org.linphone.R
import org.linphone.activities.GenericFragment
import org.linphone.activities.voip.viewmodels.ConferenceViewModel
import org.linphone.core.ConferenceLayout
import org.linphone.core.tools.Log
import org.linphone.databinding.VoipConferenceLayoutFragmentBinding
class ConferenceLayoutFragment : GenericFragment<VoipConferenceLayoutFragmentBinding>() {
@ -46,48 +44,6 @@ class ConferenceLayoutFragment : GenericFragment<VoipConferenceLayoutFragmentBin
goBack()
}
conferenceViewModel.conferenceMosaicDisplayMode.observe(
viewLifecycleOwner
) {
if (it) {
Log.i("[Conference] Trying to change conference layout to Grid")
val conference = conferenceViewModel.conference.value
if (conference != null) {
conference.layout = ConferenceLayout.Grid
} else {
Log.e("[Conference] Conference is null in ConferenceViewModel")
}
}
}
conferenceViewModel.conferenceActiveSpeakerDisplayMode.observe(
viewLifecycleOwner
) {
if (it) {
Log.i("[Conference] Trying to change conference layout to ActiveSpeaker")
val conference = conferenceViewModel.conference.value
if (conference != null) {
conference.layout = ConferenceLayout.ActiveSpeaker
} else {
Log.e("[Conference] Conference is null in ConferenceViewModel")
}
}
}
conferenceViewModel.conferenceAudioOnlyDisplayMode.observe(
viewLifecycleOwner
) {
if (it) {
Log.i("[Conference] Trying to change conference layout to AudioOnly")
val conference = conferenceViewModel.conference.value
if (conference != null) {
conference.layout = ConferenceLayout.Legacy // TODO: FIXME: Use AudioOnly
} else {
Log.e("[Conference] Conference is null in ConferenceViewModel")
}
}
}
conferenceViewModel.conferenceParticipantDevices.observe(
viewLifecycleOwner
) {

View file

@ -290,11 +290,26 @@ class ConferenceViewModel : ViewModel() {
}
}
fun changeLayout(layout: ConferenceLayout) {
Log.i("[Conference] Trying to change conference layout to $layout")
val conference = conference.value
if (conference != null) {
conference.layout = layout
updateConferenceLayout(conference)
} else {
Log.e("[Conference] Conference is null in ConferenceViewModel")
}
}
private fun updateConferenceLayout(conference: Conference) {
val layout = conference.layout
conferenceMosaicDisplayMode.value = layout == ConferenceLayout.Grid
conferenceActiveSpeakerDisplayMode.value = layout == ConferenceLayout.ActiveSpeaker
conferenceAudioOnlyDisplayMode.value = layout == ConferenceLayout.Legacy // TODO: FIXME: Use AudioOnly layout
val list = sortDevicesDataList(conferenceParticipantDevices.value.orEmpty())
conferenceParticipantDevices.value = list
Log.i("[Conference] Conference current layout is: $layout")
}
@ -372,11 +387,13 @@ class ConferenceViewModel : ViewModel() {
val deviceData = ConferenceParticipantDeviceData(device, false)
devices.add(deviceData)
val sortedDevices = sortDevicesDataList(devices)
if (speakingParticipant.value == null) {
speakingParticipant.value = deviceData
}
conferenceParticipantDevices.value = devices
conferenceParticipantDevices.value = sortedDevices
}
private fun removeParticipantDevice(device: ParticipantDevice) {
@ -395,4 +412,28 @@ class ConferenceViewModel : ViewModel() {
conferenceParticipantDevices.value = devices
}
private fun sortDevicesDataList(devices: List<ConferenceParticipantDeviceData>): ArrayList<ConferenceParticipantDeviceData> {
val sortedList = arrayListOf<ConferenceParticipantDeviceData>()
sortedList.addAll(devices)
val meDeviceData = sortedList.find {
it.isMe
}
if (meDeviceData != null) {
val index = sortedList.indexOf(meDeviceData)
val expectedIndex = if (conferenceActiveSpeakerDisplayMode.value == true) {
0
} else {
sortedList.size - 1
}
if (index != expectedIndex) {
Log.i("[Conference] Me device data is at index $index, moving it to index $expectedIndex")
sortedList.removeAt(index)
sortedList.add(expectedIndex, meDeviceData)
}
}
return sortedList
}
}

View file

@ -4,6 +4,7 @@
<data>
<import type="android.view.View" />
<import type="org.linphone.core.ConferenceLayout" />
<variable
name="cancelClickListener"
type="android.view.View.OnClickListener"/>
@ -59,6 +60,7 @@
android:orientation="vertical">
<RadioButton
android:onClickListener="@{() -> conferenceViewModel.changeLayout(ConferenceLayout.Grid)}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
@ -67,7 +69,7 @@
android:layout_marginBottom="10dp"
android:text="@string/conference_display_mode_mosaic"
android:enabled="@{conferenceViewModel.conferenceParticipantDevices.size() > conferenceViewModel.maxParticipantsForMosaicLayout ? false : true}"
android:checked="@={conferenceViewModel.conferenceMosaicDisplayMode}"
android:checked="@{conferenceViewModel.conferenceMosaicDisplayMode}"
android:drawableEnd="@drawable/icon_conference_layout_grid"
android:drawableTint="?attr/voipDrawableColor"/>
@ -77,6 +79,7 @@
android:background="?attr/dividerColor" />
<RadioButton
android:onClickListener="@{() -> conferenceViewModel.changeLayout(ConferenceLayout.ActiveSpeaker)}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
@ -85,7 +88,7 @@
android:layout_marginBottom="10dp"
android:text="@string/conference_display_mode_active_speaker"
android:enabled="@{conferenceViewModel.conferenceParticipantDevices.size() > conferenceViewModel.maxParticipantsForMosaicLayout ? false : true}"
android:checked="@={conferenceViewModel.conferenceActiveSpeakerDisplayMode}"
android:checked="@{conferenceViewModel.conferenceActiveSpeakerDisplayMode}"
android:drawableEnd="@drawable/icon_conference_layout_active_speaker"
android:drawableTint="?attr/voipDrawableColor"/>
@ -94,7 +97,9 @@
android:layout_height="1dp"
android:background="?attr/dividerColor" />
<!-- TODO: FIXME: Use AudioOnly layout -->
<RadioButton
android:onClickListener="@{() -> conferenceViewModel.changeLayout(ConferenceLayout.Legacy)}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
@ -102,7 +107,7 @@
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:text="@string/conference_display_mode_audio_only"
android:checked="@={conferenceViewModel.conferenceAudioOnlyDisplayMode}"
android:checked="@{conferenceViewModel.conferenceAudioOnlyDisplayMode}"
android:drawableEnd="@drawable/icon_conference_layout_audio_only"
android:drawableTint="?attr/voipDrawableColor"/>