From 93021ec567cdb710e0ae18e176d03586e255e4dc Mon Sep 17 00:00:00 2001 From: Julien Wadel Date: Mon, 27 Jun 2022 12:24:09 +0200 Subject: [PATCH] ActiveSpeaker details (display name) is now based on the last of speaker (and not based on speaking events). Fix Qml errors. Update SDK. --- linphone-app/src/components/camera/Camera.cpp | 18 +++---- .../ParticipantDeviceListModel.cpp | 11 ++-- .../participant/ParticipantDeviceListener.cpp | 2 + .../ParticipantDeviceProxyModel.cpp | 21 +++++++- .../ParticipantDeviceProxyModel.hpp | 3 ++ .../Linphone/Menus/VideoConferenceMenu.qml | 4 +- linphone-app/ui/views/App/Calls/Incall.js | 7 ++- linphone-app/ui/views/App/Calls/Incall.qml | 2 +- .../ui/views/App/Calls/VideoConference.qml | 2 +- .../Calls/VideoConferenceActiveSpeaker.qml | 6 ++- .../App/Calls/VideoConferenceFullscreen.qml | 52 ++++++++++--------- linphone-sdk | 2 +- 12 files changed, 78 insertions(+), 52 deletions(-) diff --git a/linphone-app/src/components/camera/Camera.cpp b/linphone-app/src/components/camera/Camera.cpp index 4226d8f75..62237398b 100644 --- a/linphone-app/src/components/camera/Camera.cpp +++ b/linphone-app/src/components/camera/Camera.cpp @@ -61,7 +61,7 @@ Camera::Camera (QQuickItem *parent) : QQuickFramebufferObject(parent) { } Camera::~Camera(){ - qDebug() << "Camera destructor" << this; + qDebug() << "[Camera] Camera destructor" << this; if(mIsPreview) deactivatePreview(); setWindowIdLocation(None); @@ -97,7 +97,7 @@ void Camera::resetWindowId() const{ if(oldRenderer) CoreManager::getInstance()->getCore()->setNativeVideoWindowId(NULL); } - qDebug() << "Removed " << oldRenderer << " at " << mWindowIdLocation << " for " << this; + qDebug() << "[Camera] Removed " << oldRenderer << " at " << mWindowIdLocation << " for " << this; mIsWindowIdSet = false; } } @@ -141,14 +141,14 @@ QQuickFramebufferObject::Renderer *Camera::createRenderer () const { QQuickFramebufferObject::Renderer * renderer = NULL; if(mWindowIdLocation == CorePreview){ - qDebug() << "Setting Camera to Preview"; + qDebug() << "[Camera] Setting Camera to Preview"; renderer=(QQuickFramebufferObject::Renderer *)CoreManager::getInstance()->getCore()->createNativePreviewWindowId(); if(renderer) CoreManager::getInstance()->getCore()->setNativePreviewWindowId(renderer); }else if(mWindowIdLocation == Call){ auto call = mCallModel->getCall(); if(call){ - qDebug() << "Setting Camera to CallModel"; + qDebug() << "[Camera] Setting Camera to CallModel"; renderer = (QQuickFramebufferObject::Renderer *) call->createNativeVideoWindowId(); if(renderer) call->setNativeVideoWindowId(renderer); @@ -156,27 +156,27 @@ QQuickFramebufferObject::Renderer *Camera::createRenderer () const { }else if( mWindowIdLocation == Device) { auto participantDevice = mParticipantDeviceModel->getDevice(); if(participantDevice){ - qDebug() << "Setting Camera to Participant Device"; - qDebug() << "Trying to create new window ID for " << participantDevice->getName().c_str() << ", addr=" << participantDevice->getAddress()->asString().c_str(); + qDebug() << "[Camera] Setting Camera to Participant Device"; + qDebug() << "[Camera] Trying to create new window ID for " << participantDevice->getName().c_str() << ", addr=" << participantDevice->getAddress()->asString().c_str(); renderer = (QQuickFramebufferObject::Renderer *) participantDevice->createNativeVideoWindowId(); if(renderer) participantDevice->setNativeVideoWindowId(renderer); } }else if( mWindowIdLocation == Core){ - qDebug() << "Setting Camera to Default Window"; + qDebug() << "[Camera] Setting Camera to Default Window"; renderer = (QQuickFramebufferObject::Renderer *) CoreManager::getInstance()->getCore()->createNativeVideoWindowId(); if(renderer) CoreManager::getInstance()->getCore()->setNativeVideoWindowId(renderer); } if( !renderer){ QTimer::singleShot(1, this, &Camera::isNotReady);// Workaround for const createRenderer - qWarning() << "Camera stream couldn't start for Rendering. Retrying in 1s"; + qWarning() << "[Camera] Stream couldn't start for Rendering. Retrying in 1s"; renderer = new CameraDummy(); QTimer::singleShot(1000, this, &Camera::requestNewRenderer); }else{ mIsWindowIdSet = true; - qDebug() << "Added " << renderer << " at " << mWindowIdLocation << " for " << this; + qDebug() << "[Camera] Added " << renderer << " at " << mWindowIdLocation << " for " << this; QTimer::singleShot(1, this, &Camera::isReady);// Workaround for const createRenderer } return renderer; diff --git a/linphone-app/src/components/participant/ParticipantDeviceListModel.cpp b/linphone-app/src/components/participant/ParticipantDeviceListModel.cpp index 156a44815..e311b4f0d 100644 --- a/linphone-app/src/components/participant/ParticipantDeviceListModel.cpp +++ b/linphone-app/src/components/participant/ParticipantDeviceListModel.cpp @@ -245,13 +245,12 @@ void ParticipantDeviceListModel::onParticipantDeviceMediaAvailabilityChanged(con } void ParticipantDeviceListModel::onParticipantDeviceIsSpeakingChanged(const std::shared_ptr & participantDevice, bool isSpeaking){ - if( isSpeaking){ - auto device = get(participantDevice); - if( device) - emit participantSpeaking(device.get()); - } + auto device = get(participantDevice); + if( device) + emit participantSpeaking(device.get()); } void ParticipantDeviceListModel::onParticipantDeviceSpeaking(){ - emit participantSpeaking(qobject_cast(sender())); + auto deviceModel = qobject_cast(sender()); + emit participantSpeaking(deviceModel); } diff --git a/linphone-app/src/components/participant/ParticipantDeviceListener.cpp b/linphone-app/src/components/participant/ParticipantDeviceListener.cpp index de188396a..4a04b54b3 100644 --- a/linphone-app/src/components/participant/ParticipantDeviceListener.cpp +++ b/linphone-app/src/components/participant/ParticipantDeviceListener.cpp @@ -47,9 +47,11 @@ void ParticipantDeviceListener::onConferenceLeft(const std::shared_ptr & participantDevice, linphone::MediaDirection direction, linphone::StreamType streamType) { + qDebug() << "onStreamCapabilityChanged: " << participantDevice->getAddress()->asString().c_str() << " " << (int)direction << " / " << (int)streamType; emit streamCapabilityChanged(participantDevice, direction, streamType); } void ParticipantDeviceListener::onStreamAvailabilityChanged(const std::shared_ptr & participantDevice, bool available, linphone::StreamType streamType) { + qDebug() << "onStreamAvailabilityChanged: " << participantDevice->getAddress()->asString().c_str() << " " << available<< " / " << (int)streamType; emit streamAvailabilityChanged(participantDevice, available, streamType); } \ No newline at end of file diff --git a/linphone-app/src/components/participant/ParticipantDeviceProxyModel.cpp b/linphone-app/src/components/participant/ParticipantDeviceProxyModel.cpp index f0be7de19..62c7c5220 100644 --- a/linphone-app/src/components/participant/ParticipantDeviceProxyModel.cpp +++ b/linphone-app/src/components/participant/ParticipantDeviceProxyModel.cpp @@ -59,6 +59,13 @@ ParticipantDeviceModel *ParticipantDeviceProxyModel::getAt(int row){ return sourceModel()->data(sourceIndex).value(); } +ParticipantDeviceModel* ParticipantDeviceProxyModel::getLastActiveSpeaking(){ + if( mActiveSpeakers.size() == 0) + return nullptr; + else + return mActiveSpeakers.first(); +} + CallModel * ParticipantDeviceProxyModel::getCallModel() const{ return mCallModel; } @@ -72,7 +79,7 @@ void ParticipantDeviceProxyModel::setCallModel(CallModel * callModel){ mCallModel = callModel; auto sourceModel = new ParticipantDeviceListModel(mCallModel); connect(sourceModel, &ParticipantDeviceListModel::countChanged, this, &ParticipantDeviceProxyModel::onCountChanged); - connect(sourceModel, &ParticipantDeviceListModel::participantSpeaking, this, &ParticipantDeviceProxyModel::participantSpeaking); + connect(sourceModel, &ParticipantDeviceListModel::participantSpeaking, this, &ParticipantDeviceProxyModel::onParticipantSpeaking); setSourceModel(sourceModel); emit countChanged(); } @@ -81,7 +88,7 @@ void ParticipantDeviceProxyModel::setParticipant(ParticipantModel * participant) setFilterType(0); auto sourceModel = participant->getParticipantDevices().get(); connect(sourceModel, &ParticipantDeviceListModel::countChanged, this, &ParticipantDeviceProxyModel::countChanged); - connect(sourceModel, &ParticipantDeviceListModel::participantSpeaking, this, &ParticipantDeviceProxyModel::participantSpeaking); + connect(sourceModel, &ParticipantDeviceListModel::participantSpeaking, this, &ParticipantDeviceProxyModel::onParticipantSpeaking); setSourceModel(sourceModel); emit countChanged(); } @@ -95,4 +102,14 @@ void ParticipantDeviceProxyModel::setShowMe(const bool& show){ } void ParticipantDeviceProxyModel::onCountChanged(){ +} + +void ParticipantDeviceProxyModel::onParticipantSpeaking(ParticipantDeviceModel * speakingDevice){ + bool changed = (mActiveSpeakers.removeAll(speakingDevice) > 0); + if( speakingDevice->getIsSpeaking()) { + mActiveSpeakers.push_front(speakingDevice); + changed = true; + } + if(changed) + emit participantSpeaking(speakingDevice); } \ No newline at end of file diff --git a/linphone-app/src/components/participant/ParticipantDeviceProxyModel.hpp b/linphone-app/src/components/participant/ParticipantDeviceProxyModel.hpp index b1ddc389c..59e8b3373 100644 --- a/linphone-app/src/components/participant/ParticipantDeviceProxyModel.hpp +++ b/linphone-app/src/components/participant/ParticipantDeviceProxyModel.hpp @@ -45,6 +45,7 @@ public: ParticipantDeviceProxyModel (QObject *parent = nullptr); Q_INVOKABLE ParticipantDeviceModel* getAt(int row); + Q_INVOKABLE ParticipantDeviceModel* getLastActiveSpeaking(); CallModel * getCallModel() const; bool isShowMe() const; @@ -55,6 +56,7 @@ public: public slots: void onCountChanged(); + void onParticipantSpeaking(ParticipantDeviceModel * speakingDevice); signals: void callModelChanged(); @@ -68,6 +70,7 @@ protected: QSharedPointer mDevices; CallModel * mCallModel; bool mShowMe = true; + QList mActiveSpeakers;// First item is last speaker }; #endif diff --git a/linphone-app/ui/modules/Linphone/Menus/VideoConferenceMenu.qml b/linphone-app/ui/modules/Linphone/Menus/VideoConferenceMenu.qml index 3cb2492b5..db1e9f77c 100644 --- a/linphone-app/ui/modules/Linphone/Menus/VideoConferenceMenu.qml +++ b/linphone-app/ui/modules/Linphone/Menus/VideoConferenceMenu.qml @@ -20,7 +20,7 @@ Rectangle{ id: mainItem property CallModel callModel property ConferenceModel conferenceModel: callModel.conferenceModel - property ParticipantModel me: conferenceModel.localParticipant + property ParticipantModel me: conferenceModel ? conferenceModel.localParticipant : null property bool isMeAdmin: me && me.adminStatus property bool isParticipantsMenu: false signal close() @@ -109,7 +109,7 @@ Rectangle{ , nextPage:mediaMenu}, {titleIndex: 1 - , icon: (mainItem.callModel.videoEnabled ? + , icon: (mainItem.callModel && mainItem.callModel.videoEnabled ? (mainItem.callModel.conferenceVideoLayout == LinphoneEnums.ConferenceLayoutGrid ? VideoConferenceMenuStyle.settingsIcons.gridIcon : VideoConferenceMenuStyle.settingsIcons.activeSpeakerIcon) : VideoConferenceMenuStyle.settingsIcons.audioOnlyIcon) , nextPage:layoutMenu}, diff --git a/linphone-app/ui/views/App/Calls/Incall.js b/linphone-app/ui/views/App/Calls/Incall.js index ddf482b21..bc9f1cebf 100644 --- a/linphone-app/ui/views/App/Calls/Incall.js +++ b/linphone-app/ui/views/App/Calls/Incall.js @@ -52,12 +52,11 @@ function handleCameraFirstFrameReceived (width, height) { window.setHeight(window.height + diff) } -function handleStatusChanged (status) { +function handleStatusChanged (status, isFullscreen) { if (status === Linphone.CallModel.CallStatusEnded) { - var fullscreen = incall._fullscreen - if (fullscreen) { + if (isFullscreen) { // Timeout => Avoid dead lock on mac. - Utils.setTimeout(window, 0, fullscreen.exit) + Utils.setTimeout(window, 0, isFullscreen.exit) } telKeypad.visible = false diff --git a/linphone-app/ui/views/App/Calls/Incall.qml b/linphone-app/ui/views/App/Calls/Incall.qml index 69b250529..0c38b5c8f 100644 --- a/linphone-app/ui/views/App/Calls/Incall.qml +++ b/linphone-app/ui/views/App/Calls/Incall.qml @@ -46,7 +46,7 @@ Rectangle { target: call onCameraFirstFrameReceived: Logic.handleCameraFirstFrameReceived(width, height) - onStatusChanged: Logic.handleStatusChanged (status) + onStatusChanged: Logic.handleStatusChanged (status, incall._fullscreen) onVideoRequested: Logic.handleVideoRequested(call) } diff --git a/linphone-app/ui/views/App/Calls/VideoConference.qml b/linphone-app/ui/views/App/Calls/VideoConference.qml index a94cc0014..54cea6eab 100644 --- a/linphone-app/ui/views/App/Calls/VideoConference.qml +++ b/linphone-app/ui/views/App/Calls/VideoConference.qml @@ -41,7 +41,7 @@ Rectangle { target: callModel onCameraFirstFrameReceived: Logic.handleCameraFirstFrameReceived(width, height) - onStatusChanged: Logic.handleStatusChanged (status) + onStatusChanged: Logic.handleStatusChanged (status, conference._fullscreen) onVideoRequested: Logic.handleVideoRequested(callModel) } diff --git a/linphone-app/ui/views/App/Calls/VideoConferenceActiveSpeaker.qml b/linphone-app/ui/views/App/Calls/VideoConferenceActiveSpeaker.qml index 03ee11abc..e90f5a69b 100644 --- a/linphone-app/ui/views/App/Calls/VideoConferenceActiveSpeaker.qml +++ b/linphone-app/ui/views/App/Calls/VideoConferenceActiveSpeaker.qml @@ -30,7 +30,11 @@ Item { property ParticipantDeviceProxyModel participantDevices : ParticipantDeviceProxyModel { id: allDevices showMe: true - onParticipantSpeaking: cameraView.currentDevice = speakingDevice + onParticipantSpeaking: { + var device = getLastActiveSpeaking() + if(device) // Get + cameraView.currentDevice = device + } property bool cameraEnabled: callModel && callModel.cameraEnabled onCameraEnabledChanged: showMe = cameraEnabled // Do it on changed to ignore hard bindings (that can be override) } diff --git a/linphone-app/ui/views/App/Calls/VideoConferenceFullscreen.qml b/linphone-app/ui/views/App/Calls/VideoConferenceFullscreen.qml index be8484157..a956fa492 100644 --- a/linphone-app/ui/views/App/Calls/VideoConferenceFullscreen.qml +++ b/linphone-app/ui/views/App/Calls/VideoConferenceFullscreen.qml @@ -81,14 +81,14 @@ Window { target: callModel onCameraFirstFrameReceived: Logic.handleCameraFirstFrameReceived(width, height) - onStatusChanged: Logic.handleStatusChanged (status) + onStatusChanged: Logic.handleStatusChanged (status, conference._fullscreen) onVideoRequested: Logic.handleVideoRequested(callModel) } // --------------------------------------------------------------------------- Rectangle{ anchors.fill: parent - visible: callModel.pausedByUser + visible: callModel && callModel.pausedByUser color: VideoConferenceStyle.pauseArea.backgroundColor z: 1 ColumnLayout{ @@ -103,7 +103,7 @@ Window { isCustom: true colorSet: VideoConferenceStyle.pauseArea.play backgroundRadius: width/2 - onClicked: callModel.pausedByUser = !callModel.pausedByUser + onClicked: if(callModel) callModel.pausedByUser = !callModel.pausedByUser } Text{ Layout.alignment: Qt.AlignCenter @@ -183,9 +183,9 @@ Window { backgroundRadius: width/2 colorSet: VideoConferenceStyle.buttons.record property CallModel callModel: conference.callModel - onCallModelChanged: if(!callModel) callModel.stopRecording() + onCallModelChanged: if(callModel) callModel.stopRecording() visible: SettingsModel.callRecorderEnabled && callModel - toggled: callModel.recording + toggled: callModel && callModel.recording onClicked: { return !toggled @@ -201,8 +201,8 @@ Window { isCustom: true backgroundRadius: width/2 colorSet: VideoConferenceStyle.buttons.screenshot - visible: conference.callModel.snapshotEnabled - onClicked: conference.callModel.takeSnapshot() + visible: conference.callModel && conference.callModel.snapshotEnabled + onClicked: conference.callModel && conference.callModel.takeSnapshot() //: 'Take Snapshot' : Tooltip for takking snapshot. tooltipText: qsTr('videoConferenceSnapshotTooltip') } @@ -260,7 +260,7 @@ Window { id: conferenceLayout Layout.fillHeight: true Layout.fillWidth: true - sourceComponent: conference.callModel.conferenceVideoLayout == LinphoneEnums.ConferenceLayoutGrid || !conference.callModel.videoEnabled? gridComponent : activeSpeakerComponent + sourceComponent: conference.callModel ? (conference.callModel.conferenceVideoLayout == LinphoneEnums.ConferenceLayoutGrid || !conference.callModel.videoEnabled? gridComponent : activeSpeakerComponent) : null onSourceComponentChanged: console.log(conference.callModel.conferenceVideoLayout) active: conference.callModel ColumnLayout { @@ -328,7 +328,7 @@ Window { Row { spacing: 2 visible: SettingsModel.muteMicrophoneEnabled - property bool microMuted: callModel.microMuted + property bool microMuted: callModel && callModel.microMuted VuMeter { enabled: !parent.microMuted @@ -337,7 +337,7 @@ Window { repeat: true running: parent.enabled - onTriggered: parent.value = callModel.microVu + onTriggered: if(callModel) parent.value = callModel.microVu } } ActionSwitch { @@ -345,12 +345,12 @@ Window { isCustom: true backgroundRadius: 90 colorSet: parent.microMuted ? VideoConferenceStyle.buttons.microOff : VideoConferenceStyle.buttons.microOn - onClicked: callModel.microMuted = !parent.microMuted + onClicked: if(callModel) callModel.microMuted = !parent.microMuted } } Row { spacing: 2 - property bool speakerMuted: callModel.speakerMuted + property bool speakerMuted: callModel && callModel.speakerMuted VuMeter { enabled: !parent.speakerMuted Timer { @@ -365,7 +365,7 @@ Window { isCustom: true backgroundRadius: 90 colorSet: parent.speakerMuted ? VideoConferenceStyle.buttons.speakerOff : VideoConferenceStyle.buttons.speakerOn - onClicked: callModel.speakerMuted = !parent.speakerMuted + onClicked: if(callModel) callModel.speakerMuted = !parent.speakerMuted } } ActionSwitch { @@ -373,8 +373,8 @@ Window { isCustom: true backgroundRadius: 90 colorSet: callModel && callModel.cameraEnabled ? VideoConferenceStyle.buttons.cameraOn : VideoConferenceStyle.buttons.cameraOff - updating: callModel.videoEnabled && callModel.updating - enabled: callModel.videoEnabled + updating: callModel && callModel.videoEnabled && callModel.updating + enabled: callModel && callModel.videoEnabled onClicked: if(callModel) callModel.cameraEnabled = !callModel.cameraEnabled } } @@ -384,16 +384,16 @@ Window { isCustom: true backgroundRadius: width/2 visible: SettingsModel.callPauseEnabled - updating: callModel.updating - colorSet: callModel.pausedByUser ? VideoConferenceStyle.buttons.play : VideoConferenceStyle.buttons.pause - onClicked: callModel.pausedByUser = !callModel.pausedByUser + updating: callModel && callModel.updating + colorSet: callModel && callModel.pausedByUser ? VideoConferenceStyle.buttons.play : VideoConferenceStyle.buttons.pause + onClicked: if(callModel) callModel.pausedByUser = !callModel.pausedByUser } ActionButton{ isCustom: true backgroundRadius: width/2 colorSet: VideoConferenceStyle.buttons.hangup - onClicked: callModel.terminate() + onClicked: if(callModel) callModel.terminate() } } } @@ -433,12 +433,14 @@ Window { running: true triggeredOnStart: true onTriggered: { - // Note: `quality` is in the [0, 5] interval and -1. - var quality = callModel.quality - if(quality >= 0) - callQuality.percentageDisplayed = quality * 100 / 5 - else - callQuality.percentageDisplayed = 0 + if(callModel) { + // Note: `quality` is in the [0, 5] interval and -1. + var quality = callModel.quality + if(quality >= 0) + callQuality.percentageDisplayed = quality * 100 / 5 + else + callQuality.percentageDisplayed = 0 + } } } } diff --git a/linphone-sdk b/linphone-sdk index baeed5ae0..1e4bdbdcf 160000 --- a/linphone-sdk +++ b/linphone-sdk @@ -1 +1 @@ -Subproject commit baeed5ae055e519284f7314d3a9bace134c3ecb5 +Subproject commit 1e4bdbdcf843b5c0b4cea23c0b27ee031bdaf08f