diff --git a/CMakeLists.txt b/CMakeLists.txt index 84efca85..92fb9685 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 1d62fe8e..f43aaa94 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 d85d1cbe..0c69a807 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 218b9a90..ef3f8b09 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 { @@ -349,30 +255,6 @@ AvAdapter::setDeviceName(const QString& deviceName) lrcInstance_->getCurrentAccountInfo().deviceModel->setCurrentDeviceName(deviceName); } -void -AvAdapter::setCurrentVideoDeviceRateAndResolution(qreal rate, const QString& resolution) -{ - auto settings = lrcInstance_->avModel().getDeviceSettings( - lrcInstance_->avModel().getCurrentVideoCaptureDevice()); - settings.rate = rate; - settings.size = resolution; - lrcInstance_->avModel().setDeviceSettings(settings); -} - -QString -AvAdapter::getVideoSettingsSize(const QString& deviceId) -{ - return lrcInstance_->avModel().getDeviceSettings(deviceId).size; -} - -int -AvAdapter::getCurrentVideoDeviceCapabilitiesSize() -{ - return lrcInstance_->avModel() - .getDeviceCapabilities(lrcInstance_->avModel().getCurrentVideoCaptureDevice()) - .size(); -} - void AvAdapter::enableCodec(unsigned int id, bool isToEnable) { @@ -390,3 +272,34 @@ AvAdapter::decreaseCodecPriority(unsigned int id, bool isVideo) { lrcInstance_->getCurrentAccountInfo().codecModel->decreasePriority(id, isVideo); } + +bool +AvAdapter::getHardwareAcceleration() +{ + return lrcInstance_->avModel().getHardwareAcceleration(); +} +void +AvAdapter::setHardwareAcceleration(bool accelerate) +{ + lrcInstance_->avModel().setHardwareAcceleration(accelerate); +} + +void +AvAdapter::startPreviewing(bool force) +{ + lrcInstance_->renderer()->startPreviewing(force); +} + +void +AvAdapter::stopPreviewing() +{ + 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 a6ef42b3..186bb25a 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 fced33a9..80faca19 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 c84b29dd..cdb9ee98 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 + + MaterialToolTip { + id: toolTip + + parent: root + visible: hovered && (text.length > 0) + delay: Qt.styleHints.mousePressAndHoldInterval + } displayText: currentIndex !== -1 ? - currentText : - (placeholderText !== "" ? - placeholderText : - JamiStrings.notAvailable) - - ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval - ToolTip.visible: hovered && (tooltipText.length > 0) - ToolTip.text: tooltipText + 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 e1f5438c..820c2df3 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 b1b9ce0e..b3145de4 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 ac88a300..97ffa3e2 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 0939c3d6..0eae57dc 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 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 2f2df581..4a6908c5 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 b108e7ac..9db8100b 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 5f5f32c2..0b7599be 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 725e2aa9..102a2c29 100644 --- a/src/qtutils.h +++ b/src/qtutils.h @@ -80,6 +80,29 @@ oneShotConnect(const typename QtPrivate::FunctionPointer::Object* sender, }); } +template +void +oneShotConnect(const typename QtPrivate::FunctionPointer::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 void oneShotConnect(const typename QtPrivate::FunctionPointer::Object* sender, diff --git a/src/rendermanager.cpp b/src/rendermanager.cpp index a60c52a9..86cb1887 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 cad854e6..152a3aa7 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 475253fd..237c1bb5 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 da1d57a9..34649f31 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 d01564c4..52cd2b50 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 1b775227..ed0aa246 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 7307fb75..50fd6649 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() - - previewWidget.visible = count > 0 - deviceComboBoxSetting.enabled = count > 0 - resolutionComboBoxSetting.enabled = count > 0 - fpsComboBoxSetting.enabled = count > 0 - - if (count === 0) { - resolutionComboBoxSetting.reset() - fpsComboBoxSetting.reset() - } else { - deviceComboBoxSetting.modelIndex = - deviceComboBoxSetting.comboModel.getCurrentIndex() - } - 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 + 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") } - - if (AVModel.getCurrentVideoCaptureDevice() !== deviceId) { - AVModel.setCurrentVideoCaptureDevice(deviceId) - AVModel.setDefaultDevice(deviceId) - } - - resolutionComboBoxSetting.reset() - } catch(err){ console.warn(err.message) } - } - - 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") } + } onVisibleChanged: { - if (visible) - startPreviewing(true) + if (visible) { + hardwareAccelControl.checked = AvAdapter.getHardwareAcceleration() + updatePreviewRatio() + if (previewWidget.visible) + startPreviewing(true) + } else { + AvAdapter.stopPreviewing() + } + } + + Connections { + target: VideoDevices + + function onDefaultResChanged() { + updatePreviewRatio() + } + + function onDeviceAvailable() { + startPreviewing() + } + + 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 + + labelText: JamiStrings.device tipText: JamiStrings.selectVideoDevice - role: "DeviceName_UTF8" - - onModelIndexChanged: slotDeviceBoxCurrentIndexChanged(modelIndex) - 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 - } + enabled: VideoDevices.listSize !== 0 + widthOfComboBox: itemWidth + fontPointSize: JamiTheme.settingsFontSize + + labelText: JamiStrings.resolution + currentSelectionText: VideoDevices.defaultRes tipText: JamiStrings.selectVideoResolution - role: "Resolution_UTF8" + comboModel: VideoDevices.resFilterModel() + role: "Resolution" - modelIndex: -1 - - onModelIndexChanged: { - if (modelIndex === -1) - return - var resolution = comboModel.data(comboModel.index(modelIndex, 0), - VideoFormatResolutionModel.Resolution) - fpsComboBoxSetting.comboModel.currentResolution = resolution - fpsComboBoxSetting.modelIndex = 0 - - var rate = fpsComboBoxSetting.comboModel.data( - fpsComboBoxSetting.comboModel.index(0, 0), - VideoFormatFpsModel.FPS) - - 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 - } + enabled: VideoDevices.listSize !== 0 + widthOfComboBox: itemWidth + fontPointSize: JamiTheme.settingsFontSize + tipText: JamiStrings.selectFPS - role: "FPS_ToDisplay_UTF8" + labelText: JamiStrings.fps + currentSelectionText: VideoDevices.defaultFps.toString() + comboModel: VideoDevices.fpsFilterModel() + role: "FPS" - modelIndex: -1 - - onModelIndexChanged: { - if (modelIndex === -1) - return - var resolution = resolutionComboBoxSetting.comboModel.data( - resolutionComboBoxSetting.comboModel.index( - resolutionComboBoxSetting.modelIndex, 0), - VideoFormatResolutionModel.Resolution) - - var rate = comboModel.data(comboModel.index(modelIndex, 0), - VideoFormatFpsModel.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 00000000..94cb0bbe --- /dev/null +++ b/src/videodevices.cpp @@ -0,0 +1,443 @@ +/*! + * Copyright (C) 2020 by Savoir-faire Linux + * Author: Mingrui Zhang + * + * 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 . + */ + +#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 +VideoInputDeviceModel::roleNames() const +{ + QHash 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 +VideoFormatResolutionModel::roleNames() const +{ + QHash 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(fpsList[index.row()])); + case Role::FPS_Float: + return QVariant(fpsList[index.row()]); + } + + return QVariant(); +} + +QHash +VideoFormatFpsModel::roleNames() const +{ + QHash 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(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 00000000..e6adab00 --- /dev/null +++ b/src/videodevices.h @@ -0,0 +1,205 @@ +/*! + * Copyright (C) 2020 by Savoir-faire Linux + * Author: Mingrui Zhang + * + * 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 . + */ + +#pragma once + +#include "lrcinstance.h" +#include "qtutils.h" + +#include "api/newdevicemodel.h" + +#include +#include + +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 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 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 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 cb5fc9a0..00000000 --- a/src/videoformatfpsmodel.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (C) 2019-2020 by Savoir-faire Linux - * Author: Yang Wang - * - * 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 . - */ - -#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 -VideoFormatFpsModel::roleNames() const -{ - QHash 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 ef6f62a0..00000000 --- a/src/videoformatfpsmodel.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2019-2020 by Savoir-faire Linux - * Author: Yang Wang - * - * 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 . - */ - -#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 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 59a864d4..00000000 --- a/src/videoformatresolutionmodel.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2019-2020 by Savoir-faire Linux - * Author: Yang Wang - * - * 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 . - */ - -#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 -VideoFormatResolutionModel::roleNames() const -{ - QHash 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 dad1c2cd..00000000 --- a/src/videoformatresolutionmodel.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2019-2020 by Savoir-faire Linux - * Author: Yang Wang - * - * 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 . - */ - -#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 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 49d63939..00000000 --- a/src/videoinputdevicemodel.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2019-2020 by Savoir-faire Linux - * Author: Yang Wang - * - * 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 . - */ - -#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 -VideoInputDeviceModel::roleNames() const -{ - QHash 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 63a1a1d8..00000000 --- a/src/videoinputdevicemodel.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2019-2020 by Savoir-faire Linux - * Author: Yang Wang - * - * 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 . - */ - -#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 roleNames() const override; - - Q_INVOKABLE void reset(); - Q_INVOKABLE int deviceCount(); - - // get model index of the current device - Q_INVOKABLE int getCurrentIndex() const; -};