From e0737f4b70cb0e31bd7f8514847a26ccbedc8169 Mon Sep 17 00:00:00 2001 From: Ming Rui Zhang <mingrui.zhang@savoirfairelinux.com> Date: Tue, 31 Aug 2021 10:37:11 -0400 Subject: [PATCH] settings: refactor for SettingsView - stage two 1. Remove redundant functions in AvAdapter 2. Add CurrentDevice for video device treatment Audio device treatment should be improved in the next stage 3. Add QSortFilterProxyModel to all video list models and manage them together to avoid redundant function calls 4. Video device call action should be responsive to device change as well Gitlab: #508 Change-Id: I3df949a08bc19042b73f033139cd6ab06925c0b6 --- CMakeLists.txt | 12 +- src/accountadapter.cpp | 20 - src/accountadapter.h | 4 - src/avadapter.cpp | 163 ++----- src/avadapter.h | 34 +- src/commoncomponents/PhotoboothView.qml | 11 +- src/commoncomponents/SettingParaCombobox.qml | 33 +- src/lrcinstance.cpp | 12 + src/lrcinstance.h | 1 + src/mainview/MainView.qml | 1 - src/mainview/components/CallActionBar.qml | 37 +- src/mainview/components/OngoingCallPage.qml | 7 +- src/mainview/components/RecordBox.qml | 13 +- src/qmlregister.cpp | 12 +- src/qtutils.h | 23 + src/rendermanager.cpp | 4 - src/settingsview/SettingsView.qml | 26 +- .../AdvancedSIPSecuritySettings.qml | 4 +- src/settingsview/components/AudioSettings.qml | 8 +- src/settingsview/components/AvSettingPage.qml | 10 - .../components/SettingsComboBox.qml | 5 + src/settingsview/components/VideoSettings.qml | 210 ++++----- src/videodevices.cpp | 443 ++++++++++++++++++ src/videodevices.h | 205 ++++++++ src/videoformatfpsmodel.cpp | 226 --------- src/videoformatfpsmodel.h | 70 --- src/videoformatresolutionmodel.cpp | 171 ------- src/videoformatresolutionmodel.h | 55 --- src/videoinputdevicemodel.cpp | 106 ----- src/videoinputdevicemodel.h | 50 -- 30 files changed, 884 insertions(+), 1092 deletions(-) create mode 100644 src/videodevices.cpp create mode 100644 src/videodevices.h delete mode 100644 src/videoformatfpsmodel.cpp delete mode 100644 src/videoformatfpsmodel.h delete mode 100644 src/videoformatresolutionmodel.cpp delete mode 100644 src/videoformatresolutionmodel.h delete mode 100644 src/videoinputdevicemodel.cpp delete mode 100644 src/videoinputdevicemodel.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 84efca855..92fb96859 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,10 +67,7 @@ set(COMMON_SOURCES ${SRC_DIR}/mediacodeclistmodel.cpp ${SRC_DIR}/accountstomigratelistmodel.cpp ${SRC_DIR}/audiodevicemodel.cpp - ${SRC_DIR}/videoinputdevicemodel.cpp ${SRC_DIR}/pluginlistpreferencemodel.cpp - ${SRC_DIR}/videoformatfpsmodel.cpp - ${SRC_DIR}/videoformatresolutionmodel.cpp ${SRC_DIR}/audiomanagerlistmodel.cpp ${SRC_DIR}/qmlregister.cpp ${SRC_DIR}/utilsadapter.cpp @@ -88,7 +85,8 @@ set(COMMON_SOURCES ${SRC_DIR}/wizardviewstepmodel.cpp ${SRC_DIR}/avatarregistry.cpp ${SRC_DIR}/currentconversation.cpp - ${SRC_DIR}/currentaccount.cpp) + ${SRC_DIR}/currentaccount.cpp + ${SRC_DIR}/videodevices.cpp) set(COMMON_HEADERS ${SRC_DIR}/avatarimageprovider.h @@ -123,10 +121,7 @@ set(COMMON_HEADERS ${SRC_DIR}/mediacodeclistmodel.h ${SRC_DIR}/accountstomigratelistmodel.h ${SRC_DIR}/audiodevicemodel.h - ${SRC_DIR}/videoinputdevicemodel.h ${SRC_DIR}/pluginlistpreferencemodel.h - ${SRC_DIR}/videoformatfpsmodel.h - ${SRC_DIR}/videoformatresolutionmodel.h ${SRC_DIR}/audiomanagerlistmodel.h ${SRC_DIR}/qmlregister.h ${SRC_DIR}/abstractlistmodelbase.h @@ -147,7 +142,8 @@ set(COMMON_HEADERS ${SRC_DIR}/wizardviewstepmodel.h ${SRC_DIR}/avatarregistry.h ${SRC_DIR}/currentconversation.h - ${SRC_DIR}/currentaccount.h) + ${SRC_DIR}/currentaccount.h + ${SRC_DIR}/videodevices.h) set(QML_LIBS Qt5::Quick diff --git a/src/accountadapter.cpp b/src/accountadapter.cpp index 1d62fe8ed..f43aaa947 100644 --- a/src/accountadapter.cpp +++ b/src/accountadapter.cpp @@ -263,32 +263,12 @@ AccountAdapter::savePassword(const QString& accountId, return lrcInstance_->accountModel().changeAccountPassword(accountId, oldPassword, newPassword); } -void -AccountAdapter::startPreviewing(bool force) -{ - lrcInstance_->renderer()->startPreviewing(force); -} - -void -AccountAdapter::stopPreviewing() -{ - if (!lrcInstance_->hasActiveCall(true) && lrcInstance_->renderer()->isPreviewing()) { - lrcInstance_->renderer()->stopPreviewing(); - } -} - bool AccountAdapter::hasVideoCall() { return lrcInstance_->hasActiveCall(true); } -bool -AccountAdapter::isPreviewing() -{ - return lrcInstance_->renderer()->isPreviewing(); -} - void AccountAdapter::setCurrAccDisplayName(const QString& text) { diff --git a/src/accountadapter.h b/src/accountadapter.h index d85d1cbee..0c69a8073 100644 --- a/src/accountadapter.h +++ b/src/accountadapter.h @@ -77,11 +77,7 @@ public: Q_INVOKABLE bool savePassword(const QString& accountId, const QString& oldPassword, const QString& newPassword); - - Q_INVOKABLE void startPreviewing(bool force = false); - Q_INVOKABLE void stopPreviewing(); Q_INVOKABLE bool hasVideoCall(); - Q_INVOKABLE bool isPreviewing(); Q_INVOKABLE void setCurrAccDisplayName(const QString& text); Q_INVOKABLE void setCurrentAccountAvatarFile(const QString& source); Q_INVOKABLE void setCurrentAccountAvatarBase64(const QString& source = {}); diff --git a/src/avadapter.cpp b/src/avadapter.cpp index 218b9a907..ef3f8b096 100644 --- a/src/avadapter.cpp +++ b/src/avadapter.cpp @@ -36,36 +36,18 @@ AvAdapter::AvAdapter(LRCInstance* instance, QObject* parent) : QmlAdapterBase(instance, parent) { - auto& avModel = lrcInstance_->avModel(); - - deviceListSize_ = avModel.getDevices().size(); - connect(&avModel, &lrc::api::AVModel::audioDeviceEvent, this, &AvAdapter::onAudioDeviceEvent); - connect(&avModel, &lrc::api::AVModel::deviceEvent, this, &AvAdapter::onVideoDeviceEvent); connect(lrcInstance_->renderer(), &RenderManager::previewFrameStarted, [this]() { // TODO: listen to the correct signals that are needed to be added in daemon or lrc - auto callId = getCurrentCallId(); + auto callId = lrcInstance_->getCurrentCallId(); if (!callId.isEmpty()) set_currentRenderingDeviceType( lrcInstance_->avModel().getCurrentRenderedDevice(callId).type); }); -} -void -AvAdapter::selectVideoInputDeviceByName(const QString& deviceName) -{ - auto deviceId = lrcInstance_->avModel().getDeviceIdFromName(deviceName); - if (deviceId.isEmpty()) { - qWarning() << "Couldn't find device: " << deviceName; - return; - } - selectVideoInputDeviceById(deviceId); -} - -void -AvAdapter::selectVideoInputDeviceById(const QString& deviceId) -{ - lrcInstance_->avModel().setCurrentVideoCaptureDevice(deviceId); - lrcInstance_->avModel().switchInputTo(deviceId, getCurrentCallId()); + connect(&lrcInstance_->avModel(), + &lrc::api::AVModel::audioDeviceEvent, + this, + &AvAdapter::onAudioDeviceEvent); } // The top left corner of primary screen is (0, 0). @@ -114,7 +96,7 @@ AvAdapter::shareEntireScreen(int screenNumber) rect.y(), rect.width() * screen->devicePixelRatio(), rect.height() * screen->devicePixelRatio(), - getCurrentCallId()); + lrcInstance_->getCurrentCallId()); } void @@ -127,7 +109,7 @@ AvAdapter::shareAllScreens() arrangementRect.y(), arrangementRect.width(), arrangementRect.height(), - getCurrentCallId()); + lrcInstance_->getCurrentCallId()); } void @@ -187,7 +169,7 @@ AvAdapter::captureAllScreens() void AvAdapter::shareFile(const QString& filePath) { - lrcInstance_->avModel().setInputFile(filePath, getCurrentCallId()); + lrcInstance_->avModel().setInputFile(filePath, lrcInstance_->getCurrentCallId()); } void @@ -206,7 +188,7 @@ AvAdapter::shareScreenArea(unsigned x, unsigned y, unsigned width, unsigned heig y, width < 128 ? 128 : width, height < 128 ? 128 : height, - getCurrentCallId()); + lrcInstance_->getCurrentCallId()); }); #else lrcInstance_->avModel().setDisplay(getScreenNumber(), @@ -214,14 +196,14 @@ AvAdapter::shareScreenArea(unsigned x, unsigned y, unsigned width, unsigned heig y, width < 128 ? 128 : width, height < 128 ? 128 : height, - getCurrentCallId()); + lrcInstance_->getCurrentCallId()); #endif } void AvAdapter::stopSharing() { - auto callId = getCurrentCallId(); + auto callId = lrcInstance_->getCurrentCallId(); if (!callId.isEmpty()) lrcInstance_->avModel().switchInputTo(lrcInstance_->avModel().getCurrentVideoCaptureDevice(), callId); @@ -248,82 +230,6 @@ AvAdapter::onAudioDeviceEvent() Q_EMIT audioDeviceListChanged(inputs, outputs); } -void -AvAdapter::onVideoDeviceEvent() -{ - auto& avModel = lrcInstance_->avModel(); - auto defaultDevice = avModel.getDefaultDevice(); - auto currentCaptureDevice = avModel.getCurrentVideoCaptureDevice(); - QString callId = getCurrentCallId(); - - /* - * Decide whether a device has plugged, unplugged, or nothing has changed. - */ - auto deviceList = avModel.getDevices(); - auto currentDeviceListSize = deviceList.size(); - - DeviceEvent deviceEvent {DeviceEvent::None}; - if (currentDeviceListSize > deviceListSize_) { - deviceEvent = DeviceEvent::Added; - } else if (currentDeviceListSize < deviceListSize_) { - /* - * Check if the currentCaptureDevice is still in the device list. - */ - if (std::find(std::begin(deviceList), std::end(deviceList), currentCaptureDevice) - == std::end(deviceList)) { - deviceEvent = DeviceEvent::RemovedCurrent; - } - } - - auto cb = [this, currentDeviceListSize, deviceEvent, defaultDevice, callId] { - auto& avModel = lrcInstance_->avModel(); - if (currentDeviceListSize == 0) { - avModel.clearCurrentVideoCaptureDevice(); - avModel.switchInputTo({}, callId); - avModel.stopPreview(); - } else if (deviceEvent == DeviceEvent::RemovedCurrent && currentDeviceListSize > 0) { - avModel.setDefaultDevice(defaultDevice); - avModel.setCurrentVideoCaptureDevice(defaultDevice); - avModel.switchInputTo(defaultDevice, callId); - } - }; - - if (lrcInstance_->renderer()->isPreviewing()) { - Utils::oneShotConnect(lrcInstance_->renderer(), - &RenderManager::previewRenderingStopped, - [cb] { QtConcurrent::run([cb]() { cb(); }); }); - } else { - if (deviceEvent == DeviceEvent::Added && currentDeviceListSize == 1) { - avModel.setDefaultDevice(defaultDevice); - avModel.setCurrentVideoCaptureDevice(defaultDevice); - if (callId.isEmpty()) { - Q_EMIT videoDeviceAvailable(); - } else { - avModel.switchInputTo(defaultDevice, callId); - } - } else { - cb(); - } - } - - Q_EMIT videoDeviceListChanged(currentDeviceListSize); - - deviceListSize_ = currentDeviceListSize; -} - -QString -AvAdapter::getCurrentCallId() -{ - try { - const auto& convInfo = lrcInstance_->getConversationFromConvUid( - lrcInstance_->get_selectedConvUid()); - auto call = lrcInstance_->getCallInfoForConversation(convInfo); - return call ? call->id : QString(); - } catch (...) { - return QString(); - } -} - int AvAdapter::getScreenNumber() const { @@ -350,43 +256,50 @@ AvAdapter::setDeviceName(const QString& deviceName) } void -AvAdapter::setCurrentVideoDeviceRateAndResolution(qreal rate, const QString& resolution) +AvAdapter::enableCodec(unsigned int id, bool isToEnable) { - auto settings = lrcInstance_->avModel().getDeviceSettings( - lrcInstance_->avModel().getCurrentVideoCaptureDevice()); - settings.rate = rate; - settings.size = resolution; - lrcInstance_->avModel().setDeviceSettings(settings); + lrcInstance_->getCurrentAccountInfo().codecModel->enable(id, isToEnable); } -QString -AvAdapter::getVideoSettingsSize(const QString& deviceId) +void +AvAdapter::increaseCodecPriority(unsigned int id, bool isVideo) { - return lrcInstance_->avModel().getDeviceSettings(deviceId).size; + lrcInstance_->getCurrentAccountInfo().codecModel->increasePriority(id, isVideo); } -int -AvAdapter::getCurrentVideoDeviceCapabilitiesSize() +void +AvAdapter::decreaseCodecPriority(unsigned int id, bool isVideo) { - return lrcInstance_->avModel() - .getDeviceCapabilities(lrcInstance_->avModel().getCurrentVideoCaptureDevice()) - .size(); + lrcInstance_->getCurrentAccountInfo().codecModel->decreasePriority(id, isVideo); } +bool +AvAdapter::getHardwareAcceleration() +{ + return lrcInstance_->avModel().getHardwareAcceleration(); +} void -AvAdapter::enableCodec(unsigned int id, bool isToEnable) +AvAdapter::setHardwareAcceleration(bool accelerate) { - lrcInstance_->getCurrentAccountInfo().codecModel->enable(id, isToEnable); + lrcInstance_->avModel().setHardwareAcceleration(accelerate); } void -AvAdapter::increaseCodecPriority(unsigned int id, bool isVideo) +AvAdapter::startPreviewing(bool force) { - lrcInstance_->getCurrentAccountInfo().codecModel->increasePriority(id, isVideo); + lrcInstance_->renderer()->startPreviewing(force); } void -AvAdapter::decreaseCodecPriority(unsigned int id, bool isVideo) +AvAdapter::stopPreviewing() { - lrcInstance_->getCurrentAccountInfo().codecModel->decreasePriority(id, isVideo); + if (!lrcInstance_->hasActiveCall(true)) { + lrcInstance_->renderer()->stopPreviewing(); + } } + +bool +AvAdapter::isPreviewing() +{ + return lrcInstance_->renderer()->isPreviewing(); +} \ No newline at end of file diff --git a/src/avadapter.h b/src/avadapter.h index a6ef42b32..186bb25a4 100644 --- a/src/avadapter.h +++ b/src/avadapter.h @@ -29,28 +29,20 @@ class AvAdapter final : public QmlAdapterBase { Q_OBJECT - QML_PROPERTY(lrc::api::video::DeviceType, currentRenderingDeviceType) + QML_RO_PROPERTY(lrc::api::video::DeviceType, currentRenderingDeviceType) public: explicit AvAdapter(LRCInstance* instance, QObject* parent = nullptr); ~AvAdapter() = default; Q_SIGNALS: - - void audioDeviceListChanged(int inputs, int outputs); - void videoDeviceListChanged(int inputs); void screenCaptured(int screenNumber, QString source); - void videoDeviceAvailable(); + // TODO: move to future audio device class + void audioDeviceListChanged(int inputs, int outputs); protected: void safeInit() override {}; - // switch preview video input by device name - Q_INVOKABLE void selectVideoInputDeviceByName(const QString& deviceName); - - // switch preview video input by device id - Q_INVOKABLE void selectVideoInputDeviceById(const QString& deviceId); - // Share the screen specificed by screen number. Q_INVOKABLE void shareEntireScreen(int screenNumber); @@ -76,31 +68,25 @@ protected: Q_INVOKABLE void stopAudioMeter(); Q_INVOKABLE void setDeviceName(const QString& deviceName); - Q_INVOKABLE void setCurrentVideoDeviceRateAndResolution(qreal rate, const QString& resolution); - Q_INVOKABLE QString getVideoSettingsSize(const QString& deviceId); - Q_INVOKABLE int getCurrentVideoDeviceCapabilitiesSize(); Q_INVOKABLE void enableCodec(unsigned int id, bool isToEnable); Q_INVOKABLE void increaseCodecPriority(unsigned int id, bool isVideo); Q_INVOKABLE void decreaseCodecPriority(unsigned int id, bool isVideo); + // TODO: to be removed + Q_INVOKABLE bool getHardwareAcceleration(); + Q_INVOKABLE void setHardwareAcceleration(bool accelerate); + Q_INVOKABLE bool isPreviewing(); + Q_INVOKABLE void startPreviewing(bool force = false); + Q_INVOKABLE void stopPreviewing(); + private Q_SLOTS: void onAudioDeviceEvent(); - void onVideoDeviceEvent(); private: // Get screens arrangement rect relative to primary screen. const QRect getAllScreensBoundingRect(); - // Get current callId from current selected conv id. - QString getCurrentCallId(); - - // Used to classify capture device events. - enum class DeviceEvent { Added, RemovedCurrent, None }; - - // Used to track the capture device count. - int deviceListSize_; - // Get the screen number int getScreenNumber() const; }; diff --git a/src/commoncomponents/PhotoboothView.qml b/src/commoncomponents/PhotoboothView.qml index fced33a92..80faca19f 100644 --- a/src/commoncomponents/PhotoboothView.qml +++ b/src/commoncomponents/PhotoboothView.qml @@ -39,13 +39,13 @@ Item { height: boothLayout.height function startBooth() { - AccountAdapter.startPreviewing(false) + AvAdapter.startPreviewing(false) isPreviewing = true } function stopBooth(){ if (!AccountAdapter.hasVideoCall()) { - AccountAdapter.stopPreviewing() + AvAdapter.stopPreviewing() } isPreviewing = false } @@ -136,8 +136,6 @@ Item { anchors.margins: 1 visible: isPreviewing - - onRenderingStopped: stopBooth() lrcInstance: LRCInstance layer.enabled: true @@ -148,6 +146,11 @@ Item { radius: avatarSize / 2 } } + + onRenderingStopped: { + if (root.visible) + stopBooth() + } } Rectangle { diff --git a/src/commoncomponents/SettingParaCombobox.qml b/src/commoncomponents/SettingParaCombobox.qml index c84b29dd5..cdb9ee980 100644 --- a/src/commoncomponents/SettingParaCombobox.qml +++ b/src/commoncomponents/SettingParaCombobox.qml @@ -24,19 +24,23 @@ import net.jami.Constants 1.1 ComboBox { id: root - property string tooltipText - property string comboBoxBackgroundColor: JamiTheme.editBackgroundColor + property alias tooltipText: toolTip.text property string placeholderText + property string currentSelectionText: currentText + property string comboBoxBackgroundColor: JamiTheme.editBackgroundColor - displayText: currentIndex !== -1 ? - currentText : - (placeholderText !== "" ? - placeholderText : - JamiStrings.notAvailable) + MaterialToolTip { + id: toolTip - ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval - ToolTip.visible: hovered && (tooltipText.length > 0) - ToolTip.text: tooltipText + parent: root + visible: hovered && (text.length > 0) + delay: Qt.styleHints.mousePressAndHoldInterval + } + + displayText: currentIndex !== -1 ? + currentSelectionText : (placeholderText !== "" ? + placeholderText : + JamiStrings.notAvailable) delegate: ItemDelegate { width: root.width @@ -53,7 +57,6 @@ ComboBox { elide: Text.ElideRight verticalAlignment: Text.AlignVCenter } - highlighted: root.highlightedIndex === index background: Rectangle { color: highlighted? JamiTheme.selectedColor : JamiTheme.editBackgroundColor } @@ -61,8 +64,10 @@ ComboBox { indicator: Canvas { id: canvas + x: root.width - width - root.rightPadding y: root.topPadding + (root.availableHeight - height) / 2 + width: 12 height: 8 contextType: "2d" @@ -113,17 +118,17 @@ ComboBox { contentItem: ListView { id: listView + clip: true implicitHeight: contentHeight model: root.delegateModel - currentIndex: root.highlightedIndex - ScrollBar.vertical: ScrollBar { } + ScrollBar.vertical: ScrollBar {} } background: Rectangle { color: JamiTheme.editBackgroundColor - border.color: "gray" + border.color: JamiTheme.greyBorderColor radius: 2 } } diff --git a/src/lrcinstance.cpp b/src/lrcinstance.cpp index e1f5438cd..820c2df3c 100644 --- a/src/lrcinstance.cpp +++ b/src/lrcinstance.cpp @@ -417,3 +417,15 @@ LRCInstance::monitor(bool continuous) { lrc_->monitor(continuous); } + +QString +LRCInstance::getCurrentCallId() +{ + try { + const auto& convInfo = getConversationFromConvUid(get_selectedConvUid()); + auto call = getCallInfoForConversation(convInfo); + return call ? call->id : QString(); + } catch (...) { + return QString(); + } +} diff --git a/src/lrcinstance.h b/src/lrcinstance.h index b1b9ce0ef..b3145de46 100644 --- a/src/lrcinstance.h +++ b/src/lrcinstance.h @@ -89,6 +89,7 @@ public: const account::Info& getAccountInfo(const QString& accountId); const account::Info& getCurrentAccountInfo(); + QString getCurrentCallId(); QString getCallIdForConversationUid(const QString& convUid, const QString& accountId); const call::Info* getCallInfo(const QString& callId, const QString& accountId); const call::Info* getCallInfoForConversation(const conversation::Info& convInfo, diff --git a/src/mainview/MainView.qml b/src/mainview/MainView.qml index ac88a3006..97ffa3e2b 100644 --- a/src/mainview/MainView.qml +++ b/src/mainview/MainView.qml @@ -57,7 +57,6 @@ Rectangle { property string currentAccountId: LRCInstance.currentAccountId onCurrentAccountIdChanged: { if (inSettingsView) { - settingsView.accountListChanged() settingsView.setSelected(settingsView.selectedMenu, true) } else { backToMainView(true) diff --git a/src/mainview/components/CallActionBar.qml b/src/mainview/components/CallActionBar.qml index 0939c3d69..0eae57dca 100644 --- a/src/mainview/components/CallActionBar.qml +++ b/src/mainview/components/CallActionBar.qml @@ -70,11 +70,6 @@ Control { audioOutputDeviceListModel.reset(); audioOutputMenuAction.enabled = outputs } - - function onVideoDeviceListChanged(inputs) { - videoInputDeviceListModel.reset(); - videoInputMenuAction.enabled = inputs - } } property list<Action> menuActions: [ @@ -144,34 +139,16 @@ Control { }, Action { id: videoInputMenuAction + enabled: VideoDevices.listSize !== 0 text: JamiStrings.selectVideoDevice - Component.onCompleted: enabled = videoInputDeviceListModel.rowCount() - property var listModel: VideoInputDeviceModel { - id: videoInputDeviceListModel - lrcInstance: LRCInstance - } + property var listModel: VideoDevices.devicesSourceModel() function accept(index) { - if (listModel.deviceCount() < 1) + if (VideoDevices.listSize < 1) return - try { - var deviceId = listModel.data( - listModel.index(index, 0), - VideoInputDeviceModel.DeviceId) - var deviceName = listModel.data( - listModel.index(index, 0), - VideoInputDeviceModel.DeviceName) - if (deviceId.length === 0) { - console.warn("Couldn't find device: " + deviceName) - return - } - if (AVModel.getCurrentVideoCaptureDevice() !== deviceId) { - AVModel.setCurrentVideoCaptureDevice(deviceId) - AVModel.setDefaultDevice(deviceId) - } - AvAdapter.selectVideoInputDeviceById(deviceId) - } catch (err) { - console.warn(err.message) - } + // TODO: change it when we can suppot showing default and + // current rendering device at the same time and + // start and stop preview logic in here should be in LRC + VideoDevices.setDefaultDevice(index, true) } } ] diff --git a/src/mainview/components/OngoingCallPage.qml b/src/mainview/components/OngoingCallPage.qml index 2f2df5817..4a6908c5b 100644 --- a/src/mainview/components/OngoingCallPage.qml +++ b/src/mainview/components/OngoingCallPage.qml @@ -190,10 +190,11 @@ Rectangle { } Connections { - target: AvAdapter + target: VideoDevices - function onVideoDeviceListChanged(inputs) { - previewRenderer.visible = (inputs !== 0) + // TODO: previewRenderer visible should be listening to a property + function onDeviceListChanged() { + previewRenderer.visible = VideoDevices.listSize !== 0 } } diff --git a/src/mainview/components/RecordBox.qml b/src/mainview/components/RecordBox.qml index b108e7ac8..9db8100b9 100644 --- a/src/mainview/components/RecordBox.qml +++ b/src/mainview/components/RecordBox.qml @@ -59,7 +59,7 @@ Rectangle { updateState(RecordBox.States.INIT) if (isVideo) { - AccountAdapter.startPreviewing(false) + AvAdapter.startPreviewing(false) previewAvailable = true } } @@ -67,10 +67,9 @@ Rectangle { function scaleHeight() { height = preferredHeight if (isVideo) { - var device = AVModel.getDefaultDevice() - var settings = AvAdapter.getVideoSettingsSize(device) - var res = settings.split("x") - var aspectRatio = res[1] / res[0] + var resolution = VideoDevices.defaultRes + var resVec = resolution.split("x") + var aspectRatio = resVec[1] / resVec[0] if (aspectRatio) { height = preferredWidth * aspectRatio } else { @@ -80,8 +79,8 @@ Rectangle { } function closeRecorder() { - if (isVideo && AccountAdapter.isPreviewing()) { - AccountAdapter.stopPreviewing() + if (isVideo && AvAdapter.isPreviewing()) { + AvAdapter.stopPreviewing() } stopRecording() visible = false diff --git a/src/qmlregister.cpp b/src/qmlregister.cpp index 5f5f32c27..0b7599beb 100644 --- a/src/qmlregister.cpp +++ b/src/qmlregister.cpp @@ -28,6 +28,7 @@ #include "conversationsadapter.h" #include "currentconversation.h" #include "currentaccount.h" +#include "videodevices.h" #include "accountlistmodel.h" #include "accountstomigratelistmodel.h" @@ -52,9 +53,6 @@ #include "pluginlistpreferencemodel.h" #include "previewrenderer.h" #include "version.h" -#include "videoformatfpsmodel.h" -#include "videoformatresolutionmodel.h" -#include "videoinputdevicemodel.h" #include "wizardviewstepmodel.h" #include "api/peerdiscoverymodel.h" @@ -116,6 +114,7 @@ registerTypes(QQmlEngine* engine, auto pluginAdapter = new PluginAdapter(lrcInstance, parent); auto currentConversation = new CurrentConversation(lrcInstance, parent); auto currentAccount = new CurrentAccount(lrcInstance, appSettingsManager, parent); + auto videoDevices = new VideoDevices(lrcInstance, parent); // qml adapter registration QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, callAdapter, "CallAdapter"); @@ -128,6 +127,7 @@ registerTypes(QQmlEngine* engine, QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, pluginAdapter, "PluginAdapter"); QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, currentConversation, "CurrentConversation"); QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, currentAccount, "CurrentAccount"); + QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, videoDevices, "VideoDevices"); // TODO: remove these QML_REGISTERSINGLETONTYPE_CUSTOM(NS_MODELS, AVModel, &lrcInstance->avModel()) @@ -152,9 +152,6 @@ registerTypes(QQmlEngine* engine, QML_REGISTERTYPE(NS_MODELS, AccountsToMigrateListModel); QML_REGISTERTYPE(NS_MODELS, AudioDeviceModel); QML_REGISTERTYPE(NS_MODELS, AudioManagerListModel); - QML_REGISTERTYPE(NS_MODELS, VideoInputDeviceModel); - QML_REGISTERTYPE(NS_MODELS, VideoFormatResolutionModel); - QML_REGISTERTYPE(NS_MODELS, VideoFormatFpsModel); QML_REGISTERTYPE(NS_MODELS, PluginListPreferenceModel); QML_REGISTERTYPE(NS_MODELS, FilesToSendListModel); QML_REGISTERTYPE(NS_MODELS, SmartListModel); @@ -216,6 +213,9 @@ registerTypes(QQmlEngine* engine, QML_REGISTERUNCREATABLE(NS_ENUMS, NetWorkManager) QML_REGISTERUNCREATABLE(NS_ENUMS, WizardViewStepModel) QML_REGISTERUNCREATABLE(NS_ENUMS, DeviceItemListModel) + QML_REGISTERUNCREATABLE(NS_ENUMS, VideoInputDeviceModel) + QML_REGISTERUNCREATABLE(NS_ENUMS, VideoFormatResolutionModel) + QML_REGISTERUNCREATABLE(NS_ENUMS, VideoFormatFpsModel) engine->addImageProvider(QLatin1String("qrImage"), new QrImageProvider(lrcInstance)); engine->addImageProvider(QLatin1String("avatarImage"), diff --git a/src/qtutils.h b/src/qtutils.h index 725e2aa9b..102a2c299 100644 --- a/src/qtutils.h +++ b/src/qtutils.h @@ -80,6 +80,29 @@ oneShotConnect(const typename QtPrivate::FunctionPointer<Func1>::Object* sender, }); } +template<typename Func1, typename Func2> +void +oneShotConnect(const typename QtPrivate::FunctionPointer<Func1>::Object* sender, + Func1 signal, + QObject* context, + Func2 slot, + Qt::ConnectionType connectionType = Qt::ConnectionType::AutoConnection) +{ + QMetaObject::Connection* const connection = new QMetaObject::Connection; + *connection = QObject::connect(sender, signal, context, slot, connectionType); + QMetaObject::Connection* const disconnectConnection = new QMetaObject::Connection; + *disconnectConnection = QObject::connect(sender, signal, [connection, disconnectConnection] { + if (connection) { + QObject::disconnect(*connection); + delete connection; + } + if (disconnectConnection) { + QObject::disconnect(*disconnectConnection); + delete disconnectConnection; + } + }); +} + template<typename Func1, typename Func2, typename Func3> void oneShotConnect(const typename QtPrivate::FunctionPointer<Func1>::Object* sender, diff --git a/src/rendermanager.cpp b/src/rendermanager.cpp index a60c52a99..86cb18873 100644 --- a/src/rendermanager.cpp +++ b/src/rendermanager.cpp @@ -234,10 +234,6 @@ RenderManager::isPreviewing() void RenderManager::stopPreviewing() { - if (!previewFrameWrapper_->isRendering()) { - return; - } - previewFrameWrapper_->stopRendering(); avModel_.stopPreview(); } diff --git a/src/settingsview/SettingsView.qml b/src/settingsview/SettingsView.qml index cad854e64..152a3aa76 100644 --- a/src/settingsview/SettingsView.qml +++ b/src/settingsview/SettingsView.qml @@ -42,7 +42,7 @@ Rectangle { if(visible){ setSelected(selectedMenu,true) } else { - AccountAdapter.stopPreviewing() + AvAdapter.stopPreviewing() } } @@ -50,12 +50,10 @@ Rectangle { if(selectedMenu === sel && (!recovery)) { return } switch(sel) { case SettingsView.Account: - AccountAdapter.stopPreviewing() selectedMenu = sel pageIdCurrentAccountSettings.updateAccountInfoDisplayed() break case SettingsView.General: - AccountAdapter.stopPreviewing() selectedMenu = sel break case SettingsView.Media: @@ -63,25 +61,15 @@ Rectangle { avSettings.populateAVSettings() break case SettingsView.Plugin: - AccountAdapter.stopPreviewing() selectedMenu = sel pluginSettings.populatePluginSettings() break } } - Connections { - id: accountListChangedConnection - target: LRCInstance - - function onAccountListChanged() { - accountListChanged() - } - } - // slots function leaveSettingsSlot(showMainView) { - AccountAdapter.stopPreviewing() + AvAdapter.stopPreviewing() settingsViewRect.stopBooth() if (showMainView) settingsViewNeedToShowMainView() @@ -89,16 +77,6 @@ Rectangle { settingsViewNeedToShowNewWizardWindow() } - function accountListChanged() { - var accountList = AccountAdapter.model.getAccountList() - if(accountList.length === 0) - return - var device = AVModel.getDefaultDevice() - if(device.length === 0) { - AVModel.setCurrentVideoCaptureDevice(device) - } - } - property int selectedMenu: SettingsView.Account // signal to redirect the page to main view signal settingsViewNeedToShowMainView() diff --git a/src/settingsview/components/AdvancedSIPSecuritySettings.qml b/src/settingsview/components/AdvancedSIPSecuritySettings.qml index 475253fde..237c1bb5d 100644 --- a/src/settingsview/components/AdvancedSIPSecuritySettings.qml +++ b/src/settingsview/components/AdvancedSIPSecuritySettings.qml @@ -267,8 +267,8 @@ ColumnLayout { modelIndex: CurrentAccount.method_TLS - onModelIndexChanged: CurrentAccount.method_TLS = - parseInt(comboModel.get(modelIndex).secondArg) + onActivated: CurrentAccount.method_TLS = + parseInt(comboModel.get(modelIndex).secondArg) } SettingsMaterialLineEdit { diff --git a/src/settingsview/components/AudioSettings.qml b/src/settingsview/components/AudioSettings.qml index da1d57a9c..34649f314 100644 --- a/src/settingsview/components/AudioSettings.qml +++ b/src/settingsview/components/AudioSettings.qml @@ -75,7 +75,7 @@ ColumnLayout { tipText: JamiStrings.selectAudioInputDevice role: "DeviceName" - onModelIndexChanged: { + onActivated: { AvAdapter.stopAudioMeter() AVModel.setInputDevice(comboModel.data( comboModel.index(modelIndex, 0), @@ -114,7 +114,7 @@ ColumnLayout { tipText: JamiStrings.selectAudioOutputDevice role: "DeviceName" - onModelIndexChanged: { + onActivated: { AvAdapter.stopAudioMeter() AVModel.setOutputDevice(comboModel.data( comboModel.index(modelIndex, 0), @@ -140,7 +140,7 @@ ColumnLayout { tipText: JamiStrings.selectRingtoneOutputDevice role: "DeviceName" - onModelIndexChanged: { + onActivated: { AvAdapter.stopAudioMeter() AVModel.setRingtoneDevice(comboModel.data( comboModel.index(modelIndex, 0), @@ -164,7 +164,7 @@ ColumnLayout { widthOfComboBox: itemWidth role: "ID_UTF8" - onModelIndexChanged: { + onActivated: { AvAdapter.stopAudioMeter() var selectedAudioManager = comboModel.data( comboModel.index(modelIndex, 0), AudioManagerListModel.AudioManagerID) diff --git a/src/settingsview/components/AvSettingPage.qml b/src/settingsview/components/AvSettingPage.qml index d01564c47..52cd2b50f 100644 --- a/src/settingsview/components/AvSettingPage.qml +++ b/src/settingsview/components/AvSettingPage.qml @@ -34,20 +34,10 @@ Rectangle { function populateAVSettings() { audioSettings.populateAudioSettings() - videoSettings.populateVideoSettings() } color: JamiTheme.secondaryBackgroundColor - Connections { - target: AvAdapter - - function onVideoDeviceAvailable() { - if (root.visible) - videoSettings.startPreviewing() - } - } - ColumnLayout { id: avSettingsColumnLayout diff --git a/src/settingsview/components/SettingsComboBox.qml b/src/settingsview/components/SettingsComboBox.qml index 1b7752270..ed0aa2467 100644 --- a/src/settingsview/components/SettingsComboBox.qml +++ b/src/settingsview/components/SettingsComboBox.qml @@ -31,6 +31,7 @@ RowLayout { property alias tipText: comboBoxOfLayout.tooltipText property alias role: comboBoxOfLayout.textRole property alias placeholderText: comboBoxOfLayout.placeholderText + property alias currentSelectionText: comboBoxOfLayout.currentSelectionText property alias enabled: comboBoxOfLayout.enabled property alias fontPointSize: comboBoxOfLayout.font.pointSize property alias modelIndex: comboBoxOfLayout.currentIndex @@ -38,6 +39,8 @@ RowLayout { property int heightOfLayout: 30 property int widthOfComboBox: 50 + signal activated + ElidedTextLabel { id: label @@ -62,5 +65,7 @@ RowLayout { textRole: role tooltipText: tipText + + onActivated: root.activated() } } diff --git a/src/settingsview/components/VideoSettings.qml b/src/settingsview/components/VideoSettings.qml index 7307fb75d..50fd6649b 100644 --- a/src/settingsview/components/VideoSettings.qml +++ b/src/settingsview/components/VideoSettings.qml @@ -35,79 +35,72 @@ ColumnLayout { property bool previewAvailable: false property int itemWidth - Connections { - target: AvAdapter - - function onVideoDeviceListChanged() { - populateVideoSettings() - } - } - function startPreviewing(force = false) { if (root.visible) { - AccountAdapter.startPreviewing(force) + AvAdapter.startPreviewing(force) previewAvailable = true } } - function populateVideoSettings() { - deviceComboBoxSetting.comboModel.reset() - - var count = deviceComboBoxSetting.comboModel.deviceCount() + function updatePreviewRatio() { + var resolution = VideoDevices.defaultRes + if (resolution.length !== 0) { + var resVec = resolution.split("x") + var ratio = resVec[1] / resVec[0] + if (ratio) { + aspectRatio = ratio + } else { + console.error("Could not scale recording video preview") + } + } - previewWidget.visible = count > 0 - deviceComboBoxSetting.enabled = count > 0 - resolutionComboBoxSetting.enabled = count > 0 - fpsComboBoxSetting.enabled = count > 0 + } - if (count === 0) { - resolutionComboBoxSetting.reset() - fpsComboBoxSetting.reset() + onVisibleChanged: { + if (visible) { + hardwareAccelControl.checked = AvAdapter.getHardwareAcceleration() + updatePreviewRatio() + if (previewWidget.visible) + startPreviewing(true) } else { - deviceComboBoxSetting.modelIndex = - deviceComboBoxSetting.comboModel.getCurrentIndex() + AvAdapter.stopPreviewing() } - hardwareAccelControl.checked = AVModel.getHardwareAcceleration() } - function slotDeviceBoxCurrentIndexChanged(index) { - if (deviceComboBoxSetting.comboModel.deviceCount() <= 0) - return - - try { - var deviceId = deviceComboBoxSetting.comboModel.data( - deviceComboBoxSetting.comboModel.index(index, 0), - VideoInputDeviceModel.DeviceId) - var deviceName = deviceComboBoxSetting.comboModel.data( - deviceComboBoxSetting.comboModel.index(index, 0), - VideoInputDeviceModel.DeviceName) - if(deviceId.length === 0) { - console.warn("Couldn't find device: " + deviceName) - return - } - - if (AVModel.getCurrentVideoCaptureDevice() !== deviceId) { - AVModel.setCurrentVideoCaptureDevice(deviceId) - AVModel.setDefaultDevice(deviceId) - } + Connections { + target: VideoDevices - resolutionComboBoxSetting.reset() - } catch(err){ console.warn(err.message) } - } + function onDefaultResChanged() { + updatePreviewRatio() + } - function updatePreviewRatio(resolution) { - var res = resolution.split("x") - var ratio = res[1] / res[0] - if (ratio) { - aspectRatio = ratio - } else { - console.error("Could not scale recording video preview") + function onDeviceAvailable() { + startPreviewing() } - } - onVisibleChanged: { - if (visible) - startPreviewing(true) + function onDeviceListChanged() { + var deviceModel = deviceComboBoxSetting.comboModel + var resModel = resolutionComboBoxSetting.comboModel + var fpsModel = fpsComboBoxSetting.comboModel + + var resultList = deviceModel.match(deviceModel.index(0, 0), + VideoInputDeviceModel.DeviceId, + VideoDevices.defaultId) + deviceComboBoxSetting.modelIndex = resultList.length > 0 ? + resultList[0].row : deviceModel.rowCount() ? 0 : -1 + + resultList = resModel.match(resModel.index(0, 0), + VideoFormatResolutionModel.Resolution, + VideoDevices.defaultRes) + resolutionComboBoxSetting.modelIndex = resultList.length > 0 ? + resultList[0].row : deviceModel.rowCount() ? 0 : -1 + + resultList = fpsModel.match(fpsModel.index(0, 0), + VideoFormatFpsModel.FPS, + VideoDevices.defaultFps) + fpsComboBoxSetting.modelIndex = resultList.length > 0 ? + resultList[0].row : deviceModel.rowCount() ? 0 : -1 + } } ElidedTextLabel { @@ -126,98 +119,66 @@ ColumnLayout { Layout.preferredHeight: JamiTheme.preferredFieldHeight Layout.leftMargin: JamiTheme.preferredMarginSize - labelText: JamiStrings.device + enabled: VideoDevices.listSize !== 0 + fontPointSize: JamiTheme.settingsFontSize - comboModel: VideoInputDeviceModel { - lrcInstance: LRCInstance - } widthOfComboBox: itemWidth - tipText: JamiStrings.selectVideoDevice - role: "DeviceName_UTF8" - - onModelIndexChanged: slotDeviceBoxCurrentIndexChanged(modelIndex) + labelText: JamiStrings.device + tipText: JamiStrings.selectVideoDevice placeholderText: JamiStrings.noVideoDevice + currentSelectionText: VideoDevices.defaultName + comboModel: VideoDevices.devicesFilterModel() + role: "DeviceName" + + onActivated: { + // TODO: start and stop preview logic in here should be in LRC + AvAdapter.stopPreviewing() + VideoDevices.setDefaultDevice(modelIndex) + startPreviewing() + } } SettingsComboBox { id: resolutionComboBoxSetting - function reset() { - modelIndex = -1 - comboModel.reset() - modelIndex = 0 - } - Layout.fillWidth: true Layout.preferredHeight: JamiTheme.preferredFieldHeight Layout.leftMargin: JamiTheme.preferredMarginSize - labelText: JamiStrings.resolution - fontPointSize: JamiTheme.settingsFontSize - comboModel: VideoFormatResolutionModel { - lrcInstance: LRCInstance - } - widthOfComboBox: itemWidth - tipText: JamiStrings.selectVideoResolution - role: "Resolution_UTF8" - - modelIndex: -1 + enabled: VideoDevices.listSize !== 0 - onModelIndexChanged: { - if (modelIndex === -1) - return - var resolution = comboModel.data(comboModel.index(modelIndex, 0), - VideoFormatResolutionModel.Resolution) - fpsComboBoxSetting.comboModel.currentResolution = resolution - fpsComboBoxSetting.modelIndex = 0 + widthOfComboBox: itemWidth + fontPointSize: JamiTheme.settingsFontSize - var rate = fpsComboBoxSetting.comboModel.data( - fpsComboBoxSetting.comboModel.index(0, 0), - VideoFormatFpsModel.FPS) + labelText: JamiStrings.resolution + currentSelectionText: VideoDevices.defaultRes + tipText: JamiStrings.selectVideoResolution + comboModel: VideoDevices.resFilterModel() + role: "Resolution" - AvAdapter.setCurrentVideoDeviceRateAndResolution(rate, resolution) - updatePreviewRatio(resolution) - } + onActivated: VideoDevices.setDefaultDeviceRes(modelIndex) } SettingsComboBox { id: fpsComboBoxSetting - function reset() { - modelIndex = -1 - comboModel.reset() - modelIndex = 0 - } - Layout.fillWidth: true Layout.preferredHeight: JamiTheme.preferredFieldHeight Layout.leftMargin: JamiTheme.preferredMarginSize - labelText: JamiStrings.fps - fontPointSize: JamiTheme.settingsFontSize - comboModel: VideoFormatFpsModel { - lrcInstance: LRCInstance - } - widthOfComboBox: itemWidth - tipText: JamiStrings.selectFPS - role: "FPS_ToDisplay_UTF8" - - modelIndex: -1 + enabled: VideoDevices.listSize !== 0 - onModelIndexChanged: { - if (modelIndex === -1) - return - var resolution = resolutionComboBoxSetting.comboModel.data( - resolutionComboBoxSetting.comboModel.index( - resolutionComboBoxSetting.modelIndex, 0), - VideoFormatResolutionModel.Resolution) + widthOfComboBox: itemWidth + fontPointSize: JamiTheme.settingsFontSize - var rate = comboModel.data(comboModel.index(modelIndex, 0), - VideoFormatFpsModel.FPS) + tipText: JamiStrings.selectFPS + labelText: JamiStrings.fps + currentSelectionText: VideoDevices.defaultFps.toString() + comboModel: VideoDevices.fpsFilterModel() + role: "FPS" - AvAdapter.setCurrentVideoDeviceRateAndResolution(rate, resolution) - } + onActivated: VideoDevices.setDefaultDeviceFps(modelIndex) } ToggleSwitch { @@ -230,7 +191,7 @@ ColumnLayout { fontPointSize: JamiTheme.settingsFontSize onSwitchToggled: { - AVModel.setHardwareAcceleration(checked) + AvAdapter.setHardwareAcceleration(checked) startPreviewing(true) } } @@ -247,8 +208,7 @@ ColumnLayout { Layout.preferredWidth: itemWidth * 2 Layout.bottomMargin: JamiTheme.preferredMarginSize - color: "white" - radius: 5 + color: JamiTheme.primaryForegroundColor PreviewRenderer { id: previewWidget @@ -257,6 +217,7 @@ ColumnLayout { lrcInstance: LRCInstance + visible: VideoDevices.listSize !== 0 layer.enabled: true layer.effect: OpacityMask { maskSource: rectBox @@ -265,6 +226,7 @@ ColumnLayout { } Label { + // TODO: proper use of previewAvailable visible: !previewAvailable Layout.fillWidth: true diff --git a/src/videodevices.cpp b/src/videodevices.cpp new file mode 100644 index 000000000..94cb0bbe6 --- /dev/null +++ b/src/videodevices.cpp @@ -0,0 +1,443 @@ +/*! + * Copyright (C) 2020 by Savoir-faire Linux + * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "videodevices.h" + +// VideoInputDeviceModel +VideoInputDeviceModel::VideoInputDeviceModel(LRCInstance* lrcInstance, + VideoDevices* videoDeviceInstance) + : QAbstractListModel(videoDeviceInstance) + , lrcInstance_(lrcInstance) + , videoDevices_(videoDeviceInstance) +{} + +VideoInputDeviceModel::~VideoInputDeviceModel() {} + +int +VideoInputDeviceModel::rowCount(const QModelIndex& parent) const +{ + if (!parent.isValid() && lrcInstance_) { + return videoDevices_->get_listSize(); + } + return 0; +} + +QVariant +VideoInputDeviceModel::data(const QModelIndex& index, int role) const +{ + auto deviceList = lrcInstance_->avModel().getDevices(); + if (!index.isValid() || deviceList.size() == 0 || index.row() >= deviceList.size()) { + return QVariant(); + } + + auto currentDeviceSetting = lrcInstance_->avModel().getDeviceSettings(deviceList[index.row()]); + + switch (role) { + case Role::DeviceName: + return QVariant(currentDeviceSetting.name); + case Role::DeviceId: + return QVariant(currentDeviceSetting.id); + } + return QVariant(); +} + +QHash<int, QByteArray> +VideoInputDeviceModel::roleNames() const +{ + QHash<int, QByteArray> roles; + roles[DeviceName] = "DeviceName"; + roles[DeviceId] = "DeviceId"; + return roles; +} + +int +VideoInputDeviceModel::getCurrentIndex() const +{ + QString currentId = videoDevices_->get_defaultId(); + auto resultList = match(index(0, 0), DeviceId, QVariant(currentId)); + return resultList.size() > 0 ? resultList[0].row() : 0; +} + +// VideoFormatResolutionModel +VideoFormatResolutionModel::VideoFormatResolutionModel(LRCInstance* lrcInstance, + VideoDevices* videoDeviceInstance) + : QAbstractListModel(videoDeviceInstance) + , lrcInstance_(lrcInstance) + , videoDevices_(videoDeviceInstance) +{} + +VideoFormatResolutionModel::~VideoFormatResolutionModel() {} + +int +VideoFormatResolutionModel::rowCount(const QModelIndex& parent) const +{ + if (!parent.isValid() && lrcInstance_) { + return videoDevices_->get_defaultResRateList().size(); + } + return 0; +} + +QVariant +VideoFormatResolutionModel::data(const QModelIndex& index, int role) const +{ + auto& channelCaps = videoDevices_->get_defaultResRateList(); + if (!index.isValid() || channelCaps.size() <= index.row() || channelCaps.size() == 0) { + return QVariant(); + } + + switch (role) { + case Role::Resolution: + return QVariant(channelCaps.at(index.row()).first); + } + + return QVariant(); +} + +QHash<int, QByteArray> +VideoFormatResolutionModel::roleNames() const +{ + QHash<int, QByteArray> roles; + roles[Resolution] = "Resolution"; + return roles; +} + +int +VideoFormatResolutionModel::getCurrentIndex() const +{ + QString currentDeviceId = videoDevices_->get_defaultId(); + QString currentResolution = videoDevices_->get_defaultRes(); + auto resultList = match(index(0, 0), Resolution, QVariant(currentResolution)); + + return resultList.size() > 0 ? resultList[0].row() : 0; +} + +// VideoFormatFpsModel +VideoFormatFpsModel::VideoFormatFpsModel(LRCInstance* lrcInstance, VideoDevices* videoDeviceInstance) + : QAbstractListModel(videoDeviceInstance) + , lrcInstance_(lrcInstance) + , videoDevices_(videoDeviceInstance) +{} + +VideoFormatFpsModel::~VideoFormatFpsModel() {} + +int +VideoFormatFpsModel::rowCount(const QModelIndex& parent) const +{ + if (!parent.isValid() && lrcInstance_) { + return videoDevices_->get_defaultFpsList().size(); + } + return 0; +} + +QVariant +VideoFormatFpsModel::data(const QModelIndex& index, int role) const +{ + auto& fpsList = videoDevices_->get_defaultFpsList(); + if (!index.isValid() || fpsList.size() == 0 || index.row() >= fpsList.size()) { + return QVariant(); + } + + switch (role) { + case Role::FPS: + return QVariant(static_cast<int>(fpsList[index.row()])); + case Role::FPS_Float: + return QVariant(fpsList[index.row()]); + } + + return QVariant(); +} + +QHash<int, QByteArray> +VideoFormatFpsModel::roleNames() const +{ + QHash<int, QByteArray> roles; + roles[FPS] = "FPS"; + roles[FPS_Float] = "FPS_Float"; + return roles; +} + +int +VideoFormatFpsModel::getCurrentIndex() const +{ + QString currentDeviceId = videoDevices_->get_defaultId(); + float currentFps = videoDevices_->get_defaultFps(); + auto resultList = match(index(0, 0), FPS, QVariant(currentFps)); + + return resultList.size() > 0 ? resultList[0].row() : 0; +} + +// VideoDevices +VideoDevices::VideoDevices(LRCInstance* lrcInstance, QObject* parent) + : QObject(parent) + , lrcInstance_(lrcInstance) + , devicesFilterModel_(new CurrentItemFilterModel(this)) + , resFilterModel_(new CurrentItemFilterModel(this)) + , fpsFilterModel_(new CurrentItemFilterModel(this)) +{ + devicesSourceModel_ = new VideoInputDeviceModel(lrcInstance, this); + resSourceModel_ = new VideoFormatResolutionModel(lrcInstance, this); + fpsSourceModel_ = new VideoFormatFpsModel(lrcInstance, this); + + devicesFilterModel_->setSourceModel(devicesSourceModel_); + resFilterModel_->setSourceModel(resSourceModel_); + fpsFilterModel_->setSourceModel(fpsSourceModel_); + + devicesFilterModel_->setFilterRole(VideoInputDeviceModel::DeviceName); + resFilterModel_->setFilterRole(VideoFormatResolutionModel::Resolution); + fpsFilterModel_->setFilterRole(VideoFormatFpsModel::FPS); + + connect(&lrcInstance_->avModel(), + &lrc::api::AVModel::deviceEvent, + this, + &VideoDevices::onVideoDeviceEvent); + + updateData(); +} + +VideoDevices::~VideoDevices() {} + +QVariant +VideoDevices::devicesFilterModel() +{ + return QVariant::fromValue(devicesFilterModel_); +} + +QVariant +VideoDevices::devicesSourceModel() +{ + return QVariant::fromValue(devicesSourceModel_); +} + +QVariant +VideoDevices::resFilterModel() +{ + return QVariant::fromValue(resFilterModel_); +} + +QVariant +VideoDevices::resSourceModel() +{ + return QVariant::fromValue(resSourceModel_); +} + +QVariant +VideoDevices::fpsFilterModel() +{ + return QVariant::fromValue(fpsFilterModel_); +} + +QVariant +VideoDevices::fpsSourceModel() +{ + return QVariant::fromValue(fpsSourceModel_); +} + +void +VideoDevices::setDefaultDevice(int index, bool useSourceModel) +{ + QString deviceId {}; + auto callId = lrcInstance_->getCurrentCallId(); + + if (useSourceModel) + deviceId = devicesSourceModel_ + ->data(devicesSourceModel_->index(index, 0), VideoInputDeviceModel::DeviceId) + .toString(); + else + deviceId = devicesFilterModel_ + ->data(devicesFilterModel_->index(index, 0), VideoInputDeviceModel::DeviceId) + .toString(); + + lrcInstance_->avModel().setDefaultDevice(deviceId); + + if (!callId.isEmpty()) + lrcInstance_->avModel().switchInputTo(deviceId, callId); + + updateData(); +} + +void +VideoDevices::setDefaultDeviceRes(int index) +{ + auto& channelCaps = get_defaultResRateList(); + auto settings = lrcInstance_->avModel().getDeviceSettings(get_defaultId()); + settings.size = resFilterModel_ + ->data(resFilterModel_->index(index, 0), + VideoFormatResolutionModel::Resolution) + .toString(); + + for (int i = 0; i < channelCaps.size(); i++) { + if (channelCaps[i].first == settings.size) { + settings.rate = channelCaps[i].second.at(0); + lrcInstance_->avModel().setDeviceSettings(settings); + break; + } + } + + updateData(); +} + +void +VideoDevices::setDefaultDeviceFps(int index) +{ + auto settings = lrcInstance_->avModel().getDeviceSettings(get_defaultId()); + settings.size = get_defaultRes(); + settings.rate = fpsFilterModel_ + ->data(fpsFilterModel_->index(index, 0), VideoFormatFpsModel::FPS_Float) + .toFloat(); + + lrcInstance_->avModel().setDeviceSettings(settings); + + updateData(); +} + +void +VideoDevices::updateData() +{ + set_listSize(lrcInstance_->avModel().getDevices().size()); + + if (get_listSize() != 0) { + auto defaultDevice = lrcInstance_->avModel().getDefaultDevice(); + auto defaultDeviceSettings = lrcInstance_->avModel().getDeviceSettings(defaultDevice); + auto defaultDeviceCap = lrcInstance_->avModel().getDeviceCapabilities(defaultDevice); + auto currentResRateList = defaultDeviceCap[defaultDeviceSettings.channel.isEmpty() + ? "default" + : defaultDeviceSettings.channel]; + lrc::api::video::FrameratesList fpsList; + + for (int i = 0; i < currentResRateList.size(); i++) { + if (currentResRateList[i].first == defaultDeviceSettings.size) { + fpsList = currentResRateList[i].second; + } + } + + set_defaultChannel(defaultDeviceSettings.channel); + set_defaultId(defaultDeviceSettings.id); + set_defaultName(defaultDeviceSettings.name); + set_defaultRes(defaultDeviceSettings.size); + set_defaultFps(defaultDeviceSettings.rate); + set_defaultResRateList(currentResRateList); + set_defaultFpsList(fpsList); + + devicesFilterModel_->setCurrentItemFilter(defaultDeviceSettings.name); + resFilterModel_->setCurrentItemFilter(defaultDeviceSettings.size); + fpsFilterModel_->setCurrentItemFilter(static_cast<int>(defaultDeviceSettings.rate)); + } else { + set_defaultChannel(""); + set_defaultId(""); + set_defaultName(""); + set_defaultRes(""); + set_defaultFps(0); + set_defaultResRateList({}); + set_defaultFpsList({}); + + devicesFilterModel_->setCurrentItemFilter(""); + resFilterModel_->setCurrentItemFilter(""); + fpsFilterModel_->setCurrentItemFilter(0); + } + + devicesSourceModel_->reset(); + resSourceModel_->reset(); + fpsSourceModel_->reset(); +} + +void +VideoDevices::onVideoDeviceEvent() +{ + auto& avModel = lrcInstance_->avModel(); + auto defaultDevice = avModel.getDefaultDevice(); + QString callId = lrcInstance_->getCurrentCallId(); + + // Decide whether a device has plugged, unplugged, or nothing has changed. + auto deviceList = avModel.getDevices(); + auto currentDeviceListSize = deviceList.size(); + auto previousDeviceListSize = get_listSize(); + + DeviceEvent deviceEvent {DeviceEvent::None}; + if (currentDeviceListSize > previousDeviceListSize) { + if (previousDeviceListSize == 0) + deviceEvent = DeviceEvent::FirstDevice; + else + deviceEvent = DeviceEvent::Added; + } else if (currentDeviceListSize < previousDeviceListSize) { + deviceEvent = DeviceEvent::Removed; + } + + auto cb = [this, currentDeviceListSize, deviceEvent, defaultDevice, callId] { + auto& avModel = lrcInstance_->avModel(); + if (currentDeviceListSize == 0) { + avModel.switchInputTo({}, callId); + avModel.stopPreview(); + } else if (deviceEvent == DeviceEvent::Removed) { + avModel.switchInputTo(defaultDevice, callId); + } + + updateData(); + Q_EMIT deviceListChanged(currentDeviceListSize); + }; + + if (deviceEvent == DeviceEvent::Added) { + updateData(); + Q_EMIT deviceListChanged(currentDeviceListSize); + } else if (deviceEvent == DeviceEvent::FirstDevice) { + updateData(); + + if (callId.isEmpty()) { + Q_EMIT deviceAvailable(); + } else { + avModel.switchInputTo(defaultDevice, callId); + } + + Q_EMIT deviceListChanged(currentDeviceListSize); + } else if (lrcInstance_->renderer()->isPreviewing()) { + updateData(); + + // Use QueuedConnection to make sure that it happens at the event loop of current device + Utils::oneShotConnect( + lrcInstance_->renderer(), + &RenderManager::previewRenderingStopped, + this, + [cb] { cb(); }, + Qt::QueuedConnection); + } else { + cb(); + } +} + +const lrc::api::video::ResRateList& +VideoDevices::get_defaultResRateList() +{ + return defaultResRateList_; +} + +void +VideoDevices::set_defaultResRateList(lrc::api::video::ResRateList resRateList) +{ + defaultResRateList_.swap(resRateList); +} + +const lrc::api::video::FrameratesList& +VideoDevices::get_defaultFpsList() +{ + return defaultFpsList_; +} + +void +VideoDevices::set_defaultFpsList(lrc::api::video::FrameratesList rateList) +{ + defaultFpsList_.swap(rateList); +} diff --git a/src/videodevices.h b/src/videodevices.h new file mode 100644 index 000000000..e6adab009 --- /dev/null +++ b/src/videodevices.h @@ -0,0 +1,205 @@ +/*! + * Copyright (C) 2020 by Savoir-faire Linux + * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "lrcinstance.h" +#include "qtutils.h" + +#include "api/newdevicemodel.h" + +#include <QSortFilterProxyModel> +#include <QObject> + +class VideoDevices; + +class CurrentItemFilterModel final : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + explicit CurrentItemFilterModel(QObject* parent = nullptr) + : QSortFilterProxyModel(parent) + + {} + + void setCurrentItemFilter(const QVariant& filter) + { + currentItemFilter_ = filter; + } + + virtual bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override + { + // Do not filter if there is only one item. + if (currentItemFilter_.isNull() || sourceModel()->rowCount() == 1) + return true; + + // Exclude current item filter. + auto index = sourceModel()->index(sourceRow, 0, sourceParent); + return index.data(filterRole()) != currentItemFilter_ && !index.parent().isValid(); + } + +private: + QVariant currentItemFilter_ {}; +}; + +class VideoInputDeviceModel : public QAbstractListModel +{ + Q_OBJECT +public: + enum Role { DeviceName = Qt::UserRole + 1, DeviceId }; + Q_ENUM(Role) + + explicit VideoInputDeviceModel(LRCInstance* lrcInstance, VideoDevices* videoDeviceInstance); + ~VideoInputDeviceModel(); + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + QHash<int, QByteArray> roleNames() const override; + + Q_INVOKABLE void reset() + { + beginResetModel(); + endResetModel(); + } + + // Get model index of the current device + Q_INVOKABLE int getCurrentIndex() const; + +private: + LRCInstance* lrcInstance_ {nullptr}; + VideoDevices* const videoDevices_; +}; + +class VideoFormatResolutionModel : public QAbstractListModel +{ + Q_OBJECT +public: + enum Role { Resolution = Qt::UserRole + 1 }; + Q_ENUM(Role) + + explicit VideoFormatResolutionModel(LRCInstance* lrcInstance, VideoDevices* videoDeviceInstance); + ~VideoFormatResolutionModel(); + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + QHash<int, QByteArray> roleNames() const override; + + Q_INVOKABLE void reset() + { + beginResetModel(); + endResetModel(); + } + + // Get model index of the current device + Q_INVOKABLE int getCurrentIndex() const; + +private: + LRCInstance* lrcInstance_ {nullptr}; + VideoDevices* const videoDevices_; +}; + +class VideoFormatFpsModel : public QAbstractListModel +{ + Q_OBJECT + +public: + enum Role { FPS = Qt::UserRole + 1, FPS_Float }; + Q_ENUM(Role) + + explicit VideoFormatFpsModel(LRCInstance* lrcInstance, VideoDevices* videoDeviceInstance); + ~VideoFormatFpsModel(); + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + QHash<int, QByteArray> roleNames() const override; + + Q_INVOKABLE void reset() + { + beginResetModel(); + endResetModel(); + } + + // Get model index of the current device + Q_INVOKABLE int getCurrentIndex() const; + +private: + LRCInstance* lrcInstance_; + VideoDevices* const videoDevices_; +}; + +class VideoDevices : public QObject +{ + Q_OBJECT + QML_RO_PROPERTY(int, listSize) + + QML_RO_PROPERTY(QString, defaultChannel) + QML_RO_PROPERTY(QString, defaultId) + QML_RO_PROPERTY(QString, defaultName) + QML_RO_PROPERTY(QString, defaultRes) + QML_RO_PROPERTY(int, defaultFps) + +public: + explicit VideoDevices(LRCInstance* lrcInstance, QObject* parent = nullptr); + ~VideoDevices(); + + Q_INVOKABLE QVariant devicesFilterModel(); + Q_INVOKABLE QVariant devicesSourceModel(); + + Q_INVOKABLE QVariant resFilterModel(); + Q_INVOKABLE QVariant resSourceModel(); + + Q_INVOKABLE QVariant fpsFilterModel(); + Q_INVOKABLE QVariant fpsSourceModel(); + + Q_INVOKABLE void setDefaultDevice(int index, bool useSourceModel = false); + Q_INVOKABLE void setDefaultDeviceRes(int index); + Q_INVOKABLE void setDefaultDeviceFps(int index); + + const lrc::api::video::ResRateList& get_defaultResRateList(); + void set_defaultResRateList(lrc::api::video::ResRateList resRateList); + + const lrc::api::video::FrameratesList& get_defaultFpsList(); + void set_defaultFpsList(lrc::api::video::FrameratesList rateList); + +Q_SIGNALS: + void deviceAvailable(); + void deviceListChanged(int inputs); + +private Q_SLOTS: + void onVideoDeviceEvent(); + +private: + // Used to classify capture device events. + enum class DeviceEvent { FirstDevice, Added, Removed, None }; + + void updateData(); + + LRCInstance* lrcInstance_; + + CurrentItemFilterModel* devicesFilterModel_; + CurrentItemFilterModel* resFilterModel_; + CurrentItemFilterModel* fpsFilterModel_; + + VideoInputDeviceModel* devicesSourceModel_; + VideoFormatResolutionModel* resSourceModel_; + VideoFormatFpsModel* fpsSourceModel_; + + lrc::api::video::ResRateList defaultResRateList_; + lrc::api::video::FrameratesList defaultFpsList_; +}; diff --git a/src/videoformatfpsmodel.cpp b/src/videoformatfpsmodel.cpp deleted file mode 100644 index cb5fc9a0a..000000000 --- a/src/videoformatfpsmodel.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (C) 2019-2020 by Savoir-faire Linux - * Author: Yang Wang <yang.wang@savoirfairelinux.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "videoformatfpsmodel.h" - -#include "lrcinstance.h" - -#include "api/account.h" -#include "api/contact.h" -#include "api/conversation.h" -#include "api/newdevicemodel.h" - -VideoFormatFpsModel::VideoFormatFpsModel(QObject* parent) - : AbstractListModelBase(parent) -{ - connect(this, &AbstractListModelBase::lrcInstanceChanged, [this] { - if (lrcInstance_) - try { - QString currentDeviceId = lrcInstance_->avModel().getCurrentVideoCaptureDevice(); - auto currentSettings = lrcInstance_->avModel().getDeviceSettings(currentDeviceId); - currentResolution_ = currentSettings.size; - } catch (const std::exception& e) { - qWarning() << "Constructor of VideoFormatFpsModel, exception: " << e.what(); - } - }); -} - -VideoFormatFpsModel::~VideoFormatFpsModel() {} - -int -VideoFormatFpsModel::rowCount(const QModelIndex& parent) const -{ - if (!parent.isValid() && lrcInstance_) { - /* - * Count. - */ - QString currentDeviceId = lrcInstance_->avModel().getCurrentVideoCaptureDevice(); - auto deviceCapabilities = lrcInstance_->avModel().getDeviceCapabilities(currentDeviceId); - if (deviceCapabilities.size() == 0) { - return 0; - } - try { - auto currentSettings = lrcInstance_->avModel().getDeviceSettings(currentDeviceId); - auto currentChannel = currentSettings.channel; - currentChannel = currentChannel.isEmpty() ? "default" : currentChannel; - auto channelCaps = deviceCapabilities[currentChannel]; - - bool resolutionFound = false; - int indexOfCurrentResolutionInResRateList = 0; - - for (int i = 0; i < channelCaps.size(); i++) { - if (channelCaps[i].first == currentResolution_) { - indexOfCurrentResolutionInResRateList = i; - resolutionFound = true; - break; - } - } - - if (resolutionFound) { - auto fpsList = channelCaps[indexOfCurrentResolutionInResRateList].second; - return fpsList.size(); - } - } catch (const std::exception& e) { - qWarning() << e.what(); - } - return 0; - } - /* - * A valid QModelIndex returns 0 as no entry has sub-elements. - */ - return 0; -} - -int -VideoFormatFpsModel::columnCount(const QModelIndex& parent) const -{ - Q_UNUSED(parent); - /* - * Only need one column. - */ - return 1; -} - -QVariant -VideoFormatFpsModel::data(const QModelIndex& index, int role) const -{ - try { - QString currentDeviceId = lrcInstance_->avModel().getCurrentVideoCaptureDevice(); - auto deviceCapabilities = lrcInstance_->avModel().getDeviceCapabilities(currentDeviceId); - - auto currentSettings = lrcInstance_->avModel().getDeviceSettings(currentDeviceId); - auto currentChannel = currentSettings.channel; - currentChannel = currentChannel.isEmpty() ? "default" : currentChannel; - auto channelCaps = deviceCapabilities[currentChannel]; - - bool resolutionFound = false; - int indexOfCurrentResolutionInResRateList = 0; - - for (int i = 0; i < channelCaps.size(); i++) { - if (channelCaps[i].first == currentResolution_) { - indexOfCurrentResolutionInResRateList = i; - resolutionFound = true; - break; - } - } - - if (!index.isValid() || channelCaps.size() <= index.row() || deviceCapabilities.size() == 0 - || !resolutionFound) { - return QVariant(); - } - - auto fpsList = channelCaps[indexOfCurrentResolutionInResRateList].second; - - switch (role) { - case Role::FPS: - return QVariant(fpsList[index.row()]); - case Role::FPS_ToDisplay_UTF8: - QString rateDisplayUtf8 = QString("%1 fps").arg((int) fpsList[index.row()]); - return QVariant(rateDisplayUtf8.toUtf8()); - } - - } catch (const std::exception& e) { - qWarning() << e.what(); - } - - return QVariant(); -} - -QHash<int, QByteArray> -VideoFormatFpsModel::roleNames() const -{ - QHash<int, QByteArray> roles; - roles[FPS] = "FPS"; - roles[FPS_ToDisplay_UTF8] = "FPS_ToDisplay_UTF8"; - return roles; -} - -QModelIndex -VideoFormatFpsModel::index(int row, int column, const QModelIndex& parent) const -{ - Q_UNUSED(parent); - if (column != 0) { - return QModelIndex(); - } - - if (row >= 0 && row < rowCount()) { - return createIndex(row, column); - } - return QModelIndex(); -} - -QModelIndex -VideoFormatFpsModel::parent(const QModelIndex& child) const -{ - Q_UNUSED(child); - return QModelIndex(); -} - -Qt::ItemFlags -VideoFormatFpsModel::flags(const QModelIndex& index) const -{ - auto flags = QAbstractItemModel::flags(index) | Qt::ItemNeverHasChildren | Qt::ItemIsSelectable; - if (!index.isValid()) { - return QAbstractItemModel::flags(index); - } - return flags; -} - -void -VideoFormatFpsModel::reset() -{ - beginResetModel(); - endResetModel(); -} - -int -VideoFormatFpsModel::getCurrentSettingIndex() -{ - int resultRowIndex = 0; - try { - QString currentDeviceId = lrcInstance_->avModel().getCurrentVideoCaptureDevice(); - auto currentSettings = lrcInstance_->avModel().getDeviceSettings(currentDeviceId); - float currentFps = currentSettings.rate; - auto resultList = match(index(0, 0), FPS, QVariant(currentFps)); - - if (resultList.size() > 0) { - resultRowIndex = resultList[0].row(); - } - - } catch (const std::exception& e) { - qWarning() << e.what(); - } - - return resultRowIndex; -} - -QString -VideoFormatFpsModel::getCurrentResolution() -{ - return currentResolution_; -} - -void -VideoFormatFpsModel::setCurrentResolution(QString resNew) -{ - if (currentResolution_ != resNew) { - currentResolution_ = resNew; - reset(); - Q_EMIT currentResolutionChanged(resNew); - } -} diff --git a/src/videoformatfpsmodel.h b/src/videoformatfpsmodel.h deleted file mode 100644 index ef6f62a06..000000000 --- a/src/videoformatfpsmodel.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2019-2020 by Savoir-faire Linux - * Author: Yang Wang <yang.wang@savoirfairelinux.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include "abstractlistmodelbase.h" - -class VideoFormatFpsModel : public AbstractListModelBase -{ - Q_OBJECT - Q_PROPERTY(QString currentResolution READ getCurrentResolution WRITE setCurrentResolution NOTIFY - currentResolutionChanged); - -public: - enum Role { FPS = Qt::UserRole + 1, FPS_ToDisplay_UTF8 }; - Q_ENUM(Role) - - explicit VideoFormatFpsModel(QObject* parent = nullptr); - ~VideoFormatFpsModel(); - - /* - * QAbstractListModel override. - */ - int rowCount(const QModelIndex& parent = QModelIndex()) const override; - int columnCount(const QModelIndex& parent) const override; - QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; - /* - * Override role name as access point in qml. - */ - QHash<int, QByteArray> roleNames() const override; - QModelIndex index(int row, int column = 0, const QModelIndex& parent = QModelIndex()) const; - QModelIndex parent(const QModelIndex& child) const; - Qt::ItemFlags flags(const QModelIndex& index) const; - - /* - * This function is to reset the model when there's new account added. - */ - Q_INVOKABLE void reset(); - /* - * This function is to get the current device id in the demon. - */ - Q_INVOKABLE int getCurrentSettingIndex(); - - /* - * Getters and setters - */ - QString getCurrentResolution(); - void setCurrentResolution(QString resNew); - -Q_SIGNALS: - void currentResolutionChanged(QString resNew); - -private: - QString currentResolution_; -}; diff --git a/src/videoformatresolutionmodel.cpp b/src/videoformatresolutionmodel.cpp deleted file mode 100644 index 59a864d49..000000000 --- a/src/videoformatresolutionmodel.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2019-2020 by Savoir-faire Linux - * Author: Yang Wang <yang.wang@savoirfairelinux.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "videoformatresolutionmodel.h" - -#include "lrcinstance.h" - -#include "api/account.h" -#include "api/contact.h" -#include "api/conversation.h" -#include "api/newdevicemodel.h" - -VideoFormatResolutionModel::VideoFormatResolutionModel(QObject* parent) - : AbstractListModelBase(parent) -{} - -VideoFormatResolutionModel::~VideoFormatResolutionModel() {} - -int -VideoFormatResolutionModel::rowCount(const QModelIndex& parent) const -{ - if (!parent.isValid() && lrcInstance_) { - /* - * Count. - */ - QString currentDeviceId = lrcInstance_->avModel().getCurrentVideoCaptureDevice(); - auto deviceCapabilities = lrcInstance_->avModel().getDeviceCapabilities(currentDeviceId); - if (deviceCapabilities.size() == 0) { - return 0; - } - try { - auto currentSettings = lrcInstance_->avModel().getDeviceSettings(currentDeviceId); - auto currentChannel = currentSettings.channel; - currentChannel = currentChannel.isEmpty() ? "default" : currentChannel; - auto channelCaps = deviceCapabilities[currentChannel]; - - return channelCaps.size(); - } catch (const std::exception& e) { - qWarning() << e.what(); - return 0; - } - } - /* - * A valid QModelIndex returns 0 as no entry has sub-elements. - */ - return 0; -} - -int -VideoFormatResolutionModel::columnCount(const QModelIndex& parent) const -{ - Q_UNUSED(parent); - /* - * Only need one column. - */ - return 1; -} - -QVariant -VideoFormatResolutionModel::data(const QModelIndex& index, int role) const -{ - try { - QString currentDeviceId = lrcInstance_->avModel().getCurrentVideoCaptureDevice(); - auto deviceCapabilities = lrcInstance_->avModel().getDeviceCapabilities(currentDeviceId); - - auto currentSettings = lrcInstance_->avModel().getDeviceSettings(currentDeviceId); - auto currentChannel = currentSettings.channel; - currentChannel = currentChannel.isEmpty() ? "default" : currentChannel; - auto channelCaps = deviceCapabilities[currentChannel]; - - if (!index.isValid() || channelCaps.size() <= index.row() - || deviceCapabilities.size() == 0) { - return QVariant(); - } - - switch (role) { - case Role::Resolution: - return QVariant(channelCaps.at(index.row()).first); - case Role::Resolution_UTF8: - return QVariant(channelCaps.at(index.row()).first.toUtf8()); - } - - } catch (const std::exception& e) { - qWarning() << e.what(); - } - - return QVariant(); -} - -QHash<int, QByteArray> -VideoFormatResolutionModel::roleNames() const -{ - QHash<int, QByteArray> roles; - roles[Resolution] = "Resolution"; - roles[Resolution_UTF8] = "Resolution_UTF8"; - return roles; -} - -QModelIndex -VideoFormatResolutionModel::index(int row, int column, const QModelIndex& parent) const -{ - Q_UNUSED(parent); - if (column != 0) { - return QModelIndex(); - } - - if (row >= 0 && row < rowCount()) { - return createIndex(row, column); - } - return QModelIndex(); -} - -QModelIndex -VideoFormatResolutionModel::parent(const QModelIndex& child) const -{ - Q_UNUSED(child); - return QModelIndex(); -} - -Qt::ItemFlags -VideoFormatResolutionModel::flags(const QModelIndex& index) const -{ - auto flags = QAbstractItemModel::flags(index) | Qt::ItemNeverHasChildren | Qt::ItemIsSelectable; - if (!index.isValid()) { - return QAbstractItemModel::flags(index); - } - return flags; -} - -void -VideoFormatResolutionModel::reset() -{ - beginResetModel(); - endResetModel(); -} - -int -VideoFormatResolutionModel::getCurrentSettingIndex() -{ - int resultRowIndex = 0; - try { - QString currentDeviceId = lrcInstance_->avModel().getCurrentVideoCaptureDevice(); - auto currentSettings = lrcInstance_->avModel().getDeviceSettings(currentDeviceId); - QString currentResolution = currentSettings.size; - auto resultList = match(index(0, 0), Resolution, QVariant(currentResolution)); - - if (resultList.size() > 0) { - resultRowIndex = resultList[0].row(); - } - - } catch (const std::exception& e) { - qWarning() << e.what(); - } - - return resultRowIndex; -} diff --git a/src/videoformatresolutionmodel.h b/src/videoformatresolutionmodel.h deleted file mode 100644 index dad1c2cd6..000000000 --- a/src/videoformatresolutionmodel.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2019-2020 by Savoir-faire Linux - * Author: Yang Wang <yang.wang@savoirfairelinux.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include "abstractlistmodelbase.h" - -class VideoFormatResolutionModel : public AbstractListModelBase -{ - Q_OBJECT -public: - enum Role { Resolution = Qt::UserRole + 1, Resolution_UTF8 }; - Q_ENUM(Role) - - explicit VideoFormatResolutionModel(QObject* parent = nullptr); - ~VideoFormatResolutionModel(); - - /* - * QAbstractListModel override. - */ - int rowCount(const QModelIndex& parent = QModelIndex()) const override; - int columnCount(const QModelIndex& parent) const override; - QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; - /* - * Override role name as access point in qml. - */ - QHash<int, QByteArray> roleNames() const override; - QModelIndex index(int row, int column = 0, const QModelIndex& parent = QModelIndex()) const; - QModelIndex parent(const QModelIndex& child) const; - Qt::ItemFlags flags(const QModelIndex& index) const; - - /* - * This function is to reset the model when there's new account added. - */ - Q_INVOKABLE void reset(); - /* - * This function is to get the current device id in the demon. - */ - Q_INVOKABLE int getCurrentSettingIndex(); -}; diff --git a/src/videoinputdevicemodel.cpp b/src/videoinputdevicemodel.cpp deleted file mode 100644 index 49d639390..000000000 --- a/src/videoinputdevicemodel.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2019-2020 by Savoir-faire Linux - * Author: Yang Wang <yang.wang@savoirfairelinux.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "videoinputdevicemodel.h" - -#include "lrcinstance.h" - -#include "api/newdevicemodel.h" - -VideoInputDeviceModel::VideoInputDeviceModel(QObject* parent) - : AbstractListModelBase(parent) -{} - -VideoInputDeviceModel::~VideoInputDeviceModel() {} - -int -VideoInputDeviceModel::rowCount(const QModelIndex& parent) const -{ - if (!parent.isValid() && lrcInstance_) { - return lrcInstance_->avModel().getDevices().size(); - } - return 0; -} - -QVariant -VideoInputDeviceModel::data(const QModelIndex& index, int role) const -{ - auto deviceList = lrcInstance_->avModel().getDevices(); - if (!index.isValid()) { - return QVariant(); - } - - if (deviceList.size() <= index.row()) { - return QVariant(); - } - - auto currentDeviceSetting = lrcInstance_->avModel().getDeviceSettings(deviceList[index.row()]); - - switch (role) { - case Role::DeviceChannel: - return QVariant((QString) currentDeviceSetting.channel); - case Role::DeviceName: - return QVariant(currentDeviceSetting.name); - case Role::DeviceId: - return QVariant(currentDeviceSetting.id); - case Role::CurrentFrameRate: - return QVariant((float) currentDeviceSetting.rate); - case Role::CurrentResolution: - return QVariant((QString) currentDeviceSetting.size); - case Role::DeviceName_UTF8: - return QVariant(currentDeviceSetting.name.toUtf8()); - case Role::isCurrent: - return QVariant(index.row() == getCurrentIndex()); - } - return QVariant(); -} - -QHash<int, QByteArray> -VideoInputDeviceModel::roleNames() const -{ - QHash<int, QByteArray> roles; - roles[DeviceChannel] = "DeviceChannel"; - roles[DeviceName] = "DeviceName"; - roles[DeviceId] = "DeviceId"; - roles[CurrentFrameRate] = "CurrentFrameRate"; - roles[CurrentResolution] = "CurrentResolution"; - roles[DeviceName_UTF8] = "DeviceName_UTF8"; - roles[isCurrent] = "isCurrent"; - return roles; -} - -void -VideoInputDeviceModel::reset() -{ - beginResetModel(); - endResetModel(); -} - -int -VideoInputDeviceModel::deviceCount() -{ - return lrcInstance_->avModel().getDevices().size(); -} - -int -VideoInputDeviceModel::getCurrentIndex() const -{ - QString currentId = lrcInstance_->avModel().getCurrentVideoCaptureDevice(); - auto resultList = match(index(0, 0), DeviceId, QVariant(currentId)); - return resultList.size() > 0 ? resultList[0].row() : 0; -} diff --git a/src/videoinputdevicemodel.h b/src/videoinputdevicemodel.h deleted file mode 100644 index 63a1a1d88..000000000 --- a/src/videoinputdevicemodel.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2019-2020 by Savoir-faire Linux - * Author: Yang Wang <yang.wang@savoirfairelinux.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include "abstractlistmodelbase.h" - -class VideoInputDeviceModel : public AbstractListModelBase -{ - Q_OBJECT -public: - enum Role { - DeviceName = Qt::UserRole + 1, - DeviceChannel, - DeviceId, - CurrentFrameRate, - CurrentResolution, - DeviceName_UTF8, - isCurrent - }; - Q_ENUM(Role) - - explicit VideoInputDeviceModel(QObject* parent = nullptr); - ~VideoInputDeviceModel(); - - int rowCount(const QModelIndex& parent = QModelIndex()) const override; - QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; - QHash<int, QByteArray> roleNames() const override; - - Q_INVOKABLE void reset(); - Q_INVOKABLE int deviceCount(); - - // get model index of the current device - Q_INVOKABLE int getCurrentIndex() const; -}; -- GitLab