diff --git a/linphone-app/src/components/call/CallModel.cpp b/linphone-app/src/components/call/CallModel.cpp index 101707b83..d1d72b37a 100644 --- a/linphone-app/src/components/call/CallModel.cpp +++ b/linphone-app/src/components/call/CallModel.cpp @@ -69,7 +69,10 @@ CallModel::CallModel (shared_ptr call){ mCallListener = std::make_shared(); connectTo(mCallListener.get()); mCall->addListener(mCallListener); - mConferenceVideoLayout = LinphoneEnums::fromLinphone(mCall->getParams()->getConferenceVideoLayout()); + auto callParams = mCall->getParams(); + mConferenceVideoLayout = LinphoneEnums::fromLinphone(callParams->getConferenceVideoLayout()); + if(mConferenceVideoLayout == LinphoneEnums::ConferenceLayoutGrid && !callParams->videoEnabled()) + mConferenceVideoLayout = LinphoneEnums::ConferenceLayoutAudioOnly; if(mCall->getConference()){ if( mConferenceVideoLayout == LinphoneEnums::ConferenceLayoutGrid) settings->setCameraMode(settings->getGridCameraMode()); @@ -479,7 +482,7 @@ void CallModel::handleCallStateChanged (const shared_ptr &call, mWasConnected = true; } mPausedByRemote = false; - setConferenceVideoLayout(LinphoneEnums::fromLinphone(call->getParams()->getConferenceVideoLayout())); + updateConferenceVideoLayout(); setCallId(QString::fromStdString(mCall->getCallLog()->getCallId())); break; } @@ -994,7 +997,8 @@ std::shared_ptr CallModel::getRemoteAddress()const{ } LinphoneEnums::ConferenceLayout CallModel::getConferenceVideoLayout() const{ - return mCall ? LinphoneEnums::fromLinphone(mCall->getParams()->getConferenceVideoLayout()) : LinphoneEnums::ConferenceLayoutGrid; + return mConferenceVideoLayout; +// return mCall ? LinphoneEnums::fromLinphone(mCall->getParams()->getConferenceVideoLayout()) : LinphoneEnums::ConferenceLayoutGrid; } void CallModel::changeConferenceVideoLayout(LinphoneEnums::ConferenceLayout layout){ @@ -1005,21 +1009,26 @@ void CallModel::changeConferenceVideoLayout(LinphoneEnums::ConferenceLayout layo coreManager->getSettingsModel()->setCameraMode(coreManager->getSettingsModel()->getActiveSpeakerCameraMode()); shared_ptr params = coreManager->getCore()->createCallParams(mCall); params->setConferenceVideoLayout(LinphoneEnums::toLinphone(layout)); - params->enableVideo(true); + params->enableVideo(layout != LinphoneEnums::ConferenceLayoutAudioOnly); mCall->update(params); } -void CallModel::setConferenceVideoLayout(LinphoneEnums::ConferenceLayout layout){ +void CallModel::updateConferenceVideoLayout(){ + auto callParams = mCall->getParams(); auto settings = CoreManager::getInstance()->getSettingsModel(); - if(mCall->getConference()){ - if( layout == LinphoneEnums::ConferenceLayoutGrid) + auto newLayout = LinphoneEnums::fromLinphone(callParams->getConferenceVideoLayout()); + if( !callParams->videoEnabled()) + newLayout = LinphoneEnums::ConferenceLayoutAudioOnly; + if( mConferenceVideoLayout != newLayout && !getPausedByUser()){// Only update if not in pause. + if(mCall->getConference()){ + if( callParams->getConferenceVideoLayout() == linphone::ConferenceLayout::Grid) settings->setCameraMode(settings->getGridCameraMode()); else settings->setCameraMode(settings->getActiveSpeakerCameraMode()); }else settings->setCameraMode(settings->getCallCameraMode()); - if( mConferenceVideoLayout != layout){ - mConferenceVideoLayout = layout; + qWarning() << "Changing layout from " << mConferenceVideoLayout << " into " << newLayout; + mConferenceVideoLayout = newLayout; emit conferenceVideoLayoutChanged(); emit snapshotEnabledChanged(); } diff --git a/linphone-app/src/components/call/CallModel.hpp b/linphone-app/src/components/call/CallModel.hpp index d44288749..6fd95514b 100644 --- a/linphone-app/src/components/call/CallModel.hpp +++ b/linphone-app/src/components/call/CallModel.hpp @@ -181,7 +181,7 @@ public: LinphoneEnums::ConferenceLayout getConferenceVideoLayout() const; void changeConferenceVideoLayout(LinphoneEnums::ConferenceLayout layout); // Make a call request - void setConferenceVideoLayout(LinphoneEnums::ConferenceLayout layout); // Called from call state changed ater the new layout has been set. + void updateConferenceVideoLayout(); // Called from call state changed ater the new layout has been set. static constexpr int DtmfSoundDelay = 200; diff --git a/linphone-app/src/utils/LinphoneEnums.cpp b/linphone-app/src/utils/LinphoneEnums.cpp index e2d547628..90026d573 100644 --- a/linphone-app/src/utils/LinphoneEnums.cpp +++ b/linphone-app/src/utils/LinphoneEnums.cpp @@ -71,7 +71,10 @@ LinphoneEnums::CallStatus LinphoneEnums::fromLinphone(const linphone::Call::Stat } linphone::ConferenceLayout LinphoneEnums::toLinphone(const LinphoneEnums::ConferenceLayout& layout){ - return static_cast(layout); + if( layout != LinphoneEnums::ConferenceLayoutAudioOnly) + return static_cast(layout); + else + return linphone::ConferenceLayout::Grid;// Audio Only mode } LinphoneEnums::ConferenceLayout LinphoneEnums::fromLinphone(const linphone::ConferenceLayout& layout){ diff --git a/linphone-app/src/utils/LinphoneEnums.hpp b/linphone-app/src/utils/LinphoneEnums.hpp index da2eb568f..7a71ddbf2 100644 --- a/linphone-app/src/utils/LinphoneEnums.hpp +++ b/linphone-app/src/utils/LinphoneEnums.hpp @@ -115,6 +115,7 @@ LinphoneEnums::CallStatus fromLinphone(const linphone::Call::Status& capability) enum ConferenceLayout { ConferenceLayoutGrid = int(linphone::ConferenceLayout::Grid), ConferenceLayoutActiveSpeaker = int(linphone::ConferenceLayout::ActiveSpeaker), + ConferenceLayoutAudioOnly = ConferenceLayoutGrid + ConferenceLayoutActiveSpeaker + 1, }; Q_ENUM_NS(ConferenceLayout) diff --git a/linphone-app/ui/modules/Linphone/Menus/IncallMenu.qml b/linphone-app/ui/modules/Linphone/Menus/IncallMenu.qml index 0c05f6bf0..5a4a550f7 100644 --- a/linphone-app/ui/modules/Linphone/Menus/IncallMenu.qml +++ b/linphone-app/ui/modules/Linphone/Menus/IncallMenu.qml @@ -113,9 +113,13 @@ Rectangle{ , visible: true}, {titleIndex: 1 - , icon: (mainItem.callModel && mainItem.callModel.localVideoEnabled ? - (mainItem.callModel.conferenceVideoLayout == LinphoneEnums.ConferenceLayoutGrid ? IncallMenuStyle.settingsIcons.gridIcon : IncallMenuStyle.settingsIcons.activeSpeakerIcon) - : IncallMenuStyle.settingsIcons.audioOnlyIcon) + , icon: (mainItem.callModel + ? mainItem.callModel.conferenceVideoLayout == LinphoneEnums.ConferenceLayoutAudioOnly + ? IncallMenuStyle.settingsIcons.audioOnlyIcon + : mainItem.callModel.conferenceVideoLayout == LinphoneEnums.ConferenceLayoutGrid + ? IncallMenuStyle.settingsIcons.gridIcon + : IncallMenuStyle.settingsIcons.activeSpeakerIcon + : IncallMenuStyle.settingsIcons.audioOnlyIcon) , nextPage:layoutMenu , visible: mainItem.callModel && mainItem.callModel.isConference}, @@ -215,7 +219,7 @@ Rectangle{ //: 'Active speaker mode' : Active speaker layout for video conference. , {text: qsTr('incallMenuActiveSpeakerLayout'), icon: IncallMenuStyle.modeIcons.activeSpeakerIcon, value:LinphoneEnums.ConferenceLayoutActiveSpeaker} //: 'Audio only mode' : Audio only layout for video conference. - , {text: qsTr('incallMenuAudioLayout'), icon: IncallMenuStyle.modeIcons.audioOnlyIcon, value:2} + , {text: qsTr('incallMenuAudioLayout'), icon: IncallMenuStyle.modeIcons.audioOnlyIcon, value:LinphoneEnums.ConferenceLayoutAudioOnly} ] delegate: Borders{ @@ -236,7 +240,7 @@ Rectangle{ text: modelData.text property bool isInternallyChecked: mainItem.callModel ? (mainItem.callModel.localVideoEnabled && modelData.value == mainItem.callModel.conferenceVideoLayout) - || (!mainItem.callModel.localVideoEnabled && modelData.value == 2) + || (!mainItem.callModel.localVideoEnabled && modelData.value == LinphoneEnums.ConferenceLayoutAudioOnly) : false // break bind. Radiobutton checked itself without taking care of custom binding. This workaound works as long as we don't really need the binding. onIsInternallyCheckedChanged: checked = isInternallyChecked @@ -255,7 +259,7 @@ Rectangle{ onClicked:{ // Do changes only if we choose a different layout. if(! ( mainItem.callModel ? (mainItem.callModel.localVideoEnabled && modelData.value == mainItem.callModel.conferenceVideoLayout) - || (!mainItem.callModel.localVideoEnabled && modelData.value == 2) + || (!mainItem.callModel.localVideoEnabled && modelData.value == LinphoneEnums.ConferenceLayoutAudioOnly) : false)){ mainItem.enabled = false mainItem.layoutChanging(modelData.value)// Let time to clear cameras diff --git a/linphone-app/ui/views/App/Calls/Incall.qml b/linphone-app/ui/views/App/Calls/Incall.qml index 7636ed30c..3842958e8 100644 --- a/linphone-app/ui/views/App/Calls/Incall.qml +++ b/linphone-app/ui/views/App/Calls/Incall.qml @@ -328,11 +328,11 @@ Rectangle { id: conferenceLayout anchors.fill: parent sourceComponent: mainItem.conferenceModel - ? mainItem.callModel.conferenceVideoLayout == LinphoneEnums.ConferenceLayoutGrid || !mainItem.callModel.videoEnabled - ? gridComponent - : activeSpeakerComponent + ? mainItem.callModel.conferenceVideoLayout == LinphoneEnums.ConferenceLayoutActiveSpeaker + ? activeSpeakerComponent + : gridComponent : activeSpeakerComponent - onSourceComponentChanged: console.log("conferenceLayout: "+mainItem.callModel.conferenceVideoLayout) + onSourceComponentChanged: console.log("conferenceLayout: "+mainItem.callModel.conferenceVideoLayout + " => " +sourceComponent) active: mainItem.callModel && !mainItem.isFullScreen } Rectangle{ diff --git a/linphone-app/ui/views/App/Calls/IncallActiveSpeaker.qml b/linphone-app/ui/views/App/Calls/IncallActiveSpeaker.qml index f5b29cc4b..29b100698 100644 --- a/linphone-app/ui/views/App/Calls/IncallActiveSpeaker.qml +++ b/linphone-app/ui/views/App/Calls/IncallActiveSpeaker.qml @@ -25,8 +25,9 @@ Item { property bool isRightReducedLayout: false property bool isLeftReducedLayout: false property bool cameraEnabled: true - property bool showMe : !(callModel && callModel.pausedByUser) && (callModel.isConference || callModel.localVideoEnabled) - property int participantCount: callModel.isConference ? allDevices.count + 1 : 2 // +me + property bool isConferenceReady: callModel.isConference && callModel.conferenceModel && callModel.conferenceModel.isReady + + property int participantCount: callModel.isConference ? allDevices.count + 1 : 2 // +me. allDevices==0 if !conference onParticipantCountChanged: {console.log("Conf count: " +participantCount);allDevices.updateCurrentDevice()} @@ -66,15 +67,19 @@ Item { anchors.leftMargin: isRightReducedLayout || isLeftReducedLayout? 30 : 140 anchors.rightMargin: isRightReducedLayout ? 10 : 140 callModel: mainItem.callModel - deactivateCamera: callModel.isConference - ? (callModel && (callModel.pausedByUser || callModel.status === CallModel.CallStatusPaused) ) - || (!callModel.cameraEnabled && mainItem.participantCount == 1) - || (currentDevice && !currentDevice.videoEnabled && mainItem.participantCount == 2) - : (callModel && (callModel.pausedByUser || callModel.status === CallModel.CallStatusPaused) ) - || currentDevice && !currentDevice.videoEnabled + deactivateCamera: isPreview && callModel.pausedByUser + ? true + : callModel.isConference + ? (callModel && (callModel.pausedByUser || callModel.status === CallModel.CallStatusPaused) ) + || (!callModel.cameraEnabled && mainItem.participantCount == 1) + || (currentDevice && !currentDevice.videoEnabled)// && mainItem.participantCount == 2) + || !mainItem.isConferenceReady + : (callModel && (callModel.pausedByUser || callModel.status === CallModel.CallStatusPaused || !callModel.videoEnabled) ) + || currentDevice && !currentDevice.videoEnabled + isVideoEnabled: !deactivateCamera onDeactivateCameraChanged: console.log("deactivateCamera? "+deactivateCamera) - isPreview: mainItem.showMe && mainItem.participantCount == 1 + isPreview: !preview.visible && mainItem.participantCount == 1 onIsPreviewChanged: { console.log("ispreview ? " +isPreview) if( isPreview){ @@ -86,10 +91,12 @@ Item { } isCameraFromDevice: isPreview onCurrentDeviceChanged: console.log("CurrentDevice: "+currentDevice) - isPaused: callModel.isConference - ? callModel && callModel.pausedByUser && mainItem.participantCount != 2 - || (currentDevice && currentDevice.isPaused) - : callModel && !callModel.pausedByUser && (callModel.status === CallModel.CallStatusPaused) + isPaused: isPreview && callModel.pausedByUser + ? false + : callModel.isConference + ? //callModel && callModel.pausedByUser && mainItem.participantCount != 2 || + (currentDevice && currentDevice.isPaused) + : callModel && !callModel.pausedByUser && (callModel.status === CallModel.CallStatusPaused) onIsPausedChanged: console.log("ispaused ? " +isPaused + " = " +callModel.pausedByUser + " / " + (currentDevice ? currentDevice.isPaused : 'noDevice') +" / " +callModel.isConference + " / " +callModel.status ) quickTransition: true @@ -98,6 +105,12 @@ Item { showCustomButton: false avatarStickerBackgroundColor: isPreview ? IncallStyle.container.avatar.stickerPreviewBackgroundColor : IncallStyle.container.avatar.stickerBackgroundColor avatarBackgroundColor: IncallStyle.container.avatar.backgroundColor + Component.onCompleted: console.log("Completed: "+isPaused + " = " +callModel.pausedByUser + " / " + (currentDevice ? currentDevice.isPaused : 'noDevice') + +" isPreview?" +isPreview + +" / Video?" +(currentDevice ? currentDevice.videoEnabled : "NoDevice") + "-"+(callModel ? callModel.videoEnabled : "NoCall") + +" / Camera?" +(currentDevice ? currentDevice.cameraEnabled : "NoDevice") + "-"+(callModel ? callModel.cameraEnabled : "NoCall") + +" / Deactivated?"+deactivateCamera + +" / " +callModel.isConference + " / " +callModel.status) } Item{// Need an item to not override Sticker internal states. States are needed for changing anchors. id: preview @@ -106,10 +119,17 @@ Item { anchors.rightMargin: 30 anchors.bottomMargin: 15 - height: miniViews.cellHeight + height: visible ? miniViews.cellHeight : 0 width: 16 * height / 9 - visible: mainItem.showMe && (!callModel.isConference || allDevices.count >= 1) + //property bool showMe : !(callModel && callModel.pausedByUser) && (callModel.isConference || callModel.localVideoEnabled) + + visible: mainItem.isConferenceReady && allDevices.count >= 1 + || (!callModel.isConference && mainItem.callModel.cameraEnabled)// use videoEnabled if we want to show the preview sticker + + onVisibleChanged: console.log("visible? "+visible + " / video?" +(callModel ? callModel.videoEnabled : "NoCall") + + " / camera?" +(callModel ? callModel.cameraEnabled : "NoCall") + ) Loader{ anchors.fill: parent @@ -117,9 +137,12 @@ Item { sourceComponent: Sticker{ id: previewSticker - deactivateCamera: !mainItem.callModel || !mainItem.showMe || !mainItem.callModel.cameraEnabled + deactivateCamera: !mainItem.callModel || callModel.pausedByUser || !mainItem.callModel.cameraEnabled + //|| (!callModel.isConference && !mainItem.callModel.videoEnabled) + //|| (callModel.isConference && !mainItem.callModel.cameraEnabled) + //|| ( (callModel.isConference && !mainItem.callModel.cameraEnabled) || (!callModel.isConference && !mainItem.callModel.localVideoEnabled) ) - onDeactivateCameraChanged: console.log(deactivateCamera + " = " +mainItem.callModel +" / " +mainItem.showMe +" / " +mainItem.callModel.localVideoEnabled + " / " +mainItem.callModel.cameraEnabled) + onDeactivateCameraChanged: console.log(deactivateCamera + " = " +mainItem.callModel +" / " +mainItem.callModel.localVideoEnabled + " / " +mainItem.callModel.cameraEnabled) currentDevice: allDevices.me isPreview: true callModel: mainItem.callModel @@ -139,10 +162,11 @@ Item { anchors.bottom: preview.top anchors.rightMargin: 30 anchors.topMargin: 15 -//--------------- - anchors.bottomMargin: 15 +//--------------- width: 16 * miniViews.cellHeight / 9 + visible: mainItem.isConferenceReady || !callModel.isConference + ScrollableListView{ id: miniViews property int cellHeight: 150 @@ -177,11 +201,13 @@ Item { id: miniView anchors.fill: parent anchors.margins: 3 - deactivateCamera: index <0 || !mainItem.cameraEnabled || (!modelData.videoEnabled) || (callModel && callModel.pausedByUser) + deactivateCamera: (!mainItem.isConferenceReady || !callModel.isConference) + && (index <0 || !mainItem.cameraEnabled || (!modelData.videoEnabled) || (callModel && callModel.pausedByUser) ) currentDevice: modelData.isPreview ? null : modelData callModel: modelData.isPreview ? null : mainItem.callModel isCameraFromDevice: mainItem.callModel.isConference isPaused: currentDevice && currentDevice.isPaused + onIsPausedChanged: console.log("paused:"+isPaused) showCloseButton: false showCustomButton: false showAvatarBorder: true diff --git a/linphone-app/ui/views/App/Calls/IncallFullscreen.qml b/linphone-app/ui/views/App/Calls/IncallFullscreen.qml index f9cb5b36e..60fcae72f 100644 --- a/linphone-app/ui/views/App/Calls/IncallFullscreen.qml +++ b/linphone-app/ui/views/App/Calls/IncallFullscreen.qml @@ -296,9 +296,11 @@ Window { Layout.fillHeight: true Layout.fillWidth: true - sourceComponent: conference.callModel - ? conference.conferenceModel - ? conference.callModel.conferenceVideoLayout == LinphoneEnums.ConferenceLayoutGrid || !conference.callModel.videoEnabled? gridComponent : activeSpeakerComponent + sourceComponent: conference.callModel + ? conference.conferenceModel + ? conference.callModel.conferenceVideoLayout == LinphoneEnums.ConferenceLayoutActiveSpeaker + ? activeSpeakerComponent + : gridComponent : activeSpeakerComponent : null active: conference.callModel diff --git a/linphone-app/ui/views/App/Calls/IncallGrid.qml b/linphone-app/ui/views/App/Calls/IncallGrid.qml index 10d2f20a9..1369bf7ec 100644 --- a/linphone-app/ui/views/App/Calls/IncallGrid.qml +++ b/linphone-app/ui/views/App/Calls/IncallGrid.qml @@ -59,7 +59,7 @@ Mosaic { currentDevice: gridModel.participantDevices.getAt(index) isCameraFromDevice: true - isPaused: avatarCell.currentDevice && avatarCell.currentDevice.isPaused + isPaused: !isPreview && avatarCell.currentDevice && avatarCell.currentDevice.isPaused showCloseButton: false showCustomButton: false avatarStickerBackgroundColor: isPreview? IncallStyle.container.avatar.stickerPreviewBackgroundColor : IncallStyle.container.avatar.stickerBackgroundColor