/*! * 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); auto displaySettings = lrcInstance_->avModel().getDeviceSettings(DEVICE_DESKTOP); auto desktopfpsSource = lrcInstance_->avModel().getDeviceCapabilities(DEVICE_DESKTOP); if (desktopfpsSource.contains(CHANNEL_DEFAULT) && !desktopfpsSource[CHANNEL_DEFAULT].empty()) { desktopfpsSourceModel_ = desktopfpsSource[CHANNEL_DEFAULT][0].second; if (desktopfpsSourceModel_.indexOf(displaySettings.rate) >= 0) set_screenSharingDefaultFps(displaySettings.rate); } 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::setDisplayFPS(const QString& fps) { auto settings = lrcInstance_->avModel().getDeviceSettings(DEVICE_DESKTOP); settings.id = DEVICE_DESKTOP; settings.rate = fps.toInt(); lrcInstance_->avModel().setDeviceSettings(settings); set_screenSharingDefaultFps(fps.toInt()); } QVariant VideoDevices::getScreenSharingFpsModel() { return QVariant::fromValue(desktopfpsSourceModel_.toList()); } 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() ? CHANNEL_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); }