Skip to content
Snippets Groups Projects
Select Git revision
  • master default protected
  • beta/202505231812
  • stable/20250523.0
  • nightly/20250523.0
  • nightly/20250515.0
  • nightly/20250510.0
  • nightly/20250509.1
  • nightly/20250509.0
  • stable/20250430.1
  • stable/20250430.0
  • beta/202504301614
  • nightly/20250430.0
  • stable/20250424.1
  • beta/202504241506
  • stable/20250424.0
  • nightly/20250424.1
  • nightly/20250424.0
  • nightly/20250422.0
  • beta/202504120241
  • stable/20250411.0
  • nightly/20250411.0
21 results

videodevices.cpp

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    videodevices.cpp 16.06 KiB
    /*!
     * Copyright (C) 2020-2022 Savoir-faire Linux Inc.
     * 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);
    
        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_->getCurrentCallModel()->switchInputTo(deviceId, callId);
    
        updateData();
    }
    
    const QString
    VideoDevices::getDefaultDevice()
    {
        auto idx = devicesSourceModel_->getCurrentIndex();
        auto rendererId = QString("camera://")
                          + devicesSourceModel_
                                ->data(devicesSourceModel_->index(idx, 0),
                                       VideoInputDeviceModel::DeviceId)
                                .toString();
        return rendererId;
    }
    
    QString
    VideoDevices::startDevice(const QString& deviceId, bool force)
    {
        if (deviceId.isEmpty())
            return {};
        lrcInstance_->renderer()->addDistantRenderer(deviceId);
        deviceOpen_ = true;
        return lrcInstance_->renderer()->startPreviewing(deviceId, force);
    }
    
    void
    VideoDevices::stopDevice(const QString& deviceId, bool force)
    {
        if (!deviceId.isEmpty() && (!lrcInstance_->hasActiveCall(true) || force)) {
            lrcInstance_->renderer()->stopPreviewing(deviceId);
            lrcInstance_->renderer()->removeDistantRenderer(deviceId);
            deviceOpen_ = false;
        }
    }
    
    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;
                }
            }
    
            if (deviceOpen_ && defaultId_ != defaultDeviceSettings.id) {
                auto callId = lrcInstance_->getCurrentCallId();
                if (!callId.isEmpty()) {
                    auto callId = lrcInstance_->getCurrentCallId();
                    auto callInfos = lrcInstance_->getCallInfo(callId,
                                                               lrcInstance_->get_currentAccountId());
                    for (const auto& media : callInfos->mediaList) {
                        if (media["MUTED"] == "false" && media["ENABLED"] == "true"
                            && media["SOURCE"] == getDefaultDevice()) {
                            /*lrcInstance_->avModel().switchInputTo("camera://" +
                               defaultDeviceSettings.id, callId);*/
                            // startDevice("camera://" + defaultDeviceSettings.id);
                            break;
                        }
                    }
                }
            }
    
            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* callModel = lrcInstance_->getCurrentCallModel();
        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();
            auto* callModel = lrcInstance_->getCurrentCallModel();
            if (currentDeviceListSize == 0) {
                callModel->switchInputTo({}, callId);
                avModel.stopPreview(this->getDefaultDevice());
            } else if (deviceEvent == DeviceEvent::Removed) {
                callModel->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 {
                callModel->switchInputTo(defaultDevice, callId);
            }
    
            Q_EMIT deviceListChanged(currentDeviceListSize);
        } else if (deviceOpen_) {
            updateData();
    
            // Use QueuedConnection to make sure that it happens at the event loop of current device
            Utils::oneShotConnect(
                lrcInstance_->renderer(),
                &RenderManager::distantRenderingStopped,
                this,
                [this, cb](const QString& id) {
                    if (this->getDefaultDevice() == id)
                        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);
    }